js将文字填充与canvas画布再转为图片
需求:封装consul服务的webUI;
原因:展示consul的服务信息时,需要嵌套动画,由于其没有内置的icon,所以将服务name放于图片位;
分析:展示信息时采用了卡片式的服务布局,缩放式的服务卡片,只有将服务名称作为图片才能实现动画效果;
最基础动画:->
实现:将服务名称置于canvas画布中,再将画布转为图片
代码实现:
1、获取dom
/** * 获取service卡片中img对象并赋值src * @param serviceName 服务名称 */ setImageSrc(serviceName) { //因为src不是该HTMLElement类型的属性,而是HTMLImageElement。 let image = <HTMLImageElement>document.querySelector("#nameImage" + serviceName); image.src = this.canvasWrapText({canvas:<HTMLElement>document.querySelector("#canvas" + serviceName),text: serviceName}); }
2、画布=>图片
/** * 绘制文字到canvas,判断换行位置,和设置canvas高度 * @param options canvas画布对象 */ canvasWrapText(options) { let settings = { canvas:document.getElementsByTagName("canvas")[0], //canvas对象,必填,不填写默认找到页面中的第一个canvas canvasWidth:240, //canvas的宽度 drawStartX:50, //绘制字符串起始x坐标 drawStartY:30, //绘制字符串起始y坐标 lineHeight:30, //文字的行高 font:"24px 'Microsoft Yahei'", //文字样式 text:"请修改掉默认的配置", //需要绘制的文本 drawWidth:220, //文字显示的宽度 color:"#000000", //文字的颜色 textAlain: "center", backgroundColor:"#ffffff", //背景颜色 }; //将传入的配置覆盖掉默认配置 if(!!options && typeof options === "object"){ for(let i in options){ settings[i] = options[i]; } } //获取2d的上线文开始设置相关属性 let canvas = settings.canvas; canvas.width = settings.canvasWidth; let ctx = canvas.getContext("2d"); //绘制背景色 ctx.fillStyle = settings.backgroundColor; ctx.fillRect(0,0,canvas.width,canvas.height); //绘制文字 ctx.font = settings.font; ctx.fillStyle = settings.color; // @ts-ignore ctx.textAlign = settings.textAlain; let lineWidth = 0; //当前行的绘制的宽度 let lastTextIndex = 0; //已经绘制上canvas最后的一个字符的下标 //由于改变canvas 的高度会导致绘制的纹理被清空,所以,不预先绘制,先放入到一个数组当中 let arr = []; for(let i = 0; i< settings.text.length; i++){ //获取当前的截取的字符串的宽度 lineWidth = ctx.measureText(settings.text.substr(lastTextIndex,i-lastTextIndex)).width; if(lineWidth > settings.drawWidth){ //判断最后一位是否是标点符号 if(judgePunctuationMarks(settings.text[i-1])){ arr.push(settings.text.substr(lastTextIndex,i-lastTextIndex)); lastTextIndex = i; }else{ arr.push(settings.text.substr(lastTextIndex,i-lastTextIndex-1)); lastTextIndex = i-1; } } //将最后多余的一部分添加到数组 if(i === settings.text.length - 1){ arr.push(settings.text.substr(lastTextIndex,i-lastTextIndex+1)); } } //根据arr的长度设置canvas的高度 canvas.height = arr.length*settings.lineHeight+settings.drawStartY; ctx.font = settings.font; ctx.fillStyle = settings.color; for(let i =0; i<arr.length; i++){ ctx.fillText(arr[i],settings.drawStartX,settings.drawStartY+i*settings.lineHeight); } //判断是否是需要避开的标签符号 function judgePunctuationMarks(value) { let arr = [".",",",";","?","!",":","\"",",","。","?","!",";",":","、"]; for(let i = 0; i< arr.length; i++){ if(value === arr[i]){ return true; } } return false; } return canvas.toDataURL(); }
注:关于代码实现中的关键节点都有详细的注解,此处不再累赘。
3、html:
<div class="member-image"> <!--为了将文字渲染为图片所设置的样例canvas--> <canvas id="canvas{{card.name}}" width="" height="" style="background-color:#ffffff;display: none;"></canvas> <img id="nameImage{{card.name}}" alt="Member"> </div>
注:html代码中有遍历,不可直接使用