I am trying to bridge examples from Paintcode and Snap SVG.
Here is a simple project that has the gears that spin when a slider is dragged. This is great but I would lik
EDIT: SEE LOWER DOWN FOR IMPROVED METHOD
Firstly, it may be easier to move the transform from the group in the 2nd example to the path. Then you can add any rotation transforms to the group without getting too messy. Eg.
<g id="gears-largeGroup" >
<path transform="translate(149.59, 96.41)" id="gears-largeGear".....
Once you have your SVG, you can select it in Snap with the Snap.select() method. This takes a css selector.
So we can find one with
Snap.select('#gears-smallGroup')
Now we have our gear, we can add a drag handler to it.
Snap.select('#gears-smallGroup').drag( dragRotate, dragStart )
So we just need to write our handler. Firstly we want to store the start of the drag (see updated solution at end, which is better), so we can write our startRotate function. This just stores an x,y object alongside the element.
function dragRotateStart( x, y ) {
this.data('oxy', { x: x, y: y })
}
Then we can write the main drag rotation handler. This takes the original start position oxy stored above, and adds it to the drags delta increments that is passes over.
Then we uses Snaps angle() method to calculate the angle between two points. One the x,y we just had, and the other the center of the element.
Now we have the angle, we can just do a rotation transform. Snap can use a shortform for a transform (r=rotation, t=translate, s=scale and r&s with Snap will transform from their centers unless specified).
So this becomes
function dragRotate( dx, dy, x, y ) {
this.transform('r' + Snap.angle( this.getBBox().cx, this.getBBox().cy, dx + this.data('oxy').x, dy + this.data('oxy').y ) );
}
So whole code...
Snap.select('#gears-smallGroup').drag( dragRotate, dragRotateStart )
Snap.select('#gears-largeGroup').drag( dragRotate, dragRotateStart )
function dragRotate( dx, dy, x, y ) {
this.transform('r' + Snap.angle( this.getBBox().cx, this.getBBox().cy, dx + this.data('oxy').x, dy + this.data('oxy').y ) );
}
function dragRotateStart( x, y ) {
this.data('oxy', { x: x, y: y })
}
jsfiddle
Now you have this, you can fiddle with it, so that one will rotate the other. You may also have to check the starting points after a redrag depending on where your new drag starts from.
(quick stab at making smaller gear rotate bigger one jsfiddle)
UPDATED AND IMPROVED VERSION:
Extending this further, you will need to adapt it, to take into account both the starting rotation (also if it's pre-rotated) and the starting angle in the drag, we only want the difference in angles, so it doesn't reset.
So we can store out starting bits. What angle was the start of the drag at (I've set default to 10 as the image dot was offset by about 10deg). What was the old rotation of the element.
function dragRotateStart(x, y) {
this.data('startingAngle', Snap.angle(this.getBBox().cx, this.getBBox().cy, x, y));
this.data('startingRotation', this.data('rotation')||10)
}
And then calculate the correct rotation from the starting rotation, plus the angle difference, storing it as we go (so if we drag again later, we know what its last rotation was)...
function dragRotate(dx, dy, x, y) {
var angleDiff = Snap.angle(this.getBBox().cx, this.getBBox().cy, x, y) - this.data('startingAngle')
var newRotation = angleDiff + +this.data('startingRotation');
this.data('rotation', newRotation)
this.transform('r' + newRotation);
}
jsfiddle