I am trying to draw a line with arrow at the tip of the line. But i am unable to complete it. Can any one help me.
I tried adding triangle with line but unfortunately it wont work while dynamically drawing. This is what i tried along with line.
var myPath;
function onMouseDown(event) {
myPath = new Path();
myPath.strokeColor = 'black';
}
function onMouseDrag(event) {
myPath.add(event.point);
}
function onMouseUp(event) {
var myCircle = new Path.RegularPolygon(event.point, 3, 10);
myCircle.strokeColor = 'black';
myCircle.fillColor = 'white';
}
you draw line with arrow with this code ,
paper.Shape.ArrowLine = function (sx, sy, ex, ey, isDouble) {
function calcArrow(px0, py0, px, py) {
var points = [];
var l = Math.sqrt(Math.pow((px - px0), 2) + Math.pow((py - py0), 2));
points[0] = (px - ((px - px0) * Math.cos(0.5) - (py - py0) * Math.sin(0.5)) * 10 / l);
points[1] = (py - ((py - py0) * Math.cos(0.5) + (px - px0) * Math.sin(0.5)) * 10 / l);
points[2] = (px - ((px - px0) * Math.cos(0.5) + (py - py0) * Math.sin(0.5)) * 10 / l);
points[3] = (py - ((py - py0) * Math.cos(0.5) - (px - px0) * Math.sin(0.5)) * 10 / l);
return points;
}
var endPoints = calcArrow(sx, sy, ex, ey);
var startPoints = calcArrow(ex, ey, sx, sy);
var e0 = endPoints[0],
e1 = endPoints[1],
e2 = endPoints[2],
e3 = endPoints[3],
s0 = startPoints[0],
s1 = startPoints[1],
s2 = startPoints[2],
s3 = startPoints[3];
var line = new paper.Path({
segments: [
new paper.Point(sx, sy),
new paper.Point(ex, ey)
],
strokeWidth: 1
});
var arrow1 = new paper.Path({
segments: [
new paper.Point(e0, e1),
new paper.Point(ex, ey),
new paper.Point(e2, e3)
]
});
var compoundPath = new paper.CompoundPath([line, arrow1]);
if (isDouble === true) {
var arrow2 = new paper.Path({
segments: [
new paper.Point(s0, s1),
new paper.Point(sx, sy),
new paper.Point(s2, s3)
]
});
compoundPath.addChild(arrow2);
}
return compoundPath;};
use
tool.onMouseDrag = function (event) { this.item = new paper.Shape.ArrowLine(event.downPoint.x, event.downPoint.y, event.point.x, event.point.y);
this.item.removeOnDrag();}
There is an example code in paperjs refrence which draws an arrow at the end of a vector.
Have a look at: http://paperjs.org/tutorials/geometry/vector-geometry/ (scroll all the way down to the end of the page)
A simple approach is to create a group that consists of the vector itself (the line) and the arrow head. lineStart
and lineEnd
are the points where the line of the arrow starts and ends.
// parameters
headLength = 10;
headAngle = 150;
lineStart = new Point(200, 200);
lineEnd = new Point (250, 250);
tailLine = new Path.Line(lineStart, lineEnd);
tailVector = lineEnd - lineStart;
headLine = tailVector.normalize(headLength);
arrow = new Group([
new Path([lineStart, lineEnd]),
new Path([
lineEnd + headLine.rotate(headAngle),
lineEnd,
lineEnd + headLine.rotate(-headAngle)
])
]);
arrow.strokeColor = 'black';
And, as previously mentioned, if you want to recreate it each time then you can make the previous code a function, something like:
// parameters
var headLength = 10;
var headAngle = 150;
var arrowColor = 'black';
// the arrow
var arrow = null;
function drawArrow(start, end) {
var tailLine = new Path.Line(start, end);
var tailVector = end - start;
var headLine = tailVector.normalize(headLength);
arrow = new Group([
new Path([start, end]),
new Path([
end + headLine.rotate(headAngle),
end,
end + headLine.rotate(-headAngle)
])
]);
arrow.strokeColor = arrowColor;
}
tool.onMouseDrag = function(e) {
if (arrow) {
arrow.remove();
}
drawArrow(e.downPoint, e.point);
}
Here is a sketch of the previous code sketch.paperjs.org
Here's an example, where I extend paper.Group
.
In my example I avoid redrawing the arrow on each mousedrag
. I create once on mousedown
and then transform the line and the arrow parts to the appropriate position/rotation on each mousedrag
.
Note: I'm fairly certain the following code can be improved a lot.
Drawing via mouse events
'use strict'
/* Arrow Class extends Group */
const Arrow = paper.Group.extend({
initialize: function (args) {
paper.Group.call(this, args)
this._class = 'Arrow'
this._serializeFields = Object.assign(this._serializeFields, {
from: null,
to: null,
headSize: null
})
this.from = args.from
this.to = args.to || args.from
this.headSize = args.headSize
// @NOTE
// `paper.project.importJSON()` passes the deserialized children
// (the arrow parts) to the `Group` superclass so there's no need to
// create them again.
if (this.children.length)
return
this.addChildren([
new paper.Path({
...args,
segments: [
this.from,
this.from
]
}),
new paper.Path({
...args,
segments: [
this.from,
this.from
]
}),
new paper.Path({
...args,
segments: [
this.from,
this.from
]
})
])
this.update(this.to)
},
update: function (point) {
const angle = this.from.subtract(point).angle - 90
this.children[0].lastSegment.point = point
this.children[1].firstSegment.point = point
this.children[1].lastSegment.point = point.add(
this.headSize,
this.headSize
)
this.children[2].firstSegment.point = point
this.children[2].lastSegment.point = point.add(
-this.headSize,
this.headSize
)
this.children[1].rotate(angle, point)
this.children[2].rotate(angle, point)
return this
}
})
paper.Base.exports.Arrow = Arrow
/* Usage */
paper.setup(document.querySelector('canvas'))
const tool = new paper.Tool()
let arrow
tool.onMouseDown = e => {
arrow = new Arrow({
from: e.point,
headSize: 10,
strokeWidth: 1,
strokeColor: '#555',
strokeCap: 'round'
})
}
tool.onMouseDrag = e => {
arrow.update(e.point)
}
canvas {
display: block;
width: 100%;
height: 100%;
margin: 0;
background: #fafafa;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.11.5/paper-core.min.js"></script>
<canvas resize="true"></canvas>
... or just draw to a static position
If you want to just draw the arrow (without using mouse events), just do the following:
const arrow = new Arrow({
from: new paper.Point(100, 100),
to: new paper.Point(200, 200),
headSize: 10,
strokeWidth: 1,
strokeColor: '#555',
strokeCap: 'round'
})