googlearchive/js-map-label

Multiline / Wrap Text Support

Opened this issue · 2 comments

To get multiline support, add this:

MapLabel.prototype.wrapText = function(context, text, x, y, maxWidth, lineHeight) {
  var words = text.split(' ');
  var line = '';

  for(var n = 0; n < words.length; n++) {
    var testLine = line + words[n] + ' ';
    var metrics = context.measureText(testLine);
    var testWidth = metrics.width;
    if (testWidth > maxWidth && n > 0) {
      context.strokeText(line, x, y);
      context.fillText(line, x, y);

      line = words[n] + ' ';
      y += lineHeight;
    }
    else {
      line = testLine;
    }
  }
  context.strokeText(line, x, y);
  context.fillText(line, x, y);
};

In drawCanvas_, change

    if (strokeWeight) {
      ctx.lineWidth = strokeWeight;
      ctx.strokeText(text, strokeWeight, strokeWeight);
    }

    ctx.fillText(text, strokeWeight, strokeWeight);

to

    if (strokeWeight) {
      ctx.lineWidth = strokeWeight;

    }

    this.wrapText(ctx, text, strokeWeight, strokeWeight, *ADD MAX WIDTH*, *ADD LINEHEIGHT*);
    //e.g.  this.wrapText(ctx, text, strokeWeight, strokeWeight, 200, 14);

This code is an extension of:
http://www.html5canvastutorials.com/tutorials/html5-canvas-wrap-text-tutorial/

I had to implement this with \n for newline.

Replace:

if (strokeWeight) {
   ctx.lineWidth = strokeWeight;
   ctx.strokeText(text, strokeWeight, strokeWeight);
}

ctx.fillText(text, strokeWeight, strokeWeight);

with

if (strokeWeight) {
   ctx.lineWidth = strokeWeight;
  // ctx.strokeText(text, strokeWeight, strokeWeight);
}
    // ctx.fillText(text, strokeWeight, strokeWeight);
    var lineheight = 15;
    var lines = text.split('\n');

for (var i = 0; i<lines.length; i++) {
   ctx.fillText(lines[i], strokeWeight, strokeWeight + (i * lineheight));
   if (strokeWeight) {
        ctx.lineWidth = strokeWeight;
        ctx.strokeText(lines[i], strokeWeight, strokeWeight + (i * lineheight));
      }
}
a6o commented

modified from @patrickjaja

replace whole function with this

MapLabel.prototype.drawCanvas_ = function() {
  var canvas = this.canvas_;
  if (!canvas) return;

  var style = canvas.style;
  style.zIndex = /** @type number */ (this.get('zIndex'));

  var ctx = canvas.getContext('2d');
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.strokeStyle = this.get('strokeColor');
  ctx.fillStyle = this.get('fontColor');
  ctx.font = this.get('fontSize') + 'px ' + this.get('fontFamily');

  var strokeWeight = Number(this.get('strokeWeight'));

  var text = this.get('text');
  if (text) {
    if (strokeWeight) {
      ctx.lineWidth = strokeWeight;
    }
    var lineheight = this.get('fontSize');
    var lines = text.split('\n');

    maxText = "";
    for (var i = 0; i < lines.length; i++) {
      if(lines[i].length>maxText.length){
        maxText = lines[i];
      }
      if (strokeWeight) {
        ctx.lineWidth = strokeWeight;
        ctx.strokeText(lines[i], strokeWeight, strokeWeight + (i * lineheight));
      }
      ctx.fillText(lines[i], strokeWeight, strokeWeight + (i * lineheight));
    }
    text = maxText;

    var textMeasure = ctx.measureText(text);
    var textWidth = textMeasure.width + strokeWeight;
    style.marginLeft = this.getMarginLeft_(textWidth) + 'px';
    // Bring actual text top in line with desired latitude.
    // Cheaper than calculating height of text.
    style.marginTop = '-'+lines.length*lineheight/2+"px";
  }
};

whats different is

  1. line height adjusted with font size
  2. always vertical center
  3. horizontal center now possible (depending on the option)
  4. stroketext first, (or else actual text goes behind)