You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by sh...@apache.org on 2020/09/13 08:02:52 UTC
[incubator-echarts] 01/01: feat(custom): add shapeMorphing option
in renderItem returns.
This is an automated email from the ASF dual-hosted git repository.
shenyi pushed a commit to branch custom-shape-morphing
in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git
commit 69be972c5ffca252e572fbee913418a1fc811429
Author: pissang <bm...@gmail.com>
AuthorDate: Sun Sep 13 16:01:55 2020 +0800
feat(custom): add shapeMorphing option in renderItem returns.
---
src/chart/custom.ts | 42 +++++++++++++-
test/custom-hexbin.html | 143 ++++++++++++++++++++++++++++++------------------
2 files changed, 129 insertions(+), 56 deletions(-)
diff --git a/src/chart/custom.ts b/src/chart/custom.ts
index 5940580..dd60ba1 100644
--- a/src/chart/custom.ts
+++ b/src/chart/custom.ts
@@ -18,7 +18,7 @@
*/
import {
- hasOwn, assert, isString, retrieve2, retrieve3, defaults, each, keys, isArrayLike, bind
+ hasOwn, assert, isString, retrieve2, retrieve3, defaults, each, keys, isArrayLike, bind, logError, isFunction
} from 'zrender/src/core/util';
import * as graphicUtil from '../util/graphic';
import { setDefaultStateProxy, enableHoverEmphasis } from '../util/states';
@@ -80,6 +80,7 @@ import {
import Transformable from 'zrender/src/core/Transformable';
import { ItemStyleProps } from '../model/mixin/itemStyle';
import { cloneValue } from 'zrender/src/animation/Animator';
+import { morphPath } from 'zrender/src/tool/morphPath';
const inner = makeInner<{
@@ -119,6 +120,13 @@ type TransitionTransformOption = {
enterFrom?: Dictionary<unknown>;
leaveTo?: Dictionary<unknown>;
};
+type ShapeMorphingOption = {
+ /**
+ * If do shape morphing animation when type is changed.
+ * Only available on path.
+ */
+ shapeMorphing?: boolean
+};
interface CustomBaseElementOption extends Partial<Pick<
Element, TransformProps | 'silent' | 'ignore' | 'textConfig'
@@ -167,10 +175,10 @@ interface CustomGroupOption extends CustomBaseElementOption {
children: Omit<CustomElementOption, 'focus' | 'blurScope'>[];
$mergeChildren: false | 'byName' | 'byIndex';
}
-interface CustomZRPathOption extends CustomDisplayableOption {
+interface CustomZRPathOption extends CustomDisplayableOption, ShapeMorphingOption {
shape?: PathProps['shape'] & TransitionAnyOption;
}
-interface CustomSVGPathOption extends CustomDisplayableOption {
+interface CustomSVGPathOption extends CustomDisplayableOption, ShapeMorphingOption {
type: 'path';
shape?: {
// SVG Path, like 'M0,0 L0,-20 L70,-1 L70,0 Z'
@@ -1539,6 +1547,28 @@ function createOrUpdateItem(
return el;
}
+function applyShapeMorphingAnimation(oldEl: Element, el: Element, seriesModel: SeriesModel, dataIndex: number) {
+ if (!((oldEl instanceof graphicUtil.Path) && (el instanceof graphicUtil.Path))) {
+ if (__DEV__) {
+ logError('shapeMorphing can only be applied on two paths.');
+ }
+ return;
+ }
+ if (seriesModel.isAnimationEnabled()) {
+ const duration = seriesModel.get('animationDurationUpdate');
+ const delay = seriesModel.get('animationDelayUpdate');
+ const easing = seriesModel.get('animationEasingUpdate');
+ const durationNumber = isFunction(duration) ? duration(dataIndex) : duration;
+ if (durationNumber > 0) {
+ morphPath(oldEl, el, {
+ duration: durationNumber,
+ delay: isFunction(delay) ? delay(dataIndex) : delay,
+ easing: easing
+ });
+ }
+ }
+}
+
function doCreateOrUpdateEl(
el: Element,
dataIndex: number,
@@ -1553,10 +1583,12 @@ function doCreateOrUpdateEl(
}
let toBeReplacedIdx = -1;
+ let oldEl: Element;
if (el && doesElNeedRecreate(el, elOption)) {
// Should keep at the original index, otherwise "merge by index" will be incorrect.
toBeReplacedIdx = group.childrenRef().indexOf(el);
+ oldEl = el;
el = null;
}
@@ -1588,6 +1620,10 @@ function doCreateOrUpdateEl(
);
updateElNormal(el, dataIndex, elOption, elOption.style, attachedTxInfoTmp, seriesModel, isInit, false);
+ // Do shape morphing
+ if ((elOption as CustomZRPathOption).shapeMorphing && el && oldEl) {
+ applyShapeMorphingAnimation(oldEl, el, seriesModel, dataIndex);
+ }
for (let i = 0; i < STATES.length; i++) {
const stateName = STATES[i];
diff --git a/test/custom-hexbin.html b/test/custom-hexbin.html
index c9c42e2..7d69a93 100644
--- a/test/custom-hexbin.html
+++ b/test/custom-hexbin.html
@@ -38,7 +38,7 @@ under the License.
font-weight: bold;
font-size: 14px;
}
- .chart {
+ .test-chart {
height: 500px;
margin: 10px auto;
}
@@ -156,56 +156,71 @@ under the License.
return [bin.x, bin.y, bin.points.length, (made / bin.points.length * 100).toFixed(2)];
});
- function renderItemHexBin(params, api) {
- var center = api.coord([api.value(0), api.value(1)]);
- var points = [];
- var pointsBG = [];
-
- var maxViewRadius = api.size([hexagonRadiusInGeo, 0])[0];
- var minViewRadius = Math.min(maxViewRadius, 4);
- var extentMax = Math.log(Math.sqrt(hexBinResult.maxBinLen));
- var viewRadius = echarts.number.linearMap(
- Math.log(Math.sqrt(api.value(2))),
- [0, extentMax],
- [minViewRadius, maxViewRadius]
- );
-
- var angle = Math.PI / 6;
- for (var i = 0; i < 6; i++, angle += Math.PI / 3) {
- points.push([
- center[0] + viewRadius * Math.cos(angle),
- center[1] + viewRadius * Math.sin(angle)
- ]);
- pointsBG.push([
- center[0] + maxViewRadius * Math.cos(angle),
- center[1] + maxViewRadius * Math.sin(angle)
- ]);
- }
+ function createItemRenderer(type) {
+ type = type || 'polygon';
+ return function renderItemHexBin(params, api) {
+ var center = api.coord([api.value(0), api.value(1)]);
+ var points = [];
+ var pointsBG = [];
+
+ var maxViewRadius = api.size([hexagonRadiusInGeo, 0])[0];
+ var minViewRadius = Math.min(maxViewRadius, 4);
+ var extentMax = Math.log(Math.sqrt(hexBinResult.maxBinLen));
+ var viewRadius = echarts.number.linearMap(
+ Math.log(Math.sqrt(api.value(2))),
+ [0, extentMax],
+ [minViewRadius, maxViewRadius]
+ );
+
+ var angle = Math.PI / 6;
+ for (var i = 0; i < 6; i++, angle += Math.PI / 3) {
+ points.push([
+ center[0] + viewRadius * Math.cos(angle),
+ center[1] + viewRadius * Math.sin(angle)
+ ]);
+ pointsBG.push([
+ center[0] + maxViewRadius * Math.cos(angle),
+ center[1] + maxViewRadius * Math.sin(angle)
+ ]);
+ }
- return {
- type: 'group',
- children: [{
- type: 'polygon',
- shape: {
- points: points
- },
- style: {
- stroke: '#ccc',
- fill: api.visual('color'),
- lineWidth: 0
- }
- }, {
- type: 'polygon',
- shape: {
- points: pointsBG
- },
- style: {
- stroke: null,
- fill: 'rgba(0,0,0,0.5)',
- lineWidth: 0
- },
- z2: -19
- }]
+ return {
+ type: 'group',
+ children: [{
+ type,
+ shapeMorphing: true,
+ shape: type === 'polygon' ? {
+ points: points
+ } : {
+ // Circle
+ cx: center[0],
+ cy: center[1],
+ r: viewRadius
+ },
+ style: {
+ stroke: '#ccc',
+ fill: api.visual('color'),
+ lineWidth: 0
+ }
+ }, {
+ type,
+ shapeMorphing: true,
+ shape: type === 'polygon' ? {
+ points: pointsBG
+ } : {
+ // Circle
+ cx: center[0],
+ cy: center[1],
+ r: maxViewRadius
+ },
+ style: {
+ stroke: null,
+ fill: 'rgba(0,0,0,0.5)',
+ lineWidth: 0
+ },
+ z2: -19
+ }]
+ };
};
}
@@ -292,7 +307,7 @@ under the License.
type: 'custom',
coordinateSystem: 'geo',
geoIndex: 0,
- renderItem: renderItemHexBin,
+ renderItem: createItemRenderer(),
dimensions: [null, null, 'Field Goals Attempted (hexagon size)', 'Field Goal Percentage (color)'],
encode: {
tooltip: [2, 3]
@@ -308,8 +323,30 @@ under the License.
}]
};
- var width = 700;
- testHelper.createChart(echarts, 'hexagonal-binning', option, {
+ var width = 1000;
+ const myChart = testHelper.create(echarts, 'hexagonal-binning', {
+ option,
+ buttons: [{
+ text: 'Hexgon',
+ onClick: function() {
+ myChart.setOption({
+ series: [{
+ type: 'custom',
+ renderItem: createItemRenderer('polygon')
+ }]
+ });
+ }
+ }, {
+ text: 'Circle',
+ onClick: function() {
+ myChart.setOption({
+ series: [{
+ type: 'custom',
+ renderItem: createItemRenderer('circle')
+ }]
+ });
+ }
+ }],
width: width,
height: width * nbaCourt.height / nbaCourt.width
});
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org