I am attempting to draw the 3 arrows below. I can draw the top one correctly but I cannot draw the other 2 arrow heads correctly. I am using HTML5 Canvas to draw these arrows.
The problem occurs with my arcTo calls. I just cannot get the correct curve to occur for some reason. Maybe I should be using a Bezier curve? Would anyone be able to tell me what HTML5/Javascript functions I use to produce the above arrow heads?
Can you provide an example of how to achieve the above arrow heads?
Heres the JSFiddle to show whats going wrong: http://jsfiddle.net/hJX8X/
<canvas id="testCanvas" width="400px" height="400px">
</canvas>
<script type="text/javascript">
<!--
var canvas = document.getElementById("testCanvas");
var dc = canvas.getContext("2d");
// Points which are correct (when I draw straight lines its a perfect arrow
var width = 400;
var height = 100;
var arrowW = 0.35 * width;
var arrowH = 0.75 * height;
var p1 = {x: 0, y: (height-arrowH)/2};
var p2 = {x: (width-arrowW), y: (height-arrowH)/2};
var p3 = {x: (width-arrowW), y: 0};
var p4 = {x: width, y: height/2};
var p5 = {x: (width-arrowW), y: height};
var p6 = {x: (width-arrowW), y: height-((height-arrowH)/2)};
var p7 = {x: 0, y: height-((height-arrowH)/2)};
dc.clearRect(0, 0, canvas.width, canvas.height);
dc.fillStyle = "#FF0000";
dc.beginPath();
dc.moveTo(p1.x, p1.y);
dc.lineTo(p2.x, p2.y);
dc.lineTo(p3.x, p3.y);
dc.moveTo(p3.x, p3.y);
dc.arcTo(p3.x, p3.y, p4.x, p4.y, 50);
dc.moveTo(p4.x, p4.y);
dc.arcTo(p4.x, p4.y, p5.x, p5.y, 50);
dc.moveTo(p5.x, p5.y);
dc.lineTo(p6.x, p6.y);
dc.lineTo(p7.x, p7.y);
dc.closePath();
dc.fill();
/* Draw arrow without curves
dc.moveTo(p1.x, p1.y);
dc.lineTo(p2.x, p2.y);
dc.lineTo(p3.x, p3.y);
dc.lineTo(p4.x, p4.y);
dc.lineTo(p5.x, p5.y);
dc.lineTo(p6.x, p6.y);
dc.lineTo(p7.x, p7.y);
*/
-->
</script>
So we've got this path that makes an arrow. I've annotated it:
dc.moveTo(p1.x, p1.y);
dc.lineTo(p2.x, p2.y); // end of main block
dc.lineTo(p3.x, p3.y); // topmost point
dc.lineTo(p4.x, p4.y); // endpoint
dc.lineTo(p5.x, p5.y); // bottommost point
dc.lineTo(p6.x, p6.y); // end at bottom point
dc.lineTo(p7.x, p7.y);
We really want to keep it as similar as possible except we want to get to the endpoint (and back) in a different way than just a straight line. We absolutely do not want to use any moveTo
commands except the first one. That really confounds things and makes them hard to understand. I'd also avoid using arcTo unless you really need part of an arc (like in a pie) because its fairly confusing compared to the other path commands.
So we'll use quadratic curves which are like beziers but only have one control point, making them pretty simple. They work by specifying a control point like this (on the left).
So we take the same exact arrow code and insert two quadratic beziers to make a skinny arrow. We want the control points to be sorta "inside" the mass of the arrow to make the quadratics bend inwards:
dc.moveTo(p1.x, p1.y);
dc.lineTo(p2.x, p2.y); // end of main block
dc.lineTo(p3.x, p3.y); // topmost point
// control point is based on p3 (topmost point)
dc.quadraticCurveTo(p3.x + 20, p3.y + 30, p4.x, p4.y); // endpoint
// control point is based on p5 (bottommost point)
dc.quadraticCurveTo(p5.x + 20, p5.y - 30, p5.x, p5.y); // bottommost point
dc.lineTo(p6.x, p6.y); // end at bottom point
dc.lineTo(p7.x, p7.y);
Or a fat one, we put the control point at the same height as the topmost and bottommost point, and around the same X as the endpoint:
dc.beginPath();
// Draw arrow without curves
dc.moveTo(p1.x, p1.y);
dc.lineTo(p2.x, p2.y); // end of main block
dc.lineTo(p3.x, p3.y); // topmost point
// control point is based on p3 (topmost point)
dc.quadraticCurveTo(p3.x + 120, p3.y, p4.x, p4.y); // endpoint
// control point is based on p5 (bottommost point)
dc.quadraticCurveTo(p5.x + 120, p5.y, p5.x, p5.y); // bottommost point
dc.lineTo(p6.x, p6.y); // end at bottom point
dc.lineTo(p7.x, p7.y);
Live example here: http://jsfiddle.net/Yp7DM/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With