Issue when dragging text on canvas if slightly scrolled down

Viewed 44

When I scroll slightly down on my canvas, it does not allow me to drag my text at all. Examples (These are GIFs) -

https://gyazo.com/e60d2efd924ced758c2c6441391804db

GIF explained: So you saw the drag was working when I was on top of the page but when I scrolled slightly down. It completely stopped working. I added a few console.logs around, and what I know is the click event listener for the canvas is working but it isn't detected the text when I slightly scroll down on the page.

I based my drag code from: http://jsfiddle.net/m1erickson/9xAGa/ | What you can see is if you change the canvas size width: 667 and height: 800, and when you scroll slightly down, you will have the same issue I am having.

HTML Code:

<div id="middle_container">
        <div class="center_container">
            <canvas id="canvas" width="667px" height="800px"></canvas>
        </div>
</div>

JavaScript Code:

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var $canvas = $("#canvas");
var BB=canvas.getBoundingClientRect();
var offsetX = BB.left;
var offsetY = BB.top;
var mx;
var my;
var texts = [];
var images = [];
var dragF = -1;
var mode = "none";

function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    for(const { text, x, y, width, height } of texts) {
        ctx.fillText(text, x, y);
    }
}

function addNewText(string_text) {
    var y = texts.length * 20 + 20;
    var text = {
        text: string_text,
        x: 20,
        y: y
    };
    ctx.font = "32px verdana";
    ctx.textBaseline = "top";
    text.width = ctx.measureText(text.text).width;
    text.height = 32;

    texts.push(text);
    draw();
}



function hitDrag(x,y,textIndex) {
    var r=texts[textIndex];
    return (x>r.x && x<r.x+r.width && y>r.y && y<r.y+r.height);
}

function myDrag(a,e) {
    if (a == "down") {
        e.preventDefault();
        e.stopPropagation();
        mx=parseInt(e.clientX-offsetX);
        my=parseInt(e.clientY-offsetY);
        for(var i=0;i<texts.length;i++){
            if(hitDrag(mx,my,i)){
                console.log("found");
                dragF = i;
            }
        }
    }
}

addNewText("Hello World")

$("#canvas").mousedown(function(e) {
    myDrag("down", e);
});
1 Answers

The problem is this line of code:

var BB=canvas.getBoundingClientRect();

which is only populated once at the start of your script. The .getBoundingClientRect() method returns the position of a HTML element relative to the viewport.

Well if you scroll the window, the viewport moves - as the canvas element - but the BB object still holds the position of your canvas at startup.

The fix is rather simple - you need to use the actual position of the canvas element by calling .getBoundingClientRect() again on mouse down and on mouse move.

I've prepared a little sample based on your code and the fiddle you've linked:

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var $canvas = $("#canvas");
var BB = canvas.getBoundingClientRect();
var offsetX = BB.left;
var offsetY = BB.top;
var mx;
var my;
var texts = [];
var images = [];
var dragF = -1;
var mode = "none";

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  for (const {
      text,
      x,
      y,
      width,
      height
    } of texts) {
    ctx.fillText(text, x, y);
  }
}

function addNewText(string_text) {
  var y = texts.length * 20 + 20;
  var text = {
    text: string_text,
    x: 20,
    y: y
  };
  ctx.font = "32px verdana";
  ctx.textBaseline = "top";
  text.width = ctx.measureText(text.text).width;
  text.height = 32;

  texts.push(text);
  draw();
}

function myDrag(a, e) {
  if (a == "down") {
    e.preventDefault();
    e.stopPropagation();
    let rect = canvas.getBoundingClientRect();
    mx = parseInt(e.clientX - rect.left);
    my = parseInt(e.clientY - rect.top);
    for (var i = 0; i < texts.length; i++) {
      if (hitDrag(mx, my, i)) {
        // console.log("found");
        dragF = i;
      }
    }
  }
}

function hitDrag(x, y, textIndex) {
  var r = texts[textIndex];
  return (x > r.x && x < r.x + r.width && y > r.y && y < r.y + r.height);
}

function handleMouseMove(e) {
  if (dragF < 0) {
    return;
  }
  e.preventDefault();
  let rect = canvas.getBoundingClientRect();
  mouseX = parseInt(e.clientX - rect.left);
  mouseY = parseInt(e.clientY - rect.top);

  var dx = mouseX - mx;
  var dy = mouseY - my;
  mx = mouseX;
  my = mouseY;

  var text = texts[dragF];
  text.x += dx;
  text.y += dy;
  draw();
}

function handleMouseUp(e) {
  e.preventDefault();
  dragF = -1;
}

addNewText("Hello World")

$("#canvas").mousedown(function(e) {
  myDrag("down", e);
});

$("#canvas").mousemove(function(e) {
  handleMouseMove(e);
});

$("#canvas").mouseup(function(e) {
  handleMouseUp(e);
});
body {
  background-color: ivory;
}

#canvas {
  border: 1px solid red;
}

#theText {
  width: 10em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="middle_container">
  <div class="center_container">
    <canvas id="canvas" width="667px" height="800px"></canvas>
  </div>
</div>
<br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br>

Related