Compartir tecnología de lienzo

Introducción al lienzo.

Antes de aprender una nueva tecnología, comprender el desarrollo histórico y las causas de esta tecnología nos ayudará a comprender esta tecnología más profundamente.

Históricamente, Apple Inc. propuso por primera vez el lienzo para crear un componente de panel de control en el kit web de Mac OS X. Antes de que el lienzo se llamara HTML draft and standard, utilizamos algunos métodos alternativos para dibujar, como ser criticado. Flash y SVG muy potente (Gráficos vectoriales escalables, marcado de vectores escalables) y VML (Lenguaje de marcado de vectores, marcado de vectores) que solo se pueden usar en IE (IE 5.0 y superior). Incluso algunos front-end pueden usar div + css para completar el dibujo.

En general, cuando no hay un lienzo, dibujar gráficos en el navegador es más complicado, y después de la aparición del lienzo, dibujar gráficos en 2D es relativamente fácil.

NOTA: Use div para dibujar algunos gráficos simples, como rectángulo, círculo, triángulo, trapecio, pero no es tan complicado.

Pero el lienzo también tiene desventajas. Debido a que es un lienzo con la naturaleza de la correspondiente resolución de imágenes digitales de tela , está condenada en diferentes resoluciones, cuando el contenido de la pantalla lienzo de dibujo será diferente. Además, el contenido de dibujo tela no pertenece a ningún elemento DOM , el espectador navegador elemento no puede encontrar que no puede detectar un clic del ratón sobre un lienzo en el que el contenido, es evidente que estos dos aspectos, no son tan buenos como lienzo SVG De

Por ejemplo: si usa CSS para establecer el tamaño del elemento del lienzo, puede hacer que los gráficos dibujados se distorsionen, como rectangular a cuadrado, circular a elipse, etc. Esto se debe a que el tamaño del lienzo y el tamaño del elemento son diferentes Se adaptará automáticamente al tamaño del elemento. Si los dos son proporcionales, el lienzo se escalará proporcionalmente sin distorsión.

De esta manera, el lienzo tiene defectos tan obvios, ¿es mejor usar SVG directamente?

No, ¿has escuchado una palabra? No existe una solución perfecta, solo adecuada.

SVG se basa en XML, lo que significa que los elementos en SVG se pueden considerar elementos DOM y se puede habilitar la operación DOM. Al mismo tiempo, cada imagen dibujada en SVG se considera un objeto. Reproduce gráficos automáticamente.

Lo anterior son las ventajas de SVG, pero a través de esta ventaja, también podemos encontrar algunos problemas:

  1. Por lo general, las aplicaciones que usan en exceso DOM se volverán muy lentas, por lo que SVG complejo causará un procesamiento lento. Pero para aplicaciones como mapas, SVG es la primera opción.
  2. La reorganización del navegador ocurre cuando la ventana del navegador cambia, la posición del tamaño del elemento cambia, la fuente cambia, etc.
  3. Incluso si las operaciones DOM se pueden habilitar, el costo de las operaciones DOM sigue siendo relativamente costoso (DOM y JS se implementan por separado).

De vuelta al tema.

2D lona gráficos se dibuja a través de JavaScript, y <canvas>la etiqueta en sí no es el dibujo ningún poder, es sólo un contenedor. Al dibujar, el lienzo se representa píxel por píxel. Una vez que se dibujan los gráficos, el navegador deja de preocuparse por el elemento (el guión está terminado y los gráficos dibujados no forman parte del DOM).

Vale la pena señalar que el estándar HTML (estándar whatwg ) establece claramente: los autores no deben usar el canvaselemento en un documento cuando hay un elemento más adecuado disponible , por lo tanto, no abuse del elemento.

lienzo es ahora casi toda la ayuda de los navegadores, pero las versiones anteriores de Internet Explorer 9.0 no es compatible con canvaselementos

Uso básico del lienzo.

El lienzo es un elemento HTML, por lo que para usar el lienzo, primero debe:

<canvas id="canvas" width="600" height="300">
    当前浏览器不支持canvas
</canvas>

En la primera línea de código HTML, puede ver dos atributos: widthe heightindica el ancho y la altura del lienzo. Como se mencionó anteriormente, no use CSS para especificar el tamaño, porque cuando la proporción de CSS y el tamaño del lienzo son inconsistentes No se puede escalar proporcionalmente, lo que resulta en gráficos distorsionados. Cuando no se establece el tamaño del lienzo, el lienzo se inicializará en un lienzo de 300 px * 150 px de forma predeterminada.

"El navegador actual no es compatible con el lienzo" es el contenido del elemento, pero solo se usa como contenido de reserva (es decir, contenido de reserva ). Este contenido se mostrará solo cuando el navegador no sea compatible con el lienzo.

El elemento de lienzo en sí no tiene capacidad de dibujo, pero solo sirve como contenedor, por lo que debe dibujarse a través de un script como JavaScript:

const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');

El código HTML + JS anterior es necesario para usar el lienzo, sin importar qué contenido dibujar, estas pocas líneas de código son indispensables.

getContext()Es un método proporcionado por el elemento de lienzo para obtener el contexto de dibujo (o el contexto de representación). Solo tiene un parámetro: el formato de contexto. Pasar aquí 2dsignifica obtener un entorno de dibujo de imágenes 2D. Dado que getContextes un método proporcionado por el elemento de lienzo, podemos getContextverificar el soporte del navegador al detectar la existencia del método.

El tipo de variable de contexto es CanvasRenderingContext2D.

El contexto de renderizado no es fácil de entender, puede entenderse como un pincel para dibujar.

¿Cómo determinar la posición de dibujo en el lienzo? Es las coordenadas.

En el lienzo, la esquina superior izquierda del lienzo es el origen, el eje horizontal es el eje x para el ancho y el eje vertical es el eje y para la altura [^ 1]. La posición del origen se puede mover. No consideraremos el movimiento del origen por el momento.

En la escuela w3c , la API de dibujo proporcionada por canvas se divide aproximadamente en los siguientes tipos [^ 2]:

  1. Color, estilo, sombra
  2. Estilo de línea
  3. Rectángulo
  4. Camino
  5. Convertir
  6. Texto
  7. Representación de imagen
  8. Operación de píxeles
  9. Síntesis
  10. Otros

Ejemplo de combinación de lienzo

En el ejemplo anterior, contiene rectángulos, círculos, líneas, texto y "texto". En detalle, involucrará muchas API, lo que hará que este artículo sea muy largo y no es necesario. Vale la pena uno. Se menciona la curva de Bézier, que es la curva matemática de la aplicación de gráficos bidimensionales. El software general de gráficos vectoriales la utiliza para dibujar con precisión la curva. La curva de Bézier es una curva de parámetros muy importante en gráficos de computadora 3]

Curva de Bezier de primer orden

Curva de Bezier cuadrática

Curva bezier cúbica

Las imágenes de arriba son curva de Bézier de primer orden, curva de Bézier de segundo orden y curva de Bézier de tercer orden en orden. De la figura, se puede ver claramente que la curva de Bezier de una sola vez es en realidad una línea recta. Por supuesto, hay curvas de orden superior, pero el lienzo solo proporciona curvas Bezier cuadráticas y cúbicas.

Tome la API de la curva de Bezier cuadrática como ejemplo:

quadraticCurveTo(cp1x, cp1y, x, y);

(cp1x, cp1y) representa las coordenadas del punto de control, (x, y) representa las coordenadas del punto final. Todavía falta una coordenada de punto de partida, suponiendo que sea (x0, y0), ¿quién es este (x0, y0)?

Está llamando a quadraticCurveTouna función, contexto en el que las coordenadas (contexto dibujo). Por ejemplo:

var cxt = canvas.getContext('2d'); // 认为canvas已经获取到
cxt.beginPath();
cxt.moveTo(120, 90);
cxt.quadraticCurveTo(130, 80, 130, 70);
cxt.quadraticCurveTo(115, 70, 115, 50);
cxt.quadraticCurveTo(115, 30, 155, 30);
cxt.quadraticCurveTo(195, 30, 195, 50);
cxt.quadraticCurveTo(195, 70, 155, 70);
cxt.quadraticCurveTo(135, 90, 120, 90);
cxt.stroke();

El resultado de ejecutar este código es un cuadro de diálogo (representado en la primera imagen). Como puede ver, antes de llamar a la curva de Bezier cuadrática, establecemos el punto de partida, es decir, mover el pincel a las coordenadas (120, 90 ), En llamadas posteriores, el punto final de la curva de Bezier anterior se utiliza como punto de partida de esta curva.

En este momento, algunas personas pueden preguntar: ¿No moveTopuedo dibujar si elimino esta llamada? Si se llama a la lineTofunción posterior , realmente no se puede dibujar. Pero no olvide, hay otra curva de Bezier, esta es una línea recta, él es una línea recta con (cp1x, cp1y) como punto de partida y (x, y) como punto final. Entonces, moveTodespués de eliminarlo , solo afectará el dibujo de la primera curva. Pero si elimina la última línea de código stroke(), no verá nada en el navegador cuando finalice el programa.

A partir de esto, debemos pensar en otra pregunta: ¿por qué es stroke()necesaria una función?

De hecho, el lienzo es un dibujo basado en estado, de acuerdo con esto, las API proporcionadas por el lienzo se pueden dividir en dos tipos: configuración de estado y dibujo específico.

stroke(), fill()Etc. La función es dibujar el contenido en el contenedor del lienzo del lienzo.

arc(), lineTo(), rect()Y otras funciones se proporciona una función del estado de la brocha.

En esa película o serie de televisión de tipo fantasía, a menudo se puede ver un símbolo de vacío taoísta. Después de dibujar, empujarlo hacia adelante y se imprimirá en el símbolo o persona correspondiente.

Símbolo vacío taoísta, este proceso es como el proceso de establecer el estado del pincel del lienzo.

Empuje hacia adelante, este es el dibujo específico, no sabemos cómo dibujar, de todos modos, se dibuja este símbolo. (Mencionado antes, la lona es un pixel por pixel de representación de)

Dibujo de "texto", tenga en cuenta que este texto está citado, texto ordinario, solo necesitamos llamar al dibujo fillText(), y el texto aquí se refiere a la fuente de matriz de puntos , en programas como un solo chip o LCD, mediante iluminación Una serie de puntos muestra texto o patrones. El proceso de iluminación es más complicado. Se puede entender simplemente que el píxel en la pantalla LCD se ilumina cuando el píxel se establece en 1, y no se ilumina cuando es 0 (lo real puede ser lo contrario). Entonces, el dibujo de "texto" en el lienzo es el mismo. Al establecer una biblioteca de fuentes correspondiente al texto, cuando se necesita dibujar cierto texto, encuentre la matriz de puntos de texto correspondiente en la biblioteca de fuentes y luego marque la matriz de puntos como 1. La posición está iluminada (llena).

En la operación real, puede que no sea tan fácil de iluminar. Es posible que desee hacer un contenido más fresco, llenarlo con un círculo, llenarlo con un rectángulo o incluso decir que desea crear un efecto de explosión dinámica. Para algunos otros cálculos.

Rectángulo de relleno

La imagen de arriba es un ejemplo lleno de rectángulos, los números corresponden a una matriz de puntos de 8x8.

Animación avanzada de lienzo.

Pensemos primero en un problema. Supongamos ahora que hemos aprendido a dibujar un círculo. Ahora tenemos que hacer una animación relacionada con la física: movimiento de lanzamiento plano.

¿Cómo lograrlo ahora?

Cuando veas este problema, algunas personas se confunden de repente: aprendí una función para dibujar un círculo y me dejas simular una animación tan difícil. ¡Claramente quieres matar a Zheng!

Algunas personas pueden pensar que el movimiento de tiro plano, aprendido en la física de la escuela secundaria, es básicamente un problema de una pelota pequeña. En un plano bidimensional, esta pelota pequeña puede considerarse como un círculo, pero solo necesitas aprender a dibujar. ¿Solo un círculo?

Después de esto, continuamos pensando hacia abajo, asumiendo que la bola en el movimiento de lanzamiento horizontal tiene una velocidad inicial v0 en la dirección horizontal, excepto la gravedad, no se ve afectada por otras fuerzas externas, es decir, hay una aceleración de la gravedad g (por simplicidad de cálculo, nosotros Simplemente se puede establecer como g = 10m/s^2), y no hay una velocidad inicial vh (o llamada vh = 0;) en la dirección vertical , como se muestra a continuación:

Tiro plano

De la imagen, podemos ver algunos fenómenos muy interesantes, tales como: la dirección horizontal de la pelota es exactamente la misma que el eje horizontal del lienzo, y la dirección vertical también es consistente con el eje vertical.

Luego, la fórmula física correspondiente al movimiento de lanzamiento plano:

// 竖直方向无初速度,水平方向没有外力
x = v0 * t; // 水平方向位移
h = 1/2 * g * t * t; // 竖直方向位移

// 竖直方向有初速度
h = vh * t - 1/2 * g * t * t; // 竖直方向位移

Se encuentra que las coordenadas (x, h) y el lienzo (x, y) son las mismas, y no estamos haciendo problemas de física, es decir, los parámetros v0, t, g, vh son conocidos, nuestro único Lo que hay que hacer es calcular el (x, h) en cualquier momento, es decir, las coordenadas (x, y) de la pelota en el lienzo.

Al final del análisis, ahora podemos obtener las coordenadas de posición de la pelota en cualquier momento, luego también podemos dibujar la pelota en cualquier momento en el lienzo.

Según el análisis anterior, algunas personas pueden decir: Estás equivocado, debes ser especial. La pelota no necesariamente se lanza desde la izquierda, sino que también se puede lanzar desde la derecha o hacia arriba.

De hecho, el análisis anterior solo sacó uno de los estados más especiales para estudiar, limitado al espacio (y el tema de este artículo es el lienzo en lugar de la física), y no se generalizó a conclusiones más generales, pero de hecho, estos análisis son suficientes, ya sea desplazamiento O la velocidad, él es un vector, con una dirección, entonces podemos desear estipular: tome el eje de coordenadas del lienzo, la dirección en la que aumenta el valor es la dirección positiva, luego tírelo desde el lado derecho, puede considerarse como la dirección inversa, que puede expresarse como -v0, y finalmente a través del cálculo La fórmula de desplazamiento puede obtener las coordenadas correctas (pero esta vez es más problemático calcular la coordenada x, no puede usar la fórmula anterior directamente).

He analizado mucho y dicho que estamos más preocupados por la realización.

En el análisis anterior, sabemos que si queremos encontrar las coordenadas de ubicación de la pelota en cualquier momento, los parámetros requeridos son: v0, t, g, vh. ¿Dónde deben almacenarse estos parámetros? ¿Cómo diseñar esta estructura de datos?

Por supuesto, podemos establecer directamente estos parámetros como variables globales, pero esto obviamente no es adecuado. Entre estos parámetros, el único ajuste adecuado para las variables globales es la aceleración de la gravedad g. Y v0, t, vh deben ser las "propiedades" de la pelota en sí, por lo que debemos abstraerla en una clase.

function Ball(r, v0, vh, t) {
    this.r = r;
    this.v0 = v0;
    this.vh = vh;
    this.t = t;
    this.x = 0;
    this.h = 0;

    this.calcX = function() { /* 计算水平位移 */ }
    this.calcH = function() { /* 计算竖直位移 */ }
}

var ball = { x: 0, h: 0, r: 10, v0: 0, vh: 0, g: 10};
// 重力加速度无论是作为全局变量还是小球属性,均可

// es6之后
class Ball {
    constructor();
}

Cada uno de los tres métodos anteriores tiene sus propias ventajas. Simplemente elija un método adecuado.

"Dices que tengo una gran cabeza en física. ¿Hay alguna más simple?"

Es aún más simple. De todos modos, no requiere una reducción del 100% de las escenas de física:

var ball = { x: 0, y: 0, r: 10, vx: 5, vy: 0, g: 5 };
setInterval(() => {
    ball.vy += ball.g; // 竖直方向速度增加
    ball.y += ball.vy; // 竖直方向位移
    ball.x += ball.vx; // 水平方向位移
    cxt.clearRect(0, 0, 800, 300);
    cxt.beginPath();
    cxt.fillStyle = 'black';
    cxt.arc(ball.x, ball.y, ball.r, 0, 2*Math.PI);
    cxt.fill();
}, 50);

OK, se acabó.

Esta es una animación un poco más avanzada. Puede estar aprendiendo algunas funciones, esta animación será más deslumbrante. Por ejemplo, después de aprender el relleno rectangular y dominar un poco de conocimiento de rgba, puede hacer una "cola", es decir, el efecto de cola larga. Específicamente, simplemente reemplace el código anterior cxt.clearRect()con:

cxt.fillStyle = 'rgba(255, 255, 255, 0.2)';
cxt.fillRect(0, 0, 800, 300);

Esto puede hacernos parecer que nuestra codificación es muy poderosa.

Todavía no es satisfactorio hacer este paso: la pelota cae vigorosamente y la animación desaparecerá después de un tiempo.

No importa, podemos hacer " detección de colisión ". Parece ser un vocabulario más alto, pero en realidad no hay nada más alto.Si se basa en el análisis en la primera parte de esta sección, entonces tenemos que considerar la pérdida de impulso causada por la colisión, que es bastante complicada.

Pero la versión simplificada es fácil de decir. La pelota golpea el límite superior / inferior, la velocidad en la dirección vertical se invierte y la velocidad se reduce a la mitad. Los bordes izquierdo y derecho se pueden tratar de manera similar.

if (ball.r + ball.x > canvas_width) {
    ball.vx *= -0.5
}
if (ball.r + ball.y > canvas_height) {
    ball.vy *= -0.5;
}

NOTA: La detección de colisión se refiere a la " detección de límites " aquí. Obviamente no tiene sentido continuar cayendo cuando la pelota cae al borde, porque no podemos ver la animación detrás. Por lo tanto, deténgase cuando llegue al límite o comience de nuevo o realice otro procesamiento. En resumen, no puede aparecer una animación sin sentido.

Al igual que las serpientes codiciosas que jugaste antes, habrá varios muros: cuando la serpiente controlada toca el muro, el juego fallará, o cuando no hay muro, la serpiente saldrá de la otra dirección.

Resumen

Una vez dicho esto, descubrirá que este artículo no solo no enumera directamente diferentes DEMO para introducir funciones, sino que también trata de evitar la introducción de demasiadas API en el lienzo.

Personalmente, el lienzo es en realidad una biblioteca de funciones. No es diferente de lo que usamos habitualmente para Cada, empalmar, dividir, mapear, reducir. Se empaquetan y usan directamente. Consulte el manual de funciones para comprender el uso. , Más familiarizado con él algunas veces.

Cuando ingresé por primera vez a la universidad, el profesor profesional nos dijo que programa = algoritmo + estructura de datos. Incluso ahora, muchas personas están enfatizando este punto. Si tiene el corazón, piense en la sección anterior. Al analizar el movimiento de lanzamiento plano, esencialmente estoy considerando el algoritmo; al diseñar la clase de pelota, estoy considerando orientado a objetos, pero más está considerando los datos El problema de la estructura, después de considerar estos contenidos, comencé a darme cuenta del concreto.

Materiales de referencia:

[^ 1]: documento MDN
[^ 2]: HTML 5 Canvas Reference Manual


Este artículo fue publicado por primera vez en un blog personal . Bienvenido a ^ - ^.
Barra y progrese un poco todos los días ~

Supongo que te gusta

Origin blog.51cto.com/12419668/2486697
Recomendado
Clasificación