Estoy creando un tablero de dibujo basado en la web. Parte de la funcionalidad de esto es dibujar formas (como líneas).
Me encuentro en la necesidad de realizar un seguimiento de todos los puntos dibujados en el lienzo en una matriz. Específicamente porque necesito despejar el tablero y volver a dibujar los puntos al dibujar líneas y otras formas para que se sienta "interactivo". Para aclarar la funcionalidad, he creado este JSFiddle https://jsfiddle.net/hwa95rcx/35/
HTML:
<canvas id="test" width="500" height="500"> </canvas>JavaScript:
let lineStartX = 0; let lineStartY = 0; const drawingPoints = []; let mouseDown = false; const c = document.getElementById("test"); const ctx = c.getContext("2d"); c.onmousedown = (e) => { lineStartX = e.clientX; lineStartY = e.clientY; mouseDown = true; } c.onmousemove = (e) => { if (mouseDown) { ctx.beginPath(); ctx.clearRect(0, 0, 500, 500); redraw(); ctx.moveTo(lineStartX, lineStartY); ctx.lineTo(e.clientX, e.clientY); ctx.stroke(); } } c.onmouseup = (e) => { mouseDown = false; drawingPoints.push({ startX: lineStartX, startY: lineStartY, lineEndX: e.clientX, lineEndY: e.clientY }); } function redraw() { drawingPoints.forEach(el => { ctx.moveTo(el.startX, el.startY); ctx.lineTo(el.lineEndX, el.lineEndY); ctx.stroke() }); }eso ejemplifica la razón por la que necesito almacenar una serie de puntos para volver a dibujar.
Me gustaría evitar hacer esto porque con grandes cantidades de datos, el dibujo se ralentiza o incluso falla porque estamos recorriendo todos los puntos para volver a dibujarlos. ¿Existe una forma más efectiva de lograr este efecto de dibujo de formas interactivas que estoy buscando?
Su función de redraw llama a stroke() para cada subsegmento, pero nunca llama a beginPath() . Esto significa que cuando tiene dos subsegmentos, el primero se pintará en su propio turno, y luego nuevamente cuando el segundo subsegmento llame a stroke() .
Puede ver esto con bastante claridad al observar sus primeros trazos y cómo su antialiasing oscurece la mayor parte de los subsegmentos que hay.
En realidad, le está pidiendo a la computadora que represente magnitudes de más elementos de los necesarios, esto es lo que hace que su aplicación sea lenta y, finalmente, se bloquee.
Por lo tanto, podría llamar a beginPath() en el bucle, pero lo mejor es eliminar completamente stroke() de allí. De esta manera, en cada cuadro solo pintas un solo camino. La GPU solo tiene que hacer una sola operación y debería estar bien para días de dibujos.
let lineStartX = 0; let lineStartY = 0; const drawingPoints = []; let mouseDown = false; const c = document.getElementById("test"); const ctx = c.getContext("2d"); c.onmousedown = (e) => { lineStartX = e.clientX; lineStartY = e.clientY; mouseDown = true; } c.onmousemove = (e) => { if (mouseDown) { ctx.beginPath(); ctx.clearRect(0, 0, 500, 500); redraw(); ctx.moveTo(lineStartX, lineStartY); ctx.lineTo(e.clientX, e.clientY); ctx.stroke(); } } c.onmouseup = (e) => { mouseDown = false; drawingPoints.push({ startX: lineStartX, startY: lineStartY, lineEndX: e.clientX, lineEndY: e.clientY }); } function redraw() { // 'redraw' only traces the previous sub-segments drawingPoints.forEach(el => { ctx.moveTo(el.startX, el.startY); ctx.lineTo(el.lineEndX, el.lineEndY); }); } <canvas id="test" width="500" height="500"></canvas>Tenga en cuenta que si mide que incluso el trazado requiere algo de tiempo de cálculo (aunque esto sería sorprendente), puede intentar almacenar la ruta secundaria en un objeto Path2D en lugar de llamar a los métodos de dibujo cada vez:
let lineStartX = 0; let lineStartY = 0; const path = new Path2D(); let mouseDown = false; const c = document.getElementById("test"); const ctx = c.getContext("2d"); c.onmousedown = (e) => { lineStartX = e.clientX; lineStartY = e.clientY; mouseDown = true; } c.onmousemove = (e) => { if (mouseDown) { ctx.beginPath(); ctx.clearRect(0, 0, 500, 500); redraw(); ctx.moveTo(lineStartX, lineStartY); ctx.lineTo(e.clientX, e.clientY); ctx.stroke(); } } c.onmouseup = (e) => { mouseDown = false; path.moveTo(lineStartX, lineStartY); path.lineTo(e.clientX, e.clientY); } function redraw() { ctx.stroke(path); } <canvas id="test" width="500" height="500"></canvas>