Ecahrts.toolbox 图标自定义

862 阅读4分钟

echars.toolbox 除了各个内置的工具按钮外,还可以自定义工具按钮,每个工具按钮都可以通过icon自定义展示图标,同时配置iconStyle设置图标样式。

icon 选项

  • 可以通过 'image://url' 设置为图片,其中 URL 为图片的链接,或者 dataURI

    • URL 为图片链接例如:
    'image://http://example.website/a/b.png'
    
    • URL 为 dataURI 例如:
    'image://data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7'
    
  • 可以通过 'path://' 将图标设置为任意的矢量路径。这种方式相比于使用图片的方式,不用担心因为缩放而产生锯齿或模糊,而且可以设置为任意颜色。路径图形会自适应调整为合适的大小。路径的格式参见 SVG PathData。可以从 Adobe Illustrator 等工具编辑导出。

'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'

缺点:只能设置线性图标-无背景

iconStyle 选项

配置过的都知道,只能配置线性图标颜色或者阴影(基本少用),无法添加背景色,只能设置简单的线性图标按钮样式。

如果我们的设计稿是实现这样的图标,那该如何处理?

image.png

思路

  1. 通过你所掌握的任意绘图工具,获得对应图标的 image://[url]image://[dataURI] 链接,通过 icon 选项配置得到自定义图标

image.png

通过 image:// 格式指定的自定义图标,会有尺寸缩放问题,所以需要稍微调整实际尺寸。

例子通过 svg + btoa 获取一个dataURI:

const customIconSVG = `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 30 30"><rect x="0" y="0" width="30" height="30" rx="5" fill="#F7F7F7" /><polyline points="10 13 15 18 20 13" fill="black" /><line x1="15" y1="13" x2="15" y2="5" stroke="black" stroke-width="2" stroke-linecap="round" /><line x1="6" y1="23" x2="24" y2="23" stroke="black" stroke-width="2" stroke-linecap="round" /></svg>`

const iconDataURI = 'data:image/svg+xml;base64,' + btoa(customIconSVG);
// data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMCIgaGVpZ2h0PSIzMCIgdmlld0JveD0iMCAwIDMwIDMwIj48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMzAiIGhlaWdodD0iMzAiIHJ4PSI1IiBmaWxsPSIjRjdGN0Y3IiAvPjxwb2x5bGluZSBwb2ludHM9IjEwIDEzIDE1IDE4IDIwIDEzIiBmaWxsPSJibGFjayIgLz48bGluZSB4MT0iMTUiIHkxPSIxMyIgeDI9IjE1IiB5Mj0iNSIgc3Ryb2tlPSJibGFjayIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIC8+PGxpbmUgeDE9IjYiIHkxPSIyMyIgeDI9IjI0IiB5Mj0iMjMiIHN0cm9rZT0iYmxhY2siIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiAvPjwvc3ZnPg==

image.png

  1. 定义每个图标的普通状态icon和悬浮状态icon
// 定义每个图标的普通状态和鼠标悬浮状态的路径
const iconInfo = {
    save: {
        normal: 'image://data:image/png;base64,XXXXX', // 保存图标的普通状态路径
        hover: 'image://data:image/png;base64,YYYYY' // 保存图标的鼠标悬浮状态路径
    },
    dataZoom: {
        normal: 'image://data:image/png;base64,AAAAA', // 数据区域缩放图标的普通状态路径
        hover: 'image://data:image/png;base64,BBBBB' // 数据区域缩放图标的鼠标悬浮状态路径
    },
    // 其他图标的普通状态和鼠标悬浮状态路径 // ...
};
  1. 声明echart实例
const option = {
    // ...
    toolbox: {
        feature: {
            saveAsImage: {
                icon: iconInfo.save.normal, // 保存图标的普通状态路径
            },
            dataZoom: {
                icon: iconInfo.dataZoom.normal, // 数据区域缩放图标的普通状态路径
            }
            // 其他图标的配置
        },
        // ...
   }
   // ...
};
  1. 最后通过echart实例监听鼠标 mousemove 事件,通过 echartInstance.containPixel api判断鼠标位置,如果是toolbox对应图标,则进行图标替换:
myChart.getZr().on('mousemove', function (params) {
    var pointInPixel = [params.offsetX, params.offsetY];
    for (var key in iconInfo) {
        if (myChart.containPixel('toolbox', pointInPixel, {icon: key})) {
            // 根据图标名称切换图标显示
            myChart.dispatchAction({
                type: 'updateAxisPointer',
                axisPointer: {
                    toolboxIcon: iconInfo[key].hover // 切换为鼠标悬浮状态的图标
                }
            });
        } else {
            // 鼠标不在该图标区域内,恢复普通状态的图标
            myChart.dispatchAction({
                type: 'updateAxisPointer',
                axisPointer: {
                    toolboxIcon: iconInfo[key].normal // 恢复为普通状态的图标
                }
            });
        }
   }
});

最终实现

var customIconSVG = `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 30 30"><rect x="0" y="0" width="30" height="30" rx="5" fill="#F7F7F7" /><polyline points="10 13 15 18 20 13" fill="black" /><line x1="15" y1="13" x2="15" y2="5" stroke="black" stroke-width="2" stroke-linecap="round" /><line x1="6" y1="23" x2="24" y2="23" stroke="black" stroke-width="2" stroke-linecap="round" /></svg>`;


var customIconHoverSVG = `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 30 30"><rect x="0" y="0" width="30" height="30" rx="5" fill="#3D97D0" /><polyline points="10 13 15 18 20 13" fill="white" /><line x1="15" y1="13" x2="15" y2="5" stroke="white" stroke-width="2" stroke-linecap="round" /><line x1="6" y1="23" x2="24" y2="23" stroke="white" stroke-width="2" stroke-linecap="round" /></svg>`;

// 自定义图标
var iconInfo = {
    saveAsImage: {
        normal: 'image://data:image/svg+xml;base64,' + btoa(customIconSVG), // 保存图标的普通状态路径
        hover: 'image://data:image/svg+xml;base64,' + btoa(customIconHoverSVG), // 保存图标的鼠标悬浮状态路径
    }
};

// 配置项
option = {
   // ...
  toolbox: {
    feature: {
      saveAsImage: {
        title: 'Save as image', // 基于title值进行判断
        icon: iconInfo.saveAsImage.normal
      }
    }
  },
   // ...
};

// 事件监听
// 不同版本echarts实现方式有差异
///5.5.0 版本简单监听实现
myChart.getZr().on('mousemove', function (params) {
    var pointInPixel = [params.offsetX, params.offsetY];
    if (params.topTarget && params.topTarget.__title === 'Save as image') { // 基于title值进行判断
        // 鼠标悬浮在保存图标区域内,切换图标显示
        option.toolbox.feature.saveAsImage.icon = iconInfo.saveAsImage.hover; // 切换为鼠标悬浮状态的图标
        myChart.setOption(option);
    } else {
        // 鼠标不在保存图标区域内,恢复普通状态的图标
        option.toolbox.feature.saveAsImage.icon = iconInfo.saveAsImage.normal; // 恢复为普通状态的图标
        myChart.setOption(option);
    }
});


normal: image.png

hover: image.png

注:不同版本ecahrts监听鼠标移动到toolbox有差异

注:setOption引发重绘导致悬浮文字不显示