Dibujar líneas semitransparentes en el movimiento del mouse en el canvas de HTML5

Intento que los usuarios especifiquen un área al pintar sobre ella con una herramienta de "pintura" que dibuja líneas semitransparentes en un canvas. Su propósito es especificar una "máscara" para una image que se dibujará debajo en el canvas.

Esto es lo que intenté hasta ahora:

var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); var canvasPos = canvas.getBoundingClientRect(); var dragging = false; drawImage(); $(canvas).mousedown(mouseDown); $(canvas).mouseup(mouseUp); $(canvas).mousemove(mouseMove); function drawImage() { var img = new Image(); img.src = 'http://img.javascriptes.com/javascript/cat-allergies-400x400.jpg'; img.onload = function () { ctx.drawImage(img, 0, 0); }; } function mouseDown(e) { var pos = getCursorPosition(e); dragging = true; ctx.strokeStyle = 'rgba(0, 100, 0, 0.25)'; ctx.lineCap = 'round'; ctx.lineJoin = 'round'; ctx.lineWidth = 15; ctx.beginPath(); ctx.moveTo(pos.x, pos.y); } function mouseUp(e) { dragging = false; } function mouseMove(e) { var pos, i; if (!dragging) { return; } pos = getCursorPosition(e); ctx.lineTo(pos.x, pos.y); ctx.stroke(); } function getCursorPosition(e) { return { x: e.clientX - canvasPos.left, y: e.clientY - canvasPos.top }; } 
  • Enlace a un jsfiddle del código anterior: http://jsfiddle.net/s34PL/2/

El problema con este código de ejemplo es que los píxeles posteriores que se dibujan hacen que la opacidad sea cada vez less visible. Creo que es porque la línea tiene 15 píxeles de ancho (aunque también quiero que sea de ancho).

¿Cómo puedo resolver este problema?

¡Gracias!

El problema es que estás dibujando todo el path una y otra vez:

 function mouseMove(e) { ... ctx.stroke(); // Draws whole path which begins where mouseDown happened. } 

Solo debe dibujar el nuevo segmento de la ruta ( http://jsfiddle.net/jF9a6/ ). Y luego … tienes el problema con el ancho de 15 píxeles de la línea.

Entonces, ¿cómo resolver esto? Tenemos que trazar la línea de inmediato como lo hizo, pero evite pintar encima de las líneas existentes. Aquí está el código: http://jsfiddle.net/yfDdC/

El mayor cambio es la matriz de paths . Contiene sí, routes 🙂 Una ruta es una matriz de puntos almacenados en las funciones mouseDown y mouseMove . Se crea una nueva ruta en la function mouseDown:

 paths.push([pos]); // Add new path, the first point is current pos. 

En mouseMove, agrega la position actual del mouse a la última ruta en la matriz de paths y actualiza la image.

 paths[paths.length-1].push(pos); // Append point tu current path. refresh(); 

La function refresh() borra todo el canvas, atrae al gato de nuevo y dibuja todos los paths.

 function refresh() { // Clear canvas and draw the cat. ctx.clearRect(0, 0, ctx.width, ctx.height); if (globImg) ctx.drawImage(globImg, 0, 0); for (var i=0; i<paths.length; ++i) { var path = paths[i]; if (path.length<1) continue; // Need at least two points to draw a line. ctx.beginPath(); ctx.moveTo(path[0].x, path[0].y); ... for (var j=1; j<path.length; ++j) ctx.lineTo(path[j].x, path[j].y); ctx.stroke(); } } 

El enfoque alternativo es dibujar las routes sólidas y hacer que todo el canvas sea transparente. Por supuesto, debe mover la image fuera del canvas y astackrla debajo. Puede encontrar el código aquí: http://jsfiddle.net/fP297/

 <div style="position: relative; border: 1px solid black; width: 400px; height: 400px;"> <img src='cat.jpg' style="position: absolute; z-order: 1;"> <canvas id="canvas" width="400" height="400" style="position: absolute; z-order: 2; opacity: 0.25;"></canvas> </div> 

Al dibujar líneas sólidas, no tiene que preocuparse por dibujar un área varias veces, por lo que no tiene que preocuparse por borrar la image y volver a dibujar todo.