canvas如何绘制标签,在知识的海洋狗刨(下)

简介: 下面总结了一些canvas绘制标签的心得体会,希望能够对你有所帮助。

接下来只需要设定参数调用即可


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, // 文本左内边距
    paddingRight: 20, // 文本右内边距
    labelHeight: 50, // 标签高度
    labelRadius: 5, // 圆角
    labelBackgroundColor: "#ff6a61" // 标签背景色
  };
  var x = 100;
  var y = 100;
  var str = "快狗打车";
  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 = "快狗打车-前端团队";
  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 );


运行结果:



measureText() 方法返回包含一个对象,该对象包含以像素计的指定字体宽度。


多标签自动换行



如何实现绘制多标签自动换行?


标签的实际占用空间宽度 = 文本宽度 + 左右内边距 + 左右外边距


遍历所有标签文本,根据限定空间宽度与标签的实际占用空间宽度计算出每一个标签的具体坐标值。


配置参数:


var labelList = [
  { "id": 1, "name": "小型面包" },
  { "id": 2, "name": "金杯" },
  { "id": 3, "name": "依维柯" },
  { "id": 4, "name": "商务车" },
  { "id": 5, "name": "皮卡" },
  { "id": 6, "name": "冷藏车" },
  { "id": 7, "name": "平板货车" },
  { "id": 8, "name": "高栏货车" },
  { "id": 9, "name": "宽体尾板" },
  { "id": 10, "name": "厢式货车" },
  { "id": 11, "name": "其它" }
]
var config = {
  // 标签范围参数
  spaceX: 0, // x坐标
  spaceY: 0, // y坐标
  spaceWidth: 300, // 宽度
  spaceHeight: 300, // 高度
  // 标签参数
  paddingRight: 10, // 文本至左边框距离
  paddingLeft: 10, // 文本至右边框距离
  marginTop: 0, // 上外边界
  marginRight: 10, // 右外边界
  marginBottom: 10, // 下外边界
  marginLeft: 0, // 左外边界
  labelHeight: 30, // 高度
  labelRadius: 5, // 圆角
  labelBackgroundColor: '#ff6a61', // 背景色
  // 字体参数
  fontSize: 12, // 字体大小
  fontColor: '#fff', // 字体颜色
  fontFamily: 'PingFangSC-Regular', // 字体类型
}


遍历标签列表计算出每一个标签具体参数:


function formatLine(ctx, list, config) {
  let labelLine = [];
  let lineIndex = 0;
  let usedWidth = 0;
  list.forEach(item => {
    item.textWidth = ctx.measureText(item.name).width; // 文字占据空间
    let labelSpace = item.textWidth + config.paddingLeft + config.paddingRight + config.marginLeft + config.marginRight; // 标签实际占据宽度
    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
}


接下来就是遍历标签进行绘制了:


let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
// 填充背景色,以便于观察边界
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);
  })
}


运行结果:



延伸



那么到这里标签的绘制已经结束。鬼机灵的小伙伴可能会想到既然ctx.measureText(text).width可以获得文本实际占据宽度,那ctx.measureText(text).height肯定就是获取文本实际占据高度了呗(俺也一样),很遗憾并不是_(°:з」∠)_)


canvas并没有提供获取文本高度的接口,需要通过其他方式间接获取。所幸,我还是百度到了一种解决方案(百度打钱_(°:з」∠)_)——通过获取指定范围内的所有像素数据,计算非白色像素点之间的最大高度差值即为文本实际像素高度。说人话就是找出第一个与最后一个非白色像素点,两者所在像素行之间的差值即为文本实际高度。


核心代码如下


function measureTextHeight(ctx, x, y, width, height) {
  // 从画布获取像素数据
  var data = ctx.getImageData(x, y, width, height).data,
    first = false,
    last = false,
    r = height,
    c = 0;
  // 找到最后一行非白色像素
  while (!last && r) {
    r--;
    for (c = 0; c < width; c++) {
      if (data[r * width * 4 + c * 4 + 3]) {
        last = r;
        break;
      }
    }
  }
  // 找到第一行非白色像素
  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;
}


getImageData()属性:复制画布上指定矩形的像素数据


这种方法简单粗暴,但是局限性也非常明显,先绘制后获取数据等于耍流氓。小伙伴们还有除此之外的方法不妨在评论区探讨一下。


相关文章
|
3月前
ThreeJs绘制线
这篇文章详细说明了如何使用Three.js来绘制线条,包括创建线几何体、设置材质以及将线条添加到3D场景中的具体步骤。
42 1
|
8月前
|
前端开发
canvas详解04-绘制文字
canvas详解04-绘制文字
98 2
canvas详解04-绘制文字
|
8月前
|
缓存 前端开发 JavaScript
canvas详解01-绘制基本图形
canvas详解01-绘制基本图形
132 2
|
8月前
|
监控 API 计算机视觉
OpenCV这么简单为啥不学——1.4、基础标识绘制(绘制线line函数、rectangle函数绘制四边形、circle函数绘制圆形、putText函数绘制文字、putText绘制中文文字)
OpenCV这么简单为啥不学——1.4、基础标识绘制(绘制线line函数、rectangle函数绘制四边形、circle函数绘制圆形、putText函数绘制文字、putText绘制中文文字)
78 0
|
8月前
|
前端开发 API
canvas详解03-绘制图像和视频
canvas详解03-绘制图像和视频
100 1
|
Java 图形学
JavaSwing矩形绘制教程
JavaSwing矩形绘制教程 矩形是计算机图形学中最基本的图形,JavaSwing也提供了绘制矩形的功能。本教程将介绍如何使用JavaSwing绘制矩形。
212 0
|
前端开发
canvas绘制五角星
canvas绘制五角星
192 0
|
前端开发
canvas如何绘制标签,在知识的海洋狗刨(上)
下面总结了一些canvas绘制标签的心得体会,希望能够对你有所帮助。
|
前端开发 数据可视化
canvas可视化效果之内阴影效果
canvas可视化效果之内阴影效果
canvas可视化效果之内阴影效果
|
移动开发 前端开发 JavaScript
H5画布 canvas(一)canvas简介、绘制圆形/矩形、案例饼状图绘制
H5画布 canvas(一)canvas简介、绘制圆形/矩形、案例饼状图绘制
709 0
H5画布 canvas(一)canvas简介、绘制圆形/矩形、案例饼状图绘制