I'm drawing an arrow between two spots on the page. Each time this is called, the arrow is cleared and redrawn with different points. Right now the line is drawing correctly, but there is no arrow at the end. I'm using the jQuery SVG plugin
var svg = $('#board').svg('get');
svg.clear();
var startX = fromCol*sideLen + sideLen/2;
var startY = fromRow*sideLen + sideLen/2;
var endX = toCol*sideLen + sideLen/2;
var endY = toRow*sideLen + sideLen/2;
svg.line(startX, startY, endX, endY, {
strokeWidth: 5
, stroke: 'yellow'
, strokeLineCap: 'round'
, strokeLineJoin: 'miter'
});
The camel-case variables are setting to the correct CSS properties, I double checked that. An example output of this code in the DOM is
`<line x1="375" y1="325" x2="325" y2="275" stroke-width="5" stroke="yellow" stroke-linecap="round" stroke-linejoin="miter"></line>`
I'm stumped. Thanks for the help!
Figured it out. I define this in the setup:
$('#board').svg();
var svg = $('#board').svg('get');
// Adds a marker to the svg defs element
var defs = svg.defs();
var marker = svg.marker(defs, 'arrow', 3, 2, 5, 5, 'auto');
// Define the shape of the marker
svg.polyline(marker, [[0,0], [4,2], [0,4], [1,2]], {
"fill" : "yellow"
});
And call this when drawing the line, similar to earlier but with the new setting and an id.
var svg = $('#board').svg('get');
var g = svg.group({stroke: 'yellow', strokeWidth: 5});
svg.line(g, startX, startY, endX, endY, {
"id" : "line"
, "strokeLineCap" : "round"
, "marker-end" : "url(#arrow)"
});
Related
im trying to put the marker-mid on the line element, im using SVG.js. For example im using this code:
var draw = SVG('yourdivid');
var line = draw.line( 100, 100, 0, 0).move(20, 20);
line.stroke({ color: '#000', width: 2};
now how can i put the marker at the mid of this line using the marker-mid?
i read the doc of svg.js and also this" https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/marker-mid#Examples"
they say that you can use the marker-mid element also with the line, i know that this marker works with the path element, but i need to use it with a line, can you help me please?
thank you for your help
You could just work out the mid point of the line yourself and draw a circle at that point.
var start = [100, 100];
var end = [0, 0];
function midPoint(start, end) {
return [
(start[0] + end[0]) / 2,
(start[1] + end[1]) / 2
];
}
var lineGroup = svg.group();
lineGroup.line(start[0][0], start[0][1], end[0][0], end[0][1]);
var dot = lineGroup.circle(3);
var mid = midPoint(start, end);
dot.cx(mid[0]);
dot.cy(mid[1]);
marker-mid does not work on lines. To have start and end markers, this code would do it:
var draw = SVG('yourdivid');
draw.line( 100, 100, 0, 0)
.move(20, 20)
.stroke({ color: '#000', width: 2})
.marker('start', 10, 10, function(add){
add.circle(10).center(5,5)
})
However, to have markers at the mid of a line see p0wdr.com's answer
I have a simple rectangle that forms the clipping area for all shapes added to the canvas, which is working great:
var area = new paper.Rectangle(
100, 100, 300, 120
);
var path = new paper.Path.Rectangle(area);
group.addChild(path);
group.clipped = true;
What I'm trying to achieve is instead of hiding the paths that fall outside of this area, they are shown with a slight opacity, something like:
Thanks in advance for any help and suggestions.
This is not a simple way as clipped, you might do it by using method intersect.
Please try this code.
// SET INITIAL
var area = new paper.Path.Rectangle(100, 100, 300, 220);
area.fillColor = 'yellow'
area.opacity = 0.2
var circle1 = new paper.Path.Circle({
center:[150, 150],
radius: 100,
fillColor: 'red'
})
// OPACITY CLIPPING
var circle2 = circle1.intersect(area)
circle1.opacity = 0.2
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!
I'm trying to have a circle follow an elliptical path that is rotated, using Snap.svg, but I've ran into a problem.
Using the getPointAtLength only returns the point of the path that is not rotated, so when I rotate the path, the circle will still follow the original path, before rotation.
var firstOrbit = s.path("M250,400a150,75 0 1,0 300,0a150,75 0 1,0 -300,0")
.attr({stroke: "#000", strokeWidth:"5", fill: "transparent"});
var len = firstOrbit.getTotalLength();
firstOrbit = firstOrbit.transform('r75,400,400');
var circleA = s.circle(0,0,10);
var startingPointA = Snap.path.getPointAtLength(firstOrbit, 0);
Snap.animate(0, len, function(value){
var movePoint = firstOrbit.getPointAtLength(value);
circleA.attr({ cx: movePoint.x, cy: movePoint.y });
}, 2000, mina.linear);
The problem is, that the ellipse rotates, but the path that circleA follows does not, so it follows a wrong path. Is there an easy way to fix this, or do I have to calculate the difference at each step of the animation?
You have two possible solutions for this issue. Either you will have to put the <path> and <circle> inside a <g> group and apply transformations to the group Or find actual point on path and then find the transformed point by applying the transformation matrix.
Solution 1
var len = firstOrbit.getTotalLength();
var circleA = s.circle(0,0,10);
var group = s.g(firstOrbit,circleA);
group = group.transform('r75,400,400');
JSFiddle
Solution 2
var pt = s.node.createSVGPoint();
Snap.animate(0, len, function(value){
var movePoint = firstOrbit.getPointAtLength(value);
pt.x = movePoint.x;
pt.y = movePoint.y;
movePoint = pt.matrixTransform(firstOrbit.node.getCTM());
circleA.attr({ cx: movePoint.x, cy: movePoint.y });
}, 2000, mina.linear);
JSFiddle
Put both the circle and the path inside a group. Apply the transform/rotation to the group (instead of the path) so that both the circle and the path inherit the same transform.
.
I am making a polygon from lines.
x = options.e.pageX - offset.left;
y = options.e.pageY - offset.top;
On click, I capture mouse position. After, I add that point to array of points.
roofPoints.push(new Point(x, y));
function Point(x, y) {
this.x = x;
this.y = y;
}
When all points are set I do this:
var roof = new fabric.Polyline(roofPoints, {
fill : 'purple',
});
The problem with this is that while I set points I am drawing lines for the polygon like so:
var points = [ x, y, x, y ];
lines.push(new fabric.Line(points, {
strokeWidth : 1,
selectable : false,
stroke : 'red'
}).setOriginX(x).setOriginY(y));
So basically I'm making a counter of a polygon and when I'm done drawing the counter, I just create a polygon. But the problem is that when I create polygon it doesn't fit in the counter it just moves away from the counter. I have tried to find how to correctly offset it.
roof.set({
left : left,
top : top,
});
I was trying to get left upper point of a bounding rectangle for the polygon and to set it so it places correctly. But that din't work. This how it looks
And a fiddle How it looks
Ok so I checked coords of created polygon and saw that it has recalculated them somehow and that's why it was offset. For example:
PointBefore
58 | 193
PointAfter
-189 | -52
This is how it changes, so to make the correct offset all I did was get it before I create the polygon and set top and left after it has been created.
var left = findLeftPaddingForRoof(roofPoints);
var top = findTopPaddingForRoof(roofPoints);
var roof = new fabric.Polyline(roofPoints, {
fill: 'purple'
});
roof.set({
left: left,
top: top
});
return roof;
And a fiddle that works.
This script doesn't work on 1.4.13 and 1.5.0 fabricjs versions. Cannot confirm on previus versions.
EDIT: Fixed the problem, also in later versions:
Change this:
var points = [ x, y, x, y ];
lines.push(new fabric.Line(points, {
strokeWidth : 1,
selectable : false,
stroke : 'red'
}).setOriginX(x).setOriginY(y));
into this:
var points = [ x, y, x, y ];
lines.push(new fabric.Line(points, {
strokeWidth : 1,
selectable : false,
stroke : 'red'
}));