You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by wa...@apache.org on 2021/03/01 16:08:39 UTC

[echarts] 01/01: 1) fix: markLine `symbolOffset` doesn't work bug - Resolves #9325 - Resolves #14106 - Resolves #4771 2) feat: `markLine.symbolRotate` can be an array to specify symbol rotation at the two endpoints. - Related #12736, #12392 3) feat: add `markLine.symbolKeepAspect` and fix `symbolKeepAspect` doesn't work bug. 4) feat: `symbolOffset` can be a callback function, close #12495.

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

wangzx pushed a commit to branch fix/markLine-symbol
in repository https://gitbox.apache.org/repos/asf/echarts.git

commit 01e2da59277c7b7a094300873854c1cc008f74cc
Author: plainheart <yh...@all-my-life.cn>
AuthorDate: Tue Mar 2 00:07:01 2021 +0800

    1) fix: markLine `symbolOffset` doesn't work bug
    - Resolves #9325
    - Resolves #14106
    - Resolves #4771
    2) feat: `markLine.symbolRotate` can be an array to specify symbol rotation at the two endpoints.
    - Related #12736, #12392
    3) feat: add `markLine.symbolKeepAspect` and fix `symbolKeepAspect` doesn't work bug.
    4) feat: `symbolOffset` can be a callback function, close #12495.
---
 src/chart/helper/Line.ts              | 32 +++++++++++++++++++++++---------
 src/chart/helper/Symbol.ts            | 20 ++++++++------------
 src/chart/helper/SymbolDraw.ts        |  5 -----
 src/component/marker/MarkLineModel.ts |  7 ++++++-
 src/component/marker/MarkLineView.ts  | 20 +++++++++++++++++---
 src/data/List.ts                      |  1 +
 src/util/types.ts                     |  4 ++--
 src/visual/commonVisualTypes.ts       |  8 ++++++--
 src/visual/symbol.ts                  | 20 ++++++++++++++++----
 9 files changed, 79 insertions(+), 38 deletions(-)

diff --git a/src/chart/helper/Line.ts b/src/chart/helper/Line.ts
index 93d0fb3..797504d 100644
--- a/src/chart/helper/Line.ts
+++ b/src/chart/helper/Line.ts
@@ -17,14 +17,14 @@
 * under the License.
 */
 
-import * as zrUtil from 'zrender/src/core/util';
+import { isArray, each, retrieve2 } from 'zrender/src/core/util';
 import * as vector from 'zrender/src/core/vector';
 import * as symbolUtil from '../../util/symbol';
 import ECLinePath from './LinePath';
 import * as graphic from '../../util/graphic';
 import { enableHoverEmphasis, enterEmphasis, leaveEmphasis, SPECIAL_STATES } from '../../util/states';
 import {getLabelStatesModels, setLabelStyle} from '../../label/labelStyle';
-import {round} from '../../util/number';
+import {round, parsePercent} from '../../util/number';
 import List from '../../data/List';
 import { ZRTextAlign, ZRTextVerticalAlign, LineLabelOption, ColorString } from '../../util/types';
 import SeriesModel from '../../model/Series';
@@ -70,12 +70,26 @@ function createSymbol(name: 'fromSymbol' | 'toSymbol', lineData: LineList, idx:
 
     const symbolSize = lineData.getItemVisual(idx, name + 'Size' as 'fromSymbolSize' | 'toSymbolSize');
     const symbolRotate = lineData.getItemVisual(idx, name + 'Rotate' as 'fromSymbolRotate' | 'toSymbolRotate');
+    const symbolOffset = lineData.getItemVisual(idx, name + 'Offset' as 'fromSymbolOffset' | 'toSymbolOffset');
+    const symbolKeepAspect = lineData.getItemVisual(idx, name + 'KeepAspect' as 'fromSymbolKeepAspect' | 'toSymbolKeepAspect');
 
-    const symbolSizeArr = zrUtil.isArray(symbolSize)
+    const symbolSizeArr = isArray(symbolSize)
         ? symbolSize : [symbolSize, symbolSize];
+
+    const symbolOffsetArr = isArray(symbolOffset)
+        ? symbolOffset : [symbolOffset, symbolOffset];
+
+    symbolOffsetArr[0] = parsePercent(symbolOffsetArr[0], symbolSizeArr[0]);
+    symbolOffsetArr[1] = parsePercent(retrieve2(symbolOffsetArr[1], symbolOffsetArr[0]),symbolSizeArr[1]);
+
     const symbolPath = symbolUtil.createSymbol(
-        symbolType, -symbolSizeArr[0] / 2, -symbolSizeArr[1] / 2,
-        symbolSizeArr[0], symbolSizeArr[1]
+        symbolType,
+        -symbolSizeArr[0] / 2 + (symbolOffsetArr as number[])[0],
+        -symbolSizeArr[1] / 2 + (symbolOffsetArr as number[])[1],
+        symbolSizeArr[0],
+        symbolSizeArr[1],
+        null,
+        symbolKeepAspect
     );
 
     (symbolPath as LineECSymbol).__specifiedRotation = symbolRotate == null || isNaN(symbolRotate)
@@ -142,7 +156,7 @@ class Line extends graphic.Group {
 
         this.add(line);
 
-        zrUtil.each(SYMBOL_CATEGORIES, function (symbolCategory) {
+        each(SYMBOL_CATEGORIES, function (symbolCategory) {
             const symbol = createSymbol(symbolCategory, lineData, idx);
             // symbols must added after line to make sure
             // it will be updated after line#update.
@@ -167,7 +181,7 @@ class Line extends graphic.Group {
         setLinePoints(target.shape, linePoints);
         graphic.updateProps(line, target, seriesModel, idx);
 
-        zrUtil.each(SYMBOL_CATEGORIES, function (symbolCategory) {
+        each(SYMBOL_CATEGORIES, function (symbolCategory) {
             const symbolType = (lineData as LineList).getItemVisual(idx, symbolCategory);
             const key = makeSymbolTypeKey(symbolCategory);
             // Symbol changed
@@ -220,7 +234,7 @@ class Line extends graphic.Group {
         line.ensureState('select').style = selectLineStyle;
 
         // Update symbol
-        zrUtil.each(SYMBOL_CATEGORIES, function (symbolCategory) {
+        each(SYMBOL_CATEGORIES, function (symbolCategory) {
             const symbol = this.childOfName(symbolCategory) as ECSymbol;
             if (symbol) {
                 // Share opacity and color with line.
@@ -275,7 +289,7 @@ class Line extends graphic.Group {
             label.__position = labelNormalModel.get('position') || 'middle';
 
             let distance = labelNormalModel.get('distance');
-            if (!zrUtil.isArray(distance)) {
+            if (!isArray(distance)) {
                 distance = [distance, distance];
             }
             label.__labelDistance = distance;
diff --git a/src/chart/helper/Symbol.ts b/src/chart/helper/Symbol.ts
index cea1c1a..6a53bc6 100644
--- a/src/chart/helper/Symbol.ts
+++ b/src/chart/helper/Symbol.ts
@@ -28,7 +28,7 @@ import { ColorString, BlurScope, AnimationOption } from '../../util/types';
 import SeriesModel from '../../model/Series';
 import { PathProps } from 'zrender/src/graphic/Path';
 import { SymbolDrawSeriesScope, SymbolDrawItemModelOption } from './SymbolDraw';
-import { extend } from 'zrender/src/core/util';
+import { extend, isArray, retrieve2 } from 'zrender/src/core/util';
 import { setLabelStyle, getLabelStatesModels } from '../../label/labelStyle';
 import ZRImage from 'zrender/src/graphic/Image';
 
@@ -216,8 +216,6 @@ class Symbol extends graphic.Group {
         let focus;
         let blurScope: BlurScope;
 
-        let symbolOffset;
-
         let labelStatesModels;
 
         let hoverScale;
@@ -230,8 +228,6 @@ class Symbol extends graphic.Group {
             focus = seriesScope.focus;
             blurScope = seriesScope.blurScope;
 
-            symbolOffset = seriesScope.symbolOffset;
-
             labelStatesModels = seriesScope.labelStatesModels;
 
             hoverScale = seriesScope.hoverScale;
@@ -250,8 +246,6 @@ class Symbol extends graphic.Group {
             focus = emphasisModel.get('focus');
             blurScope = emphasisModel.get('blurScope');
 
-            symbolOffset = itemModel.getShallow('symbolOffset');
-
             labelStatesModels = getLabelStatesModels(itemModel);
 
             hoverScale = emphasisModel.getShallow('scale');
@@ -259,14 +253,16 @@ class Symbol extends graphic.Group {
         }
 
         const symbolRotate = data.getItemVisual(idx, 'symbolRotate');
-
         symbolPath.attr('rotation', (symbolRotate || 0) * Math.PI / 180 || 0);
 
-        if (symbolOffset) {
-            symbolPath.x = parsePercent(symbolOffset[0], symbolSize[0]);
-            symbolPath.y = parsePercent(symbolOffset[1], symbolSize[1]);
+        let symbolOffset = data.getItemVisual(idx, 'symbolOffset') || 0;
+        if (!isArray(symbolOffset)) {
+            symbolOffset = [symbolOffset, symbolOffset];
         }
 
+        symbolPath.x = parsePercent(symbolOffset[0], symbolSize[0]);
+        symbolPath.y = parsePercent(retrieve2(symbolOffset[1], symbolOffset[0]) || 0, symbolSize[1]);
+
         cursorStyle && symbolPath.attr('cursor', cursorStyle);
 
         const symbolStyle = data.getItemVisual(idx, 'style');
@@ -398,7 +394,7 @@ class Symbol extends graphic.Group {
 
     static getSymbolSize(data: List, idx: number) {
         const symbolSize = data.getItemVisual(idx, 'symbolSize');
-        return symbolSize instanceof Array
+        return isArray(symbolSize)
             ? symbolSize.slice()
             : [+symbolSize, +symbolSize];
     }
diff --git a/src/chart/helper/SymbolDraw.ts b/src/chart/helper/SymbolDraw.ts
index aace5bd..28d9f5d 100644
--- a/src/chart/helper/SymbolDraw.ts
+++ b/src/chart/helper/SymbolDraw.ts
@@ -114,9 +114,6 @@ export interface SymbolDrawSeriesScope {
     focus?: string
     blurScope?: BlurScope
 
-    symbolRotate?: ScatterSeriesOption['symbolRotate']
-    symbolOffset?: (number | string)[]
-
     labelStatesModels: Record<DisplayState, Model<LabelOption>>
 
     itemModel?: Model<SymbolDrawItemModelOption>
@@ -138,8 +135,6 @@ function makeSeriesScope(data: List): SymbolDrawSeriesScope {
         focus: emphasisModel.get('focus'),
         blurScope: emphasisModel.get('blurScope'),
 
-        symbolRotate: seriesModel.get('symbolRotate'),
-        symbolOffset: seriesModel.get('symbolOffset'),
         hoverScale: emphasisModel.get('scale'),
 
         labelStatesModels: getLabelStatesModels(seriesModel),
diff --git a/src/component/marker/MarkLineModel.ts b/src/component/marker/MarkLineModel.ts
index 44bc99f..4fed8c5 100644
--- a/src/component/marker/MarkLineModel.ts
+++ b/src/component/marker/MarkLineModel.ts
@@ -60,6 +60,8 @@ export interface MarkLine1DDataItemOption extends MarkLineDataItemOptionBase {
      */
     symbol?: string[] | string
     symbolSize?: number[] | number
+    symbolRotate?: number[] | number
+    symbolOffset: number | string | (number | string)[]
 }
 
 // 2D markLine on any direction
@@ -82,6 +84,8 @@ export interface MarkLineOption extends MarkerOption,
 
     symbol?: string[] | string
     symbolSize?: number[] | number
+    symbolRotate?: number[] | number
+    symbolOffset?: number | string | (number | string)[]
 
     /**
      * Precision used on statistic method
@@ -112,6 +116,7 @@ class MarkLineModel extends MarkerModel<MarkLineOption> {
         symbolSize: [8, 16],
 
         //symbolRotate: 0,
+        symbolOffset: 0,
 
         precision: 2,
         tooltip: {
@@ -137,4 +142,4 @@ class MarkLineModel extends MarkerModel<MarkLineOption> {
     };
 }
 
-export default MarkLineModel;
\ No newline at end of file
+export default MarkLineModel;
diff --git a/src/component/marker/MarkLineView.ts b/src/component/marker/MarkLineView.ts
index f0f713e..da7e0cf 100644
--- a/src/component/marker/MarkLineView.ts
+++ b/src/component/marker/MarkLineView.ts
@@ -319,12 +319,20 @@ class MarkLineView extends MarkerView {
 
         let symbolType = mlModel.get('symbol');
         let symbolSize = mlModel.get('symbolSize');
+        let symbolRotate = mlModel.get('symbolRotate');
+        let symbolOffset = mlModel.get('symbolOffset');
         if (!isArray(symbolType)) {
             symbolType = [symbolType, symbolType];
         }
         if (!isArray(symbolSize)) {
             symbolSize = [symbolSize, symbolSize];
         }
+        if (!isArray(symbolRotate)) {
+            symbolRotate = [symbolRotate, symbolRotate];
+        }
+        if (!isArray(symbolOffset)) {
+            symbolOffset = [symbolOffset, symbolOffset];
+        }
 
         // Update visual and layout of from symbol and to symbol
         mlData.from.each(function (idx) {
@@ -349,9 +357,13 @@ class MarkLineView extends MarkerView {
             }
 
             lineData.setItemVisual(idx, {
+                fromSymbolKeepAspect: fromData.getItemVisual(idx, 'symbolKeepAspect'),
+                fromSymbolOffset: fromData.getItemVisual(idx, 'symbolOffset'),
                 fromSymbolRotate: fromData.getItemVisual(idx, 'symbolRotate'),
                 fromSymbolSize: fromData.getItemVisual(idx, 'symbolSize') as number,
                 fromSymbol: fromData.getItemVisual(idx, 'symbol'),
+                toSymbolKeepAspect: toData.getItemVisual(idx, 'symbolKeepAspect'),
+                toSymbolOffset: toData.getItemVisual(idx, 'symbolOffset'),
                 toSymbolRotate: toData.getItemVisual(idx, 'symbolRotate'),
                 toSymbolSize: toData.getItemVisual(idx, 'symbolSize') as number,
                 toSymbol: toData.getItemVisual(idx, 'symbol'),
@@ -384,9 +396,11 @@ class MarkLineView extends MarkerView {
             if (style.fill == null) {
                 style.fill = getVisualFromData(seriesData, 'color') as ColorString;
             }
-
+            const a = symbolOffset
             data.setItemVisual(idx, {
-                symbolRotate: itemModel.get('symbolRotate'),
+                symbolKeepAspect: itemModel.get('symbolKeepAspect'),
+                symbolOffset: itemModel.get('symbolOffset') || (symbolOffset as (string | number)[])[isFrom ? 0 : 1],
+                symbolRotate: itemModel.get('symbolRotate', true) || (symbolRotate as number[])[isFrom ? 0 : 1],
                 symbolSize: itemModel.get('symbolSize') || (symbolSize as number[])[isFrom ? 0 : 1],
                 symbol: itemModel.get('symbol', true) || (symbolType as string[])[isFrom ? 0 : 1],
                 style
@@ -462,4 +476,4 @@ function createList(coordSys: CoordinateSystem, seriesModel: SeriesModel, mlMode
     };
 }
 
-export default MarkLineView;
\ No newline at end of file
+export default MarkLineView;
diff --git a/src/data/List.ts b/src/data/List.ts
index 7a8b245..116dec9 100644
--- a/src/data/List.ts
+++ b/src/data/List.ts
@@ -135,6 +135,7 @@ export interface DefaultDataVisual {
     symbolSize?: number | number[]
     symbolRotate?: number
     symbolKeepAspect?: boolean
+    symbolOffset?: string | number | (string | number)[]
 
     liftZ?: number
     // For legend.
diff --git a/src/util/types.ts b/src/util/types.ts
index 823310c..f9b3923 100644
--- a/src/util/types.ts
+++ b/src/util/types.ts
@@ -925,7 +925,7 @@ export interface RoamOptionMixin {
 export type SymbolSizeCallback<T> = (rawValue: any, params: T) => number | number[];
 export type SymbolCallback<T> = (rawValue: any, params: T) => string;
 export type SymbolRotateCallback<T> = (rawValue: any, params: T) => number;
-// export type SymbolOffsetCallback<T> = (rawValue: any, params: T) => (string | number)[];
+export type SymbolOffsetCallback<T> = (rawValue: any, params: T) => (string | number)[];
 /**
  * Mixin of option set to control the element symbol.
  * Include type of symbol, and size of symbol.
@@ -944,7 +944,7 @@ export interface SymbolOptionMixin<T = unknown> {
 
     symbolKeepAspect?: boolean
 
-    symbolOffset?: (string | number)[]
+    symbolOffset?: (string | number)[] | (unknown extends T ? never : SymbolOffsetCallback<T>)
 }
 
 /**
diff --git a/src/visual/commonVisualTypes.ts b/src/visual/commonVisualTypes.ts
index 00f180e..e279a4c 100644
--- a/src/visual/commonVisualTypes.ts
+++ b/src/visual/commonVisualTypes.ts
@@ -22,9 +22,13 @@ import { DefaultDataVisual } from '../data/List';
 export interface LineDataVisual extends DefaultDataVisual {
     fromSymbol: string
     toSymbol: string
-    fromSymbolSize: number
-    toSymbolSize: number
+    fromSymbolSize: number | number[]
+    toSymbolSize: number | number[]
     fromSymbolRotate: number
     toSymbolRotate: number
+    fromSymbolOffset: string | number | (string | number)[]
+    toSymbolOffset: string | number | (string | number)[]
+    fromSymbolKeepAspect: boolean
+    toSymbolKeepAspect: boolean
 }
 
diff --git a/src/visual/symbol.ts b/src/visual/symbol.ts
index 99be9f0..b4a8d0a 100644
--- a/src/visual/symbol.ts
+++ b/src/visual/symbol.ts
@@ -25,7 +25,8 @@ import {
     SymbolSizeCallback,
     SymbolCallback,
     CallbackDataParams,
-    SymbolRotateCallback
+    SymbolRotateCallback,
+    SymbolOffsetCallback
 } from '../util/types';
 import List from '../data/List';
 import SeriesModel from '../model/Series';
@@ -57,14 +58,17 @@ const seriesSymbolTask: StageHandler = {
         const symbolSize = seriesModel.get('symbolSize');
         const keepAspect = seriesModel.get('symbolKeepAspect');
         const symbolRotate = seriesModel.get('symbolRotate');
+        const symbolOffset = seriesModel.get('symbolOffset');
 
         const hasSymbolTypeCallback = isFunction(symbolType);
         const hasSymbolSizeCallback = isFunction(symbolSize);
         const hasSymbolRotateCallback = isFunction(symbolRotate);
-        const hasCallback = hasSymbolTypeCallback || hasSymbolSizeCallback || hasSymbolRotateCallback;
+        const hasSymbolOffsetCallback = isFunction(symbolOffset);
+        const hasCallback = hasSymbolTypeCallback || hasSymbolSizeCallback || hasSymbolRotateCallback || hasSymbolOffsetCallback;
         const seriesSymbol = (!hasSymbolTypeCallback && symbolType) ? symbolType : seriesModel.defaultSymbol;
         const seriesSymbolSize = !hasSymbolSizeCallback ? symbolSize : null;
         const seriesSymbolRotate = !hasSymbolRotateCallback ? symbolRotate : null;
+        const seriesSymbolOffset = !hasSymbolOffsetCallback ? symbolOffset : null;
 
         data.setVisual({
             legendSymbol: seriesModel.legendSymbol || seriesSymbol as string,
@@ -75,7 +79,8 @@ const seriesSymbolTask: StageHandler = {
             symbol: seriesSymbol as string,
             symbolSize: seriesSymbolSize as number | number[],
             symbolKeepAspect: keepAspect,
-            symbolRotate: seriesSymbolRotate as number
+            symbolRotate: seriesSymbolRotate as number,
+            symbolOffset: seriesSymbolOffset as (string | number)[]
         });
 
         // Only visible series has each data be visual encoded
@@ -95,6 +100,9 @@ const seriesSymbolTask: StageHandler = {
             hasSymbolRotateCallback && data.setItemVisual(
                 idx, 'symbolRotate', (symbolRotate as SymbolRotateCallback<CallbackDataParams>)(rawValue, params)
             );
+            hasSymbolOffsetCallback && data.setItemVisual(
+                idx, 'symbolOffset', (symbolOffset as SymbolOffsetCallback<CallbackDataParams>)(rawValue, params)
+            );
         }
 
         return { dataEach: hasCallback ? dataEach : null };
@@ -127,6 +135,7 @@ const dataSymbolTask: StageHandler = {
             const itemSymbolType = itemModel.getShallow('symbol', true);
             const itemSymbolSize = itemModel.getShallow('symbolSize', true);
             const itemSymbolRotate = itemModel.getShallow('symbolRotate', true);
+            const itemSymbolOffset = itemModel.getShallow('symbolOffset', true);
             const itemSymbolKeepAspect = itemModel.getShallow('symbolKeepAspect', true);
 
             // If has item symbol
@@ -140,6 +149,9 @@ const dataSymbolTask: StageHandler = {
             if (itemSymbolRotate != null) {
                 data.setItemVisual(idx, 'symbolRotate', itemSymbolRotate);
             }
+            if (itemSymbolOffset != null) {
+                data.setItemVisual(idx, 'symbolOffset', itemSymbolOffset);
+            }
             if (itemSymbolKeepAspect != null) {
                 data.setItemVisual(idx, 'symbolKeepAspect', itemSymbolKeepAspect);
             }
@@ -149,4 +161,4 @@ const dataSymbolTask: StageHandler = {
     }
 };
 
-export {seriesSymbolTask, dataSymbolTask};
\ No newline at end of file
+export {seriesSymbolTask, dataSymbolTask};


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