Paintcode and Snap SVG

前端 未结 1 419
一个人的身影
一个人的身影 2021-01-28 18:21

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

相关标签:
1条回答
  • 2021-01-28 18:54

    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

    0 讨论(0)
提交回复
热议问题