dane
dane

Reputation: 55

Draw arrow using Javascript lineTo

I'm currently trying to draw a arrow under my canvas speechbubble element.

My problem:

The right side of the arrow seems to be way longer then the left side.

What have I tried:

I've tried to create the arrow in the following way:

ctx.moveTo(x, y);
ctx.lineTo(30, 30);
ctx.lineTo(50, 10);

Which seems to work as can be seen here: https://jsfiddle.net/eefja4kk/1/

But whatever I try, I can't get it to work in my currently code. I appreciate any kind of help and suggestions.

My current code:

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext("2d");
ctx.font = "12px Helvetica";
var text = 'Speechbubble Speechbubble Speechbubble';
var fontHeight = getTextHeight(text, ctx.font);
component(ctx, ctx.measureText(text).width, fontHeight, "#37f", 10, 10, 16, text);

function component(ctx, width, height, color, x, y, radius, text)
{
   var r = radius;
   var w = width + 40;
   var h = height + 40;
   var pi2 = Math.PI * 2;
   var ap = w * 0.15;
   var aw = 5;
   var ah = 10;

   ctx.beginPath();
   ctx.arc(r, r, r, pi2 * 0.5 , pi2 * 0.75);
   ctx.arc(w - r, r, r, pi2 * 0.75, pi2);
   ctx.arc(w - r, h - r, r, 0, pi2 * 0.25);

   // Speechbubble arrow
   ctx.lineTo(w - ap, h);
   ctx.lineTo(w - (ap * 2), h + ah);
   ctx.lineTo(w - (ap * 2) - (aw * 2), h);

   ctx.arc(r  , h - r, r, pi2 * 0.25, pi2 * 0.5);
   ctx.fillStyle = '#37f';
   ctx.fill();

   // Text fillstyle
   ctx.fillStyle = "#fff";
   ctx.fillText(text, w - ctx.measureText(text).width - 20, h - fontHeight - 10);
}

function getTextHeight(txt, font)
{
   var el = document.createElement('div'), height;
   el.style.cssText = "position:fixed; padding:0; left:-9999px; top:-9999px; font:" + font;
   el.textContent = txt;

   document.body.appendChild(el); 
   height = parseInt(getComputedStyle(el).getPropertyValue('height'), 10);
   document.body.removeChild(el);

   return height;
}
<canvas width="500" height="500" id="canvas"></canvas>

Upvotes: 2

Views: 364

Answers (1)

musefan
musefan

Reputation: 48455

Your calculations are off. You can change it to the following to get the arrow to be correct:

// Speechbubble arrow
ctx.lineTo(w - ap, h);
ctx.lineTo(w - (ap * 2), h + ah);
ctx.lineTo(w - (ap * 3), h);

Here is a working example


Having said that, your variable naming suggests maybe that isn't what you want. I assume aw is meant to be the arrow width, in which case you could use:

// Speechbubble arrow
ctx.lineTo(w - ap, h);
ctx.lineTo(w - ap - (aw / 2), h + ah);
ctx.lineTo(w - ap - aw, h);

But I would suggest you then change you aw to something bigger, perhaps 20, as per this example.


It's hard to say for sure without knowing exactly what you variables are to represent (i.e. what is ap actually meant to be? in my examples it acts as the offset for the start of the arrow), but you get the idea, hopefully my solutions get you back on track anyway.

Upvotes: 2

Related Questions