前言
玩转ECharts系列,主要为大家讲解我们基于ECharts如何实现企业级大屏项目中较为常用的各种奇奇怪怪的图表,接下来我们将通过几篇文章从基础图表开始为大家详细讲解实现这些图表样式的一些“小心机”。
导读阅读完此文,你会了解基于ECharts:
1、如何实现能够动态配置颜色的图标
2、如何通过自定义图标写条形图
背景
在使用ECharts绘制折线图时,为了丰富图表的视觉表达,设计师们常常会为视图搭配上不同的图标。但ECharts官方所提供的预置图标样式却是有限的,无法匹配设计师们的创造性。
如下图所示,通常这样的需求需要使用3个不同颜色的icon资源,设计师需要提供多个图标切图,当数据颜色序列数量不固定时,需要的图标数量不可控,研发同学又控制不了颜色,由此可见,当形状相同颜色不同时,我们可以使用一个icon资源来解决这件事,接下来,笔者将说明如何使用自定义图标来解决上述问题,需求可以拆解为:
1.图标颜色需要能够动态与数据相匹配,并能够在指定位置自定义(不同的位置颜色不同);
2.在折线图节点、legend和tooltip中,图标能够统一。
知识点
查阅ECharts官方文档可知,自定义图标的返回值有2种(series.line中可以使用函数的形式返回,但返回的字符串还是需要符合以下格式):URL
通过 'image://url' 设置为图片,其中 URL 为图片的链接,或者 dataURI。
URL 为图片链接,例如:
'image://http://xxx.xxx.xxx/a/b.png'
URL 为 dataURI ,一般为base64格式,例如:
'image://data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7'path
通过 'path://' 将图标设置为任意的矢量路径,例如:
'path://M30.9,53.2C16.8,53.2,5.3,41.7,5.3,27.6S16.8,2,30.9,2C45,2,56.4,13.5,56.4,27.6S45,53.2,30.9,53.2z M30.9,3.5C17.6,3.5,6.8,14.4,6.8,27.6c0,13.3,10.8,24.1,24.101,24.1C44.2,51.7,55,40.9,55,27.6C54.9,14.4,44.1,3.5,30.9,3.5z M36.9,35.8c0,0.601-0.4,1-0.9,1h-1.3c-0.5,0-0.9-0.399-0.9-1V19.5c0-0.6,0.4-1,0.9-1H36c0.5,0,0.9,0.4,0.9,1V35.8z M27.8,35.8 c0,0.601-0.4,1-0.9,1h-1.3c-0.5,0-0.9-0.399-0.9-1V19.5c0-0.6,0.4-1,0.9-1H27c0.5,0,0.9,0.4,0.9,1L27.8,35.8L27.8,35.8z'
比较这两种方法(如下表所示),可以发现它们各自的优缺点都十分明显,但似乎没有哪一种方式能够满足我们的需求。
但是实际上,dataURI存在一个不同于常见的“使用base64转码”的“隐藏”配置方式,不仅好用、还可读。也就是笔者在本篇文章中要重点介绍的:将svg格式文件转换为CSS的url()可以内联的svg代码。
基础实现
单折线示例
首先,我们准备一张svg格式的图标(可以直接去各大图标库里找一找)。
示例图标:
CSS的url()可用的svg内联代码配置方式为:
'data:image/svg+xml;utf8,'
加上经过encodeURIComponent() 转译的完整的SVG代码主体(即整个节点)。
然后,为了能够在ECharts中使用,还需要按照ECharts的需要在这段代码之前加上image://
let icon = ''
icon = encodeURIComponent(icon) // 转译
icon = 'data:image/svg+xml;utf8,' + icon // 添加url前缀
icon = 'image://' + icon // 添加ECharts需要的前缀
将我们拼接好的图标运用到折线图中,得到如下效果。
可以看到,这种方式最大限度的保留了svg的文件格式,也就一定程度上保证了图片文件的易读和易写性。
多折线示例
当然,仅仅是这样并不能满足我们的需求,在有多组数据时,我们提出要求:图标外圈的光晕部分,颜色与数据保持一致,但内圈的颜色不变。这就显出了保持原本svg格式的好处:我们可以很容易的找到外圈的颜色样式信息 :fill="#FF6E6E",并在代码中动态的修改它。
为了方便修改,将代码块中需要替换的颜色部分用 __color标识出来,即,将fill="#FF6E6E" 变成 fill="#__color",之后在代码中动态替换为对应的颜色。
需要注意的是,我们使用的图标字符串是经过转码的,因此,这里的 #__color 以及用来替换的颜色也需要转码。
let myTag = '#__color'
myTag = encodeURIComponent(myTag)
let currentColor = '#FF0' // 当前颜色
currentColor= encodeURIComponent(currentColor)
const symbol = icon.replace(myTag, currentColor)
为了保证在视图、legend和tooltip中图标样式的统一,还需要配置一下tooltip中的formatter,将自定义的图标配置到节点上。
扩展实现
实际上,这样的自定义节点除了可以帮助我们让视图变得更好看,还能用在很多其他的地方。比如,在legend中动态绘制长条图。
通过手写svg,并将其转换为自定义图标添加到legend中,可以做到图例项的选取交互和数据表达两不误。
核心代码
newData.forEach(item => {
const _num = Math.log10(Math.round(item.max))
const _max = Math.log10(Math.round(_lengedMax))
const _numWidth = Math.round(_num / _max * maxWidth)
const _dataWidth = _numWidth > 20 ? _numWidth : 20
item.textStyle = {
color: countryMap[item._name].color
}
// 在这里对 legend 的 icon 做了自定义 动态的修改了他的${_dataWidth}属性
item.icon = `image://data:image/svg+xml,` +
`%3Csvg xmlns='http://www.w3.org/2000/svg'%3E` +
`%3Cpath d='M0 260h${_dataWidth}v270H0z' fill='${countryMap[item._name].color}'/%3E` +
`%3Cpath fill='rgba(0, 0,0,0)' d='M${_dataWidth} 60h${maxWidth - _dataWidth}v100H100z'/%3E` +
`%3Ctext x='${_dataWidth}' y='0' style='color: red' %3E${item.max}%3C/text%3E` +
`%3C/svg%3E`// `path://M10 60 H ${_a / _max * maxWidth} V 70 H 10 Z`
legendData.push(item)
})
实例展示
这里有一些我们在实际应用中使用的的效果,抛砖引玉,为大家设计时提供一个思路。