Draw line with arrow cap

2019-07-18 18:19发布

问题:

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';
}

回答1:

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();}


回答2:

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)



回答3:

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



回答4:

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'
})