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.