diff --git a/17_canvas.md b/17_canvas.md
new file mode 100644
index 000000000..e9f29b1d8
--- /dev/null
+++ b/17_canvas.md
@@ -0,0 +1,1523 @@
+{{meta {load_files: ["code/chapter/16_game.js", "code/levels.js", "code/chapter/17_canvas.js"], zip: "html include=[\"img/player.png\", \"img/sprites.png\"]"}}}
+
+# Dibujando en Canvas
+
+{{quote {author: "M.C. Escher", title: "citado por Bruno Ernst en The Magic Mirror of M.C. Escher", chapter: true}
+
+El dibujo es decepción.
+
+quote}}
+
+{{index "Escher, M.C."}}
+
+{{figure {url: "img/chapter_picture_17.jpg", alt: "Imagen de un brazo robótico dibujando en un papel", chapter: "framed"}}}
+
+{{index CSS, "transform (CSS)", [DOM, graphics]}}
+
+Los navegadores nos proporcionan varias formas de mostrar((gráficos)). La más simple
+es usar estilos para posiciones y colores de elementos regulares del DOM.
+Esto puede ser tardado, como vimos en el [previous
+chapter](juego) pasado. Agregando ((imagenes))s de fondo transparentes
+ a los nodos, podemos hacer que se vean exactamente de la form que
+queremos. incluso es posible rotar o distorsionar nodos con el estilo `transform`.
+
+Pero estaríamos usando el DOM para algo para lo que
+no fue diseñado. Algunas tareas, como dibujar una ((línea)) entre
+puntos arbitrarios, son extremadamente incómodas de hacer con elementos HTML
+regulares.
+
+{{index SVG, "img (HTML tag)"}}
+
+Tenemos dos alternativas. La primera es basada en el DOM, pero utiliza
+_Scalable Vector Graphics_ (SVG), más que HTML. Piensa en SVG como un
+dialecto de un ((documento)) de marcado que se centra en ((figura))s más que en
+texto. Puedes embeber un documento SVG directamente en un archivo HTML o
+puedes incluirlo con una etiqueta ` `.
+
+{{index clearing, [DOM graphics], [interface, canvas]}}
+
+La segunda alternativa es llamada _((canvas))_. Un canvas es un
+elemento del DOM que encapsula una ((imagen)). Proporciona una
+intefaz de programción para dibujar ((forma))s en el espacio
+del nodo. La principal diferencia entre un canvas y una imagen
+SVG es que en SVG la descripción original de las figuras es
+preservada de manera que puedan ser movidas o reescaladas en cualquier momento. Un canvas,
+por otro lado, convierte las figuras a ((pixel))es (puntos de color en
+una rejilla) tan pronto son dibujadas y no recuerda cuáles
+pixeles representa. La única forma de mover una figura en un canvas es limpíando
+el canvas (o la parte del canvas alrededor de la figura) y redibujarlo
+con la figura en una nueva posición.
+
+## SVG
+
+Este libro no hablará de ((SVG)) a detalle, pero explicaré
+de forma breve como funciona. Al final de [final del capítulo](canvas#graphics_tradeoffs), regresaré a estos temas
+que debes considerar cuando debas decidir cuál mecanismo de ((dibujo)) sea
+apropiado dada una aplicación.
+
+Este es un documento HTML con una ((imagen)) SVG simple:
+
+```{lang: "text/html", sandbox: "svg"}
+
HTML normal aquí.
+
+
+
+
+```
+
+{{index "circle (SVG tag)", "rect (SVG tag)", "XML namespace", XML, "xmlns attribute"}}
+
+El atributo `xmlns` cambia un elemento (y sus hijos) a un
+_XML namespace_ diferente. Este _namespace_, identificado por una ((URL)),
+especifica el dialecto que estamos usando. las etiquetas
+`` y ``, —que no existen en HTML, pero tienen un significado en
+SVG— dibujan formas usando el estilo y posición especificados por sus atributos.
+
+{{if book
+
+El documento muestra algo así:
+
+{{figure {url: "img/svg-demo.png", alt: "Una imagen SVG embebida",width: "4.5cm"}}}
+
+if}}
+
+{{index [DOM, graphics]}}
+
+Estas etiquetas crean elementos en el DOM, como etiquetas de HTML, con las
+que los scripts pueden interactuar. Por ejemplo, el siguiente código cambia el elemento ``
+para que sea ((color))eado de cyan:
+
+```{sandbox: "svg"}
+let circulo = document.querySelector("circle");
+circulo.setAttribute("fill", "cyan");
+```
+
+## El elemento canvas
+
+{{index [canvas, size], "canvas (HTML tag)"}}
+
+Los ((gráficos)) canvas pueden ser dibujados en un elemento ``. Puedes
+agregarle los atributos `width` y `height` para determinar su
+tamaño en ((pixel))es.
+
+Un nuevo canvas se encuentra vacío, lo que significa que es completamente ((transparente)) y
+se muestra como un espacio vacío en el documento.
+
+{{index "2d (canvas context)", "webgl (canvas context)", OpenGL, [canvas, context], dimensions, [interface, canvas]}}
+
+La etiqueta `` esta diseñada para permtir diferentes estilos de
+((dibujo)). Para tener acceso a una verdadera interfaz de dibujo,
+primero neceistamos crear un _((context))_, un objeto cuyos métodos proveen
+la interfaz de dibujo. Actualmente hay 2 estilos de dibujo ampliamente soportados
+: `"2d"` para gráficos en dos dimensiones y `"webgl"` para
+gráficos de tres dimensiones mediante la intefaz de OpenGL.
+
+{{index rendering, graphics, efficiency}}
+
+Este libro no abordará WebGL —nos limitaremos a dos dimensiones—. Pero si
+de verdad te interesan los gráficos tridimensionales, te recomiendo que
+investigues sobre WebGL. Provee una interfaz directa hacia hardware de
+gráficos y te permite renderizar escenarios complicados de forma
+eficiente usando JavaScript.
+
+{{index "getContext method", [canvas, context]}}
+
+Crea un ((contexto)) con el método `getContext` en el
+elemento `` del DOM.
+
+```{lang: "text/html"}
+Antes del canvas.
+
+Después del canvas.
+
+```
+
+Después de crear el objeto contexto, el ejemplo dibuja un
+((rectángulo)) rojo de 100 ((pixel))es de ancho y 50 pixeles de alto con su esquina superior izquierda
+en las coordenadas (10,10).
+
+{{if book
+
+{{figure {url: "img/canvas_fill.png", alt: "Un canvas con un rectángulo",width: "2.5cm"}}}
+
+if}}
+
+{{index SVG, coordinates}}
+
+Al igual que en HTML (y SVG), el sistema de coordenadas que usa el canvas
+coloca (0,0) en la esquina superior izquierda y el ((eje)) positivo y
+baja a partir de ahí. Así que (10,10) significa 10 pixeles debajo y a la derecha de
+la esquina superior izquierda.
+
+{{id fill_stroke}}
+
+## Líneas y superficies
+
+{{index filling, stroking, drawing, SVG}}
+
+En la interfaz del ((canvas)), una figura puede ser _rellenada_ dado
+un cierto color o diseño, o puede ser _delimtada_, que
+significa una ((línea)) dibujada en los bordes. La misma terminología aplica para SVG.
+
+{{index "fillRect method", "strokeRect method"}}
+
+El método `fillRect` rellena un ((rectángulo)). Usa primero las ((coordenadas)) `x` e
+`y` desde la esquina superior izquierda del rectángulo, después su dimensiones de ancho
+y alto. Un método parecido `strokeRect`, dibuja los ((bordes)) del rectángulo.
+
+{{index [state, "of canvas"]}}
+
+Ningún método toma parámetros adicionales. Tanto el color de relleno
+como el grueso del orden, no son determinados por el argumento
+del método (como podría esperarse normalmente) sino por las
+propiedades del contexto del objeto.
+
+{{index filling, "fillStyle property"}}
+
+La propiedad `fillStyle` controla La manera que se rellenan las figuras. Puede ser
+estableciendo una cadena que especifique un ((color)), usando la
+misma notación que en ((CSS)).
+
+{{index stroking, "line width", "strokeStyle property", "lineWidth property", canvas}}
+
+La propiedad `strokeStyle` funciona de forma similar, pero determinando el color
+usado por la línea. El ancho de dicha línea es determinado por la
+propiedad `lineWidth`, que puede ser cualquier número positivo.
+
+```{lang: "text/html"}
+
+
+```
+
+{{if book
+
+Este código dibuja dos cuadrados azules, usando un borde más delgado para el segundo.
+
+{{figure {url: "img/canvas_stroke.png", alt: "Dos cuadrados con borde",width: "5cm"}}}
+
+if}}
+
+{{index "default value", [canvas, size]}}
+
+Cuando no se especifican atributos `width` or `height` como en el ejemplo,
+el canvas asigna un valor por defecto de 300 pixeles de ancho y 150
+pixeles de alto.
+
+## Rutas
+
+{{index [path, canvas], [interface, design], [canvas, path]}}
+
+Una ruta es una secuencia de ((linea))s. La interfaz del canvas 2D
+usa una forma particular para describir dicha ruta. Usualmente se infieren.
+Las rutas no son valores que se puedan almacenar y usar.
+En su lugar, si quieres hacer algo con una ruta, debes
+hacer llamar a una secuencia de métodos para describir su figura.
+
+```{lang: "text/html"}
+
+
+```
+
+{{index canvas, "stroke method", "lineTo method", "moveTo method", shape}}
+
+Este ejemplo crea una ruta con un número de segmentos de ((líneas))
+horizontales y las une usando el método `stroke`. Cada segmento
+creado con `lineTo` empieza en la posición _actual_ de la ruta. Esa
+posición suele ser la última del segmento anterior, a menos que `moveTo` fuera
+llamada. En ese caso, the next segment would start at the position
+passed to `moveTo`.
+
+{{if book
+
+La ruta descrita por el programa anterior se ve así:
+
+{{figure {url: "img/canvas_path.png", alt: "Uniendo un número de líneas",width: "2.1cm"}}}
+
+if}}
+
+{{index [path, canvas], filling, [path, closing], "fill method"}}
+
+Cuando se llena una ruta (usando el método`fill`), cada ((figura)) es
+rellenada de forma separada. Una ruta puede contener múltiples figuras —cada movimiento `moveTo`
+comienza una nueva—. Pero la ruta debe _cerrarse_ (es decir, que empieza y termina en el mismo punto) antes de ser rellenada.
+Si la ruta no se ha cerrado, se agrega una linea desde el final hasta el
+principio, y la figura definida por la ruta será rellenada.
+
+```{lang: "text/html"}
+
+
+```
+
+Este ejemplo dibuja y rellena un triangulo. Nota que sólo dos de
+sus lados estan explícitamente dibujados. El tercero,
+de la esquina inferior derecha al vértice superior, está inferido y no debería estar ahí
+cuando definas la ruta.
+
+{{if book
+
+{{figure {url: "img/canvas_triangle.png", alt: "Rellenando una ruta",width: "2.2cm"}}}
+
+if}}
+
+{{index "stroke method", "closePath method", [path, closing], canvas}}
+
+También podrías usar el método `closePath` para cerrar una ruta de
+forma explícita agregando un segmento de ((linea)) de vuelta al inicio de la ruta.
+Este segmento _es_ dibujado cuando delineas la ruta.
+
+## Curvas
+
+{{index [path, canvas], canvas, drawing}}
+
+Una ruta puede contener ((linea))s ((curva))s. Desafortunadamente
+requieren algo más que dibujar.
+
+{{index "quadraticCurveTo method"}}
+
+El método `quadraticCurveTo` dibuja una curva dado un punto.
+Para determinar la curvatura de la linea, el método proporciona un ((punto de
+control)) que funciona como punto de destino. Imagina este punto de control como
+_ancla_ de la línea, dándole su curvatura. La línea no irá a través
+del punto de control, pero su dirección entre los puntos de inicio y cierre
+será como una línea recta en esa dirección que guía el punto de control. Veamos el siguiente ejemplo:
+
+```{lang: "text/html"}
+
+
+```
+
+{{if book
+
+Genera una ruta que se ve así:
+
+{{figure {url: "img/canvas_quadraticcurve.png", alt: "Una curva cuadrática",width: "2.3cm"}}}
+
+if}}
+
+{{index "stroke method"}}
+
+Dibujamos una ((curva cuadrática)) de la izquierda a la derecha, con la coordenada (60,10)
+como punto de control, y dibujamos dos segmentos de ((linea)) a través
+del punto de control y de regreso al principio de la línea. El resultado
+se asemeja a una insignia de _((Star Trek))_. Puedes ver el efecto
+del punto de control: las líneas empiezan en la esquina inferior
+y toman la dirección del punto de control y se ((curvan)) hacia
+el objetivo.
+
+{{index canvas, "bezierCurveTo method"}}
+
+El método `bezierCurveTo` dibuja un tipo de curva similar. En vez de
+un sólo ((punto de control)), este posee dos para cada uno
+de los vértices de la ((linea)). A continuación un ejemplo para
+ilustrar el comportamiento de la curva:
+
+```{lang: "text/html"}
+
+
+```
+
+Ambos puntos de control especifican la dirección en la que ambos terminan
+la curva. Mientras más lejos estén de los puntos de inicio correspondientes, más
+se "abultará" la curva en esa dirección.
+
+{{if book
+
+{{figure {url: "img/canvas_beziercurve.png", alt: "Una curva abultada",width: "2.2cm"}}}
+
+if}}
+
+{{index "trial and error"}}
+
+Dichas ((curva))s pueden ser difíciled de trabajar, dado que no siempre
+es posible encontrar los ((puntos de control)) que proporciona la ((figura)) que quieres
+dibujar. A veces puedes calcularlos, y otras debes encontrar
+el valor mediante prueba y error.
+
+{{index "arc method", arc}}
+
+El método `arc` es una manera de dibujar una linea que se curva en el
+borde de un circulo. Toma un par de ((coordenadas)) para el centro del arco, un
+radio, y un ángulo de inicio y un ángulo de fin.
+
+{{index pi, "Math.PI constant"}}
+
+Estos últimos dos parámetros hacen posible dibujar sólo parte del
+circulo. Los ((ángulo))s se miden en ((radian))es, no en ((grados)).
+Esto implica que un ((círculo)) tiene un ángulo de 2π, or `2 * Math.PI`,
+que es alrededor de 6.28. El ángulo comienza a contarse desde el
+punto a la derecha del centro del círculo y sigue el sentido de
+las manecillas del reloj.
+Puedes usar un inicio de 0 y con un final mayor que 2π (digamos, 7)
+para dibujar un círculo completo.
+
+```{lang: "text/html"}
+
+
+```
+
+{{index "moveTo method", "arc method", [path, " canvas"]}}
+
+La ilustración resultante muestra una ((línea)) desde la derecha del
+círculo (llamando primero a `arc`) hasta la derecha de la semiluna
+(segunda llamada). Al igual que otros métodos, una línea dibujada
+con `arc` esta relacionada con la ruta del segmento anterior.
+Puedes llamar a `moveTo` o empezar una nueva ruta para evitar esto.
+
+{{if book
+
+{{figure {url: "img/canvas_circle.png", alt: "Dibujando un círcuo",width: "4.9cm"}}}
+
+if}}
+
+{{id pie_chart}}
+
+## Dibujando una gráfica de pastel
+
+{{index "pie chart example"}}
+
+Imagina que tienes un ((trabajo)) en EconomiCorp, Inc., y tu
+primera tarea es dibujar una gráfica de pastel de los resultados
+de la ((encuesta)) de satifacción al cliente.
+
+En este caso `resultados` contiene un arreglo de objetos que
+representa las respuestas de las encuestas.
+
+```{sandbox: "pie", includeCode: true}
+const resultados = [
+ {name: "Satisfecho", count: 1043, color: "lightblue"},
+ {name: "Neutral", count: 563, color: "lightgreen"},
+ {name: "Insatisfecho", count: 510, color: "pink"},
+ {name: "No comentó", count: 175, color: "silver"}
+];
+```
+
+{{index "pie chart example"}}
+
+Para dibujar una gráfica de pastel, dibujamos un número de rebanadas, cada una hecha de
+un ((arco)) y un par de ((línea))s hacia el centro de dicho arco.
+Podemos calcular el ((ángulo)) de cada arco diviendo el círculo
+(2π) entre el total de respuestas y multiplicar el resultado por el
+(el ángulo por respuesta) por el numero de personas que seleccionaron una opción.
+
+```{lang: "text/html", sandbox: "pie"}
+
+
+```
+
+{{if book
+
+Lo anterior muestra la siguiente gráfica:
+
+{{figure {url: "img/canvas_pie_chart.png", alt: "Una gráfica de pastel",width: "5cm"}}}
+
+if}}
+
+Pero una gráfica que no indica que significa las secciones no es
+muy útil. Necesitamos mostrar texto en el ((canvas)).
+
+## Texto
+
+{{index stroking, filling, "fillStyle property", "fillText method", "strokeText method"}}
+
+El contexto de un dibujo en un canvas 2D proporciona los métodos
+`fillText` y `strokeText`. El útltimo es muy útil para delinear las
+letras, pero por lo general `fillText` es lo que usarás. Para el delinear el ((text)) con el `fillStyle` actual.
+
+```{lang: "text/html"}
+
+
+```
+
+Puedes específicar el tamaño, estilo, y ((fuente)) del texto con
+la propiedad `font`. Este ejemplo sólo muestra un tamaño de fuente
+y el nombre de la familia.
+También es posible agregar `italic` (cursiva) o `bold` (negrita)
+al principio de una cadena para darles un estilo.
+
+{{index "fillText method", "strokeText method", "textAlign property", "textBaseline property"}}
+
+Los últimos dos argumentos de `fillText` y `strokeText` indican la
+posición en la cuál se dibujan las fuentes. Por defecto, indican
+la posición del comienzo de la línea base del alfabeto del texto,
+que es la línea en las que las letras se apoyan, no se cuentan las
+letras con ganchos como la _j_ o la _p_. Puedes cambiar la
+propiedad `textAlign` a `"end"` (final) o `"center"` (centrar) y
+la posición vertical cambiando `textBaseline` a `"top"` (superior)
+, `"middle"` (en medio), o`"bottom"` (inferior).
+
+{{index "pie chart example"}}
+
+Regresaremos a nuestra gráfica de pastel, y el problema de ((etiquetar)) las
+secciones, en los [ejercicios](canvas#exercise_pie_chart) al final
+del capítulo.
+
+## Imágenes
+
+{{index "vector graphics", "bitmap graphics"}}
+
+En computación ((gráfica)), a menudo se distingue entre gráficos de _vectores_
+y gráficos de _mapa de bits_. Los primeros son los que hemos estado
+trabajando en este capítulo, especificando una imagen mediante la
+descripción lógica de sus ((figura))s. Los gráficos de mapa de bits,
+por otro lado, especifican figuras, pero funcionan con datos de pixeles
+(rejillas de puntos coloreados).
+
+{{index "load event", "event handling", "img (HTML tag)", "drawImage method"}}
+
+El método `drawImage` nos permite dibujar datos de ((pixel))es en
+un ((canvas)). Estos datos pueden originarse desde un elemento ` ` o
+desde otro canvas. El siguiente ejemplo crea un elemento ` `
+y carga un archivo de imagen en él. Pero no podemos empezar a
+de esta imagen porquen el navegador podría no haberla cargadao aún.
+Para lidiar con esto, registramos un `"load"` _event handler_
+y dibujamos después de que la imagen se ha cargado.
+
+```{lang: "text/html"}
+
+
+```
+
+{{index "drawImage method", scaling}}
+
+Por defecto, `drawImage` dibujará la imagen en su tamaño original.
+También puedes darle dos argumentos adicionales para definir
+ancho y alto distintos.
+
+Cuando `drawImage` recibe _nueve_ argumentos, puede usarse para
+dibujar solo un fragmento de la imagen. Del segundo al quinto argumentos
+indican el rectángulo (x, y, ancho y alto) en la imagen de origen
+que debe copiarse, y de los argumentos cinco a nueve indicen el
+otro (en el canvas) en donde serán copiados.
+
+{{index "player", "pixel art"}}
+
+Esto puede ser usado para empaquetar múltiples _((sprite))s_ (elementos de imagen)
+en una sola imagen y dibujar solo la parte que necesitas. Por ejemplo,
+tenemos una imagen con un personaje de un juego en múltiples
+((pose))s:
+
+{{figure {url: "img/player_big.png", alt: "Varias poses de un personaje",width: "6cm"}}}
+
+{{index [animation, "platform game"]}}
+
+Alternando las poses que dibujamos, podemos mostrar una animación
+en la que se vea nuestro personaje caminando.
+
+{{index "fillRect method", "clearRect method", clearing}}
+
+Para animar una ((imagen)) en un ((canvas)), el método `clearRect` es
+muy útil. Reutiliza `fillRect`, pero en vez de colorear el
+rectángulo, lo vuelve ((transparente)), quitando los pixeles
+previamente dibujados.
+
+{{index "setInterval function", "img (HTML tag)"}}
+
+Sabemos que cada _((sprite))_, cada subimagen, es de 24 ((pixele))s de ancho
+y 30 pixeles de alto. El siguiente código carga la imagen y establece
+un intervalo de tiempo para dibujar el siguiente ((frame)):
+
+```{lang: "text/html"}
+
+
+```
+
+{{index "remainder operator", "% operator", [animation, "platform game"]}}
+
+El valor `ciclo` rastrea la posición en la animación. Para cada
+((frame)), se incrementa y regresa al rango del 0 al 7 usando
+el operador del remanente. Entonces este valor es usado para
+calcular la coordenada en x que tiene el _sprite_ para la pose que
+tiene actualmente la imagen.
+
+## Transformaciones
+
+{{index transformation, mirroring}}
+
+{{indexsee flipping, mirroring}}
+
+¿Pero que pasa si quieremos que nuestro personaje camine a la izquierda
+en vez de la derecha? Podríamos dibujar otro conjunto de _sprites_... o podríamos
+decirle al ((canvas)) que redibuje la ilustración hacia el otro lado.
+
+{{index "scale method", scaling}}
+
+Llamar al método `scale` provocará que todo lo que dibujemos después sea escalado. Este método toma dos parámetros, uno para
+establecer la escala horizontal y otro para establecer la
+escala vertical.
+
+```{lang: "text/html"}
+
+
+```
+
+{{if book
+
+El resultado de llamar a `scale`, es que el círculo es dibujado con
+el triple de ancho y la mitad de alto.
+
+{{figure {url: "img/canvas_scale.png", alt: "Un círculo escalado",width: "6.6cm"}}}
+
+if}}
+
+{{index mirroring}}
+
+Escalar provoca que todo lo que se encuentre sobre la imagen, incluyendo el
+((ancho de línea)), y se ajustan de acuerdo a las instrucciones que se dieron.
+Escalar en una escala negativa dará vuelta a la figura. El giro
+sucede sobre la coordenada (0,0), lo que significa que también gira
+la dirección del sistema de coordinadas. Cuando el escalado
+horzontal es de -1 es aplicado, una figura en la posición 100
+terminará en lo que era la posición -100.
+
+{{index "drawImage method"}}
+
+Para girar una imagen, podemos sencillamente agregar `cx.scale(-1, 1)`
+antes de llamar `drawImage` porque eso movería nuestra figura
+fuera del ((canvas)), donde no será visible. Puedes ajustar
+las ((coordenadas)) dadas a `drawImage` para compensar que la
+la imagen se dibuja en la posición x -50 en vez de 0. Otra solución,
+que no requiere que el código que hace le dibujo necesite saber
+sobre el cambio de escala, es ajustar el ((eje)) sobre el que el
+escalado sucede.
+
+{{index "rotate method", "translate method", transformation}}
+
+Hay otros métodos además de `scale` que influencian el sistema
+de coordenadas de un ((canvas)). Puedes rotar las figuras de forma
+subsecuente con el método `rotate` y movelos con el método
+`translate`. Lo interesante —y confuso— de esto es que las
+transformaciones se _apilan_, lo que significa que cada una sucede
+de forma relativa a la transformación anterior.
+
+{{index "rotate method", "translate method"}}
+
+Entonces trasladando por 10 pixeles horizontales dos veces, todo de dibujará
+20 pixeles a la derecha. Si primero movemos el centro del sistema
+de coordenadas hacia (50,50) y lo rotamos por 20 ((grado))s (alrededor
+de 0.1π ((radian))es), la rotación sucederá _alredador_ del punto (50,50).
+
+{{figure {url: "img/transform.svg", alt: "Apilando transformaciones",width: "9cm"}}}
+
+{{index coordinates}}
+
+Pero si _primero_ rotamos por 20 grados _y entonces_ trasladamos
+(50,50), la traslación sucederá en el sistema de coordenadas rotadas
+y esto producirá una orientación distinta. El orden en el cual se
+aplican las transformaciones importa.
+
+{{index axis, mirroring}}
+
+Para voltear una imagen alrededor de la línea vertical dada una
+posición en x, podemos hacer lo siguiente:
+
+```{includeCode: true}
+function voltearHorizontalmente(context, around) {
+ context.translate(around, 0);
+ context.scale(-1, 1);
+ context.translate(-around, 0);
+}
+```
+
+{{index "flipHorizontally method"}}
+
+Recorremos el ((eje))-y donde queramor colocar el ((espejo)),
+aplicamos el espejeado, y regresamos el eje-y de regreso a su lugar
+en el universo espejeado. la sigiente imagen explica como funciona:
+
+{{figure {url: "img/mirror.svg", alt: "Espejeando sobre la línea vertical",width: "8cm"}}}
+
+{{index "translate method", "scale method", transformation, canvas}}
+
+Esto muestra el sistema de coordenadas antes y después de espejear
+atravesando la línea central. Los tríangulos están numerados para
+illustrar cada paso.
+Si dibujamos un triángulo en una posición x positiva, debería estar
+por defecto en el lugar donde se encuentra el tríangulo 1. Una
+llamada a `voltearHorizontalmente`
+realiza primero la traslación a la derecha, la cual nos da el
+triángulo 2. Cuando lo escala, voltea el triángulo hacia la
+posición 3. Esto no debería ser así, si espejeamos en la línea inicial.
+La segunda llamada a `translate` corrige esto, "cancelando" la
+traslación inicial y el triángulo 4 aparece donde debe.
+
+Ahora podemos dibujar un personaje en la posición (100,0) girando el
+universo alrededor del centro vertical de los personajes.
+
+```{lang: "text/html"}
+
+
+```
+
+## Almacenando y limpiando transformaciones
+
+{{index "side effect", canvas, transformation}}
+
+La transformaciones se mantienen. Todo lo que dibujemos después de
+((dibujar)) de nuestro personaje espejeado también puede ser
+espejeado. Eso puede ser un inconveniente.
+
+Es posible guardar el estado actual de la transformación, dibujar
+de nuevo y restaurar la transformación anterior. Usualmente esto
+es lo que debemos hacer para una función que necesite transformar
+de forma temporal el sistema de coordenadas. Primero, guardamos el
+código de la transformación que haya llamado a la función que estamos
+usando. La función hace lo suyo, agregando más transformaiones
+sobre la transformación actual. Finalmente, revertimos a la
+transformación con la que empezamos.
+
+{{index "save method", "restore method", [state, "of canvas"]}}
+
+Los métodos `save` y `restore` en el contexto del ((canvas)) 2D
+realizan el manejo de las ((transformaciones)). Conceptualmente
+mantienen una pila de los estados de la transformación. Cuando
+se llama `save`, el estado actual se agrega a la pila, y cuando se
+llama `restore`, el estado en la cima de la pila se usa en el
+contexto actual de la transformación. También puedes llamar
+`resetTransform` para resetear por completo la transformación.
+
+{{index "branching recursion", "fractal example", recursion}}
+
+La función `ramificar` en el siguiente ejemplo ilustra lo que puedes
+hacer con una función que cambia la transformación y llama una
+función (en este caso a sí misma), que continúa dibujando con una
+transformación dada.
+
+La función dibuja un árbol dibujando una línea, moviendo el centro
+del sistema de coordenadas hacia el final de la línea, y llamándose
+a sí misma rotándose a la izquierda y luego a la derecha.
+Cada cada llamada reduce el ancho de la rama dibujada, y la
+recursión se detiene cuando el ancho es menor a 8.
+
+```{lang: "text/html"}
+
+
+```
+
+{{if book
+
+El resultado es un simple fractal.
+
+{{figure {url: "img/canvas_tree.png", alt: "Una imagen recursiva",width: "5cm"}}}
+
+if}}
+
+{{index "save method", "restore method", canvas, "rotate method"}}
+
+Sí la llamada a `save` y `restore` no estuvieran, la segunda llamada
+recursiva a `ramificar` terminarían con la posición y rotación
+creados en la primera llamada. No se conectarían con la rama actual,
+excepto por las mas cercanas, la mayoría dibujadas en la primera
+llamada. La figura resultante sería interesante, pero no es un árbol definitivamente.
+
+{{id canvasdisplay}}
+
+## De regreso al juego
+
+{{index "drawImage method"}}
+
+Ahora que sabemos dibujar en el ((canvas)), es tiempo de empezar
+a trabajar en el sistema de ((_display_)) basado en el ((canvas))
+para el ((juego)) del [capítulo anterior](game). El nuevo display
+no mostrará sólo cajas de colores. En vez de eso, usaremos
+`drawImage` para dibujar imágenes que representen los elementos
+del juego.
+
+{{index "CanvasDisplay class", "DOMDisplay class", [interface, object]}}
+
+Definimos otro objeto del _display_ llamado `CanvasDisplay`,
+que soporta la misma interfaz que en `DOMDisplay` del [Capítulo
+?](game#domdisplay), los métodos `syncState` y `clear`.
+
+{{index [state, "in objects"]}}
+
+Este objeto posee algo más de información que `DOMDisplay`. En vez
+de usar la posición del _scroll_ de su elemento DOM, rastrea su propio
+((_viewport_)), que nos dice en que parte del nivel nos encontramos.
+Finalmente, hace uso de la propiedas `flipPlayer` de modo que
+incluso cuando el jugador se encuentra detenido, lo hace en la última
+dirección en que se movió.
+
+```{sandbox: "game", includeCode: true}
+class CanvasDisplay {
+ constructor(parent, level) {
+ this.canvas = document.createElement("canvas");
+ this.canvas.width = Math.min(600, level.width * scale);
+ this.canvas.height = Math.min(450, level.height * scale);
+ parent.appendChild(this.canvas);
+ this.cx = this.canvas.getContext("2d");
+
+ this.flipPlayer = false;
+
+ this.viewport = {
+ left: 0,
+ top: 0,
+ width: this.canvas.width / scale,
+ height: this.canvas.height / scale
+ };
+ }
+
+ clear() {
+ this.canvas.remove();
+ }
+}
+```
+
+El método `syncState` calcula primero un nuevo _viewport_ y después
+dibuja la escena del juego en la posición apropiada.
+
+```{sandbox: "game", includeCode: true}
+CanvasDisplay.prototype.syncState = function(state) {
+ this.updateViewport(state);
+ this.clearDisplay(state.status);
+ this.drawBackground(state.level);
+ this.drawActors(state.actors);
+};
+```
+
+{{index scrolling, clearing}}
+
+Contrario al `DOMDisplay`, este estilo de display _tiene que_ redibujar
+el fondo en cada _frame_. Esto se debe a que las figuras en un canvas
+son solo ((pixel))es, después de que los dibujamos no hay un método
+apropiado para movelos (o eliminarlos). La única forma de actualizar
+el canvas es limpiarlo y redibujar la escena. También podríamos desplazarlo,
+Lo que requiere que el fondo este en una posición diferente.
+
+{{index "CanvasDisplay class"}}
+
+El método `updateViewport` es similar al método `scrollPlayerIntoView`
+del método `DOMDisplay`. Comprueba si el jugador esta muy cerca
+del borde de la pantalla y mueve el ((_viewport_)) cuando asi sea el caso
+
+```{sandbox: "game", includeCode: true}
+CanvasDisplay.prototype.updateViewport = function(state) {
+ let view = this.viewport, margin = view.width / 3;
+ let player = state.player;
+ let center = player.pos.plus(player.size.times(0.5));
+
+ if (center.x < view.left + margin) {
+ view.left = Math.max(center.x - margin, 0);
+ } else if (center.x > view.left + view.width - margin) {
+ view.left = Math.min(center.x + margin - view.width,
+ state.level.width - view.width);
+ }
+ if (center.y < view.top + margin) {
+ view.top = Math.max(center.y - margin, 0);
+ } else if (center.y > view.top + view.height - margin) {
+ view.top = Math.min(center.y + margin - view.height,
+ state.level.height - view.height);
+ }
+};
+```
+
+{{index boundary, "Math.max function", "Math.min function", clipping}}
+
+Las llamadas a `Math.max` y `Math.min` aseguran que el _viewport_
+no termine mostrando espacio fuera del nivel.
+`Math.max(x, 0)` aseguramos que el resultado sea mayor a cero.
+`Math.min` hacer algo similar al garantizar que un valor se mantenga
+por debajo de lo indicado.
+
+Cuando se ((limpia)) el _display_, usamos un ((color)) ligeramente
+distinto dependiendo si el jugador ganó (más claro) o perdió (más oscuro).
+
+```{sandbox: "game", includeCode: true}
+CanvasDisplay.prototype.clearDisplay = function(status) {
+ if (status == "won") {
+ this.cx.fillStyle = "rgb(68, 191, 255)";
+ } else if (status == "lost") {
+ this.cx.fillStyle = "rgb(44, 136, 214)";
+ } else {
+ this.cx.fillStyle = "rgb(52, 166, 251)";
+ }
+ this.cx.fillRect(0, 0,
+ this.canvas.width, this.canvas.height);
+};
+```
+
+{{index "Math.floor function", "Math.ceil function", rounding}}
+
+Para dibujar el fondo, hacemos que los mosaicos sean visibles en el
+_viewport_ actual, usando el mismo truco que en el método `touches`
+del [capítulo anterior](game#touches).
+
+```{sandbox: "game", includeCode: true}
+let otherSprites = document.createElement("img");
+otherSprites.src = "img/sprites.png";
+
+CanvasDisplay.prototype.drawBackground = function(level) {
+ let {left, top, width, height} = this.viewport;
+ let xStart = Math.floor(left);
+ let xEnd = Math.ceil(left + width);
+ let yStart = Math.floor(top);
+ let yEnd = Math.ceil(top + height);
+
+ for (let y = yStart; y < yEnd; y++) {
+ for (let x = xStart; x < xEnd; x++) {
+ let tile = level.rows[y][x];
+ if (tile == "empty") continue;
+ let screenX = (x - left) * scale;
+ let screenY = (y - top) * scale;
+ let tileX = tile == "lava" ? scale : 0;
+ this.cx.drawImage(otherSprites,
+ tileX, 0, scale, scale,
+ screenX, screenY, scale, scale);
+ }
+ }
+};
+```
+
+{{index "drawImage method", sprite, tile}}
+
+Los mosaicos que no están vacíos se dibujan con `drawImage`. La
+imagen `otherSprites` contiene las imagenes usadas para los elementos
+distintos al jugador. Contiene, de izquierda a derecha, el
+mosaico del muro, el mosaico de lava, y el _sprite_ de una moneda.
+
+{{figure {url: "img/sprites_big.png", alt: "Sprites para nuestro juego",width: "1.4cm"}}}
+
+{{index scaling}}
+
+Los mosaicos del fondo son de 20 por 20 pixeles dado que usaremos
+la misma escala que en `DOMDisplay`. Así, el _offset_ para el
+mosaico de lava es de 20 (el valor encapsulado de `scale`), y
+el _offset_ para el de muro es de 0.
+
+{{index drawing, "load event", "drawImage method"}}
+
+No hace falta quedarse esperando a que carge el _sprite_ de la imagen.
+Llamar a `drawImage` con una imagen que aún no ha sido cargada,
+simplemente no hace anda. Aun así, podría fallar en dibujar el luego
+de forma adecuada durante los primeros ((_frame_))s, mientras la
+imagen siga cargádose, pero esto no es un problema. Mietras sigamos
+actualizando la pantalla, la escena correcta aparecerá tan pronto
+la imagen termine de cargarse.
+
+{{index "player", [animation, "platform game"], drawing}}
+
+El personaje ((caminante)) mostrado antes será usado para representar al
+jugador. El código que lo dibuja necesita escoger el ((sprite)) correcto y la
+dirección basados en el movimiento actual del jugador. Los primeros ocho
+_sprites_ contienen una animación de caminata. Cuando el jugador se mueve sobre
+el suelo, los pasamos conforme al tiempo actual. Como queremos
+cambiar _frames_ cada 60 millisegundos, entonces el ((tiempo)) es dividido entre 60
+ṕrimero. Cuando el jugador se detiene, dibujamos el noveno _sprite_.
+Durante los saltos, que reconoceremos por el hecho de que la velocidad vertical
+no es cero, usaremos el décimo _sprite_.
+
+{{index "flipHorizontally function", "CanvasDisplay class"}}
+
+Ya que los ((_sprite_))s son ligeramente más anchos que el jugador
+—24 píxeles en vez de 16 para permitir algo de espacio para
+pies y brazos— tenemos que ajustar las coordenadas en x y el ancho por el cantidad dada por (`playerXOverlap`).
+
+```{sandbox: "game", includeCode: true}
+let playerSprites = document.createElement("img");
+playerSprites.src = "img/player.png";
+const playerXOverlap = 4;
+
+CanvasDisplay.prototype.drawPlayer = function(player, x, y,
+ width, height){
+ width += playerXOverlap * 2;
+ x -= playerXOverlap;
+ if (player.speed.x != 0) {
+ this.flipPlayer = player.speed.x < 0;
+ }
+
+ let tile = 8;
+ if (player.speed.y != 0) {
+ tile = 9;
+ } else if (player.speed.x != 0) {
+ tile = Math.floor(Date.now() / 60) % 8;
+ }
+
+ this.cx.save();
+ if (this.flipPlayer) {
+ voltearHorizontalmente(this.cx, x + width / 2);
+ }
+ let tileX = tile * width;
+ this.cx.drawImage(playerSprites, tileX, 0, width, height,
+ x, y, width, height);
+ this.cx.restore();
+};
+```
+
+El método `drawPlayer` es llamado por `drawActors`, que es
+responsable de dibujar todos los involucrados en el juego.
+
+```{sandbox: "game", includeCode: true}
+CanvasDisplay.prototype.drawActors = function(actors) {
+ for (let actor of actors) {
+ let width = actor.size.x * scale;
+ let height = actor.size.y * scale;
+ let x = (actor.pos.x - this.viewport.left) * scale;
+ let y = (actor.pos.y - this.viewport.top) * scale;
+ if (actor.type == "player") {
+ this.drawPlayer(actor, x, y, width, height);
+ } else {
+ let tileX = (actor.type == "coin" ? 2 : 1) * scale;
+ this.cx.drawImage(otherSprites,
+ tileX, 0, width, height,
+ x, y, width, height);
+ }
+ }
+};
+```
+
+Cuando se trata de ((dibujar)) algo que no es el ((jugador)), nos fijamos en
+el tipo de objeto que es para encontrar el _offset_ del _sprite_ correcto.
+El mosaico de ((lava)) se encuentra en un _offset_ de 20, y el _sprite_
+de ((moneda)) se encuentra en 40 (dos veces `scale`).
+
+{{index viewport}}
+
+Debemos restar la posición del viewport cuando calculamos la posición
+de los involucrados desde la posición (0,0) en nuestro ((canvas))
+correspondiente a la esquina superior izquierda del viewport,
+no la esquina superior izquierda del nivel. También podemos hacer
+uso de `translate` para esto. Ambos métodos funcionan.
+
+{{if interactive
+
+Este documento se enlaza con el nuevo display en `runGame`:
+
+```{lang: "text/html", sandbox: game, focus: yes, startCode: true}
+
+
+
+```
+
+if}}
+
+{{if book
+
+{{index [game, screenshot], [game, "with canvas"]}}
+
+Con eso terminamos el nuevo sistema de ((display)). El luego resultante
+luce como algo así:
+
+{{figure {url: "img/canvas_game.png", alt: "El juego se muestra en el canvas",width: "8cm"}}}
+
+if}}
+
+{{id graphics_tradeoffs}}
+
+## Escogiendo una interfaz gráfica
+
+Cuando se necesita generar gráficos en el navegador, se puede escoger
+entre HTML plano, ((SVG)), y ((canvas)). No existe un enfoque que
+funcione mejor en cualquier situación. Cada opción tiene sus pros
+y sus contras.
+
+{{index "text wrapping"}}
+
+El HTML plano tiene la ventaja de ser simple. También puede integrar
+((texto)). Tanto el SVG como el canvas permiten dibujar texto, pero
+no te ayudarán si necesitas cambiar la posición o acomodarlo cuando
+necesites más de una línea. En una imagen basada en HTML es mucho
+más fácil incluir bloques de texto.
+
+{{index zooming, SVG}}
+
+SVG puede usarse para generar ((gráficos)) ((claros)) que se ven
+bien con cualquier nivel de zoom. a diferencia del HTML, está diseñado
+para dibjar y es más adecuado a para ese propósito.
+
+{{index [DOM, graphics], SVG, "event handling", ["data structure", tree]}}
+
+Tanto SVG como HTML contienen una estrucura de datos (el DOM) que
+representa tu imagen. Esto hace posible modificar elementos después
+después de que son dibujados. Si necesitas cambiar de forma repetida
+una pequeña parte de una ((imagen)) grande como respuesta a lo que
+el usuario este haciendo o como parte de una ((animación)), hacerlo
+en un canvas puede ser innecesariamente difícil.
+El DOM también nos permite registrar los _event handlers_ del mouse
+en cada elemento en la imagen (incluso en figuras dibujadas en SVG), cosa que no se puede hacer con el canvas.
+
+{{index performance, optimization}}
+
+Pero el enfoque orientado a ((pixeles)) del ((canvas)) puede ser una ventaja
+cuando se trata de dibujar un gran número de elementos pequeños.
+El hecho de que no posea una estructura de datos sino únicamente de
+dibujar de forma repetida sobre la misma superficie de pixeles le
+da al canvas un costo menor por figura.
+
+{{index "ray tracer"}}
+
+También se pueden agregar efectos, como renderizar una escena con un pixel
+a la vez (por ejemplo, usando trazado de rayos) o postprocesar una
+imagen con JavaScript (agregando _blur o distorsionándola_), que
+puede hacerse de forma realista usando un enfoque basados en pizeles.
+
+En algunso casos, podrías intentar combinar varias de estas técnicas.
+Por ejemplo, podrías dibujar un ((gráfico)) con ((SVG)) o ((canvas)) pero
+mostral información con ((texto)) posicionando un elemnto HTML en
+la parte superior de la imagen.
+
+{{index display}}
+
+Para aplicaciones de baja demanda, no importa mucho que interfaz
+escogas. El display que construimos para nuestro juego en este
+capítulo podría haberse hecho implementando cual sea de estas tres
+tecnologías de ((gráficos)) dado que no necesitamos dibujar texto,
+manejar interacciones del mouse o trabajar con un numero de elementos
+extraordinariamente grande.
+
+## Resumen
+
+En este capítulo discutimos técnicas para dibujo de gráficos en el
+navegador, enfoncándonos en el elemento ``.
+
+Un nodo de canvas representa un área en un documento en el que nuestro
+programa puede dibujar. Este dibujo se hace a través de objetos de
+contexto de dibujo, usando el método `getContext`.
+
+La interfaz de dibujo 2D nos permite rellenar y delineas varias figuras.
+La propiedad `fillStyle` del contexto determina como las figuras son rellenadas.
+Las propiedades `strokeStyle` y `lineWidth` controlan la manera en
+que las líneas se dibujan.
+
+Los rectángulos y textos se pueden dibujar con una simple llamada de método.
+Los métodos `fillRect` y `strokeRect` dibujan rectángulos y los
+métodos `fillText` y `strokeText` dibujan texto. Para crear
+figuras a medida, primero debemos crear una ruta.
+
+{{index stroking, filling}}
+
+Llamar a `beginPath` empieza una nueva ruta. Otra serie de métodos
+agregan líneas y curvas a la ruta actual. Por ejemplo `lineTo`
+puede dibujar una línea reacta. Cuando la ruta de termina, puede
+rellenarse con el método `fill` o delinearse con el método `stroke`.
+
+Mover pixeles desde una imagen o desde un canvas a otro puede hacerse
+con el método `drawImage`. Por defecto, este método dibuja la imagen
+fuente completa, pero dándole parámetros, puedes copiar un área
+específica de la imagen. La usamos para nuestro juego copiando poses
+individuales del personajes salidas de una imagen que contiene
+muchas poses.
+
+Las transformaciones te permiten dibujar una figura en múltiples orientaciones
+un contexto de dibujo 2D tiene transformaciones que se pueden usar
+con los métodos `translate`, `scale` y `rotate`. Estos afectarán
+todas las operaciones de dibujo subsecuentes. El estado de una
+transformación se puede guardar con el método `save` y restaurar
+con el método `restore`.
+
+Cuando se muestra una animación en un canvas, el método `clearRect`
+puede usarse para limpiar parte del canvas antes de redibujarlo.
+
+## Ejercicios
+
+### Figuras
+
+{{index "shapes (exercise)"}}
+
+Escribe un programa que dibuje las siguientes ((figura))s en un ((canvas)):
+
+{{index rotation}}
+
+1. Un ((trapezoide)) (un ((rectángle)) que es más inclinado de un lado).
+
+2. Un ((diamante)) rojo (un rentángulo rotado 45 grados o ¼π radianes).
+
+3. Una ((línea)) zigzaggeada.
+
+4. Una ((espiral)) hecha de 100 segmentos de línea.
+
+5. Una ((estrella)) amarilla.
+
+{{figure {url: "img/exercise_shapes.png", alt: "Las figuras a dibujar",width: "8cm"}}}
+
+Cuando dibujes las últimas dos, quizás te interese ver las explicaciones
+de `Math.cos` y `Math.sin` en el [capítulo ?](dom#sin_cos), que
+describe como obtener coordenadas en un círculo usando estas funciones.
+
+{{index readability, "hard-coding"}}
+
+Recomiendo crear una función para cada figura. Pasa la prporción y
+optionalmente otras propiedades como el tamaño o el número de puntos
+como parámetros. La alternativa, que requiere escribir una numerología
+complicada, tiende a hacer el código innecesariamente difícil de
+leer y modificar.
+
+{{if interactive
+
+```{lang: "text/html", test: no}
+
+
+```
+
+if}}
+
+{{hint
+
+{{index [path, canvas], "shapes (exercise)"}}
+
+El ((trapezoide)) (1) es el más sencillo de dibujar usando una ruta.
+Escoge unas coordenadas para el centro y agrega una de las esquinas
+alrededor del centro.
+
+{{index "flipHorizontally function", rotation}}
+
+El ((diamante)) (2) puede dibujarse de la forma simple, con una ruta,
+o de la forma interesante, con una ((transformación)) `rotate`.
+Para usar rotación, tendrás que usar un truco similar al que usamos
+con la función `voltearHorizontalmente`. Ya que lo que se quiere
+es rotar alrededor del centro de su rectángulo y no alrededor del
+punto (0,0), deberías primero usar `translate` ahí, luego rotar, y
+trasladar de regreso.
+Asegúrate de reiniciar la transformación después de dibujar cualquier
+figura que se haya creado.
+
+{{index "remainder operator", "% operator"}}
+
+Para el ((zigzag)) (3) se vuelve impráctico escribir una nueva llamada
+a `lineTo` para cada línea de segmento. En vez de eso, deberías
+usar un ((loop)). Puedes tener una iteración de dibujo por cada dos
+segmentos de ((línea))s (derecha y luego izquierda de nuevo) o uno,
+en cuyo caso deberías usar el operador (`% 2`) del índice del loop
+para determinar la dirección a la derecha o a la izquierda.
+
+También necesitarás usar un loop para el ((espiral)) (4). Si dibujas
+una serie de puntos, con cada punto moviéndose en un círculo alrededor
+del centro de la espiral, obtienes un círculo. Si durante el loop
+varías el radio del círculo en el que colocas el punto y lo repites,
+el resultado es una espiral.
+
+{{index "quadraticCurveTo method"}}
+
+La ((estrella)) (5) se puede dibujar a partir de las líneas de `quadraticCurveTo`.
+También podrías dibujar una con líneas gruesas. Divide un círculo
+en ocho piezas para una estrella de ocho puntos, o cuantas piezas
+quieras. Dibuja líneas entre estos puntos, haciéndolas curvas alrededor
+del centro de la estrella. Con `quadraticCurveTo`, puedes hacer uso
+del centro como punto de control.
+
+hint}}
+
+{{id exercise_pie_chart}}
+
+### La gráfica de pastel
+
+{{index label, text, "pie chart example"}}
+
+[Anteriormente](canvas#pie_chart) en este capítulo, vimos el ejemplo
+de un programa que dibuja una gráfica de pastel. Modifica este programa
+de forma que el nombre de cada categoría este al lado de la sección
+que representa. Trata de encontrar una forma que se posicione automáticamente
+de forma adecuada que funcione con otros conjuntos de datos. Puedes
+asumir que esas categorías son lo suficientemente amplias para las etiquetas.
+
+Podrías necesitar `Math.sin` y `Math.cos` de nuevo, las cuales se
+describen en el [Capítulo ?](dom#sin_cos).
+
+{{if interactive
+
+```{lang: "text/html", test: no}
+
+
+```
+
+if}}
+
+{{hint
+
+{{index "fillText method", "textAlign property", "textBaseline property", "pie chart example"}}
+
+Necesitarás llamar `fillText` y establecer el contexto de `textAlign`
+y las propiedades de `textBaseline` de manera que el texto termine
+donde quieres.
+
+Una manera sensible de posicionar las etiquetas podría ser poner el
+texto en la línea desde el centro de la gráfica a través de la mitad
+de la sección.
+No queremos que el texto quede directamente al lado de la gráfica,
+sino moverlo al lado de la gráfica por unos cuantos píxeles.
+
+El ((ángulo)) de está línea es `currentAngle + 0.5 * sliceAngle`.
+El siguiente código encuentra una posición en esta línea 120 píxels
+desde el centro:
+
+```{test: no}
+let middleAngle = currentAngle + 0.5 * sliceAngle;
+let textX = Math.cos(middleAngle) * 120 + centerX;
+let textY = Math.sin(middleAngle) * 120 + centerY;
+```
+
+Para `textBaseline`, el valor `"middle"` es muy apropiado cuando
+se quiere usar este enfoque. Para lo que se use `textAlign` depende
+de que lado del círculo este. A la izquierda, deberá ser `"right"`, a la derecha, deberá ser `"left"`, para que el texto se coloque lejos de la gráfica.
+
+{{index "Math.cos function"}}
+
+Si no estamos seguros de como encontrar el lado del círculo dado
+un ángulo, mira la explicación de `Math.cos` en el [Capítulo
+?](dom#sin_cos). El coseno de un ángulo nos dice en que coordenada
+en x le corresponde para saber exactamente en que lado del círculo
+nos encontramos.
+
+hint}}
+
+### Un balón botador
+
+{{index [animation, "bouncing ball"], "requestAnimationFrame function", bouncing}}
+
+Usar la técnica de `requestAnimationFrame` que vimos en el [Capítulo
+?](dom#animationFrame) y [Chapter ?](game#runAnimation) para dibujar una
+((caja)) con un ((balón)) botando en el. El balón se mueve a una
+((velocidad)) constante y bota fuera de la caja cuando golpea un borde de la caja.
+
+{{if interactive
+
+```{lang: "text/html", test: no}
+
+
+```
+
+if}}
+
+{{hint
+
+{{index "strokeRect method", animation, "arc method"}}
+
+Una ((caja)) es fácil de dibujar con `strokeRect`. Define los bordes
+para su tamaño o define dos bordes si el ancho y largo de la caja
+son distintos. Para crear el ((balón)), empieza una ruta y llama
+`arc(x, y, radius, 0, 7)`, que crea un arco desde cero hasta algo
+más de un círculo entero. Entonces rellena la ruta.
+
+{{index "collision detection", "Vec class"}}
+
+Para modelar la posición y ((velocidad)), puedes usar la clase `Vec`
+del [Capítulo ?](game#vector)[ (que está disponible en está página
+)]{if interactive}. Dada una velocidad inicial, preferentemente uno
+que no es puramente vertical o horizontal, y para cada ((frame))
+multiplica esa velocidad por el monto de tiempo que transcurra.
+Cuando el balón esté cerca de un muro vertical, invierte el componente x
+en su velocidad. De manera similar, invierte el componente y cuando
+golpee un muro horizontal.
+
+{{index "clearRect method", clearing}}
+
+Después de encontrar la nueva posición y velocidad del balón, usa
+`clearRect` para borrar la escena y redibujarla usando la nueva posición.
+
+hint}}
+
+### Reflejo precalculado
+
+{{index optimization, "bitmap graphics", mirror}}
+
+Una cosa desafortunada sobre la ((transformacion))es que ralentizan
+el dibujado de mapa de bits. La posición y tamaño de cada ((pixel))
+tiene que ser transformada e incluso es posible que los ((navegador))es
+estén listos para la transformación en el ((futuro)), actualmente
+causa un incremento considerable en el tiempo que toma dibujar un
+mapa de bits.
+
+En un juego como el nuestro, donde dibujamos un simple sprite transformado,
+esto no es un gran problema. Pero imagina que necesitamos dibujar
+cientos de personajes o miles de partículas rotatorias de una explosión.
+
+Piensa en una forma de permitirnos dibujar personajes sin cargar
+imágenes adiciones y sin tener que transformar las llamadas de
+`drawImage` en cada frame.
+
+{{hint
+
+{{index mirror, scaling, "drawImage method"}}
+
+La clave de la solución es el hecho de que podemos hacer uso de un elemento
+((canvas)) como fuente de la imagen cuando usemos `drawImage`. Es
+posible crear un elemento `` sin agregarlo al documento
+y dibujar nuestros sprites invertidos en ello. Cuando dibujamos un
+frame, en realidad solo copiamos los sprites invertidos al canvas principal.
+
+{{index "load event"}}
+
+Podríamos necesitar algunas precauciones para evitar que las imágenes
+se carguen de forma instantánea. Hacemos el dibujo invertido una
+sola vez, y si lo hacemos antes de que cargue la imagen, no dibujará nada.
+Un handler `"load"` en la imagen puede usarse para dibujar imágenes
+invertidas en el canvas extra. Este canvas puede ser usado como una
+imagen fuente (solo aparecerá en blanco hasta que dibujemos un
+personaje en él).
+
+hint}}
+