富文本
自 v3.7 起,Apache EChartsTM 的系列、坐标轴或其他组件的标签开始支持富文本。富文本支持:
- 可以指定一个文本块的盒模型样式(背景、边框、阴影等)、旋转和位置。
- 可以对文本片段自定义样式(颜色、字体、宽度/高度、背景、阴影等)和对齐方式。
- 可以在文本中使用图片作为图标或背景。
- 结合这些配置,可以制作出一些特殊效果,例如简单的表格、水平分割线(hr)。
首先,需要明确下文将用到的两个术语的含义:
- 文本块(Text Block):整个标签文本的区块。
- 文本片段(Text fragment):文本块中的某一段文本。
例如:
文本相关配置项
ECharts 提供了丰富的文本配置项,包括:
- 基本字体样式:
fontStyle
、fontWeight
、fontSize
、fontFamily
。 - 文本填充:
color
。 - 文本描边:
textBorderColor
、textBorderWidth
。 - 文本阴影:
textShadowColor
、textShadowBlur
、textShadowOffsetX
、textShadowOffsetY
。 - 文本块或文本片段的盒大小:
lineHeight
、width
、height
、padding
。 - 文本块或文本片段的对齐方式:
align
、verticalAlign
。 - 文本块或文本片段的边框、背景(颜色或图片):
backgroundColor
、borderColor
、borderWidth
、borderRadius
。 - 文本块或文本片段的阴影:
shadowColor
、shadowBlur
、shadowOffsetX
、shadowOffsetY
。 - 文本块的位置和旋转:
position
、distance
、rotate
。
用户可以在 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
}
// ...
}
};
注意:
width
和height
只有在指定了rich
时才生效。
文本、文本块和文本片段的基本样式
可以为文本设置基本字体样式:fontStyle
、fontWeight
、fontSize
、fontFamily
。
可以为文本设置填充色和描边色:color
、textBorderColor
、textBorderWidth
。
可以为文本块设置边框和背景样式:borderColor
、borderWidth
、backgroundColor
、padding
。
也可以为文本片段设置边框和背景样式:borderColor
、borderWidth
、backgroundColor
、padding
。
例如:
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
配置项可用于如柱状图
、折线图
、散点图
等图表中。标签的位置可以通过 label.position 和 label.distance 指定。
尝试在以下示例中修改 position
和 distance
配置项:
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] } ] };
在这种情况下,可以使用 align 和 verticalAlign 来调整标签的位置。
注意,会先应用 align
和 verticalAlign
,然后再进行旋转。
文本片段的布局和对齐
为了理解布局规则,可以将每个文本片段想象成 CSS 中的一个 inline-block
DOM 元素。
一个文本片段的内容盒大小
(content box size)默认由其字体大小决定。也可以通过 width
和 height
直接指定,尽管很少这样设置。一个文本片段的边框盒大小
(border box size)是通过将内容盒大小
和 padding
相加计算得出的。
只有 '\n'
是换行符,用于换行。
一行中可以存在多个文本片段。一行的高度由文本片段中最大的 lineHeight
决定。文本片段的 lineHeight
可以在 rich
中指定,或者在 rich
的父级中指定,否则使用文本片段的盒大小
。
确定了 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.org.cn/examples/data/asset/img/weather/sunny_128.png' } }, cloudy: { height: 30, align: 'left', backgroundColor: { image: 'https://echarts.org.cn/examples/data/asset/img/weather/cloudy_128.png' } }, showers: { height: 30, align: 'left', backgroundColor: { image: 'https://echarts.org.cn/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'
}
}
简单表格可以通过为不同行中同一列的文本片段指定相同的宽度来实现。参见此示例。