Below is a summary of some canvas drawing tag experience, hope to help you.

Draw the arc


<canvas id="canvas" width="300" height="300" ref="canvas"></canvas>
Copy the code
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.arc(150.150.50.0.Math.PI*1/2);
ctx.stroke();
Copy the code

Running results:

Draw a straight line


var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(100.100);
ctx.lineTo(200.150);
ctx.stroke();
Copy the code

Running results:

Draw rounded rectangles


Through the combination of arc and straight line, the rectangular path is drawn.

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

var width = 100;
var height = 50;
var radius = 5;

ctx.translate(100.100);
ctx.beginPath(0);
ctx.arc(width - radius, height - radius, radius, 0.Math.PI / 2);
ctx.lineTo(radius, height);
ctx.arc(radius, height - radius, radius, Math.PI / 2.Math.PI);
ctx.lineTo(0, radius);
ctx.arc(radius, radius, radius, Math.PI, Math.PI * 3 / 2);
ctx.lineTo(width - radius, 0);
ctx.arc(width - radius, radius, radius, Math.PI * 3 / 2.Math.PI * 2);
ctx.lineTo(width, height - radius);
ctx.closePath();
// Fill the background color
ctx.fillStyle = "#ff6a61";
ctx.fill();
ctx.restore();
Copy the code

Running results:

Populate the text

. ctx.font ='16px PingFangSC-Regular';
ctx.textAlign = "center"; 
ctx.textBaseline = 'middle';
ctx.fillStyle = '#fff';
ctx.fillText('Quick Dog Taxi'.50.25);
Copy the code

The textBaseline property sets or returns the current textBaseline at the time the text is drawn.

Running results:

Width adaptation


The practice of setting the value of the label width is inevitable some play rogue, how to achieve the width of the label by the text up? Canvas provides the ctX.measureText (text).width interface to get text content width; Label width = text content width + left and right inside margins.

First, separate out the part that draws the rounded rectangle’s background:

function drawRoundRect(ctx, x, y, width, height, radius, bgc) {
  ctx.save();
  ctx.translate(x, y);
  drawRoundRectPath(ctx, width, height, radius);
  ctx.fillStyle = bgc;
  ctx.fill();
  ctx.restore();
}
function drawRoundRectPath(ctx, width, height, radius) {
  ctx.beginPath(0);
  ctx.arc(width - radius, height - radius, radius, 0.Math.PI / 2);
  ctx.lineTo(radius, height);
  ctx.arc(radius, height - radius, radius, Math.PI / 2.Math.PI);
  ctx.lineTo(0, radius);
  ctx.arc(radius, radius, radius, Math.PI, (Math.PI * 3) / 2);
  ctx.lineTo(width - radius, 0);
  ctx.arc(width - radius, radius, radius, (Math.PI * 3) / 2.Math.PI * 2); ctx.lineTo(width, height - radius); ctx.closePath(); }};Copy the code

Then you just need to set the parameters to call

  var canvas = document.getElementById("canvas");
  var ctx = canvas.getContext("2d");

  ctx.font = "16px PingFangSC-Regular";
  ctx.textAlign = "center";
  ctx.textBaseline = "middle";
  ctx.fillStyle = "#fff";

  var config = {
    paddingLeft: 20.// Text left inner margin
    paddingRight: 20.// Right inner margin of text
    labelHeight: 50.// Label height
    labelRadius: 5./ / the rounded
    labelBackgroundColor: "#ff6a61" // Label background color
  };
  var x = 100;
  var y = 100;
  var str = "Quick Dog Taxi";
  var textWidth = ctx.measureText(str).width;
  
  drawRoundRect( ctx, x, y, textWidth + config.paddingLeft + config.paddingRight, config.labelHeight, config.labelRadius, config.labelBackgroundColor);
  ctx.fillText( str, x + config.paddingLeft + textWidth / 2, y + config.labelHeight / 2 );

  var x = 100;
  var y = 200;
  var str = "Quick Dog taxi - Front End Team";
  var textWidth = ctx.measureText(str).width;

  drawRoundRect( ctx, x, y, textWidth + config.paddingLeft + config.paddingRight, config.labelHeight, config.labelRadius, config.labelBackgroundColor);
  ctx.fillText( str, x + config.paddingLeft + textWidth / 2, y + config.labelHeight / 2 );

Copy the code

Running results:

The measureText() method returns an object containing the specified font width in pixels.

Multi-label auto-wrap


How to draw multi-label wrapping?

The actual space taken up by the tag = text width + left and right inner margins + left and right margins

The text of all labels is traversed, and the specific coordinate value of each label is calculated according to the limited space width and the actual space occupied by the label.

Configuration parameters:

var labelList = [
  { "id": 1."name": "Miniature bread" },
  { "id": 2."name": "Golden cup" },
  { "id": 3."name": iveco },
  { "id": 4."name": "Commercial vehicles" },
  { "id": 5."name": "Pickup" },
  { "id": 6."name": "Refrigerated truck" },
  { "id": 7."name": "Flatbed truck" },
  { "id": 8."name": "High hurdle truck" },
  { "id": 9."name": "Wide body tail plate" },
  { "id": 10."name": "Van" },
  { "id": 11."name": "Other"}]var config = {
  // Label range parameters
  spaceX: 0./ / x coordinate
  spaceY: 0./ / y
  spaceWidth: 300./ / width
  spaceHeight: 300./ / height

  // Label parameters
  paddingRight: 10.// Distance from text to left border
  paddingLeft: 10.// Distance from text to right border
  marginTop: 0.// Upper outer boundary
  marginRight: 10.// Right outer boundary
  marginBottom: 10.// Lower outer boundary
  marginLeft: 0.// Left outer boundary
  labelHeight: 30./ / height
  labelRadius: 5./ / the rounded
  labelBackgroundColor: '#ff6a61'./ / the background color

  // Font parameters
  fontSize: 12.// Font size
  fontColor: '#fff'.// Font color
  fontFamily: 'PingFangSC-Regular'.// Font type
}
Copy the code

Iterate through the tag list to calculate the specific parameters of each tag:

function formatLine(ctx, list, config) {
  let labelLine = [];
  let lineIndex = 0;
  let usedWidth = 0;
  list.forEach(item= > {
    item.textWidth = ctx.measureText(item.name).width; // Text takes up space
    let labelSpace = item.textWidth + config.paddingLeft + config.paddingRight + config.marginLeft + config.marginRight; // The label actually occupies the width
    if(usedWidth + labelSpace > config.spaceWidth) {
      usedWidth = 0;
      lineIndex = lineIndex + 1;
    }
    item.x = config.spaceX + usedWidth + config.marginLeft;
    item.y = config.spaceY + lineIndex * (config.labelHeight + config.marginTop + config.marginBottom) + config.marginTop;
    labelLine.push(item);
    usedWidth = usedWidth + labelSpace;
  });
  return labelLine
}
Copy the code

The next step is to iterate over the label to draw:

let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
// Fill the background color so that the boundary can be easily observed
ctx.fillStyle = "#ccc";  
ctx.fillRect(config.spaceX, config.spaceY, config.spaceWidth, config.spaceHeight);

let labelLine = formatLine(ctx, labelList, config);
drawLabel(ctx, labelLine, config);

function drawLabel(ctx, labelLine, config) {
  ctx.font = `${config.fontSize}px ${config.fontFamily}`;
  ctx.textAlign = "center";
  ctx.textBaseline = 'middle';
  ctx.fillStyle = config.fontColor;

  labelLine.map((item) = >{
    drawRoundRect(ctx, item.x, item.y, item.textWidth + config.paddingLeft + config.paddingRight , config.labelHeight , config.labelRadius , config.labelBackgroundColor);
    ctx.fillText(item.name, item.x + config.paddingLeft + item.textWidth/2, item.y + config.labelHeight/2); })}Copy the code

Running results:

extension


So at this point we’re done drawing the label. If ctx.measureText(text).width can measure the actual measureText width, then ctx.measureText(text).height can measure the actual measureText height. Unfortunately not _(°:з “Angle)_)

Canvas does not provide an interface to get the height of the text. Thankfully, I’ve come up with a solution (from baidu for varying degrees :з “Angle) that allows me to calculate the maximum height difference between non-white pixels, i.e. the actual pixel height of the text, by capturing all pixel data within a specified range. Speaking is to find the first and last non-white pixels, and the difference between the two pixels is the actual height of the text.

The core code is as follows

function measureTextHeight(ctx, x, y, width, height) {
  // Get pixel data from the canvas
  var data = ctx.getImageData(x, y, width, height).data,
    first = false,
    last = false,
    r = height,
    c = 0;
  // Find the last line of non-white pixels
  while(! last && r) { r--;for (c = 0; c < width; c++) {
      if (data[r * width * 4 + c * 4 + 3]) {
        last = r;
        break; }}}// Find the first line of non-white pixels
  while (r) {
    r--;
    for (c = 0; c < width; c++) {
      if (data[r * width * 4 + c * 4 + 3]) {
        first = r;
        break; }}if(first ! = r)return last - first;
  }
  return 0;
}
Copy the code

GetImageData () property: Copies the pixel data of the specified rectangle on the canvas

This method is simple and crude, but the limitations are also very obvious, draw first and then get data is tantamount to playing rogue. There are other ways to do this in the comments section.

Pay attention to our