nodeの環境の下でecharts図表に文案を加えます.


開発環境:node開発言語:javascript開発に依存するパッケージ:
  • node-charts
  • canvas
  • グラフの幅は1000です.最後に出す効果を下の図を見てください.
    チャートに追加のテキストブロックを追加すると、1つの属性graphic【ˈgrafik】だけが実装できるようになります.これは、元のパターン要素コンポーネントを指しています.image, text, circle, sector, ring, polygon, polyline, ...などの様々なタイプから構成されてもいいです.すぐやります
    コードは以下の通りです
    var node_echarts = require("node-echarts");
    var Path = require("path");
    const text = '      4G    ,     idea  ,   30       >80% ,     OOM!Chrome     !                    ,  idea chrome   ,      40% 。            ,             ,                (16G macbook pro),       ,      4G     ,       !  ,                     ,         ,        。            ,     ,            JetBrains        。';
    
    const config = {
      legend: { bottom: 0, show: true, data: ["     ", "     "] },
      xAxis: [
        {
          type: "category",
          data: [
            "201701",
            "201702",
            "201703",
            "201704",
            "201705",
            "201706",
            "201707",
            "201708",
            "201709",
            "201710",
            "201711",
            "201712",
            "201801"
          ],
          axisLabel: { interval: 0 },
          axisPointer: { type: "shadow" },
          splitLine:{show: false}
        }
      ],
      yAxis: [
        { type: "value", axisLabel: { formatter: null }  },
        { type: "value", axisLabel: { formatter: "{value}%" }}
      ],
      series: [
        {
          type: "bar",
          name: "     ",
          data: [
            23620000,
            21060000,
            26420000,
            30180000,
            31430000,
            34100000,
            33740000,
            40170000,
            39910000,
            38420000,
            49300000,
            50710000,
            46550000
          ],
          yAxisIndex: 0
        },
        {
          type: "line",
          name: "     ",
          data: [
            -23,
            -12.13,
            20.26,
            12.46,
            4,
            7.82,
            -1.09,
            16.02,
            -0.65,
            -3.88,
            22.05,
            2.79,
            -8.95
          ],
          yAxisIndex: 1
        }
      ],
      color: ["#4498f6", "#d9e96c"],
      graphic: [
        {
                     type: 'text',
                     left: '10%',
                     bottom: 'bottom',
                     style: {
                         fill: '#333',
                         text: text,
                         font: '14px Microsoft YaHei'
                     }
         }
     ],
    };
    
    node_echarts({
      width: 1000,
      height: 400,
      option: config, 
      path: Path.join(__dirname, "./charts.png")
    });
    
    process.exit();
    効果は下図のようです
    問題は二つあります
  • は一行だけで、後ろの文字は全部切断されました.
  • は、凡例の文字をカバーしており、間隔がない
  • .
    第2の問題はよく解決しています.echartsの配置を熟知すれば、gridのbottom、legendのbottomに値を設定します.しかし、この値はダイナミックで、文案の行数と関係があります.まず基本値を決めます.一行だけあれば、gridのbottomは90、legendのbottomは35です.
    const config = {
      legend: { bottom: 3 * 15 + 35, show: true, data: ["     ", "     "] },
      grid: {bottom:  3 * 15 + 90}
    ...
    具体的な行数を得るには、1つ目の問題を解決するために、最も核心的な問題は限られた幅の中でどのように1つの文字の行数を計算しますか?まず次の行にどれぐらいの文字を入れるかを計算してください.中国語は全部中国語で計算します.これで63,行数=Math.ceeir(文字の総長さ/63).行数を得ると、各行の文字が分かります.つまり、改行はこうなります.
    ...
      graphic: [
        {
                     type: 'text',
                     left: '10%',
                     bottom: 'bottom',
                     style: {
                         fill: '#333',
                         text: ['text','text2', 'text3'].join('
    '), font: '14px Microsoft YaHei' } } ], ...
    長い間考えましたが、コードが出ました.
    ...
    const buildText = (result=text) => {
        const graphicY = 15;
        let texts = [];
        let gridBottom = 90;
        let legendBottom = 35;
        
    
        const rlen = 63; //          
        const len = result.length; //       
        //     
        if (len > rlen) {
          const temp = Math.ceil(len / rlen); //    
          const arr = result.split(""); //           
          const newArrs = {};
          //      
          for (let k = 0; k < temp; k++) {
            newArrs[k] = []; //        
    
            for (let i = rlen * k; i < rlen * (k + 1); i++) {
              if(arr[i] != undefined)
                newArrs[k].push(arr[i]);
            }
          }
          for(let j in newArrs){
            texts.push(newArrs[j].join(''));
          }
          const lastLen = texts.length-1;
          gridBottom =  lastLen * graphicY + gridBottom;
          legendBottom = lastLen * graphicY + legendBottom;
        } else {
          texts = [result];
        }
       // console.log(texts);
    
        return {
          graphic: [
            {
              type: "text",
              left: "10%",
              bottom: "bottom",
              style: {
                fill: "#333",
                text: texts.join("
    "), font: "14px Microsoft YaHei" } } ], gridBottom: gridBottom, legendBottom: legendBottom }; } const texts = buildText(); const config = { ... legend: { bottom: texts.legendBottom, show: true, data: [" ", " "] }, grid:{ bottom: texts.gridBottom}, ... } config.graphic = texts.graphic;
    効果は以下の通りです.
    改行しましたが、一行の文字が違っていて、行間がないので、窮屈です.行ごとの長さを計算する方法を説明します.中国語と英語の幅が違っています.各文字の幅を知る必要があります.そして、graphicはimageをサポートしているのではないですか?考えを変えて、文字を画像に変えましょう.canvasに関連してgoogleがcanvas文字を改行した後、このcanvasテキストを見つけて自動的に改行、字間、縦列などを描きます.また、このアムウェイの下で、彼の書いたブログは全部干物だらけで、canvasの中に有用なAPIがあります.measureText、文字の幅を計算します.文字を画像のコードに変えます.
    var fs = require('fs')
    var path = require('path')
    var Canvas = require('canvas')
    const maxWidth = 1000;
    let height = 20;
    const text = '      4G    ,     idea  ,   30       >80% ,     OOM!Chrome     !                    ,  idea chrome   ,      40% 。            ,             ,                (16G macbook pro),       ,      4G     ,       !  ,                     ,         ,        。            ,     ,            JetBrains        。';
    const rlen = 63; //          
    const len = text.length; //       
    const temp = Math.ceil(len / rlen); //    
    
    var canvas = Canvas.createCanvas(maxWidth, temp * height)
    var ctx = canvas.getContext('2d')
    
    ctx.globalAlpha = 1
    ctx.font = '14px Microsoft Yahei'
    ctx.lineWidth = 1
    ctx.fillStyle = '#000'
    
    const arrText = text.split('');
    let line = '';
    let y = 20;
    const lineHeight = 25;
      //          ,      ,              , Y     
      for (var n = 0; n < arrText.length; n++) {
          var testLine = line + arrText[n];
          var metrics = ctx.measureText(testLine);
          var testWidth = metrics.width;
          if (testWidth > maxWidth && n > 0) {
            ctx.fillText(line, 0, y);
            line = arrText[n];
            y += lineHeight;
          } else {
            line = testLine;
          }
        //  console.log(line)
      }
      console.log(line)
      ctx.fillText(line, 0, y);
    
    canvas.createPNGStream().pipe(fs.createWriteStream(path.join(__dirname, 'text.png')))
    もらった写真は以下の通りです.
    そしてgraphicを修正します
    ...
      graphic:[{
                     type: 'image',
                     left: '10%',
                     bottom: 'bottom',
                     style: {
                         image: path.join(__dirname, 'text.png')
                         width: 1000,
                         height: 200  
                     }
         }],
       ...
    しかし、画像は生成されておらず、上のコードは機能していません.ソースコードを調べましたが、原因が見つからないので、issueを提出するしかありません.これはまた起点に戻りますが、文字の長さを計算する方法は上記のようになります.
    const buildText = (text=text) => {
      const graphicY = 15;
      let gridBottom = 90;
      let legendBottom = 35;
      const maxWidth = 900;
      const canvas = createCanvas(maxWidth,100);
      const ctx = canvas.getContext("2d");
      ctx.font = "normal 14px SongTi";
      const arrText = text.split('');
      let line = '';
      const newArrs = [];
      for (var n = 0; n < arrText.length; n++) {
          var testLine = line + arrText[n];
          var metrics = ctx.measureText(testLine);
          var testWidth = metrics.width;
         
          if (testWidth > maxWidth & n>0) {
            line = arrText[n];
            newArrs.push(testLine.substr(0, testLine.length-1));
          } else {
            line = testLine;
          }
      }
      newArrs.push(line);
      //console.log(newArrs);
      const row = newArrs.length;
      if (row > 1) {
        gridBottom = row * graphicY + gridBottom;
        legendBottom = row * graphicY + legendBottom;
      }
     
      return {
        graphic:[
            {
              type: "text",
              left: "10%",
              bottom: "bottom",
              style: {
                fill: "#333",
                text: newArrs.join("
    "), font: "14px Songti" } } ], gridBottom: gridBottom, legendBottom: legendBottom }; }
    得られた効果は以下の通りです.
    行間の問題は解決されていませんでした.graphicは配列である以上、行ごとに分解して個々の対象として、bottomの値が違います.
    const buildText = (text=text) =>{
      const graphicY = 15;
      const lineY = 20; //       bottom   
      let gridBottom = 90;
      let legendBottom = 35;
      const maxWidth = 900;
      const canvas = createCanvas(maxWidth,100);
      const ctx = canvas.getContext("2d");
      ctx.font = "normal 14px SongTi";
      const arrText = text.split('');
      let line = '';
      const newArrs = [];
      for (var n = 0; n < arrText.length; n++) {
          var testLine = line + arrText[n];
          var metrics = ctx.measureText(testLine);
          var testWidth = metrics.width;
         
          if (testWidth > maxWidth & n>0) {
            line = arrText[n];
            newArrs.push(testLine.substr(0, testLine.length-1));
          } else {
            line = testLine;
          }
      }
      newArrs.push(line);
      //console.log(newArrs);
      const row = newArrs.length; //    
      if (row > 1) {
        gridBottom = row * graphicY + gridBottom;
        legendBottom = row * graphicY + legendBottom;
      }
      let graphics = [];
      //        
      for (let k=0; k < row; k++){
         const temp = {
          type: "text",
          left: "5%",
          bottom: (row-1-k) * lineY, //     ,   
          style: {
            fill: "#333",
            text: [`${newArrs[k]}`].join("
    "), font: "14px SongTi" } } graphics.push(temp); } // console.log(graphics); return { graphic: graphics, gridBottom: gridBottom, legendBottom: legendBottom };
    これで問題はすべて解決された.
    最終ソースコード転送ゲート:github
    締め括りをつける
    echart座標系を理解してecharts基本構成を熟知しています.canvas基本APIは数学を熟知しています.数字に対して敏感にして、書かないでください.
    多く捜索して、多く試みて、多く考えてやっと融通がききます.