Draw arrow on canvas tag

后端 未结 12 807
小鲜肉
小鲜肉 2020-11-27 13:50

I want to draw an arrow using the canvas tag, javascript. I\'ve made it using the quadratic function, but I\'m having problems to calculate the angle of rotation of the arro

相关标签:
12条回答
  • 2020-11-27 13:57

    This code is similar to Titus Cieslewski's solution, maybe the arrow is a bit nicer:

    function canvasDrawArrow(context, fromx, fromy, tox, toy) {
        var headlen = 10.0;
        var back = 4.0;
        var angle1 = Math.PI / 13.0;
        var angle2 = Math.atan2(toy - fromy, tox - fromx);
        var diff1 = angle2 - angle1;
        var diff2 = angle2 + angle1;
        var xx = getBack(back, fromx, fromy, tox, toy);
        var yy = getBack(back, fromy, fromx, toy, tox);
    
        context.moveTo(fromx, fromy);
        context.lineTo(tox, toy);
    
        context.moveTo(xx, yy);
        context.lineTo(xx - headlen * Math.cos(diff1), yy - headlen * Math.sin(diff1));
    
        context.moveTo(xx, yy);
        context.lineTo(xx - headlen * Math.cos(diff2), yy - headlen * Math.sin(diff2));
    }
    
    function getBack(len, x1, y1, x2, y2) {
        return x2 - (len * (x2 - x1) / (Math.sqrt(Math.pow(y2 - y1, 2) + Math.pow(x2 - x1, 2))));
    }
    

    this works well with lineWidth > 1. It can come in handy when drawing x and y axis

    0 讨论(0)
  • 2020-11-27 13:58

    Typescript version, with the fixed arrow tip when line width >> 1

    function canvas_arrow( context, fromx, fromy, tox, toy ) {
        const dx = tox - fromx;
        const dy = toy - fromy;
        const headlen = Math.sqrt( dx * dx + dy * dy ) * 0.3; // length of head in pixels
        const angle = Math.atan2( dy, dx );
        context.beginPath();
        context.moveTo( fromx, fromy );
        context.lineTo( tox, toy );
        context.stroke();
        context.beginPath();
        context.moveTo( tox - headlen * Math.cos( angle - Math.PI / 6 ), toy - headlen * Math.sin( angle - Math.PI / 6 ) );
        context.lineTo( tox, toy );
        context.lineTo( tox - headlen * Math.cos( angle + Math.PI / 6 ), toy - headlen * Math.sin( angle + Math.PI / 6 ) );
        context.stroke();
    }
    

    0 讨论(0)
  • 2020-11-27 13:59

    Here is another method to draw arrows. It uses the triangle method from here: https://stackoverflow.com/a/8937325/1828637

    A little helper function.

    function canvas_arrow(context, fromx, fromy, tox, toy, r){
        var x_center = tox;
        var y_center = toy;
    
        var angle;
        var x;
        var y;
    
        context.beginPath();
    
        angle = Math.atan2(toy-fromy,tox-fromx)
        x = r*Math.cos(angle) + x_center;
        y = r*Math.sin(angle) + y_center;
    
        context.moveTo(x, y);
    
        angle += (1/3)*(2*Math.PI)
        x = r*Math.cos(angle) + x_center;
        y = r*Math.sin(angle) + y_center;
    
        context.lineTo(x, y);
    
        angle += (1/3)*(2*Math.PI)
        x = r*Math.cos(angle) + x_center;
        y = r*Math.sin(angle) + y_center;
    
        context.lineTo(x, y);
    
        context.closePath();
    
        context.fill();
    }
    

    And here is a demonstration of it to draw arrows at the start and at the end of a line.

    var can = document.getElementById('c');
    var ctx = can.getContext('2d');
    
    ctx.lineWidth = 10;
    ctx.strokeStyle = 'steelblue';
    ctx.fillStyle = 'steelbllue'; // for the triangle fill
    ctx.lineJoin = 'butt';
    
    ctx.beginPath();
    ctx.moveTo(50, 50);
    ctx.lineTo(150, 150);
    ctx.stroke();
    
    canvas_arrow(ctx, 50, 50, 150, 150, 10);
    canvas_arrow(ctx, 150, 150, 50, 50, 10);
    
    function canvas_arrow(context, fromx, fromy, tox, toy, r){
    	var x_center = tox;
    	var y_center = toy;
    	
    	var angle;
    	var x;
    	var y;
    	
    	context.beginPath();
    	
    	angle = Math.atan2(toy-fromy,tox-fromx)
    	x = r*Math.cos(angle) + x_center;
    	y = r*Math.sin(angle) + y_center;
    
    	context.moveTo(x, y);
    	
    	angle += (1/3)*(2*Math.PI)
    	x = r*Math.cos(angle) + x_center;
    	y = r*Math.sin(angle) + y_center;
    	
    	context.lineTo(x, y);
    	
    	angle += (1/3)*(2*Math.PI)
    	x = r*Math.cos(angle) + x_center;
    	y = r*Math.sin(angle) + y_center;
    	
    	context.lineTo(x, y);
    	
    	context.closePath();
    	
    	context.fill();
    }
    <canvas id="c" width=300 height=300></canvas>

    0 讨论(0)
  • 2020-11-27 14:00

    You can do:

    ctx.save();
    ctx.translate(xOrigin, yOrigin);
    ctx.rotate(angle);
     // draw your arrow, with its origin at [0, 0]
    ctx.restore();
    
    0 讨论(0)
  • 2020-11-27 14:00

    Here is the working solution

    function draw_arrow(ctx,fx,fy,tx,ty){ //ctx is the context
        var angle=Math.atan2(ty-fy,tx-fx);
        ctx.moveTo(fx,fy); ctx.lineTo(tx,ty);
        var w=3.5; //width of arrow to one side. 7 pixels wide arrow is pretty
        ctx.strokeStyle="#4d4d4d"; ctx.fillStyle="#4d4d4d";
        angle=angle+Math.PI/2; tx=tx+w*Math.cos(angle); ty=ty+w*Math.sin(angle);
        ctx.lineTo(tx,ty);
      //Drawing an isosceles triangle of sides proportional to 2:7:2
        angle=angle-1.849096; tx=tx+w*3.5*Math.cos(angle); ty=ty+w*3.5*Math.sin(angle);
        ctx.lineTo(tx,ty);
        angle=angle-2.584993; tx=tx+w*3.5*Math.cos(angle); ty=ty+w*3.5*Math.sin(angle);
        ctx.lineTo(tx,ty);
        angle=angle-1.849096; tx=tx+w*Math.cos(angle); ty=ty+w*Math.sin(angle);
        ctx.lineTo(tx,ty);
        ctx.stroke(); ctx.fill();
    }
    
    0 讨论(0)
  • 2020-11-27 14:03

    You can push your matrix, rotate it, draw your arrow and then pop the matrix.

    0 讨论(0)
提交回复
热议问题