提交 01e2da59 编写于 作者: P plainheart

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.
上级 cc8a94aa
......@@ -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;
......
......@@ -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];
}
......
......@@ -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),
......
......@@ -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;
......@@ -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;
......@@ -135,6 +135,7 @@ export interface DefaultDataVisual {
symbolSize?: number | number[]
symbolRotate?: number
symbolKeepAspect?: boolean
symbolOffset?: string | number | (string | number)[]
liftZ?: number
// For legend.
......
......@@ -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>)
}
/**
......
......@@ -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
}
......@@ -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};
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册