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]

Reply via email to