Pointers X Y doesn't update on drag and drop an html element

Hello everyone,

I’m trying to retrieve the pointerX and Y when dropping an html element in the canvas to import an element at the place of the drop.

The problem is that the value of the pointers remain fixed to those of the output of the canvas cursor and do not update when dragging and dropping an element, most of the time the 1st try works but not the following ones.

for examples the following code

HTML :

<canvas id="renderCanvas"></canvas>

<div id="elementHTML" draggable="true"></div>

JS :

const canvas = document.getElementById("renderCanvas");
const engine = new BABYLON.Engine(canvas, true);

  var createScene = function() {
    const scene = new BABYLON.Scene(engine);
    scene.clearColor = new BABYLON.Color3(0.92, 0.92, 0.92);

    const camera = new BABYLON.ArcRotateCamera("camera", -3 * Math.PI / 4, Math.PI / 3, 15);
    camera.attachControl(canvas, true);

    const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(-0.5, 1.5, 1.5));
    light.intensity = 0.7;

    let planeMat = new BABYLON.StandardMaterial("planeMat");
    planeMat.diffuseColor = new BABYLON.Color3(1, 1, 1);
    planeMat.alpha = 0.1;

    const abstractPlane = BABYLON.Plane.FromPositionAndNormal(new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(0, 1, 0));
    const plane = BABYLON.MeshBuilder.CreatePlane("plane", {
      size: 100,
      sourcePlane: abstractPlane
    });
    plane.material = planeMat;

    const box = BABYLON.MeshBuilder.CreateBox("box", {});
    box.position.x = 0.5;
    box.position.y = 0.5;
    box.position.z = 0.5;

    return scene;
};

var scene = createScene();

console.log("first scene.pointerX", scene.pointerX);
console.log("first scene.pointerY", scene.pointerY);

canvas.addEventListener('mouseleave', event => {
  console.log("mouseleave scene.pointerX", scene.pointerX);
  console.log("mouseleave scene.pointerY", scene.pointerY);
});

canvas.addEventListener('dragenter', event => {
  console.log("dragenter scene.pointerX", scene.pointerX);
  console.log("dragenter scene.pointerY", scene.pointerY);
});

canvas.addEventListener('dragover', event => {
  event.preventDefault();
  event.dataTransfer.dropEffect = "move";
});

canvas.addEventListener('drop', event => {
  console.log("drop scene.pointerX", scene.pointerX);
  console.log("drop scene.pointerY", scene.pointerY);

  let pickResult = scene.pick(scene.pointerX, scene.pointerY);
  console.log(pickResult);
  let location = pickResult.pickedPoint;
  console.log(location);

  if (location) {
    let myBox = scene.meshes.find(meshe => meshe.name == "box");
    let instance = myBox.createInstance(myBox.name + "-Instance-" + (myBox.instances.length + 1));

    instance.position = location;
  }
  else {
    console.log("no pickedPoint");
  }
});

engine.runRenderLoop(function() {
  scene.render();
});

window.addEventListener("resize", function() {
  engine.resize();
});

CSS :

body {
  overflow: hidden;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  font-family: Arial, Helvetica, sans-serif;
  background-color: #464650;
}

#renderCanvas {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

#elementHTML {
  position: absolute;
  top: 200px;
  left: 100px;
  width: 200px;
  height: 400px;
  background-color: red;
}

It look like this :

Did someone have an idea to solve this ?
Thanks by advance

Adding @PolygonalSun our Input Specialist.

1 Like

If I’m remembering correctly, scene.pointerX/Y are only updated when there are events dispatched to the canvas. When dragging and dropping something, your target (HTMLElement that should be receiving input events) isn’t actually the canvas so this change wouldn’t be updated. One thing that you could try would be to use the clientX/Y directly from your events and use the canvas’ dimensions to get a position, relative to it. Here’s a snippet to try out:

let canvasRect = scene.getEngine().getInputElementClientRect();
...
canvas.addEventListener('dragenter', event => {
  console.log("dragenter scene.pointerX", scene.pointerX, " vs ", (event.clientX - canvasRect.left));
  console.log("dragenter scene.pointerY", scene.pointerY, " vs ", (event.clientY - canvasRect.top));
});

Subtracting the canvas’ top and left values are effectively the same thing that we use to calculate pointerX/Y so this might be a possible solution. Lemme know if this works for you.

2 Likes

Yep, it works.

I only changed the event into drop so i get the clientX and Y from the drop, it look like this :

const canvasRect = scene.getEngine().getInputElementClientRect();

const locationX = event.clientX - canvasRect.left;
const locationY = event.clientY - canvasRect.top;

const pickResult = scene.pick(locationX, locationY);

Thanks for fast and helpful respond.

2 Likes