12

How can I draw an arrowhead in hummusJS? I am using hummus for drawing in pdf. I need to draw an arrow in pdf. I am able to draw the line. But how can I draw an arrowhead? I tried the following

if(x2 > y2)
            {
                a1 = x2-5;
                b1 = y2-5;
                a2 = x2-5;
                b2 = y2+5;
                a3 = x2+5;
                b3 = y2;
            }
            else
            {
                a1 = x2-5;
                b1 = y2+5;
                a2 = x2+5;
                b2 = y2+5;
                a3 = x2;
                b3 = y2-5;                
            }

 cxt.drawPath(a1,b1,a2,b2,a3,b3,{type: 'fill',
            color: '#000000'})

I tried like this also

      var d =5;
            a1 = x2-d*Math.sin(45);
            b1 = y2-d*Math.cos(45);
            a2 = x2+d*Math.sin(45);
            b2 = y2+d*Math.cos(45);
cxt.drawPath(x2,y2,a1,b1,{type: 'fill',
                color: '#000000'})
cxt.drawPath(x2,y2,a2,b2,{type: 'fill',
                color: '#000000'})

But this is not drawing arrowhead in the correct position here is the image enter image description here

user1187
  • 2,116
  • 8
  • 41
  • 74
  • Could you please share the complete code? how do the arrow be drawn (_horizontal/vertical_ and direction of the arrowhead _left/right_ ) ? – baymax Jun 12 '18 at 15:00
  • arrow is drawn by a user. it will horizontal/vertical direction will be left or right. – user1187 Jun 12 '18 at 18:46

2 Answers2

2

This is an example using function drawArrow to draw an arrow on PDF. The PDF is produced accessing http://localhost:3000/ via browser. It can draw horizontal and vertical arrow and put arrowhead on start or end. You can rehearse input variables startPoint, endPoint, endArrowHead

var express = require('express');
var app = express();


const DELTA = 5; //used to draw triangle arrowhead points

app.get('/', function(req, res){

var startPoint = {x:100, y:100}
var endPoint = {x:150, y:100}
var endArrowHead = true;

res.writeHead(200, {'Content-Type': 'application/pdf'});

var hummus = require('hummus');

var pdfWriter = hummus.createWriter(new hummus.PDFStreamForResponse(res));
var page = pdfWriter.createPage(0,0,595,842);
var cxt = pdfWriter.startPageContentContext(page);

drawArrow(cxt, startPoint, endPoint, endArrowHead);

startPoint = {x:200, y:100}
endPoint = {x:250, y:100}
endArrowHead = false;

drawArrow(cxt, startPoint, endPoint, endArrowHead);


startPoint = {x:300, y:100}
endPoint = {x:300, y:150}
endArrowHead = true;

drawArrow(cxt, startPoint, endPoint, endArrowHead);

startPoint = {x:400, y:200}
endPoint = {x:400, y:250}
endArrowHead = false;

drawArrow(cxt, startPoint, endPoint, endArrowHead);

pdfWriter.writePage(page);
pdfWriter.end();

res.end();

});

function drawArrow(cxt, startPoint, endPoint, endArrowHead) {
    cxt.drawPath(startPoint.x, startPoint.y, endPoint.x, endPoint.y);

    if (endPoint.x > startPoint.x) { //horizontal line
        if (endArrowHead) {// right arrowhead
            cxt.drawPath(endPoint.x, endPoint.y + DELTA, endPoint.x, endPoint.y - DELTA, endPoint.x + DELTA, endPoint.y, {
                type: 'fill',
                color: '#000000'
            });
        } else {// left arrowhead
            cxt.drawPath(startPoint.x, startPoint.y + DELTA, startPoint.x, startPoint.y - DELTA, startPoint.x - DELTA, startPoint.y, {
                type: 'fill',
                color: '#000000'
            });
        }

    } else {//vertical line
        if (endArrowHead) { //up arrowhead
            cxt.drawPath(endPoint.x + DELTA, endPoint.y, endPoint.x - DELTA, endPoint.y, endPoint.x, endPoint.y + DELTA, {
                type: 'fill',
                color: '#000000'
            });
        } else { //down arrowhead
            cxt.drawPath(startPoint.x + DELTA, startPoint.y, startPoint.x - DELTA, startPoint.y, startPoint.x, startPoint.y - DELTA, {
                type: 'fill',
                color: '#000000'
            });
        }
    }
}

app.listen(3000);

Here the output PDF

baymax
  • 151
  • 3
  • I tried this. I am getting correct arrow only for the right side. I have attached the image in my question. for other sides, the arrowhead is not correct. – user1187 Jun 15 '18 at 07:26
  • I updated my post and attached an ouput image with more examples. All is looking fine even for left side and vertical arrows... – baymax Jun 21 '18 at 16:24
2

Based on answers from this question: How to calculate the coordinates of a arrowhead based on the arrow? particularly the accepted one: https://stackoverflow.com/a/10316601/1713942

You can calculate the coordinates needed using vector arithmetic:

function arrowhead(A, B) {
    var h = 10 * Math.sqrt(3);
    var w = 10;
    var d = {x: B.x - A.x, y: B.y - A.y};
    var length = Math.sqrt(d.x*d.x + d.y*d.y);
    var U = {x: d.x/length, y: d.y/length};
    var V = {x: -U.y, y: U.x};
    return [
        {x: B.x - U.x*h + V.x*w, y: B.y - U.y*h + V.y*w},
        {x: B.x - U.x*h - V.x*w, y: B.y - U.y*h - V.y*w}
    ];
}

h and w determine the length and half-width. The function returns two points: the ends of the arrowhead.

Usage Example:

var startPoint = {x:100, y:100};
var endPoint = {x:200, y:200};

var arrowPoint = arrowhead(startPoint, endPoint);

// draw line
cxt.drawPath(startPoint.x, startPoint.y, endPoint.x, endPoint.y);

// draw arrow head
cxt.drawPath(endPoint.x, endPoint.y, arrowPoint[0].x, arrowPoint[0].y, arrowPoint[1].x, arrowPoint[1].y, endPoint.x, endPoint.y, {type: 'fill', color: '#000000'});
mdker
  • 1,234
  • 7
  • 11