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 05:38:10 UTC

[incubator-echarts] branch state created (now 31f9a59)

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

shenyi pushed a change to branch state
in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git.


      at 31f9a59  refact(state): add selected, blur state. move label related helpers to label/labelStyle

This branch includes the following new commits:

     new 31f9a59  refact(state): add selected, blur state. move label related helpers to label/labelStyle

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



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


[incubator-echarts] 01/01: refact(state): add selected, blur state. move label related helpers to label/labelStyle

Posted by sh...@apache.org.
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

commit 31f9a59eb783751801e64f22b2e3e518eb7e942b
Author: pissang <bm...@gmail.com>
AuthorDate: Tue Jul 7 13:37:31 2020 +0800

    refact(state): add selected, blur state. move label related helpers to label/labelStyle
---
 src/chart/bar/BarSeries.ts                     |  48 +--
 src/chart/bar/BarView.ts                       |  30 +-
 src/chart/bar/BaseBarSeries.ts                 |  22 +-
 src/chart/bar/PictorialBarSeries.ts            |  38 +-
 src/chart/bar/PictorialBarView.ts              |  16 +-
 src/chart/boxplot/BoxplotSeries.ts             |  27 +-
 src/chart/boxplot/BoxplotView.ts               |   8 +-
 src/chart/candlestick/CandlestickSeries.ts     |  35 +-
 src/chart/candlestick/CandlestickView.ts       |   4 +-
 src/chart/custom.ts                            |  11 +-
 src/chart/effectScatter/EffectScatterSeries.ts |  23 +-
 src/chart/funnel/FunnelSeries.ts               |  39 +-
 src/chart/funnel/FunnelView.ts                 |   7 +-
 src/chart/gauge/GaugeSeries.ts                 |  17 +-
 src/chart/gauge/GaugeView.ts                   |  12 +-
 src/chart/graph/GraphSeries.ts                 |  59 +--
 src/chart/graph/GraphView.ts                   |  14 -
 src/chart/heatmap/HeatmapSeries.ts             |  27 +-
 src/chart/heatmap/HeatmapView.ts               |  18 +-
 src/chart/helper/EffectSymbol.ts               |  32 +-
 src/chart/helper/Line.ts                       |  45 +-
 src/chart/helper/LineDraw.ts                   |  31 +-
 src/chart/helper/Polyline.ts                   |   2 +-
 src/chart/helper/Symbol.ts                     |  42 +-
 src/chart/helper/SymbolDraw.ts                 |  43 +-
 src/chart/line/LineSeries.ts                   |  34 +-
 src/chart/lines/LinesSeries.ts                 |  28 +-
 src/chart/map/MapSeries.ts                     |  35 +-
 src/chart/parallel/ParallelSeries.ts           |  25 +-
 src/chart/parallel/ParallelView.ts             |   5 +-
 src/chart/pie/PieSeries.ts                     |  43 +-
 src/chart/pie/PieView.ts                       |  36 +-
 src/chart/radar/RadarSeries.ts                 |  34 +-
 src/chart/radar/RadarView.ts                   |  26 +-
 src/chart/sankey/SankeySeries.ts               |  50 +--
 src/chart/sankey/SankeyView.ts                 |  13 +-
 src/chart/scatter/ScatterSeries.ts             |  32 +-
 src/chart/sunburst/SunburstPiece.ts            |   9 +-
 src/chart/sunburst/SunburstSeries.ts           |  71 +--
 src/chart/themeRiver/ThemeRiverSeries.ts       |  23 +-
 src/chart/themeRiver/ThemeRiverView.ts         |   8 +-
 src/chart/tree/TreeSeries.ts                   |  60 +--
 src/chart/treemap/TreemapSeries.ts             |  41 +-
 src/chart/treemap/TreemapView.ts               |  33 +-
 src/component/axis/AngleAxisView.ts            |   3 +-
 src/component/axis/AxisBuilder.ts              |   5 +-
 src/component/calendar/CalendarView.ts         |   7 +-
 src/component/helper/MapDraw.ts                |  22 +-
 src/component/helper/selectableMixin.ts        |   1 -
 src/component/legend/LegendView.ts             |   5 +-
 src/component/marker/MarkAreaView.ts           |   3 +-
 src/component/timeline/SliderTimelineView.ts   |   5 +-
 src/component/title.ts                         |   5 +-
 src/coord/geo/GeoModel.ts                      |  34 +-
 src/echarts.ts                                 | 176 +++++---
 src/label/labelStyle.ts                        | 405 +++++++++++++++++
 src/model/globalDefault.ts                     |   9 +-
 src/model/mixin/textStyle.ts                   |   3 +-
 src/util/graphic.ts                            | 572 ++-----------------------
 src/util/types.ts                              |  29 +-
 test/bar.html                                  |   4 +-
 61 files changed, 1183 insertions(+), 1361 deletions(-)

diff --git a/src/chart/bar/BarSeries.ts b/src/chart/bar/BarSeries.ts
index dad4736..cd00afb 100644
--- a/src/chart/bar/BarSeries.ts
+++ b/src/chart/bar/BarSeries.ts
@@ -19,36 +19,38 @@
 
 import BaseBarSeriesModel, {BaseBarSeriesOption} from './BaseBarSeries';
 import SeriesModel from '../../model/Series';
-import { ItemStyleOption, OptionDataValue, LabelOption, SeriesStackOptionMixin } from '../../util/types';
+import {
+    ItemStyleOption,
+    OptionDataValue,
+    LabelOption,
+    SeriesStackOptionMixin,
+    StatesOptionMixin,
+    OptionDataItemObject
+} from '../../util/types';
 import type Cartesian2D from '../../coord/cartesian/Cartesian2D';
 import type Polar from '../../coord/polar/Polar';
 import { inheritDefaultOption } from '../../util/component';
 import List from '../../data/List';
 import { BrushCommonSelectorsForSeries } from '../../component/brush/selector';
 
-type BarDataValue = OptionDataValue | OptionDataValue[];
+
+export interface BarStateOption {
+    itemStyle?: BarItemStyleOption
+    label?: LabelOption
+}
 
 export interface BarItemStyleOption extends ItemStyleOption {
     // Border radius is not supported for bar on polar
     borderRadius?: number | number[]
 }
-export interface BarDataItemOption {
-    name?: string
-
-    value?: BarDataValue
-
-    itemStyle?: BarItemStyleOption
-    label?: LabelOption
-
+export interface BarDataItemOption extends BarStateOption, StatesOptionMixin<BarStateOption>,
+    OptionDataItemObject<OptionDataValue> {
     cursor?: string
-
-    emphasis?: {
-        itemStyle?: BarItemStyleOption
-        label?: LabelOption
-    }
 }
 
-export interface BarSeriesOption extends BaseBarSeriesOption, SeriesStackOptionMixin {
+export interface BarSeriesOption extends BaseBarSeriesOption<BarStateOption>, BarStateOption,
+    SeriesStackOptionMixin {
+
     type?: 'bar'
 
     coordinateSystem?: 'cartesian2d' | 'polar'
@@ -67,17 +69,11 @@ export interface BarSeriesOption extends BaseBarSeriesOption, SeriesStackOptionM
         borderRadius?: number | number[]
     }
 
-    data?: (BarDataItemOption | BarDataValue)[]
-
-    label?: LabelOption
-
-    itemStyle?: BarItemStyleOption
-
-    emphasis?: {
-        label?: LabelOption
-        itemStyle?: BarItemStyleOption
-    }
+    data?: (BarDataItemOption | OptionDataValue | OptionDataValue[])[]
 
+    emphasis?: BarStateOption
+    blur?: BarStateOption
+    select?: BarStateOption
 }
 
 class BarSeriesModel extends BaseBarSeriesModel<BarSeriesOption> {
diff --git a/src/chart/bar/BarView.ts b/src/chart/bar/BarView.ts
index d7dc1e1..34ccafc 100644
--- a/src/chart/bar/BarView.ts
+++ b/src/chart/bar/BarView.ts
@@ -18,7 +18,6 @@
 */
 
 import {__DEV__} from '../../config';
-import * as zrUtil from 'zrender/src/core/util';
 import {
     Rect,
     Sector,
@@ -26,11 +25,12 @@ import {
     updateProps,
     initProps,
     enableHoverEmphasis,
-    setLabelStyle,
     updateLabel,
     initLabel,
-    removeElement
+    removeElement,
+    setStatesStylesFromModel
 } from '../../util/graphic';
+import { setLabelStyle } from '../../label/labelStyle';
 import Path, { PathProps } from 'zrender/src/graphic/Path';
 import Group from 'zrender/src/graphic/Group';
 import {throttle} from '../../util/throttle';
@@ -59,6 +59,7 @@ import { getDefaultLabel } from '../helper/labelHelper';
 import OrdinalScale from '../../scale/Ordinal';
 import AngleAxis from '../../coord/polar/AngleAxis';
 import RadiusAxis from '../../coord/polar/RadiusAxis';
+import { extend, map, defaults, each } from 'zrender/src/core/util';
 
 const BAR_BORDER_WIDTH_QUERY = ['itemStyle', 'borderWidth'] as const;
 const BAR_BORDER_RADIUS_QUERY = ['itemStyle', 'borderRadius'] as const;
@@ -454,7 +455,7 @@ class BarView extends ChartView {
 
     _dataSort(
         data: List<BarSeriesModel, DefaultDataVisual>,
-        map: ((idx: number) => number)
+        idxMap: ((idx: number) => number)
     ): OrdinalSortInfo[] {
         type SortValueInfo = {
             mappedValue: number,
@@ -464,7 +465,7 @@ class BarView extends ChartView {
         const info: SortValueInfo[] = [];
         data.each(idx => {
             info.push({
-                mappedValue: map(idx),
+                mappedValue: idxMap(idx),
                 ordinalNumber: idx,
                 beforeSortIndex: null
             });
@@ -479,7 +480,7 @@ class BarView extends ChartView {
             info[info[i].ordinalNumber].beforeSortIndex = i;
         }
 
-        return zrUtil.map(info, item => {
+        return map(info, item => {
             return {
                 ordinalNumber: item.ordinalNumber,
                 beforeSortIndex: item.beforeSortIndex
@@ -629,7 +630,7 @@ const elementCreator: {
         animationModel, isUpdate, during
     ) {
         const rect = new Rect({
-            shape: zrUtil.extend({}, layout),
+            shape: extend({}, layout),
             z2: 1
         });
         // rect.autoBatch = true;
@@ -674,7 +675,7 @@ const elementCreator: {
         const ShapeClass = (!isRadial && roundCap) ? Sausage : Sector;
 
         const sector = new ShapeClass({
-            shape: zrUtil.defaults({clockwise: clockwise}, layout),
+            shape: defaults({clockwise: clockwise}, layout),
             z2: 1
         });
 
@@ -781,7 +782,6 @@ function updateStyle(
     isPolar: boolean
 ) {
     const style = data.getItemVisual(dataIndex, 'style');
-    const hoverStyle = itemModel.getModel(['emphasis', 'itemStyle']).getItemStyle();
 
     if (!isPolar) {
         (el as Rect).setShape('r', itemModel.get(BAR_BORDER_RADIUS_QUERY) || 0);
@@ -812,10 +812,16 @@ function updateStyle(
             }
         );
     }
+
+    enableHoverEmphasis(el);
+    setStatesStylesFromModel(el, itemModel);
     if (isZeroOnPolar(layout as SectorLayout)) {
-        hoverStyle.fill = hoverStyle.stroke = 'none';
+        each(el.states, (state) => {
+            if (state.style) {
+                state.style.fill = state.style.stroke = 'none';
+            }
+        });
     }
-    enableHoverEmphasis(el, hoverStyle);
 }
 
 // In case width or height are too small.
@@ -973,7 +979,7 @@ function setLargeStyle(
 ) {
     const globalStyle = data.getVisual('style');
 
-    el.useStyle(zrUtil.extend({}, globalStyle));
+    el.useStyle(extend({}, globalStyle));
     // Use stroke instead of fill.
     el.style.fill = null;
     el.style.stroke = globalStyle.fill;
diff --git a/src/chart/bar/BaseBarSeries.ts b/src/chart/bar/BaseBarSeries.ts
index bf40728..9eac179 100644
--- a/src/chart/bar/BaseBarSeries.ts
+++ b/src/chart/bar/BaseBarSeries.ts
@@ -23,8 +23,6 @@ import {
     SeriesOption,
     SeriesOnCartesianOptionMixin,
     SeriesOnPolarOptionMixin,
-    LabelOption,
-    ItemStyleOption,
     ScaleDataValue
 } from '../../util/types';
 import GlobalModel from '../../model/Global';
@@ -32,7 +30,9 @@ import Cartesian2D from '../../coord/cartesian/Cartesian2D';
 import List from '../../data/List';
 
 
-export interface BaseBarSeriesOption extends SeriesOption, SeriesOnCartesianOptionMixin, SeriesOnPolarOptionMixin {
+export interface BaseBarSeriesOption<StateOption> extends SeriesOption<StateOption>,
+    SeriesOnCartesianOptionMixin,
+    SeriesOnPolarOptionMixin {
 
     /**
      * Min height of bar
@@ -68,16 +68,9 @@ export interface BaseBarSeriesOption extends SeriesOption, SeriesOnCartesianOpti
 
     large?: boolean
     largeThreshold?: number
-
-    label?: LabelOption
-    itemStyle?: ItemStyleOption
-    emphasis?: {
-        label?: LabelOption
-        itemStyle?: ItemStyleOption
-    }
 }
 
-class BaseBarSeriesModel<Opts extends BaseBarSeriesOption = BaseBarSeriesOption> extends SeriesModel<Opts> {
+class BaseBarSeriesModel<Opts extends BaseBarSeriesOption<any> = BaseBarSeriesOption<any>> extends SeriesModel<Opts> {
 
     static type = 'series.__base_bar__';
     type = BaseBarSeriesModel.type;
@@ -101,7 +94,7 @@ class BaseBarSeriesModel<Opts extends BaseBarSeriesOption = BaseBarSeriesOption>
         return [NaN, NaN];
     }
 
-    static defaultOption: BaseBarSeriesOption = {
+    static defaultOption: BaseBarSeriesOption<any> = {
         zlevel: 0,
         z: 2,
         coordinateSystem: 'cartesian2d',
@@ -119,10 +112,7 @@ class BaseBarSeriesModel<Opts extends BaseBarSeriesOption = BaseBarSeriesOption>
         large: false,
         largeThreshold: 400,
         progressive: 3e3,
-        progressiveChunkMode: 'mod',
-
-        itemStyle: {},
-        emphasis: {}
+        progressiveChunkMode: 'mod'
     };
 }
 
diff --git a/src/chart/bar/PictorialBarSeries.ts b/src/chart/bar/PictorialBarSeries.ts
index 778ec14..4d5d03c 100644
--- a/src/chart/bar/PictorialBarSeries.ts
+++ b/src/chart/bar/PictorialBarSeries.ts
@@ -24,11 +24,18 @@ import {
     ItemStyleOption,
     LabelOption,
     AnimationOptionMixin,
-    SeriesStackOptionMixin
+    SeriesStackOptionMixin,
+    StatesOptionMixin,
+    OptionDataItemObject
 } from '../../util/types';
 import type Cartesian2D from '../../coord/cartesian/Cartesian2D';
 import { inheritDefaultOption } from '../../util/component';
 
+export interface PictorialBarStateOption {
+    itemStyle?: ItemStyleOption
+    label?: LabelOption
+}
+
 interface PictorialBarSeriesSymbolOption {
     /**
      * Customized bar shape
@@ -82,22 +89,11 @@ interface PictorialBarSeriesSymbolOption {
     symbolPatternSize?: number
 }
 
-type PictorialBarValue = OptionDataValue;
-
 export interface PictorialBarDataItemOption extends PictorialBarSeriesSymbolOption,
     // Pictorial bar support configure animation in each data item.
-    AnimationOptionMixin {
-    name?: string
-
-    value?: PictorialBarValue
-
-    itemStyle?: ItemStyleOption
-    label?: LabelOption
-
-    emphasis?: {
-        itemStyle?: ItemStyleOption
-        label?: LabelOption
-    }
+    AnimationOptionMixin,
+    PictorialBarStateOption, StatesOptionMixin<PictorialBarStateOption>,
+    OptionDataItemObject<OptionDataValue> {
 
     hoverAnimation?: boolean
 
@@ -106,14 +102,20 @@ export interface PictorialBarDataItemOption extends PictorialBarSeriesSymbolOpti
     cursor?: string
 }
 
-export interface PictorialBarSeriesOption extends BaseBarSeriesOption,
+export interface PictorialBarSeriesOption extends BaseBarSeriesOption<PictorialBarStateOption>,
     PictorialBarSeriesSymbolOption,
-    SeriesStackOptionMixin {
+    SeriesStackOptionMixin,
+    PictorialBarStateOption {
+
     type?: 'pictorialBar'
 
     coordinateSystem?: 'cartesian2d'
 
-    data?: (PictorialBarDataItemOption | PictorialBarValue)[]
+    emphasis?: PictorialBarStateOption
+    blur?: PictorialBarStateOption
+    select?: PictorialBarStateOption
+
+    data?: (PictorialBarDataItemOption | OptionDataValue | OptionDataValue[])[]
 
     hoverAnimation?: boolean
 }
diff --git a/src/chart/bar/PictorialBarView.ts b/src/chart/bar/PictorialBarView.ts
index 48a7774..b118edc 100644
--- a/src/chart/bar/PictorialBarView.ts
+++ b/src/chart/bar/PictorialBarView.ts
@@ -34,6 +34,7 @@ import type Axis2D from '../../coord/cartesian/Axis2D';
 import type Element from 'zrender/src/Element';
 import { getDefaultLabel } from '../helper/labelHelper';
 import { PathProps, PathStyleProps } from 'zrender/src/graphic/Path';
+import { setLabelStyle } from '../../label/labelStyle';
 
 
 const BAR_BORDER_WIDTH_QUERY = ['itemStyle', 'borderWidth'] as const;
@@ -928,25 +929,30 @@ function updateCommon(
     const itemModel = symbolMeta.itemModel;
     // Color must be excluded.
     // Because symbol provide setColor individually to set fill and stroke
-    const hoverStyle = itemModel.getModel(['emphasis', 'itemStyle']).getItemStyle();
+    const emphasisStyle = itemModel.getModel(['emphasis', 'itemStyle']).getItemStyle();
+    const blurStyle = itemModel.getModel(['blur', 'itemStyle']).getItemStyle();
+    const selectStyle = itemModel.getModel(['select', 'itemStyle']).getItemStyle();
     const cursorStyle = itemModel.getShallow('cursor');
 
     eachPath(bar, function (path) {
         path.useStyle(symbolMeta.style);
-        graphic.enableHoverEmphasis(path, hoverStyle);
+        graphic.enableHoverEmphasis(path);
+
+        path.ensureState('emphasis').style = emphasisStyle;
+        path.ensureState('blur').style = blurStyle;
+        path.ensureState('select').style = selectStyle;
 
         cursorStyle && (path.cursor = cursorStyle);
         path.z2 = symbolMeta.z2;
     });
 
-    const barRectHoverStyle = {};
     const barPositionOutside = opt.valueDim.posDesc[+(symbolMeta.boundingLength > 0)];
     const barRect = bar.__pictorialBarRect;
 
     const labelModel = itemModel.getModel('label');
     const hoverLabelModel = itemModel.getModel(['emphasis', 'label']);
 
-    graphic.setLabelStyle(
+    setLabelStyle(
         barRect, labelModel, hoverLabelModel,
         {
             labelFetcher: opt.seriesModel,
@@ -957,7 +963,7 @@ function updateCommon(
         }
     );
 
-    graphic.enableHoverEmphasis(barRect, barRectHoverStyle);
+    graphic.enableHoverEmphasis(barRect);
 }
 
 function toIntTimes(times: number) {
diff --git a/src/chart/boxplot/BoxplotSeries.ts b/src/chart/boxplot/BoxplotSeries.ts
index 61f6eb4..9715584 100644
--- a/src/chart/boxplot/BoxplotSeries.ts
+++ b/src/chart/boxplot/BoxplotSeries.ts
@@ -26,27 +26,27 @@ import {
     LayoutOrient,
     ItemStyleOption,
     LabelOption,
-    OptionDataValueNumeric
+    OptionDataValueNumeric,
+    StatesOptionMixin
 } from '../../util/types';
 import type Axis2D from '../../coord/cartesian/Axis2D';
 import Cartesian2D from '../../coord/cartesian/Cartesian2D';
 
 // [min,  Q1,  median (or Q2),  Q3,  max]
 type BoxplotDataValue = OptionDataValueNumeric[];
-export interface BoxplotDataItemOption {
-    value: BoxplotDataValue
 
+
+export interface BoxplotStateOption {
     itemStyle?: ItemStyleOption
     label?: LabelOption
+}
 
-    emphasis?: {
-        itemStyle: ItemStyleOption
-        label?: LabelOption
-    }
-
+export interface BoxplotDataItemOption extends BoxplotStateOption, StatesOptionMixin<BoxplotStateOption> {
+    value: BoxplotDataValue
 }
 
-export interface BoxplotSeriesOption extends SeriesOption, SeriesOnCartesianOptionMixin {
+export interface BoxplotSeriesOption extends SeriesOption<BoxplotStateOption>, BoxplotStateOption,
+    SeriesOnCartesianOptionMixin {
     type?: 'boxplot'
 
     coordinateSystem?: 'cartesian2d'
@@ -58,15 +58,6 @@ export interface BoxplotSeriesOption extends SeriesOption, SeriesOnCartesianOpti
      */
     boxWidth?: (string | number)[]
 
-    itemStyle?: ItemStyleOption
-
-    label?: LabelOption
-
-    emphasis?: {
-        itemStyle: ItemStyleOption
-        label?: LabelOption
-    }
-
     data?: (BoxplotDataValue | BoxplotDataItemOption)[]
 }
 
diff --git a/src/chart/boxplot/BoxplotView.ts b/src/chart/boxplot/BoxplotView.ts
index 21df40f..0ce6c02 100644
--- a/src/chart/boxplot/BoxplotView.ts
+++ b/src/chart/boxplot/BoxplotView.ts
@@ -27,9 +27,6 @@ import ExtensionAPI from '../../ExtensionAPI';
 import List from '../../data/List';
 import { BoxplotItemLayout } from './boxplotLayout';
 
-// Update common properties
-const EMPHASIS_ITEM_STYLE_PATH = ['emphasis', 'itemStyle'] as const;
-
 class BoxplotView extends ChartView {
     static type = 'boxplot';
     type = BoxplotView.type;
@@ -178,15 +175,12 @@ function updateNormalBoxData(
         dataIndex
     );
 
-    const itemModel = data.getItemModel<BoxplotDataItemOption>(dataIndex);
-
     el.useStyle(data.getItemVisual(dataIndex, 'style'));
     el.style.strokeNoScale = true;
 
     el.z2 = 100;
 
-    const hoverStyle = itemModel.getModel(EMPHASIS_ITEM_STYLE_PATH).getItemStyle();
-    graphic.enableHoverEmphasis(el, hoverStyle);
+    graphic.setStatesStylesFromModel(el, data.getItemModel<BoxplotDataItemOption>(dataIndex));
 }
 
 function transInit(points: number[][], dim: number, itemLayout: BoxplotItemLayout) {
diff --git a/src/chart/candlestick/CandlestickSeries.ts b/src/chart/candlestick/CandlestickSeries.ts
index 12454e0..add0a95 100644
--- a/src/chart/candlestick/CandlestickSeries.ts
+++ b/src/chart/candlestick/CandlestickSeries.ts
@@ -29,32 +29,31 @@ import {
     ColorString,
     LabelOption,
     SeriesLargeOptionMixin,
-    OptionDataValueNumeric
+    OptionDataValueNumeric,
+    StatesOptionMixin
 } from '../../util/types';
 import List from '../../data/List';
 import Cartesian2D from '../../coord/cartesian/Cartesian2D';
 import { BrushCommonSelectorsForSeries } from '../../component/brush/selector';
 
 type CandlestickDataValue = OptionDataValueNumeric[];
-export interface CandlestickDataItemOption {
-    value: CandlestickDataValue
-
-    itemStyle?: CandlestickItemStyleOption
-    label?: LabelOption
-
-    emphasis?: {
-        itemStyle: CandlestickItemStyleOption
-        label?: LabelOption
-    }
-
-}
 
 interface CandlestickItemStyleOption extends ItemStyleOption {
     color0?: ZRColor
     borderColor0?: ColorString
 }
+export interface CandlestickStateOption {
+    itemStyle?: CandlestickItemStyleOption
+    label?: LabelOption
+}
+export interface CandlestickDataItemOption extends CandlestickStateOption, StatesOptionMixin<CandlestickStateOption> {
+    value: CandlestickDataValue
+}
 
-export interface CandlestickSeriesOption extends SeriesOption, SeriesOnCartesianOptionMixin, SeriesLargeOptionMixin {
+
+export interface CandlestickSeriesOption extends SeriesOption<CandlestickStateOption>, CandlestickStateOption,
+    SeriesOnCartesianOptionMixin,
+    SeriesLargeOptionMixin {
 
     type?: 'candlestick'
 
@@ -68,14 +67,6 @@ export interface CandlestickSeriesOption extends SeriesOption, SeriesOnCartesian
     barMinWidth?: number | string
     barWidth?: number | string
 
-    itemStyle?: CandlestickItemStyleOption
-    label?: LabelOption
-
-    emphasis?: {
-        itemStyle?: CandlestickItemStyleOption
-        label?: LabelOption
-    }
-
     data?: (CandlestickDataValue | CandlestickDataItemOption)[]
 }
 
diff --git a/src/chart/candlestick/CandlestickView.ts b/src/chart/candlestick/CandlestickView.ts
index 636a0af..c61ba6b 100644
--- a/src/chart/candlestick/CandlestickView.ts
+++ b/src/chart/candlestick/CandlestickView.ts
@@ -31,7 +31,6 @@ import {CandlestickItemLayout} from './candlestickLayout';
 import { CoordinateSystemClipArea } from '../../coord/CoordinateSystem';
 import Model from '../../model/Model';
 
-const EMPHASIS_ITEM_STYLE_PATH = ['emphasis', 'itemStyle'] as const;
 const SKIP_PROPS = ['color', 'borderColor'] as const;
 
 class CandlestickView extends ChartView {
@@ -280,8 +279,7 @@ function setBoxCommon(el: NormalBoxPath, data: List, dataIndex: number, isSimple
 
     el.__simpleBox = isSimpleBox;
 
-    const hoverStyle = itemModel.getModel(EMPHASIS_ITEM_STYLE_PATH).getItemStyle();
-    graphic.enableHoverEmphasis(el, hoverStyle);
+    graphic.setStatesStylesFromModel(el, itemModel);
 }
 
 function transInit(points: number[][], itemLayout: CandlestickItemLayout) {
diff --git a/src/chart/custom.ts b/src/chart/custom.ts
index 6d8ba01..5330c07 100644
--- a/src/chart/custom.ts
+++ b/src/chart/custom.ts
@@ -23,6 +23,7 @@ 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 {getDefaultLabel} from './helper/labelHelper';
 import createListFromArray from './helper/createListFromArray';
 import {getLayoutOnAxis} from '../layout/barGrid';
@@ -1382,14 +1383,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 = graphicUtil.createTextStyle(labelModel, null, opt, false, true);
+        const textStyle = SetLabelStyleOpt.createTextStyle(labelModel, null, opt, false, true);
         textStyle.text = labelModel.getShallow('show')
             ? retrieve2(
                 customSeries.getFormattedLabel(dataIndexInside, NORMAL),
                 getDefaultLabel(data, dataIndexInside)
             )
             : null;
-        const textConfig = graphicUtil.createTextConfig(textStyle, labelModel, opt, false);
+        const textConfig = SetLabelStyleOpt.createTextConfig(textStyle, labelModel, opt, false);
 
         preFetchFromExtra(userProps, itemStyle);
         itemStyle = convertToEC4StyleForCustomSerise(itemStyle, textStyle, textConfig);
@@ -1414,7 +1415,7 @@ function makeRenderItem(
 
         let itemStyle = getItemStyleModel(dataIndexInside, EMPHASIS).getItemStyle();
         const labelModel = getLabelModel(dataIndexInside, EMPHASIS);
-        const textStyle = graphicUtil.createTextStyle(labelModel, null, null, true, true);
+        const textStyle = SetLabelStyleOpt.createTextStyle(labelModel, null, null, true, true);
         textStyle.text = labelModel.getShallow('show')
             ? retrieve3(
                 customSeries.getFormattedLabel(dataIndexInside, EMPHASIS),
@@ -1422,7 +1423,7 @@ function makeRenderItem(
                 getDefaultLabel(data, dataIndexInside)
             )
             : null;
-        const textConfig = graphicUtil.createTextConfig(textStyle, labelModel, null, true);
+        const textConfig = SetLabelStyleOpt.createTextConfig(textStyle, labelModel, null, true);
 
         preFetchFromExtra(userProps, itemStyle);
         itemStyle = convertToEC4StyleForCustomSerise(itemStyle, textStyle, textConfig);
@@ -1501,7 +1502,7 @@ function makeRenderItem(
     function font(
         opt: Parameters<typeof graphicUtil.getFont>[0]
     ): ReturnType<typeof graphicUtil.getFont> {
-        return graphicUtil.getFont(opt, ecModel);
+        return SetLabelStyleOpt.getFont(opt, ecModel);
     }
 }
 
diff --git a/src/chart/effectScatter/EffectScatterSeries.ts b/src/chart/effectScatter/EffectScatterSeries.ts
index e4887c7..9c1d60e 100644
--- a/src/chart/effectScatter/EffectScatterSeries.ts
+++ b/src/chart/effectScatter/EffectScatterSeries.ts
@@ -29,7 +29,8 @@ import {
     SymbolOptionMixin,
     OptionDataValue,
     ItemStyleOption,
-    LabelOption
+    LabelOption,
+    StatesOptionMixin
 } from '../../util/types';
 import GlobalModel from '../../model/Global';
 import List from '../../data/List';
@@ -38,25 +39,25 @@ import { BrushCommonSelectorsForSeries } from '../../component/brush/selector';
 
 type ScatterDataValue = OptionDataValue | OptionDataValue[];
 
-export interface EffectScatterDataItemOption extends SymbolOptionMixin {
-    name?: string
-
-    value?: ScatterDataValue
-
+export interface EffectScatterStateOption {
     itemStyle?: ItemStyleOption
     label?: LabelOption
+}
 
-    emphasis?: {
-        itemStyle?: ItemStyleOption
-        label?: LabelOption
-    }
+export interface EffectScatterDataItemOption extends SymbolOptionMixin,
+    EffectScatterStateOption,
+    StatesOptionMixin<EffectScatterStateOption> {
+    name?: string
+
+    value?: ScatterDataValue
 
     rippleEffect?: SymbolDrawItemModelOption['rippleEffect']
 }
 
-export interface EffectScatterSeriesOption extends SeriesOption,
+export interface EffectScatterSeriesOption extends SeriesOption<EffectScatterStateOption>, EffectScatterStateOption,
     SeriesOnCartesianOptionMixin, SeriesOnPolarOptionMixin, SeriesOnCalendarOptionMixin,
     SeriesOnGeoOptionMixin, SeriesOnSingleOptionMixin, SymbolOptionMixin {
+
     type?: 'effectScatter'
 
     coordinateSystem?: string
diff --git a/src/chart/funnel/FunnelSeries.ts b/src/chart/funnel/FunnelSeries.ts
index 3e3c98f..94565bb 100644
--- a/src/chart/funnel/FunnelSeries.ts
+++ b/src/chart/funnel/FunnelSeries.ts
@@ -30,7 +30,9 @@ import {
     LabelOption,
     LabelLineOption,
     ItemStyleOption,
-    OptionDataValueNumeric
+    OptionDataValueNumeric,
+    StatesOptionMixin,
+    OptionDataItemObject
 } from '../../util/types';
 import GlobalModel from '../../model/Global';
 import List from '../../data/List';
@@ -42,26 +44,21 @@ type FunnelLabelOption = Omit<LabelOption, 'position'> & {
         | 'outer' | 'inner' | 'center' | 'rightTop' | 'rightBottom' | 'leftTop' | 'leftBottom'
 };
 
-export interface FunnelDataItemOption {
-    name?: string
-
-    value?: OptionDataValueNumeric
-
-    itemStyle?: ItemStyleOption & {
-        height?: number | string
-    }
+export interface FunnelStateOption {
+    itemStyle?: ItemStyleOption
     label?: FunnelLabelOption
     labelLine?: LabelLineOption
+}
 
-    emphasis?: {
-        itemStyle?: ItemStyleOption
-        label?: FunnelLabelOption
-        labelLine?: LabelLineOption
+export interface FunnelDataItemOption extends FunnelStateOption, StatesOptionMixin<FunnelStateOption>,
+    OptionDataItemObject<OptionDataValueNumeric> {
+    itemStyle?: ItemStyleOption & {
+        height?: number | string
     }
 }
 
-export interface FunnelSeriesOption
-    extends SeriesOption, BoxLayoutOptionMixin {
+export interface FunnelSeriesOption extends SeriesOption<FunnelStateOption>, FunnelStateOption,
+    BoxLayoutOptionMixin {
     type?: 'funnel'
 
     min?: number
@@ -79,17 +76,7 @@ export interface FunnelSeriesOption
 
     funnelAlign?: HorizontalAlign
 
-    label?: FunnelLabelOption
-    labelLine?: LabelLineOption
-    itemStyle?: ItemStyleOption
-
-    emphasis?: {
-        label?: FunnelLabelOption
-        labelLine?: LabelLineOption
-        itemStyle?: ItemStyleOption
-    }
-
-    data?: OptionDataValueNumeric[] | FunnelDataItemOption[]
+    data?: (OptionDataValueNumeric | OptionDataValueNumeric[] | FunnelDataItemOption)[]
 }
 
 class FunnelSeriesModel extends SeriesModel<FunnelSeriesOption> {
diff --git a/src/chart/funnel/FunnelView.ts b/src/chart/funnel/FunnelView.ts
index 334510d..25fa13c 100644
--- a/src/chart/funnel/FunnelView.ts
+++ b/src/chart/funnel/FunnelView.ts
@@ -26,7 +26,7 @@ import List from '../../data/List';
 import { ColorString, LabelOption } from '../../util/types';
 import Model from '../../model/Model';
 import { setLabelLineStyle } from '../../label/labelGuideHelper';
-import points from '../../layout/points';
+import { setLabelStyle } from '../../label/labelStyle';
 
 const opacityAccessPath = ['itemStyle', 'opacity'] as const;
 
@@ -84,8 +84,7 @@ class FunnelPiece extends graphic.Polygon {
             }, seriesModel, idx);
         }
 
-        const polygonEmphasisState = polygon.ensureState('emphasis');
-        polygonEmphasisState.style = itemModel.getModel(['emphasis', 'itemStyle']).getItemStyle();
+        graphic.setStatesStylesFromModel(polygon, itemModel);
 
         this._updateLabel(data, idx);
 
@@ -110,7 +109,7 @@ class FunnelPiece extends graphic.Polygon {
 
         const visualColor = data.getItemVisual(idx, 'style').fill as ColorString;
 
-        graphic.setLabelStyle(
+        setLabelStyle(
             // position will not be used in setLabelStyle
             labelText, labelModel as Model<LabelOption>, labelHoverModel as Model<LabelOption>,
             {
diff --git a/src/chart/gauge/GaugeSeries.ts b/src/chart/gauge/GaugeSeries.ts
index ab9828f..18c8fb8 100644
--- a/src/chart/gauge/GaugeSeries.ts
+++ b/src/chart/gauge/GaugeSeries.ts
@@ -26,7 +26,8 @@ import {
     ColorString,
     LabelOption,
     ItemStyleOption,
-    OptionDataValueNumeric
+    OptionDataValueNumeric,
+    StatesOptionMixin
 } from '../../util/types';
 import GlobalModel from '../../model/Global';
 import List from '../../data/List';
@@ -47,16 +48,17 @@ interface PointerOption {
     width?: number
 }
 
-export interface GaugeDataItemOption {
+export interface GaugeStateOption {
+    itemStyle?: ItemStyleOption
+}
+
+export interface GaugeDataItemOption extends GaugeStateOption, StatesOptionMixin<GaugeStateOption> {
     name?: string
     value?: OptionDataValueNumeric
-    itemStyle?: ItemStyleOption
-    emphasis?: {
-        itemStyle?: ItemStyleOption
-    }
     pointer?: PointerOption
 }
-export interface GaugeSeriesOption extends SeriesOption, CircleLayoutOptionMixin {
+export interface GaugeSeriesOption extends SeriesOption<GaugeStateOption>, GaugeStateOption,
+    CircleLayoutOptionMixin {
     type?: 'gauge'
 
     // override radius
@@ -102,7 +104,6 @@ export interface GaugeSeriesOption extends SeriesOption, CircleLayoutOptionMixin
     }
 
     pointer?: PointerOption
-    itemStyle?: ItemStyleOption
 
     title?: LabelOption & {
         /**
diff --git a/src/chart/gauge/GaugeView.ts b/src/chart/gauge/GaugeView.ts
index cd766d0..eb09903 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 {createTextStyle} from '../../label/labelStyle';
 import ChartView from '../../view/Chart';
 import {parsePercent, round, linearMap} from '../../util/number';
 import GaugeSeriesModel, { GaugeDataItemOption } from './GaugeSeries';
@@ -256,7 +257,7 @@ class GaugeView extends ChartView {
                 const autoColor = getColor(i / splitNumber);
 
                 group.add(new graphic.Text({
-                    style: graphic.createTextStyle(labelModel, {
+                    style: createTextStyle(labelModel, {
                         text: label,
                         x: unitX * (r - splitLineLen - distance) + cx,
                         y: unitY * (r - splitLineLen - distance) + cy,
@@ -384,9 +385,8 @@ class GaugeView extends ChartView {
                 ));
             }
 
-            graphic.enableHoverEmphasis(
-                pointer, itemModel.getModel(['emphasis', 'itemStyle']).getItemStyle()
-            );
+            graphic.setStatesStylesFromModel(pointer, itemModel);
+            graphic.enableHoverEmphasis(pointer);
         });
 
         this._data = data;
@@ -416,7 +416,7 @@ class GaugeView extends ChartView {
 
             this.group.add(new graphic.Text({
                 silent: true,
-                style: graphic.createTextStyle(titleModel, {
+                style: createTextStyle(titleModel, {
                     x: x,
                     y: y,
                     // FIXME First data name ?
@@ -452,7 +452,7 @@ class GaugeView extends ChartView {
 
             this.group.add(new graphic.Text({
                 silent: true,
-                style: graphic.createTextStyle(detailModel, {
+                style: createTextStyle(detailModel, {
                     x: x,
                     y: y,
                     text: formatLabel(
diff --git a/src/chart/graph/GraphSeries.ts b/src/chart/graph/GraphSeries.ts
index be5c250..817550c 100644
--- a/src/chart/graph/GraphSeries.ts
+++ b/src/chart/graph/GraphSeries.ts
@@ -40,7 +40,8 @@ import {
     BoxLayoutOptionMixin,
     LabelFormatterCallback,
     Dictionary,
-    LineLabelOption
+    LineLabelOption,
+    StatesOptionMixin
 } from '../../util/types';
 import SeriesModel from '../../model/Series';
 import Graph from '../../data/Graph';
@@ -54,18 +55,17 @@ type GraphDataValue = OptionDataValue | OptionDataValue[];
 interface GraphEdgeLineStyleOption extends LineStyleOption {
     curveness: number
 }
-export interface GraphNodeItemOption extends SymbolOptionMixin {
-    id?: string
-    name?: string
-    value?: GraphDataValue
 
+export interface GraphNodeStateOption {
     itemStyle?: ItemStyleOption
     label?: LabelOption
+}
 
-    emphasis?: {
-        itemStyle?: ItemStyleOption
-        label?: LabelOption
-    }
+export interface GraphNodeItemOption extends SymbolOptionMixin, GraphNodeStateOption,
+    GraphNodeStateOption, StatesOptionMixin<GraphNodeStateOption> {
+    id?: string
+    name?: string
+    value?: GraphDataValue
 
     /**
      * Fixed x position
@@ -91,7 +91,11 @@ export interface GraphNodeItemOption extends SymbolOptionMixin {
     focusNodeAdjacency?: boolean
 }
 
-export interface GraphEdgeItemOption {
+export interface GraphEdgeStateOption {
+    lineStyle?: GraphEdgeLineStyleOption
+    label?: LineLabelOption
+}
+export interface GraphEdgeItemOption extends GraphEdgeStateOption, StatesOptionMixin<GraphEdgeStateOption> {
     /**
      * Name or index of source node.
      */
@@ -103,14 +107,6 @@ export interface GraphEdgeItemOption {
 
     value?: number
 
-    lineStyle?: GraphEdgeLineStyleOption
-    label?: LineLabelOption
-
-    emphasis?: {
-        lineStyle?: GraphEdgeLineStyleOption
-        label?: LineLabelOption
-    }
-
     /**
      * Symbol of both line ends
      */
@@ -123,21 +119,14 @@ export interface GraphEdgeItemOption {
     focusNodeAdjacency?: boolean
 }
 
-export interface GraphCategoryItemOption extends SymbolOptionMixin {
+export interface GraphCategoryItemOption extends SymbolOptionMixin,
+    GraphNodeStateOption, StatesOptionMixin<GraphNodeStateOption> {
     name?: string
 
     value?: OptionDataValue
-
-    itemStyle?: ItemStyleOption
-    label?: LabelOption
-
-    emphasis?: {
-        itemStyle?: ItemStyleOption
-        label?: LabelOption
-    }
 }
 
-export interface GraphSeriesOption extends SeriesOption,
+export interface GraphSeriesOption extends SeriesOption<any>,
     SeriesOnCartesianOptionMixin, SeriesOnPolarOptionMixin, SeriesOnCalendarOptionMixin,
     SeriesOnGeoOptionMixin, SeriesOnSingleOptionMixin,
     SymbolOptionMixin,
@@ -190,6 +179,20 @@ export interface GraphSeriesOption extends SeriesOption,
         lineStyle?: LineStyleOption
     }
 
+    blur?: {
+        label?: LabelOption
+        edgeLabel?: LabelOption
+        itemStyle?: ItemStyleOption
+        lineStyle?: LineStyleOption
+    }
+
+    select?: {
+        label?: LabelOption
+        edgeLabel?: LabelOption
+        itemStyle?: ItemStyleOption
+        lineStyle?: LineStyleOption
+    }
+
     // Configuration of circular layout
     circular?: {
         rotateLabel?: boolean
diff --git a/src/chart/graph/GraphView.ts b/src/chart/graph/GraphView.ts
index 33539f1..46d71e5 100644
--- a/src/chart/graph/GraphView.ts
+++ b/src/chart/graph/GraphView.ts
@@ -185,13 +185,6 @@ class GraphView extends ChartView {
             (el as any)[UNFOCUS_ADJACENCY] && el.off('mouseout', (el as any)[UNFOCUS_ADJACENCY]);
 
             if (itemModel.get('focusNodeAdjacency')) {
-                const symbolPath = el.getSymbolPath();
-                const blurState = symbolPath.ensureState('blur');
-                blurState.style = {
-                    // TODO Based on the original opacity.
-                    opacity: 0.1
-                };
-
                 el.on('mouseover', (el as any)[FOCUS_ADJACENCY] = function () {
                     api.dispatchAction({
                         type: 'focusNodeAdjacency',
@@ -213,13 +206,6 @@ class GraphView extends ChartView {
             (el as any)[UNFOCUS_ADJACENCY] && el.off('mouseout', (el as any)[UNFOCUS_ADJACENCY]);
 
             if (edge.getModel<GraphEdgeItemOption>().get('focusNodeAdjacency')) {
-
-                const linePath = el.getLinePath();
-                const blurState = linePath.ensureState('blur');
-                blurState.style = {
-                    opacity: 0.1
-                };
-
                 el.on('mouseover', (el as any)[FOCUS_ADJACENCY] = function () {
                     api.dispatchAction({
                         type: 'focusNodeAdjacency',
diff --git a/src/chart/heatmap/HeatmapSeries.ts b/src/chart/heatmap/HeatmapSeries.ts
index 0cfe55f..affda28 100644
--- a/src/chart/heatmap/HeatmapSeries.ts
+++ b/src/chart/heatmap/HeatmapSeries.ts
@@ -26,7 +26,8 @@ import {
     SeriesOnGeoOptionMixin,
     ItemStyleOption,
     LabelOption,
-    OptionDataValue
+    OptionDataValue,
+    StatesOptionMixin
 } from '../../util/types';
 import GlobalModel from '../../model/Global';
 import List from '../../data/List';
@@ -35,41 +36,29 @@ import type Cartesian2D from '../../coord/cartesian/Cartesian2D';
 import type Calendar from '../../coord/calendar/Calendar';
 
 type HeatmapDataValue = OptionDataValue[];
-export interface HeatmapDataItemOption {
-    value: HeatmapDataValue
 
+export interface HeatmapStateOption {
+    // Available on cartesian2d coordinate system
     itemStyle?: ItemStyleOption
     label?: LabelOption
+}
 
-    emphasis?: {
-        itemStyle: ItemStyleOption
-        label?: LabelOption
-    }
-
+export interface HeatmapDataItemOption extends HeatmapStateOption, StatesOptionMixin<HeatmapStateOption> {
+    value: HeatmapDataValue
 }
 
-export interface HeatmapSeriesOption extends SeriesOption,
+export interface HeatmapSeriesOption extends SeriesOption<HeatmapStateOption>, HeatmapStateOption,
     SeriesOnCartesianOptionMixin, SeriesOnGeoOptionMixin {
     type?: 'heatmap'
 
     coordinateSystem?: 'cartesian2d' | 'geo' | 'calendar'
 
-    // Available on cartesian2d coordinate system
-    itemStyle?: ItemStyleOption
-    label?: LabelOption
-
-    emphasis?: {
-        itemStyle?: ItemStyleOption
-        label?: LabelOption
-    }
-
     // Available on geo coordinate system
     blurSize?: number
     pointSize?: number
     maxOpacity?: number
     minOpacity?: number
 
-
     data?: (HeatmapDataItemOption | HeatmapDataValue)[]
 }
 
diff --git a/src/chart/heatmap/HeatmapView.ts b/src/chart/heatmap/HeatmapView.ts
index 3cfae66..36b1382 100644
--- a/src/chart/heatmap/HeatmapView.ts
+++ b/src/chart/heatmap/HeatmapView.ts
@@ -32,6 +32,7 @@ import { CoordinateSystem, isCoordinateSystemType } from '../../coord/Coordinate
 import { StageHandlerProgressParams, Dictionary, OptionDataValue } from '../../util/types';
 import type Cartesian2D from '../../coord/cartesian/Cartesian2D';
 import type Calendar from '../../coord/calendar/Calendar';
+import { setLabelStyle } from '../../label/labelStyle';
 
 // Coord can be 'geo' 'bmap' 'amap' 'leaflet'...
 interface GeoLikeCoordSys extends CoordinateSystem {
@@ -184,7 +185,9 @@ class HeatmapView extends ChartView {
         const group = this.group;
         const data = seriesModel.getData();
 
-        let hoverStl = seriesModel.getModel(['emphasis', 'itemStyle']).getItemStyle();
+        let emphasisStyle = seriesModel.getModel(['emphasis', 'itemStyle']).getItemStyle();
+        let blurStyle = seriesModel.getModel(['blur', 'itemStyle']).getItemStyle();
+        let selectStyle = seriesModel.getModel(['select', 'itemStyle']).getItemStyle();
         let labelModel = seriesModel.getModel('label');
         let hoverLabelModel = seriesModel.getModel(['emphasis', 'label']);
 
@@ -240,7 +243,10 @@ class HeatmapView extends ChartView {
 
             // Optimization for large datset
             if (data.hasItemOption) {
-                hoverStl = itemModel.getModel(['emphasis', 'itemStyle']).getItemStyle();
+                emphasisStyle = itemModel.getModel(['emphasis', 'itemStyle']).getItemStyle();
+                blurStyle = itemModel.getModel(['blur', 'itemStyle']).getItemStyle();
+                selectStyle = itemModel.getModel(['select', 'itemStyle']).getItemStyle();
+
                 labelModel = itemModel.getModel('label');
                 hoverLabelModel = itemModel.getModel(['emphasis', 'label']);
             }
@@ -251,7 +257,7 @@ class HeatmapView extends ChartView {
                 defaultText = rawValue[2] + '';
             }
 
-            graphic.setLabelStyle(
+            setLabelStyle(
                 rect, labelModel, hoverLabelModel,
                 {
                     labelFetcher: seriesModel,
@@ -260,7 +266,11 @@ class HeatmapView extends ChartView {
                 }
             );
 
-            graphic.enableHoverEmphasis(rect, data.hasItemOption ? hoverStl : zrUtil.extend({}, hoverStl));
+            rect.ensureState('emphasis').style = emphasisStyle;
+            rect.ensureState('blur').style = blurStyle;
+            rect.ensureState('select').style = selectStyle;
+
+            graphic.enableHoverEmphasis(rect);
 
             rect.incremental = incremental;
             // PENDING
diff --git a/src/chart/helper/EffectSymbol.ts b/src/chart/helper/EffectSymbol.ts
index 75769ce..57f6618 100644
--- a/src/chart/helper/EffectSymbol.ts
+++ b/src/chart/helper/EffectSymbol.ts
@@ -19,11 +19,11 @@
 
 import * as zrUtil from 'zrender/src/core/util';
 import {createSymbol} from '../../util/symbol';
-import {Group, Path, enterEmphasis, leaveEmphasis} from '../../util/graphic';
+import {Group, Path, enterEmphasis, leaveEmphasis, enableHoverEmphasis} from '../../util/graphic';
 import {parsePercent} from '../../util/number';
 import SymbolClz from './Symbol';
 import List from '../../data/List';
-import type { ZRColor } from '../../util/types';
+import type { ZRColor, ECElement } from '../../util/types';
 import type Displayable from 'zrender/src/graphic/Displayable';
 import { SymbolDrawItemModelOption } from './SymbolDraw';
 
@@ -218,30 +218,28 @@ class EffectSymbol extends Group {
             this._effectCfg = null;
 
             this.stopEffectAnimation();
-            const symbol = this.childAt(0) as SymbolClz;
-            const onEmphasis = function (this: EffectSymbol) {
-                symbol.highlight();
-                if (effectCfg.showEffectOn !== 'render') {
-                    this.startEffectAnimation(effectCfg);
+
+            (this as ECElement).onStateChange = (fromState, toState) => {
+                if (toState === 'emphasis') {
+                    if (effectCfg.showEffectOn !== 'render') {
+                        this.startEffectAnimation(effectCfg);
+                    }
                 }
-            };
-            const onNormal = function (this: EffectSymbol) {
-                symbol.downplay();
-                if (effectCfg.showEffectOn !== 'render') {
-                    this.stopEffectAnimation();
+                else if (toState === 'normal') {
+                    if (effectCfg.showEffectOn !== 'render') {
+                        this.stopEffectAnimation();
+                    }
                 }
             };
-            this.on('mouseover', onEmphasis, this)
-                .on('mouseout', onNormal, this)
-                .on('emphasis', onEmphasis, this)
-                .on('normal', onNormal, this);
         }
 
         this._effectCfg = effectCfg;
+
+        enableHoverEmphasis(this);
     };
 
     fadeOut(cb: () => void) {
-        this.off('mouseover').off('mouseout').off('emphasis').off('normal');
+        this.off('mouseover').off('mouseout');
         cb && cb();
     };
 
diff --git a/src/chart/helper/Line.ts b/src/chart/helper/Line.ts
index 7ae5b86..b13d510 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 {createTextStyle} from '../../label/labelStyle';
 import {round} from '../../util/number';
 import List from '../../data/List';
 import { ZRTextAlign, ZRTextVerticalAlign, LineLabelOption, ColorString } from '../../util/types';
@@ -191,18 +192,27 @@ class Line extends graphic.Group {
 
         const line = this.childOfName('line') as ECLinePath;
 
-        let hoverLineStyle = seriesScope && seriesScope.hoverLineStyle;
+        let emphasisLineStyle = seriesScope && seriesScope.emphasisLineStyle;
+        let blurLineStyle = seriesScope && seriesScope.blurLineStyle;
+        let selectLineStyle = seriesScope && seriesScope.selectLineStyle;
+
         let labelModel = seriesScope && seriesScope.labelModel;
-        let hoverLabelModel = seriesScope && seriesScope.hoverLabelModel;
+        let emphasisLabelModel = seriesScope && seriesScope.emphasisLabelModel;
+        let blurLabelModel = seriesScope && seriesScope.blurLabelModel;
+        let selectLabelModel = seriesScope && seriesScope.selectLabelModel;
 
         // Optimization for large dataset
         if (!seriesScope || lineData.hasItemOption) {
             const itemModel = lineData.getItemModel<LineDrawModelOption>(idx);
 
-            hoverLineStyle = itemModel.getModel(['emphasis', 'lineStyle']).getLineStyle();
+            emphasisLineStyle = itemModel.getModel(['emphasis', 'lineStyle']).getLineStyle();
+            blurLineStyle = itemModel.getModel(['blur', 'lineStyle']).getLineStyle();
+            selectLineStyle = itemModel.getModel(['select', 'lineStyle']).getLineStyle();
 
             labelModel = itemModel.getModel('label');
-            hoverLabelModel = itemModel.getModel(['emphasis', 'label']);
+            emphasisLabelModel = itemModel.getModel(['emphasis', 'label']);
+            blurLabelModel = itemModel.getModel(['blur', 'label']);
+            selectLabelModel = itemModel.getModel(['select', 'label']);
         }
 
         const lineStyle = lineData.getItemVisual(idx, 'style');
@@ -212,8 +222,9 @@ class Line extends graphic.Group {
         line.style.fill = null;
         line.style.strokeNoScale = true;
 
-        const lineEmphasisState = line.ensureState('emphasis');
-        lineEmphasisState.style = hoverLineStyle;
+        line.ensureState('emphasis').style = emphasisLineStyle;
+        line.ensureState('blur').style = blurLineStyle;
+        line.ensureState('select').style = selectLineStyle;
 
         // Update symbol
         zrUtil.each(SYMBOL_CATEGORIES, function (symbolCategory) {
@@ -226,7 +237,7 @@ class Line extends graphic.Group {
         }, this);
 
         const showLabel = labelModel.getShallow('show');
-        const hoverShowLabel = hoverLabelModel.getShallow('show');
+        const hoverShowLabel = emphasisLabelModel.getShallow('show');
 
         const label = this.childOfName('label') as InnerLineLabel;
         let defaultLabelColor;
@@ -257,7 +268,7 @@ class Line extends graphic.Group {
         // Always set `textStyle` even if `normalStyle.text` is null, because default
         // values have to be set on `normalStyle`.
         if (normalText != null || emphasisText != null) {
-            label.useStyle(graphic.createTextStyle(labelModel, {
+            label.useStyle(createTextStyle(labelModel, {
                 text: normalText as string
             }, {
                 inheritColor: defaultLabelColor
@@ -275,23 +286,23 @@ class Line extends graphic.Group {
             label.__labelDistance = distance;
         }
 
-        const emphasisState = label.ensureState('emphasis');
+        const labelEmphasisState = label.ensureState('emphasis');
         if (emphasisText != null) {
-            emphasisState.ignore = false;
+            labelEmphasisState.ignore = false;
             // Only these properties supported in this emphasis style here.
-            emphasisState.style = {
+            labelEmphasisState.style = {
                 text: emphasisText as string,
-                fill: hoverLabelModel.getTextColor(true),
+                fill: emphasisLabelModel.getTextColor(true),
                 // For merging hover style to normal style, do not use
                 // `hoverLabelModel.getFont()` here.
-                fontStyle: hoverLabelModel.getShallow('fontStyle'),
-                fontWeight: hoverLabelModel.getShallow('fontWeight'),
-                fontSize: hoverLabelModel.getShallow('fontSize'),
-                fontFamily: hoverLabelModel.getShallow('fontFamily')
+                fontStyle: emphasisLabelModel.getShallow('fontStyle'),
+                fontWeight: emphasisLabelModel.getShallow('fontWeight'),
+                fontSize: emphasisLabelModel.getShallow('fontSize'),
+                fontFamily: emphasisLabelModel.getShallow('fontFamily')
             };
         }
         else {
-            emphasisState.ignore = true;
+            labelEmphasisState.ignore = true;
         }
 
         label.ignore = !showLabel && !hoverShowLabel;
diff --git a/src/chart/helper/LineDraw.ts b/src/chart/helper/LineDraw.ts
index d5c5da1..4590a08 100644
--- a/src/chart/helper/LineDraw.ts
+++ b/src/chart/helper/LineDraw.ts
@@ -26,7 +26,8 @@ import {
     LineLabelOption,
     ColorString,
     AnimationOptionMixin,
-    ZRStyleProps
+    ZRStyleProps,
+    StatesOptionMixin
 } from '../../util/types';
 import Displayable from 'zrender/src/graphic/Displayable';
 import Model from '../../model/Model';
@@ -41,14 +42,12 @@ interface LineLikeCtor {
     new(data: List, idx: number, scope?: LineDrawSeriesScope): LineLike
 }
 
-export interface LineDrawModelOption {
+interface LineDrawStateOption {
     lineStyle?: LineStyleOption
     label?: LineLabelOption
-    emphasis?: {
-        lineStyle?: LineStyleOption
-        label?: LineLabelOption
-    }
+}
 
+export interface LineDrawModelOption extends LineDrawStateOption, StatesOptionMixin<LineDrawStateOption> {
     // If has effect
     effect?: {
         show?: boolean
@@ -77,10 +76,15 @@ export interface LineDrawModelOption {
 type ListForLineDraw = List<Model<LineDrawModelOption & AnimationOptionMixin>>;
 
 export interface LineDrawSeriesScope {
-    hoverLineStyle?: ZRStyleProps
+    lineStyle?: ZRStyleProps
+    emphasisLineStyle?: ZRStyleProps
+    blurLineStyle?: ZRStyleProps
+    selectLineStyle?: ZRStyleProps
 
     labelModel?: Model<LineLabelOption>
-    hoverLabelModel?: Model<LineLabelOption>
+    emphasisLabelModel?: Model<LineLabelOption>
+    blurLabelModel?: Model<LineLabelOption>
+    selectLabelModel?: Model<LineLabelOption>
 }
 
 class LineDraw {
@@ -217,13 +221,18 @@ function isEffectObject(el: Displayable) {
     return el.animators && el.animators.length > 0;
 }
 
-function makeSeriesScope(lineData: ListForLineDraw) {
+function makeSeriesScope(lineData: ListForLineDraw): LineDrawSeriesScope {
     const hostModel = lineData.hostModel;
     return {
         lineStyle: hostModel.getModel('lineStyle').getLineStyle(),
-        hoverLineStyle: hostModel.getModel(['emphasis', 'lineStyle']).getLineStyle(),
+        emphasisLineStyle: hostModel.getModel(['emphasis', 'lineStyle']).getLineStyle(),
+        blurLineStyle: hostModel.getModel(['blur', 'lineStyle']).getLineStyle(),
+        selectLineStyle: hostModel.getModel(['select', 'lineStyle']).getLineStyle(),
+
         labelModel: hostModel.getModel('label'),
-        hoverLabelModel: hostModel.getModel(['emphasis', 'label'])
+        emphasisLabelModel: hostModel.getModel(['emphasis', 'label']),
+        blurLabelModel: hostModel.getModel(['blur', 'label']),
+        selectLabelModel: hostModel.getModel(['select', 'label'])
     };
 }
 
diff --git a/src/chart/helper/Polyline.ts b/src/chart/helper/Polyline.ts
index 0e8df66..8527dd6 100644
--- a/src/chart/helper/Polyline.ts
+++ b/src/chart/helper/Polyline.ts
@@ -61,7 +61,7 @@ class Polyline extends graphic.Group {
         const itemModel = lineData.getItemModel<LineDrawModelOption>(idx);
 
 
-        let hoverLineStyle = seriesScope && seriesScope.hoverLineStyle;
+        let hoverLineStyle = seriesScope && seriesScope.emphasisLineStyle;
 
         if (!seriesScope || lineData.hasItemOption) {
             hoverLineStyle = itemModel.getModel(['emphasis', 'lineStyle']).getLineStyle();
diff --git a/src/chart/helper/Symbol.ts b/src/chart/helper/Symbol.ts
index e67e654..41963be 100644
--- a/src/chart/helper/Symbol.ts
+++ b/src/chart/helper/Symbol.ts
@@ -22,20 +22,14 @@ import * as graphic from '../../util/graphic';
 import {parsePercent} from '../../util/number';
 import {getDefaultLabel} from './labelHelper';
 import List from '../../data/List';
-import { DisplayState, ColorString } from '../../util/types';
+import { ColorString } 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 { setLabelStyle } from '../../label/labelStyle';
 
-// Update common properties
-const emphasisStyleAccessPath = ['emphasis', 'itemStyle'] as const;
-const normalLabelAccessPath = ['label'] as const;
-const emphasisLabelAccessPath = ['emphasis', 'label'] as const;
-
-type ECSymbol = ReturnType<typeof createSymbol> & {
-    onStateChange(fromState: DisplayState, toState: DisplayState): void
-};
+type ECSymbol = ReturnType<typeof createSymbol>;
 
 class Symbol extends graphic.Group {
 
@@ -197,10 +191,17 @@ class Symbol extends graphic.Group {
         const symbolPath = this.childAt(0) as ECSymbol;
         const seriesModel = data.hostModel as SeriesModel;
 
-        let hoverItemStyle = seriesScope && seriesScope.hoverItemStyle;
+        let emphasisItemStyle = seriesScope && seriesScope.emphasisItemStyle;
+        let blurItemStyle = seriesScope && seriesScope.blurItemStyle;
+        let selectItemStyle = seriesScope && seriesScope.selectItemStyle;
+
         let symbolOffset = seriesScope && seriesScope.symbolOffset;
+
         let labelModel = seriesScope && seriesScope.labelModel;
-        let hoverLabelModel = seriesScope && seriesScope.hoverLabelModel;
+        let emphasisLabelModel = seriesScope && seriesScope.emphasisLabelModel;
+        let blurLabelModel = seriesScope && seriesScope.blurLabelModel;
+        let selectLabelModel = seriesScope && seriesScope.selectLabelModel;
+
         let hoverAnimation = seriesScope && seriesScope.hoverAnimation;
         let cursorStyle = seriesScope && seriesScope.cursorStyle;
 
@@ -208,12 +209,17 @@ class Symbol extends graphic.Group {
             const itemModel = (seriesScope && seriesScope.itemModel)
                 ? seriesScope.itemModel : data.getItemModel<SymbolDrawItemModelOption>(idx);
 
-            hoverItemStyle = itemModel.getModel(emphasisStyleAccessPath).getItemStyle();
+            emphasisItemStyle = itemModel.getModel(['emphasis', 'itemStyle']).getItemStyle();
+            selectItemStyle = itemModel.getModel(['select', 'itemStyle']).getItemStyle();
+            blurItemStyle = itemModel.getModel(['blur', 'itemStyle']).getItemStyle();
 
             symbolOffset = itemModel.getShallow('symbolOffset');
 
-            labelModel = itemModel.getModel(normalLabelAccessPath);
-            hoverLabelModel = itemModel.getModel(emphasisLabelAccessPath);
+            labelModel = itemModel.getModel(['label']);
+            emphasisLabelModel = itemModel.getModel(['emphasis', 'label']);
+            blurLabelModel = itemModel.getModel(['blur', 'label']);
+            selectLabelModel = itemModel.getModel(['select', 'label']);
+
             hoverAnimation = itemModel.getShallow('hoverAnimation');
             cursorStyle = itemModel.getShallow('cursor');
         }
@@ -258,8 +264,8 @@ class Symbol extends graphic.Group {
 
         const useNameLabel = seriesScope && seriesScope.useNameLabel;
 
-        graphic.setLabelStyle(
-            symbolPath, labelModel, hoverLabelModel,
+        setLabelStyle(
+            symbolPath, labelModel, emphasisLabelModel,
             {
                 labelFetcher: seriesModel,
                 labelDataIndex: idx,
@@ -276,7 +282,9 @@ class Symbol extends graphic.Group {
         this._sizeX = symbolSize[0] / 2;
         this._sizeY = symbolSize[1] / 2;
 
-        symbolPath.ensureState('emphasis').style = hoverItemStyle;
+        symbolPath.ensureState('emphasis').style = emphasisItemStyle;
+        symbolPath.ensureState('select').style = selectItemStyle;
+        symbolPath.ensureState('blur').style = blurItemStyle;
 
         if (hoverAnimation && seriesModel.isAnimationEnabled()) {
             this.ensureState('emphasis');
diff --git a/src/chart/helper/SymbolDraw.ts b/src/chart/helper/SymbolDraw.ts
index 37da3a7..4022416 100644
--- a/src/chart/helper/SymbolDraw.ts
+++ b/src/chart/helper/SymbolDraw.ts
@@ -30,10 +30,12 @@ import {
     ItemStyleOption,
     ZRColor,
     AnimationOptionMixin,
-    ZRStyleProps
+    ZRStyleProps,
+    StatesOptionMixin
 } from '../../util/types';
 import { CoordinateSystemClipArea } from '../../coord/CoordinateSystem';
 import Model from '../../model/Model';
+import { ScatterSeriesOption } from '../scatter/ScatterSeries';
 
 interface UpdateOpt {
     isIgnore?(idx: number): boolean
@@ -78,14 +80,16 @@ interface RippleEffectOption {
     color?: ZRColor
 }
 
-// TODO Separate series and item?
-export interface SymbolDrawItemModelOption extends SymbolOptionMixin<object> {
+interface SymbolDrawStateOption {
     itemStyle?: ItemStyleOption
     label?: LabelOption
-    emphasis?: {
-        itemStyle?: ItemStyleOption
-        label?: LabelOption
-    }
+}
+
+// TODO Separate series and item?
+export interface SymbolDrawItemModelOption extends SymbolOptionMixin<object>,
+    StatesOptionMixin<SymbolDrawStateOption>,
+    SymbolDrawStateOption {
+
     hoverAnimation?: boolean
     cursor?: string
 
@@ -94,11 +98,18 @@ export interface SymbolDrawItemModelOption extends SymbolOptionMixin<object> {
 }
 
 export interface SymbolDrawSeriesScope {
-    hoverItemStyle?: ZRStyleProps
+    emphasisItemStyle?: ZRStyleProps
+    blurItemStyle?: ZRStyleProps
+    selectItemStyle?: ZRStyleProps
+
     symbolRotate?: number
     symbolOffset?: number[]
+
     labelModel?: Model<LabelOption>
-    hoverLabelModel?: Model<LabelOption>
+    emphasisLabelModel?: Model<LabelOption>
+    blurLabelModel?: Model<LabelOption>
+    selectLabelModel?: Model<LabelOption>
+
     hoverAnimation?: boolean
     itemModel?: Model<SymbolDrawItemModelOption>
     symbolInnerColor?: ColorString
@@ -108,14 +119,22 @@ export interface SymbolDrawSeriesScope {
 }
 
 function makeSeriesScope(data: List): SymbolDrawSeriesScope {
-    const seriesModel = data.hostModel;
+    const seriesModel = data.hostModel as Model<ScatterSeriesOption>;
     return {
-        hoverItemStyle: seriesModel.getModel(['emphasis', 'itemStyle']).getItemStyle(),
+        emphasisItemStyle: seriesModel.getModel(['emphasis', 'itemStyle']).getItemStyle(),
+        blurItemStyle: seriesModel.getModel(['blur', 'itemStyle']).getItemStyle(),
+        selectItemStyle: seriesModel.getModel(['select', 'itemStyle']).getItemStyle(),
+
         symbolRotate: seriesModel.get('symbolRotate'),
         symbolOffset: seriesModel.get('symbolOffset'),
         hoverAnimation: seriesModel.get('hoverAnimation'),
+
         labelModel: seriesModel.getModel('label'),
-        hoverLabelModel: seriesModel.getModel(['emphasis', 'label']),
+        emphasisLabelModel: seriesModel.getModel(['emphasis', 'label']),
+        blurLabelModel: seriesModel.getModel(['blur', 'label']),
+        selectLabelModel: seriesModel.getModel(['select', 'label']),
+
+
         cursorStyle: seriesModel.get('cursor')
     };
 }
diff --git a/src/chart/line/LineSeries.ts b/src/chart/line/LineSeries.ts
index d4ad0d5..f02cf71 100644
--- a/src/chart/line/LineSeries.ts
+++ b/src/chart/line/LineSeries.ts
@@ -31,7 +31,8 @@ import {
     AreaStyleOption,
     OptionDataValue,
     SymbolOptionMixin,
-    SeriesSamplingOptionMixin
+    SeriesSamplingOptionMixin,
+    StatesOptionMixin
 } from '../../util/types';
 import List from '../../data/List';
 import type Cartesian2D from '../../coord/cartesian/Cartesian2D';
@@ -39,22 +40,20 @@ import type Polar from '../../coord/polar/Polar';
 
 type LineDataValue = OptionDataValue | OptionDataValue[];
 
-export interface LineDataItemOption extends SymbolOptionMixin {
-    name?: string
-
-    value?: LineDataValue
-
+export interface LineStateOption {
     itemStyle?: ItemStyleOption
     label?: LabelOption
+}
 
-    emphasis?: {
-        itemStyle?: ItemStyleOption
-        label?: LabelOption
-    }
+export interface LineDataItemOption extends SymbolOptionMixin,
+    LineStateOption, StatesOptionMixin<LineStateOption> {
+    name?: string
+
+    value?: LineDataValue
 }
 
 
-export interface LineSeriesOption extends SeriesOption,
+export interface LineSeriesOption extends SeriesOption<LineStateOption>, LineStateOption,
     SeriesOnCartesianOptionMixin,
     SeriesOnPolarOptionMixin,
     SeriesStackOptionMixin,
@@ -73,15 +72,18 @@ export interface LineSeriesOption extends SeriesOption,
 
     lineStyle?: LineStyleOption
 
-    itemStyle?: ItemStyleOption
-
     areaStyle?: AreaStyleOption & {
         origin?: 'auto' | 'start' | 'end'
     }
 
-    emphasis?: {
-        label?: LabelOption
-        itemStyle?: ItemStyleOption
+    emphasis?: LineStateOption & {
+        lineStyle?: LineStyleOption
+        areaStyle?: AreaStyleOption
+    }
+
+    blur?: LineStateOption & {
+        lineStyle?: LineStyleOption
+        areaStyle?: AreaStyleOption
     }
 
     step?: false | 'start' | 'end' | 'middle'
diff --git a/src/chart/lines/LinesSeries.ts b/src/chart/lines/LinesSeries.ts
index 4163ee1..e654ef5 100644
--- a/src/chart/lines/LinesSeries.ts
+++ b/src/chart/lines/LinesSeries.ts
@@ -34,7 +34,8 @@ import {
     SeriesLargeOptionMixin,
     LineStyleOption,
     OptionDataValue,
-    LineLabelOption
+    LineLabelOption,
+    StatesOptionMixin
 } from '../../util/types';
 import GlobalModel from '../../model/Global';
 import type { LineDrawModelOption } from '../helper/LineDraw';
@@ -81,7 +82,12 @@ interface LegacyDataItemOption {
     name: string
 }
 
-export interface LinesDataItemOption {
+export interface LinesStateOption {
+    lineStyle?: LinesLineStyleOption
+    label?: LineLabelOption
+}
+
+export interface LinesDataItemOption extends LinesStateOption, StatesOptionMixin<LinesStateOption> {
     name?: string
 
     fromName?: string
@@ -93,17 +99,9 @@ export interface LinesDataItemOption {
     coords?: LinesCoords
 
     value?: LinesValue
-
-    lineStyle?: LinesLineStyleOption
-    label?: LineLabelOption
-
-    emphasis?: {
-        lineStyle?: LineStyleOption
-        label?: LineLabelOption
-    }
 }
 
-export interface LinesSeriesOption extends SeriesOption,
+export interface LinesSeriesOption extends SeriesOption<LinesStateOption>, LinesStateOption,
     SeriesOnCartesianOptionMixin, SeriesOnGeoOptionMixin, SeriesOnPolarOptionMixin,
     SeriesOnCalendarOptionMixin, SeriesLargeOptionMixin {
 
@@ -128,14 +126,6 @@ export interface LinesSeriesOption extends SeriesOption,
      */
     clip?: boolean
 
-    label?: LineLabelOption
-    lineStyle?: LinesLineStyleOption
-
-    emphasis?: {
-        label?: LineLabelOption
-        lineStyle?: LineStyleOption
-    }
-
     data?: LinesDataItemOption[]
         // Stored as a flat array. In format
         // Points Count(2) | x | y | x | y | Points Count(3) | x |  y | x | y | x | y |
diff --git a/src/chart/map/MapSeries.ts b/src/chart/map/MapSeries.ts
index 8861612..9d5ee1f 100644
--- a/src/chart/map/MapSeries.ts
+++ b/src/chart/map/MapSeries.ts
@@ -35,7 +35,8 @@ import {
     OptionDataItemObject,
     OptionDataValueNumeric,
     ParsedValue,
-    SeriesOnGeoOptionMixin
+    SeriesOnGeoOptionMixin,
+    StatesOptionMixin
 } from '../../util/types';
 import { Dictionary } from 'zrender/src/core/types';
 import GeoModel, { GeoCommonOptionMixin, GeoItemStyleOption } from '../../coord/geo/GeoModel';
@@ -43,23 +44,22 @@ import List from '../../data/List';
 import Model from '../../model/Model';
 import Geo from '../../coord/geo/Geo';
 
-export interface MapDataItemOption extends
-    OptionDataItemObject<OptionDataValueNumeric>,
-    SelectableTarget {
-
+export interface MapStateOption {
     itemStyle?: GeoItemStyleOption
+    // FIXME:TS formatter?
     label?: LabelOption
-
-    emphasis?: {
-        itemStyle?: GeoItemStyleOption
-        label?: LabelOption
-    }
+}
+export interface MapDataItemOption extends MapStateOption, StatesOptionMixin<MapStateOption>,
+    OptionDataItemObject<OptionDataValueNumeric>,
+    SelectableTarget {
+    cursor?: string
 }
 
 export type MapValueCalculationType = 'sum' | 'average' | 'min' | 'max';
 
 export interface MapSeriesOption extends
-    SeriesOption,
+    SeriesOption<MapStateOption>, MapStateOption,
+
     GeoCommonOptionMixin,
     // If `geoIndex` is not specified, a exclusive geo will be
     // created. Otherwise use the specified geo component, and
@@ -73,10 +73,6 @@ export interface MapSeriesOption extends
     coordinateSystem?: string;
     silent?: boolean;
 
-    // FIXME:TS formatter?
-    label?: LabelOption;
-    itemStyle?: GeoItemStyleOption;
-
     tooltip?: SeriesTooltipOption;
 
     // FIXME:TS add marker types
@@ -93,11 +89,6 @@ export interface MapSeriesOption extends
 
     data?: OptionDataValueNumeric[] | OptionDataValueNumeric[][] | MapDataItemOption[]
 
-    emphasis?: {
-        // FIXME:TS formatter?
-        label?: LabelOption;
-        itemStyle?: GeoItemStyleOption;
-    };
 
     nameProperty: string;
 }
@@ -130,7 +121,7 @@ class MapSeries extends SeriesModel<MapSeriesOption> {
         });
         const valueDim = data.mapDimension('value');
         const dataNameMap = zrUtil.createHashMap();
-        const selectTargetList = [];
+        const selectTargetList: MapDataItemOption[] = [];
         const toAppendNames = [] as string[];
 
         for (let i = 0, len = data.count(); i < len; i++) {
@@ -138,7 +129,7 @@ class MapSeries extends SeriesModel<MapSeriesOption> {
             dataNameMap.set(name, true);
             selectTargetList.push({
                 name: name,
-                value: data.get(valueDim, i),
+                value: data.get(valueDim, i) as number,
                 selected: retrieveRawAttr(data, i, 'selected')
             });
         }
diff --git a/src/chart/parallel/ParallelSeries.ts b/src/chart/parallel/ParallelSeries.ts
index 1fd5c8f..dd14cdc 100644
--- a/src/chart/parallel/ParallelSeries.ts
+++ b/src/chart/parallel/ParallelSeries.ts
@@ -28,7 +28,8 @@ import {
     LabelOption,
     SeriesTooltipOption,
     DimensionName,
-    OptionDataValue
+    OptionDataValue,
+    StatesOptionMixin
  } from '../../util/types';
 import GlobalModel from '../../model/Global';
 import List from '../../data/List';
@@ -39,21 +40,17 @@ import ParallelModel from '../../coord/parallel/ParallelModel';
 
 type ParallelSeriesDataValue = OptionDataValue[];
 
-export interface ParallelSeriesDataItemOption {
-
-    value?: ParallelSeriesDataValue[]
-
+export interface ParallelStateOption {
     lineStyle?: LineStyleOption
     label?: LabelOption
+}
 
-    emphasis?: {
-        lineStyle?: LineStyleOption
-        label?: LabelOption
-    }
+export interface ParallelSeriesDataItemOption extends ParallelStateOption, StatesOptionMixin<ParallelStateOption> {
+    value?: ParallelSeriesDataValue[]
 }
 
 export interface ParallelSeriesOption extends
-    SeriesOption,
+    SeriesOption<ParallelStateOption>, ParallelStateOption,
     SeriesEncodeOptionMixin {
 
     type?: 'parallel';
@@ -62,9 +59,6 @@ export interface ParallelSeriesOption extends
     parallelIndex?: number;
     parallelId?: string;
 
-    label?: LabelOption;
-    lineStyle?: LineStyleOption;
-
     inactiveOpacity?: number;
     activeOpacity?: number;
 
@@ -72,11 +66,6 @@ export interface ParallelSeriesOption extends
     realtime?: boolean;
     tooltip?: SeriesTooltipOption;
 
-    emphasis?: {
-        label?: LabelOption;
-        lineStyle?: LineStyleOption;
-    }
-
     data?: (ParallelSeriesDataValue | ParallelSeriesDataItemOption)[]
 }
 
diff --git a/src/chart/parallel/ParallelView.ts b/src/chart/parallel/ParallelView.ts
index e3d5083..659b671 100644
--- a/src/chart/parallel/ParallelView.ts
+++ b/src/chart/parallel/ParallelView.ts
@@ -20,7 +20,7 @@
 import * as graphic from '../../util/graphic';
 import ChartView from '../../view/Chart';
 import List from '../../data/List';
-import ParallelSeriesModel from './ParallelSeries';
+import ParallelSeriesModel, { ParallelSeriesDataItemOption } from './ParallelSeries';
 import GlobalModel from '../../model/Global';
 import ExtensionAPI from '../../ExtensionAPI';
 import { StageHandlerProgressParams, ParsedValue, Payload } from '../../util/types';
@@ -201,6 +201,9 @@ function updateElCommon(
     el.useStyle(data.getItemVisual(dataIndex, 'style'));
     el.style.fill = null;
     seriesScope.smooth && (el.shape.smooth = seriesScope.smooth);
+
+    const itemModel = data.getItemModel<ParallelSeriesDataItemOption>(dataIndex);
+    graphic.setStatesStylesFromModel(el, itemModel, 'lineStyle', 'getLineStyle');
 }
 
 // function simpleDiff(oldData, newData, dimensions) {
diff --git a/src/chart/pie/PieSeries.ts b/src/chart/pie/PieSeries.ts
index de34310..87ce8ac 100644
--- a/src/chart/pie/PieSeries.ts
+++ b/src/chart/pie/PieSeries.ts
@@ -36,11 +36,17 @@ import {
     BoxLayoutOptionMixin,
     OptionDataValueNumeric,
     SeriesEncodeOptionMixin,
-    OptionDataItemObject
+    OptionDataItemObject,
+    StatesOptionMixin
 } from '../../util/types';
 import List from '../../data/List';
 
-
+export interface PieStateOption {
+    // TODO: TYPE Color Callback
+    itemStyle?: ItemStyleOption
+    label?: PieLabelOption
+    labelLine?: PieLabelLineOption
+}
 interface PieLabelOption extends Omit<LabelOption, 'rotate' | 'position'> {
     rotate?: number
     alignTo?: 'none' | 'labelLine' | 'edge'
@@ -61,20 +67,14 @@ interface PieLabelLineOption extends LabelLineOption {
 
 export interface PieDataItemOption extends
     OptionDataItemObject<OptionDataValueNumeric>,
-    SelectableTarget {
-
-    itemStyle?: ItemStyleOption
-    label?: PieLabelOption
-    labelLine?: PieLabelLineOption
+    SelectableTarget,
+    PieStateOption, StatesOptionMixin<PieStateOption> {
 
-    emphasis?: {
-        itemStyle?: ItemStyleOption
-        label?: PieLabelOption
-        labelLine?: PieLabelLineOption
-    }
+    cursor?: string
+    hoverAnimation?: boolean
 }
 export interface PieSeriesOption extends
-    SeriesOption,
+    Omit<SeriesOption<PieStateOption>, 'labelLine'>, PieStateOption,
     DataSelectableOptionMixin,
     CircleLayoutOptionMixin,
     BoxLayoutOptionMixin,
@@ -86,11 +86,6 @@ export interface PieSeriesOption extends
 
     roseType?: 'radius' | 'area'
 
-    // TODO: TYPE Color Callback
-    itemStyle?: ItemStyleOption
-    label?: PieLabelOption
-    labelLine?: PieLabelLineOption
-
     clockwise?: boolean
     startAngle?: number
     minAngle?: number
@@ -104,12 +99,6 @@ export interface PieSeriesOption extends
 
     stillShowZeroSum?: boolean
 
-    emphasis?: {
-        itemStyle?: ItemStyleOption
-        label?: PieLabelOption
-        labelLine?: PieLabelLineOption
-    }
-
     animationType?: 'expansion' | 'scale'
     animationTypeUpdate?: 'transition' | 'expansion'
 
@@ -158,14 +147,14 @@ class PieSeriesModel extends SeriesModel<PieSeriesOption> {
         });
     }
 
-    private _createSelectableList(): SelectableTarget[] {
+    private _createSelectableList(): PieDataItemOption[] {
         const data = this.getRawData();
         const valueDim = data.mapDimension('value');
-        const targetList = [];
+        const targetList: PieDataItemOption[] = [];
         for (let i = 0, len = data.count(); i < len; i++) {
             targetList.push({
                 name: data.getName(i),
-                value: data.get(valueDim, i),
+                value: data.get(valueDim, i) as number,
                 selected: retrieveRawAttr(data, i, 'selected')
             });
         }
diff --git a/src/chart/pie/PieView.ts b/src/chart/pie/PieView.ts
index c4c73af..7d038e2 100644
--- a/src/chart/pie/PieView.ts
+++ b/src/chart/pie/PieView.ts
@@ -19,7 +19,7 @@
 */
 
 
-import * as zrUtil from 'zrender/src/core/util';
+import { extend, curry } from 'zrender/src/core/util';
 import * as graphic from '../../util/graphic';
 import ChartView from '../../view/Chart';
 import GlobalModel from '../../model/Global';
@@ -30,6 +30,7 @@ import PieSeriesModel, {PieDataItemOption, PieSeriesOption} from './PieSeries';
 import labelLayout from './labelLayout';
 import { setLabelLineStyle } from '../../label/labelGuideHelper';
 import Model from '../../model/Model';
+import { setLabelStyle } from '../../label/labelStyle';
 
 function updateDataSelected(
     this: PiePiece,
@@ -76,7 +77,7 @@ class PiePiece extends graphic.Sector {
         const seriesModel = data.hostModel as PieSeriesModel;
         const itemModel = data.getItemModel<PieDataItemOption>(idx);
         const layout = data.getItemLayout(idx);
-        const sectorShape = zrUtil.extend({}, layout);
+        const sectorShape = extend({}, layout);
 
         if (firstCreate) {
             sector.setShape(sectorShape);
@@ -120,39 +121,40 @@ class PiePiece extends graphic.Sector {
         }
 
         sector.useStyle(data.getItemVisual(idx, 'style'));
-        const sectorEmphasisState = sector.ensureState('emphasis');
-        sectorEmphasisState.style = itemModel.getModel(['emphasis', 'itemStyle']).getItemStyle();
+        graphic.setStatesStylesFromModel(sector, itemModel);
 
-        const sectorSelectState = sector.ensureState('select');
         const midAngle = (layout.startAngle + layout.endAngle) / 2;
         const offset = seriesModel.get('selectedOffset');
         const dx = Math.cos(midAngle) * offset;
         const dy = Math.sin(midAngle) * offset;
-        sectorSelectState.x = dx;
-        sectorSelectState.y = dy;
 
         const cursorStyle = itemModel.getShallow('cursor');
         cursorStyle && sector.attr('cursor', cursorStyle);
 
         this._updateLabel(seriesModel, data, idx);
 
-        const emphasisState = sector.ensureState('emphasis');
-        emphasisState.shape = {
+
+        sector.ensureState('emphasis').shape = {
             r: layout.r + (itemModel.get('hoverAnimation') // TODO: Change a name.
                 ? seriesModel.get('hoverOffset') : 0)
         };
+        extend(sector.ensureState('select'), {
+            x: dx,
+            y: dy
+        });
 
         const labelLine = sector.getTextGuideLine();
         const labelText = sector.getTextContent();
 
-        labelLine.states.select = {
-            x: dx, y: dy
-        };
+        extend(labelLine.ensureState('select'), {
+            x: dx,
+            y: dy
+        });
         // TODO: needs dx, dy in zrender?
-        labelText.states.select = {
+        extend(labelText.ensureState('select'), {
             x: dx,
             y: dy
-        };
+        });
 
         graphic.enableHoverEmphasis(this);
 
@@ -176,7 +178,7 @@ class PiePiece extends graphic.Sector {
         const style = data.getItemVisual(idx, 'style');
         const visualColor = style && style.fill as ColorString;
 
-        graphic.setLabelStyle(
+        setLabelStyle(
             sector,
             labelModel as Model<Omit<PieSeriesOption['label'], 'position' | 'rotate'>>, // position / rotate won't be used.
             labelHoverModel as Model<Omit<PieSeriesOption['label'], 'position' | 'rotate'>>,
@@ -253,9 +255,7 @@ class PieView extends ChartView {
 
         const hasAnimation = ecModel.get('animation');
 
-        const onSectorClick = zrUtil.curry(
-            updateDataSelected, this.uid, seriesModel, hasAnimation, api
-        );
+        const onSectorClick = curry(updateDataSelected, this.uid, seriesModel, hasAnimation, api);
 
         const selectedMode = seriesModel.get('selectedMode');
 
diff --git a/src/chart/radar/RadarSeries.ts b/src/chart/radar/RadarSeries.ts
index 05c8dd1..65ffc21 100644
--- a/src/chart/radar/RadarSeries.ts
+++ b/src/chart/radar/RadarSeries.ts
@@ -29,7 +29,9 @@ import {
     SymbolOptionMixin,
     ItemStyleOption,
     AreaStyleOption,
-    OptionDataValue
+    OptionDataValue,
+    StatesOptionMixin,
+    OptionDataItemObject
 } from '../../util/types';
 import GlobalModel from '../../model/Global';
 import List from '../../data/List';
@@ -37,40 +39,26 @@ import Radar from '../../coord/radar/Radar';
 
 type RadarSeriesDataValue = OptionDataValue[];
 
-export interface RadarSeriesDataItemOption extends SymbolOptionMixin {
+export interface RadarSeriesStateOption {
     lineStyle?: LineStyleOption
     areaStyle?: AreaStyleOption
     label?: LabelOption
     itemStyle?: ItemStyleOption
-
-    emphasis?: {
-        lineStyle?: LineStyleOption
-        areaStyle?: AreaStyleOption
-        label?: LabelOption
-        itemStyle?: ItemStyleOption
-    }
-
-    value?: RadarSeriesDataValue
+}
+export interface RadarSeriesDataItemOption extends SymbolOptionMixin,
+    RadarSeriesStateOption, StatesOptionMixin<RadarSeriesStateOption>,
+    OptionDataItemObject<RadarSeriesDataValue> {
 }
 
-export interface RadarSeriesOption extends SeriesOption, SymbolOptionMixin {
+export interface RadarSeriesOption extends SeriesOption<RadarSeriesStateOption>, RadarSeriesStateOption,
+    SymbolOptionMixin {
     type?: 'radar'
     coordinateSystem: 'radar'
 
     radarIndex?: number
     radarId?: string
 
-    lineStyle?: LineStyleOption
-    areaStyle?: AreaStyleOption
-    label?: LabelOption
-    itemStyle?: ItemStyleOption
-
-    emphasis?: {
-        lineStyle?: LineStyleOption
-        areaStyle?: AreaStyleOption
-        label?: LabelOption
-        itemStyle?: ItemStyleOption
-    }
+    data?: RadarSeriesStateOption[]
 }
 
 class RadarSeriesModel extends SeriesModel<RadarSeriesOption> {
diff --git a/src/chart/radar/RadarView.ts b/src/chart/radar/RadarView.ts
index 29bd6fb..39ff302 100644
--- a/src/chart/radar/RadarView.ts
+++ b/src/chart/radar/RadarView.ts
@@ -24,9 +24,10 @@ import ChartView from '../../view/Chart';
 import RadarSeriesModel, { RadarSeriesDataItemOption } from './RadarSeries';
 import ExtensionAPI from '../../ExtensionAPI';
 import List from '../../data/List';
-import { DisplayState, ECElement, ColorString } from '../../util/types';
+import { ColorString } from '../../util/types';
 import GlobalModel from '../../model/Global';
 import { VectorArray } from 'zrender/src/core/vector';
+import { setLabelStyle } from '../../label/labelStyle';
 
 function normalizeSymbolSize(symbolSize: number | number[]) {
     if (!zrUtil.isArray(symbolSize)) {
@@ -195,16 +196,19 @@ class RadarView extends ChartView {
                     }
                 )
             );
-            const polylineEmphasisState = polyline.ensureState('emphasis');
-            polylineEmphasisState.style = itemModel.getModel(['emphasis', 'lineStyle']).getLineStyle();
+
+            graphic.setStatesStylesFromModel(polyline, itemModel, 'lineStyle');
+            graphic.setStatesStylesFromModel(polygon, itemModel, 'areaStyle');
 
             const areaStyleModel = itemModel.getModel('areaStyle');
-            const hoverAreaStyleModel = itemModel.getModel(['emphasis', 'areaStyle']);
             const polygonIgnore = areaStyleModel.isEmpty() && areaStyleModel.parentModel.isEmpty();
-            let hoverPolygonIgnore = hoverAreaStyleModel.isEmpty() && hoverAreaStyleModel.parentModel.isEmpty();
 
-            hoverPolygonIgnore = hoverPolygonIgnore && polygonIgnore;
-            polygon.ignore = polygonIgnore;
+            zrUtil.each(['emphasis', 'select', 'blur'] as const, function (stateName) {
+                const stateModel = itemModel.getModel([stateName, 'areaStyle']);
+                const stateIgnore = stateModel.isEmpty() && stateModel.parentModel.isEmpty();
+                // Won't be ignore if normal state is not ignore.
+                polygon.ensureState(stateName).ignore = stateIgnore && polygonIgnore;
+            });
 
             polygon.useStyle(
                 zrUtil.defaults(
@@ -215,9 +219,6 @@ class RadarView extends ChartView {
                     }
                 )
             );
-            const polygonEmphasisState = polygon.ensureState('emphasis');
-            polygonEmphasisState.style = hoverAreaStyleModel.getAreaStyle();
-
             const itemHoverStyle = itemModel.getModel(['emphasis', 'itemStyle']).getItemStyle();
             const labelModel = itemModel.getModel('label');
             const labelHoverModel = itemModel.getModel(['emphasis', 'label']);
@@ -230,7 +231,7 @@ class RadarView extends ChartView {
                 let defaultText = data.get(data.dimensions[symbolPath.__dimIdx], idx);
                 (defaultText == null || isNaN(defaultText as number)) && (defaultText = '');
 
-                graphic.setLabelStyle(
+                setLabelStyle(
                     symbolPath, labelModel, labelHoverModel,
                     {
                         labelFetcher: data.hostModel,
@@ -242,9 +243,6 @@ class RadarView extends ChartView {
                 );
             });
 
-            (itemGroup as ECElement).onStateChange = function (fromState: DisplayState, toState: DisplayState) {
-                polygon.attr('ignore', toState === 'emphasis' ? hoverPolygonIgnore : polygonIgnore);
-            };
             graphic.enableHoverEmphasis(itemGroup);
         });
 
diff --git a/src/chart/sankey/SankeySeries.ts b/src/chart/sankey/SankeySeries.ts
index 7579be6..f2f2eea 100644
--- a/src/chart/sankey/SankeySeries.ts
+++ b/src/chart/sankey/SankeySeries.ts
@@ -30,24 +30,36 @@ import {
     ItemStyleOption,
     LineStyleOption,
     LayoutOrient,
-    ColorString
+    ColorString,
+    StatesOptionMixin,
+    OptionDataItemObject
 } from '../../util/types';
 import GlobalModel from '../../model/Global';
 import List from '../../data/List';
 import { LayoutRect } from '../../util/layout';
 
-type SankeyDataValue = OptionDataValue | OptionDataValue[];
-
 type FocusNodeAdjacency = boolean | 'inEdges' | 'outEdges' | 'allEdges';
 
+export interface SankeyNodeStateOption {
+    label?: LabelOption
+    itemStyle?: ItemStyleOption
+}
+
+export interface SankeyEdgeStateOption {
+    lineStyle?: SankeyEdgeStyleOption
+}
+
+interface SankeyBothStateOption extends SankeyNodeStateOption, SankeyEdgeStateOption {
+}
+
 interface SankeyEdgeStyleOption extends LineStyleOption {
     curveness?: number
 }
 
-export interface SankeyNodeItemOption {
+export interface SankeyNodeItemOption extends SankeyNodeStateOption,
+    StatesOptionMixin<SankeyNodeStateOption>,
+    OptionDataItemObject<OptionDataValue> {
     id?: string
-    name?: string
-    value?: SankeyDataValue
 
     localX?: number
     localY?: number
@@ -57,16 +69,9 @@ export interface SankeyNodeItemOption {
     draggable?: boolean
 
     focusNodeAdjacency?: FocusNodeAdjacency
-
-    label?: LabelOption
-    itemStyle?: ItemStyleOption
-    emphasis?: {
-        label?: LabelOption
-        itemStyle?: ItemStyleOption
-    }
 }
 
-export interface SankeyEdgeItemOption {
+export interface SankeyEdgeItemOption extends SankeyEdgeStateOption, StatesOptionMixin<SankeyEdgeStateOption> {
     /**
      * Name or index of source node.
      */
@@ -77,18 +82,14 @@ export interface SankeyEdgeItemOption {
     target?: string | number
 
     focusNodeAdjacency?: FocusNodeAdjacency
-
-    lineStyle?: SankeyEdgeStyleOption
-    emphasis?: {
-        lineStyle?: SankeyEdgeStyleOption
-    }
 }
 
 export interface SankeyLevelOption {
     depth: number
 }
 
-export interface SankeySeriesOption extends SeriesOption, BoxLayoutOptionMixin {
+export interface SankeySeriesOption extends SeriesOption<SankeyBothStateOption>, SankeyBothStateOption,
+    BoxLayoutOptionMixin {
     type?: 'sankey'
 
     /**
@@ -123,15 +124,6 @@ export interface SankeySeriesOption extends SeriesOption, BoxLayoutOptionMixin {
 
     nodeAlign?: 'justify' | 'left' | 'right'    // TODO justify should be auto
 
-    label?: LabelOption
-    itemStyle?: ItemStyleOption
-    lineStyle?: SankeyEdgeStyleOption
-    emphasis?: {
-        label?: LabelOption
-        itemStyle?: ItemStyleOption
-        lineStyle?: SankeyEdgeStyleOption
-    }
-
     data?: SankeyNodeItemOption[]
     nodes?: SankeyNodeItemOption[]
 
diff --git a/src/chart/sankey/SankeyView.ts b/src/chart/sankey/SankeyView.ts
index 9c31ab4..9c6d82a 100644
--- a/src/chart/sankey/SankeyView.ts
+++ b/src/chart/sankey/SankeyView.ts
@@ -29,6 +29,7 @@ import { GraphNode, GraphEdge } from '../../data/Graph';
 import { GraphEdgeItemOption } from '../graph/GraphSeries';
 import List from '../../data/List';
 import { RectLike } from 'zrender/src/core/BoundingRect';
+import { setLabelStyle } from '../../label/labelStyle';
 
 interface FocusNodeAdjacencyPayload extends Payload {
     dataIndex?: number
@@ -260,7 +261,7 @@ class SankeyView extends ChartView {
 
             const hoverStyle = itemModel.getModel(['emphasis', 'itemStyle']).getItemStyle();
 
-            graphic.setLabelStyle(
+            setLabelStyle(
                 rect, labelModel, labelHoverModel,
                 {
                     labelFetcher: seriesModel,
@@ -315,11 +316,6 @@ class SankeyView extends ChartView {
             el.unfocusNodeAdjHandler && el.off('mouseout', el.unfocusNodeAdjHandler);
 
             if (itemModel.get('focusNodeAdjacency')) {
-                const blurState = el.ensureState('blur');
-                blurState.style = {
-                    opacity: 0.1
-                };
-
                 el.on('mouseover', el.focusNodeAdjHandler = function () {
                     if (!sankeyView._focusAdjacencyDisabled) {
                         api.dispatchAction({
@@ -345,11 +341,6 @@ class SankeyView extends ChartView {
             el.unfocusNodeAdjHandler && el.off('mouseout', el.unfocusNodeAdjHandler);
 
             if (edgeModel.get('focusNodeAdjacency')) {
-                const blurState = el.ensureState('blur');
-                blurState.style = {
-                    opacity: 0.02
-                };
-
                 el.on('mouseover', el.focusNodeAdjHandler = function () {
                     if (!sankeyView._focusAdjacencyDisabled) {
                         api.dispatchAction({
diff --git a/src/chart/scatter/ScatterSeries.ts b/src/chart/scatter/ScatterSeries.ts
index e6b721b..8f93815 100644
--- a/src/chart/scatter/ScatterSeries.ts
+++ b/src/chart/scatter/ScatterSeries.ts
@@ -31,29 +31,25 @@ import {
     LabelOption,
     SeriesLargeOptionMixin,
     SeriesStackOptionMixin,
-    SymbolOptionMixin
+    SymbolOptionMixin,
+    StatesOptionMixin,
+    OptionDataItemObject
 } from '../../util/types';
 import GlobalModel from '../../model/Global';
 import List from '../../data/List';
 import { BrushCommonSelectorsForSeries } from '../../component/brush/selector';
 
-type ScatterDataValue = OptionDataValue | OptionDataValue[];
-
-export interface ScatterDataItemOption extends SymbolOptionMixin {
-    name?: string
-
-    value?: ScatterDataValue
-
+interface ScatterStateOption {
     itemStyle?: ItemStyleOption
     label?: LabelOption
+}
 
-    emphasis?: {
-        itemStyle?: ItemStyleOption
-        label?: LabelOption
-    }
+export interface ScatterDataItemOption extends SymbolOptionMixin,
+    ScatterStateOption, StatesOptionMixin<ScatterStateOption>,
+    OptionDataItemObject<OptionDataValue> {
 }
 
-export interface ScatterSeriesOption extends SeriesOption,
+export interface ScatterSeriesOption extends SeriesOption<ScatterStateOption>, ScatterStateOption,
     SeriesOnCartesianOptionMixin, SeriesOnPolarOptionMixin, SeriesOnCalendarOptionMixin,
     SeriesOnGeoOptionMixin, SeriesOnSingleOptionMixin,
     SeriesLargeOptionMixin, SeriesStackOptionMixin,
@@ -67,15 +63,7 @@ export interface ScatterSeriesOption extends SeriesOption,
     cursor?: string
     clip?: boolean
 
-    itemStyle?: ItemStyleOption
-    label?: LabelOption
-
-    emphasis?: {
-        itemStyle?: ItemStyleOption
-        label?: LabelOption
-    }
-
-    data?: (ScatterDataItemOption | OptionDataValue)[]
+    data?: (ScatterDataItemOption | OptionDataValue | OptionDataValue[])[]
         | ArrayLike<number> // Can be a flattern array
 }
 
diff --git a/src/chart/sunburst/SunburstPiece.ts b/src/chart/sunburst/SunburstPiece.ts
index efb3125..70aaaa8 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 {createTextStyle} from '../../label/labelStyle';
 import { TreeNode } from '../../data/Tree';
 import SunburstSeriesModel, { SunburstSeriesNodeItemOption, SunburstSeriesOption } from './SunburstSeries';
 import GlobalModel from '../../model/Global';
@@ -111,7 +112,7 @@ class SunburstPiece extends graphic.Sector {
         const normalStyle = node.getVisual('style') as PathStyleProps;
         normalStyle.lineJoin = 'bevel';
 
-        zrUtil.each(['emphasis', 'highlight', 'downplay'] as const, function (stateName) {
+        zrUtil.each(['emphasis', 'blur', 'select'] as const, function (stateName) {
             const state = sector.ensureState(stateName);
             state.style = itemModel.getModel([stateName, 'itemStyle']).getItemStyle();
         });
@@ -164,7 +165,7 @@ class SunburstPiece extends graphic.Sector {
                     n.piece.useState('emphasis', true);
                 }
                 else if (isNodeHighlighted(n, that.node, highlightPolicy)) {
-                    n.piece.useState('highlight', true);
+                    // n.piece.useState('highlight', true);
                 }
                 else if (highlightPolicy !== NodeHighlightPolicy.NONE) {
                     n.piece.useState('downplay', true);
@@ -206,7 +207,7 @@ class SunburstPiece extends graphic.Sector {
         const label = sector.getTextContent();
         const dataIndex = this.node.dataIndex;
 
-        zrUtil.each(['normal', 'emphasis', 'highlight', 'downplay'] as const, (stateName) => {
+        zrUtil.each(['normal', 'emphasis', 'blur', 'select'] as const, (stateName) => {
 
             const labelStateModel = stateName === 'normal' ? itemModel.getModel('label')
                 : itemModel.getModel([stateName, 'label']);
@@ -219,7 +220,7 @@ class SunburstPiece extends graphic.Sector {
                 text = text || this.node.name;
             }
 
-            state.style = graphic.createTextStyle(labelStateModel, {
+            state.style = createTextStyle(labelStateModel, {
             }, null, stateName !== 'normal', true);
             if (text) {
                 state.style.text = text;
diff --git a/src/chart/sunburst/SunburstSeries.ts b/src/chart/sunburst/SunburstSeries.ts
index bc679c9..e690c17 100644
--- a/src/chart/sunburst/SunburstSeries.ts
+++ b/src/chart/sunburst/SunburstSeries.ts
@@ -27,7 +27,9 @@ import {
     LabelOption,
     ItemStyleOption,
     OptionDataValue,
-    CallbackDataParams
+    CallbackDataParams,
+    StatesOptionMixin,
+    OptionDataItemObject
 } from '../../util/types';
 import GlobalModel from '../../model/Global';
 
@@ -46,54 +48,34 @@ interface SunburstDataParams extends CallbackDataParams {
     }[]
 }
 
-export interface SunburstSeriesNodeItemOption {
-    name?: string
+export interface SunburstStateOption {
+    itemStyle?: ItemStyleOption
+    label?: SunburstLabelOption
+}
 
+export interface SunburstSeriesNodeItemOption extends
+    SunburstStateOption, StatesOptionMixin<SunburstStateOption>,
+    OptionDataItemObject<OptionDataValue>
+{
     nodeClick?: 'rootToNode' | 'link'
     // Available when nodeClick is link
     link?: string
     target?: string
 
-    itemStyle?: ItemStyleOption
-    label?: SunburstLabelOption
-    emphasis?: {
-        itemStyle?: ItemStyleOption
-        label?: SunburstLabelOption
-    }
-    highlight?: {
-        itemStyle?: ItemStyleOption
-        label?: SunburstLabelOption
-    }
-    downplay?: {
-        itemStyle?: ItemStyleOption
-        label?: SunburstLabelOption
-    }
-
-    value?: OptionDataValue | OptionDataValue[]
-
     children?: SunburstSeriesNodeItemOption[]
 
     collapsed?: boolean
 
     cursor?: string
 }
-export interface SunburstSeriesLevelOption {
-    itemStyle?: ItemStyleOption
-    label?: SunburstLabelOption
-    emphasis?: {
-        itemStyle?: ItemStyleOption
-        label?: SunburstLabelOption
-    }
+export interface SunburstSeriesLevelOption extends SunburstStateOption, StatesOptionMixin<SunburstStateOption> {
     highlight?: {
         itemStyle?: ItemStyleOption
         label?: SunburstLabelOption
     }
-    downplay?: {
-        itemStyle?: ItemStyleOption
-        label?: SunburstLabelOption
-    }
 }
-export interface SunburstSeriesOption extends SeriesOption, CircleLayoutOptionMixin {
+export interface SunburstSeriesOption extends SeriesOption<SunburstStateOption>, SunburstStateOption,
+    CircleLayoutOptionMixin {
     type?: 'sunburst'
 
     clockwise?: boolean
@@ -114,21 +96,6 @@ export interface SunburstSeriesOption extends SeriesOption, CircleLayoutOptionMi
 
     renderLabelForZeroData?: boolean
 
-    itemStyle?: ItemStyleOption
-    label?: SunburstLabelOption
-    emphasis?: {
-        itemStyle?: ItemStyleOption
-        label?: SunburstLabelOption
-    }
-    highlight?: {
-        itemStyle?: ItemStyleOption
-        label?: SunburstLabelOption
-    }
-    downplay?: {
-        itemStyle?: ItemStyleOption
-        label?: SunburstLabelOption
-    }
-
     levels?: SunburstSeriesLevelOption[]
 
     animationType?: 'expansion' | 'scale'
@@ -139,7 +106,7 @@ export interface SunburstSeriesOption extends SeriesOption, CircleLayoutOptionMi
 interface SunburstSeriesModel {
     getFormattedLabel(
         dataIndex: number,
-        state?: 'emphasis' | 'normal' | 'highlight' | 'downplay'
+        state?: 'emphasis' | 'normal' | 'highlight' | 'blur' | 'select'
     ): string
 }
 class SunburstSeriesModel extends SeriesModel<SunburstSeriesOption> {
@@ -235,12 +202,8 @@ class SunburstSeriesModel extends SeriesModel<SunburstSeriesOption> {
             shadowOffsetY: 0,
             opacity: 1
         },
-        highlight: {
-            itemStyle: {
-                opacity: 1
-            }
-        },
-        downplay: {
+
+        blur: {
             itemStyle: {
                 opacity: 0.5
             },
diff --git a/src/chart/themeRiver/ThemeRiverSeries.ts b/src/chart/themeRiver/ThemeRiverSeries.ts
index 5e28bf2..1b213f3 100644
--- a/src/chart/themeRiver/ThemeRiverSeries.ts
+++ b/src/chart/themeRiver/ThemeRiverSeries.ts
@@ -41,17 +41,17 @@ import Single from '../../coord/single/Single';
 
 const DATA_NAME_INDEX = 2;
 
-// export interface ThemeRiverSeriesDataItemOption {
-//     date: OptionDataValueDate
-//     value: OptionDataValueNumeric
-//     name: string
-// }
-
 interface ThemeRiverSeriesLabelOption extends LabelOption {
     margin?: number
 }
 
-export interface ThemeRiverSeriesOption extends SeriesOption, SeriesOnSingleOptionMixin, BoxLayoutOptionMixin {
+export interface ThemeRiverStateOption {
+    label?: ThemeRiverSeriesLabelOption
+    itemStyle?: ItemStyleOption
+}
+
+export interface ThemeRiverSeriesOption extends SeriesOption<ThemeRiverStateOption>, ThemeRiverStateOption,
+    SeriesOnSingleOptionMixin, BoxLayoutOptionMixin {
     type?: 'themeRiver'
 
     color?: ZRColor[]
@@ -62,15 +62,6 @@ export interface ThemeRiverSeriesOption extends SeriesOption, SeriesOnSingleOpti
      * gap in axis's orthogonal orientation
      */
     boundaryGap: (string | number)[]
-
-    label?: ThemeRiverSeriesLabelOption
-    itemStyle?: ItemStyleOption
-
-    emphasis?: {
-        label?: ThemeRiverSeriesLabelOption
-        itemStyle?: ItemStyleOption
-    }
-
     /**
      * [date, value, name]
      */
diff --git a/src/chart/themeRiver/ThemeRiverView.ts b/src/chart/themeRiver/ThemeRiverView.ts
index 28d1845..0617eab 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 {createTextStyle} from '../../label/labelStyle';
 import {bind, extend} from 'zrender/src/core/util';
 import DataDiffer from '../../data/DataDiffer';
 import ChartView from '../../view/Chart';
@@ -97,7 +98,7 @@ class ThemeRiverView extends ChartView {
             const labelModel = seriesModel.getModel('label');
             const margin = labelModel.get('margin');
 
-            const commonTextStyle = graphic.createTextStyle(labelModel, {
+            const commonTextStyle = createTextStyle(labelModel, {
                 text: labelModel.get('show')
                     ? seriesModel.getFormattedLabel(indices[j - 1], 'normal')
                         || data.getName(indices[j - 1])
@@ -155,10 +156,11 @@ class ThemeRiverView extends ChartView {
                 }, seriesModel);
             }
 
-            const hoverItemStyleModel = seriesModel.getModel(['emphasis', 'itemStyle']);
             polygon.useStyle(style);
 
-            graphic.enableHoverEmphasis(polygon, hoverItemStyleModel.getItemStyle());
+            graphic.setStatesStylesFromModel(polygon, seriesModel);
+
+            graphic.enableHoverEmphasis(polygon);
         }
 
         this._layersSeries = layersSeries;
diff --git a/src/chart/tree/TreeSeries.ts b/src/chart/tree/TreeSeries.ts
index 892e67e..5e68707 100644
--- a/src/chart/tree/TreeSeries.ts
+++ b/src/chart/tree/TreeSeries.ts
@@ -28,7 +28,9 @@ import {
     LineStyleOption,
     ItemStyleOption,
     LabelOption,
-    OptionDataValue
+    OptionDataValue,
+    StatesOptionMixin,
+    OptionDataItemObject
 } from '../../util/types';
 import List from '../../data/List';
 import View from '../../coord/View';
@@ -39,23 +41,18 @@ interface CurveLineStyleOption extends LineStyleOption{
     curveness?: number
 }
 
-export interface TreeSeriesNodeItemOption extends SymbolOptionMixin {
-    name?: string
-
+export interface TreeSeriesStateOption {
     itemStyle?: ItemStyleOption
     /**
      * Line style of the edge between node and it's parent.
      */
-    lineStyle?: LineStyleOption
+    lineStyle?: CurveLineStyleOption
     label?: LabelOption
+}
 
-    emphasis?: {
-        itemStyle?: ItemStyleOption
-        lineStyle?: LineStyleOption
-        label?: LabelOption
-    }
-
-    value?: OptionDataValue | OptionDataValue[]
+export interface TreeSeriesNodeItemOption extends SymbolOptionMixin,
+    TreeSeriesStateOption, StatesOptionMixin<TreeSeriesStateOption>,
+    OptionDataItemObject<OptionDataValue> {
 
     children?: TreeSeriesNodeItemOption[]
 
@@ -65,8 +62,16 @@ export interface TreeSeriesNodeItemOption extends SymbolOptionMixin {
     target?: string
 }
 
+/**
+ * Configuration of leaves nodes.
+ */
+export interface TreeSeriesLeavesOption extends TreeSeriesStateOption, StatesOptionMixin<TreeSeriesStateOption> {
+
+}
+
 export interface TreeSeriesOption extends
-    SeriesOption, SymbolOptionMixin, BoxLayoutOptionMixin, RoamOptionMixin {
+    SeriesOption<TreeSeriesStateOption>, TreeSeriesStateOption,
+    SymbolOptionMixin, BoxLayoutOptionMixin, RoamOptionMixin {
     type?: 'tree'
 
     hoverAnimation?: boolean
@@ -95,34 +100,7 @@ export interface TreeSeriesOption extends
      */
     initialTreeDepth?: number
 
-    /**
-     * Line style of links
-     */
-    lineStyle?: CurveLineStyleOption
-    /**
-     * Item style of nodes
-     */
-    itemStyle?: ItemStyleOption
-    label?: LabelOption
-
-    emphasis?: {
-        lineStyle?: CurveLineStyleOption
-        itemStyle?: ItemStyleOption
-        label?: LabelOption
-    }
-
-    leaves?: {
-        /**
-         * Item style of leave nodes
-         */
-        itemStyle?: ItemStyleOption
-        label?: LabelOption
-
-        emphasis?: {
-            itemStyle?: ItemStyleOption
-            label?: LabelOption
-        }
-    }
+    leaves?: TreeSeriesLeavesOption
 
     data?: TreeSeriesNodeItemOption[]
 }
diff --git a/src/chart/treemap/TreemapSeries.ts b/src/chart/treemap/TreemapSeries.ts
index c61d8d2..81c7907 100644
--- a/src/chart/treemap/TreemapSeries.ts
+++ b/src/chart/treemap/TreemapSeries.ts
@@ -31,7 +31,8 @@ import {
     RoamOptionMixin,
     // OptionDataValue,
     CallbackDataParams,
-    ColorString
+    ColorString,
+    StatesOptionMixin
 } from '../../util/types';
 import GlobalModel from '../../model/Global';
 import { LayoutRect } from '../../util/layout';
@@ -69,6 +70,12 @@ interface TreemapSeriesCallbackDataParams extends CallbackDataParams {
     treePathInfo?: TreePathInfo[]
 }
 
+export interface TreemapStateOption {
+    itemStyle?: TreemapSeriesItemStyleOption
+    label?: TreemapSeriesLabelOption
+    upperLabel?: TreemapSeriesLabelOption
+}
+
 export interface TreemapSeriesVisualOption {
     /**
      * Which dimension will be applied with the visual properties.
@@ -96,33 +103,14 @@ export interface TreemapSeriesVisualOption {
     childrenVisibleMin?: number
 }
 
-
-export interface TreemapSeriesStyleSetOption {
-    itemStyle?: TreemapSeriesItemStyleOption
-    label?: TreemapSeriesLabelOption
-    upperLabel?: TreemapSeriesLabelOption
-
-    emphasis?: {
-        label?: TreemapSeriesLabelOption
-        upperLabel?: TreemapSeriesLabelOption
-        itemStyle?: TreemapSeriesItemStyleOption
-    }
-}
-export interface TreemapSeriesLevelOption extends TreemapSeriesVisualOption, TreemapSeriesStyleSetOption {
-    itemStyle?: TreemapSeriesItemStyleOption
-    label?: TreemapSeriesLabelOption
-    upperLabel?: TreemapSeriesLabelOption
-
-    emphasis?: {
-        label?: TreemapSeriesLabelOption
-        upperLabel?: TreemapSeriesLabelOption
-        itemStyle?: TreemapSeriesItemStyleOption
-    }
+export interface TreemapSeriesLevelOption extends TreemapSeriesVisualOption,
+    TreemapStateOption, StatesOptionMixin<TreemapStateOption> {
 
     color?: ColorString[] | 'none'
 }
 
-export interface TreemapSeriesNodeItemOption extends TreemapSeriesVisualOption, TreemapSeriesStyleSetOption {
+export interface TreemapSeriesNodeItemOption extends TreemapSeriesVisualOption,
+    TreemapStateOption, StatesOptionMixin<TreemapStateOption> {
     id?: string
     name?: string
 
@@ -133,11 +121,10 @@ export interface TreemapSeriesNodeItemOption extends TreemapSeriesVisualOption,
     color?: ColorString[] | 'none'
 }
 
-export interface TreemapSeriesOption extends SeriesOption,
+export interface TreemapSeriesOption extends SeriesOption<TreemapStateOption>, TreemapStateOption,
     BoxLayoutOptionMixin,
     RoamOptionMixin,
-    TreemapSeriesVisualOption,
-    TreemapSeriesStyleSetOption {
+    TreemapSeriesVisualOption {
 
     type?: 'treemap'
 
diff --git a/src/chart/treemap/TreemapView.ts b/src/chart/treemap/TreemapView.ts
index cd5af6a..0712c7f 100644
--- a/src/chart/treemap/TreemapView.ts
+++ b/src/chart/treemap/TreemapView.ts
@@ -49,6 +49,7 @@ import {
 import { ColorString } from '../../util/types';
 import { windowOpen } from '../../util/format';
 import { TextStyleProps } from 'zrender/src/graphic/Text';
+import { setLabelStyle } from '../../label/labelStyle';
 
 const Group = graphic.Group;
 const Rect = graphic.Rect;
@@ -62,7 +63,7 @@ const Z_BASE = 10; // Should bigger than every z.
 const Z_BG = 1;
 const Z_CONTENT = 2;
 
-const getItemStyleEmphasis = makeStyleMapper([
+const getStateItemStyle = makeStyleMapper([
     ['fill', 'color'],
     // `borderColor` and `borderWidth` has been occupied,
     // so use `stroke` to indicate the stroke of the rect.
@@ -75,7 +76,7 @@ const getItemStyleEmphasis = makeStyleMapper([
 ]);
 const getItemStyleNormal = function (model: Model<TreemapSeriesNodeItemOption['itemStyle']>): PathStyleProps {
     // Normal style props should include emphasis style props.
-    const itemStyle = getItemStyleEmphasis(model) as PathStyleProps;
+    const itemStyle = getStateItemStyle(model) as PathStyleProps;
     // Clear styles set by emphasis.
     itemStyle.stroke = itemStyle.fill = itemStyle.lineWidth = null;
     return itemStyle;
@@ -759,6 +760,8 @@ function renderNode(
     const isParent = thisViewChildren && thisViewChildren.length;
     const itemStyleNormalModel = nodeModel.getModel('itemStyle');
     const itemStyleEmphasisModel = nodeModel.getModel(['emphasis', 'itemStyle']);
+    const itemStyleBlurModel = nodeModel.getModel(['blur', 'itemStyle']);
+    const itemStyleSelectModel = nodeModel.getModel(['select', 'itemStyle']);
 
     // End of closure ariables available in "Procedures in renderNode".
     // -----------------------------------------------------------------
@@ -835,11 +838,14 @@ function renderNode(
         else {
             bg.invisible = false;
             const visualBorderColor = thisNode.getVisual('style').stroke;
-            const emphasisBorderColor = itemStyleEmphasisModel.get('borderColor');
             const normalStyle = getItemStyleNormal(itemStyleNormalModel);
             normalStyle.fill = visualBorderColor;
-            const emphasisStyle = getItemStyleEmphasis(itemStyleEmphasisModel);
-            emphasisStyle.fill = emphasisBorderColor;
+            const emphasisStyle = getStateItemStyle(itemStyleEmphasisModel);
+            emphasisStyle.fill = itemStyleEmphasisModel.get('borderColor');
+            const blurStyle = getStateItemStyle(itemStyleBlurModel);
+            blurStyle.fill = itemStyleBlurModel.get('borderColor');
+            const selectStyle = getStateItemStyle(itemStyleSelectModel);
+            selectStyle.fill = itemStyleSelectModel.get('borderColor');
 
             if (useUpperLabel) {
                 const upperLabelWidth = thisWidth - 2 * borderWidth;
@@ -855,7 +861,11 @@ function renderNode(
             }
 
             bg.setStyle(normalStyle);
-            graphic.enableElementHoverEmphasis(bg, emphasisStyle);
+
+            bg.ensureState('emphasis').style = emphasisStyle;
+            bg.ensureState('blur').style = blurStyle;
+            bg.ensureState('select').style = selectStyle;
+            graphic.enableElementHoverEmphasis(bg);
         }
 
         group.add(bg);
@@ -890,12 +900,17 @@ function renderNode(
             const visualColor = thisNode.getVisual('style').fill;
             const normalStyle = getItemStyleNormal(itemStyleNormalModel);
             normalStyle.fill = visualColor;
-            const emphasisStyle = getItemStyleEmphasis(itemStyleEmphasisModel);
+            const emphasisStyle = getStateItemStyle(itemStyleEmphasisModel);
+            const blurStyle = getStateItemStyle(itemStyleBlurModel);
+            const selectStyle = getStateItemStyle(itemStyleSelectModel);
 
             prepareText(content, visualColor, contentWidth, contentHeight);
 
             content.setStyle(normalStyle);
-            graphic.enableElementHoverEmphasis(content, emphasisStyle);
+            content.ensureState('emphasis').style = emphasisStyle;
+            content.ensureState('blur').style = blurStyle;
+            content.ensureState('select').style = selectStyle;
+            graphic.enableElementHoverEmphasis(content);
         }
 
         group.add(content);
@@ -934,7 +949,7 @@ function renderNode(
 
         const isShow = normalLabelModel.getShallow('show');
 
-        graphic.setLabelStyle(
+        setLabelStyle(
             rectEl, normalLabelModel, emphasisLabelModel,
             {
                 defaultText: isShow ? text : null,
diff --git a/src/component/axis/AngleAxisView.ts b/src/component/axis/AngleAxisView.ts
index 0518754..b3d650a 100644
--- a/src/component/axis/AngleAxisView.ts
+++ b/src/component/axis/AngleAxisView.ts
@@ -19,6 +19,7 @@
 
 import * as zrUtil from 'zrender/src/core/util';
 import * as graphic from '../../util/graphic';
+import {createTextStyle} from '../../label/labelStyle';
 import Model from '../../model/Model';
 import AxisView from './AxisView';
 import AxisBuilder from './AxisBuilder';
@@ -259,7 +260,7 @@ const angelAxisElementsBuilders: Record<typeof elementList[number], AngleAxisEle
 
             const textEl = new graphic.Text({
                 silent: AxisBuilder.isLabelSilent(angleAxisModel),
-                style: graphic.createTextStyle(labelModel, {
+                style: createTextStyle(labelModel, {
                     x: p[0],
                     y: p[1],
                     fill: labelModel.getTextColor()
diff --git a/src/component/axis/AxisBuilder.ts b/src/component/axis/AxisBuilder.ts
index ed95b41..bd04a44 100644
--- a/src/component/axis/AxisBuilder.ts
+++ b/src/component/axis/AxisBuilder.ts
@@ -19,6 +19,7 @@
 
 import {retrieve, defaults, extend, each, isObject} from 'zrender/src/core/util';
 import * as graphic from '../../util/graphic';
+import {createTextStyle} from '../../label/labelStyle';
 import Model from '../../model/Model';
 import {isRadianAroundZero, remRadian} from '../../util/number';
 import {createSymbol} from '../../util/symbol';
@@ -427,7 +428,7 @@ const builders: Record<'axisLine' | 'axisTickLabel' | 'axisName', AxisElementsBu
             y: pos[1],
             rotation: labelLayout.rotation,
             silent: AxisBuilder.isLabelSilent(axisModel),
-            style: graphic.createTextStyle(textStyleModel, {
+            style: createTextStyle(textStyleModel, {
                 text: name,
                 font: textFont,
                 overflow: 'truncate',
@@ -774,7 +775,7 @@ function buildAxisLabel(
             rotation: labelLayout.rotation,
             silent: silent,
             z2: 10,
-            style: graphic.createTextStyle(itemLabelModel, {
+            style: createTextStyle(itemLabelModel, {
                 text: formattedLabel,
                 align: itemLabelModel.getShallow('align', true)
                     || labelLayout.textAlign,
diff --git a/src/component/calendar/CalendarView.ts b/src/component/calendar/CalendarView.ts
index 571bd3b..a1cf115 100644
--- a/src/component/calendar/CalendarView.ts
+++ b/src/component/calendar/CalendarView.ts
@@ -19,6 +19,7 @@
 
 import * as zrUtil from 'zrender/src/core/util';
 import * as graphic from '../../util/graphic';
+import {createTextStyle} from '../../label/labelStyle';
 import * as formatUtil from '../../util/format';
 import * as numberUtil from '../../util/number';
 import CalendarModel from '../../coord/calendar/CalendarModel';
@@ -349,7 +350,7 @@ class CalendarView extends ComponentView {
 
         const yearText = new graphic.Text({
             z2: 30,
-            style: graphic.createTextStyle(yearLabel, {
+            style: createTextStyle(yearLabel, {
                 text: content
             })
         });
@@ -450,7 +451,7 @@ class CalendarView extends ComponentView {
             const monthText = new graphic.Text({
                 z2: 30,
                 style: zrUtil.extend(
-                    graphic.createTextStyle(monthLabel, {text: content}),
+                    createTextStyle(monthLabel, {text: content}),
                     this._monthTextPositionControl(tmp, isCenter, orient, pos, margin)
                 )
             });
@@ -535,7 +536,7 @@ class CalendarView extends ComponentView {
             const weekText = new graphic.Text({
                 z2: 30,
                 style: zrUtil.extend(
-                    graphic.createTextStyle(dayLabel, {text: nameMap[day]}),
+                    createTextStyle(dayLabel, {text: nameMap[day]}),
                     this._weekTextPositionControl(point, orient, pos, margin, cellSize)
                 )
             });
diff --git a/src/component/helper/MapDraw.ts b/src/component/helper/MapDraw.ts
index 0d50756..77c4251 100644
--- a/src/component/helper/MapDraw.ts
+++ b/src/component/helper/MapDraw.ts
@@ -35,6 +35,7 @@ import Region from '../../coord/geo/Region';
 import Geo from '../../coord/geo/Geo';
 import Model from '../../model/Model';
 import Transformable from 'zrender/src/core/Transformable';
+import { setLabelStyle } from '../../label/labelStyle';
 
 
 interface RegionsGroup extends graphic.Group {
@@ -161,8 +162,6 @@ class MapDraw {
 
         regionsGroup.removeAll();
 
-        const itemStyleAccessPath = 'itemStyle';
-        const hoverItemStyleAccessPath = ['emphasis', 'itemStyle'] as const;
         const labelAccessPath = 'label';
         const hoverLabelAccessPath = ['emphasis', 'label'] as const;
         const nameMap = zrUtil.createHashMap<RegionsGroup>();
@@ -192,14 +191,20 @@ class MapDraw {
             const regionModel = mapOrGeoModel.getRegionModel(region.name) || mapOrGeoModel;
 
             // @ts-ignore FIXME:TS fix the "compatible with each other"?
-            const itemStyleModel = regionModel.getModel(itemStyleAccessPath);
+            const itemStyleModel = regionModel.getModel('itemStyle');
             // @ts-ignore FIXME:TS fix the "compatible with each other"?
-            const hoverItemStyleModel = regionModel.getModel(hoverItemStyleAccessPath);
+            const emphasisItemStyleModel = regionModel.getModel(['emphasis', 'itemStyle']);
+            // @ts-ignore FIXME:TS fix the "compatible with each other"?
+            const blurItemStyleModel = regionModel.getModel(['blur', 'itemStyle']);
+            // @ts-ignore FIXME:TS fix the "compatible with each other"?
+            const selectItemStyleModel = regionModel.getModel(['select', 'itemStyle']);
 
             // NOTE: DONT use 'style' in visual when drawing map.
             // This component is used for drawing underlying map for both geo component and map series.
             const itemStyle = getFixedItemStyle(itemStyleModel);
-            const hoverItemStyle = getFixedItemStyle(hoverItemStyleModel);
+            const emphasisItemStyle = getFixedItemStyle(emphasisItemStyleModel);
+            const blurItemStyle = getFixedItemStyle(blurItemStyleModel);
+            const selectItemStyle = getFixedItemStyle(selectItemStyleModel);
 
             // @ts-ignore FIXME:TS fix the "compatible with each other"?
             const labelModel = regionModel.getModel(labelAccessPath);
@@ -265,8 +270,9 @@ class MapDraw {
             compoundPath.style.strokeNoScale = true;
             compoundPath.culling = true;
 
-            const compoundPathEmphasisState = compoundPath.ensureState('emphasis');
-            compoundPathEmphasisState.style = hoverItemStyle;
+            compoundPath.ensureState('emphasis').style = emphasisItemStyle;
+            compoundPath.ensureState('blur').style = blurItemStyle;
+            compoundPath.ensureState('select').style = selectItemStyle;
 
             // Label
             const showLabel = labelModel.get('show');
@@ -304,7 +310,7 @@ class MapDraw {
                     silent: true
                 });
 
-                graphic.setLabelStyle<typeof query>(
+                setLabelStyle<typeof query>(
                     textEl, labelModel, hoverLabelModel,
                     {
                         labelFetcher: labelFetcher,
diff --git a/src/component/helper/selectableMixin.ts b/src/component/helper/selectableMixin.ts
index 28a24ff..3f4abef 100644
--- a/src/component/helper/selectableMixin.ts
+++ b/src/component/helper/selectableMixin.ts
@@ -30,7 +30,6 @@ import { Dictionary } from 'zrender/src/core/types';
 export interface SelectableTarget {
     name?: string;
     selected?: boolean;
-    [key: string]: any;
 };
 
 export interface DataSelectableOptionMixin {
diff --git a/src/component/legend/LegendView.ts b/src/component/legend/LegendView.ts
index 4a07bc0..6805e00 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 {setLabelStyle, createTextStyle} from '../../label/labelStyle';
 import {makeBackground} from '../helper/listComponent';
 import * as layoutUtil from '../../util/layout';
 import ComponentView from '../../view/Component';
@@ -312,7 +313,7 @@ class LegendView extends ComponentView {
             const labelModel = legendModel.getModel('selectorLabel');
             const emphasisLabelModel = legendModel.getModel(['emphasis', 'selectorLabel']);
 
-            graphic.setLabelStyle(
+            setLabelStyle(
                 labelText, labelModel, emphasisLabelModel,
                 {
                     defaultText: selectorItem.title
@@ -412,7 +413,7 @@ class LegendView extends ComponentView {
         }
 
         itemGroup.add(new graphic.Text({
-            style: graphic.createTextStyle(textStyleModel, {
+            style: createTextStyle(textStyleModel, {
                 text: content,
                 x: textX,
                 y: itemHeight / 2,
diff --git a/src/component/marker/MarkAreaView.ts b/src/component/marker/MarkAreaView.ts
index 574fc55..383b31f 100644
--- a/src/component/marker/MarkAreaView.ts
+++ b/src/component/marker/MarkAreaView.ts
@@ -38,6 +38,7 @@ import ExtensionAPI from '../../ExtensionAPI';
 import MarkerModel from './MarkerModel';
 import { makeInner } from '../../util/model';
 import { getVisualFromData } from '../../visual/helper';
+import { setLabelStyle } from '../../label/labelStyle';
 
 interface MarkAreaDrawGroup {
     group: graphic.Group
@@ -294,7 +295,7 @@ class MarkAreaView extends MarkerView {
             const style = areaData.getItemVisual(idx, 'style');
             polygon.useStyle(areaData.getItemVisual(idx, 'style'));
 
-            graphic.setLabelStyle(
+            setLabelStyle(
                 polygon, labelModel, labelHoverModel,
                 {
                     labelFetcher: maModel,
diff --git a/src/component/timeline/SliderTimelineView.ts b/src/component/timeline/SliderTimelineView.ts
index 5bced31..792654f 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 { createTextStyle } from '../../label/labelStyle';
 import * as layout from '../../util/layout';
 import TimelineView from './TimelineView';
 import TimelineAxis from './TimelineAxis';
@@ -444,7 +445,7 @@ class SliderTimelineView extends TimelineView {
                 rotation: layoutInfo.labelRotation - layoutInfo.rotation,
                 onclick: bind(this._changeTimeline, this, dataIndex),
                 silent: false,
-                style: graphic.createTextStyle(normalLabelModel, {
+                style: createTextStyle(normalLabelModel, {
                     text: labelItem.formattedLabel,
                     align: layoutInfo.labelAlign,
                     verticalAlign: layoutInfo.labelBaseline
@@ -453,7 +454,7 @@ class SliderTimelineView extends TimelineView {
 
             group.add(textEl);
             graphic.enableHoverEmphasis(
-                textEl, graphic.createTextStyle(hoverLabelModel)
+                textEl, createTextStyle(hoverLabelModel)
             );
 
         }, this);
diff --git a/src/component/title.ts b/src/component/title.ts
index d506b3f..9b41939 100644
--- a/src/component/title.ts
+++ b/src/component/title.ts
@@ -19,6 +19,7 @@
 
 import * as zrUtil from 'zrender/src/core/util';
 import * as graphic from '../util/graphic';
+import {createTextStyle} from '../label/labelStyle';
 import {getLayoutRect} from '../util/layout';
 import ComponentModel from '../model/Component';
 import {
@@ -152,7 +153,7 @@ class TitleView extends ComponentView {
         );
 
         const textEl = new graphic.Text({
-            style: graphic.createTextStyle(textStyleModel, {
+            style: createTextStyle(textStyleModel, {
                 text: titleModel.get('text'),
                 fill: textStyleModel.getTextColor()
             }, {disableBox: true}),
@@ -163,7 +164,7 @@ class TitleView extends ComponentView {
 
         const subText = titleModel.get('subtext');
         const subTextEl = new graphic.Text({
-            style: graphic.createTextStyle(subtextStyleModel, {
+            style: createTextStyle(subtextStyleModel, {
                 text: subText,
                 fill: subtextStyleModel.getTextColor(),
                 y: textRect.height + titleModel.get('itemGap'),
diff --git a/src/coord/geo/GeoModel.ts b/src/coord/geo/GeoModel.ts
index ba8f524..6eb87e0 100644
--- a/src/coord/geo/GeoModel.ts
+++ b/src/coord/geo/GeoModel.ts
@@ -33,7 +33,8 @@ import {
     LabelOption,
     DisplayState,
     RoamOptionMixin,
-    AnimationOptionMixin
+    AnimationOptionMixin,
+    StatesOptionMixin
 } from '../../util/types';
 import { NameMap } from './geoTypes';
 import GlobalModel from '../../model/Global';
@@ -45,18 +46,17 @@ export interface GeoItemStyleOption extends ItemStyleOption {
 interface GeoLabelOption extends LabelOption {
     formatter?: string | ((params: GeoLabelFormatterDataParams) => string);
 }
+export interface GeoStateOption {
+    itemStyle?: GeoItemStyleOption
+    // FIXME:TS formatter?
+    label?: GeoLabelOption
+}
 interface GeoLabelFormatterDataParams {
     name: string;
     status: DisplayState;
 }
 
-export interface RegoinOption extends SelectableTarget {
-    itemStyle?: GeoItemStyleOption;
-    label?: GeoLabelOption;
-    emphasis?: {
-        itemStyle?: GeoItemStyleOption;
-        label?: GeoLabelOption;
-    }
+export interface RegoinOption extends SelectableTarget, GeoStateOption, StatesOptionMixin<GeoStateOption> {
 };
 
 export interface GeoCommonOptionMixin extends RoamOptionMixin {
@@ -87,27 +87,17 @@ export interface GeoOption extends
     DataSelectableOptionMixin,
     // For lens animation on geo.
     AnimationOptionMixin,
-    GeoCommonOptionMixin {
+    GeoCommonOptionMixin,
+    StatesOptionMixin<GeoStateOption>, GeoStateOption {
 
     show?: boolean;
     silent?: boolean;
 
-    itemStyle?: GeoItemStyleOption;
-    label?: GeoLabelOption;
-
-    emphasis?: {
-        itemStyle?: GeoItemStyleOption;
-        label?: GeoLabelOption;
-    };
-
     regions: RegoinOption[];
 
     stateAnimation?: AnimationOptionMixin
 }
 
-const LABEL_FORMATTER_NORMAL = ['label', 'formatter'] as const;
-const LABEL_FORMATTER_EMPHASIS = ['emphasis', 'label', 'formatter'] as const;
-
 class GeoModel extends ComponentModel<GeoOption> {
 
     static type = 'geo';
@@ -220,8 +210,8 @@ class GeoModel extends ComponentModel<GeoOption> {
     getFormattedLabel(name: string, status?: DisplayState) {
         const regionModel = this.getRegionModel(name);
         const formatter = status === 'normal'
-            ? regionModel.get(LABEL_FORMATTER_NORMAL)
-            : regionModel.get(LABEL_FORMATTER_EMPHASIS);
+            ? regionModel.get(['label', 'formatter'])
+            : regionModel.get(['emphasis', 'label', 'formatter']);
         const params = {
             name: name
         } as GeoLabelFormatterDataParams;
diff --git a/src/echarts.ts b/src/echarts.ts
index e0d748a..79649f3 100644
--- a/src/echarts.ts
+++ b/src/echarts.ts
@@ -61,8 +61,7 @@ import {
     ECUnitOption,
     ZRColor,
     ComponentMainType,
-    ComponentSubType,
-    ZRElementEvent
+    ComponentSubType
 } from './util/types';
 import Displayable from 'zrender/src/graphic/Displayable';
 import IncrementalDisplayable from 'zrender/src/graphic/IncrementalDisplayable';
@@ -133,8 +132,9 @@ export const PRIORITY = {
 // dispatchAction with updateMethod "none" in main process.
 // This flag is used to carry out this rule.
 // All events will be triggered out side main process (i.e. when !this[IN_MAIN_PROCESS]).
-const IN_MAIN_PROCESS = '__flagInMainProcess' as const;
-const OPTION_UPDATED = '__optionUpdated' as const;
+const IN_MAIN_PROCESS_KEY = '__flagInMainProcess' as const;
+const OPTION_UPDATED_KEY = '__optionUpdated' as const;
+const STATUS_NEEDS_UPDATE_KEY = '__needsUpdateStatus' as const;
 const ACTION_REG = /^[a-zA-Z0-9_]+$/;
 
 const CONNECT_STATUS_KEY = '__connectUpdateStatus' as const;
@@ -203,6 +203,7 @@ let doDispatchAction: (this: ECharts, payload: Payload, silent: boolean) => void
 let flushPendingActions: (this: ECharts, silent: boolean) => void;
 let triggerUpdatedEvent: (this: ECharts, silent: boolean) => void;
 let bindRenderedEvent: (zr: zrender.ZRenderType, ecIns: ECharts) => void;
+let bindMouseEvent: (zr: zrender.ZRenderType, ecIns: ECharts) => void;
 let clearColorPalette: (ecModel: GlobalModel) => void;
 let render: (ecIns: ECharts, ecModel: GlobalModel, api: ExtensionAPI, payload: Payload) => void;
 let renderComponents: (
@@ -217,7 +218,10 @@ let renderSeries: (
 ) => void;
 let performPostUpdateFuncs: (ecModel: GlobalModel, api: ExtensionAPI) => void;
 let createExtensionAPI: (ecIns: ECharts) => ExtensionAPI;
-let enableConnect: (chart: ECharts) => void;
+let enableConnect: (ecIns: ECharts) => void;
+
+let markStatusToUpdate: (ecIns: ECharts) => void;
+let applyChangedStates: (ecIns: ECharts) => void;
 
 class ECharts extends Eventful {
 
@@ -269,10 +273,10 @@ class ECharts extends Eventful {
 
     private _labelManager: LabelManager;
 
-    private [OPTION_UPDATED]: boolean | {silent: boolean};
-    private [IN_MAIN_PROCESS]: boolean;
+    private [OPTION_UPDATED_KEY]: boolean | {silent: boolean};
+    private [IN_MAIN_PROCESS_KEY]: boolean;
     private [CONNECT_STATUS_KEY]: ConnectStatus;
-
+    private [STATUS_NEEDS_UPDATE_KEY]: boolean;
 
     constructor(
         dom: HTMLElement,
@@ -345,6 +349,8 @@ class ECharts extends Eventful {
 
         bindRenderedEvent(zr, this);
 
+        bindMouseEvent(zr, this);
+
         // ECharts instance can be used as value.
         zrUtil.setAsPrimitive(this);
     }
@@ -354,20 +360,22 @@ class ECharts extends Eventful {
             return;
         }
 
+        applyChangedStates(this);
+
         const scheduler = this._scheduler;
 
         // Lazy update
-        if (this[OPTION_UPDATED]) {
-            const silent = (this[OPTION_UPDATED] as any).silent;
+        if (this[OPTION_UPDATED_KEY]) {
+            const silent = (this[OPTION_UPDATED_KEY] as any).silent;
 
-            this[IN_MAIN_PROCESS] = true;
+            this[IN_MAIN_PROCESS_KEY] = true;
 
             prepare(this);
             updateMethods.update.call(this);
 
-            this[IN_MAIN_PROCESS] = false;
+            this[IN_MAIN_PROCESS_KEY] = false;
 
-            this[OPTION_UPDATED] = false;
+            this[OPTION_UPDATED_KEY] = false;
 
             flushPendingActions.call(this, silent);
 
@@ -444,7 +452,7 @@ class ECharts extends Eventful {
     setOption(option: ECOption, opts?: SetOptionOpts): void;
     setOption(option: ECOption, notMerge?: boolean | SetOptionOpts, lazyUpdate?: boolean): void {
         if (__DEV__) {
-            assert(!this[IN_MAIN_PROCESS], '`setOption` should not be called during main process.');
+            assert(!this[IN_MAIN_PROCESS_KEY], '`setOption` should not be called during main process.');
         }
         if (this._disposed) {
             disposedWarning(this.id);
@@ -458,7 +466,7 @@ class ECharts extends Eventful {
             notMerge = notMerge.notMerge;
         }
 
-        this[IN_MAIN_PROCESS] = true;
+        this[IN_MAIN_PROCESS_KEY] = true;
 
         if (!this._model || notMerge) {
             const optionManager = new OptionManager(this._api);
@@ -471,8 +479,8 @@ class ECharts extends Eventful {
         this._model.setOption(option, optionPreprocessorFuncs);
 
         if (lazyUpdate) {
-            this[OPTION_UPDATED] = {silent: silent};
-            this[IN_MAIN_PROCESS] = false;
+            this[OPTION_UPDATED_KEY] = {silent: silent};
+            this[IN_MAIN_PROCESS_KEY] = false;
         }
         else {
             prepare(this);
@@ -483,8 +491,8 @@ class ECharts extends Eventful {
             // fetched after `setOption`.
             this._zr.flush();
 
-            this[OPTION_UPDATED] = false;
-            this[IN_MAIN_PROCESS] = false;
+            this[OPTION_UPDATED_KEY] = false;
+            this[IN_MAIN_PROCESS_KEY] = false;
 
             flushPendingActions.call(this, silent);
             triggerUpdatedEvent.call(this, silent);
@@ -839,6 +847,7 @@ class ECharts extends Eventful {
         return this._chartsMap[seriesModel.__viewId];
     }
 
+
     private _initEvents(): void {
         each(MOUSE_EVENT_NAMES, function (eveName) {
             const handler = (e: ElementEvent) => {
@@ -975,7 +984,7 @@ class ECharts extends Eventful {
         silent?: boolean // by default false.
     }): void {
         if (__DEV__) {
-            assert(!this[IN_MAIN_PROCESS], '`resize` should not be called during main process.');
+            assert(!this[IN_MAIN_PROCESS_KEY], '`resize` should not be called during main process.');
         }
         if (this._disposed) {
             disposedWarning(this.id);
@@ -997,12 +1006,12 @@ class ECharts extends Eventful {
 
         const silent = opts && opts.silent;
 
-        this[IN_MAIN_PROCESS] = true;
+        this[IN_MAIN_PROCESS_KEY] = true;
 
         optionChanged && prepare(this);
         updateMethods.update.call(this);
 
-        this[IN_MAIN_PROCESS] = false;
+        this[IN_MAIN_PROCESS_KEY] = false;
 
         flushPendingActions.call(this, silent);
 
@@ -1096,7 +1105,7 @@ class ECharts extends Eventful {
         }
 
         // May dispatchAction in rendering procedure
-        if (this[IN_MAIN_PROCESS]) {
+        if (this[IN_MAIN_PROCESS_KEY]) {
             this._pendingActions.push(payload);
             return;
         }
@@ -1489,23 +1498,6 @@ class ECharts extends Eventful {
 
             updateLayout: function (this: ECharts, payload: Payload): void {
                 updateMethods.update.call(this, payload);
-
-                // let ecModel = this._model;
-
-                // // update before setOption
-                // if (!ecModel) {
-                //     return;
-                // }
-
-                // ChartView.markUpdateMethod(payload, 'updateLayout');
-
-                // // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.
-                // // this._scheduler.performVisualTasks(ecModel, payload, 'layout', true);
-                // this._scheduler.performVisualTasks(ecModel, payload, {setDirty: true});
-
-                // render(this, this._model, this._api, payload);
-
-                // performPostUpdateFuncs(ecModel, this._api);
             }
         };
 
@@ -1559,7 +1551,7 @@ class ECharts extends Eventful {
             const updateMethod = cptTypeTmp.pop();
             const cptType = cptTypeTmp[0] != null && parseClassType(cptTypeTmp[0]);
 
-            this[IN_MAIN_PROCESS] = true;
+            this[IN_MAIN_PROCESS_KEY] = true;
 
             let payloads: Payload[] = [payload];
             let batched = false;
@@ -1590,6 +1582,11 @@ class ECharts extends Eventful {
                 if (isHighDown) {
                     // method, payload, mainType, subType
                     updateDirectly(this, updateMethod, batchItem as Payload, 'series');
+
+                    // Mark status to update
+                    // It can only being marked in echarts.ts.
+                    // So there is no chance that chart it self can trigger the highlight itself without action.
+                    markStatusToUpdate(this);
                 }
                 else if (cptType) {
                     updateDirectly(this, updateMethod, batchItem as Payload, cptType.main, cptType.sub);
@@ -1598,11 +1595,11 @@ class ECharts extends Eventful {
 
             if (updateMethod !== 'none' && !isHighDown && !cptType) {
                 // Still dirty
-                if (this[OPTION_UPDATED]) {
+                if (this[OPTION_UPDATED_KEY]) {
                     // FIXME Pass payload ?
                     prepare(this);
                     updateMethods.update.call(this, payload);
-                    this[OPTION_UPDATED] = false;
+                    this[OPTION_UPDATED_KEY] = false;
                 }
                 else {
                     updateMethods[updateMethod as keyof typeof updateMethods].call(this, payload);
@@ -1621,7 +1618,7 @@ class ECharts extends Eventful {
                 eventObj = eventObjBatch[0] as ECEvent;
             }
 
-            this[IN_MAIN_PROCESS] = false;
+            this[IN_MAIN_PROCESS_KEY] = false;
 
             !silent && this._messageCenter.trigger(eventObj.type, eventObj);
         };
@@ -1664,7 +1661,7 @@ class ECharts extends Eventful {
                     // and this checking is called on frame, we also check
                     // animation finished for robustness.
                     zr.animation.isFinished()
-                    && !ecIns[OPTION_UPDATED]
+                    && !ecIns[OPTION_UPDATED_KEY]
                     && !ecIns._scheduler.unfinished
                     && !ecIns._pendingActions.length
                 ) {
@@ -1673,6 +1670,28 @@ class ECharts extends Eventful {
             });
         };
 
+        bindMouseEvent = function (zr: zrender.ZRenderType, ecIns: ECharts): void {
+            function getHighDownDispatcher(target: Element) {
+                while (target && !graphic.isHighDownDispatcher(target)) {
+                    target = target.parent;
+                }
+                return target;
+            }
+            zr.on('mouseover', function (e) {
+                const dispatcher = getHighDownDispatcher(e.target);
+                if (dispatcher) {
+                    markStatusToUpdate(ecIns);
+                    graphic.enterEmphasisWhenMouseOver(dispatcher, e);
+                }
+            }).on('mouseout', function (e) {
+                const dispatcher = getHighDownDispatcher(e.target);
+                if (dispatcher) {
+                    markStatusToUpdate(ecIns);
+                    graphic.leaveEmphasisWhenMouseOut(dispatcher, e);
+                }
+            });
+        };
+
         clearColorPalette = function (ecModel: GlobalModel): void {
             ecModel.clearColorPalette();
             ecModel.eachSeries(function (seriesModel) {
@@ -1708,7 +1727,6 @@ class ECharts extends Eventful {
                 componentView.render(componentModel, ecModel, api, payload);
 
                 updateZ(componentModel, componentView);
-                updateHoverEmphasisHandler(componentView);
 
                 updateStates(componentModel, componentView);
             });
@@ -1758,8 +1776,6 @@ class ECharts extends Eventful {
 
                 updateBlend(seriesModel, chartView);
 
-                updateHoverEmphasisHandler(chartView);
-
                 // Add labels.
                 labelManager.addLabelsOfSeries(chartView);
             });
@@ -1792,6 +1808,47 @@ class ECharts extends Eventful {
             });
         };
 
+        markStatusToUpdate = function (ecIns: ECharts): void {
+            ecIns[STATUS_NEEDS_UPDATE_KEY] = true;
+            // Wake up zrender if it's sleep. Let it update states in the next frame.
+            ecIns.getZr().wakeUp();
+        };
+
+        applyChangedStates = function (ecIns: ECharts): void {
+            if (!ecIns[STATUS_NEEDS_UPDATE_KEY]) {
+                return;
+            }
+
+            ecIns.getZr().storage.traverse(function (el: ECElement) {
+                const newStates = [];
+                const oldStates = el.currentStates;
+
+                // Keep other states.
+                for (let i = 0; i < oldStates.length; i++) {
+                    const stateName = oldStates[i];
+                    if (!(stateName === 'emphasis' || stateName === 'blur' || stateName === 'select')) {
+                        newStates.push(stateName);
+                    }
+                }
+
+                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');
+                    }
+                }
+                else if (el.blurred && el.states.blur) {
+                    newStates.push('blur');
+                }
+                el.useStates(newStates);
+            });
+
+            ecIns[STATUS_NEEDS_UPDATE_KEY] = false;
+        };
+
         function updateHoverLayerStatus(ecIns: ECharts, ecModel: GlobalModel): void {
             const zr = ecIns._zr;
             const storage = zr.storage;
@@ -1949,29 +2006,6 @@ class ECharts extends Eventful {
             });
         };
 
-        function getHighDownDispatcher(target: Element) {
-            while (target && !graphic.isHighDownDispatcher(target)) {
-                target = target.parent;
-            }
-            return target;
-        }
-        function onMouseOver(e: ZRElementEvent) {
-            const dispatcher = getHighDownDispatcher(e.target);
-            if (dispatcher) {
-                graphic.enterEmphasisWhenMouseOver(dispatcher, e);
-            }
-        }
-        function onMouseOut(e: ZRElementEvent) {
-            const dispatcher = getHighDownDispatcher(e.target);
-            if (dispatcher) {
-                graphic.leaveEmphasisWhenMouseOut(dispatcher, e);
-            }
-        }
-        function updateHoverEmphasisHandler(view: ComponentView | ChartView): void {
-            view.group.on('mouseover', onMouseOver)
-                .on('mouseout', onMouseOut);
-        };
-
         createExtensionAPI = function (ecIns: ECharts): ExtensionAPI {
             return new (class extends ExtensionAPI {
                 getCoordinateSystems(): CoordinateSystemMaster[] {
diff --git a/src/label/labelStyle.ts b/src/label/labelStyle.ts
new file mode 100644
index 0000000..0c156d2
--- /dev/null
+++ b/src/label/labelStyle.ts
@@ -0,0 +1,405 @@
+import ZRText, { TextStyleProps } from 'zrender/src/graphic/Text';
+import { Dictionary } from 'zrender/src/core/types';
+import Element, { ElementTextConfig } from 'zrender/src/Element';
+import Model from '../model/Model';
+import { LabelOption, DisplayState, TextCommonOption, ParsedValue, CallbackDataParams } from '../util/types';
+import GlobalModel from '../model/Global';
+import { isFunction, retrieve2, extend, keys, trim } from 'zrender/src/core/util';
+import { TextCommonParams, EMPTY_OBJ } from '../util/graphic';
+
+interface SetLabelStyleOpt<LDI> extends TextCommonParams {
+    defaultText?: string | ((labelDataIndex: LDI, opt: SetLabelStyleOpt<LDI>) => string);
+    // Fetch text by:
+    // opt.labelFetcher.getFormattedLabel(
+    //     opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex, opt.labelProp
+    // )
+    labelFetcher?: {
+        getFormattedLabel: (
+            // In MapDraw case it can be string (region name)
+            labelDataIndex: LDI,
+            status: DisplayState,
+            dataType?: string,
+            labelDimIndex?: number,
+            formatter?: string | ((params: object) => string),
+            extendParams?: Partial<CallbackDataParams>
+        ) => string;
+    };
+    labelDataIndex?: LDI;
+    labelDimIndex?: number;
+}
+type LabelModel = Model<LabelOption & {
+    formatter?: string | ((params: any) => string);
+}>;
+type LabelModelForText = Model<Omit<
+    // Remove
+    LabelOption, 'position' | 'rotate'> & {
+        formatter?: string | ((params: any) => string);
+    }>;
+
+export function getLabelText<LDI>(
+    opt: SetLabelStyleOpt<LDI>,
+    normalModel: LabelModel,
+    emphasisModel: LabelModel,
+    interpolateValues?: ParsedValue | ParsedValue[]
+) {
+    const labelFetcher = opt.labelFetcher;
+    const labelDataIndex = opt.labelDataIndex;
+    const labelDimIndex = opt.labelDimIndex;
+    let baseText;
+    if (labelFetcher) {
+        baseText = labelFetcher.getFormattedLabel(
+            labelDataIndex, 'normal',
+            null,
+            labelDimIndex,
+            normalModel && normalModel.get('formatter'),
+            interpolateValues != null ? {
+                value: interpolateValues
+            } : null
+        );
+    }
+    if (baseText == null) {
+        baseText = isFunction(opt.defaultText) ? opt.defaultText(labelDataIndex, opt) : opt.defaultText;
+    }
+    const emphasisStyleText = retrieve2(labelFetcher
+        ? labelFetcher.getFormattedLabel(
+            labelDataIndex,
+            'emphasis',
+            null,
+            labelDimIndex,
+            emphasisModel && emphasisModel.get('formatter')
+        )
+        : null, baseText);
+    return {
+        normal: baseText,
+        emphasis: emphasisStyleText
+    };
+}
+/**
+ * Set normal styles and emphasis styles about text on target element
+ * If target is a ZRText. It will create a new style object.
+ * If target is other Element. It will create or reuse ZRText which is attached on the target.
+ * And create a new style object.
+ *
+ * NOTICE: Because the style on ZRText will be replaced with new(only x, y are keeped).
+ * So please update the style on ZRText after use this method.
+ */
+// eslint-disable-next-line
+function setLabelStyle<LDI>(targetEl: ZRText, normalModel: LabelModelForText, emphasisModel: LabelModelForText, opt?: SetLabelStyleOpt<LDI>, normalSpecified?: TextStyleProps, emphasisSpecified?: TextStyleProps): void;
+// eslint-disable-next-line
+function setLabelStyle<LDI>(targetEl: Element, normalModel: LabelModel, emphasisModel: LabelModel, opt?: SetLabelStyleOpt<LDI>, normalSpecified?: TextStyleProps, emphasisSpecified?: TextStyleProps): void;
+function setLabelStyle<LDI>(
+    targetEl: Element,
+    normalModel: LabelModel,
+    emphasisModel: LabelModel,
+    opt?: SetLabelStyleOpt<LDI>,
+    normalSpecified?: TextStyleProps,
+    emphasisSpecified?: TextStyleProps
+    // TODO specified position?
+) {
+    opt = opt || EMPTY_OBJ;
+    const isSetOnText = targetEl instanceof ZRText;
+    const showNormal = normalModel.getShallow('show');
+    const showEmphasis = emphasisModel.getShallow('show');
+    let richText = isSetOnText ? targetEl as ZRText : null;
+    if (showNormal || showEmphasis) {
+        if (!isSetOnText) {
+            // Reuse the previous
+            richText = targetEl.getTextContent();
+            if (!richText) {
+                richText = new ZRText();
+                targetEl.setTextContent(richText);
+            }
+        }
+        richText.ignore = !showNormal;
+        const emphasisState = richText.ensureState('emphasis');
+        emphasisState.ignore = !showEmphasis;
+        const normalStyle = createTextStyle(normalModel, normalSpecified, opt, false, !isSetOnText);
+        emphasisState.style = createTextStyle(emphasisModel, emphasisSpecified, opt, true, !isSetOnText);
+        if (!isSetOnText) {
+            // Always create new
+            targetEl.setTextConfig(createTextConfig(normalStyle, normalModel, opt, false));
+            const targetElEmphasisState = targetEl.ensureState('emphasis');
+            targetElEmphasisState.textConfig = createTextConfig(emphasisState.style, emphasisModel, opt, true);
+        }
+        // PENDING: if there is many requirements that emphasis position
+        // need to be different from normal position, we might consider
+        // auto slient is those cases.
+        richText.silent = !!normalModel.getShallow('silent');
+        const labelText = getLabelText(opt, normalModel, emphasisModel);
+        normalStyle.text = labelText.normal;
+        emphasisState.style.text = labelText.emphasis;
+        // Keep x and y
+        if (richText.style.x != null) {
+            normalStyle.x = richText.style.x;
+        }
+        if (richText.style.y != null) {
+            normalStyle.y = richText.style.y;
+        }
+        // Always create new style.
+        richText.useStyle(normalStyle);
+        richText.dirty();
+    }
+    else if (richText) {
+        // Not display rich text.
+        richText.ignore = true;
+    }
+    targetEl.dirty();
+}
+export { setLabelStyle };
+/**
+ * Set basic textStyle properties.
+ */
+export function createTextStyle(textStyleModel: Model, specifiedTextStyle?: TextStyleProps, // Can be overrided by settings in model.
+    opt?: Pick<TextCommonParams, 'inheritColor' | 'disableBox'>, isNotNormal?: boolean, isAttached?: boolean // If text is attached on an element. If so, auto color will handling in zrender.
+) {
+    const textStyle: TextStyleProps = {};
+    setTextStyleCommon(textStyle, textStyleModel, opt, isNotNormal, isAttached);
+    specifiedTextStyle && extend(textStyle, specifiedTextStyle);
+    // textStyle.host && textStyle.host.dirty && textStyle.host.dirty(false);
+    return textStyle;
+}
+export function createTextConfig(textStyle: TextStyleProps,
+    textStyleModel: Model,
+    opt?: Pick<TextCommonParams, 'defaultOutsidePosition' | 'inheritColor'>,
+    isNotNormal?: boolean
+) {
+    opt = opt || {};
+    const textConfig: ElementTextConfig = {};
+    let labelPosition;
+    let labelRotate = textStyleModel.getShallow('rotate');
+    const labelDistance = retrieve2(textStyleModel.getShallow('distance'), isNotNormal ? null : 5);
+    const labelOffset = textStyleModel.getShallow('offset');
+    labelPosition = textStyleModel.getShallow('position')
+        || (isNotNormal ? null : 'inside');
+    // 'outside' is not a valid zr textPostion value, but used
+    // in bar series, and magric type should be considered.
+    labelPosition === 'outside' && (labelPosition = opt.defaultOutsidePosition || 'top');
+    if (labelPosition != null) {
+        textConfig.position = labelPosition;
+    }
+    if (labelOffset != null) {
+        textConfig.offset = labelOffset;
+    }
+    if (labelRotate != null) {
+        labelRotate *= Math.PI / 180;
+        textConfig.rotation = labelRotate;
+    }
+    if (labelDistance != null) {
+        textConfig.distance = labelDistance;
+    }
+    // fill and auto is determined by the color of path fill if it's not specified by developers.
+    textConfig.outsideFill = textStyleModel.get('color') === 'inherit'
+        ? (opt.inheritColor || null)
+        : 'auto';
+    return textConfig;
+}
+/**
+ * The uniform entry of set text style, that is, retrieve style definitions
+ * from `model` and set to `textStyle` object.
+ *
+ * Never in merge mode, but in overwrite mode, that is, all of the text style
+ * properties will be set. (Consider the states of normal and emphasis and
+ * default value can be adopted, merge would make the logic too complicated
+ * to manage.)
+ */
+function setTextStyleCommon(
+    textStyle: TextStyleProps,
+    textStyleModel: Model,
+    opt?: Pick<TextCommonParams, 'inheritColor' | 'disableBox'>,
+    isNotNormal?: boolean,
+    isAttached?: boolean
+) {
+    // Consider there will be abnormal when merge hover style to normal style if given default value.
+    opt = opt || EMPTY_OBJ;
+    const ecModel = textStyleModel.ecModel;
+    const globalTextStyle = ecModel && ecModel.option.textStyle;
+    // Consider case:
+    // {
+    //     data: [{
+    //         value: 12,
+    //         label: {
+    //             rich: {
+    //                 // no 'a' here but using parent 'a'.
+    //             }
+    //         }
+    //     }],
+    //     rich: {
+    //         a: { ... }
+    //     }
+    // }
+    const richItemNames = getRichItemNames(textStyleModel);
+    let richResult: TextStyleProps['rich'];
+    if (richItemNames) {
+        richResult = {};
+        for (const name in richItemNames) {
+            if (richItemNames.hasOwnProperty(name)) {
+                // Cascade is supported in rich.
+                const richTextStyle = textStyleModel.getModel(['rich', name]);
+                // In rich, never `disableBox`.
+                // FIXME: consider `label: {formatter: '{a|xx}', color: 'blue', rich: {a: {}}}`,
+                // the default color `'blue'` will not be adopted if no color declared in `rich`.
+                // That might confuses users. So probably we should put `textStyleModel` as the
+                // root ancestor of the `richTextStyle`. But that would be a break change.
+                setTokenTextStyle(richResult[name] = {}, richTextStyle, globalTextStyle, opt, isNotNormal, isAttached);
+            }
+        }
+    }
+    if (richResult) {
+        textStyle.rich = richResult;
+    }
+    const overflow = textStyleModel.get('overflow');
+    if (overflow) {
+        textStyle.overflow = overflow;
+    }
+    const margin = textStyleModel.get('minMargin');
+    if (margin != null) {
+        textStyle.margin = margin;
+    }
+    setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isNotNormal, isAttached, true);
+}
+// Consider case:
+// {
+//     data: [{
+//         value: 12,
+//         label: {
+//             rich: {
+//                 // no 'a' here but using parent 'a'.
+//             }
+//         }
+//     }],
+//     rich: {
+//         a: { ... }
+//     }
+// }
+// TODO TextStyleModel
+function getRichItemNames(textStyleModel: Model<LabelOption>) {
+    // Use object to remove duplicated names.
+    let richItemNameMap: Dictionary<number>;
+    while (textStyleModel && textStyleModel !== textStyleModel.ecModel) {
+        const rich = (textStyleModel.option || EMPTY_OBJ as LabelOption).rich;
+        if (rich) {
+            richItemNameMap = richItemNameMap || {};
+            const richKeys = keys(rich);
+            for (let i = 0; i < richKeys.length; i++) {
+                const richKey = richKeys[i];
+                richItemNameMap[richKey] = 1;
+            }
+        }
+        textStyleModel = textStyleModel.parentModel;
+    }
+    return richItemNameMap;
+}
+const TEXT_PROPS_WITH_GLOBAL = [
+    'fontStyle', 'fontWeight', 'fontSize', 'fontFamily', 'opacity',
+    'textShadowColor', 'textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY'
+] as const;
+const TEXT_PROPS_SELF = [
+    'align', 'lineHeight', 'width', 'height', 'tag', 'verticalAlign'
+] as const;
+const TEXT_PROPS_BOX = [
+    'padding', 'borderWidth', 'borderRadius',
+    'backgroundColor', 'borderColor',
+    'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY'
+] as const;
+
+function setTokenTextStyle(
+    textStyle: TextStyleProps['rich'][string],
+    textStyleModel: Model<LabelOption>,
+    globalTextStyle: LabelOption,
+    opt?: Pick<TextCommonParams, 'inheritColor' | 'disableBox'>,
+    isNotNormal?: boolean,
+    isAttached?: boolean,
+    isBlock?: boolean
+) {
+    // In merge mode, default value should not be given.
+    globalTextStyle = !isNotNormal && globalTextStyle || EMPTY_OBJ;
+    const inheritColor = opt && opt.inheritColor;
+    let fillColor = textStyleModel.getShallow('color');
+    let strokeColor = textStyleModel.getShallow('textBorderColor');
+    if (fillColor === 'inherit') {
+        if (inheritColor) {
+            fillColor = inheritColor;
+        }
+        else {
+            fillColor = null;
+        }
+    }
+    if (strokeColor === 'inherit' && inheritColor) {
+        if (inheritColor) {
+            strokeColor = inheritColor;
+        }
+        else {
+            strokeColor = inheritColor;
+        }
+    }
+    fillColor = fillColor || globalTextStyle.color;
+    strokeColor = strokeColor || globalTextStyle.textBorderColor;
+    if (fillColor != null) {
+        textStyle.fill = fillColor;
+    }
+    if (strokeColor != null) {
+        textStyle.stroke = strokeColor;
+    }
+    const lineWidth = retrieve2(textStyleModel.getShallow('textBorderWidth'), globalTextStyle.textBorderWidth);
+    if (lineWidth != null) {
+        textStyle.lineWidth = lineWidth;
+    }
+    // TODO
+    if (!isNotNormal && !isAttached) {
+        // Set default finally.
+        if (textStyle.fill == null && opt.inheritColor) {
+            textStyle.fill = opt.inheritColor;
+        }
+    }
+    // Do not use `getFont` here, because merge should be supported, where
+    // part of these properties may be changed in emphasis style, and the
+    // others should remain their original value got from normal style.
+    for (let i = 0; i < TEXT_PROPS_WITH_GLOBAL.length; i++) {
+        const key = TEXT_PROPS_WITH_GLOBAL[i];
+        const val = retrieve2(textStyleModel.getShallow(key), globalTextStyle[key]);
+        if (val != null) {
+            (textStyle as any)[key] = val;
+        }
+    }
+    for (let i = 0; i < TEXT_PROPS_SELF.length; i++) {
+        const key = TEXT_PROPS_SELF[i];
+        const val = textStyleModel.getShallow(key);
+        if (val != null) {
+            (textStyle as any)[key] = val;
+        }
+    }
+    if (textStyle.verticalAlign == null) {
+        const baseline = textStyleModel.getShallow('baseline');
+        if (baseline != null) {
+            textStyle.verticalAlign = baseline;
+        }
+    }
+    if (!isBlock || !opt.disableBox) {
+        if (textStyle.backgroundColor === 'auto' && inheritColor) {
+            textStyle.backgroundColor = inheritColor;
+        }
+        if (textStyle.borderColor === 'auto' && inheritColor) {
+            textStyle.borderColor = inheritColor;
+        }
+        for (let i = 0; i < TEXT_PROPS_BOX.length; i++) {
+            const key = TEXT_PROPS_BOX[i];
+            const val = textStyleModel.getShallow(key);
+            if (val != null) {
+                (textStyle as any)[key] = val;
+            }
+        }
+    }
+}
+export function getFont(
+    opt: Pick<TextCommonOption, 'fontStyle' | 'fontWeight' | 'fontSize' | 'fontFamily'>,
+    ecModel: GlobalModel
+) {
+    const gTextStyleModel = ecModel && ecModel.getModel('textStyle');
+    return trim([
+        // FIXME in node-canvas fontWeight is before fontStyle
+        opt.fontStyle || gTextStyleModel && gTextStyleModel.getShallow('fontStyle') || '',
+        opt.fontWeight || gTextStyleModel && gTextStyleModel.getShallow('fontWeight') || '',
+        (opt.fontSize || gTextStyleModel && gTextStyleModel.getShallow('fontSize') || 12) + 'px',
+        opt.fontFamily || gTextStyleModel && gTextStyleModel.getShallow('fontFamily') || 'sans-serif'
+    ].join(' '));
+}
diff --git a/src/model/globalDefault.ts b/src/model/globalDefault.ts
index 4625525..72defe7 100644
--- a/src/model/globalDefault.ts
+++ b/src/model/globalDefault.ts
@@ -35,10 +35,11 @@ export default {
     // color: ['#bcd3bb', '#e88f70', '#edc1a5', '#9dc5c8', '#e1e8c8', '#7b7c68', '#e5b5b5', '#f0b489', '#928ea8', '#bda29a'],
     // color: ['#cc5664', '#9bd6ec', '#ea946e', '#8acaaa', '#f1ec64', '#ee8686', '#a48dc1', '#5da6bc', '#b9dcae'],
     // Dark colors:
-    color: [
-        '#c23531', '#2f4554', '#61a0a8', '#d48265', '#91c7ae', '#749f83',
-        '#ca8622', '#bda29a', '#6e7074', '#546570', '#c4ccd3'
-    ],
+    // color: [
+    //     '#c23531', '#2f4554', '#61a0a8', '#d48265', '#91c7ae', '#749f83',
+    //     '#ca8622', '#bda29a', '#6e7074', '#546570', '#c4ccd3'
+    // ],
+    color: [ '#51689b', '#ce5c5c', '#fbc357', '#8fbf8f', '#659d84', '#fb8e6a', '#c77288', '#786090', '#91c4c5', '#6890ba'],
 
     gradientColor: ['#f6efa6', '#d88273', '#bf444c'],
 
diff --git a/src/model/mixin/textStyle.ts b/src/model/mixin/textStyle.ts
index 907bba4..894f410 100644
--- a/src/model/mixin/textStyle.ts
+++ b/src/model/mixin/textStyle.ts
@@ -18,6 +18,7 @@
 */
 
 import * as graphicUtil from '../../util/graphic';
+import {getFont} from '../../label/labelStyle';
 import Model from '../Model';
 import { LabelOption, ColorString } from '../../util/types';
 import ZRText from 'zrender/src/graphic/Text';
@@ -49,7 +50,7 @@ class TextStyleMixin {
      * @return {string}
      */
     getFont(this: Model<LabelFontOption>) {
-        return graphicUtil.getFont({
+        return getFont({
             fontStyle: this.getShallow('fontStyle'),
             fontWeight: this.getShallow('fontWeight'),
             fontSize: this.getShallow('fontSize'),
diff --git a/src/util/graphic.ts b/src/util/graphic.ts
index 36c1160..d5e1500 100644
--- a/src/util/graphic.ts
+++ b/src/util/graphic.ts
@@ -25,7 +25,7 @@ import Path, { PathProps } from 'zrender/src/graphic/Path';
 import Transformable from 'zrender/src/core/Transformable';
 import ZRImage, { ImageStyleProps } from 'zrender/src/graphic/Image';
 import Group from 'zrender/src/graphic/Group';
-import ZRText, { TextStyleProps } from 'zrender/src/graphic/Text';
+import ZRText from 'zrender/src/graphic/Text';
 import Circle from 'zrender/src/graphic/shape/Circle';
 import Ellipse from 'zrender/src/graphic/shape/Ellipse';
 import Sector from 'zrender/src/graphic/shape/Sector';
@@ -49,7 +49,7 @@ 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, ElementTextConfig, ElementProps } from 'zrender/src/Element';
+import Element, { ElementEvent, ElementProps } from 'zrender/src/Element';
 import Model from '../model/Model';
 import {
     AnimationOptionMixin,
@@ -62,20 +62,10 @@ import {
     DataModel,
     ECEventData,
     ZRStyleProps,
-    AnimationOption,
-    TextCommonOption,
-    SeriesOption,
-    ParsedValue,
-    CallbackDataParams
-} from './types';
-import GlobalModel from '../model/Global';
+    ParsedValue} from './types';
 import { makeInner } from './model';
 import {
-    isFunction,
-    retrieve2,
     extend,
-    keys,
-    trim,
     isArrayLike,
     map,
     defaults,
@@ -86,12 +76,13 @@ import * as numberUtil from './number';
 import SeriesModel from '../model/Series';
 import {interpolateNumber} from 'zrender/src/animation/Animator';
 import List from '../data/List';
+import { getLabelText } from '../label/labelStyle';
 
 
 const mathMax = Math.max;
 const mathMin = Math.min;
 
-const EMPTY_OBJ = {};
+export const EMPTY_OBJ = {};
 
 export const Z2_EMPHASIS_LIFT = 10;
 
@@ -119,7 +110,7 @@ type ExtendedProps = {
 type ExtendedElement = Element & ExtendedProps;
 type ExtendedDisplayable = Displayable & ExtendedProps;
 
-type TextCommonParams = {
+export type TextCommonParams = {
     /**
      * Whether diable drawing box of block (outer most).
      */
@@ -370,21 +361,15 @@ function liftColor(color: string): string {
 }
 
 function singleEnterEmphasis(el: Element) {
-
+    // Only mark the flag.
+    // States will be applied in the echarts.ts in next frame.
     (el as ECElement).highlighted = true;
-
-    // el may be an array.
-    if (!el.states.emphasis) {
-        return;
-    }
-
-    el.useState('emphasis', true);
-    // TODO hover layer
 }
 
 
 function singleLeaveEmphasis(el: Element) {
-    el.removeState('emphasis');
+    // Only mark the flag.
+    // States will be applied in the echarts.ts in next frame.
     (el as ECElement).highlighted = false;
 }
 
@@ -413,7 +398,6 @@ function traverseUpdateState<T>(
     el.isGroup && el.traverse(function (child: ExtendedElement) {
         updateElementState(child, updater, commonParam);
     });
-
 }
 
 /**
@@ -492,12 +476,7 @@ function elementStateProxy(this: Displayable, stateName: string): DisplayableSta
  * Set hover style (namely "emphasis style") of element.
  * @param el Should not be `zrender/graphic/Group`.
  */
-export function enableElementHoverEmphasis(el: Displayable, hoverStl?: ZRStyleProps) {
-    if (hoverStl) {
-        const emphasisState = el.ensureState('emphasis');
-        emphasisState.style = hoverStl;
-    }
-
+export function enableElementHoverEmphasis(el: Displayable) {
     el.stateProxy = elementStateProxy;
     const textContent = el.getTextContent();
     const textGuide = el.getTextGuideLine();
@@ -540,37 +519,40 @@ function shouldSilent(el: Element, e: ElementEvent) {
 /**
  * Enable the function that mouseover will trigger the emphasis state.
  *
- * It will set hoverStyle to 'emphasis' state of each children displayables.
- * If hoverStyle is not given, it will just ignore it and use the preset 'emphasis' state.
- *
- * NOTICE
- * (1)
+ * 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.
- *
- * (2) The given hover style will replace the style in emphasis state already exists.
  */
-export function enableHoverEmphasis(el: Element, hoverStyle?: ZRStyleProps) {
+export function enableHoverEmphasis(el: Element) {
     setAsHighDownDispatcher(el, true);
-    traverseUpdateState(el as ExtendedElement, enableElementHoverEmphasis, hoverStyle);
+    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 animation config on state transition.
+ * Set emphasis/blur/selected states of element.
  */
-export function setStateTransition(el: Element, animatableModel: Model<AnimationOption>) {
-    const duration = animatableModel.get('duration');
-    if (duration > 0) {
-        el.stateTransition = {
-            duration,
-            delay: animatableModel.get('delay'),
-            easing: animatableModel.get('easing')
-        };
-    }
-    else if (el.stateTransition) {
-        el.stateTransition = null;
+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]]();
     }
 }
 
@@ -653,486 +635,6 @@ export function getHighlightDigit(highlightKey: number) {
     return highlightDigit;
 }
 
-interface SetLabelStyleOpt<LDI> extends TextCommonParams {
-    defaultText?: string | (
-        (labelDataIndex: LDI, opt: SetLabelStyleOpt<LDI>) => string
-    ),
-    // Fetch text by:
-    // opt.labelFetcher.getFormattedLabel(
-    //     opt.labelDataIndex, 'normal'/'emphasis', null, opt.labelDimIndex, opt.labelProp
-    // )
-    labelFetcher?: {
-        getFormattedLabel: (
-            // In MapDraw case it can be string (region name)
-            labelDataIndex: LDI,
-            status: DisplayState,
-            dataType?: string,
-            labelDimIndex?: number,
-            formatter?: string | ((params: object) => string),
-            extendParams?: Partial<CallbackDataParams>
-        ) => string
-        // getDataParams: (labelDataIndex: LDI, dataType?: string) => object
-    },
-    labelDataIndex?: LDI,
-    labelDimIndex?: number
-}
-
-
-type LabelModel = Model<LabelOption & {
-    formatter?: string | ((params: any) => string)
-}>;
-type LabelModelForText = Model<Omit<
-    // Remove
-    LabelOption, 'position' | 'rotate'
-> & {
-    formatter?: string | ((params: any) => string)
-}>;
-
-function getLabelText<LDI>(
-    opt: SetLabelStyleOpt<LDI>,
-    normalModel: LabelModel,
-    emphasisModel: LabelModel,
-    interpolateValues?: ParsedValue | ParsedValue[]
-) {
-    const labelFetcher = opt.labelFetcher;
-    const labelDataIndex = opt.labelDataIndex;
-    const labelDimIndex = opt.labelDimIndex;
-
-    let baseText;
-    if (labelFetcher) {
-        baseText = labelFetcher.getFormattedLabel(
-            labelDataIndex,
-            'normal',
-            null,
-            labelDimIndex,
-            normalModel && normalModel.get('formatter'),
-            interpolateValues != null ? {
-                value: interpolateValues
-            } : null
-        );
-    }
-    if (baseText == null) {
-        baseText = isFunction(opt.defaultText) ? opt.defaultText(labelDataIndex, opt) : opt.defaultText;
-    }
-    const emphasisStyleText = retrieve2(
-        labelFetcher
-            ? labelFetcher.getFormattedLabel(
-                labelDataIndex,
-                'emphasis',
-                null,
-                labelDimIndex,
-                emphasisModel && emphasisModel.get('formatter')
-            )
-            : null,
-        baseText
-    );
-    return {
-        normal: baseText,
-        emphasis: emphasisStyleText
-    };
-}
-
-/**
- * Set normal styles and emphasis styles about text on target element
- * If target is a ZRText. It will create a new style object.
- * If target is other Element. It will create or reuse ZRText which is attached on the target.
- * And create a new style object.
- *
- * NOTICE: Because the style on ZRText will be replaced with new(only x, y are keeped).
- * So please update the style on ZRText after use this method.
- */
-// eslint-disable-next-line
-function setLabelStyle<LDI>(targetEl: ZRText, normalModel: LabelModelForText, emphasisModel: LabelModelForText, opt?: SetLabelStyleOpt<LDI>, normalSpecified?: TextStyleProps, emphasisSpecified?: TextStyleProps): void;
-// eslint-disable-next-line
-function setLabelStyle<LDI>(targetEl: Element, normalModel: LabelModel, emphasisModel: LabelModel, opt?: SetLabelStyleOpt<LDI>, normalSpecified?: TextStyleProps, emphasisSpecified?: TextStyleProps): void;
-function setLabelStyle<LDI>(
-    targetEl: Element,
-    normalModel: LabelModel,
-    emphasisModel: LabelModel,
-    opt?: SetLabelStyleOpt<LDI>,
-    normalSpecified?: TextStyleProps,
-    emphasisSpecified?: TextStyleProps
-    // TODO specified position?
-) {
-    opt = opt || EMPTY_OBJ;
-    const isSetOnText = targetEl instanceof ZRText;
-
-    const showNormal = normalModel.getShallow('show');
-    const showEmphasis = emphasisModel.getShallow('show');
-
-    let richText = isSetOnText ? targetEl as ZRText : null;
-    if (showNormal || showEmphasis) {
-        if (!isSetOnText) {
-            // Reuse the previous
-            richText = targetEl.getTextContent();
-            if (!richText) {
-                richText = new ZRText();
-                targetEl.setTextContent(richText);
-            }
-        }
-        richText.ignore = !showNormal;
-
-        const emphasisState = richText.ensureState('emphasis');
-        emphasisState.ignore = !showEmphasis;
-
-        const normalStyle = createTextStyle(
-            normalModel,
-            normalSpecified,
-            opt,
-            false,
-            !isSetOnText
-        );
-        emphasisState.style = createTextStyle(
-            emphasisModel,
-            emphasisSpecified,
-            opt,
-            true,
-            !isSetOnText
-        );
-
-        if (!isSetOnText) {
-            // Always create new
-            targetEl.setTextConfig(createTextConfig(
-                normalStyle,
-                normalModel,
-                opt,
-                false
-            ));
-            const targetElEmphasisState = targetEl.ensureState('emphasis');
-            targetElEmphasisState.textConfig = createTextConfig(
-                emphasisState.style,
-                emphasisModel,
-                opt,
-                true
-            );
-        }
-
-        // PENDING: if there is many requirements that emphasis position
-        // need to be different from normal position, we might consider
-        // auto slient is those cases.
-        richText.silent = !!normalModel.getShallow('silent');
-
-        const labelText = getLabelText(opt, normalModel, emphasisModel);
-        normalStyle.text = labelText.normal;
-        emphasisState.style.text = labelText.emphasis;
-
-        // Keep x and y
-        if (richText.style.x != null) {
-            normalStyle.x = richText.style.x;
-        }
-        if (richText.style.y != null) {
-            normalStyle.y = richText.style.y;
-        }
-
-        // Always create new style.
-        richText.useStyle(normalStyle);
-
-        richText.dirty();
-    }
-    else if (richText) {
-        // Not display rich text.
-        richText.ignore = true;
-    }
-
-    targetEl.dirty();
-}
-
-export {setLabelStyle};
-/**
- * Set basic textStyle properties.
- */
-export function createTextStyle(
-    textStyleModel: Model,
-    specifiedTextStyle?: TextStyleProps,    // Can be overrided by settings in model.
-    opt?: Pick<TextCommonParams, 'inheritColor' | 'disableBox'>,
-    isNotNormal?: boolean,
-    isAttached?: boolean // If text is attached on an element. If so, auto color will handling in zrender.
-) {
-    const textStyle: TextStyleProps = {};
-    setTextStyleCommon(textStyle, textStyleModel, opt, isNotNormal, isAttached);
-    specifiedTextStyle && extend(textStyle, specifiedTextStyle);
-    // textStyle.host && textStyle.host.dirty && textStyle.host.dirty(false);
-
-    return textStyle;
-}
-
-export function createTextConfig(
-    textStyle: TextStyleProps,
-    textStyleModel: Model,
-    opt?: Pick<TextCommonParams, 'defaultOutsidePosition' | 'inheritColor'>,
-    isNotNormal?: boolean
-) {
-    opt = opt || {};
-    const textConfig: ElementTextConfig = {};
-    let labelPosition;
-    let labelRotate = textStyleModel.getShallow('rotate');
-    const labelDistance = retrieve2(
-        textStyleModel.getShallow('distance'), isNotNormal ? null : 5
-    );
-    const labelOffset = textStyleModel.getShallow('offset');
-
-    labelPosition = textStyleModel.getShallow('position')
-        || (isNotNormal ? null : 'inside');
-    // 'outside' is not a valid zr textPostion value, but used
-    // in bar series, and magric type should be considered.
-    labelPosition === 'outside' && (labelPosition = opt.defaultOutsidePosition || 'top');
-
-    if (labelPosition != null) {
-        textConfig.position = labelPosition;
-    }
-    if (labelOffset != null) {
-        textConfig.offset = labelOffset;
-    }
-    if (labelRotate != null) {
-        labelRotate *= Math.PI / 180;
-        textConfig.rotation = labelRotate;
-    }
-    if (labelDistance != null) {
-        textConfig.distance = labelDistance;
-    }
-
-    // fill and auto is determined by the color of path fill if it's not specified by developers.
-
-    textConfig.outsideFill = textStyleModel.get('color') === 'inherit'
-        ? (opt.inheritColor || null)
-        : 'auto';
-
-    return textConfig;
-}
-
-
-/**
- * The uniform entry of set text style, that is, retrieve style definitions
- * from `model` and set to `textStyle` object.
- *
- * Never in merge mode, but in overwrite mode, that is, all of the text style
- * properties will be set. (Consider the states of normal and emphasis and
- * default value can be adopted, merge would make the logic too complicated
- * to manage.)
- */
-function setTextStyleCommon(
-    textStyle: TextStyleProps,
-    textStyleModel: Model,
-    opt?: Pick<TextCommonParams, 'inheritColor' | 'disableBox'>,
-    isNotNormal?: boolean,
-    isAttached?: boolean
-) {
-    // Consider there will be abnormal when merge hover style to normal style if given default value.
-    opt = opt || EMPTY_OBJ;
-
-    const ecModel = textStyleModel.ecModel;
-    const globalTextStyle = ecModel && ecModel.option.textStyle;
-
-    // Consider case:
-    // {
-    //     data: [{
-    //         value: 12,
-    //         label: {
-    //             rich: {
-    //                 // no 'a' here but using parent 'a'.
-    //             }
-    //         }
-    //     }],
-    //     rich: {
-    //         a: { ... }
-    //     }
-    // }
-    const richItemNames = getRichItemNames(textStyleModel);
-    let richResult: TextStyleProps['rich'];
-    if (richItemNames) {
-        richResult = {};
-        for (const name in richItemNames) {
-            if (richItemNames.hasOwnProperty(name)) {
-                // Cascade is supported in rich.
-                const richTextStyle = textStyleModel.getModel(['rich', name]);
-                // In rich, never `disableBox`.
-                // FIXME: consider `label: {formatter: '{a|xx}', color: 'blue', rich: {a: {}}}`,
-                // the default color `'blue'` will not be adopted if no color declared in `rich`.
-                // That might confuses users. So probably we should put `textStyleModel` as the
-                // root ancestor of the `richTextStyle`. But that would be a break change.
-                setTokenTextStyle(richResult[name] = {}, richTextStyle, globalTextStyle, opt, isNotNormal, isAttached);
-            }
-        }
-    }
-
-    if (richResult) {
-        textStyle.rich = richResult;
-    }
-    const overflow = textStyleModel.get('overflow');
-    if (overflow) {
-        textStyle.overflow = overflow;
-    }
-    const margin = textStyleModel.get('minMargin');
-    if (margin != null) {
-        textStyle.margin = margin;
-    }
-
-    setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isNotNormal, isAttached, true);
-}
-
-// Consider case:
-// {
-//     data: [{
-//         value: 12,
-//         label: {
-//             rich: {
-//                 // no 'a' here but using parent 'a'.
-//             }
-//         }
-//     }],
-//     rich: {
-//         a: { ... }
-//     }
-// }
-// TODO TextStyleModel
-function getRichItemNames(textStyleModel: Model<LabelOption>) {
-    // Use object to remove duplicated names.
-    let richItemNameMap: Dictionary<number>;
-    while (textStyleModel && textStyleModel !== textStyleModel.ecModel) {
-        const rich = (textStyleModel.option || EMPTY_OBJ as LabelOption).rich;
-        if (rich) {
-            richItemNameMap = richItemNameMap || {};
-            const richKeys = keys(rich);
-            for (let i = 0; i < richKeys.length; i++) {
-                const richKey = richKeys[i];
-                richItemNameMap[richKey] = 1;
-            }
-        }
-        textStyleModel = textStyleModel.parentModel;
-    }
-    return richItemNameMap;
-}
-
-const TEXT_PROPS_WITH_GLOBAL = [
-    'fontStyle', 'fontWeight', 'fontSize', 'fontFamily', 'opacity',
-    'textShadowColor', 'textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY'
-] as const;
-
-const TEXT_PROPS_SELF = [
-    'align', 'lineHeight', 'width', 'height', 'tag', 'verticalAlign'
-] as const;
-
-const TEXT_PROPS_BOX = [
-    'padding', 'borderWidth', 'borderRadius',
-    'backgroundColor', 'borderColor',
-    'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY'
-] as const;
-
-function setTokenTextStyle(
-    textStyle: TextStyleProps['rich'][string],
-    textStyleModel: Model<LabelOption>,
-    globalTextStyle: LabelOption,
-    opt?: Pick<TextCommonParams, 'inheritColor' | 'disableBox'>,
-    isNotNormal?: boolean,
-    isAttached?: boolean,
-    isBlock?: boolean
-) {
-    // In merge mode, default value should not be given.
-    globalTextStyle = !isNotNormal && globalTextStyle || EMPTY_OBJ;
-
-    const inheritColor = opt && opt.inheritColor;
-    let fillColor = textStyleModel.getShallow('color');
-    let strokeColor = textStyleModel.getShallow('textBorderColor');
-    if (fillColor === 'inherit') {
-        if (inheritColor) {
-            fillColor = inheritColor;
-        }
-        else {
-            fillColor = null;
-        }
-    }
-    if (strokeColor === 'inherit' && inheritColor) {
-        if (inheritColor) {
-            strokeColor = inheritColor;
-        }
-        else {
-            strokeColor = inheritColor;
-        }
-    }
-    fillColor = fillColor || globalTextStyle.color;
-    strokeColor = strokeColor || globalTextStyle.textBorderColor;
-    if (fillColor != null) {
-        textStyle.fill = fillColor;
-    }
-    if (strokeColor != null) {
-        textStyle.stroke = strokeColor;
-    }
-
-    const lineWidth = retrieve2(
-        textStyleModel.getShallow('textBorderWidth'),
-        globalTextStyle.textBorderWidth
-    );
-    if (lineWidth != null) {
-        textStyle.lineWidth = lineWidth;
-    }
-
-    // TODO
-    if (!isNotNormal && !isAttached) {
-        // Set default finally.
-        if (textStyle.fill == null && opt.inheritColor) {
-            textStyle.fill = opt.inheritColor;
-        }
-    }
-
-    // Do not use `getFont` here, because merge should be supported, where
-    // part of these properties may be changed in emphasis style, and the
-    // others should remain their original value got from normal style.
-    for (let i = 0; i < TEXT_PROPS_WITH_GLOBAL.length; i++) {
-        const key = TEXT_PROPS_WITH_GLOBAL[i];
-        const val = retrieve2(textStyleModel.getShallow(key), globalTextStyle[key]);
-        if (val != null) {
-            (textStyle as any)[key] = val;
-        }
-    }
-
-    for (let i = 0; i < TEXT_PROPS_SELF.length; i++) {
-        const key = TEXT_PROPS_SELF[i];
-        const val = textStyleModel.getShallow(key);
-        if (val != null) {
-            (textStyle as any)[key] = val;
-        }
-    }
-
-    if (textStyle.verticalAlign == null) {
-        const baseline = textStyleModel.getShallow('baseline');
-        if (baseline != null) {
-            textStyle.verticalAlign = baseline;
-        }
-    }
-
-
-    if (!isBlock || !opt.disableBox) {
-        if (textStyle.backgroundColor === 'auto' && inheritColor) {
-            textStyle.backgroundColor = inheritColor;
-        }
-        if (textStyle.borderColor === 'auto' && inheritColor) {
-            textStyle.borderColor = inheritColor;
-        }
-
-        for (let i = 0; i < TEXT_PROPS_BOX.length; i++) {
-            const key = TEXT_PROPS_BOX[i];
-            const val = textStyleModel.getShallow(key);
-            if (val != null) {
-                (textStyle as any)[key] = val;
-            }
-        }
-    }
-}
-
-export function getFont(
-    opt: Pick<TextCommonOption, 'fontStyle' | 'fontWeight' | 'fontSize' | 'fontFamily'>,
-    ecModel: GlobalModel
-) {
-    const gTextStyleModel = ecModel && ecModel.getModel('textStyle');
-    return trim([
-        // FIXME in node-canvas fontWeight is before fontStyle
-        opt.fontStyle || gTextStyleModel && gTextStyleModel.getShallow('fontStyle') || '',
-        opt.fontWeight || gTextStyleModel && gTextStyleModel.getShallow('fontWeight') || '',
-        (opt.fontSize || gTextStyleModel && gTextStyleModel.getShallow('fontSize') || 12) + 'px',
-        opt.fontFamily || gTextStyleModel && gTextStyleModel.getShallow('fontFamily') || 'sans-serif'
-    ].join(' '));
-}
-
 type AnimateOrSetPropsOption = {
     dataIndex?: number;
     cb?: () => void;
@@ -1303,7 +805,6 @@ function animateOrSetLabel<Props extends PathProps>(
     animatableModel?: Model<AnimationOptionMixin>,
     defaultTextGetter?: (value: ParsedValue[] | ParsedValue) => string
 ) {
-    const element = el as Element<Props> & { __value: ParsedValue[] | ParsedValue };
     const valueAnimationEnabled = labelModel && labelModel.get('valueAnimation');
     if (valueAnimationEnabled) {
         const precisionOption = labelModel.get('precision');
@@ -1334,7 +835,7 @@ function animateOrSetLabel<Props extends PathProps>(
             }
             else {
                 interpolated = [];
-                for (let i = 0, j = 0; i < (rawValues as []).length; ++i) {
+                for (let i = 0; i < (rawValues as []).length; ++i) {
                     const info = data.getDimensionInfo(i);
                     // Don't interpolate ordinal dims
                     if (info.type === 'ordinal') {
@@ -1343,7 +844,6 @@ function animateOrSetLabel<Props extends PathProps>(
                     else {
                         const value = interpolateNumber(0, (interpolateValues as number[])[i], percent);
                         interpolated[i] = numberUtil.round(value), precision;
-                        ++j;
                     }
                 }
             }
diff --git a/src/util/types.ts b/src/util/types.ts
index bfd2006..f6b9358 100644
--- a/src/util/types.ts
+++ b/src/util/types.ts
@@ -107,8 +107,10 @@ export interface ECElement extends Element {
     highDownSilentOnTouch?: boolean;
     onStateChange?: (fromState: 'normal' | 'emphasis', toState: 'normal' | 'emphasis') => void;
 
+    blurred?: boolean;
     highlighted?: boolean;
     selected?: boolean;
+
     z2EmphasisLift?: number;
 }
 
@@ -1122,10 +1124,33 @@ export interface ComponentOption {
     // FIXME:TS more
 }
 
-export interface SeriesOption extends
+export interface StatesOptionMixin<StateOption> {
+    /**
+     * 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'
+    }
+    /**
+     * Select states
+     */
+    select?: StateOption
+    /**
+     * Blur states.
+     */
+    blur?: StateOption
+}
+
+export interface SeriesOption<StateOption> extends
     ComponentOption,
     AnimationOptionMixin,
-    ColorPaletteOptionMixin
+    ColorPaletteOptionMixin,
+    StatesOptionMixin<StateOption>
 {
     name?: string
 
diff --git a/test/bar.html b/test/bar.html
index ad8923d..9ea1797 100644
--- a/test/bar.html
+++ b/test/bar.html
@@ -100,8 +100,8 @@ under the License.
                         label: {
                             position: 'outside'
                         },
-                        barBorderColor: '#fff',
-                        barBorderWidth: 1,
+                        // barBorderColor: '#fff',
+                        // barBorderWidth: 1,
                         shadowBlur: 10,
                         shadowOffsetX: 0,
                         shadowOffsetY: 0,


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