Drag'n drop dans un canvas
Cliquer & déplacer/glisser un objet dans un canvas en javascript
Un canvas permet de faire de nombreuses choses, dessiner, écrire, … et piloter le tout en javascript.
En particulier, on peut gérer les événements liés à la souris, par exemple déjà récupérer les coordonnées d'un click.
Ensuite, en gérant convenablement les événements
onmousedown
, onmousemove
et onmouseup
on peut assez facilement créer des objets "draggable" en
- récupérant la position de la souris au click (
onmousedown
) - si la position correspond à celle de l'objet, on déclenche l'événement
onmousemove
qui appelle une fonctionMove
- cette dernière fonction efface l'objet, puis le redessine à chaque nouvelle position de la souris, tant que le click de la souris n'est pas relˆché, événément
onmouseup
- on désactive alors l'écoute de l'événement
onmousemove
Résultat / Affichage
Programmation en html/javascript
Définition du canvas en html…
<div id="overcnv" style="width:400px;height:400px;border:2px solid blue">
<canvas id="canvas"></canvas>
</div>
…puis le code javascript pour dessiner, animer, glisser
<script>
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const Width=document.getElementById("overcnv").clientWidth;
const Height=document.getElementById("overcnv").clientHeight;
document.getElementById("canvas").width=Width;
document.getElementById("canvas").height=Height;
const bz=Width/8;
ctx.clearRect(0, 0, Width, Height);
// Objet dessiné:
function Bloc(X,Y) {
ctx.strokeStyle = "black";ctx.lineWidth=3;
ctx.fillStyle = "lightblue";
ctx.beginPath();
ctx.roundRect(X-bz/2,Y-bz/2,bz,bz,10);
ctx.stroke();ctx.fill();
}
XB=100;YB=200;
Bloc(XB,YB);
function MouseClickDown(e){
// Coordonnées du click, qui va ensuite lancer le déplacement
Xclick=e.pageX-canvas.offsetLeft;Yclick=e.pageY-canvas.offsetTop;
// On ne lance le déplacement onmousemove que si
// le click est dans l'objet
if (Math.abs(Xclick-XB)<bz/2 && Math.abs(Yclick - YB)<bz/2) {
document.getElementById("canvas").style.cursor="grabbing";
canvas.onmousemove = Move;
}
}
function Move(e){
ctx.clearRect(0,0,Width,Height);
XB=e.pageX-canvas.offsetLeft;YB=e.pageY-canvas.offsetTop;
Bloc(XB,YB);
}
function MouseClickUp(e){canvas.onmousemove = null;}
canvas.onmousedown = MouseClickDown;
canvas.onmouseup = MouseClickUp;
</script>
Mapping entre mousedown/mousemove/mouseup et touchstart/touchmove/touchend
Ce programme répond aux commandes d'une souris: onmousedown
, onmouseup
et onmousemove
, et ne va pas forcément réagir à des commandes tactiles.
Je relaie ici un moyen simple de faire correspondre les événements tactiles aux événements de la souris, provenant de JavaScript mapping touch events to mouse events.
On peut rajouter pour cela dans le javascript les quelques lignes:
function touchHandler(event) {
var touches = event.changedTouches,
first = touches[0],
type = "";
switch(event.type) {
case "touchstart": type = "mousedown"; break;
case "touchmove": type = "mousemove"; break;
case "touchend": type = "mouseup"; break;
default: return;}
var simulatedEvent = document.createEvent("MouseEvent");
simulatedEvent.initMouseEvent(type, true, true, window, 1,
first.screenX, first.screenY,
first.clientX, first.clientY, false,
false, false, false, 0/*left*/, null);
first.target.dispatchEvent(simulatedEvent);
event.preventDefault();
}
function init() {
document.getElementById("overcnv").addEventListener("touchstart", touchHandler, true);
document.getElementById("overcnv").addEventListener("touchmove", touchHandler, true);
document.getElementById("overcnv").addEventListener("touchend", touchHandler, true);
document.getElementById("overcnv").addEventListener("touchcancel", touchHandler, true);
}
canvas.onmousedown = MouseClickDown;
canvas.onmouseup = MouseClickUp;
init();
On applique ce mapping seulement au canvas, dans la fonction init()
et ainsi, on ne désactive aussi que le comportement tactile normal (via event.preventDefault();
) dans le canvas et pas dans le reste de la page (les liens continuent de fonctionner, on peut encore scroller sur la page, …)
Voir aussi:
<div id="overcnv" style="width:400px;height:400px;border:2px solid blue">
<canvas id="canvas"></canvas>
</div>
<script>
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const Width=document.getElementById("overcnv").clientWidth;
const Height=document.getElementById("overcnv").clientHeight;
document.getElementById("canvas").width=Width;
document.getElementById("canvas").height=Height;
const bz=Width/8;
ctx.clearRect(0, 0, Width, Height);
// Objet dessiné:
function Bloc(X,Y) {
ctx.strokeStyle = "black";ctx.lineWidth=3;
ctx.fillStyle = "lightblue";
ctx.beginPath();
ctx.roundRect(X-bz/2,Y-bz/2,bz,bz,10);
ctx.stroke();ctx.fill();
}
XB=100;YB=200;
Bloc(XB,YB);
function MouseClickDown(e){
// Coordonnées du click, qui va ensuite lancer le déplacement
Xclick=e.pageX-canvas.offsetLeft;Yclick=e.pageY-canvas.offsetTop;
// On ne lance le déplacement onmousemove que si
// le click est dans l'objet
if (Math.abs(Xclick-XB)<bz/2 && Math.abs(Yclick - YB)<bz/2) {
document.getElementById("canvas").style.cursor="grabbing";
canvas.onmousemove = Move;
}
}
function Move(e){
ctx.clearRect(0,0,Width,Height);
XB=e.pageX-canvas.offsetLeft;YB=e.pageY-canvas.offsetTop;
Bloc(XB,YB);
}
function MouseClickUp(e){canvas.onmousemove = null;}
canvas.onmousedown = MouseClickDown;
canvas.onmouseup = MouseClickUp;
</script>
function touchHandler(event) {
var touches = event.changedTouches,
first = touches[0],
type = "";
switch(event.type) {
case "touchstart": type = "mousedown"; break;
case "touchmove": type = "mousemove"; break;
case "touchend": type = "mouseup"; break;
default: return;}
var simulatedEvent = document.createEvent("MouseEvent");
simulatedEvent.initMouseEvent(type, true, true, window, 1,
first.screenX, first.screenY,
first.clientX, first.clientY, false,
false, false, false, 0/*left*/, null);
first.target.dispatchEvent(simulatedEvent);
event.preventDefault();
}
function init() {
document.getElementById("overcnv").addEventListener("touchstart", touchHandler, true);
document.getElementById("overcnv").addEventListener("touchmove", touchHandler, true);
document.getElementById("overcnv").addEventListener("touchend", touchHandler, true);
document.getElementById("overcnv").addEventListener("touchcancel", touchHandler, true);
}
canvas.onmousedown = MouseClickDown;
canvas.onmouseup = MouseClickUp;
init();