This is an automated email from the ASF dual-hosted git repository.
shenyi pushed a commit to branch label-enhancement
in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git
The following commit(s) were added to refs/heads/label-enhancement by this push:
new 5239e3c feat: using state for all user interactions.
5239e3c is described below
commit 5239e3cf3b732255fdfc793d393c76262c0462b0
Author: pissang <[email protected]>
AuthorDate: Thu Apr 30 17:32:13 2020 +0800
feat: using state for all user interactions.
---
src/chart/helper/Symbol.ts | 57 +++++-------------
src/chart/pie/PieSeries.ts | 2 +-
src/chart/pie/PieView.ts | 142 +++++++++++++++++----------------------------
src/util/LabelManager.ts | 17 +++++-
src/util/graphic.ts | 69 +++++++++++++++-------
src/util/layout.ts | 1 +
6 files changed, 130 insertions(+), 158 deletions(-)
diff --git a/src/chart/helper/Symbol.ts b/src/chart/helper/Symbol.ts
index 33eab5d..7bb3cd5 100644
--- a/src/chart/helper/Symbol.ts
+++ b/src/chart/helper/Symbol.ts
@@ -112,19 +112,6 @@ class Symbol extends graphic.Group {
}
/**
- * Get scale(aka, current symbol size).
- * Including the change caused by animation
- */
- getScale() {
- const symbolPath = this.childAt(0);
- return [symbolPath.scaleX, symbolPath.scaleY];
- }
-
- getOriginalScale() {
- return [this._scaleX, this._scaleY];
- }
-
- /**
* Highlight symbol
*/
highlight() {
@@ -291,11 +278,20 @@ class Symbol extends graphic.Group {
this._scaleX = symbolSize[0] / 2;
this._scaleY = symbolSize[1] / 2;
- symbolPath.onStateChange = (
- hoverAnimation && seriesModel.isAnimationEnabled()
- ) ? onStateChange : null;
- graphic.enableHoverEmphasis(symbolPath, hoverItemStyle);
+ symbolPath.ensureState('emphasis').style = hoverItemStyle;
+
+ if (hoverAnimation && seriesModel.isAnimationEnabled()) {
+ const scaleEmphasisState = this.ensureState('emphasis');
+ const scale = Math.max(1.1, 3 / this._scaleY + 1);
+ scaleEmphasisState.scaleX = scale;
+ scaleEmphasisState.scaleY = scale;
+ }
+ else {
+ this.states.emphasis = null;
+ }
+
+ graphic.enableHoverEmphasis(this);
}
fadeOut(cb: () => void, opt?: {
@@ -330,33 +326,6 @@ class Symbol extends graphic.Group {
}
}
-function onStateChange(this: ECSymbol, fromState: DisplayState, toState:
DisplayState) {
- // Do not support this hover animation util some scenario required.
- // Animation can only be supported in hover layer when using
`el.incremetal`.
- if (this.incremental || this.useHoverLayer) {
- return;
- }
-
- const scale = (this.parent as Symbol).getOriginalScale();
- if (toState === 'emphasis') {
- const ratio = scale[1] / scale[0];
- const emphasisOpt = {
- scaleX: Math.max(scale[0] * 1.1, scale[0] + 3),
- scaleY: Math.max(scale[1] * 1.1, scale[1] + 3 * ratio)
- };
- // FIXME
- // modify it after support stop specified animation.
- // toState === fromState
- // ? (this.stopAnimation(), this.attr(emphasisOpt))
- this.animateTo(emphasisOpt, { duration: 400, easing: 'elasticOut' });
- }
- else if (toState === 'normal') {
- this.animateTo({
- scaleX: scale[0],
- scaleY: scale[1]
- }, { duration: 400, easing: 'elasticOut' });
- }
-}
function driftSymbol(this: ECSymbol, dx: number, dy: number) {
this.parent.drift(dx, dy);
diff --git a/src/chart/pie/PieSeries.ts b/src/chart/pie/PieSeries.ts
index f1bc70d..4e0306c 100644
--- a/src/chart/pie/PieSeries.ts
+++ b/src/chart/pie/PieSeries.ts
@@ -222,7 +222,7 @@ class PieSeriesModel extends SeriesModel<PieSeriesOption> {
// 选中时扇区偏移量
selectedOffset: 10,
// 高亮扇区偏移量
- hoverOffset: 10,
+ hoverOffset: 5,
// If use strategy to avoid label overlapping
avoidLabelOverlap: true,
diff --git a/src/chart/pie/PieView.ts b/src/chart/pie/PieView.ts
index 4383b25..8e1a9cb 100644
--- a/src/chart/pie/PieView.ts
+++ b/src/chart/pie/PieView.ts
@@ -24,11 +24,10 @@ import * as graphic from '../../util/graphic';
import ChartView from '../../view/Chart';
import GlobalModel from '../../model/Global';
import ExtensionAPI from '../../ExtensionAPI';
-import { Payload, DisplayState, ECElement, ColorString } from
'../../util/types';
+import { Payload, ColorString } from '../../util/types';
import List from '../../data/List';
import PieSeriesModel, {PieDataItemOption} from './PieSeries';
-import { Dictionary } from 'zrender/src/core/types';
-import Element from 'zrender/src/Element';
+import { ElementAnimateConfig } from 'zrender/src/Element';
function updateDataSelected(
this: PiePiece,
@@ -40,7 +39,6 @@ function updateDataSelected(
const data = seriesModel.getData();
const dataIndex = graphic.getECData(this).dataIndex;
const name = data.getName(dataIndex);
- const selectedOffset = seriesModel.get('selectedOffset');
api.dispatchAction({
type: 'pieToggleSelect',
@@ -49,67 +47,38 @@ function updateDataSelected(
seriesId: seriesModel.id
});
+ const animationCfg: ElementAnimateConfig = {
+ duration: seriesModel.get('animation') ? 200 : 0,
+ easing: 'cubicOut'
+ };
data.each(function (idx) {
- toggleItemSelected(
- data.getItemGraphicEl(idx),
- data.getItemLayout(idx),
- seriesModel.isSelected(data.getName(idx)),
- selectedOffset,
- hasAnimation
- );
+ const el = data.getItemGraphicEl(idx);
+ el.toggleState('select', seriesModel.isSelected(data.getName(idx)),
animationCfg);
});
}
-function toggleItemSelected(
- el: Element,
- layout: Dictionary<any>, // FIXME:TS make a type.
- isSelected: boolean,
- selectedOffset: number,
- hasAnimation: boolean
-): void {
- const midAngle = (layout.startAngle + layout.endAngle) / 2;
-
- const dx = Math.cos(midAngle);
- const dy = Math.sin(midAngle);
-
- const offset = isSelected ? selectedOffset : 0;
- const obj = {
- x: dx * offset,
- y: dy * offset
- };
-
- hasAnimation
- // animateTo will stop revious animation like update transition
- ? el.animate()
- .when(200, obj)
- .start('bounceOut')
- : el.attr(obj);
-}
-
/**
* Piece of pie including Sector, Label, LabelLine
*/
-class PiePiece extends graphic.Group {
+class PiePiece extends graphic.Sector {
constructor(data: List, idx: number) {
super();
- const sector = new graphic.Sector({
- z2: 2
- });
+ this.z2 = 2;
const polyline = new graphic.Polyline();
const text = new graphic.Text();
- this.add(sector);
- this.add(polyline);
- sector.setTextContent(text);
+ this.setTextGuideLine(polyline);
+
+ this.setTextContent(text);
this.updateData(data, idx, true);
}
updateData(data: List, idx: number, firstCreate?: boolean): void {
- const sector = this.childAt(0) as graphic.Sector;
+ const sector = this;
const seriesModel = data.hostModel as PieSeriesModel;
const itemModel = data.getItemModel<PieDataItemOption>(idx);
@@ -161,53 +130,50 @@ class PiePiece extends graphic.Group {
const sectorEmphasisState = sector.ensureState('emphasis');
sectorEmphasisState.style = itemModel.getModel(['emphasis',
'itemStyle']).getItemStyle();
+ const sectorSelectState = sector.ensureState('select');
+ const midAngle = (layout.startAngle + layout.endAngle) / 2;
+ const offset = seriesModel.get('selectedOffset');
+ const dx = Math.cos(midAngle) * offset;
+ const dy = Math.sin(midAngle) * offset;
+ sectorSelectState.x = dx;
+ sectorSelectState.y = dy;
+
+
+ sector.toggleState('select',
seriesModel.isSelected(data.getName(idx)), {
+ duration: seriesModel.get('animation') ? 200 : 0,
+ easing: 'cubicOut'
+ });
+
const cursorStyle = itemModel.getShallow('cursor');
cursorStyle && sector.attr('cursor', cursorStyle);
- // Toggle selected
- toggleItemSelected(
- this,
- data.getItemLayout(idx),
- seriesModel.isSelected(data.getName(idx)),
- seriesModel.get('selectedOffset'),
- seriesModel.get('animation')
- );
-
// Label and text animation should be applied only for transition type
animation when update
const withAnimation = !firstCreate && animationTypeUpdate ===
'transition';
this._updateLabel(data, idx, withAnimation);
- (this as ECElement).onStateChange = (itemModel.get('hoverAnimation')
&& seriesModel.isAnimationEnabled())
- ? function (fromState: DisplayState, toState: DisplayState): void {
- if (toState === 'emphasis') {
-
- // Sector may has animation of updating data. Force to
move to the last frame
- // Or it may stopped on the wrong shape
- sector.stopAnimation(true);
- sector.animateTo({
- shape: {
- r: layout.r + seriesModel.get('hoverOffset')
- }
- }, { duration: 300, easing: 'elasticOut' });
- }
- else {
- sector.stopAnimation(true);
- sector.animateTo({
- shape: {
- r: layout.r
- }
- }, { duration: 300, easing: 'elasticOut' });
- }
- }
- : null;
+ const emphasisState = sector.ensureState('emphasis');
+ emphasisState.shape = {
+ r: layout.r + itemModel.get('hoverAnimation') // TODO: Change a
name.
+ ? seriesModel.get('hoverOffset') : 0
+ };
+
+ const labelLine = sector.getTextGuideLine();
+ const labelText = sector.getTextContent();
+
+ const labelLineSelectState = labelLine.ensureState('select');
+ const labelTextSelectState = labelText.ensureState('select');
+ labelLineSelectState.x = dx;
+ labelLineSelectState.y = dy;
+ labelTextSelectState.x = dx;
+ labelTextSelectState.y = dy;
graphic.enableHoverEmphasis(this);
}
private _updateLabel(data: List, idx: number, withAnimation: boolean):
void {
- const sector = this.childAt(0);
- const labelLine = this.childAt(1) as graphic.Polyline;
- const labelText = sector.getTextContent() as graphic.Text;
+ const sector = this;
+ const labelLine = sector.getTextGuideLine();
+ const labelText = sector.getTextContent();
const seriesModel = data.hostModel;
const itemModel = data.getItemModel<PieDataItemOption>(idx);
@@ -358,11 +324,9 @@ class PieView extends ChartView {
.add(function (idx) {
const piePiece = new PiePiece(data, idx);
// Default expansion animation
- if (isFirstRender && animationType !== 'scale') {
- piePiece.eachChild(function (child) {
- child.stopAnimation(true);
- });
- }
+ // if (isFirstRender && animationType !== 'scale') {
+ // piePiece.stopAnimation(true);
+ // }
selectedMode && piePiece.on('click', onSectorClick);
@@ -375,11 +339,9 @@ class PieView extends ChartView {
graphic.clearStates(piePiece);
- if (!isFirstRender && animationTypeUpdate !== 'transition') {
- piePiece.eachChild(function (child) {
- child.stopAnimation(true);
- });
- }
+ // if (!isFirstRender && animationTypeUpdate !== 'transition')
{
+ // piePiece.stopAnimation(true);
+ // }
piePiece.updateData(data, newIdx);
diff --git a/src/util/LabelManager.ts b/src/util/LabelManager.ts
index 23e09b7..48c6988 100644
--- a/src/util/LabelManager.ts
+++ b/src/util/LabelManager.ts
@@ -128,11 +128,20 @@ class LabelManager {
const hostEl = label.__hostTarget;
const textConfig = hostEl.textConfig || {};
+ // TODO: If label is in other state.
const labelTransform = label.getComputedTransform();
const labelRect = label.getBoundingRect().plain();
BoundingRect.applyTransform(labelRect, labelRect, labelTransform);
- dummyTransformable.setLocalTransform(labelTransform);
+ if (labelTransform) {
+ dummyTransformable.setLocalTransform(labelTransform);
+ }
+ else {
+ // Identity transform.
+ dummyTransformable.x = dummyTransformable.y =
dummyTransformable.rotation =
+ dummyTransformable.originX = dummyTransformable.originY = 0;
+ dummyTransformable.scaleX = dummyTransformable.scaleY = 1;
+ }
const host = label.__hostTarget;
let hostRect;
@@ -224,6 +233,8 @@ class LabelManager {
layoutOption = layoutOption || {};
if (hostEl) {
hostEl.setTextConfig({
+ // Force to set local false.
+ local: false,
// Ignore position and rotation config on the host el if x
or y is changed.
position: (layoutOption.x != null || layoutOption.y !=
null)
? null : defaultLabelAttr.attachedPos,
@@ -347,6 +358,10 @@ class LabelManager {
}
}
}
+
+ updateLabelGuidLine() {
+
+ }
}
diff --git a/src/util/graphic.ts b/src/util/graphic.ts
index 69775eb..c3e79c9 100644
--- a/src/util/graphic.ts
+++ b/src/util/graphic.ts
@@ -45,7 +45,7 @@ import IncrementalDisplayable from
'zrender/src/graphic/IncrementalDisplayable';
import * as subPixelOptimizeUtil from
'zrender/src/graphic/helper/subPixelOptimize';
import { Dictionary } from 'zrender/src/core/types';
import LRU from 'zrender/src/core/LRU';
-import Displayable, { DisplayableProps } from
'zrender/src/graphic/Displayable';
+import Displayable, { DisplayableProps, DisplayableState } from
'zrender/src/graphic/Displayable';
import { PatternObject } from 'zrender/src/graphic/Pattern';
import { GradientObject } from 'zrender/src/graphic/Gradient';
import Element, { ElementEvent, ElementTextConfig } from 'zrender/src/Element';
@@ -377,23 +377,12 @@ function singleEnterEmphasis(el: Element) {
if (!el.states.emphasis) {
return;
}
- const disp = el as Displayable;
- const emphasisStyle = disp.states.emphasis.style;
- const currentFill = disp.style && disp.style.fill;
- const currentStroke = disp.style && disp.style.stroke;
-
- el.useState('emphasis');
-
- if (emphasisStyle && (currentFill || currentStroke)) {
- if (!hasFillOrStroke(emphasisStyle.fill)) {
- disp.style.fill = liftColor(currentFill);
- }
- if (!hasFillOrStroke(emphasisStyle.stroke)) {
- disp.style.stroke = liftColor(currentStroke);
- }
- disp.z2 += Z2_EMPHASIS_LIFT;
- }
+ el.useState('emphasis', true, {
+ duration: 300,
+ // TODO Configuration
+ easing: 'cubicOut'
+ });
const textContent = el.getTextContent();
if (textContent) {
@@ -403,8 +392,10 @@ function singleEnterEmphasis(el: Element) {
}
-function singleEnterNormal(el: Element) {
- el.clearStates();
+function singleLeaveEmphasis(el: Element) {
+ el.removeState('emphasis', {
+ duration: 300
+ });
(el as ExtendedElement).__highlighted = false;
}
@@ -452,6 +443,38 @@ export function clearStates(el: Element) {
}
}
+function elementStateProxy(this: Displayable, stateName: string):
DisplayableState {
+ let state = this.states[stateName];
+ if (stateName === 'emphasis' && this.style) {
+ const currentFill = this.style.fill;
+ const currentStroke = this.style.stroke;
+ if (currentFill || currentStroke) {
+ state = state || {};
+ // Apply default color lift
+ let emphasisStyle = state.style || {};
+ let cloned = false;
+ if (!hasFillOrStroke(emphasisStyle.fill)) {
+ cloned = true;
+ // Not modify the original value.
+ state = extend({}, state);
+ emphasisStyle = extend({}, emphasisStyle);
+ emphasisStyle.fill = liftColor(currentFill);
+ }
+ if (!hasFillOrStroke(emphasisStyle.stroke)) {
+ if (!cloned) {
+ state = extend({}, state);
+ emphasisStyle = extend({}, emphasisStyle);
+ }
+ emphasisStyle.stroke = liftColor(currentStroke);
+ }
+
+ state.style = emphasisStyle;
+ }
+ }
+
+ return state;
+}
+
/**
* Set hover style (namely "emphasis style") of element.
* @param el Should not be `zrender/graphic/Group`.
@@ -462,6 +485,8 @@ export function enableElementHoverEmphasis(el: Displayable,
hoverStl?: ZRStylePr
emphasisState.style = hoverStl;
}
+ el.stateProxy = elementStateProxy;
+
// FIXME
// It is not completely right to save "normal"/"emphasis" flag on elements.
// It probably should be saved on `data` of series. Consider the cases:
@@ -469,7 +494,7 @@ export function enableElementHoverEmphasis(el: Displayable,
hoverStl?: ZRStylePr
// again by dataZoom.
// (2) call `setOption` and replace elements totally when they are
highlighted.
if ((el as ExtendedDisplayable).__highlighted) {
- singleEnterNormal(el);
+ // singleLeaveEmphasis(el);
singleEnterEmphasis(el);
}
}
@@ -485,7 +510,7 @@ export function leaveEmphasisWhenMouseOut(el: Element, e:
ElementEvent) {
!shouldSilent(el, e)
// "emphasis" event highlight has higher priority than mouse highlight.
&& !(el as ExtendedElement).__highByOuter
- && traverseUpdateState((el as ExtendedElement), singleEnterNormal);
+ && traverseUpdateState((el as ExtendedElement), singleLeaveEmphasis);
}
export function enterEmphasis(el: Element, highlightDigit?: number) {
@@ -495,7 +520,7 @@ export function enterEmphasis(el: Element, highlightDigit?:
number) {
export function leaveEmphasis(el: Element, highlightDigit?: number) {
!((el as ExtendedElement).__highByOuter &= ~(1 << (highlightDigit || 0)))
- && traverseUpdateState((el as ExtendedElement), singleEnterNormal);
+ && traverseUpdateState((el as ExtendedElement), singleLeaveEmphasis);
}
function shouldSilent(el: Element, e: ElementEvent) {
diff --git a/src/util/layout.ts b/src/util/layout.ts
index c18e990..31e0fac 100644
--- a/src/util/layout.ts
+++ b/src/util/layout.ts
@@ -116,6 +116,7 @@ function boxLayout(
child.x = x;
child.y = y;
+ child.markRedraw();
orient === 'horizontal'
? (x = nextX + gap)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]