ECharts 自定义系列 profile 坐标转置

2017-11-18  本文已影响0人  Abbott思宇

[TOC]

参考资料

ECharts 自定义系列 profile - ECharts

背景

希望将 ECharts 自定义系列官方提供的 profile 图表,横纵坐标进行转换。

实现效果

image.png

关键点

series-custom.encode

encode 的作用是映射

简单的说,就是从一个二维数组中,选择需要映射那几列数据到图表中。本例中,encode 从 data.value 中映射数据。

option = {
    series: [{
        encode: {
            x: 0,
            y: [1, 2]
        },
        data: data
};

数据映射,有两层意思。

为什么说被选中的数据映射到画布上

画布的尺寸是有限的,也是是随界面布局的变化,时时相对发生变化。

图形(柱状图,折线图,饼图等等)在画布上的比例(相对尺寸)是一定的,那么一个具体的数值,在展现在图形上时,就需要按照一定的比例进行映射。

以本例为例,

画布大概只有 400*600 px

x 轴,只有3个数据 (0,1,2)
y 轴,上的数据很多,是基于时间戳用随机数计算出来的(例如:1510975537362),科学计数法基本上都在 10e12 这个范围。

显然,不可能直接把数值 转化为像素,因此就需要知道 x 和 y 轴的 最大值 和
最小值 然后把每一个具体的值映射为屏幕中的像素值。

上面 encode 中,x 只选择 data.value 中的第一列,也就是范围 0-2;y 轴选择 data.value 中的第二、三列(即开始时间和结束时间范围)

在数值到画布坐标映射时,调用 api.coord([x, y]) 这个方法实现。本例中详见 series-custom.renderItem 的说明

data 的结构

本例中,data 是由 echarts.util.each(categories, function (category, index) 生成的。data 的完整结构如下:

data.push({
    name: typeItem.name,
    value: [
        index,
        baseTime,
        baseTime += duration,
        duration
    ],
    itemStyle: {
        normal: {
            color: typeItem.color
        }
    }

series-custom.xAxis (series-custom.yAxis)

xAxis 和 yAxis 的作用是绘制坐标轴。

在转置的时候,坐标轴需要配套转置。

series-custom.renderItem

renderItem 是数据映射过程中的关键,其作用好比 excel 中的数据透视表。不同的是,renderItem 需要把图形是什么样子的,定义清楚。

api.coord([x, y])

在本例中,我们需要对坐标轴进行转置,因此,在一开始的时候,修改了 series-custom.encode 中的映射行为。坐标轴对应的数据发生了修改,因此,在映射具体图形坐标的时候,需要配套修改。

var start = api.coord([categoryIndex, api.value(1)]);
var end = api.coord([categoryIndex, api.value(2)]);

api.size([x, y])

这个方法用来获取一组坐标在画布中的坐标轴上对应的长度。这就好比获取地图比例尺的长度。返回值为一个数组,第一个元素对应x轴,第二个元素对应y轴

本例中,我们想知道转置以后,x轴一个单位的长度。

var width = api.size([1, 1])[0] * 0.6;

源码

var data = [];
var dataCount = 10;
var startTime = +new Date();
var categories = ['categoryA', 'categoryB', 'categoryC'];
var types = [
    {name: 'JS Heap', color: '#7b9ce1'},
    {name: 'Documents', color: '#bd6d6c'},
    {name: 'Nodes', color: '#75d874'},
    {name: 'Listeners', color: '#e0bc78'},
    {name: 'GPU Memory', color: '#dc77dc'},
    {name: 'GPU', color: '#72b362'}
];

// Generate mock data
echarts.util.each(categories, function (category, index) {
    var baseTime = startTime;
    for (var i = 0; i < dataCount; i++) {
        var typeItem = types[Math.round(Math.random() * (types.length - 1))];
        var duration = Math.round(Math.random() * 10000);
        data.push({
            name: typeItem.name,
            value: [
                index,
                baseTime,
                baseTime += duration,
                duration
            ],
            itemStyle: {
                normal: {
                    color: typeItem.color
                }
            }
        });
        baseTime += Math.round(Math.random() * 6000);
    }
});

function renderItem(params, api) {
    var categoryIndex = api.value(0);
    var start = api.coord([categoryIndex, api.value(1)]);
    var end = api.coord([categoryIndex, api.value(2)]);
    
    var width = api.size([1, 1])[0] * 0.6;
    var height = end[1] - start[1];
    var x = start[0] - width / 2;
    var y = start[1];

    return {
        type: 'rect',
        shape: {
            x: x,
            y: y,
            width: width,
            height: height
        },
        style: api.style()
    };
}


option = {
    tooltip: {
        formatter: function (params) {
            return params.marker + params.name + ': ' + params.value[3] + ' ms';
        }
    },
    title: {
        text: 'Profile',
        left: 'center'
    },
    legend: {
        data: ['bar', 'error']
    },
    dataZoom: [{
        type: 'slider',
        filterMode: 'weakFilter',
        showDataShadow: false,
        top: 400,
        height: 10,
        borderColor: 'transparent',
        backgroundColor: '#e2e2e2',
        handleIcon: 'M10.7,11.9H9.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4h1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7v-1.2h6.6z M13.3,22H6.7v-1.2h6.6z M13.3,19.6H6.7v-1.2h6.6z', // jshint ignore:line
        handleSize: 20,
        handleStyle: {
            shadowBlur: 6,
            shadowOffsetX: 1,
            shadowOffsetY: 2,
            shadowColor: '#aaa'
        },
        labelFormatter: ''
    }, {
        type: 'inside',
        filterMode: 'weakFilter'
    }],
    grid: {
        height:500
    },
    yAxis: {
        min: startTime,
        scale: true,
        axisLabel: {
            formatter: function (val) {
                return Math.max(0, val - startTime) + ' ms';
            }
        }
    },
    xAxis: {
        data: categories
    },
    series: [{
        type: 'custom',
        renderItem: renderItem,
        itemStyle: {
            normal: {
                opacity: 0.8
            }
        },
        encode: {
            x: 0,
            y: [1, 2]
        },
        data: data
    }]
};
上一篇下一篇

猜你喜欢

热点阅读