富文本

自 v3.7 起,富文本可以在 Apache EChartsTM 系列、坐標軸或其他元件的標籤中使用。它支援

  • 可以指定文字區塊的方塊樣式(背景、邊框、陰影等)、旋轉、位置。
  • 可以自訂文字片段的樣式(顏色、字型、寬/高、背景、陰影等)和對齊方式。
  • 圖像可以用作文字中的圖示或背景。
  • 結合這些配置,可以製作一些特殊效果,例如簡單表格、水平線 (hr)。

首先,應澄清以下將使用的兩個術語的含義

  • 文字區塊:標籤文字的整個區塊。
  • 文字片段:文字區塊中的一部分文字。

例如

關於文字的選項

echarts 提供了大量的文字選項,包括

  • 基本字型樣式:fontStylefontWeightfontSizefontFamily
  • 文字填充:color
  • 文字筆畫:textBorderColortextBorderWidth
  • 文字陰影:textShadowColortextShadowBlurtextShadowOffsetXtextShadowOffsetY
  • 文字區塊或文字片段的方塊大小:lineHeightwidthheightpadding
  • 文字區塊或文字片段的對齊方式:alignverticalAlign
  • 文字區塊或文字片段的邊框、背景(顏色或圖像):backgroundColorborderColorborderWidthborderRadius
  • 文字區塊或文字片段的陰影:shadowColorshadowBlurshadowOffsetXshadowOffsetY
  • 文字區塊的位置和旋轉:positiondistancerotate

使用者可以在 rich 屬性中定義文字片段的樣式。例如,series-bar.label.rich

例如

labelOption = {
  // Styles defined in 'rich' can be applied to some fragments
  // of text by adding some markers to those fragment, like
  // `{styleName|text content text content}`.
  // `'\n'` is the newline character.
  formatter: [
    '{a|Style "a" is applied to this fragment}',
    '{b|Style "b" is applied to this fragment}This fragment use default style{x|use style "x"}'
  ].join('\n'),

  // Styles for the whole text block are defined here:
  color: '#333',
  fontSize: 5,
  fontFamily: 'Arial',
  borderWidth: 3,
  backgroundColor: '#984455',
  padding: [3, 10, 10, 5],
  lineHeight: 20,

  // Styles for text fragments are defined here:
  rich: {
    a: {
      color: 'red',
      lineHeight: 10
    },
    b: {
      backgroundColor: {
        image: 'xxx/xxx.jpg'
      },
      height: 40
    },
    x: {
      fontSize: 18,
      fontFamily: 'Microsoft YaHei',
      borderColor: '#449933',
      borderRadius: 4
    }
    // ...
  }
};

注意:只有在指定 rich 時,widthheight 才會生效。

文字、文字區塊和文字片段的基本樣式

可以為文字設定基本字型樣式:fontStylefontWeightfontSizefontFamily

可以為文字設定填充顏色和筆畫顏色:colortextBorderColortextBorderWidth

可以為文字區塊設定邊框樣式和背景樣式:borderColorborderWidthbackgroundColorpadding

也可以為文字片段設定邊框樣式和背景樣式:borderColorborderWidthbackgroundColorpadding

例如

option = {
  series: [
    {
      type: 'scatter',
      symbolSize: 1,
      data: [
        {
          value: [0, 0],
          label: {
            show: true,
            formatter: [
              'Plain text',
              '{textBorder|textBorderColor + textBorderWidth}',
              '{textShadow|textShadowColor + textShadowBlur + textShadowOffsetX + textShadowOffsetY}',
              '{bg|backgroundColor + borderRadius + padding}',
              '{border|borderColor + borderWidth + borderRadius + padding}',
              '{shadow|shadowColor + shadowBlur + shadowOffsetX + shadowOffsetY}'
            ].join('\n'),
            backgroundColor: '#eee',
            borderColor: '#333',
            borderWidth: 2,
            borderRadius: 5,
            padding: 10,
            color: '#000',
            fontSize: 14,
            shadowBlur: 3,
            shadowColor: '#888',
            shadowOffsetX: 0,
            shadowOffsetY: 3,
            lineHeight: 30,
            rich: {
              textBorder: {
                fontSize: 20,
                textBorderColor: '#000',
                textBorderWidth: 3,
                color: '#fff'
              },
              textShadow: {
                fontSize: 16,
                textShadowBlur: 5,
                textShadowColor: '#000',
                textShadowOffsetX: 3,
                textShadowOffsetY: 3,
                color: '#fff'
              },
              bg: {
                backgroundColor: '#339911',
                color: '#fff',
                borderRadius: 15,
                padding: 5
              },
              border: {
                color: '#000',
                borderColor: '#449911',
                borderWidth: 1,
                borderRadius: 3,
                padding: 5
              },
              shadow: {
                backgroundColor: '#992233',
                padding: 5,
                color: '#fff',
                shadowBlur: 5,
                shadowColor: '#336699',
                shadowOffsetX: 6,
                shadowOffsetY: 6
              }
            }
          }
        }
      ]
    }
  ],
  xAxis: {
    show: false,
    min: -1,
    max: 1
  },
  yAxis: {
    show: false,
    min: -1,
    max: 1
  }
};
即時範例

標籤位置

label 選項可用於 barlinescatter 等圖表中。標籤的位置可以由 label.positionlabel.distance 指定。

嘗試修改以下範例中的 positiondistance 選項

option = {
  series: [
    {
      type: 'scatter',
      symbolSize: 160,
      symbol: 'roundRect',
      data: [[1, 1]],
      label: {
        // Options: 'left', 'right', 'top', 'bottom', 'inside', 'insideTop', 'insideLeft', 'insideRight', 'insideBottom', 'insideTopLeft', 'insideTopRight', 'insideBottomLeft', 'insideBottomRight'
        position: 'top',
        distance: 10,

        show: true,
        formatter: ['Label Text'].join('\n'),
        backgroundColor: '#eee',
        borderColor: '#555',
        borderWidth: 2,
        borderRadius: 5,
        padding: 10,
        fontSize: 18,
        shadowBlur: 3,
        shadowColor: '#888',
        shadowOffsetX: 0,
        shadowOffsetY: 3,
        textBorderColor: '#000',
        textBorderWidth: 3,
        color: '#fff'
      }
    }
  ],
  xAxis: {
    max: 2
  },
  yAxis: {
    max: 2
  }
};
即時範例

請注意,不同圖表類型的 position 可選值不同。並且並非每個圖表都支援 distance。更多詳細資訊可以在 選項文件 中查看。

標籤旋轉

有時需要旋轉標籤。例如

const labelOption = {
  show: true,
  rotate: 90,
  formatter: '{c}  {name|{a}}',
  fontSize: 16,
  rich: {
    name: {}
  }
};

option = {
  xAxis: [
    {
      type: 'category',
      data: ['2012', '2013', '2014', '2015', '2016']
    }
  ],
  yAxis: [
    {
      type: 'value'
    }
  ],
  series: [
    {
      name: 'Forest',
      type: 'bar',
      barGap: 0,
      label: labelOption,
      emphasis: {
        focus: 'series'
      },
      data: [320, 332, 301, 334, 390]
    },
    {
      name: 'Steppe',
      type: 'bar',
      label: labelOption,
      emphasis: {
        focus: 'series'
      },
      data: [220, 182, 191, 234, 290]
    }
  ]
};
即時範例

alignverticalAlign 可用於調整此情況下標籤的位置。

請注意,alignverticalAlign 會先套用,然後再旋轉。

文字片段的版面配置和對齊方式

要了解版面配置規則,可以將每個文字片段想像為 CSS 中的 inline-block dom 元素。

文字片段的 content box size 預設由其字型大小決定。也可以直接透過 widthheight 指定,儘管它們很少設定。文字片段的 border box size 是透過新增 border box sizepadding 來計算的。

只有 '\n' 是換行字元,會中斷一行。

單行中存在多個文字片段。一行的高度由文字片段的最大 lineHeight 決定。文字片段的 lineHeight 可以在 rich 中或在 rich 的父層級中指定,否則使用文字片段的 box size

確定 lineHeight 後,文字片段的垂直位置可以由 verticalAlign 決定(這與 CSS 中的規則略有不同)

  • 'bottom':文字片段的底邊緣貼齊該行的底邊緣。
  • 'top':文字片段的頂邊緣貼齊該行的頂邊緣。
  • 'middle':在該行的中間。

文字區塊的寬度可以由 width 指定,否則由最長行決定。確定寬度後,文字片段可以放置在每一行中,其中文字片段的水平位置可以由其 align 決定。

  • 首先,從左到右連續放置 align'left' 的文字片段。
  • 其次,從右到左連續放置 align'right' 的文字片段。
  • 最後,剩下的文字片段將會貼齊並放置在剩餘空間的中心。

文字在文字片段中的位置

  • 如果 align'center',文字會對齊到文字片段方塊的中心。
  • 如果 align'left',文字會對齊到文字片段方塊的左側。
  • 如果 align'right',文字會對齊到文字片段方塊的右側。

效果:圖示、水平線、標題區塊、簡單表格

請參閱範例

option = {
  series: [
    {
      type: 'scatter',
      data: [
        {
          value: [0, 0],
          label: {
            formatter: [
              '{tc|Center Title}{titleBg|}',
              '  Content text xxxxxxxx {sunny|} xxxxxxxx {cloudy|}  ',
              '{hr|}',
              '  xxxxx {showers|} xxxxxxxx  xxxxxxxxx  '
            ].join('\n'),
            rich: {
              titleBg: {
                align: 'right'
              }
            }
          }
        },
        {
          value: [0, 1],
          label: {
            formatter: [
              '{titleBg|Left Title}',
              '  Content text xxxxxxxx {sunny|} xxxxxxxx {cloudy|}  ',
              '{hr|}',
              '  xxxxx {showers|} xxxxxxxx  xxxxxxxxx  '
            ].join('\n')
          }
        },
        {
          value: [0, 2],
          label: {
            formatter: [
              '{titleBg|Right Title}',
              '  Content text xxxxxxxx {sunny|} xxxxxxxx {cloudy|}  ',
              '{hr|}',
              '  xxxxx {showers|} xxxxxxxx  xxxxxxxxx  '
            ].join('\n'),
            rich: {
              titleBg: {
                align: 'right'
              }
            }
          }
        }
      ],
      symbolSize: 1,
      label: {
        show: true,
        backgroundColor: '#ddd',
        borderColor: '#555',
        borderWidth: 1,
        borderRadius: 5,
        color: '#000',
        fontSize: 14,
        rich: {
          titleBg: {
            backgroundColor: '#000',
            height: 30,
            borderRadius: [5, 5, 0, 0],
            padding: [0, 10, 0, 10],
            width: '100%',
            color: '#eee'
          },
          tc: {
            align: 'center',
            color: '#eee'
          },
          hr: {
            borderColor: '#777',
            width: '100%',
            borderWidth: 0.5,
            height: 0
          },
          sunny: {
            height: 30,
            align: 'left',
            backgroundColor: {
              image:
                'https://echarts.dev.org.tw/examples/data/asset/img/weather/sunny_128.png'
            }
          },
          cloudy: {
            height: 30,
            align: 'left',
            backgroundColor: {
              image:
                'https://echarts.dev.org.tw/examples/data/asset/img/weather/cloudy_128.png'
            }
          },
          showers: {
            height: 30,
            align: 'left',
            backgroundColor: {
              image:
                'https://echarts.dev.org.tw/examples/data/asset/img/weather/showers_128.png'
            }
          }
        }
      }
    }
  ],
  xAxis: {
    show: false,
    min: -1,
    max: 1
  },
  yAxis: {
    show: false,
    min: 0,
    max: 2,
    inverse: true
  }
};
即時範例

圖示是透過在 backgroundColor 中使用圖像來實現的。

rich: {
    Sunny: {
        backgroundColor: {
            image: './data/asset/img/weather/sunny_128.png'
        },
        // Can only height specified, but leave width auto obtained
        // from the image, where the aspect ratio kept.
        height: 30
    }
}

水平線(如 HTML <hr> 標籤)可以透過邊框實現

rich: {
    hr: {
        borderColor: '#777',
        // width is set as '100%' to fullfill the text block.
        // Notice, the percentage is based on the content box, without
        // padding. Although it is a little different from CSS rule,
        // it is convinent in most cases.
        width: '100%',
        borderWidth: 0.5,
        height: 0
    }
}

標題區塊可以透過 backgroundColor 實現

// Title is at left.
formatter: '{titleBg|Left Title}',
rich: {
    titleBg: {
        backgroundColor: '#000',
        height: 30,
        borderRadius: [5, 5, 0, 0],
        padding: [0, 10, 0, 10],
        width: '100%',
        color: '#eee'
    }
}

// Title is in the center of the line.
// This implementation is a little tricky, but is works
// without more complicated layout mechanism involved.
formatter: '{tc|Center Title}{titleBg|}',
rich: {
    titleBg: {
        align: 'right',
        backgroundColor: '#000',
        height: 30,
        borderRadius: [5, 5, 0, 0],
        padding: [0, 10, 0, 10],
        width: '100%',
        color: '#eee'
    }
}

簡單表格可以透過為不同行的相同欄位中的文字片段指定相同的寬度來實現。請參閱 範例

貢獻者 在 GitHub 上編輯此頁面

plainheart plainheartTSinChen TSinChenpissang pissang