Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular, drawing multiples rectangles with canvas on mouse event

I'm trying to create a drawing tool with angular. I created a tool that you can draw a rectangle on a canvas element, the tool is working ok, but I can only draw one rectangle at a time, I just can't figure out how to "not clear" the previous rectangle and keep multiples drawings on my canvas. I cannot clear many canvas because i'm gonna have more drawings, not just rectangles.

rectangleDrawing() {

    // first coordinates when clicked
    let startX = 0;
    let startY = 0;

    const rect = this.canvasEl.getBoundingClientRect();

    fromEvent(this.canvasEl, "mousedown")
        .pipe(
            switchMap((e:MouseEvent) => {

                startX = e.clientX - rect.left;
                startY = e.clientY - rect.top;

                return fromEvent(this.canvasEl, 'mousemove').pipe(

                    takeUntil(fromEvent(this.canvasEl, 'mouseup')),
                    takeUntil(fromEvent(this.canvasEl, 'mouseleave'))
                )

            })
        ).subscribe((event:MouseEvent) => {

            let x = event.clientX - rect.left;
            let y = event.clientY - rect.top;

            let width = x - startX;
            let height = y - startY;


            this.setCanvasProperties(10, 'square', 'rgba(255,158,43,0.6)');

            this.cx.beginPath();

            // if I comment this line, the rectangles will stay, but they 
            // won't be clear, making multiples rectangles inside the 
            // main rectangle
            this.cx.clearRect(0,0, this.canvasEl.width, this.canvasEl.height);

            this.cx.rect(startX, startY, width, height);

            this.cx.stroke();

        });

}

setCanvasProperties(lineWidth, lineCap, strokeStyle) {
    this.cx = this.canvasEl.getContext('2d');
    this.cx.lineWidth = lineWidth;
    this.cx.lineCap = lineCap;
    this.cx.strokeStyle = strokeStyle;
}

This link is a good example: https://jsfiddle.net/richardcwc/ukqhf54k/, if you comment the clear line, you can see main problem. Many examples seems to permit only one rectangle at a time.

like image 244
heliosk Avatar asked Jun 15 '26 11:06

heliosk


1 Answers

On mouse up, you could store the drawn rect in an array, and then draw that array and the current rect.

First, lets set the array and keep the width and height as a global variable:

var width;
var height;
var drawItems = [];

Then, the mouseup function will be like this:

$(canvas).on('mouseup', function(e) {
  mousedown = false;

  drawItems.push({
    x0: last_mousex,
    x1: width,
    y0: last_mousey,
    y1: height
  });
});

And this is the mousemove function:

$(canvas).on('mousemove', function(e) {
    mousex = parseInt(e.clientX-canvasx);
    mousey = parseInt(e.clientY-canvasy);
    if(mousedown) {
        ctx.clearRect(0,0,canvas.width,canvas.height); //clear canvas

        ctx.strokeStyle = 'black';
        ctx.lineWidth = 10;

        for(var i=0; i<drawItems.length; i++) {
            ctx.beginPath();
            ctx.rect(drawItems[i].x0, drawItems[i].y0, drawItems[i].x1, drawItems[i].y1);
            ctx.stroke();
        }

        width = mousex-last_mousex;
        height = mousey-last_mousey;
        ctx.beginPath();
        ctx.rect(last_mousex,last_mousey,width,height);
        ctx.stroke();
    }
    //Output
    $('#output').html('current: '+mousex+', '+mousey+'<br/>last: '+last_mousex+', '+last_mousey+'<br/>mousedown: '+mousedown);
});

Here is the updated fiddle

I hope it helps

like image 140
Guillermo Avatar answered Jun 18 '26 00:06

Guillermo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!