Question

I am trying to workout animation of meter chart. But, the pointy end of chord goes outside the circumference of the ellipse while animating. This fiddle explains the issue that I am facing.

Expected output: The pointy end should well remain within the ellipse while animating.

Here, I am using snap.svg library to animate the chord.

Code through which I am trying to achieve this animation is:

var snapper = Snap("svg");

Snap.animate([-230],[0],
function(val){
    snapper.select("#meter").attr({
        "transform":"scale(1 1) rotate(" + val[0] + " 242.5 208)"
    });
},10000,mina.linear);

Any help is appreciated.

Thanks in advance!!!

Was it helpful?

Solution

This is not a complete answer, but an investigation of your problem.

First you should draw the needle with normalized values (with the center that you wish to rotate in 0,0), and then use translate to move the graphic to the center of the display. That makes it easier to rotate it. For example:

<defs>
<g id="meter">
        <line x1="4.24" y1="-9.195" x2="194.35" y2="25.935"/>
        <line x1="0" y1="9.195" x2="194.35" y2="25.935"/>
        <line x1="0" y1="9.195" x2="-9.89" y2="-1.555"/>
        <line x1="4.24" y1="-9.195" x2="-9.89" y2="-1.555"/>
</g>
</defs> 

Then you draw it in the place you want to rotate it:

<use xlink:href="#meter" transform="translate(241.88,198.1)" />

Now it will scale in relation to the origin 0,0 and won't move around the screen.

You can also obtain the same result adding the center coordinates as arguments to the scale transform, as suggested by @Ian:

scale(1 1 241.88 198.1)

The other problem is more complex. The length of the needle has to be the radius for each point in the curve. If you have that radius, you scale it proportionally. The radius can be calculated as a function of the angle, but you are using bezier curves, not arcs, so its not a trivial formula. I am not sure, but I think there are SVG libraries that have functions that approximate bezier to arcs. You might want to pose that problem (how to obtain the radius coordinates in a bezier curve for a certain angle) as a separate question (here in SO or in math stack exchange).

Below is an approximation (covering only 90 degrees) and using a correction based on sine and log functions. It might work for you if you don't need something exact. I simplified the SVG and kept only the essential parts.

var snapper = Snap("svg");
Snap.animate([-100,0.72,0.89],[-10,1,1],
    function(val) {
        var dim = val[1];
        var corr = (Math.sin(2*(val[0]+10)*Math.PI/180))*Math.log(val[2]);

        snapper.select("#meter").attr({
        "transform":"scale("+(dim-corr)+" "+(dim-corr)+") rotate(" + val[0] + " 0 0)"
        });
    }, 10000, mina.linear);

See it here: JSFiddle. You can use it as a starting point and try to adapt it to your problem.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top