Merge branch 'master' into feat/symbol-clip
diff --git a/src/chart/helper/Symbol.ts b/src/chart/helper/Symbol.ts
index 222776f..3cba610 100644
--- a/src/chart/helper/Symbol.ts
+++ b/src/chart/helper/Symbol.ts
@@ -30,6 +30,7 @@
 import { extend } from 'zrender/src/core/util';
 import { setLabelStyle, getLabelStatesModels } from '../../label/labelStyle';
 import ZRImage from 'zrender/src/graphic/Image';
+import { makeSymbolClipPath } from './symbolClipHelper';
 import { saveOldStyle } from '../../animation/basicTrasition';
 
 type ECSymbol = ReturnType<typeof createSymbol>;
@@ -294,8 +295,8 @@
             symbolPath.style.decal = null;
             symbolPath.setColor(visualColor, opts && opts.symbolInnerColor);
             symbolPath.style.strokeNoScale = true;
-
         }
+
         const liftZ = data.getItemVisual(idx, 'liftZ');
         const z2Origin = this._z2;
         if (liftZ != null) {
@@ -322,14 +323,28 @@
             }
         );
 
+        this._sizeX = symbolSize[0] / 2;
+        this._sizeY = symbolSize[1] / 2;
+
+        // symbol clip
+        symbolPath.removeClipPath();
+        const symbolClip = data.getItemVisual(idx, 'symbolClip');
+        if (symbolClip) {
+            const clipPath = makeSymbolClipPath(symbolClip, symbolSize);
+            if (clipPath) {
+                clipPath.scaleX = 1 / this._sizeX;
+                clipPath.scaleY = 1 / this._sizeY;
+                symbolPath.setClipPath(clipPath);
+                // PENDING: ignore text clip?
+                symbolPath.getTextContent() && (symbolPath.getTextContent().ignoreClip = true);
+            }
+        }
+
         // Do not execute util needed.
         function getLabelDefaultText(idx: number) {
             return useNameLabel ? data.getName(idx) : getDefaultLabel(data, idx);
         }
 
-        this._sizeX = symbolSize[0] / 2;
-        this._sizeY = symbolSize[1] / 2;
-
         const emphasisState = symbolPath.ensureState('emphasis');
 
         emphasisState.style = emphasisItemStyle;
diff --git a/src/chart/helper/symbolClipHelper.ts b/src/chart/helper/symbolClipHelper.ts
new file mode 100644
index 0000000..b6dbcc7
--- /dev/null
+++ b/src/chart/helper/symbolClipHelper.ts
@@ -0,0 +1,240 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import { isString, isArray, map, normalizeCssArray } from 'zrender/src/core/util';
+import { parsePercent } from '../../util/number';
+import { SymbolClip } from '../../util/types';
+import * as graphic from '../../util/graphic';
+
+const REG_CSS_CLIP_SHAPE = /^([a-z]+).*\((.*)\)/;
+
+type SymbolClipPath = graphic.Path;
+
+type ParsedCSSClip = {
+    type: 'inset' | 'rect' | 'circle' | 'ellipse' | 'polygon' | 'path'
+    center?: number | string | (number | string)[]
+    radius?: number | string | (number | string)[]
+    points?: (number | string)[] | (number | string)[][],
+    path?: string
+};
+
+/**
+ * To make a symbol clip path
+ * @param clip the clip expression following the CSS `clip-path` rule
+ * @param symbolSize the size of symbol
+ * @return the symbol clip path
+ */
+export function makeSymbolClipPath(
+    clip: SymbolClip,
+    symbolSize: number[]
+): SymbolClipPath {
+
+    if (!clip) {
+        return;
+    }
+
+    if (clip instanceof graphic.Path) {
+        return clip;
+    }
+
+    if (isString(clip)) {
+        const parsedClip = parseCSSClipExp(clip);
+        return parsedClip && createSymbolClipPath(parsedClip, symbolSize);
+    }
+
+}
+
+function createSymbolClipPath(
+    clip: ParsedCSSClip,
+    symbolSize: number[]
+): SymbolClipPath {
+
+    let clipPath: SymbolClipPath;
+
+    const clipType = clip.type;
+    if (clipType === 'circle' || clipType === 'ellipse') {
+        let {radius, center} = clip;
+        let cx;
+        let cy;
+        if (!center || (center as (string | number)[]).length === 0) {
+            cx = 0;
+            cy = 0;
+        }
+        else {
+            if (!isArray(center)) {
+                center = [center, center];
+            }
+            center = [
+                parsePercent(center[0], symbolSize[0]) || 0,
+                parsePercent(center[1] == null ? center[0] : center[1], symbolSize[1]) || 0
+            ];
+            cx = -symbolSize[0] / 2 + (center as number[])[0];
+            cy = -symbolSize[1] / 2 + (center as number[])[1];
+        }
+        if (clipType === 'circle') {
+            // consider circle radius in percentage
+            isArray(radius) && (radius = radius[0]);
+            radius = parsePercent(radius, symbolSize[0]) || 0;
+            const maxRadius = symbolSize[0] / 2;
+            // restrict the max radius
+            if (radius > maxRadius) {
+                radius = maxRadius;
+            }
+            if (!(radius > 0)) {
+                return;
+            }
+            clipPath = new graphic.Circle({
+                shape: {
+                    cx: cx,
+                    cy: cy,
+                    r: radius
+                }
+            });
+        }
+        else {
+            if (!isArray(radius)) {
+                radius = [radius, radius];
+            }
+            const rx = parsePercent(radius[0], symbolSize[0]) || 0;
+            const ry = parsePercent(radius[1] == null ? radius[0] : radius[1], symbolSize[1]) || 0;
+            clipPath = new graphic.Ellipse({
+                shape: {
+                    cx: cx,
+                    cy: cy,
+                    rx: rx,
+                    ry: ry
+                }
+            });
+        }
+    }
+    else if (clipType === 'rect') {
+        const {radius, points} = clip;
+        const shapeArgs = normalizeArray(
+            map(points as (string | number)[], (point, idx) => {
+                return parsePercent(point, symbolSize[idx % 2 ? 0 : 1]);
+            })
+        );
+        const r = normalizeArray(
+            map(radius as (string | number)[], (r, idx) => {
+                return parsePercent(r, symbolSize[idx % 2 ? 0 : 1]);
+            })
+        );
+        const width = symbolSize[0] - shapeArgs[1] - shapeArgs[3];
+        const height = symbolSize[1] - shapeArgs[0] - shapeArgs[2];
+        if (!(width > 0 && height > 0 && (width < symbolSize[0] || height < symbolSize[1]))) {
+            return;
+        }
+        clipPath = new graphic.Rect({
+            shape: {
+                x: -symbolSize[0] / 2 + shapeArgs[3],
+                y: -symbolSize[1] / 2 + shapeArgs[0],
+                width: width,
+                height: height,
+                r: r
+            }
+        });
+    }
+    else if (clipType === 'polygon') {
+        const points = clip.points;
+        if (points && points.length > 0) {
+            const normalizedPoints = map(points as (number | string)[][], point => {
+                return map(point, (val, dim) => {
+                   return parsePercent(val, symbolSize[dim]) - symbolSize[dim] / 2;
+                });
+            });
+            clipPath = new graphic.Polygon({
+                shape: {
+                    points: normalizedPoints
+                }
+            });
+        }
+    }
+    else if (clipType === 'path') {
+        if (clip.path) {
+            clipPath = graphic.makePath(clip.path, {}, {
+                x: -symbolSize[0] / 2,
+                y: -symbolSize[1] / 2,
+                width: symbolSize[0],
+                height: symbolSize[1]
+            }, 'center');
+        }
+    }
+
+    return clipPath;
+}
+
+/**
+ * To parse clip expression value defined in CSS.
+ *
+ * Supported forms of value are as follows:
+ *  `inset(22% 12% 10px 35px)`
+ *  `rect(22% 12% 10px 35px)`
+ *  `circle(20px at 50% 25%)`
+ *  `ellipse(115px 55px at 50% 40%)`
+ *  `polygon(50% 20%, 90% 80%, 10% 80%)`
+ *  `path('M0.5,1 C0.5,1,0,0.7,0,0.3 A0.25,0.25,1,1,1,0.5,0.3 A0.25,0.25,1,1,1,1,0.3 C1,0.7,0.5,1,0.5,1 Z')`
+ *
+ * Note that only `px` and `%` are supported. `rem` and other units will be ignored.
+ *
+ * @param clipExp the raw clip expression in CSS
+ */
+function parseCSSClipExp(clipExp: string): ParsedCSSClip {
+    const match = clipExp && clipExp.trim().match(REG_CSS_CLIP_SHAPE);
+    if (!match) {
+        return;
+    }
+
+    const type = match[1] as any;
+    const value = match[2] && match[2].trim().replace(/(p(x|t))|(r?em)|(v(h|w))|(ch)/ig, '');
+    if (!type || !value) {
+        return;
+    }
+
+    const parsedClip: ParsedCSSClip = {type: type};
+
+    if (type === 'inset' || type === 'rect') {
+        parsedClip.type = 'rect';
+        const vals = value.split('round');
+        parsedClip.points = vals[0].trim().split(' ');
+        parsedClip.radius = vals[1] && vals[1].trim().split(' ');
+    }
+    else if (type === 'circle' || type === 'ellipse') {
+        const vals = value.split('at');
+        parsedClip.radius = vals[0].trim().split(' ');
+        parsedClip.center = vals[1] && vals[1].trim().split(' ');
+    }
+    else if (type === 'polygon') {
+        parsedClip.points = map(value.split(','), p => {
+            return p.trim().split(' ');
+        });
+    }
+    else if (type === 'path') {
+        parsedClip.path = value.replace(/[\'"]/g, '');
+    }
+
+    return parsedClip;
+}
+
+function normalizeArray(val: Parameters<typeof normalizeCssArray>[0]) {
+    const normalizedArr = normalizeCssArray(val);
+    if (normalizedArr.length === 1) {
+        normalizedArr[1] = normalizedArr[2] = normalizedArr[3] = normalizedArr[0];
+    }
+    return normalizedArr;
+}
diff --git a/src/data/List.ts b/src/data/List.ts
index 3ff4da6..7633e44 100644
--- a/src/data/List.ts
+++ b/src/data/List.ts
@@ -36,7 +36,7 @@
     DimensionIndex, DimensionName, DimensionLoose, OptionDataItem,
     ParsedValue, ParsedValueNumeric, OrdinalNumber, DimensionUserOuput,
     ModelOption, SeriesDataType, OptionSourceData, SOURCE_FORMAT_TYPED_ARRAY, SOURCE_FORMAT_ORIGINAL,
-    DecalObject
+    DecalObject, SymbolClip
 } from '../util/types';
 import {isDataItemOption, convertOptionIdName} from '../util/model';
 import {getECData, setCommonECData} from '../util/innerStore';
@@ -137,6 +137,7 @@
     symbolSize?: number | number[]
     symbolRotate?: number
     symbolKeepAspect?: boolean
+    symbolClip?: SymbolCli
     symbolOffset?: string | number | (string | number)[]
 
     liftZ?: number
diff --git a/src/util/types.ts b/src/util/types.ts
index 82a691f..a4e7fad 100644
--- a/src/util/types.ts
+++ b/src/util/types.ts
@@ -42,14 +42,13 @@
 import { RadialGradientObject } from 'zrender/src/graphic/RadialGradient';
 import { RectLike } from 'zrender/src/core/BoundingRect';
 import { TSpanStyleProps } from 'zrender/src/graphic/TSpan';
-import { PathStyleProps } from 'zrender/src/graphic/Path';
+import Path, { PathStyleProps } from 'zrender/src/graphic/Path';
 import { ImageStyleProps } from 'zrender/src/graphic/Image';
 import ZRText, { TextStyleProps } from 'zrender/src/graphic/Text';
 import { Source } from '../data/Source';
 import Model from '../model/Model';
 
 
-
 // ---------------------------
 // Common types and constants
 // ---------------------------
@@ -934,10 +933,13 @@
 }
 
 // TODO: TYPE value type?
+export type SymbolClip = string | Path;
 export type SymbolSizeCallback<T> = (rawValue: any, params: T) => number | number[];
 export type SymbolCallback<T> = (rawValue: any, params: T) => string;
 export type SymbolRotateCallback<T> = (rawValue: any, params: T) => number;
+export type SymbolClipCallback<T> = (rawValue: any, params: T) => SymbolClip;
 export type SymbolOffsetCallback<T> = (rawValue: any, params: T) => string | number | (string | number)[];
+
 /**
  * Mixin of option set to control the element symbol.
  * Include type of symbol, and size of symbol.
@@ -956,6 +958,8 @@
 
     symbolKeepAspect?: boolean
 
+    symbolClip?: SymbolClip | (unknown extends T ? never : SymbolClipCallback<T>)
+
     symbolOffset?: string | number | (string | number)[] | (unknown extends T ? never : SymbolOffsetCallback<T>)
 }
 
diff --git a/src/visual/symbol.ts b/src/visual/symbol.ts
index 1e17689..bbfd0d6 100644
--- a/src/visual/symbol.ts
+++ b/src/visual/symbol.ts
@@ -26,6 +26,8 @@
     SymbolCallback,
     CallbackDataParams,
     SymbolRotateCallback,
+    SymbolClipCallback,
+    SymbolClip
     SymbolOffsetCallback
 } from '../util/types';
 import List from '../data/List';
@@ -58,20 +60,25 @@
         const symbolSize = seriesModel.get('symbolSize');
         const keepAspect = seriesModel.get('symbolKeepAspect');
         const symbolRotate = seriesModel.get('symbolRotate');
+        const symbolClip = seriesModel.get('symbolClip');
         const symbolOffset = seriesModel.get('symbolOffset');
 
+
         const hasSymbolTypeCallback = isFunction(symbolType);
         const hasSymbolSizeCallback = isFunction(symbolSize);
         const hasSymbolRotateCallback = isFunction(symbolRotate);
         const hasSymbolOffsetCallback = isFunction(symbolOffset);
+        const hasSymbolClipCallback = isFunction(symbolClip);
         const hasCallback = hasSymbolTypeCallback
             || hasSymbolSizeCallback
             || hasSymbolRotateCallback
-            || hasSymbolOffsetCallback;
+            || hasSymbolOffsetCallback
+            || hasSymbolClipCallback;
         const seriesSymbol = (!hasSymbolTypeCallback && symbolType) ? symbolType : seriesModel.defaultSymbol;
         const seriesSymbolSize = !hasSymbolSizeCallback ? symbolSize : null;
         const seriesSymbolRotate = !hasSymbolRotateCallback ? symbolRotate : null;
         const seriesSymbolOffset = !hasSymbolOffsetCallback ? symbolOffset : null;
+        const seriesSymbolClip = !hasSymbolClipCallback ? symbolClip : null;
 
         data.setVisual({
             legendIcon: seriesModel.legendIcon || seriesSymbol as string,
@@ -83,6 +90,7 @@
             symbolSize: seriesSymbolSize as number | number[],
             symbolKeepAspect: keepAspect,
             symbolRotate: seriesSymbolRotate as number,
+            symbolClip: seriesSymbolClip as SymbolClip,
             symbolOffset: seriesSymbolOffset as string | number | (string | number)[]
         });
 
@@ -103,6 +111,9 @@
             hasSymbolRotateCallback && data.setItemVisual(
                 idx, 'symbolRotate', (symbolRotate as SymbolRotateCallback<CallbackDataParams>)(rawValue, params)
             );
+            hasSymbolClipCallback && data.setItemVisual(
+                idx, 'symbolClip', (symbolClip as SymbolClipCallback<CallbackDataParams>)(rawValue, params)
+            );
             hasSymbolOffsetCallback && data.setItemVisual(
                 idx, 'symbolOffset', (symbolOffset as SymbolOffsetCallback<CallbackDataParams>)(rawValue, params)
             );
@@ -140,6 +151,7 @@
             const itemSymbolRotate = itemModel.getShallow('symbolRotate', true);
             const itemSymbolOffset = itemModel.getShallow('symbolOffset', true);
             const itemSymbolKeepAspect = itemModel.getShallow('symbolKeepAspect', true);
+            const itemSymbolClip = itemModel.getShallow('symbolClip', true);
 
             // If has item symbol
             if (itemSymbolType != null) {
@@ -158,6 +170,9 @@
             if (itemSymbolKeepAspect != null) {
                 data.setItemVisual(idx, 'symbolKeepAspect', itemSymbolKeepAspect);
             }
+            if (itemSymbolClip != null) {
+                data.setItemVisual(idx, 'symbolClip', itemSymbolClip);
+            }
         }
 
         return { dataEach: data.hasItemOption ? dataEach : null };
diff --git a/test/symbol-clip.html b/test/symbol-clip.html
new file mode 100644
index 0000000..2709a56
--- /dev/null
+++ b/test/symbol-clip.html
@@ -0,0 +1,254 @@
+<!DOCTYPE html>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+
+<html>
+    <head>
+        <meta charset="utf-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1" />
+        <script src="lib/esl.js"></script>
+        <script src="lib/config.js"></script>
+        <!-- <script src="lib/jquery.min.js"></script> -->
+        <script src="lib/facePrint.js"></script>
+        <script src="lib/testHelper.js"></script>
+        <!-- <script src="ut/lib/canteen.js"></script> -->
+        <link rel="stylesheet" href="lib/reset.css" />
+        <style>
+            #main0 {
+                height: calc(100% - 120px);
+            }
+            .test-title-inner {
+                text-align: center;
+            }
+            .test-chart-block-left {
+                height: 100%;
+            }
+            .test-chart {
+                height: calc(100% - 45px);
+            }
+        </style>
+    </head>
+    <body>
+
+
+        <div id="main0"></div>
+
+
+        <script>
+        require(['echarts'], function (echarts) {
+            var CLIP_PATHS = [
+                // no clip
+                'NO CLIPPING', // for test
+
+                // clip path
+                'circle(50px at 50 50)',
+                'ellipse(20px 20px at 50% 50%);',
+                'inset(10% 20% 30% 10% round 100%);',
+                'rect(25% 3% 10% 5% round 5% 10% 25% 30%);',
+                'rect(25% round 10px);',
+                'path(M367.855,428.202c-3.674-1.385-7.452-1.966-11.146-1.794c0.659-2.922,0.844-5.85,0.58-8.719 c-0.937-10.407-7.663-19.864-18.063-23.834c-10.697-4.043-22.298-1.168-29.902,6.403c3.015,0.026,6.074,0.594,9.035,1.728 c13.626,5.151,20.465,20.379,15.32,34.004c-1.905,5.02-5.177,9.115-9.22,12.05c-6.951,4.992-16.19,6.536-24.777,3.271 c-13.625-5.137-20.471-20.371-15.32-34.004c0.673-1.768,1.523-3.423,2.526-4.992h-0.014c0,0,0,0,0,0.014 c4.386-6.853,8.145-14.279,11.146-22.187c23.294-61.505-7.689-130.278-69.215-153.579c-61.532-23.293-130.279,7.69-153.579,69.202 c-6.371,16.785-8.679,34.097-7.426,50.901c0.026,0.554,0.079,1.121,0.132,1.688c4.973,57.107,41.767,109.148,98.945,130.793 c58.162,22.008,121.303,6.529,162.839-34.465c7.103-6.893,17.826-9.444,27.679-5.719c11.858,4.491,18.565,16.6,16.719,28.643 c4.438-3.126,8.033-7.564,10.117-13.045C389.751,449.992,382.411,433.709,367.855,428.202z)',
+                'path(M215,100.3c97.8-32.6,90.5-71.9,336-77.6 c92.4-2.1,98.1,81.6,121.8,116.4c101.7,149.9,53.5,155.9,14.7,178c-96.4,54.9,5.4,269-257,115.1c-57-33.5-203,46.3-263.7,20.1c-33.5-14.5-132.5-45.5-95-111.1C125.9,246.6,98.6,139.1,215,100.3z)',
+                'path(M680.96 494.933H573.44l20.48-141.653c0-5.12-3.413-8.533-6.827-10.24h-1.706c-1.707 0-5.12 1.707-6.827 3.413L404.48 549.547c-3.413 3.413-1.707 8.533 1.707 11.946 1.706 1.707 3.413 1.707 5.12 1.707h109.226l-20.48 141.653c0 5.12 3.414 8.534 6.827 10.24h1.707c1.706 0 5.12-1.706 6.826-3.413l174.08-203.093c3.414-3.414 1.707-8.534-1.706-11.947-3.414-1.707-5.12-1.707-6.827-1.707z)',
+                'path(\'M0.5,1 C0.5,1,0,0.7,0,0.3 A0.25,0.25,1,1,1,0.5,0.3 A0.25,0.25,1,1,1,1,0.3 C1,0.7,0.5,1,0.5,1 Z\')',
+                'path(M348.16 276.48c-7.68 15.36-20.48 25.6-33.28 25.6L120.32 332.8c-74.24 12.8-102.4 104.96-51.2 161.28l138.24 140.8c10.24 12.8 15.36 28.16 12.8 40.96L189.44 870.4c-12.8 76.8 66.56 135.68 130.56 99.84l171.52-92.16c12.8-7.68 28.16-7.68 40.96 0l171.52 92.16c64 35.84 143.36-20.48 130.56-99.84l-33.28-197.12c-2.56-15.36 2.56-30.72 12.8-43.52l138.24-138.24c53.76-56.32 23.04-148.48-48.64-161.28l-192-28.16c-15.36-2.56-28.16-12.8-33.28-25.6l-84.48-181.76c-33.28-71.68-128-71.68-161.28 0l-84.48 181.76z)',
+                'path(M126.153,71.798c0,35.275-30.128,31.452-65.403,31.452S0.411,107.073,0.411,71.798S34,0.927,63.282,0.927             C92,0.927,126.153,36.523,126.153,71.798z)',
+                'path(M971.464704 668.658688 968.998912 651.020288 965.843968 633.814016 963.337216 624.9728 960.917504 615.569408 957.71648 606.598144 954.430464 596.612096 950.668288 587.208704 946.562048 577.545216 939.254784 561.765376 932.769792 547.8656 926.285824 535.437312 920.62208 523.848704 914.138112 513.301504 909.382656 503.616512 899.309568 489.15456 886.64064 469.894144 883.70176 465.138688 882.707456 463.107072 882.707456 461.50656 884.825088 455.000064 887.763968 449.207296 890.314752 437.772288 891.742208 431.869952 891.742208 425.77408 892.478464 420.867072 892.478464 415.93856 891.742208 410.27584 890.92096 405.649408 889.061376 396.26752 886.64064 387.145728 884.435968 378.779648 880.97792 370.651136 877.08672 363.864064 874.015744 357.487616 870.601728 351.413248 865.240064 342.463488 863.25248 339.28704 862.646272 336.520192 860.182528 319.161344 858.58304 307.725312 856.767488 293.567488 853.957632 278.93248 849.547264 262.158336 847.040512 252.754944 845.049856 244.799488 842.284032 235.547648 839.171072 225.712128 836.058112 216.590336 832.079872 206.77632 823.953408 187.817984 819.15392 178.84672 813.359104 168.557568 807.913472 159.73888 802.465792 149.751808 794.769408 140.498944 788.286464 131.52768 780.374016 122.27584 772.332544 113.88928 764.203008 105.783296 754.562048 97.373184 749.504512 94.348288 744.706048 90.153984 734.329856 82.783232 722.312192 74.806272 710.032384 67.586048 697.365504 61.079552 683.531264 55.135232 670.560256 49.492992 657.027072 44.56448 642.24256 40.521728 628.7104 36.912128 614.31296 33.75616 600.694784 30.427136 585.996288 28.827648 571.597824 27.076608 557.246464 25.19552 542.416896 25.19552 528.106496 25.19552 514.271232 25.19552 499.70176 26.039296 486.040576 27.940864 472.421376 29.821952 458.587136 32.135168 444.88192 34.750464 431.911936 37.927936 418.941952 42.121216 406.880256 46.31552 394.81856 50.357248 382.712832 56.301568 371.299328 61.079552 361.182208 66.873344 350.63296 73.37984 340.90496 80.167936 331.308032 87.819264 323.396608 94.930944 310.9888 106.626048 300.698624 117.49888 290.8416 128.048128 281.8048 138.770432 273.332224 149.751808 265.895936 160.451584 258.676736 171.15136 255.304704 175.929344 252.191744 181.722112 245.446656 191.860736 240.086016 201.977856 235.33056 211.530752 231.179264 221.648896 227.115008 230.899712 223.742976 239.5904 220.63104 248.841216 217.474048 257.380352 213.279744 272.858112 210.210816 287.753216 208.525312 300.203008 206.795776 310.925312 206.795776 319.161344 206.795776 325.818368 206.795776 331.741184 203.855872 334.941184 201.17504 339.28704 199.057408 343.177216 197.240832 347.370496 194.950144 356.493312 192.442368 364.880896 191.62112 372.381696 191.058944 377.893888 191.058944 383.816704 185.265152 392.225792 181.157888 400.613376 178.045952 408.697856 175.75424 415.93856 173.98272 422.878208 172.296192 429.405184 172.296192 434.875392 172.296192 440.971264 172.296192 446.0288 173.290496 450.071552 174.716928 457.464832 176.489472 463.107072 173.290496 465.570816 164.210688 472.358912 152.236032 483.339264 144.88576 489.846784 137.709568 496.223232 132.781056 501.303296 128.7168 505.778176 119.983104 515.180544 111.68256 524.583936 105.197568 532.690944 97.415168 544.407552 89.979904 554.954752 82.629632 566.693888 76.447744 577.545216 71.303168 589.089792 65.855488 599.810048 61.877248 610.36032 57.683968 621.362176 54.571008 632.061952 51.501056 643.064832 48.77824 652.619776 47.263744 662.888448 45.57824 672.421888 44.150784 681.695232 43.287552 699.766784 43.287552 716.540928 43.287552 724.063232 44.150784 731.456512 46.44352 744.0384 47.263744 749.572096 48.77824 755.190784 50.6368 760.510464 52.366336 764.269568 55.133184 771.23072 57.25184 772.658176 58.548224 775.597056 60.191744 776.288256 61.186048 776.288256 61.877248 776.288256 69.097472 775.597056 76.447744 773.696512 82.629632 771.23072 89.114624 767.03744 95.03744 763.14624 100.39808 758.044672 106.191872 752.72704 111.077376 747.235328 115.745792 741.010432 119.983104 735.388672 123.961344 730.722304 126.425088 725.36064 131.267584 716.540928 132.781056 712.930304 133.645312 710.769664 134.076416 708.304896 135.201792 706.27328 136.066048 705.841152 137.709568 704.974848 138.74688 704.974848 139.179008 705.841152 140.000256 705.841152 140.822528 706.27328 143.545344 718.270464 146.485248 727.955456 150.419456 738.11456 154.396672 747.235328 157.72672 756.31616 162.871296 764.269568 166.631424 772.658176 170.86976 780.352512 175.75424 787.009536 179.472384 793.409536 189.329408 805.254144 197.933056 815.804416 206.2336 824.018944 214.40512 831.412224 221.495296 837.204992 232.044544 846.58688 236.281856 848.661504 237.707264 850.650112 237.707264 851.644416 236.713984 852.552704 236.281856 852.552704 234.1632 853.244928 226.250752 853.850112 218.901504 854.844416 212.718592 855.709696 206.2336 857.135104 200.569856 858.907648 194.950144 860.637184 190.021632 863.275008 186.131456 865.696768 181.157888 867.296256 178.045952 869.890048 174.716928 871.921664 171.127808 874.816512 166.631424 880.438272 164.94592 883.076096 162.871296 885.366784 160.017408 891.290624 158.461952 896.22016 156.601344 901.146624 156.212224 905.470976 156.212224 911.133696 156.212224 913.598464 155.390976 917.618688 155.390976 921.726976 154.396672 925.7472 154.396672 929.33632 155.390976 933.269504 156.212224 936.77056 158.461952 943.516672 160.017408 946.715648 162.006016 949.9136 164.210688 953.069568 166.631424 955.838464 169.875456 958.993408 172.296192 961.5872 179.472384 966.948864 186.692608 971.444224 194.950144 975.50848 203.855872 979.139584 213.279744 983.02976 223.742976 985.452544 234.1632 988.9536 245.446656 991.289344 256.688128 992.974848 268.273664 994.748416 280.249344 996.477952 303.855616 998.940672 328.195072 999.3728 350.63296 999.3728 361.182208 999.3728 371.299328 999.3728 381.847552 998.940672 390.884352 997.905408 399.617024 997.213184 407.788544 996.477952 420.931584 993.883136 430.398464 991.289344 439.392256 988.9536 455.993344 981.994496 463.516672 979.139584 470.69184 975.50848 482.53952 968.85248 493.216768 963.489792 501.129216 958.43328 506.921984 953.069568 515.95776 954.063872 522.96192 954.843136 536.79616 955.838464 543.281152 955.838464 548.770816 955.838464 552.96512 956.70272 557.246464 958.43328 564.033536 960.893952 571.597824 963.489792 585.996288 967.986176 600.694784 973.345792 615.005184 977.496064 629.445632 980.438016 644.187136 984.155136 659.448832 986.359808 673.931264 987.959296 688.458752 989.990912 702.03392 991.289344 716.560384 992.108544 730.481664 992.108544 744.013824 992.108544 756.854784 992.108544 769.823744 990.554112 782.534656 989.990912 794.769408 987.959296 806.052864 985.452544 817.337344 983.02976 828.147712 980.438016 832.641024 979.139584 837.6576 977.496064 847.040512 973.778944 855.384064 969.887744 863.25248 965.823488 870.601728 961.5872 877.08672 956.70272 879.637504 954.063872 882.707456 950.4768 886.64064 945.677312 890.92096 939.754496 892.478464 936.77056 893.169664 934.264832 894.984192 931.064832 895.676416 927.60576 895.676416 924.275712 896.54272 920.947712 895.676416 916.063232 894.984192 911.868928 893.169664 906.940416 891.742208 902.87616 889.061376 897.946624 885.820416 893.452288 882.707456 889.561088 878.513152 886.275072 869.866496 878.751744 860.182528 871.488512 850.41152 865.696768 840.121344 859.772928 816.603136 848.186368 810.9824 844.727296 809.426944 843.127808 808.430592 842.090496 819.759104 830.675968 824.644608 825.056256 828.70784 819.867648 836.619264 808.411136 844.09856 796.694528 850.41152 786.275328 856.377344 776.288256 864.375808 756.31616 870.601728 739.714048 874.707968 727.955456 877.08672 724.063232 878.513152 720.907264 880.97792 719.004672 882.015232 719.004672 882.707456 719.438848 888.759296 731.456512 894.163968 743.042048 897.968128 749.572096 901.901312 755.190784 905.793536 762.107904 910.808064 768.941056 915.001344 773.696512 917.552128 776.288256 920.059904 778.625024 922.351616 780.352512 924.557312 781.953024 929.398784 784.417792 931.90656 785.282048 933.593088 785.282048 935.839744 785.282048 938.391552 784.417792 941.548544 782.81728 945.050624 781.216768 947.945472 778.625024 950.668288 775.597056 953.73824 771.835904 956.158976 768.941056 958.88384 764.269568 960.917504 760.510464 963.337216 755.190784 964.6336 750.695424 968.136704 739.714048 970.426368 727.565312 972.068864 714.097664 973.193216 706.27328 973.193216 699.766784 973.193216 692.805632 973.193216 684.288Z)',
+                'path(M331.428571 263.428571q0-23.428571-14.285714-37.714285t-37.714286-14.285715q-24.571429 0-43.428571 14.571429T217.142857 263.428571q0 22.285714 18.857143 36.857143t43.428571 14.571429q23.428571 0 37.714286-14t14.285714-37.428572z m424.571429 289.714286q0-16-14.571429-28.571428t-37.428571-12.571429q-15.428571 0-28.285714 12.857143T662.857143 553.142857q0 16 12.857143 28.857143t28.285714 12.857143q22.857143 0 37.428571-12.571429t14.571429-29.142857z m-134.857143-289.714286q0-23.428571-14-37.714285T569.714286 211.428571q-24.571429 0-43.428572 14.571429T507.428571 263.428571q0 22.285714 18.857143 36.857143t43.428572 14.571429q23.428571 0 37.428571-14T621.142857 263.428571z m362.857143 289.714286q0-16-14.857143-28.571428t-37.142857-12.571429q-15.428571 0-28.285714 12.857143T890.857143 553.142857q0 16 12.857143 28.857143t28.285714 12.857143q22.285714 0 37.142857-12.571429t14.857143-29.142857z m-152-226.857143q-17.714286-2.285714-40-2.285714-96.571429 0-177.714286 44T486.571429 487.142857 440 651.428571q0 44.571429 13.142857 86.857143-20 1.714286-38.857143 1.714286-14.857143 0-28.571428-0.857143t-31.428572-3.714286-25.428571-4-31.142857-6-28.571429-6l-144.571428 72.571429 41.142857-124.571429Q0 551.428571 0 387.428571q0-96.571429 55.714286-177.714285t150.857143-127.714286T414.285714 35.428571q100.571429 0 190 37.714286t149.714286 104.285714T832 326.285714z m338.285714 320.571429q0 66.857143-39.142857 127.714286T1025.142857 885.142857l31.428572 103.428572-113.714286-62.285715q-85.714286 21.142857-124.571429 21.142857-96.571429 0-177.714285-40.285714T512.857143 797.714286 466.285714 646.857143t46.571429-150.857143T640.571429 386.571429t177.714285-40.285715q92 0 173.142857 40.285715t130 109.714285T1170.285714 646.857143z)',
+                'path(M210.410732 410.339412H68.474355a68.421137 68.421137 0 0 0-68.182617 74.128577l39.866898 476.801278a68.438174 68.438174 0 0 0 68.182617 62.730733h102.069479a34.210568 34.210568 0 0 0 34.210568-34.210568V444.567017a34.227605 34.227605 0 0 0-34.210568-34.227605zM953.792071 410.339412H647.583632C752.941279 19.98456 574.340986 0 574.340986 0c-75.781179 0-60.07294 60.004792-65.763343 69.971516 0 144.883801-116.380673 265.881539-172.90989 316.107015a67.875948 67.875948 0 0 0-22.608279 50.821775v552.889126c0 18.894183 15.316385 34.210568 34.210569 34.210568h399.99787a136.654865 136.654865 0 0 0 122.616265-76.053773c31.143884-63.020365 69.290031-154.509783 93.602023-229.660589 23.528284-72.697458 44.90989-162.875017 57.449222-226.287235a68.370025 68.370025 0 0 0-67.143352-81.658991z)',
+                'path(M673.92 175.04l-64 11.2-14.08-78.72 64-11.2zM864 486.72l75.2 27.2 20.8-60.16-75.2-27.2zM919.68 224l-41.28-48.32-61.12 51.52 40.96 48.96z m-232.64 196.16A256 256 0 0 0 192 490.88 192 192 0 0 0 256 864h384a224 224 0 0 0 47.04-442.88z m34.88-40.32a268.16 268.16 0 0 1 105.28 62.4A158.08 158.08 0 0 0 838.4 384a160 160 0 0 0-241.28-136.96 306.56 306.56 0 0 1 124.8 133.76z)',
+                'polygon(50% 30%, 100% 0%, 70% 50%, 100% 100%, 50% 70%, 0% 100%, 30% 50%, 0% 0%);',
+                'polygon(50% 0%, 60% 40%, 100% 50%, 50% 100%, 40% 60%, 0% 50%)',
+                'polygon(50% 2.4%, 34.5% 33.8%, 0% 38.8%, 25% 63.1%, 19.1% 97.6%, 50% 81.3%, 80.9% 97.6%, 75% 63.1%, 100% 38.8%, 65.5% 33.8%);',
+                'polygon(30% 31%, 20% 84%, 83% 83%, 93% 42%, 90% 18%, 58% 13%, 5% 14%, 13% 50%);',
+                'polygon(0% 0%, 100% 0%, 100% 75%, 75% 75%, 75% 100%, 50% 75%, 0% 75%);',
+                'polygon(40% 0%, 40% 20%, 100% 20%, 100% 80%, 40% 80%, 40% 100%, 0% 50%);',
+                'polygon(20% 0%, 0% 20%, 30% 50%, 0% 80%, 20% 100%, 50% 70%, 80% 100%, 100% 80%, 70% 50%, 100% 20%, 80% 0%, 50% 30%);',
+                'polygon(50% 0%, 80% 10%, 100% 35%, 100% 70%, 80% 90%, 50% 100%, 20% 90%, 0% 70%, 0% 35%, 20% 10%);',
+                'polygon(20% 0%, 80% 0%, 100% 100%, 0% 100%);',
+
+                // Path
+                new echarts.graphic.Sector({
+                  shape: {
+                    cx: 0,
+                    cy: 0,
+                    r: 50,
+                    endAngle: 230 * Math.PI / 180
+                  }
+                }),
+                new echarts.graphic.Ring({
+                  shape: {
+                    cx: 0,
+                    cy: 0,
+                    r: 50,
+                    r0: 20
+                  }
+                })
+            ];
+
+            var CLIPPING = true;
+            var ROTATE = false;
+            var symbolSize = 100;
+            var dpr = window.devicePixelRatio || 1;
+
+            var option = {
+                textStyle: {
+                    fontFamily: 'PingFang SC'
+                },
+                title: {
+                    text: 'Various Clipping of Symbol'
+                },
+                xAxis: {
+                    type: 'category'
+                },
+                yAxis: {
+                    type: 'value'
+                },
+                grid: {
+                    top: '10%',
+                    left: '5%',
+                    right: '5%',
+                    bottom: '10%'
+                },
+                toolbox: {
+                    feature: {
+                        saveAsImage: {}
+                    }
+                },
+                dataZoom: [
+                    {
+                        show: true,
+                        realtime: true,
+                        xAxisIndex: [0, 1]
+                    },
+                    {
+                        type: 'inside',
+                        realtime: true,
+                        xAxisIndex: [0, 1]
+                    }
+                ],
+                series: [{
+                    type: 'line',
+                    symbolSize: symbolSize,
+                    symbol: getSymbolImage(),
+                    symbolRotate: getSymbolRotate(),
+                    symbolClip: getSymbolClip(),
+                    label: {
+                        show: true,
+                        formatter: function (params) {
+                            var clip = CLIP_PATHS[params.dataIndex % CLIP_PATHS.length];
+                            if (clip.type) {
+                                return clip.type;
+                            }
+                            var idx = clip.indexOf('(');
+                            return clip.slice(0, idx === -1 ? undefined : idx)/* + '('+ (~~params.value[1] % 360) +'°)'*/;
+                        }
+                    },
+                    data: (function() {
+                        var data = [];
+                        while (data.length < CLIP_PATHS.length) {
+                            data.push([data.length, ~~ (Math.random() * 2000)]);
+                        }
+                        return data;
+                    })()
+                }]
+            };
+
+            var refreshCounter = 0;
+
+            function getSymbolImage(refresh) {
+                refresh && (refreshCounter++);
+                return function(rawValue, params) {
+                    return 'image://https://picsum.photos/' + symbolSize * dpr + (refresh ? '?_=' + refreshCounter/*params.dataIndex*/ : '');
+                }
+            }
+
+            function getSymbolClip() {
+                return CLIPPING && function(rawValue, params) {
+                    return CLIP_PATHS[params.dataIndex % CLIP_PATHS.length];
+                }
+            }
+
+            function getSymbolRotate() {
+                return ROTATE && function(rawValue, params) {
+                    return ~~rawValue[1] % 360;
+                }
+            }
+
+            function updateChart(refreshImage) {
+                var refreshOption = {
+                    symbolClip: getSymbolClip(),
+                    symbolRotate: getSymbolRotate()
+                };
+                refreshImage && (refreshOption.symbol = getSymbolImage(refreshImage));
+                chart.setOption({
+                    series: [refreshOption]
+                });
+            }
+
+            var chart = testHelper.create(echarts, 'main0', {
+                title: [
+                    'Various Clipping of Symbol',
+                    `The supported currently rules are '**inset**'、'**rect**'、'**circle**'、'**ellipse**'、'**polygon**'、'**path**'`,
+                    'https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path'
+                ],
+                buttons: [
+                    {
+                        text: 'Clear clipping',
+                        onclick: function () {
+                            CLIPPING = false;
+                            updateChart();
+                        }
+                    },
+                    {
+                        text: 'Enable clipping',
+                        onclick: function () {
+                            CLIPPING = true;
+                            updateChart();
+                        }
+                    },
+                    {
+                        text: 'Disable Rotating',
+                        onclick: function () {
+                            ROTATE = false;
+                            updateChart();
+                        }
+                    },
+                    {
+                        text: 'Enable rotating',
+                        onclick: function () {
+                            ROTATE = true;
+                            updateChart();
+                        }
+                    },
+                    {
+                        text: 'Refresh image',
+                        onclick: function () {
+                            updateChart(true);
+                        }
+                    }
+                ],
+                option: option
+            });
+        });
+        </script>
+
+    </body>
+</html>
+