En un proyecto reciente, quiero implementar un tablero de dibujo estilo píxel, donde se pueden borrar pequeñas cuadrículas de píxeles, las selecciones de cuadros cambian de color y se pueden borrar varios gráficos. Un proyecto tan pequeño puede parecer simple, pero contiene muchos. cosas.
Dibuja una cuadrícula de píxelesPrimero definamos la clase de cuadrícula de píxeles.
Píxel = función (opción) { this.x = option.x; this.y = option.y; this.shape = option.shape;
xey representan las coordenadas del punto central. Esto es lo que hice al principio. Definir la ruta primero.
createPath: función (ctx) {if (this.shape === 'circle') {this.createCircle(ctx);} else if (this.shape === 'rect') {this.createRect(ctx);} else {this.createCircle(ctx);}},createCircle: función (ctx) {var radio = this.size / 2;ctx.arc(this.x,this.y,radius,0,Math.PI*2);},createRect: función (ctx) {var puntos = this.getPoints(); , i) { ctx[i == 0 ? 'moveTo' : 'lineTo'](punto.x, punto.y }) ctx.lineTo(puntos[0].x, puntos[0].y);},
La cuadrícula de píxeles admite círculos y rectángulos. Una vez definida la ruta, se dibuja.
dibujar: función (ctx) {ctx.save();ctx.lineWidth=this.lineWidth;ctx.strokeStyle=this.strokeStyle;ctx.fillStyle=this.fillStyle;ctx.beginPath();this.createPath(ctx); ctx.stroke();if(this.isFill){ctx.fill();}ctx.restore();}
Luego cree la cuadrícula de píxeles en lotes mediante un bucle:
for (var i = pasoX + .5; i < lienzo.ancho; i+=pasoX) {for (var j = pasoY + .5; j < lienzo.altura; j+=pasoY) {var píxel = nuevo píxel({x : i,y: j,forma: 'círculo'})box.push(pixel);pixel.draw(ctx);}}
Esto parece perfecto, pero tiene una gran desventaja. Cada vez que se dibuja un píxel, se vuelve al contexto y el estado del lienzo cambia cada vez. Esto provocará un rendimiento deficiente de la representación, porque hay muchos. píxeles.Si el lienzo es relativamente grande, el rendimiento es muy preocupante y algunas operaciones en la mesa de dibujo no son apropiadas para cambiar el estado del lienzo.
Por lo tanto, el enfoque correcto es: debemos definir todas las rutas, y es mejor dibujarlas en el lienzo en lotes a la vez;
//Definir la posición del píxel for (var i = stepX + .5; i < canvas.width; i+=stepX) {for (var j = stepY + .5; j < canvas.height; j+=stepY) { var píxel = nuevo píxel ({x: i,y: j,forma: 'circle'})box.push(pixel);}}//Dibujo por lotes console.time('time');ctx.beginPath();for (var c = 0; c < box.length; c++) {var circulo = cuadro[c];ctx.moveTo(circulo.x + 3, círculo.y);circle.createPath(ctx);}ctx.closePath();ctx.stroke();console.timeEnd('tiempo');
Puede ver que esta eficiencia de representación es muy rápida y el estado del lienzo cambia lo menos posible, porque cada vez que se cambia el estado del contexto, el lienzo se volverá a dibujar y este estado es un estado global.
Interacción con la cuadrícula de píxelesEl requisito del proyecto es que los píxeles se puedan borrar presionando y moviendo el mouse sobre el lienzo. Esto contiene dos puntos de conocimiento, uno es cómo obtener la cuadrícula de píxeles en la ruta de movimiento del mouse y el segundo son problemas de rendimiento, debido a. nuestras necesidades El requisito es dibujar 80.000 puntos, sin mencionar nada más, solo el bucle tomará decenas o cientos de milisegundos, sin mencionar el dibujo y la renderización. Veamos primero la primera pregunta:
Obtenga la cuadrícula debajo de la ruta de movimiento del mouse.Al ver este problema, podemos pensar fácilmente en escribir una función para obtener la posición del mouse a través de la posición del mouse, que contiene la cuadrícula, y luego volver a actualizar el cálculo de la posición cada vez que se mueve. De esta manera, se cumple el requisito. Se puede cumplir, pero si el mouse se mueve Es imposible hacerlo rápidamente. Se puede calcular la posición de cada punto y el efecto será inconsistente. Cambiemos nuestra forma de pensar. Podemos conocer claramente los puntos inicial y final del camino por el que pasa el mouse. Imaginamos todo el camino del dibujo como un segmento de línea. Entonces el problema se convierte en un algoritmo para cruzar el segmento de línea con el original. El segmento es El grosor del pincel y la ruta por la que pasa el segmento de línea son las rutas del movimiento del mouse, y los círculos que se cruzan con ellos son las cuadrículas que deben cambiarse. El código convertido es el siguiente:
function sqr(x) { return x * x } function dist2(p1, p2) { return sqr(p1.x - p2.x) + sqr(p1.y - p2.y) } function distToSegmentSquared(p, v, w ) { var l2 = dist2(v, w); si (l2 == 0) devuelve dist2(p, v =); ((px - vx) * (wx - vx) + (py - vy) * (wy - vy)) / l2 si (t < 0) devuelve dist2(p, v); (p, w); devuelve dist2(p, { x: vx + t * (wx - vx), y: vy + t * (wy - vy) } }/** *); @description Calcula si el segmento de línea interseca el círculo* @param {x: num, y: num} p punto central del círculo* @param {x: num, y: num} v punto inicial del segmento de línea* @param {x : num, y: num } w punto final del segmento de línea*/ function distToSegment(p, v, w) { var offset = pathHeight var minX = Math.min(vx, wx) - desplazamiento; var maxX = Math.max(vx, wx) + desplazamiento; var minY = Math.min(vy, wy) - desplazamiento var maxY = Math.max(vy, wy) + desplazamiento; || px > maxX) && (py < minY || py > maxY)) { return Number.MAX_VALUE } return Math.sqrt(distToSegmentSquared(p, v, w));
La lógica específica no se detallará. Los lectores pueden leer el código por sí mismos. Luego, al obtener la cuadrícula de intersección, eliminar los datos en el cuadro y renderizarlos nuevamente, podrá ver el efecto.
De la misma manera, podemos crear un efecto de teñido y luego podemos implementar una pequeña demostración del tablero de dibujo de píxeles del lienzo. Sin embargo, para crear un efecto de teñido, debes utilizar el primer método de dibujo. Cada píxel debe ser un objeto, porque el estado de cada objeto es independiente. Sin embargo, no hay necesidad de preocuparse por el rendimiento. Básicamente no habrá sensación de retraso. El efecto es aproximadamente el siguiente:
He sido un poco vago recientemente, así que lo dejaré así por ahora. Tendré tiempo para agregar una función para cargar imágenes, pixelar imágenes y exportar funciones más adelante.
Lo anterior es el contenido completo de este artículo. Espero que sea útil para el estudio de todos. También espero que todos apoyen VeVb Wulin Network.