共计 4830 个字符,预计需要花费 13 分钟才能阅读完成。
自定义系列(custom series),是一种系列的类型。它把绘制图形元素这一步留给开发者去做,从而开发者能在坐标系中自由绘制出自己需要的图表。利用好自定义系列,你会觉得 Echarts 无所不能了。
简介
自定义系列主要是靠 renderItem 函数来实现,如下:
var option = { | |
..., | |
series: [{ | |
type: 'custom', | |
renderItem: function (params, api) {// ...}, | |
data: data | |
}] | |
} |
这个 renderItem 函数的职责,就是返回一个(或者一组)图形元素定义,图形元素定义 中包括图形元素的类型、位置、尺寸、样式等。echarts 会根据这些 图形元素定义 来渲染出图形元素。
var option = { | |
..., | |
series: [{ | |
type: 'custom', | |
renderItem: function (params, api) { | |
// 对于 data 中的每个 dataItem,都会调用这个 renderItem 函数。//(但是注意,并不一定是按照 data 的顺序调用)// 这里进行一些处理,例如,坐标转换。// 这里使用 api.value(0) 取出当前 dataItem 中第一个维度的数值。var categoryIndex = api.value(0); | |
// 这里使用 api.coord(...) 将数值在当前坐标系中转换成为屏幕上的点的像素值。var startPoint = api.coord([api.value(1), categoryIndex]); | |
var endPoint = api.coord([api.value(2), categoryIndex]); | |
// 这里使用 api.size(...) 获得 Y 轴上数值范围为 1 的一段所对应的像素长度。var height = api.size([0, 1])[1] * 0.6; | |
// shape 属性描述了这个矩形的像素位置和大小。// 其中特殊得用到了 echarts.graphic.clipRectByRect,意思是,// 如果矩形超出了当前坐标系的包围盒,则剪裁这个矩形。// 如果矩形完全被剪掉,会返回 undefined. | |
var rectShape = echarts.graphic.clipRectByRect({ | |
// 矩形的位置和大小。x: startPoint[0], | |
y: startPoint[1] - height / 2, | |
width: endPoint[0] - startPoint[0], | |
height: height | |
}, { | |
// 当前坐标系的包围盒。x: params.coordSys.x, | |
y: params.coordSys.y, | |
width: params.coordSys.width, | |
height: params.coordSys.height | |
}); | |
// 这里返回为这个 dataItem 构建的图形元素定义。return rectShape && { | |
// 表示这个图形元素是矩形。还可以是 'circle', 'sector', 'polygon' 等等。type: 'rect', | |
shape: rectShape, | |
// 用 api.style(...) 得到默认的样式设置。这个样式设置包含了 | |
// option 中 itemStyle 的配置和视觉映射得到的颜色。style: api.style()}; | |
}, | |
data: [[12, 44, 55, 60], // 这是第一个 dataItem | |
[53, 31, 21, 56], // 这是第二个 dataItem | |
[71, 33, 10, 20], // 这是第三个 dataItem | |
... | |
] | |
}] | |
} |
renderItem 函数提供了两个参数:
params:包含了当前数据信息(如 seriesIndex、dataIndex 等等)和坐标系的信息(如坐标系包围盒的位置和尺寸)。
api: 是一些开发者可调用的方法集合(如 api.value()、api.coord())。
实例一:echarts.graphic.clipRectByRect
介绍完成后,我们来看一个实例。
https://gallery.echartsjs.com…
option = null; | |
var startTime = +new Date(); | |
var categories = ['categoryA', 'categoryB', 'categoryC', 'categoryD']; | |
var step = 14399285; | |
var data = [{ | |
name: 'JS Heap', | |
value: [0, 1563000480298, (1563000480298 + step)], | |
itemStyle: { | |
normal: {color: '#7b9ce1'} | |
} | |
}, { | |
name: 'Documents', | |
value: [1, 1563000484450, (1563000484450 + step - 3000000)], | |
itemStyle: { | |
normal: {color: '#bd6d6c'} | |
} | |
}, { | |
name: 'Nodes', | |
value: [2, 1563000493753, (1563000493753 + step - 5000000)], | |
itemStyle: { | |
normal: {color: '#75d874'} | |
} | |
}, { | |
name: 'Listeners', | |
value: [3, 1563000503740, (1563000503740 + step)], | |
itemStyle: { | |
normal: {color: '#e0bc78'} | |
} | |
}, { | |
name: 'GPU Memory', | |
value: [2, 1563000506369, (1563000506369 + step - 8000000)], | |
itemStyle: { | |
normal: {color: '#e0bc78'} | |
} | |
}, { | |
name: 'GPU', | |
value: [3, 1563000513841, (1563000513841 + step - 12000000)], | |
itemStyle: { | |
normal: {color: '#72b362'} | |
} | |
}] | |
function renderItem(params, api) {var categoryIndex = api.value(0); | |
var start = api.coord([api.value(1), categoryIndex]); | |
var end = api.coord([api.value(2), categoryIndex]); | |
var height = api.size([0, 1])[1] * 0.6; | |
var rectShape = echarts.graphic.clipRectByRect({x: start[0], | |
y: start[1] - height / 2, | |
width: end[0] - start[0], | |
height: height | |
}, { | |
x: params.coordSys.x, | |
y: params.coordSys.y, | |
width: params.coordSys.width, | |
height: params.coordSys.height | |
}); | |
return rectShape && { | |
type: 'rect', | |
shape: rectShape, | |
style: api.style()}; | |
} | |
option = { | |
tooltip: {formatter: function (params) {return params.marker + params.name + ':' + params.value[1] + 'ms'; | |
} | |
}, | |
title: { | |
text: 'Profile', | |
left: 'center' | |
}, | |
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:300}, | |
xAxis: [{ | |
min: startTime, | |
scale: true, | |
axisLabel: {formatter: function (val) {return Math.max(0, val - startTime) + 'ms'; | |
} | |
} | |
}], | |
yAxis: [{data: categories}], | |
series: [{ | |
type: 'custom', | |
renderItem: renderItem, | |
itemStyle: { | |
normal: {opacity: 0.8} | |
}, | |
encode: {x: [1, 2], | |
y: 0 | |
}, | |
data: data | |
}] | |
}; |
这里最重要的一个函数就是 renderItem, 其中里面的 echarts.graphic.clipRectByRect 更是其中的关键。
实例二:echarts.graphic.clipPointsByRect
echarts.graphic.clipRectByRect 输入两个矩形,返回第二个矩形截取第一个矩形的结果。
除了 echarts.graphic.clipRectByRect,还有一个 echarts.graphic.clipPointsByRect, echarts.graphic.clipPointsByRect 表示输入一组点,和一个矩形,返回被矩形截取过的点,比如 [[23, 44], [12, 15], …]
那我们再把上面的例子改善,绘制成多边形的形状。
https://gallery.echartsjs.com…
先看看效果图:
与上图不一样的就是右侧的形状,代码的不同之处也就是 renderItem
function renderItem(params, api) {var categoryIndex = api.value(0); | |
var start = api.coord([api.value(1), categoryIndex]); | |
var end = api.coord([api.value(2), categoryIndex]); | |
var height = api.size([0, 1])[1] * 0.6; | |
var width = end[0] - start[0]; | |
var x = start[0]; | |
var y = start[1] - height / 2; | |
var shape = echarts.graphic.clipPointsByRect([[x, y], | |
[x + width - 10, y], | |
[x + width, y - height / 2], | |
[x + width - 10, y - height], | |
[x, y - height] | |
], { | |
x: params.coordSys.x, | |
y: params.coordSys.y, | |
width: params.coordSys.width, | |
height: params.coordSys.height | |
}); | |
return shape && { | |
type: 'polygon', | |
shape: {points: shape}, | |
style: api.style()} | |
} |
这里的绘制就是采用 5 个坐标的 points 绘制而成的,即上面的 shape 对象,所以 echarts.graphic.clipPointsByRect 真的是什么东西都能绘制出来。