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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM