infinite-canvas icon indicating copy to clipboard operation
infinite-canvas copied to clipboard

Problems with Objects stored in array

Open FrankDaze opened this issue 2 years ago • 2 comments

Hi,

in my project I create filled rectagles with the mouse and store them into an objectArray. If I create a new rec I clear the screen while onmousemove and recreate the objects by looping through my array.

But in combination with your script I have the problem, that each time, when I move the canvas and then draw a new rect, everthing jumps back to it's origninal position. Any idea how to handle that?

thanks in advance Frannk

     const canvas = document.querySelector("canvas");
     let ctx = canvas.getContext("2d");
     setCanvasSize();
    
    // Initialization
    var inf_ctx = infiniteCanvas.initialize(ctx);
    
    inf_ctx.updateChunks();
    
    window.addEventListener('resize', () => {
        setCanvasSize();
        drawUpdate();
    })
    
    let color = '#e28743'
    ctx.strokeStyle = color;
    ctx.lineWidth=1;
    
    // calculate where the canvas is on the window
    // (used to help calculate mouseX/mouseY)
    
    var offsetX=canvas.offsetLeft;
    var offsetY=canvas.offsetTop;
    var scrollX=canvas.scrollLeft;
    var scrollY=canvas.scrollTop;
    
    // this flage is true when the user is dragging the mouse
    var isDown=false;
    
    // these vars will hold the starting mouse position
    var startX;
    var startY;
    
    let objectArray = [];
    let startDrawing = false;
    var width = 0;
    var height = 0;
    
    var dx = 0;
    var dy = 0;
    
    function setCanvasSize()
    {
        canvas.width= window.innerWidth;
        canvas.height = window.innerHeight;
    }
    
    function createNotepaper(x,y,width,height, color)  {
        
        this.color = color;
        this.startX = x;
        this.startY = y;
        this.width = width;
        this.height = height;
    
        this.draw = () => {
            ctx.fillStyle = '#00000020';
            ctx.beginPath();
            ctx.filter = 'blur(3px)';
            ctx.fillRect(this.startX+4,this.startY+4,this.width,this.height);
            ctx.filter = 'blur(0px)';
            ctx.fillStyle = this.color;
            ctx.beginPath();
            ctx.fillRect(this.startX,this.startY,this.width,this.height);
    
            // Text
            ctx.font = "12px Verdana";
            ctx.fillStyle = '#fff';
            ctx.textAlign = "left";
            ctx.fillText("GovBoard Demo", this.startX+5, this.startY+17, this.width-10);
            ctx.save();
        }
        
    }
    
    function changeColor(e)
    {
        
        color = window.getComputedStyle(e).getPropertyValue('background-color');
        ctx.strokeStyle = color;
        isDown=false;
        startDrawing= false;
    }
    
    function handleMouseDown(e){
        e.preventDefault();
        e.stopPropagation();
    
        // save the starting x/y of the rectangle
        startX=parseInt(e.clientX-canvas.offsetLeft);
        startY=parseInt(e.clientY-canvas.offsetTop);
    
        // set a flag indicating the drag has begun
        isDown=true;
    }
    
    function handleMouseUp(e){
      
        e.preventDefault();
        e.stopPropagation();
    
        // the drag is over, clear the dragging flag
        isDown=false;
    
        if(startDrawing)
        {
            
            newPaperNote();
            
        }
        inf_ctx.updateChunks();
        
    }
    
    function handleMouseOut(e){
        e.preventDefault();
        e.stopPropagation();
    
        // the drag is over, clear the dragging flag
        isDown=false;
    }
    
    function drawUpdate()
    {
        
        for(var i=0; i < objectArray.length; i++)
        {
        
            objectArray[i].draw();
           
        }
        
    }
    
    function moveTo(x,y)
    {  
        ctx.clearRect(0,0,canvas.width,canvas.height);
        dx = x;
        dy = y;
        inf_ctx.moveBy(x, y);
      
    }
    
    function newPaperNote()
    {
        
        const notepaper = new createNotepaper(startX,startY,width,height,color);
        ctx.clearRect(0,0,canvas.width,canvas.height);
        objectArray.push(notepaper);
    
        drawUpdate();
        
        startDrawing = false;
    }
    
    function handleMouseMove(e){
        e.preventDefault();
        e.stopPropagation();
       
        // if we're not dragging, just return
        if(isDown)
        {
          
            startDrawing = true;
            // get the current mouse position
            mouseX=parseInt(e.offsetX);
            mouseY=parseInt(e.offsetY);
           
            // calculate the rectangle width/height based
            // on starting vs current mouse position
            width=mouseX-startX;
            height=mouseY-startY;
    
    
            ctx.clearRect(0,0,canvas.width,canvas.height);
           // inf_ctx.updateChunks();
            drawUpdate();        
    
            ctx.beginPath()
            ctx.fillStyle = '#ff0000';
            ctx.rect(startX,startY,width,height);
            ctx.stroke()
           
      
        }
        if(!isDown && startDrawing)
        {
            
           newPaperNote();
    
        }   
        
       
    
    }
    
    
    
    canvas.addEventListener("mousedown",handleMouseDown);
    canvas.addEventListener("mouseup",handleMouseUp);
    canvas.addEventListener("mousemove",handleMouseMove);
    canvas.addEventListener("mouseout", handleMouseOut);

FrankDaze avatar May 13 '22 14:05 FrankDaze

The problem is that you're storing the rectangle co-ordinates and redrawing them every time. The moveTo and moveBy methods handle the drawing for you.

It works like this:

  1. You draw to your regular canvas
  2. When you call inf_ctx.updateChunks(), this gets synchronised to the infinite canvas behind
  3. You can now call inf_ctx.moveBy and inf_ctx.moveTo to move around the canvas. Whatever was drawn to the canvas originally will be automatically drawn in the new, correct position.

This interaction model only really makes sense for painting-like applications, like an infinitely-expanding whiteboard or MS Paint with an automatically expanding canvas.

Can you tell me a little bit more about your goal? This library might fit, but if it involves more than a little bit of interaction I highly recommend going for something with an interaction-model built-in like paper.js, pixi.js or phaser.js (it's a game engine, but game engines are perfectly fine for interactive canvas applications!) or if you prefer a well-filled low-level toolbox you could use p5.js.

Azeirah avatar May 13 '22 19:05 Azeirah

thanks for your quick answer.

I redraw the objects all the time because I need to do that for drawing the rectangles by dragging the mouse. My goal is to build a collaboration board like Miro (Miro.com) or Lucidchart.

I will have a look into the libraries you mentioned and will check if they suit to my idea.

Best Frank

FrankDaze avatar May 14 '22 06:05 FrankDaze