javascripthtml5-canvas

How to hide the path immediate overlap without hiding intersection overlap?


I'm making a painting app, and using the canvas path as a brush:

function onMove(){
    ctx.beginPath();
    ctx.moveTo(pos.x, pos.y); // from position
    pos=getPosition(event); 
    ctx.lineTo(pos.x, pos.y); // to position 
    ctx.stroke(); // draw it!
}

I'm stuck between in a dilemma, if I join all the paths into one I lose intersection overlap, and if I draw them real time separately I get those start/end overlaps spheres.

enter image description here

Is there a clean way I can solve this problem? Thank you.


Solution

  • Okey, then it is getting complicated since we are dealing with alpha values here..

    Basicly you can draw the "missing part" of the new line in a buffer canvas by using destination-in and source-in blend modes.

    The idea is: to "compute" the overlapp of the N-1 the Nth line and then only draw line N outside this overlap: (for demonstation the Nth line will be drawn in red.)

    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    
    const canvas2 = document.createElement('canvas')
    canvas2.width = 300
    canvas2.height = 300
    const ctx2 = canvas2.getContext('2d');
    
    ctx.lineWidth = 30
    ctx.lineCap = 'round';
    ctx.strokeStyle = 'rgba(0,0,0,0.5)';
    ctx.imageSmoothingEnabled = false;
    ctx.lineJoin = "round"
    
    
    
    function drawLine1(ctx) {
      ctx.beginPath();
      ctx.moveTo(250, 250);
      ctx.lineTo(100, 250);
      ctx.stroke();
    }
    function drawLine2(ctx) {
      ctx.beginPath();
      ctx.moveTo(100, 250);
      ctx.lineTo(100, 50);
      ctx.stroke();
    }
    
    // draw image until line n-1 on screen
    ctx.beginPath();
    ctx.moveTo(0, 100);
    ctx.lineTo(250, 100); // 1st
    ctx.lineTo(250, 250); // 2nd
    ctx.lineTo(100, 250); // n-1
    ctx.stroke();
    
    // clear buffer canvas and setup
    ctx2.clearRect(0, 0, canvas2.width, canvas2.height);
    ctx2.lineWidth = 30
    ctx2.lineCap = 'round';
    ctx2.imageSmoothingEnabled = false;
    // draw line n-1 on buffer in opaque color
    ctx2.strokeStyle = 'rgba(0,0,0,1)';
    drawLine1(ctx2)
    
    // draw line n on buffer in "destination-in" blend mode opaque
    ctx2.globalCompositeOperation = 'destination-in';
    ctx2.strokeStyle = 'rgba(0,0,0,1)';
    drawLine2(ctx2)
    
    // draw line n on buffer in "source-out" blend mode and original color
    ctx2.globalCompositeOperation = 'source-out';
    ctx2.strokeStyle = 'rgba(255,0,0,0.5)';
    drawLine2(ctx2)
    
    ctx.drawImage(canvas2, 0 ,0)
    <canvas id="canvas" width="400" height="400"></canvas>

    It is not perfect, but it is a starting point..