Related
I am using Fabric js for my project.
I have a use case where I want an object to animate along the boundary of other fabric object. Similar to motion paths in power point. To implement this, I am creating a fabric.Path object and using this path, I am getting all the boundary points of the object and animating the object along these points. The code is as shown below.
<script src="./js/fabric.js"></script>
<canvas
id="c"
width="500"
height="500"
style="border: 1px solid #ccc"
></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.1/jquery.min.js"></script>
<script id="main">
var canvas = new fabric.Canvas("c");
var circle = new fabric.Circle({
radius: 30,
fill: "#f55"
});
canvas.add(circle);
var line = new fabric.Path(
"M 0 0 L 200 100 L 170 200 z",
{
fill: "",
stroke: "black",
objectCaching : true
}
);
line.set({ name: "dummy" });
canvas.add(line);
var points = getPathValues("M 0 0 L 200 100 L 170 200 z", 1000);
function getPathValues(path_val, samples) {
var path = document.createElementNS(
"http://www.w3.org/2000/svg",
"path"
);
path.setAttribute("d", path_val);
var points = [];
var len = path.getTotalLength();
var step = (step = len / samples);
for (var i = 0; i <= len; i += step) {
var p = path.getPointAtLength(i);
points.push(p.x);
points.push(p.y);
}
return points;
}
var i = 0;
var interval = setInterval(function animate() {
i = i + 2;
if (i > points.length) {
// clearInterval(interval);
i = 0;
}
circle.left = line.left + points[i] - circle.radius;
circle.top = line.top + points[i + 1] - circle.radius;
canvas.renderAll();
}, 10);
With all this working well, Now when I scale or change position of the path object, I want to take the changed path, get the updated points and animate the object along those points. Now the problem is that when scale or change the position if the path object, The object.path for it is not getting updated automatically. I am not able to get the change path values which is needed for me to generate boundary points.
Is there any way to get the update path of the Fabric.Path object?
Is there any way to get the path of a normal fabric object?
Indeed the path data is transformed such that it becomes relative to the object's plane.
You should familiarize with relative planes and basics of matrix multiplication, at least the concepts.
This is why scale etc. don't affect it.
You need to apply the object's transformation matrix (via preTransform) to the points.
I can imagine this is too much.
That is why I have exposed fabric.util.sendPointToPlane. Check that out and it will save you a lot of headache.
fabric.util.sendPointToPlane(point, from, to), in your case fabric.util.sendPointToPlane(point, object.calcTransformMatrix(), null) will send the point to the canvas plane.
I wrote a post regarding relative planes but I can't find it, somewhere in fabric discussions
This is probably just maths.
I am using Konva to dynamically generate shapes, which I'm storing as a label. So there's a label which contains a textElement and a rectangle. I want to make sure text in that rectangle is always a) Centered horizontally and vertically and b) facing the right way up.
So a rectangle could have any rotation, but I always want the text centered and facing the right way up.
The code for creation; width, height, rotation, x and y all have values pulled from a database.
var table = new Konva.Label({
x: pos_x,
y: pos_y,
width: tableWidth,
height: tableHeight,
draggable:true
});
table.add(new Konva.Rect({
width: tableWidth,
height: tableHeight,
rotation: rotation,
fill: fillColor,
stroke: strokeColor,
strokeWidth: 4
}));
table.add(new Konva.Text({
width: tableWidth,
height: tableHeight,
x: pos_x, //Defaults to zero
y: pos_y, //Default to zero
text: tableNumber,
verticalAlign: 'middle',
align: 'center',
fontSize: 30,
fontFamily: 'Calibri',
fill: 'black'
}))
tableLayer.add(table);
The problem is, if rotation is in place, text is off center, as in this image:
I do manually correct in some circumstances - for example if rotation = 45 degrees:
pos_x = -tableWidth/2;
pos_y = tableHeight/5;
but that is not a permanent solution. I want the x and y co-ordinates of the text to be at the centerpoint of the shape itself.
I've tried a few approaches (such as applying rotation to the Label itself and then negative rotation value to the text)
This code snippet illustrates a solution. It is copied & modified from my other self-answer when I was looking for a robust approach to rotation around an arbitrary point - note that I consider this a slightly different question than my original so I have not suggested this is a dup. The difference is the need to work with a more complex grouped shape and to keep some element within that group unrotated.
Not in the OP's question, but I set a background rectangle into the text by making the text a group. The purpose of this was to show that the text rectangle will extend outside the label rectangle in some points of rotation. This is not a critical issue but it is useful to see it happen.
The fundamental challenge for the coder is to understand how the shapes move when rotated since we usually want to spin them around their centre but the fundamental 2D canvas pattern that Konva (and all HTML5 canvas wrappers) follow is to rotate from the top-left corner, al least for rectangles as per shapes in the question. It 'is' possible to move the rotation point (known as the offset) but again that is a conceptual challenge for the dev and a nice trap for anyone trying to support the code later.
There's a lot of code in this answer that is here to set up something dynamic that you can use to visualise what is going on. However, the crux is in this:
// This is the important call ! Cross is the rotation point as illustrated by crosshairs.
rotateAroundPoint(shape, rotateBy, {x: cross.x(), y: cross.y()});
// The label is a special case because we need to keep the text unrotated.
if (shape.name() === 'label'){
let text = shape.find('.text')[0];
rotateAroundPoint(text, -1 * rotateBy, {x: text.getClientRect().width/2, y: text.getClientRect().height/2});
}
The rotateAroundPoint() function takes as parameters the Konva shape to rotate, the clockwise rotation angle (not radians, good ole degrees), and the x & y position of the rotation point on the canvas / parent.
I constructed a group of shapes as my label, composing it from a rectangle and a text shape. I named this 'label'. Actually I switched the text shape to be another group of rect + text to that I could show the rectangle the text sits within. You could leave out the extra group. I named this 'text'.
The first call to rotateAroundPoint() rotates the group named 'label'. So the group rotates on the canvas. Since the 'text' is a child of the 'label' group, that would leave the 'text' rotated, so the next line checks if we are working with the 'label' group, and if so we need to get hold of the 'text' shape which is what this line does:
let text = shape.find('.text')[0];
In Konva the result of a find() is a list so we take the first in the list. Now all that remains for me to do is rotate the text on the 'label' group back again by applying the negative rotation degrees to its center point. The line below achieves this.
rotateAroundPoint(text, -1 * rotateBy, {x: text.getClientRect().width/2, y: text.getClientRect().height/2});
One note worthy of mention - I used a group for my 'text' shape. A Konva group does not naturally have a width or height - it is more of a means to collect shapes together but without a 'physical' container. So to get its width and height for the centre point calculations I use the group.getClientRect() method which gives the size of the minimum bounding box that would contain all shapes in the group, and yields an object formed as {width: , height: }.
Second note - the first use of rotateAroundPoint() affects the 'label' group which has as its parent the canvas. The second use of that function affects the 'text' group which has the 'label' group as its parent. Its subtle but worth knowing.
Here is the snippet. I urge you to run it fullscreen and spin a few shapes around a few different points.
// Code to illustrate rotation of a shape around any given point. The important functions here is rotateAroundPoint() which does the rotation and movement math !
let
angle = 0, // display value of angle
startPos = {x: 80, y: 45},
shapes = [], // array of shape ghosts / tails
rotateBy = 20, // per-step angle of rotation
shapeName = $('#shapeName').val(), // what shape are we drawing
shape = null,
ghostLimit = 10,
// Set up a stage
stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight
}),
// add a layer to draw on
layer = new Konva.Layer(),
// create the rotation target point cross-hair marker
lineV = new Konva.Line({points: [0, -20, 0, 20], stroke: 'lime', strokeWidth: 1}),
lineH = new Konva.Line({points: [-20, 0, 20, 0], stroke: 'lime', strokeWidth: 1}),
circle = new Konva.Circle({x: 0, y: 0, radius: 10, fill: 'transparent', stroke: 'lime', strokeWidth: 1}),
cross = new Konva.Group({draggable: true, x: startPos.x, y: startPos.y}),
labelRect, labelText;
// Add the elements to the cross-hair group
cross.add(lineV, lineH, circle);
layer.add(cross);
// Add the layer to the stage
stage.add(layer);
$('#shapeName').on('change', function(){
shapeName = $('#shapeName').val();
shape.destroy();
shape = null;
reset();
})
// Draw whatever shape the user selected
function drawShape(){
// Add a shape to rotate
if (shape !== null){
shape.destroy();
}
switch (shapeName){
case "rectangle":
shape = new Konva.Rect({x: startPos.x, y: startPos.y, width: 120, height: 80, fill: 'magenta', stroke: 'black', strokeWidth: 4});
break;
case "hexagon":
shape = new Konva.RegularPolygon({x: startPos.x, y: startPos.y, sides: 6, radius: 40, fill: 'magenta', stroke: 'black', strokeWidth: 4});
break;
case "ellipse":
shape = new Konva.Ellipse({x: startPos.x, y: startPos.y, radiusX: 40, radiusY: 20, fill: 'magenta', stroke: 'black', strokeWidth: 4});
break;
case "circle":
shape = new Konva.Ellipse({x: startPos.x, y: startPos.y, radiusX: 40, radiusY: 40, fill: 'magenta', stroke: 'black', strokeWidth: 4});
break;
case "star":
shape = new Konva.Star({x: startPos.x, y: startPos.y, numPoints: 5, innerRadius: 20, outerRadius: 40, fill: 'magenta', stroke: 'black', strokeWidth: 4});
break;
case "label":
shape = new Konva.Group({name: 'label'});
labelRect = new Konva.Rect({x: 0, y: 0, width: 120, height: 80, fill: 'magenta', stroke: 'black', strokeWidth: 4, name: 'rect'})
shape.add(labelRect);
labelText = new Konva.Group({name: 'text'});
labelText.add(new Konva.Rect({x: 0, y: 0, width: 100, height: 40, fill: 'cyan', stroke: 'black', strokeWidth: 2}))
labelText.add(new Konva.Text({x: 0, y: 0, width: 100, height: 40, text: 'Wombat',fontSize: 20, fontFamily: 'Calibri', align: 'center', padding: 10}))
shape.add(labelText)
labelText.position({x: (labelRect.width() - labelText.getClientRect().width) /2, y: (labelRect.height() - labelText.getClientRect().height) /2})
break;
};
layer.add(shape);
cross.moveToTop();
}
// Reset the shape position etc.
function reset(){
drawShape(); // draw the current shape
// Set to starting position, etc.
shape.position(startPos)
cross.position(startPos);
angle = 0;
$('#angle').html(angle);
$('#position').html('(' + shape.x() + ', ' + shape.y() + ')');
clearTails(); // clear the tail shapes
stage.draw(); // refresh / draw the stage.
}
// Click the stage to move the rotation point
stage.on('click', function (e) {
cross.position(stage.getPointerPosition());
stage.draw();
});
// Rotate a shape around any point.
// shape is a Konva shape
// angleRadians is the angle to rotate by, in radians
// point is an object {x: posX, y: posY}
function rotateAroundPoint(shape, angleDegrees, point) {
let angleRadians = angleDegrees * Math.PI / 180; // sin + cos require radians
const x =
point.x +
(shape.x() - point.x) * Math.cos(angleRadians) -
(shape.y() - point.y) * Math.sin(angleRadians);
const y =
point.y +
(shape.x() - point.x) * Math.sin(angleRadians) +
(shape.y() - point.y) * Math.cos(angleRadians);
shape.rotation(shape.rotation() + angleDegrees); // rotate the shape in place
shape.x(x); // move the rotated shape in relation to the rotation point.
shape.y(y);
shape.moveToTop(); //
}
$('#rotate').on('click', function(){
let newShape = shape.clone();
shapes.push(newShape);
layer.add(newShape);
// This ghost / tails stuff is just for fun.
if (shapes.length >= ghostLimit){
shapes[0].destroy();
shapes = shapes.slice(1);
}
for (var i = shapes.length - 1; i >= 0; i--){
shapes[i].opacity((i + 1) * (1/(shapes.length + 2)))
};
// This is the important call ! Cross is the rotation point as illustrated by crosshairs.
rotateAroundPoint(shape, rotateBy, {x: cross.x(), y: cross.y()});
// The label is a special case because we need to keep the text unrotated.
if (shape.name() === 'label'){
let text = shape.find('.text')[0];
rotateAroundPoint(text, -1 * rotateBy, {x: text.getClientRect().width/2, y: text.getClientRect().height/2});
}
cross.moveToTop();
stage.draw();
angle = angle + 10;
$('#angle').html(angle);
$('#position').html('(' + Math.round(shape.x() * 10) / 10 + ', ' + Math.round(shape.y() * 10) / 10 + ')');
})
// Function to clear the ghost / tail shapes
function clearTails(){
for (var i = shapes.length - 1; i >= 0; i--){
shapes[i].destroy();
};
shapes = [];
}
// User cicks the reset button.
$('#reset').on('click', function(){
reset();
})
// Force first draw!
reset();
body {
margin: 10;
padding: 10;
overflow: hidden;
background-color: #f0f0f0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://unpkg.com/konva#^3/konva.min.js"></script>
<p>1. Click the rotate button to see what happens when rotating around shape origin.</p>
<p>2. Reset then click stage to move rotation point and click rotate button again - rinse & repeat</p>
<p>
<button id = 'rotate'>Rotate</button>
<button id = 'reset'>Reset</button>
<select id='shapeName'>
<option value='label' selected='selected'>Label</option>
<option value='rectangle'>Rectangle</option>
<option value='hexagon'>Polygon</option>
<option value='ellipse' >Ellipse</option>
<option value='circle' >Circle</option>
<option value='star'>Star</option>
</select>
Angle : <span id='angle'>0</span>
Position : <span id='position'></span>
</p>
<div id="container"></div>
How to find the intersection point of a line and a quadratic curve?
Here is the code to generate the figure of choice:
var s = Snap(300, 300);
var path = s.path("M 35 50 h 100 v 50 q -25 -20 -50 0 q -25 20 -50 0 z")
path.attr({
fill:'none',
stroke: 'black'
});
var bbox = Snap.path.getBBox(path);
console.log(bbox);
var pbox = path.getBBox();
console.log(pbox);
s.circle(bbox.x, bbox.y, 3).attr('fill', 'red');
s.circle(bbox.x2, bbox.y2, 3).attr('fill', 'red');
s.circle(bbox.cx, bbox.cy, 3).attr('fill', 'magenta');
var l = s.line(bbox.cx, bbox.cy, 250, 200).attr('stroke', 'black');
var lbox = l.getBBox();
console.log(lbox);
The image looks like this:
I am trying to find the point highlighted by the blue circle.
Plunk: http://plnkr.co/edit/ZFo381tZfG4SHWHKyINZ?p=preview
Snap has a method Snap.path.intersection. So if you can use a path instead of a line, you could use that method. Just be aware that if the paths can change, there may be multiple or no intersections, so you may want to loop through the intersections, rather than just taking the first.
Changed bits of code...
var l = s.path('M'+bbox.cx+','+bbox.cy+'L250,200').attr({ stroke: 'black'})
var intersection = Snap.path.intersection( path.attr('d'), l.attr('d'))
s.circle( intersection[0].x, intersection[0].y,5 )
example
Short question: using SVG path, we can draw 99.99% of a circle and it shows up, but when it is 99.99999999% of a circle, then the circle won't show up. How can it be fixed?
The following SVG path can draw 99.99% of a circle: (try it below and see if you see 4 arcs or only 2 arcs, but note that if it is IE, it is rendered in VML, not SVG, but have the similar issue)
var paper = Raphael(0, 0, 300, 800);
// Note that there are supposed to be 4 arcs drawn, but you may see only 1, 2, or 3 arcs depending on which browser you use
paper.path("M 100 100 a 50 50 0 1 0 35 85").attr({stroke: "#080", opacity: 1, "stroke-width" : 6}) // this is about 62.5% of a circle, and it shows on most any browsers
paper.path("M 100 210 a 50 50 0 1 0 0.0001 0").attr({stroke: "#080", opacity: 1, "stroke-width" : 6}) // this one won't show anything if it is IE 8's VML, but will show if it is Chrome or Firefox's SVG. On IE 8, it needs to be 0.01 to show
paper.path("M 100 320 a 50 50 0 1 0 0.0000001 0").attr({stroke: "#080", opacity: 1, "stroke-width" : 6}) // this one won't draw anything at all, unless you change the 0.0000001 to 0.0001 on Chrome or Firefox... Safari will show it though...
paper.path("M 100 430 a 50 50 0 1 0 0 0").attr({stroke: "#080", opacity: 1, "stroke-width" : 6}) // this is 100% of a circle... even Safari won't show it
<script src="https://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
M 100 100 a 50 50 0 1 0 0.00001 0
But when it is 99.99999999% of a circle, then nothing will show at all?
M 100 100 a 50 50 0 1 0 0.00000001 0
And that's the same with 100% of a circle (it is still an arc, isn't it, just a very complete arc)
M 100 100 a 50 50 0 1 0 0 0
How can that be fixed? The reason is I use a function to draw a percentage of an arc, and if I need to "special case" a 99.9999% or 100% arc to use the circle function, that'd be kind of silly.
Again, a test case is above
(and if it is VML on IE 8, even the second circle won't show... you have to change it to 0.01)
Update:
This is because I am rendering an arc for a score in our system, so 3.3 points get 1/3 of a circle. 0.5 gets half a circle, and 9.9 points get 99% of a circle. But what if there are scores that are 9.99 in our system? Do I have to check whether it is close to 99.999% of a circle, and use an arc function or a circle function accordingly? Then what about a score of 9.9987? Which one to use? It is ridiculous to need to know what kind of scores will map to a "too complete circle" and switch to a circle function, and when it is "a certain 99.9%" of a circle or a 9.9987 score, then use the arc function.
I know it's a bit late in the game, but I remembered this question from when it was new and I had a similar dillemma, and I accidently found the "right" solution, if anyone is still looking for one:
<path
d="
M cx cy
m -r, 0
a r,r 0 1,0 (r * 2),0
a r,r 0 1,0 -(r * 2),0
"
/>
In other words, this:
<circle cx="100" cy="100" r="75" />
can be achieved as a path with this:
<path
d="
M 100, 100
m -75, 0
a 75,75 0 1,0 150,0
a 75,75 0 1,0 -150,0
"
/>
The trick is to have two arcs, the second one picking up where the first left off and using the negative diameter to get back to the original arc start point.
The reason it can't be done as a full circle in one arc (and I'm just speculating) is because you would be telling it to draw an arc from itself (let's say 150,150) to itself (150,150), which it renders as "oh, I'm already there, no arc necessary!".
The benefits of the solution I'm offering are:
it's easy to translate from a circle directly to a path, and
there is no overlap in the two arc lines (which may cause issues if you are using markers or patterns, etc). It's a clean continuous line, albeit drawn in two pieces.
None of this would matter if they would just allow textpaths to accept shapes. But I think they are avoiding that solution since shape elements like circle don't technically have a "start" point.
snippet demo:
circle, path {
fill: none;
stroke-width: 5;
stroke-opacity: .5;
}
circle {
stroke: red;
}
path {
stroke: yellow;
}
<?xml version="1.0" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
width="220px" height="220px">
<circle cx="100" cy="100" r="75" />
<path
d="
M 100, 100
m -75, 0
a 75,75 0 1,0 150,0
a 75,75 0 1,0 -150,0
"
/>
</svg>
Update:
If you are using the path for a textPath reference and you are wanting the text to render on the outer edge of the arc, you would use the exact same method but change the sweep-flag from 0 to 1 so that it treats the outside of the path as the surface instead of the inside (think of 1,0 as someone sitting at the center and drawing a circle around themselves, while 1,1 as someone walking around the center at radius distance and dragging their chalk beside them, if that's any help). Here is the code as above but with the change:
<path
d="
M cx cy
m -r, 0
a r,r 0 1,1 (r * 2),0
a r,r 0 1,1 -(r * 2),0
"
/>
Same for XAML's arc. Just close the 99.99% arc with a Z and you've got a circle!
In reference to Anthony’s solution, here is a function to get the path:
function circlePath(cx, cy, r){
return 'M '+cx+' '+cy+' m -'+r+', 0 a '+r+','+r+' 0 1,0 '+(r*2)+',0 a '+r+','+r+' 0 1,0 -'+(r*2)+',0';
}
A totally different approach:
Instead of fiddling with paths to specify an arc in svg, you can also take a circle element and specify a stroke-dasharray, in pseudo code:
with $score between 0..1, and pi = 3.141592653589793238
$length = $score * 2 * pi * $r
$max = 7 * $r (i.e. well above 2*pi*r)
<circle r="$r" stroke-dasharray="$length $max" />
Its simplicity is the main advantage over the multiple-arc-path method (e.g. when scripting you only plug in one value and you're done for any arc length)
The arc starts at the rightmost point, and can be shifted around using a rotate transform.
Note: Firefox has an odd bug where rotations over 90 degrees or more are ignored. So to start the arc from the top, use:
<circle r="$r" transform="rotate(-89.9)" stroke-dasharray="$length $max" />
Building upon Anthony and Anton's answers I incorporated the ability to rotate the generated circle without affecting it's overall appearance. This is useful if you're using the path for an animation and you need to control where it begins.
function(cx, cy, r, deg){
var theta = deg*Math.PI/180,
dx = r*Math.cos(theta),
dy = -r*Math.sin(theta);
return "M "+cx+" "+cy+"m "+dx+","+dy+"a "+r+","+r+" 0 1,0 "+-2*dx+","+-2*dy+"a "+r+","+r+" 0 1,0 "+2*dx+","+2*dy;
}
i made a jsfiddle to do it in here:
function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;
return {
x: centerX + (radius * Math.cos(angleInRadians)),
y: centerY + (radius * Math.sin(angleInRadians))
};
}
function describeArc(x, y, radius, startAngle, endAngle){
var start = polarToCartesian(x, y, radius, endAngle);
var end = polarToCartesian(x, y, radius, startAngle);
var largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";
var d = [
"M", start.x, start.y,
"A", radius, radius, 0, largeArcFlag, 0, end.x, end.y
].join(" ");
return d;
}
console.log(describeArc(255,255,220,134,136))
link
all you need to do is to change the input of console.log and get the result in console
For those like me who were looking for an ellipse attributes to path conversion:
const ellipseAttrsToPath = (rx,cx,ry,cy) =>
`M${cx-rx},${cy}a${rx},${ry} 0 1,0 ${rx*2},0a${rx},${ry} 0 1,0 -${rx*2},0 Z`
Adobe Illustrator uses bezier curves like SVG, and for circles it creates four points. You can create a circle with two elliptical arc commands...but then for a circle in SVG I would use a <circle /> :)
Written as a function, it looks like this:
function getPath(cx,cy,r){
return "M" + cx + "," + cy + "m" + (-r) + ",0a" + r + "," + r + " 0 1,0 " + (r * 2) + ",0a" + r + "," + r + " 0 1,0 " + (-r * 2) + ",0";
}
It's a good idea that using two arc command to draw a full circle.
usually, I use ellipse or circle element to draw a full circle.
Another way would be to use two Cubic Bezier Curves. That's for iOS folks using pocketSVG which doesn't recognize svg arc parameter.
C x1 y1, x2 y2, x y (or c dx1 dy1, dx2 dy2, dx dy)
The last set of coordinates here (x,y) are where you want the line to end. The other two are control points. (x1,y1) is the control point for the start of your curve, and (x2,y2) for the end point of your curve.
<path d="M25,0 C60,0, 60,50, 25,50 C-10,50, -10,0, 25,0" />
These answers are much too complicated.
A simpler way to do this without creating two arcs or convert to different coordinate systems..
This assumes your canvas area has width w and height h.
`M${w*0.5 + radius},${h*0.5}
A${radius} ${radius} 0 1 0 ${w*0.5 + radius} ${h*0.5001}`
Just use the "long arc" flag, so the full flag is filled. Then make the arcs 99.9999% the full circle. Visually it is the same. Avoid the sweep flag by just starting the circle at the rightmost point in the circle (one radius directly horizontal from the center).
I'm trying to create an animated line as if its being drawn from one point to another. I have managed to get the line drawing on to the page but can't work out how to animate it as if it's being drawn?
https://jsfiddle.net/0sdt33dz/
function svgAnimate (){
var s = Snap('#svg');
var linePath = "M-3,148.6c0,0,43.9,7,49.4-17.2c3.5-15.3-9.4-19.7-17.3-13.8c-6,4.4-10,19,11.3,25.4 c24.9,7.5,70.7-31.2,91-61.8S233-41.5,286.3,29.2c0,0-60.7,35.5-24.9,87.9c36.2,53,83.5,15.6,83.5,15.6s19.3,19.5,68.4,17.1";
var lineLength = Snap.path.getTotalLength(linePath);
var lineDraw = s.path(linePath);
lineDraw.attr({
fill:'none',
stroke:'#009FE3',
'stroke-width' :6,
'stroke-linecap' :'round',
'stroke-linejoin' :'round',
'stroke-miterlimit' :10
});
lineDraw.animate({
stroke : '#fff'
},3000, mina.easein)
console.log(lineLength);
}
svgAnimate();
You're almost there, just missing two things.
First, you need to set the stroke-dasharray to '<length> <length>', this will create a "dashed" line with gaps/fill equal to the length of the entire line
lineDraw.attr({
fill:'none',
stroke:'#009FE3',
'stroke-dasharray': lineLength + ' ' + lineLength,
'stroke-dashoffset': lineLength,
'stroke-width' :6,
...
After this you need to animate the offset of the stroke to 0 using stoke-dashoffset
lineDraw.animate({
strokeDashoffset : 0
},3000, mina.easein)
working fiddle
var s = Snap("#myLine");
//Line parameters (x1, y1, x2, y2)
var line = s.line(30, 45, 30, 45);
line.attr({
stroke: "#000",
strokeWidth: 2
});
//Old x2 values is 30 and now it is increasing to 70 with 1 second duration
line.animate({x2: 70}, 1000);
I hope this answer will help you!