在知识的海洋狗刨,使用canvas绘制标签

2024-03-17 15:30

本文主要是介绍在知识的海洋狗刨,使用canvas绘制标签,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

绘制圆弧

<canvas id="canvas" width="300" height="300" ref="canvas"></canvas>
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.arc(150,150,50,0,Math.PI*1/2);
ctx.stroke();

运行结果:

绘制直线

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(100,100);
ctx.lineTo(200,150);
ctx.stroke();

运行结果:

绘制圆角矩形

通过圆弧与直线相结合,绘制出矩形路径。

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();
// 填充背景色
ctx.fillStyle = "#ff6a61";
ctx.fill();
ctx.restore();

运行结果:

填充文本

...
ctx.font = '16px PingFangSC-Regular';
ctx.textAlign = "center";
ctx.textBaseline = 'middle';
ctx.fillStyle = '#fff';
ctx.fillText('快狗打车', 50, 25);

textBaseline 属性设置或返回在绘制文本时的当前文本基线。

运行结果:

宽度自适应

标签宽度设置定值的做法难免有些耍流氓,怎样才能实现标签宽度由文本内容撑起?canvas为我们提供了ctx.measureText(text).width接口获得文本内容宽度;标签宽度 = 文本内容宽度 + 左右内边距。

先把绘制圆角矩形背景的部分单独抽出来:

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();
}
};
复制代码
接下来只需要设定参数调用即可  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()属性:复制画布上指定矩形的像素数据

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

推荐阅读

  • 前端获取微信头像 base64 数据的踩坑实践

  • 使用vue实现HTML页面生成图片

  • 如何实现微信小程序图像剪切?代码拿去用,不谢!

好文我在看????

这篇关于在知识的海洋狗刨,使用canvas绘制标签的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/819353

相关文章

使用Java将DOCX文档解析为Markdown文档的代码实现

《使用Java将DOCX文档解析为Markdown文档的代码实现》在现代文档处理中,Markdown(MD)因其简洁的语法和良好的可读性,逐渐成为开发者、技术写作者和内容创作者的首选格式,然而,许多文... 目录引言1. 工具和库介绍2. 安装依赖库3. 使用Apache POI解析DOCX文档4. 将解析

Qt中QUndoView控件的具体使用

《Qt中QUndoView控件的具体使用》QUndoView是Qt框架中用于可视化显示QUndoStack内容的控件,本文主要介绍了Qt中QUndoView控件的具体使用,具有一定的参考价值,感兴趣的... 目录引言一、QUndoView 的用途二、工作原理三、 如何与 QUnDOStack 配合使用四、自

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

使用Python构建一个Hexo博客发布工具

《使用Python构建一个Hexo博客发布工具》虽然Hexo的命令行工具非常强大,但对于日常的博客撰写和发布过程,我总觉得缺少一个直观的图形界面来简化操作,下面我们就来看看如何使用Python构建一个... 目录引言Hexo博客系统简介设计需求技术选择代码实现主框架界面设计核心功能实现1. 发布文章2. 加

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

使用Python开发一个带EPUB转换功能的Markdown编辑器

《使用Python开发一个带EPUB转换功能的Markdown编辑器》Markdown因其简单易用和强大的格式支持,成为了写作者、开发者及内容创作者的首选格式,本文将通过Python开发一个Markd... 目录应用概览代码结构与核心组件1. 初始化与布局 (__init__)2. 工具栏 (setup_t

Python虚拟环境终极(含PyCharm的使用教程)

《Python虚拟环境终极(含PyCharm的使用教程)》:本文主要介绍Python虚拟环境终极(含PyCharm的使用教程),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录一、为什么需要虚拟环境?二、虚拟环境创建方式对比三、命令行创建虚拟环境(venv)3.1 基础命令3

Python Transformer 库安装配置及使用方法

《PythonTransformer库安装配置及使用方法》HuggingFaceTransformers是自然语言处理(NLP)领域最流行的开源库之一,支持基于Transformer架构的预训练模... 目录python 中的 Transformer 库及使用方法一、库的概述二、安装与配置三、基础使用:Pi

关于pandas的read_csv方法使用解读

《关于pandas的read_csv方法使用解读》:本文主要介绍关于pandas的read_csv方法使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录pandas的read_csv方法解读read_csv中的参数基本参数通用解析参数空值处理相关参数时间处理相关

使用Node.js制作图片上传服务的详细教程

《使用Node.js制作图片上传服务的详细教程》在现代Web应用开发中,图片上传是一项常见且重要的功能,借助Node.js强大的生态系统,我们可以轻松搭建高效的图片上传服务,本文将深入探讨如何使用No... 目录准备工作搭建 Express 服务器配置 multer 进行图片上传处理图片上传请求完整代码示例