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 2021/06/30 10:21:58 UTC

[echarts] 02/02: fix(type): provide more accurate type of custom series.

This is an automated email from the ASF dual-hosted git repository.

shenyi pushed a commit to branch enhance-morph
in repository https://gitbox.apache.org/repos/asf/echarts.git

commit 69726733df3e5a6bcf10b663dfdf99cc0afe7fbc
Author: pissang <bm...@gmail.com>
AuthorDate: Wed Jun 30 18:20:31 2021 +0800

    fix(type): provide more accurate type of custom series.
---
 src/chart/custom/CustomSeries.ts | 134 ++++++++++++++++++++++++++++-----------
 src/chart/custom/CustomView.ts   |  77 +++++++++++++---------
 src/chart/custom/prepare.ts      |   3 +-
 3 files changed, 146 insertions(+), 68 deletions(-)

diff --git a/src/chart/custom/CustomSeries.ts b/src/chart/custom/CustomSeries.ts
index 0c9d52b..c9e4d7d 100644
--- a/src/chart/custom/CustomSeries.ts
+++ b/src/chart/custom/CustomSeries.ts
@@ -20,13 +20,11 @@
 import Displayable from 'zrender/src/graphic/Displayable';
 import { ImageStyleProps } from 'zrender/src/graphic/Image';
 import { PathProps, PathStyleProps } from 'zrender/src/graphic/Path';
-import { PatternObject } from 'zrender/src/graphic/Pattern';
 import { ZRenderType } from 'zrender/src/zrender';
 import { BarGridLayoutOptionForCustomSeries, BarGridLayoutResult } from '../../layout/barGrid';
 import {
     BlurScope,
     CallbackDataParams,
-    DecalObject,
     Dictionary,
     DimensionLoose,
     ItemStyleOption,
@@ -52,6 +50,19 @@ import createListFromArray from '../helper/createListFromArray';
 import { makeInner } from '../../util/model';
 import { CoordinateSystem } from '../../coord/CoordinateSystem';
 import SeriesModel from '../../model/Series';
+import {
+    Arc,
+    BezierCurve,
+    Circle,
+    CompoundPath,
+    Ellipse,
+    Line,
+    Polygon,
+    Polyline,
+    Rect,
+    Ring,
+    Sector
+} from '../../util/graphic';
 
 
 export interface LooseElementProps extends ElementProps {
@@ -111,16 +122,21 @@ type ShapeMorphingOption = {
     morph?: boolean
 };
 
-export interface CustomDuringAPI {
+export interface CustomBaseDuringAPI {
     // Usually other props do not need to be changed in animation during.
-    setTransform(key: TransformProp, val: unknown): CustomDuringAPI
-    getTransform(key: TransformProp): unknown;
-    setShape(key: string, val: unknown): CustomDuringAPI;
-    getShape(key: string): unknown;
-    setStyle(key: string, val: unknown): CustomDuringAPI
-    getStyle(key: string): unknown;
-    setExtra(key: string, val: unknown): CustomDuringAPI
+    setTransform(key: TransformProp, val: number): this
+    getTransform(key: TransformProp): number;
+    setExtra(key: string, val: unknown): this
     getExtra(key: string): unknown
+}
+export interface CustomDuringAPI<
+    StyleOpt extends object = object,
+    ShapeOpt extends object = object
+> extends CustomBaseDuringAPI {
+    setShape<T extends keyof ShapeOpt>(key: T, val: ShapeOpt[T]): this;
+    getShape<T extends keyof ShapeOpt>(key: T): ShapeOpt[T];
+    setStyle<T extends keyof StyleOpt>(key: T, val: StyleOpt[T]): this
+    getStyle<T extends keyof StyleOpt>(key: T): StyleOpt[T];
 };
 
 
@@ -136,11 +152,11 @@ export interface CustomBaseElementOption extends Partial<Pick<
     // `false` means remove the textContent.
     textContent?: CustomTextOption | false;
     // `false` means remove the clipPath
-    clipPath?: CustomZRPathOption | false;
+    clipPath?: CustomBaseZRPathOption | false;
     // `extra` can be set in any el option for custom prop for annimation duration.
-    extra?: TransitionAnyOption;
+    extra?: Dictionary<any> & TransitionAnyOption;
     // updateDuringAnimation
-    during?(params: CustomDuringAPI): void;
+    during?(params: CustomBaseDuringAPI): void;
 
     focus?: 'none' | 'self' | 'series' | ArrayLike<number>
     blurScope?: BlurScope
@@ -149,6 +165,10 @@ export interface CustomDisplayableOption extends CustomBaseElementOption, Partia
     Displayable, 'zlevel' | 'z' | 'z2' | 'invisible'
 >> {
     style?: ZRStyleProps & TransitionAnyOption;
+    during?(params: CustomDuringAPI): void;
+    /**
+     * @deprecated
+     */
     // `false` means remove emphasis trigger.
     styleEmphasis?: ZRStyleProps | false;
     emphasis?: CustomDisplayableOptionOnState;
@@ -160,6 +180,9 @@ export interface CustomDisplayableOptionOnState extends Partial<Pick<
 >> {
     // `false` means remove emphasis trigger.
     style?: (ZRStyleProps & TransitionAnyOption) | false;
+
+
+    during?(params: CustomDuringAPI): void;
 }
 export interface CustomGroupOption extends CustomBaseElementOption {
     type: 'group';
@@ -167,32 +190,55 @@ export interface CustomGroupOption extends CustomBaseElementOption {
     height?: number;
     // @deprecated
     diffChildrenByName?: boolean;
-    // Can only set focus, blur on the root element.
-    children: Omit<CustomElementOption, 'focus' | 'blurScope'>[];
+    children: CustomChildElementOption[];
     $mergeChildren: false | 'byName' | 'byIndex';
 }
-export interface CustomZRPathOption extends CustomDisplayableOption, ShapeMorphingOption {
+export interface CustomBaseZRPathOption<T extends PathProps['shape'] = PathProps['shape']>
+    extends CustomDisplayableOption, ShapeMorphingOption {
     autoBatch?: boolean;
-    shape?: PathProps['shape'] & TransitionAnyOption;
-    style?: CustomDisplayableOption['style'] & {
-        decal?: DecalObject;
-        // Only internal usage. Any user specified value will be overwritten.
-        __decalPattern?: PatternObject;
-    };
+    shape?: T & TransitionAnyOption;
+    style?: PathProps['style']
+    during?(params: CustomDuringAPI<PathStyleProps, T>): void;
+}
+
+interface BuiltinShapes {
+    'circle': Circle['shape']
+    'rect': Rect['shape']
+    'sector': Sector['shape']
+    'poygon': Polygon['shape']
+    'polyline': Polyline['shape']
+    'line': Line['shape']
+    'arc': Arc['shape']
+    'bezierCurve': BezierCurve['shape']
+    'ring': Ring['shape']
+    'ellipse': Ellipse['shape'],
+    'compoundPath': CompoundPath['shape']
+}
+
+export interface CustomBuitinPathOption<T extends keyof BuiltinShapes>
+    extends CustomBaseZRPathOption<BuiltinShapes[T]> {
+    type: T
 }
-export interface CustomSVGPathOption extends CustomDisplayableOption, ShapeMorphingOption {
+export interface CustomSVGPathOption extends CustomBaseZRPathOption<CustomSVGPathShapeOption> {
     type: 'path';
-    shape?: {
-        // SVG Path, like 'M0,0 L0,-20 L70,-1 L70,0 Z'
-        pathData?: string;
-        // "d" is the alias of `pathData` follows the SVG convention.
-        d?: string;
-        layout?: 'center' | 'cover';
-        x?: number;
-        y?: number;
-        width?: number;
-        height?: number;
-    } & TransitionAnyOption;
+}
+
+type CreateCustomBuitinPathOption<T extends keyof BuiltinShapes> = T extends any
+    ? CustomBuitinPathOption<T> : never;
+
+export type CustomPathOption = CreateCustomBuitinPathOption<keyof BuiltinShapes>
+    | CustomSVGPathOption;
+
+interface CustomSVGPathShapeOption {
+    // SVG Path, like 'M0,0 L0,-20 L70,-1 L70,0 Z'
+    pathData?: string;
+    // "d" is the alias of `pathData` follows the SVG convention.
+    d?: string;
+    layout?: 'center' | 'cover';
+    x?: number;
+    y?: number;
+    width?: number;
+    height?: number;
 }
 export interface CustomImageOption extends CustomDisplayableOption {
     type: 'image';
@@ -207,8 +253,17 @@ export interface CustomImageOptionOnState extends CustomDisplayableOptionOnState
 export interface CustomTextOption extends CustomDisplayableOption {
     type: 'text';
 }
-export type CustomElementOption = CustomZRPathOption | CustomSVGPathOption | CustomImageOption | CustomTextOption;
-export type CustomElementOptionOnState = CustomDisplayableOptionOnState | CustomImageOptionOnState;
+
+export type CustomElementOption = CustomPathOption
+    | CustomImageOption
+    | CustomTextOption
+    | CustomGroupOption;
+
+// Can only set focus, blur on the root element.
+export type CustomChildElementOption = Omit<CustomElementOption, 'focus' | 'blurScope'>;
+
+export type CustomElementOptionOnState = CustomDisplayableOptionOnState
+    | CustomImageOptionOnState;
 
 export interface CustomSeriesRenderItemAPI extends
         CustomSeriesRenderItemCoordinateSystemAPI {
@@ -253,12 +308,17 @@ export type WrapEncodeDefRet = Dictionary<number[]>;
 
 export interface CustomSeriesRenderItemParams {
     context: Dictionary<unknown>;
+    dataIndex: number;
     seriesId: string;
     seriesName: string;
     seriesIndex: number;
     coordSys: CustomSeriesRenderItemParamsCoordSys;
-    dataInsideLength: number;
     encode: WrapEncodeDefRet;
+
+    dataIndexInside: number;
+    dataInsideLength: number;
+
+    actionType?: string;
 }
 type CustomSeriesRenderItem = (
     params: CustomSeriesRenderItemParams,
diff --git a/src/chart/custom/CustomView.ts b/src/chart/custom/CustomView.ts
index ce5713a..44bc7ad 100644
--- a/src/chart/custom/CustomView.ts
+++ b/src/chart/custom/CustomView.ts
@@ -78,7 +78,7 @@ import CustomSeriesModel, {
     CustomElementOption,
     CustomElementOptionOnState,
     CustomSVGPathOption,
-    CustomZRPathOption,
+    CustomBaseZRPathOption,
     CustomDisplayableOption,
     CustomSeriesRenderItemAPI,
     CustomSeriesRenderItemParams,
@@ -91,7 +91,8 @@ import CustomSeriesModel, {
     NON_STYLE_VISUAL_PROPS,
     customInnerStore,
     LooseElementProps,
-    PrepareCustomInfo
+    PrepareCustomInfo,
+    CustomPathOption
 } from './CustomSeries';
 import {
     prepareShapeOrExtraAllPropsFinal,
@@ -100,6 +101,7 @@ import {
     prepareTransformAllPropsFinal,
     prepareTransformTransitionFrom
 } from './prepare';
+import { PatternObject } from 'zrender/src/graphic/Pattern';
 
 const transformPropNamesStr = keys(TRANSFORM_PROPS).join(', ');
 
@@ -363,6 +365,7 @@ function createEl(elOption: CustomElementOption): Element {
     return el;
 }
 
+
 /**
  * ----------------------------------------------------------
  * [STRATEGY_MERGE] Merge properties or erase all properties:
@@ -415,6 +418,11 @@ function createEl(elOption: CustomElementOption): Element {
  *
  * @return if `isMorphTo`, return `allPropsFinal`.
  */
+
+interface InnerCustomZRPathOptionStyle extends PathStyleProps {
+    __decalPattern: PatternObject
+}
+
 function updateElNormal(
     // Can be null/undefined
     api: ExtensionAPI,
@@ -435,7 +443,7 @@ function updateElNormal(
     }
 
     // Do some normalization on style.
-    const styleOpt = elOption && elOption.style;
+    const styleOpt = elOption && (elOption as CustomDisplayableOption).style;
 
     if (styleOpt) {
         if (el.type === 'text') {
@@ -450,13 +458,13 @@ function updateElNormal(
         }
 
         let decalPattern;
-        const decalObj = isPath(el) ? (styleOpt as CustomZRPathOption['style']).decal : null;
+        const decalObj = isPath(el) ? (styleOpt as CustomBaseZRPathOption['style']).decal : null;
         if (api && decalObj) {
             (decalObj as InnerDecalObject).dirty = true;
             decalPattern = createOrUpdatePatternFromDecal(decalObj, api);
         }
         // Always overwrite in case user specify this prop.
-        (styleOpt as CustomZRPathOption['style']).__decalPattern = decalPattern;
+        (styleOpt as InnerCustomZRPathOptionStyle).__decalPattern = decalPattern;
     }
 
     // Save the meta info for further morphing. Like apply on the sub morphing elements.
@@ -488,10 +496,10 @@ function applyMiscProps(
     hasOwn(elOption, 'silent') && (el.silent = elOption.silent);
     hasOwn(elOption, 'ignore') && (el.ignore = elOption.ignore);
     if (isDisplayable(el)) {
-        hasOwn(elOption, 'invisible') && (el.invisible = elOption.invisible);
+        hasOwn(elOption, 'invisible') && (el.invisible = (elOption as CustomDisplayableOption).invisible);
     }
     if (isPath(el)) {
-        hasOwn(elOption, 'autoBatch') && (el.autoBatch = (elOption as CustomZRPathOption).autoBatch);
+        hasOwn(elOption, 'autoBatch') && (el.autoBatch = (elOption as CustomBaseZRPathOption).autoBatch);
     }
 
     if (!isTextContent) {
@@ -516,7 +524,7 @@ function applyPropsDirectly(
         // Good for performance but bad for compatibility control.
         elDisplayable.useStyle(styleOpt);
 
-        const decalPattern = (styleOpt as CustomZRPathOption['style']).__decalPattern;
+        const decalPattern = (styleOpt as InnerCustomZRPathOptionStyle).__decalPattern;
         if (decalPattern) {
             elDisplayable.style.decal = decalPattern;
         }
@@ -598,13 +606,13 @@ const customDuringAPI: CustomDuringAPI = {
         tmpDuringScope.el[key] = val as number;
         return this;
     },
-    getTransform(key: TransformProp): unknown {
+    getTransform(key: TransformProp): number {
         if (__DEV__) {
             assert(hasOwn(TRANSFORM_PROPS, key), 'Only ' + transformPropNamesStr + ' available in `getTransform`.');
         }
         return tmpDuringScope.el[key];
     },
-    setShape(key: string, val: unknown) {
+    setShape(key: any, val: unknown) {
         if (__DEV__) {
             assertNotReserved(key);
         }
@@ -614,7 +622,7 @@ const customDuringAPI: CustomDuringAPI = {
         tmpDuringScope.isShapeDirty = true;
         return this;
     },
-    getShape(key: string): unknown {
+    getShape(key: any): any {
         if (__DEV__) {
             assertNotReserved(key);
         }
@@ -623,7 +631,7 @@ const customDuringAPI: CustomDuringAPI = {
             return shape[key];
         }
     },
-    setStyle(key: string, val: unknown) {
+    setStyle(key: any, val: unknown) {
         if (__DEV__) {
             assertNotReserved(key);
         }
@@ -639,7 +647,7 @@ const customDuringAPI: CustomDuringAPI = {
         }
         return this;
     },
-    getStyle(key: string): unknown {
+    getStyle(key: any): any {
         if (__DEV__) {
             assertNotReserved(key);
         }
@@ -648,7 +656,7 @@ const customDuringAPI: CustomDuringAPI = {
             return style[key];
         }
     },
-    setExtra(key: string, val: unknown) {
+    setExtra(key: any, val: unknown) {
         if (__DEV__) {
             assertNotReserved(key);
         }
@@ -785,7 +793,7 @@ function updateZ(
     elDisplayable.z = currentZ;
     elDisplayable.zlevel = currentZLevel;
     // z2 must not be null/undefined, otherwise sort error may occur.
-    const optZ2 = elOption.z2;
+    const optZ2 = (elOption as CustomDisplayableOption).z2;
     optZ2 != null && (elDisplayable.z2 = optZ2 || 0);
 
     for (let i = 0; i < STATES.length; i++) {
@@ -799,7 +807,10 @@ function updateZForEachState(
     state: DisplayState
 ): void {
     const isNormal = state === NORMAL;
-    const elStateOpt = isNormal ? elOption : retrieveStateOption(elOption, state as DisplayStateNonNormal);
+    const elStateOpt = isNormal ? elOption : retrieveStateOption(
+        elOption as CustomElementOption,
+        state as DisplayStateNonNormal
+    );
     const optZ2 = elStateOpt ? elStateOpt.z2 : null;
     let stateObj;
     if (optZ2 != null) {
@@ -860,7 +871,7 @@ function makeRenderItem(
         coordSys: prepareResult.coordSys,
         dataInsideLength: data.count(),
         encode: wrapEncodeDef(customSeries.getData())
-    };
+    } as CustomSeriesRenderItemParams;
 
     // If someday intending to refactor them to a class, should consider do not
     // break change: currently these attribute member are encapsulated in a closure
@@ -920,7 +931,7 @@ function makeRenderItem(
                 dataIndex: data.getRawIndex(dataIndexInside),
                 // Can be used for optimization when zoom or roam.
                 actionType: payload ? payload.type : null
-            }, userParams),
+            } as CustomSeriesRenderItemParams, userParams),
             userAPI
         );
     };
@@ -1209,7 +1220,7 @@ function doCreateOrUpdateEl(
     }
 
     // Need to set morph: false explictly to disable automatically morphing.
-    if ((elOption as CustomZRPathOption).morph === false) {
+    if ((elOption as CustomBaseZRPathOption).morph === false) {
         (el as ECElement).disableMorphing = true;
     }
     else if ((el as ECElement).disableMorphing) {
@@ -1273,8 +1284,8 @@ function doCreateOrUpdateEl(
 function doesElNeedRecreate(el: Element, elOption: CustomElementOption, seriesModel: CustomSeriesModel): boolean {
     const elInner = customInnerStore(el);
     const elOptionType = elOption.type;
-    const elOptionShape = (elOption as CustomZRPathOption).shape;
-    const elOptionStyle = elOption.style;
+    const elOptionShape = (elOption as CustomBaseZRPathOption).shape;
+    const elOptionStyle = (elOption as CustomDisplayableOption).style;
     return (
         // Always create new if universal transition is enabled.
         // Because we do transition after render. It needs to know what old element is. Replacement will loose it.
@@ -1309,7 +1320,7 @@ function doCreateOrUpdateClipPath(
     // Based on the "merge" principle, if no clipPath provided,
     // do nothing. The exists clip will be totally removed only if
     // `el.clipPath` is `false`. Otherwise it will be merged/replaced.
-    const clipPathOpt = elOption.clipPath;
+    const clipPathOpt = elOption.clipPath as CustomPathOption | false;
     if (clipPathOpt === false) {
         if (el && el.getClipPath()) {
             el.removeClipPath();
@@ -1317,7 +1328,11 @@ function doCreateOrUpdateClipPath(
     }
     else if (clipPathOpt) {
         let clipPath = el.getClipPath();
-        if (clipPath && doesElNeedRecreate(clipPath, clipPathOpt, seriesModel)) {
+        if (clipPath && doesElNeedRecreate(
+            clipPath,
+            clipPathOpt,
+            seriesModel
+        )) {
             clipPath = null;
         }
         if (!clipPath) {
@@ -1385,7 +1400,7 @@ function doCreateOrUpdateAttachedTx(
             updateElNormal(
                 null, textContent, dataIndex, txConOptNormal, null, seriesModel, isInit, true
             );
-            const txConStlOptNormal = txConOptNormal && txConOptNormal.style;
+            const txConStlOptNormal = txConOptNormal && (txConOptNormal as CustomDisplayableOption).style;
             for (let i = 0; i < STATES.length; i++) {
                 const stateName = STATES[i];
                 if (stateName !== NORMAL) {
@@ -1411,7 +1426,9 @@ function processTxInfo(
     attachedTxInfo: AttachedTxInfo
 ): void {
     const stateOpt = !state ? elOption : retrieveStateOption(elOption, state);
-    const styleOpt = !state ? elOption.style : retrieveStyleOptionOnState(elOption, stateOpt, EMPHASIS);
+    const styleOpt = !state
+        ? (elOption as CustomDisplayableOption).style
+        : retrieveStyleOptionOnState(elOption, stateOpt, EMPHASIS);
 
     const elType = elOption.type;
     let txCfg = stateOpt ? stateOpt.textConfig : null;
@@ -1444,7 +1461,7 @@ function processTxInfo(
         !txConOptNormal.type && (txConOptNormal.type = 'text');
         if (__DEV__) {
             // Do not tolerate incorret type for forward compat.
-            txConOptNormal.type !== 'text' && assert(
+            assert(
                 txConOptNormal.type === 'text',
                 'textContent.type must be "text"'
             );
@@ -1459,7 +1476,7 @@ function processTxInfo(
 function retrieveStateOption(
     elOption: CustomElementOption, state: DisplayStateNonNormal
 ): CustomElementOptionOnState {
-    return !state ? elOption : elOption ? elOption[state] : null;
+    return !state ? elOption : elOption ? (elOption as CustomDisplayableOption)[state] : null;
 }
 
 function retrieveStyleOptionOnState(
@@ -1469,7 +1486,7 @@ function retrieveStyleOptionOnState(
 ): CustomElementOptionOnState['style'] {
     let style = stateOption && stateOption.style;
     if (style == null && state === EMPHASIS && stateOptionNormal) {
-        style = stateOptionNormal.styleEmphasis;
+        style = (stateOptionNormal as CustomDisplayableOption).styleEmphasis;
     }
     return style;
 }
@@ -1514,7 +1531,7 @@ function mergeChildren(
         diffGroupChildren({
             api: api,
             oldChildren: el.children() || [],
-            newChildren: newChildren || [],
+            newChildren: newChildren as CustomElementOption[] || [],
             dataIndex: dataIndex,
             seriesModel: seriesModel,
             group: el
@@ -1532,7 +1549,7 @@ function mergeChildren(
             api,
             el.childAt(index),
             dataIndex,
-            newChildren[index],
+            newChildren[index] as CustomElementOption,
             seriesModel,
             el,
             false
diff --git a/src/chart/custom/prepare.ts b/src/chart/custom/prepare.ts
index 67ceed0..37f8d99 100644
--- a/src/chart/custom/prepare.ts
+++ b/src/chart/custom/prepare.ts
@@ -21,6 +21,7 @@ import Transformable from 'zrender/src/core/Transformable';
 import Element, { ElementProps } from 'zrender/src/Element';
 import { Dictionary } from '../../util/types';
 import {
+    CustomDisplayableOption,
     CustomElementOption,
     customInnerStore,
     LooseElementProps,
@@ -242,7 +243,7 @@ export function prepareTransformAllPropsFinal(
 export function prepareStyleTransitionFrom(
     fromEl: Element,
     elOption: CustomElementOption,
-    styleOpt: CustomElementOption['style'],
+    styleOpt: CustomDisplayableOption['style'],
     transFromProps: LooseElementProps,
     isInit: boolean
 ): void {

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org