I have to do group translation (SVG) for specific reason. I don't know why I can't make it properly, because after translation is made, on the other click on group it resets translation on start position and make fool of me running around over SVG canvas. I write the barebone example at link: http://www.atarado.com/en/stripboard-layout-software/group-translation-problem.svg , and here's the code:
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<script><![CDATA[
function startMove(evt){
x1=evt.clientX;
y1=evt.clientY;
group=evt.target.parentNode;
group.setAttribute("onmousemove","moveIt(evt)");
}
function moveIt(evt){
dx=evt.clientX-x1;
dy=evt.clientY-y1;
group.setAttributeNS(null,"transform","translate("+ dx + ", " + dy +")");
}
function drop(){
group.setAttributeNS(null, "onmousemove",null);
}
]]></script>
<rect x="0" y="0" width="100%" height="100%" fill="dodgerblue"/>
<g id="BC" transform="translate(0, 0)" onmousedown="startMove(evt)" onmouseup="drop()"><circle id="C" cx="60" cy="60" r="22" fill="lightgrey" stroke="black" stroke-width="8"/><circle id="B" cx="120" cy="60" r="22" fill="orange" stroke="black" stroke-width="8" /></g>
</svg>
Anybody willing to help is welcome.
The reason position of the group resets on the second move is that you set the transform to translation with (dx, dy)
being equal to the difference between the position the move started (x1, y1)
and the current position (evt.clientX, evt.clientY)
. This means that when you click the second time and them move the mouse slightly then dx and dy are small numbers. They are then used to set the transform to something slightly off the initial position. Remember that at any time the transform applied to the group must describe the transformation from the initial position of the group.
One way to fix the problem would be to store the total delta from all the moves applied to the group so far and use this accumulated (dx, dy)
to build the transform. For example:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<script><![CDATA[
function startMove(evt){
group=evt.target.parentNode;
x1=evt.clientX - group.$x;
y1=evt.clientY - group.$y;
group.setAttribute("onmousemove","moveIt(evt)");
}
function moveIt(evt){
dx=evt.clientX-x1;
dy=evt.clientY-y1;
group.setAttributeNS(null,"transform","translate("+ dx + ", " + dy +")");
group.$x = dx;
group.$y = dy;
}
function drop(){
group.setAttributeNS(null, "onmousemove",null);
}
]]></script>
<rect x="0" y="0" width="100%" height="100%" fill="dodgerblue"/>
<g id="BC" transform="translate(0, 0)" onmousedown="startMove(evt)" onmouseup="drop()">
<circle id="C" cx="60" cy="60" r="22" fill="lightgrey" stroke="black" stroke-width="8"/>
<circle id="B" cx="120" cy="60" r="22" fill="orange" stroke="black" stroke-width="8" />
</g>
<script><![CDATA[
var group=document.getElementById("BC");
group.$x = 0;
group.$y = 0;
]]></script>
</svg>
We have added two properties to the group elememt: $x
and $y
to store the current position of the element (or the accumulated deltas from all the moves so far, depending on the way you look at it). They're initialized to zero in the script located after the element with ID "BC" is defined. They are updated in moveIt()
and consumed in startMove()
. Since we subtract our new deltas ($x, $y)
from (x1, y1)
in startMove()
, these new deltas effectively get added to (dx, dy)
later in moveIt()
. This ensures (dx, dy)
accounts for all the moves so far as well as for the current move.