La partie la plus importante de votre code manque, à savoir comment ou plus précisément sur quel élément vous enregistrez les événements. Ce que vous faites essentiellement à empêchez ce problème d'enregistrer les événements mousemove et mouseup sur l'élément svg le plus externe, et non sur l'élément que vous voulez faire glisser. Lors du démarrage du glisser, enregistrez les événements sur l'élément svg et, une fois terminé, annulez leur enregistrement.
svg.removeEventListener("mousemove", move)
svg.removeListener("mouseup", endMove)
Vous devez stocker l'élément que vous êtes en train de faire glisser, il est donc disponible dans les autres gestionnaires d'événements. Ce que je fais en plus est de mettre "pointer-events" à "none" sur l'élément déplacé de sorte que vous puissiez réagir aux événements de la souris sous l'élément déplacé (c'est-à-dire trouver la cible ...)
evt.target.setAttribute("pointer-events", "none")
mais ne pas oublier de le mettre à quelque chose raisonnable lors du déplacement se fait
evt.target.setAttribute("pointer-events", "all")
var click = false; // flag to indicate when shape has been clicked
var clickX, clickY; // stores cursor location upon first click
var moveX = 0,
moveY = 0; // keeps track of overall transformation
var lastMoveX = 0,
lastMoveY = 0; // stores previous transformation (move)
var currentTarget = null
function mouseDown(evt) {
evt.preventDefault(); // Needed for Firefox to allow dragging correctly
click = true;
clickX = evt.clientX;
clickY = evt.clientY;
evt.target.setAttribute("fill", "green");
// register move events on outermost SVG Element
currentTarget = evt.target
svg.addEventListener("mousemove", move)
svg.addEventListener("mouseup", endMove)
evt.target.setAttribute("pointer-events", "none")
}
function move(evt) {
evt.preventDefault();
if (click) {
moveX = lastMoveX + (evt.clientX - clickX);
moveY = lastMoveY + (evt.clientY - clickY);
currentTarget.setAttribute("transform", "translate(" + moveX + "," + moveY + ")");
}
}
function endMove(evt) {
click = false;
lastMoveX = moveX;
lastMoveY = moveY;
currentTarget.setAttribute("fill", "gray");
svg.removeEventListener("mousemove", move)
svg.removeEventListener("mouseup", endMove)
currentTarget.setAttribute("pointer-events", "all")
}
<svg id="svg" width="800" height="600" style="border: 1px solid black; background: #E0FFFF;">
<rect x="0" y="0" width="800" height="600" fill="none" pointer-events="all" />
<circle id="mycirc" cx="60" cy="60" r="22" onmousedown="mouseDown(evt)" />
</svg>
plus avancé
il y a encore deux les choses ne vont pas si bien avec ce code.
- il ne fonctionne pas pour les SVG viewBoxed ni pour les éléments parents transformés.
- tous les globals sont de mauvaises pratiques de codage.
Voici comment les corriger: Nr. 1 est résolu en convertissant les coordonnées de la souris en coordonnées locales en utilisant l'inverse de getScreenCTM (CTM = Current Transformation Matrix).
function globalToLocalCoords(x, y) {
var p = elem.ownerSVGElement.createSVGPoint()
var m = elem.parentNode.getScreenCTM()
p.x = x
p.y = y
return p.matrixTransform(m.inverse())
}
Pour nr. 2 voir cette mise en œuvre:
var dre = document.querySelectorAll(".draggable")
for (var i = 0; i < dre.length; i++) {
var o = new Draggable(dre[i])
}
function Draggable(elem) {
this.target = elem
this.clickPoint = this.target.ownerSVGElement.createSVGPoint()
this.lastMove = this.target.ownerSVGElement.createSVGPoint()
this.currentMove = this.target.ownerSVGElement.createSVGPoint()
this.target.addEventListener("mousedown", this)
this.handleEvent = function(evt) {
evt.preventDefault()
this.clickPoint = globalToLocalCoords(evt.clientX, evt.clientY)
this.target.classList.add("dragged")
this.target.setAttribute("pointer-events", "none")
this.target.ownerSVGElement.addEventListener("mousemove", this.move)
this.target.ownerSVGElement.addEventListener("mouseup", this.endMove)
}
this.move = function(evt) {
var p = globalToLocalCoords(evt.clientX, evt.clientY)
this.currentMove.x = this.lastMove.x + (p.x - this.clickPoint.x)
this.currentMove.y = this.lastMove.y + (p.y - this.clickPoint.y)
this.target.setAttribute("transform", "translate(" + this.currentMove.x + "," + this.currentMove.y + ")")
}.bind(this)
this.endMove = function(evt) {
this.lastMove.x = this.currentMove.x
this.lastMove.y = this.currentMove.y
this.target.classList.remove("dragged")
this.target.setAttribute("pointer-events", "all")
this.target.ownerSVGElement.removeEventListener("mousemove", this.move)
this.target.ownerSVGElement.removeEventListener("mouseup", this.endMove)
}.bind(this)
function globalToLocalCoords(x, y) {
var p = elem.ownerSVGElement.createSVGPoint()
var m = elem.parentNode.getScreenCTM()
p.x = x
p.y = y
return p.matrixTransform(m.inverse())
}
}
.dragged {
fill-opacity: 0.5;
stroke-width: 0.5px;
stroke: black;
stroke-dasharray: 1 1;
}
.draggable{cursor:move}
<svg id="svg" viewBox="0 0 800 600" style="border: 1px solid black; background: #E0FFFF;">
<rect x="0" y="0" width="800" height="600" fill="none" pointer-events="all" />
<circle class="draggable" id="mycirc" cx="60" cy="60" r="22" fill="blue" />
<g transform="rotate(45,175,75)">
<rect class="draggable" id="mycirc" x="160" y="60" width="30" height="30" fill="green" />
</g>
<g transform="translate(200 200) scale(2 2)">
<g class="draggable">
<circle cx="0" cy="0" r="30" fill="yellow"/>
<text text-anchor="middle" x="0" y="0" fill="red">I'm draggable</text>
</g>
</g>
</svg>
<div id="out"></div>
'evt.clientY - clickY' ceux-ci ne sont pas javascript juridique ... –