需求:封裝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代碼中有遍歷,不可直接使用