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 2020/07/07 08:11:38 UTC
[incubator-echarts] branch state updated: refact: move states
related code from graphic to states
This is an automated email from the ASF dual-hosted git repository.
shenyi pushed a commit to branch state
in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git
The following commit(s) were added to refs/heads/state by this push:
new ceed556 refact: move states related code from graphic to states
ceed556 is described below
commit ceed556861675d3a002cddb2e5fa83d277b8d87b
Author: pissang <bm...@gmail.com>
AuthorDate: Tue Jul 7 16:11:19 2020 +0800
refact: move states related code from graphic to states
---
src/chart/bar/BarView.ts | 6 +-
src/chart/bar/PictorialBarView.ts | 25 ++-
src/chart/boxplot/BoxplotView.ts | 3 +-
src/chart/candlestick/CandlestickView.ts | 3 +-
src/chart/custom.ts | 17 +-
src/chart/funnel/FunnelView.ts | 5 +-
src/chart/gauge/GaugeView.ts | 5 +-
src/chart/heatmap/HeatmapView.ts | 3 +-
src/chart/helper/EffectSymbol.ts | 3 +-
src/chart/helper/Line.ts | 7 +-
src/chart/helper/Polyline.ts | 3 +-
src/chart/helper/Symbol.ts | 7 +-
src/chart/parallel/ParallelView.ts | 3 +-
src/chart/pie/PieView.ts | 5 +-
src/chart/radar/RadarView.ts | 7 +-
src/chart/sankey/SankeyView.ts | 13 +-
src/chart/sunburst/SunburstPiece.ts | 3 +-
src/chart/themeRiver/ThemeRiverView.ts | 5 +-
src/chart/treemap/TreemapView.ts | 17 +-
src/component/helper/MapDraw.ts | 3 +-
src/component/legend/LegendView.ts | 5 +-
src/component/marker/MarkAreaView.ts | 3 +-
src/component/timeline/SliderTimelineView.ts | 7 +-
src/component/toolbox/ToolboxView.ts | 13 +-
src/echarts.ts | 21 +-
src/util/graphic.ts | 323 ++-------------------------
src/util/states.ts | 316 ++++++++++++++++++++++++++
src/util/types.ts | 18 +-
src/view/Chart.ts | 7 +-
29 files changed, 454 insertions(+), 402 deletions(-)
diff --git a/src/chart/bar/BarView.ts b/src/chart/bar/BarView.ts
index 34ccafc..74470ae 100644
--- a/src/chart/bar/BarView.ts
+++ b/src/chart/bar/BarView.ts
@@ -24,12 +24,10 @@ import {
getECData,
updateProps,
initProps,
- enableHoverEmphasis,
updateLabel,
initLabel,
- removeElement,
- setStatesStylesFromModel
-} from '../../util/graphic';
+ removeElement} from '../../util/graphic';
+import { enableHoverEmphasis, setStatesStylesFromModel } from '../../util/states';
import { setLabelStyle } from '../../label/labelStyle';
import Path, { PathProps } from 'zrender/src/graphic/Path';
import Group from 'zrender/src/graphic/Group';
diff --git a/src/chart/bar/PictorialBarView.ts b/src/chart/bar/PictorialBarView.ts
index b118edc..716cdc8 100644
--- a/src/chart/bar/PictorialBarView.ts
+++ b/src/chart/bar/PictorialBarView.ts
@@ -19,6 +19,13 @@
import * as zrUtil from 'zrender/src/core/util';
import * as graphic from '../../util/graphic';
+import {
+ enterEmphasisWhenMouseOver,
+ leaveEmphasisWhenMouseOut,
+ enterEmphasis,
+ leaveEmphasis,
+ enableHoverEmphasis
+} from '../../util/states';
import {createSymbol} from '../../util/symbol';
import {parsePercent, isNumeric} from '../../util/number';
import ChartView from '../../view/Chart';
@@ -27,7 +34,7 @@ import ExtensionAPI from '../../ExtensionAPI';
import List from '../../data/List';
import GlobalModel from '../../model/Global';
import Model from '../../model/Model';
-import { ColorString, AnimationOptionMixin } from '../../util/types';
+import { ColorString, AnimationOptionMixin, ZRElementEvent } from '../../util/types';
import type Cartesian2D from '../../coord/cartesian/Cartesian2D';
import type Displayable from 'zrender/src/graphic/Displayable';
import type Axis2D from '../../coord/cartesian/Axis2D';
@@ -623,15 +630,15 @@ function createOrUpdateRepeatSymbols(
};
}
- function onMouseOver() {
+ function onMouseOver(e: ZRElementEvent) {
eachPath(bar, function (path) {
- graphic.enterEmphasis(path);
+ enterEmphasisWhenMouseOver(path, e);
});
}
- function onMouseOut() {
+ function onMouseOut(e: ZRElementEvent) {
eachPath(bar, function (path) {
- graphic.leaveEmphasis(path);
+ leaveEmphasisWhenMouseOut(path, e);
});
}
}
@@ -689,11 +696,11 @@ function createOrUpdateSingleSymbol(
updateHoverAnimation(mainPath, symbolMeta);
function onMouseOver(this: typeof mainPath) {
- graphic.enterEmphasis(this);
+ enterEmphasis(this);
}
function onMouseOut(this: typeof mainPath) {
- graphic.leaveEmphasis(this);
+ leaveEmphasis(this);
}
}
@@ -936,7 +943,7 @@ function updateCommon(
eachPath(bar, function (path) {
path.useStyle(symbolMeta.style);
- graphic.enableHoverEmphasis(path);
+ enableHoverEmphasis(path);
path.ensureState('emphasis').style = emphasisStyle;
path.ensureState('blur').style = blurStyle;
@@ -963,7 +970,7 @@ function updateCommon(
}
);
- graphic.enableHoverEmphasis(barRect);
+ enableHoverEmphasis(barRect);
}
function toIntTimes(times: number) {
diff --git a/src/chart/boxplot/BoxplotView.ts b/src/chart/boxplot/BoxplotView.ts
index 0ce6c02..89a2b6f 100644
--- a/src/chart/boxplot/BoxplotView.ts
+++ b/src/chart/boxplot/BoxplotView.ts
@@ -20,6 +20,7 @@
import * as zrUtil from 'zrender/src/core/util';
import ChartView from '../../view/Chart';
import * as graphic from '../../util/graphic';
+import { setStatesStylesFromModel } from '../../util/states';
import Path, { PathProps } from 'zrender/src/graphic/Path';
import BoxplotSeriesModel, { BoxplotDataItemOption } from './BoxplotSeries';
import GlobalModel from '../../model/Global';
@@ -180,7 +181,7 @@ function updateNormalBoxData(
el.z2 = 100;
- graphic.setStatesStylesFromModel(el, data.getItemModel<BoxplotDataItemOption>(dataIndex));
+ setStatesStylesFromModel(el, data.getItemModel<BoxplotDataItemOption>(dataIndex));
}
function transInit(points: number[][], dim: number, itemLayout: BoxplotItemLayout) {
diff --git a/src/chart/candlestick/CandlestickView.ts b/src/chart/candlestick/CandlestickView.ts
index c61ba6b..595d1ee 100644
--- a/src/chart/candlestick/CandlestickView.ts
+++ b/src/chart/candlestick/CandlestickView.ts
@@ -20,6 +20,7 @@
import * as zrUtil from 'zrender/src/core/util';
import ChartView from '../../view/Chart';
import * as graphic from '../../util/graphic';
+import { setStatesStylesFromModel } from '../../util/states';
import Path, { PathProps } from 'zrender/src/graphic/Path';
import {createClipPath} from '../helper/createClipPathFromCoordSys';
import CandlestickSeriesModel, { CandlestickDataItemOption } from './CandlestickSeries';
@@ -279,7 +280,7 @@ function setBoxCommon(el: NormalBoxPath, data: List, dataIndex: number, isSimple
el.__simpleBox = isSimpleBox;
- graphic.setStatesStylesFromModel(el, itemModel);
+ setStatesStylesFromModel(el, itemModel);
}
function transInit(points: number[][], itemLayout: CandlestickItemLayout) {
diff --git a/src/chart/custom.ts b/src/chart/custom.ts
index 5330c07..d9fa1bd 100644
--- a/src/chart/custom.ts
+++ b/src/chart/custom.ts
@@ -23,7 +23,8 @@ import {
hasOwn, assert, isString, retrieve2, retrieve3, defaults, each, keys, isArrayLike, bind
} from 'zrender/src/core/util';
import * as graphicUtil from '../util/graphic';
-import * as SetLabelStyleOpt from '../label/labelStyle';
+import { enableElementHoverEmphasis, setAsHighDownDispatcher } from '../util/states';
+import * as labelStyleHelper from '../label/labelStyle';
import {getDefaultLabel} from './helper/labelHelper';
import createListFromArray from './helper/createListFromArray';
import {getLayoutOnAxis} from '../layout/barGrid';
@@ -1113,11 +1114,11 @@ function updateElOnState(
stateObj.textConfig = txCfgOpt;
}
- graphicUtil.enableElementHoverEmphasis(elDisplayable);
+ enableElementHoverEmphasis(elDisplayable);
}
if (isRoot) {
- graphicUtil.setAsHighDownDispatcher(el, styleOpt !== false);
+ setAsHighDownDispatcher(el, styleOpt !== false);
}
}
@@ -1383,14 +1384,14 @@ function makeRenderItem(
// Now that the feture of "auto adjust text fill/stroke" has been migrated to zrender
// since ec5, we should set `isAttached` as `false` here and make compat in
// `convertToEC4StyleForCustomSerise`.
- const textStyle = SetLabelStyleOpt.createTextStyle(labelModel, null, opt, false, true);
+ const textStyle = labelStyleHelper.createTextStyle(labelModel, null, opt, false, true);
textStyle.text = labelModel.getShallow('show')
? retrieve2(
customSeries.getFormattedLabel(dataIndexInside, NORMAL),
getDefaultLabel(data, dataIndexInside)
)
: null;
- const textConfig = SetLabelStyleOpt.createTextConfig(textStyle, labelModel, opt, false);
+ const textConfig = labelStyleHelper.createTextConfig(textStyle, labelModel, opt, false);
preFetchFromExtra(userProps, itemStyle);
itemStyle = convertToEC4StyleForCustomSerise(itemStyle, textStyle, textConfig);
@@ -1415,7 +1416,7 @@ function makeRenderItem(
let itemStyle = getItemStyleModel(dataIndexInside, EMPHASIS).getItemStyle();
const labelModel = getLabelModel(dataIndexInside, EMPHASIS);
- const textStyle = SetLabelStyleOpt.createTextStyle(labelModel, null, null, true, true);
+ const textStyle = labelStyleHelper.createTextStyle(labelModel, null, null, true, true);
textStyle.text = labelModel.getShallow('show')
? retrieve3(
customSeries.getFormattedLabel(dataIndexInside, EMPHASIS),
@@ -1423,7 +1424,7 @@ function makeRenderItem(
getDefaultLabel(data, dataIndexInside)
)
: null;
- const textConfig = SetLabelStyleOpt.createTextConfig(textStyle, labelModel, null, true);
+ const textConfig = labelStyleHelper.createTextConfig(textStyle, labelModel, null, true);
preFetchFromExtra(userProps, itemStyle);
itemStyle = convertToEC4StyleForCustomSerise(itemStyle, textStyle, textConfig);
@@ -1502,7 +1503,7 @@ function makeRenderItem(
function font(
opt: Parameters<typeof graphicUtil.getFont>[0]
): ReturnType<typeof graphicUtil.getFont> {
- return SetLabelStyleOpt.getFont(opt, ecModel);
+ return labelStyleHelper.getFont(opt, ecModel);
}
}
diff --git a/src/chart/funnel/FunnelView.ts b/src/chart/funnel/FunnelView.ts
index 25fa13c..a4d0822 100644
--- a/src/chart/funnel/FunnelView.ts
+++ b/src/chart/funnel/FunnelView.ts
@@ -18,6 +18,7 @@
*/
import * as graphic from '../../util/graphic';
+import { setStatesStylesFromModel, enableHoverEmphasis } from '../../util/states';
import ChartView from '../../view/Chart';
import FunnelSeriesModel, {FunnelDataItemOption} from './FunnelSeries';
import GlobalModel from '../../model/Global';
@@ -84,11 +85,11 @@ class FunnelPiece extends graphic.Polygon {
}, seriesModel, idx);
}
- graphic.setStatesStylesFromModel(polygon, itemModel);
+ setStatesStylesFromModel(polygon, itemModel);
this._updateLabel(data, idx);
- graphic.enableHoverEmphasis(this);
+ enableHoverEmphasis(this);
}
_updateLabel(data: List, idx: number) {
diff --git a/src/chart/gauge/GaugeView.ts b/src/chart/gauge/GaugeView.ts
index eb09903..5cb812f 100644
--- a/src/chart/gauge/GaugeView.ts
+++ b/src/chart/gauge/GaugeView.ts
@@ -19,6 +19,7 @@
import PointerPath from './PointerPath';
import * as graphic from '../../util/graphic';
+import { setStatesStylesFromModel, enableHoverEmphasis } from '../../util/states';
import {createTextStyle} from '../../label/labelStyle';
import ChartView from '../../view/Chart';
import {parsePercent, round, linearMap} from '../../util/number';
@@ -385,8 +386,8 @@ class GaugeView extends ChartView {
));
}
- graphic.setStatesStylesFromModel(pointer, itemModel);
- graphic.enableHoverEmphasis(pointer);
+ setStatesStylesFromModel(pointer, itemModel);
+ enableHoverEmphasis(pointer);
});
this._data = data;
diff --git a/src/chart/heatmap/HeatmapView.ts b/src/chart/heatmap/HeatmapView.ts
index 36b1382..795f000 100644
--- a/src/chart/heatmap/HeatmapView.ts
+++ b/src/chart/heatmap/HeatmapView.ts
@@ -19,6 +19,7 @@
import {__DEV__} from '../../config';
import * as graphic from '../../util/graphic';
+import { enableHoverEmphasis } from '../../util/states';
import HeatmapLayer from './HeatmapLayer';
import * as zrUtil from 'zrender/src/core/util';
import ChartView from '../../view/Chart';
@@ -270,7 +271,7 @@ class HeatmapView extends ChartView {
rect.ensureState('blur').style = blurStyle;
rect.ensureState('select').style = selectStyle;
- graphic.enableHoverEmphasis(rect);
+ enableHoverEmphasis(rect);
rect.incremental = incremental;
// PENDING
diff --git a/src/chart/helper/EffectSymbol.ts b/src/chart/helper/EffectSymbol.ts
index 57f6618..0615d88 100644
--- a/src/chart/helper/EffectSymbol.ts
+++ b/src/chart/helper/EffectSymbol.ts
@@ -19,7 +19,8 @@
import * as zrUtil from 'zrender/src/core/util';
import {createSymbol} from '../../util/symbol';
-import {Group, Path, enterEmphasis, leaveEmphasis, enableHoverEmphasis} from '../../util/graphic';
+import {Group, Path} from '../../util/graphic';
+import { enterEmphasis, leaveEmphasis, enableHoverEmphasis } from '../../util/states';
import {parsePercent} from '../../util/number';
import SymbolClz from './Symbol';
import List from '../../data/List';
diff --git a/src/chart/helper/Line.ts b/src/chart/helper/Line.ts
index b13d510..6e9318b 100644
--- a/src/chart/helper/Line.ts
+++ b/src/chart/helper/Line.ts
@@ -22,6 +22,7 @@ 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 } from '../../util/states';
import {createTextStyle} from '../../label/labelStyle';
import {round} from '../../util/number';
import List from '../../data/List';
@@ -307,15 +308,15 @@ class Line extends graphic.Group {
label.ignore = !showLabel && !hoverShowLabel;
- graphic.enableHoverEmphasis(this);
+ enableHoverEmphasis(this);
}
highlight() {
- graphic.enterEmphasis(this);
+ enterEmphasis(this);
}
downplay() {
- graphic.leaveEmphasis(this);
+ leaveEmphasis(this);
}
updateLayout(lineData: List, idx: number) {
diff --git a/src/chart/helper/Polyline.ts b/src/chart/helper/Polyline.ts
index 8527dd6..4b3d011 100644
--- a/src/chart/helper/Polyline.ts
+++ b/src/chart/helper/Polyline.ts
@@ -18,6 +18,7 @@
*/
import * as graphic from '../../util/graphic';
+import { enableHoverEmphasis } from '../../util/states';
import type { LineDrawSeriesScope, LineDrawModelOption } from './LineDraw';
import type List from '../../data/List';
@@ -72,7 +73,7 @@ class Polyline extends graphic.Group {
const lineEmphasisState = line.ensureState('emphasis');
lineEmphasisState.style = hoverLineStyle;
- graphic.enableHoverEmphasis(this);
+ enableHoverEmphasis(this);
};
updateLayout(lineData: List, idx: number) {
diff --git a/src/chart/helper/Symbol.ts b/src/chart/helper/Symbol.ts
index 41963be..0e33484 100644
--- a/src/chart/helper/Symbol.ts
+++ b/src/chart/helper/Symbol.ts
@@ -19,6 +19,7 @@
import {createSymbol} from '../../util/symbol';
import * as graphic from '../../util/graphic';
+import { enterEmphasis, leaveEmphasis, enableHoverEmphasis } from '../../util/states';
import {parsePercent} from '../../util/number';
import {getDefaultLabel} from './labelHelper';
import List from '../../data/List';
@@ -109,14 +110,14 @@ class Symbol extends graphic.Group {
* Highlight symbol
*/
highlight() {
- graphic.enterEmphasis(this.childAt(0));
+ enterEmphasis(this.childAt(0));
}
/**
* Downplay symbol
*/
downplay() {
- graphic.leaveEmphasis(this.childAt(0));
+ leaveEmphasis(this.childAt(0));
}
/**
@@ -294,7 +295,7 @@ class Symbol extends graphic.Group {
this.states.emphasis = null;
}
- graphic.enableHoverEmphasis(this);
+ enableHoverEmphasis(this);
}
setSymbolScale(scale: number) {
diff --git a/src/chart/parallel/ParallelView.ts b/src/chart/parallel/ParallelView.ts
index 659b671..b7ba339 100644
--- a/src/chart/parallel/ParallelView.ts
+++ b/src/chart/parallel/ParallelView.ts
@@ -18,6 +18,7 @@
*/
import * as graphic from '../../util/graphic';
+import { setStatesStylesFromModel } from '../../util/states';
import ChartView from '../../view/Chart';
import List from '../../data/List';
import ParallelSeriesModel, { ParallelSeriesDataItemOption } from './ParallelSeries';
@@ -203,7 +204,7 @@ function updateElCommon(
seriesScope.smooth && (el.shape.smooth = seriesScope.smooth);
const itemModel = data.getItemModel<ParallelSeriesDataItemOption>(dataIndex);
- graphic.setStatesStylesFromModel(el, itemModel, 'lineStyle', 'getLineStyle');
+ setStatesStylesFromModel(el, itemModel, 'lineStyle', 'getLineStyle');
}
// function simpleDiff(oldData, newData, dimensions) {
diff --git a/src/chart/pie/PieView.ts b/src/chart/pie/PieView.ts
index 7d038e2..0284831 100644
--- a/src/chart/pie/PieView.ts
+++ b/src/chart/pie/PieView.ts
@@ -21,6 +21,7 @@
import { extend, curry } from 'zrender/src/core/util';
import * as graphic from '../../util/graphic';
+import { setStatesStylesFromModel, enableHoverEmphasis } from '../../util/states';
import ChartView from '../../view/Chart';
import GlobalModel from '../../model/Global';
import ExtensionAPI from '../../ExtensionAPI';
@@ -121,7 +122,7 @@ class PiePiece extends graphic.Sector {
}
sector.useStyle(data.getItemVisual(idx, 'style'));
- graphic.setStatesStylesFromModel(sector, itemModel);
+ setStatesStylesFromModel(sector, itemModel);
const midAngle = (layout.startAngle + layout.endAngle) / 2;
const offset = seriesModel.get('selectedOffset');
@@ -156,7 +157,7 @@ class PiePiece extends graphic.Sector {
y: dy
});
- graphic.enableHoverEmphasis(this);
+ enableHoverEmphasis(this);
// State will be set after all rendered in the pipeline.
(sector as ECElement).selected = seriesModel.isSelected(data.getName(idx));
diff --git a/src/chart/radar/RadarView.ts b/src/chart/radar/RadarView.ts
index 39ff302..967beec 100644
--- a/src/chart/radar/RadarView.ts
+++ b/src/chart/radar/RadarView.ts
@@ -18,6 +18,7 @@
*/
import * as graphic from '../../util/graphic';
+import { setStatesStylesFromModel, enableHoverEmphasis } from '../../util/states';
import * as zrUtil from 'zrender/src/core/util';
import * as symbolUtil from '../../util/symbol';
import ChartView from '../../view/Chart';
@@ -197,8 +198,8 @@ class RadarView extends ChartView {
)
);
- graphic.setStatesStylesFromModel(polyline, itemModel, 'lineStyle');
- graphic.setStatesStylesFromModel(polygon, itemModel, 'areaStyle');
+ setStatesStylesFromModel(polyline, itemModel, 'lineStyle');
+ setStatesStylesFromModel(polygon, itemModel, 'areaStyle');
const areaStyleModel = itemModel.getModel('areaStyle');
const polygonIgnore = areaStyleModel.isEmpty() && areaStyleModel.parentModel.isEmpty();
@@ -243,7 +244,7 @@ class RadarView extends ChartView {
);
});
- graphic.enableHoverEmphasis(itemGroup);
+ enableHoverEmphasis(itemGroup);
});
this._data = data;
diff --git a/src/chart/sankey/SankeyView.ts b/src/chart/sankey/SankeyView.ts
index 9c6d82a..7e3dd6f 100644
--- a/src/chart/sankey/SankeyView.ts
+++ b/src/chart/sankey/SankeyView.ts
@@ -18,6 +18,7 @@
*/
import * as graphic from '../../util/graphic';
+import { enterEmphasis, leaveEmphasis, enableHoverEmphasis } from '../../util/states';
import * as zrUtil from 'zrender/src/core/util';
import { LayoutOrient, Payload } from '../../util/types';
import { PathProps } from 'zrender/src/graphic/Path';
@@ -117,11 +118,11 @@ class SankeyPath extends graphic.Path<SankeyPathProps> {
}
highlight() {
- graphic.enterEmphasis(this);
+ enterEmphasis(this);
}
downplay() {
- graphic.leaveEmphasis(this);
+ leaveEmphasis(this);
}
}
@@ -230,7 +231,7 @@ class SankeyView extends ChartView {
break;
}
- graphic.enableHoverEmphasis(
+ enableHoverEmphasis(
curve,
edgeModel.getModel(['emphasis', 'lineStyle']).getItemStyle()
);
@@ -272,7 +273,7 @@ class SankeyView extends ChartView {
rect.setStyle('fill', node.getVisual('color'));
- graphic.enableHoverEmphasis(rect, hoverStyle);
+ enableHoverEmphasis(rect, hoverStyle);
group.add(rect);
@@ -305,11 +306,11 @@ class SankeyView extends ChartView {
}
el.highlight = function () {
- graphic.enterEmphasis(this);
+ enterEmphasis(this);
};
el.downplay = function () {
- graphic.leaveEmphasis(this);
+ leaveEmphasis(this);
};
el.focusNodeAdjHandler && el.off('mouseover', el.focusNodeAdjHandler);
diff --git a/src/chart/sunburst/SunburstPiece.ts b/src/chart/sunburst/SunburstPiece.ts
index 70aaaa8..0ad0e63 100644
--- a/src/chart/sunburst/SunburstPiece.ts
+++ b/src/chart/sunburst/SunburstPiece.ts
@@ -19,6 +19,7 @@
import * as zrUtil from 'zrender/src/core/util';
import * as graphic from '../../util/graphic';
+import { enableHoverEmphasis } from '../../util/states';
import {createTextStyle} from '../../label/labelStyle';
import { TreeNode } from '../../data/Tree';
import SunburstSeriesModel, { SunburstSeriesNodeItemOption, SunburstSeriesOption } from './SunburstSeries';
@@ -154,7 +155,7 @@ class SunburstPiece extends graphic.Sector {
this._seriesModel = seriesModel || this._seriesModel;
this._ecModel = ecModel || this._ecModel;
- graphic.enableHoverEmphasis(this);
+ enableHoverEmphasis(this);
}
onEmphasis(highlightPolicy: AllPropTypes<typeof NodeHighlightPolicy>) {
diff --git a/src/chart/themeRiver/ThemeRiverView.ts b/src/chart/themeRiver/ThemeRiverView.ts
index 0617eab..a8af6eb 100644
--- a/src/chart/themeRiver/ThemeRiverView.ts
+++ b/src/chart/themeRiver/ThemeRiverView.ts
@@ -19,6 +19,7 @@
import {ECPolygon} from '../line/poly';
import * as graphic from '../../util/graphic';
+import { setStatesStylesFromModel, enableHoverEmphasis } from '../../util/states';
import {createTextStyle} from '../../label/labelStyle';
import {bind, extend} from 'zrender/src/core/util';
import DataDiffer from '../../data/DataDiffer';
@@ -158,9 +159,9 @@ class ThemeRiverView extends ChartView {
polygon.useStyle(style);
- graphic.setStatesStylesFromModel(polygon, seriesModel);
+ setStatesStylesFromModel(polygon, seriesModel);
- graphic.enableHoverEmphasis(polygon);
+ enableHoverEmphasis(polygon);
}
this._layersSeries = layersSeries;
diff --git a/src/chart/treemap/TreemapView.ts b/src/chart/treemap/TreemapView.ts
index 0712c7f..f6ce7c8 100644
--- a/src/chart/treemap/TreemapView.ts
+++ b/src/chart/treemap/TreemapView.ts
@@ -19,6 +19,7 @@
import {bind, each, indexOf, curry, extend, retrieve} from 'zrender/src/core/util';
import * as graphic from '../../util/graphic';
+import { isHighDownDispatcher, setAsHighDownDispatcher, enableElementHoverEmphasis } from '../../util/states';
import DataDiffer from '../../data/DataDiffer';
import * as helper from '../helper/treeHelper';
import Breadcrumb from './Breadcrumb';
@@ -794,11 +795,11 @@ function renderNode(
// Because of the implementation about "traverse" in graphic hover style, we
// can not set hover listener on the "group" of non-leaf node. Otherwise the
// hover event from the descendents will be listenered.
- if (graphic.isHighDownDispatcher(group)) {
- graphic.setAsHighDownDispatcher(group, false);
+ if (isHighDownDispatcher(group)) {
+ setAsHighDownDispatcher(group, false);
}
if (bg) {
- graphic.setAsHighDownDispatcher(bg, true);
+ setAsHighDownDispatcher(bg, true);
// Only for enabling highlight/downplay.
data.setItemGraphicEl(thisNode.dataIndex, bg);
}
@@ -807,10 +808,10 @@ function renderNode(
const content = giveGraphic('content', Rect, depth, Z_CONTENT);
content && renderContent(group, content);
- if (bg && graphic.isHighDownDispatcher(bg)) {
- graphic.setAsHighDownDispatcher(bg, false);
+ if (bg && isHighDownDispatcher(bg)) {
+ setAsHighDownDispatcher(bg, false);
}
- graphic.setAsHighDownDispatcher(group, true);
+ setAsHighDownDispatcher(group, true);
// Only for enabling highlight/downplay.
data.setItemGraphicEl(thisNode.dataIndex, group);
}
@@ -865,7 +866,7 @@ function renderNode(
bg.ensureState('emphasis').style = emphasisStyle;
bg.ensureState('blur').style = blurStyle;
bg.ensureState('select').style = selectStyle;
- graphic.enableElementHoverEmphasis(bg);
+ enableElementHoverEmphasis(bg);
}
group.add(bg);
@@ -910,7 +911,7 @@ function renderNode(
content.ensureState('emphasis').style = emphasisStyle;
content.ensureState('blur').style = blurStyle;
content.ensureState('select').style = selectStyle;
- graphic.enableElementHoverEmphasis(content);
+ enableElementHoverEmphasis(content);
}
group.add(content);
diff --git a/src/component/helper/MapDraw.ts b/src/component/helper/MapDraw.ts
index 77c4251..d518d64 100644
--- a/src/component/helper/MapDraw.ts
+++ b/src/component/helper/MapDraw.ts
@@ -22,6 +22,7 @@ import RoamController from './RoamController';
import * as roamHelper from '../../component/helper/roamHelper';
import {onIrrelevantElement} from '../../component/helper/cursorHelper';
import * as graphic from '../../util/graphic';
+import { enableHoverEmphasis } from '../../util/states';
import geoSourceManager from '../../coord/geo/geoSourceManager';
import {getUID} from '../../util/component';
import ExtensionAPI from '../../ExtensionAPI';
@@ -358,7 +359,7 @@ class MapDraw {
// @ts-ignore FIXME:TS fix the "compatible with each other"?
regionGroup.highDownSilentOnTouch = !!mapOrGeoModel.get('selectedMode');
- graphic.enableHoverEmphasis(regionGroup);
+ enableHoverEmphasis(regionGroup);
regionsGroup.add(regionGroup);
});
diff --git a/src/component/legend/LegendView.ts b/src/component/legend/LegendView.ts
index 6805e00..3edf9b2 100644
--- a/src/component/legend/LegendView.ts
+++ b/src/component/legend/LegendView.ts
@@ -21,6 +21,7 @@ import {__DEV__} from '../../config';
import * as zrUtil from 'zrender/src/core/util';
import {createSymbol} from '../../util/symbol';
import * as graphic from '../../util/graphic';
+import { enableHoverEmphasis } from '../../util/states';
import {setLabelStyle, createTextStyle} from '../../label/labelStyle';
import {makeBackground} from '../helper/listComponent';
import * as layoutUtil from '../../util/layout';
@@ -319,7 +320,7 @@ class LegendView extends ComponentView {
defaultText: selectorItem.title
}
);
- graphic.enableHoverEmphasis(labelText);
+ enableHoverEmphasis(labelText);
});
}
@@ -455,7 +456,7 @@ class LegendView extends ComponentView {
this.getContentGroup().add(itemGroup);
- graphic.enableHoverEmphasis(itemGroup);
+ enableHoverEmphasis(itemGroup);
// @ts-ignore
itemGroup.__legendDataIndex = dataIndex;
diff --git a/src/component/marker/MarkAreaView.ts b/src/component/marker/MarkAreaView.ts
index 383b31f..b9f021c 100644
--- a/src/component/marker/MarkAreaView.ts
+++ b/src/component/marker/MarkAreaView.ts
@@ -23,6 +23,7 @@ import * as colorUtil from 'zrender/src/tool/color';
import List from '../../data/List';
import * as numberUtil from '../../util/number';
import * as graphic from '../../util/graphic';
+import { enableHoverEmphasis } from '../../util/states';
import * as markerHelper from './markerHelper';
import MarkerView from './MarkerView';
import { retrieve, mergeAll, map, defaults, curry, filter, HashMap } from 'zrender/src/core/util';
@@ -306,7 +307,7 @@ class MarkAreaView extends MarkerView {
}
);
- graphic.enableHoverEmphasis(polygon, itemModel.getModel(['emphasis', 'itemStyle']).getItemStyle());
+ enableHoverEmphasis(polygon, itemModel.getModel(['emphasis', 'itemStyle']).getItemStyle());
graphic.getECData(polygon).dataModel = maModel;
});
diff --git a/src/component/timeline/SliderTimelineView.ts b/src/component/timeline/SliderTimelineView.ts
index 792654f..8caf8f9 100644
--- a/src/component/timeline/SliderTimelineView.ts
+++ b/src/component/timeline/SliderTimelineView.ts
@@ -20,6 +20,7 @@
import BoundingRect, { RectLike } from 'zrender/src/core/BoundingRect';
import * as matrix from 'zrender/src/core/matrix';
import * as graphic from '../../util/graphic';
+import { enableHoverEmphasis } from '../../util/states';
import { createTextStyle } from '../../label/labelStyle';
import * as layout from '../../util/layout';
import TimelineView from './TimelineView';
@@ -399,7 +400,7 @@ class SliderTimelineView extends TimelineView {
onclick: bind(this._changeTimeline, this, value)
};
const el = giveSymbol(itemModel, itemStyleModel, group, symbolOpt);
- graphic.enableHoverEmphasis(el, hoverStyleModel.getItemStyle());
+ enableHoverEmphasis(el, hoverStyleModel.getItemStyle());
const ecData = graphic.getECData(el);
if (itemModel.get('tooltip')) {
@@ -453,7 +454,7 @@ class SliderTimelineView extends TimelineView {
});
group.add(textEl);
- graphic.enableHoverEmphasis(
+ enableHoverEmphasis(
textEl, createTextStyle(hoverLabelModel)
);
@@ -514,7 +515,7 @@ class SliderTimelineView extends TimelineView {
};
const btn = makeControlIcon(timelineModel, iconPath, rect, opt);
group.add(btn);
- graphic.enableHoverEmphasis(btn, hoverStyle);
+ enableHoverEmphasis(btn, hoverStyle);
}
}
diff --git a/src/component/toolbox/ToolboxView.ts b/src/component/toolbox/ToolboxView.ts
index 27e6829..40f2060 100644
--- a/src/component/toolbox/ToolboxView.ts
+++ b/src/component/toolbox/ToolboxView.ts
@@ -20,6 +20,7 @@
import * as zrUtil from 'zrender/src/core/util';
import * as textContain from 'zrender/src/contain/text';
import * as graphic from '../../util/graphic';
+import { enterEmphasis, leaveEmphasis } from '../../util/states';
import Model from '../../model/Model';
import DataDiffer from '../../data/DataDiffer';
import * as listComponentHelper from '../helper/listComponent';
@@ -144,7 +145,7 @@ class ToolboxView extends ComponentView {
option.iconStatus = option.iconStatus || {};
option.iconStatus[iconName] = status;
if (iconPaths[iconName]) {
- graphic[status === 'emphasis' ? 'enterEmphasis' : 'leaveEmphasis'](iconPaths[iconName]);
+ (status === 'emphasis' ? enterEmphasis : leaveEmphasis)(iconPaths[iconName]);
}
};
@@ -262,19 +263,15 @@ class ToolboxView extends ComponentView {
// Use enterEmphasis and leaveEmphasis provide by ec.
// There are flags managed by the echarts.
- graphic.enterEmphasis(this);
+ enterEmphasis(this);
})
.on('mouseout', function () {
if (featureModel.get(['iconStatus', iconName]) !== 'emphasis') {
- graphic.leaveEmphasis(this);
+ leaveEmphasis(this);
}
textContent.hide();
});
-
- graphic[
- featureModel.get(['iconStatus', iconName]) === 'emphasis'
- ? 'enterEmphasis' : 'leaveEmphasis'
- ](path);
+ (featureModel.get(['iconStatus', iconName]) === 'emphasis' ? enterEmphasis : leaveEmphasis)(path);
group.add(path);
(path as graphic.Path).on('click', zrUtil.bind(
diff --git a/src/echarts.ts b/src/echarts.ts
index 79649f3..74103ef 100644
--- a/src/echarts.ts
+++ b/src/echarts.ts
@@ -38,6 +38,7 @@ import SeriesModel, { SeriesModelConstructor } from './model/Series';
import ComponentView, {ComponentViewConstructor} from './view/Component';
import ChartView, {ChartViewConstructor} from './view/Chart';
import * as graphic from './util/graphic';
+import { enterEmphasisWhenMouseOver, leaveEmphasisWhenMouseOut, isHighDownDispatcher } from './util/states';
import * as modelUtil from './util/model';
import {throttle} from './util/throttle';
import {seriesStyleTask, dataStyleTask, dataColorPaletteTask} from './visual/style';
@@ -1672,7 +1673,7 @@ class ECharts extends Eventful {
bindMouseEvent = function (zr: zrender.ZRenderType, ecIns: ECharts): void {
function getHighDownDispatcher(target: Element) {
- while (target && !graphic.isHighDownDispatcher(target)) {
+ while (target && !isHighDownDispatcher(target)) {
target = target.parent;
}
return target;
@@ -1681,13 +1682,13 @@ class ECharts extends Eventful {
const dispatcher = getHighDownDispatcher(e.target);
if (dispatcher) {
markStatusToUpdate(ecIns);
- graphic.enterEmphasisWhenMouseOver(dispatcher, e);
+ enterEmphasisWhenMouseOver(dispatcher, e);
}
}).on('mouseout', function (e) {
const dispatcher = getHighDownDispatcher(e.target);
if (dispatcher) {
markStatusToUpdate(ecIns);
- graphic.leaveEmphasisWhenMouseOut(dispatcher, e);
+ leaveEmphasisWhenMouseOut(dispatcher, e);
}
});
};
@@ -1831,14 +1832,12 @@ class ECharts extends Eventful {
}
}
- if (el.selected || el.highlighted) {
- // Only use states when it's exists.
- if (el.selected && el.states.select) {
- newStates.push('select');
- }
- if (el.highlighted && el.states.emphasis) {
- newStates.push('emphasis');
- }
+ // Only use states when it's exists.
+ if (el.selected && el.states.select) {
+ newStates.push('select');
+ }
+ if (el.highlighted && el.states.emphasis) {
+ newStates.push('emphasis');
}
else if (el.blurred && el.states.blur) {
newStates.push('blur');
diff --git a/src/util/graphic.ts b/src/util/graphic.ts
index d5e1500..bec255b 100644
--- a/src/util/graphic.ts
+++ b/src/util/graphic.ts
@@ -18,7 +18,6 @@
*/
import * as pathTool from 'zrender/src/tool/path';
-import * as colorTool from 'zrender/src/tool/color';
import * as matrix from 'zrender/src/core/matrix';
import * as vector from 'zrender/src/core/vector';
import Path, { PathProps } from 'zrender/src/graphic/Path';
@@ -45,31 +44,27 @@ import Point from 'zrender/src/core/Point';
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, DisplayableState } from 'zrender/src/graphic/Displayable';
-import { PatternObject } from 'zrender/src/graphic/Pattern';
-import { GradientObject } from 'zrender/src/graphic/Gradient';
-import Element, { ElementEvent, ElementProps } from 'zrender/src/Element';
+import Displayable, { DisplayableProps } from 'zrender/src/graphic/Displayable';
+import Element, { ElementProps } from 'zrender/src/Element';
import Model from '../model/Model';
import {
AnimationOptionMixin,
LabelOption,
AnimationDelayCallbackParam,
DisplayState,
- ECElement,
ZRRectLike,
ColorString,
DataModel,
ECEventData,
ZRStyleProps,
- ParsedValue} from './types';
+ ParsedValue,
+ BlurScope} from './types';
import { makeInner } from './model';
import {
extend,
isArrayLike,
map,
defaults,
- indexOf,
isObject
} from 'zrender/src/core/util';
import * as numberUtil from './number';
@@ -86,12 +81,10 @@ export const EMPTY_OBJ = {};
export const Z2_EMPHASIS_LIFT = 10;
-const EMPHASIS = 'emphasis';
-const NORMAL = 'normal';
+export const EMPHASIS = 'emphasis';
+export const NORMAL = 'normal';
-// Reserve 0 as default.
-let _highlightNextDigit = 1;
-const _highlightKeyMap: Dictionary<number> = {};
+export const _highlightKeyMap: Dictionary<number> = {};
const _customShapeMap: Dictionary<{ new(): Path }> = {};
@@ -107,8 +100,8 @@ type ExtendedProps = {
__highDownDispatcher: boolean
};
-type ExtendedElement = Element & ExtendedProps;
-type ExtendedDisplayable = Displayable & ExtendedProps;
+export type ExtendedElement = Element & ExtendedProps;
+export type ExtendedDisplayable = Displayable & ExtendedProps;
export type TextCommonParams = {
/**
@@ -341,300 +334,6 @@ export function subPixelOptimizeRect(param: {
export const subPixelOptimize = subPixelOptimizeUtil.subPixelOptimize;
-function hasFillOrStroke(fillOrStroke: string | PatternObject | GradientObject) {
- return fillOrStroke != null && fillOrStroke !== 'none';
-}
-
-// Most lifted color are duplicated.
-const liftedColorCache = new LRU<string>(100);
-
-function liftColor(color: string): string {
- if (typeof color !== 'string') {
- return color;
- }
- let liftedColor = liftedColorCache.get(color);
- if (!liftedColor) {
- liftedColor = colorTool.lift(color, -0.1);
- liftedColorCache.put(color, liftedColor);
- }
- return liftedColor;
-}
-
-function singleEnterEmphasis(el: Element) {
- // Only mark the flag.
- // States will be applied in the echarts.ts in next frame.
- (el as ECElement).highlighted = true;
-}
-
-
-function singleLeaveEmphasis(el: Element) {
- // Only mark the flag.
- // States will be applied in the echarts.ts in next frame.
- (el as ECElement).highlighted = false;
-}
-
-function updateElementState<T>(
- el: ExtendedElement,
- updater: (this: void, el: Element, commonParam?: T) => void,
- commonParam?: T
-) {
- // If root is group, also enter updater for `onStateChange`.
- let fromState: DisplayState = NORMAL;
- let toState: DisplayState = NORMAL;
- let trigger;
- // See the rule of `onStateChange` on `graphic.setAsHighDownDispatcher`.
- (el as ECElement).highlighted && (fromState = EMPHASIS, trigger = true);
- updater(el, commonParam);
- (el as ECElement).highlighted && (toState = EMPHASIS, trigger = true);
- trigger && el.__onStateChange && el.__onStateChange(fromState, toState);
-}
-
-function traverseUpdateState<T>(
- el: ExtendedElement,
- updater: (this: void, el: Element, commonParam?: T) => void,
- commonParam?: T
-) {
- updateElementState(el, updater, commonParam);
- el.isGroup && el.traverse(function (child: ExtendedElement) {
- updateElementState(child, updater, commonParam);
- });
-}
-
-/**
- * If we reuse elements when rerender.
- * DONT forget to clearStates before we update the style and shape.
- * Or we may update on the wrong state instead of normal state.
- */
-export function clearStates(el: Element) {
- if (el.isGroup) {
- el.traverse(function (child) {
- child.clearStates();
- });
- }
- else {
- el.clearStates();
- }
-}
-
-function elementStateProxy(this: Displayable, stateName: string): DisplayableState {
- let state = this.states[stateName];
- if (stateName === 'emphasis' && this.style) {
- const hasEmphasis = indexOf(this.currentStates, stateName) >= 0;
- if (!(this instanceof ZRText)) {
- const currentFill = this.style.fill;
- const currentStroke = this.style.stroke;
- if (currentFill || currentStroke) {
- let fromState: {fill: ColorString, stroke: ColorString};
- if (!hasEmphasis) {
- fromState = {fill: currentFill, stroke: currentStroke};
- for (let i = 0; i < this.animators.length; i++) {
- const animator = this.animators[i];
- if (animator.__fromStateTransition
- // Dont consider the animation to emphasis state.
- && animator.__fromStateTransition.indexOf('emphasis') < 0
- && animator.targetName === 'style'
- ) {
- animator.saveFinalToTarget(fromState, ['fill', 'stroke']);
- }
- }
- }
-
- 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);
- // Already being applied 'emphasis'. DON'T lift color multiple times.
- emphasisStyle.fill = hasEmphasis ? currentFill : liftColor(fromState.fill);
- }
- if (!hasFillOrStroke(emphasisStyle.stroke)) {
- if (!cloned) {
- state = extend({}, state);
- emphasisStyle = extend({}, emphasisStyle);
- }
- emphasisStyle.stroke = hasEmphasis ? currentStroke : liftColor(fromState.stroke);
- }
-
- state.style = emphasisStyle;
- }
- }
- if (state) {
- const z2EmphasisLift = (this as ECElement).z2EmphasisLift;
- // TODO Share with textContent?
- state.z2 = this.z2 + (z2EmphasisLift != null ? z2EmphasisLift : Z2_EMPHASIS_LIFT);
- }
- }
-
- return state;
-}
-
-/**FI
- * Set hover style (namely "emphasis style") of element.
- * @param el Should not be `zrender/graphic/Group`.
- */
-export function enableElementHoverEmphasis(el: Displayable) {
- el.stateProxy = elementStateProxy;
- const textContent = el.getTextContent();
- const textGuide = el.getTextGuideLine();
- if (textContent) {
- textContent.stateProxy = elementStateProxy;
- }
- if (textGuide) {
- textGuide.stateProxy = elementStateProxy;
- }
-}
-
-export function enterEmphasisWhenMouseOver(el: Element, e: ElementEvent) {
- !shouldSilent(el, e)
- // "emphasis" event highlight has higher priority than mouse highlight.
- && !(el as ExtendedElement).__highByOuter
- && traverseUpdateState((el as ExtendedElement), singleEnterEmphasis);
-}
-
-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), singleLeaveEmphasis);
-}
-
-export function enterEmphasis(el: Element, highlightDigit?: number) {
- (el as ExtendedElement).__highByOuter |= 1 << (highlightDigit || 0);
- traverseUpdateState((el as ExtendedElement), singleEnterEmphasis);
-}
-
-export function leaveEmphasis(el: Element, highlightDigit?: number) {
- !((el as ExtendedElement).__highByOuter &= ~(1 << (highlightDigit || 0)))
- && traverseUpdateState((el as ExtendedElement), singleLeaveEmphasis);
-}
-
-function shouldSilent(el: Element, e: ElementEvent) {
- return (el as ExtendedElement).__highDownSilentOnTouch && e.zrByTouch;
-}
-
-/**
- * Enable the function that mouseover will trigger the emphasis state.
- *
- * NOTICE:
- * Call the method for a "root" element once. Do not call it for each descendants.
- * If the descendants elemenets of a group has itself hover style different from the
- * root group, we can simply mount the style on `el.states.emphasis` for them, but should
- * not call this method for them.
- */
-export function enableHoverEmphasis(el: Element) {
- setAsHighDownDispatcher(el, true);
- traverseUpdateState(el as ExtendedElement, enableElementHoverEmphasis);
-}
-
-const OTHER_STATES = ['emphasis', 'blur', 'select'] as const;
-
-const styleGetterMap: Dictionary<'getItemStyle' | 'getLineStyle' | 'getAreaStyle'> = {
- itemStyle: 'getItemStyle',
- lineStyle: 'getLineStyle',
- areaStyle: 'getAreaStyle'
-};
-/**
- * Set emphasis/blur/selected states of element.
- */
-export function setStatesStylesFromModel(
- el: Displayable,
- itemModel: Model<Partial<Record<'emphasis' | 'blur' | 'select', any>>>,
- styleType?: string, // default itemStyle
- getterType?: 'getItemStyle' | 'getLineStyle' | 'getAreaStyle'
-) {
- styleType = styleType || 'itemStyle';
- for (let i = 0; i < OTHER_STATES.length; i++) {
- const stateName = OTHER_STATES[i];
- const model = itemModel.getModel([stateName, styleType]);
- const state = el.ensureState(stateName);
- // Let it throw error if getterType is not found.
- state.style = model[getterType || styleGetterMap[styleType]]();
- }
-}
-
-/**
- * @param {module:zrender/Element} el
- * @param {Function} [el.onStateChange] Called when state updated.
- * Since `setHoverStyle` has the constraint that it must be called after
- * all of the normal style updated, `onStateChange` is not needed to
- * trigger if both `fromState` and `toState` is 'normal', and needed to
- * trigger if both `fromState` and `toState` is 'emphasis', which enables
- * to sync outside style settings to "emphasis" state.
- * @this {string} This dispatcher `el`.
- * @param {string} fromState Can be "normal" or "emphasis".
- * `fromState` might equal to `toState`,
- * for example, when this method is called when `el` is
- * on "emphasis" state.
- * @param {string} toState Can be "normal" or "emphasis".
- *
- * FIXME
- * CAUTION: Do not expose `onStateChange` outside echarts.
- * Because it is not a complete solution. The update
- * listener should not have been mount in element,
- * and the normal/emphasis state should not have
- * mantained on elements.
- *
- * @param {boolean} [el.highDownSilentOnTouch=false]
- * In touch device, mouseover event will be trigger on touchstart event
- * (see module:zrender/dom/HandlerProxy). By this mechanism, we can
- * conveniently use hoverStyle when tap on touch screen without additional
- * code for compatibility.
- * But if the chart/component has select feature, which usually also use
- * hoverStyle, there might be conflict between 'select-highlight' and
- * 'hover-highlight' especially when roam is enabled (see geo for example).
- * In this case, `highDownSilentOnTouch` should be used to disable
- * hover-highlight on touch device.
- * @param {boolean} [asDispatcher=true] If `false`, do not set as "highDownDispatcher".
- */
-export function setAsHighDownDispatcher(el: Element, asDispatcher: boolean) {
- const disable = asDispatcher === false;
- const extendedEl = el as ExtendedElement;
- // Make `highDownSilentOnTouch` and `onStateChange` only work after
- // `setAsHighDownDispatcher` called. Avoid it is modified by user unexpectedly.
- if ((el as ECElement).highDownSilentOnTouch) {
- extendedEl.__highDownSilentOnTouch = (el as ECElement).highDownSilentOnTouch;
- }
- if ((el as ECElement).onStateChange) {
- extendedEl.__onStateChange = (el as ECElement).onStateChange;
- }
-
- // Simple optimize, since this method might be
- // called for each elements of a group in some cases.
- if (!disable || extendedEl.__highDownDispatcher) {
-
- // Emphasis, normal can be triggered manually by API or other components like hover link.
- // el[method]('emphasis', onElementEmphasisEvent)[method]('normal', onElementNormalEvent);
- // Also keep previous record.
- extendedEl.__highByOuter = extendedEl.__highByOuter || 0;
-
- extendedEl.__highDownDispatcher = !disable;
- }
-}
-
-export function isHighDownDispatcher(el: Element): boolean {
- return !!(el && (el as ExtendedDisplayable).__highDownDispatcher);
-}
-
-/**
- * Support hightlight/downplay record on each elements.
- * For the case: hover highlight/downplay (legend, visualMap, ...) and
- * user triggerred hightlight/downplay should not conflict.
- * Only all of the highlightDigit cleared, return to normal.
- * @param {string} highlightKey
- * @return {number} highlightDigit
- */
-export function getHighlightDigit(highlightKey: number) {
- let highlightDigit = _highlightKeyMap[highlightKey];
- if (highlightDigit == null && _highlightNextDigit <= 32) {
- highlightDigit = _highlightKeyMap[highlightKey] = _highlightNextDigit++;
- }
- return highlightDigit;
-}
-
type AnimateOrSetPropsOption = {
dataIndex?: number;
cb?: () => void;
@@ -1158,6 +857,10 @@ export interface ECData {
eventData?: ECEventData;
seriesIndex?: number;
dataType?: string;
+
+ // self | series
+ focus?: string
+ blurScope?: BlurScope
}
export const getECData = makeInner<ECData, Element>();
diff --git a/src/util/states.ts b/src/util/states.ts
new file mode 100644
index 0000000..32baa56
--- /dev/null
+++ b/src/util/states.ts
@@ -0,0 +1,316 @@
+import ZRText from 'zrender/src/graphic/Text';
+import { Dictionary } from 'zrender/src/core/types';
+import LRU from 'zrender/src/core/LRU';
+import Displayable, { DisplayableState } from 'zrender/src/graphic/Displayable';
+import { PatternObject } from 'zrender/src/graphic/Pattern';
+import { GradientObject } from 'zrender/src/graphic/Gradient';
+import Element, { ElementEvent } from 'zrender/src/Element';
+import Model from '../model/Model';
+import { DisplayState, ECElement, ColorString, BlurScope } from './types';
+import { extend, indexOf } from 'zrender/src/core/util';
+import { __DEV__ } from '../config';
+import {
+ ExtendedElement,
+ NORMAL,
+ EMPHASIS,
+ Z2_EMPHASIS_LIFT,
+ getECData,
+ ExtendedDisplayable,
+ _highlightKeyMap
+} from './graphic';
+import * as colorTool from 'zrender/src/tool/color';
+
+// Reserve 0 as default.
+export let _highlightNextDigit = 1;
+
+function hasFillOrStroke(fillOrStroke: string | PatternObject | GradientObject) {
+ return fillOrStroke != null && fillOrStroke !== 'none';
+}
+// Most lifted color are duplicated.
+const liftedColorCache = new LRU<string>(100);
+function liftColor(color: string): string {
+ if (typeof color !== 'string') {
+ return color;
+ }
+ let liftedColor = liftedColorCache.get(color);
+ if (!liftedColor) {
+ liftedColor = colorTool.lift(color, -0.1);
+ liftedColorCache.put(color, liftedColor);
+ }
+ return liftedColor;
+}
+
+function singleEnterEmphasis(el: Element) {
+ // Only mark the flag.
+ // States will be applied in the echarts.ts in next frame.
+ (el as ECElement).highlighted = true;
+}
+
+function singleLeaveEmphasis(el: Element) {
+ // Only mark the flag.
+ // States will be applied in the echarts.ts in next frame.
+ (el as ECElement).highlighted = false;
+}
+
+function updateElementState<T>(
+ el: ExtendedElement,
+ updater: (this: void, el: Element, commonParam?: T) => void,
+ commonParam?: T
+) {
+ // If root is group, also enter updater for `onStateChange`.
+ let fromState: DisplayState = NORMAL;
+ let toState: DisplayState = NORMAL;
+ let trigger;
+ // See the rule of `onStateChange` on `graphic.setAsHighDownDispatcher`.
+ (el as ECElement).highlighted && (fromState = EMPHASIS, trigger = true);
+ updater(el, commonParam);
+ (el as ECElement).highlighted && (toState = EMPHASIS, trigger = true);
+ trigger && el.__onStateChange && el.__onStateChange(fromState, toState);
+}
+
+function traverseUpdateState<T>(
+ el: ExtendedElement,
+ updater: (this: void, el: Element, commonParam?: T) => void,
+ commonParam?: T
+) {
+ updateElementState(el, updater, commonParam);
+ el.isGroup && el.traverse(function (child: ExtendedElement) {
+ updateElementState(child, updater, commonParam);
+ });
+}
+/**
+ * If we reuse elements when rerender.
+ * DONT forget to clearStates before we update the style and shape.
+ * Or we may update on the wrong state instead of normal state.
+ */
+export function clearStates(el: Element) {
+ if (el.isGroup) {
+ el.traverse(function (child) {
+ child.clearStates();
+ });
+ }
+ else {
+ el.clearStates();
+ }
+}
+function elementStateProxy(this: Displayable, stateName: string): DisplayableState {
+ let state = this.states[stateName];
+ if (stateName === 'emphasis' && this.style) {
+ const hasEmphasis = indexOf(this.currentStates, stateName) >= 0;
+ if (!(this instanceof ZRText)) {
+ const currentFill = this.style.fill;
+ const currentStroke = this.style.stroke;
+ if (currentFill || currentStroke) {
+ let fromState: {
+ fill: ColorString;
+ stroke: ColorString;
+ };
+ if (!hasEmphasis) {
+ fromState = { fill: currentFill, stroke: currentStroke };
+ for (let i = 0; i < this.animators.length; i++) {
+ const animator = this.animators[i];
+ if (animator.__fromStateTransition
+ // Dont consider the animation to emphasis state.
+ && animator.__fromStateTransition.indexOf('emphasis') < 0
+ && animator.targetName === 'style') {
+ animator.saveFinalToTarget(fromState, ['fill', 'stroke']);
+ }
+ }
+ }
+ 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);
+ // Already being applied 'emphasis'. DON'T lift color multiple times.
+ emphasisStyle.fill = hasEmphasis ? currentFill : liftColor(fromState.fill);
+ }
+ if (!hasFillOrStroke(emphasisStyle.stroke)) {
+ if (!cloned) {
+ state = extend({}, state);
+ emphasisStyle = extend({}, emphasisStyle);
+ }
+ emphasisStyle.stroke = hasEmphasis ? currentStroke : liftColor(fromState.stroke);
+ }
+ state.style = emphasisStyle;
+ }
+ }
+ if (state) {
+ const z2EmphasisLift = (this as ECElement).z2EmphasisLift;
+ // TODO Share with textContent?
+ state.z2 = this.z2 + (z2EmphasisLift != null ? z2EmphasisLift : Z2_EMPHASIS_LIFT);
+ }
+ }
+ return state;
+}
+/**FI
+ * Set hover style (namely "emphasis style") of element.
+ * @param el Should not be `zrender/graphic/Group`.
+ * @param focus 'self' | 'selfInSeries' | 'series'
+ */
+export function enableElementHoverEmphasis(el: Displayable) {
+ el.stateProxy = elementStateProxy;
+ const textContent = el.getTextContent();
+ const textGuide = el.getTextGuideLine();
+ if (textContent) {
+ textContent.stateProxy = elementStateProxy;
+ }
+ if (textGuide) {
+ textGuide.stateProxy = elementStateProxy;
+ }
+}
+
+export function enterEmphasisWhenMouseOver(el: Element, e: ElementEvent) {
+ !shouldSilent(el, e)
+ // "emphasis" event highlight has higher priority than mouse highlight.
+ && !(el as ExtendedElement).__highByOuter
+ && traverseUpdateState((el as ExtendedElement), singleEnterEmphasis);
+}
+
+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), singleLeaveEmphasis);
+}
+
+export function enterEmphasis(el: Element, highlightDigit?: number) {
+ (el as ExtendedElement).__highByOuter |= 1 << (highlightDigit || 0);
+ traverseUpdateState((el as ExtendedElement), singleEnterEmphasis);
+}
+
+export function leaveEmphasis(el: Element, highlightDigit?: number) {
+ !((el as ExtendedElement).__highByOuter &= ~(1 << (highlightDigit || 0)))
+ && traverseUpdateState((el as ExtendedElement), singleLeaveEmphasis);
+}
+
+function shouldSilent(el: Element, e: ElementEvent) {
+ return (el as ExtendedElement).__highDownSilentOnTouch && e.zrByTouch;
+}
+
+/**
+ * Enable the function that mouseover will trigger the emphasis state.
+ *
+ * NOTICE:
+ * Call the method for a "root" element once. Do not call it for each descendants.
+ * If the descendants elemenets of a group has itself hover style different from the
+ * root group, we can simply mount the style on `el.states.emphasis` for them, but should
+ * not call this method for them.
+ */
+export function enableHoverEmphasis(el: Element, focus?: string, blurScope?: BlurScope) {
+ setAsHighDownDispatcher(el, true);
+ traverseUpdateState(el as ExtendedElement, enableElementHoverEmphasis);
+ const ecData = getECData(el);
+ if (__DEV__) {
+ if (ecData.dataIndex == null && focus != null) {
+ console.warn('focus can only been set on element with dataIndex');
+ }
+ }
+ ecData.focus = focus;
+ ecData.blurScope = blurScope;
+}
+
+const OTHER_STATES = ['emphasis', 'blur', 'select'] as const;
+const styleGetterMap: Dictionary<'getItemStyle' | 'getLineStyle' | 'getAreaStyle'> = {
+ itemStyle: 'getItemStyle',
+ lineStyle: 'getLineStyle',
+ areaStyle: 'getAreaStyle'
+};
+/**
+ * Set emphasis/blur/selected states of element.
+ */
+export function setStatesStylesFromModel(
+ el: Displayable,
+ itemModel: Model<Partial<Record<'emphasis' | 'blur' | 'select', any>>>,
+ styleType?: string, // default itemStyle
+ getterType?: 'getItemStyle' | 'getLineStyle' | 'getAreaStyle'
+) {
+ styleType = styleType || 'itemStyle';
+ for (let i = 0; i < OTHER_STATES.length; i++) {
+ const stateName = OTHER_STATES[i];
+ const model = itemModel.getModel([stateName, styleType]);
+ const state = el.ensureState(stateName);
+ // Let it throw error if getterType is not found.
+ state.style = model[getterType || styleGetterMap[styleType]]();
+ }
+}
+
+/**
+ * @param {module:zrender/Element} el
+ * @param {Function} [el.onStateChange] Called when state updated.
+ * Since `setHoverStyle` has the constraint that it must be called after
+ * all of the normal style updated, `onStateChange` is not needed to
+ * trigger if both `fromState` and `toState` is 'normal', and needed to
+ * trigger if both `fromState` and `toState` is 'emphasis', which enables
+ * to sync outside style settings to "emphasis" state.
+ * @this {string} This dispatcher `el`.
+ * @param {string} fromState Can be "normal" or "emphasis".
+ * `fromState` might equal to `toState`,
+ * for example, when this method is called when `el` is
+ * on "emphasis" state.
+ * @param {string} toState Can be "normal" or "emphasis".
+ *
+ * FIXME
+ * CAUTION: Do not expose `onStateChange` outside echarts.
+ * Because it is not a complete solution. The update
+ * listener should not have been mount in element,
+ * and the normal/emphasis state should not have
+ * mantained on elements.
+ *
+ * @param {boolean} [el.highDownSilentOnTouch=false]
+ * In touch device, mouseover event will be trigger on touchstart event
+ * (see module:zrender/dom/HandlerProxy). By this mechanism, we can
+ * conveniently use hoverStyle when tap on touch screen without additional
+ * code for compatibility.
+ * But if the chart/component has select feature, which usually also use
+ * hoverStyle, there might be conflict between 'select-highlight' and
+ * 'hover-highlight' especially when roam is enabled (see geo for example).
+ * In this case, `highDownSilentOnTouch` should be used to disable
+ * hover-highlight on touch device.
+ * @param {boolean} [asDispatcher=true] If `false`, do not set as "highDownDispatcher".
+ */
+export function setAsHighDownDispatcher(el: Element, asDispatcher: boolean) {
+ const disable = asDispatcher === false;
+ const extendedEl = el as ExtendedElement;
+ // Make `highDownSilentOnTouch` and `onStateChange` only work after
+ // `setAsHighDownDispatcher` called. Avoid it is modified by user unexpectedly.
+ if ((el as ECElement).highDownSilentOnTouch) {
+ extendedEl.__highDownSilentOnTouch = (el as ECElement).highDownSilentOnTouch;
+ }
+ if ((el as ECElement).onStateChange) {
+ extendedEl.__onStateChange = (el as ECElement).onStateChange;
+ }
+ // Simple optimize, since this method might be
+ // called for each elements of a group in some cases.
+ if (!disable || extendedEl.__highDownDispatcher) {
+ // Emphasis, normal can be triggered manually by API or other components like hover link.
+ // el[method]('emphasis', onElementEmphasisEvent)[method]('normal', onElementNormalEvent);
+ // Also keep previous record.
+ extendedEl.__highByOuter = extendedEl.__highByOuter || 0;
+ extendedEl.__highDownDispatcher = !disable;
+ }
+}
+
+export function isHighDownDispatcher(el: Element): boolean {
+ return !!(el && (el as ExtendedDisplayable).__highDownDispatcher);
+}
+
+/**
+ * Support hightlight/downplay record on each elements.
+ * For the case: hover highlight/downplay (legend, visualMap, ...) and
+ * user triggerred hightlight/downplay should not conflict.
+ * Only all of the highlightDigit cleared, return to normal.
+ * @param {string} highlightKey
+ * @return {number} highlightDigit
+ */
+export function getHighlightDigit(highlightKey: number) {
+ let highlightDigit = _highlightKeyMap[highlightKey];
+ if (highlightDigit == null && _highlightNextDigit <= 32) {
+ highlightDigit = _highlightKeyMap[highlightKey] = _highlightNextDigit++;
+ }
+ return highlightDigit;
+}
diff --git a/src/util/types.ts b/src/util/types.ts
index f6b9358..c4fc3bf 100644
--- a/src/util/types.ts
+++ b/src/util/types.ts
@@ -1124,17 +1124,29 @@ export interface ComponentOption {
// FIXME:TS more
}
-export interface StatesOptionMixin<StateOption> {
+export type BlurScope = 'coordinateSystem' | 'series' | 'global';
+
+export interface StatesOptionMixin<StateOption, ExtraFocusOptions = never> {
/**
* Emphasis states
*/
emphasis?: StateOption & {
/**
* self: Focus self and blur all others.
- * selfInSeries: Focus self and blur others in the same series.
* series: Focus series and blur all other series.
*/
- focus?: 'self' | 'selfInSeries' | 'series'
+ focus?: 'self' | 'series' | ExtraFocusOptions
+
+ /**
+ * Scope of blurred element when focus.
+ *
+ * coordinateSystem: blur others in the same coordinateSystem
+ * series: blur others in the same series
+ * global: blur all others
+ *
+ * Default to be coordinate system.
+ */
+ blurScope?: BlurScope
}
/**
* Select states
diff --git a/src/view/Chart.ts b/src/view/Chart.ts
index 529ed94..c5b7292 100644
--- a/src/view/Chart.ts
+++ b/src/view/Chart.ts
@@ -22,7 +22,7 @@ import Group from 'zrender/src/graphic/Group';
import * as componentUtil from '../util/component';
import * as clazzUtil from '../util/clazz';
import * as modelUtil from '../util/model';
-import * as graphicUtil from '../util/graphic';
+import { enterEmphasis, leaveEmphasis, getHighlightDigit } from '../util/states';
import {createTask, TaskResetCallbackReturn} from '../stream/task';
import createRenderPlanner from '../chart/helper/createRenderPlanner';
import SeriesModel from '../model/Series';
@@ -202,8 +202,7 @@ class ChartView {
*/
function elSetState(el: Element, state: DisplayState, highlightDigit: number) {
if (el) {
- state === 'emphasis' ? graphicUtil.enterEmphasis(el, highlightDigit)
- : graphicUtil.leaveEmphasis(el, highlightDigit);
+ (state === 'emphasis' ? enterEmphasis : leaveEmphasis)(el, highlightDigit);
}
}
@@ -211,7 +210,7 @@ function toggleHighlight(data: List, payload: Payload, state: DisplayState) {
const dataIndex = modelUtil.queryDataIndex(data, payload);
const highlightDigit = (payload && payload.highlightKey != null)
- ? graphicUtil.getHighlightDigit(payload.highlightKey)
+ ? getHighlightDigit(payload.highlightKey)
: null;
if (dataIndex != null) {
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org