skip to Main Content

I am creating an app which is a "paint like".

So when the user click on the image it draws on it like this:

const drawHandler = () => {
    const middle = brushSize / 2;
    context.fillRect(
        currentTransformedCursor.x - middle,
        currentTransformedCursor.y - middle,
        brushSize,
        brushSize
    );
};

When the user is moving its mouse over the image without clicking, so when mouseMove is trigger but mouseDown isn’t, I would like to show the user a preview of the rectangle that’ll be drawn if the user click.

I don’t want to fill the rectangle. I though of doing something like this:

const drawPreview = () => {
    if (currentTransformedCursor) {
        const middle = brushSize / 2;
        context.strokeRect(
            currentTransformedCursor.x - middle,
            currentTransformedCursor.y - middle,
            brushSize,
            brushSize
        );
    }
};

The problem is the strokeRect is drawn and "save" to my canvas, resulting on my canvas being filled with ‘preview’. What I want is for the preview to only exists at specific place and instant, then if the cursor move, another preview would be created at the new place and the previous one would disappear.

I can’t clearReact because it clears any rectangle below the preview too and I need to keep that data.
I know I could create another context and delete the newest rectangle (the preview) on it but I was wondering about the existence of a feature that allow to show a preview of a rectangle without really drawing it to my canvas.

Thanks

2

Answers


  1. Chosen as BEST ANSWER

    I accepted the previous answer because it does work on simple cases.

    However I have a lot of transformation on my canvas and the code wasn't working for me.

    This is the code that does exactly what I need.

    const drawPreview = () => {
        const middle = brushSize / 2;
        const currentContext = context.getTransform();
    
        context.setTransform(1, 0, 0, 1, 0, 0);
        context.clearRect(0, 0, canvas.width, canvas.height);
    
        context.setTransform(
            currentContext.a,
            currentContext.b,
            currentContext.c,
            currentContext.d,
            currentContext.e,
            currentContext.f
        );
        context.beginPath();
        context.strokeRect(
            currentTransformedCursor.x - middle,
            currentTransformedCursor.y - middle,
            brushSize,
            brushSize
        );
        context.closePath();
    };
    

    So these two lines clear the canvas: context.setTransform(1, 0, 0, 1, 0, 0); context.clearRect(0, 0, canvas.width, canvas.height);

    Then, I transform back with my current scaling and finally I draw the preview


  2. You can place another canvas above the main one

    const canvas = document.querySelector('#paint')
    const ctx = canvas.getContext('2d')
    const preview = document.querySelector('#preview')
    const previewCtx = preview.getContext('2d')
    
    canvas.addEventListener('click', e => {
      const { x, y } = getMousePos(canvas, e)
    
      const size = 50
      ctx.strokeRect(x - size / 2, y - size / 2, size, size)
    })
    
    canvas.addEventListener('mousemove', (e) => {
      const { x, y } = getMousePos(canvas, e)
    
      previewCtx.clearRect(0, 0, preview.width, preview.height)
      const size = 50
      previewCtx.strokeRect(x - size / 2, y - size / 2, size, size)
    })
    
    
    function getMousePos(canvas, evt) {
      const rect = canvas.getBoundingClientRect()
    
      return {
        x: evt.clientX - rect.left,
        y: evt.clientY - rect.top
      }
    }
    .container {
      position: relative;
    }
    
    #paint {
      border: 1px solid black;
    }
    
    #preview {
      top: 0;
      left: 0;
      position: absolute;
      pointer-events: none;
    }
    <div class="container">
      <canvas id="paint"></canvas>
      <canvas id="preview"></canvas>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search