You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by su...@apache.org on 2021/03/09 17:58:23 UTC

[echarts] 05/06: feature: [geo] support geo svg named elements have the same behavior as regions of geoJSON

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

sushuang pushed a commit to branch fix/geo-svg
in repository https://gitbox.apache.org/repos/asf/echarts.git

commit ca5817445241ab7ccc55853ac8049b662b632449
Author: 100pah <su...@gmail.com>
AuthorDate: Tue Mar 9 12:51:20 2021 +0800

    feature: [geo] support geo svg named elements have the same behavior as regions of geoJSON
---
 src/component/helper/MapDraw.ts | 386 +++++++++++++++++++++++-----------------
 src/coord/geo/GeoModel.ts       |   1 -
 src/coord/geo/GeoSVGResource.ts |   6 +-
 test/geo-svg.html               | 170 ++++++++++++++++++
 4 files changed, 398 insertions(+), 165 deletions(-)

diff --git a/src/component/helper/MapDraw.ts b/src/component/helper/MapDraw.ts
index 1ca9ad9..a7176bf 100644
--- a/src/component/helper/MapDraw.ts
+++ b/src/component/helper/MapDraw.ts
@@ -39,11 +39,24 @@ import { getECData } from '../../util/innerStore';
 import { createOrUpdatePatternFromDecal } from '../../util/decal';
 import { ViewCoordSysTransformInfoPart } from '../../coord/View';
 import { GeoSVGResource } from '../../coord/geo/GeoSVGResource';
+import Displayable from 'zrender/src/graphic/Displayable';
+import Element, { ElementTextConfig } from 'zrender/src/Element';
+import List from '../../data/List';
 
 
 interface RegionsGroup extends graphic.Group {
 }
 
+interface ViewBuildContext {
+    api: ExtensionAPI;
+    geo: Geo;
+    mapOrGeoModel: GeoModel | MapSeries;
+    data: List;
+    isVisualEncodedByVisualMap: boolean;
+    isGeo: boolean;
+    transformInfoRaw: ViewCoordSysTransformInfoPart;
+}
+
 function getFixedItemStyle(model: Model<GeoItemStyleOption>) {
     const itemStyle = model.getItemStyle();
     const areaColor = model.get('areaColor');
@@ -78,12 +91,14 @@ class MapDraw {
      */
     private _mouseDownFlag: boolean;
 
-    private _mapName: string;
+    private _svgMapName: string;
 
     private _regionsGroup: RegionsGroup;
 
     private _svgGroup: graphic.Group;
 
+    private _svgNamedElements: Displayable[];
+
 
     constructor(api: ExtensionAPI) {
         const group = new graphic.Group();
@@ -117,7 +132,6 @@ class MapDraw {
 
         const geo = mapOrGeoModel.coordinateSystem;
 
-
         const regionsGroup = this._regionsGroup;
         const group = this.group;
 
@@ -125,8 +139,6 @@ class MapDraw {
         const transformInfoRaw = transformInfo.raw;
         const transformInfoRoam = transformInfo.roam;
 
-        this._updateSVG(geo, transformInfoRaw);
-
         // No animation when first draw or in action
         const isFirstDraw = !regionsGroup.childAt(0) || payload;
 
@@ -141,17 +153,44 @@ class MapDraw {
             graphic.updateProps(group, transformInfoRoam, mapOrGeoModel);
         }
 
-        regionsGroup.removeAll();
-
-        const nameMap = zrUtil.createHashMap<RegionsGroup>();
-
-
         const isVisualEncodedByVisualMap = data
             && data.getVisual('visualMeta')
             && data.getVisual('visualMeta').length > 0;
 
+        const viewBuildCtx = {
+            api,
+            geo,
+            mapOrGeoModel,
+            data,
+            isVisualEncodedByVisualMap,
+            isGeo,
+            transformInfoRaw
+        };
+
+        this._buildGeoJSON(viewBuildCtx);
+        this._buildSVG(viewBuildCtx);
+
+        this._updateController(mapOrGeoModel, ecModel, api);
+
+        this._updateMapSelectHandler(mapOrGeoModel, regionsGroup, api, fromView);
+    }
+
+    private _buildGeoJSON(viewBuildCtx: ViewBuildContext): void {
+        const nameMap = zrUtil.createHashMap<RegionsGroup>();
+        const regionsGroup = this._regionsGroup;
+        const transformInfoRaw = viewBuildCtx.transformInfoRaw;
+
+        const transformPoint = function (point: number[]): number[] {
+            return [
+                point[0] * transformInfoRaw.scaleX + transformInfoRaw.x,
+                point[1] * transformInfoRaw.scaleY + transformInfoRaw.y
+            ];
+        };
+
+        regionsGroup.removeAll();
 
-        zrUtil.each(geo.regions, function (region) {
+        // Only when the resource is GeoJSON, there is `geo.regions`.
+        zrUtil.each(viewBuildCtx.geo.regions, function (region) {
 
             // Consider in GeoJson properties.name may be duplicated, for example,
             // there is multiple region named "United Kindom" or "France" (so many
@@ -169,50 +208,6 @@ class MapDraw {
             });
             regionGroup.add(compoundPath);
 
-            const regionModel = mapOrGeoModel.getRegionModel(region.name) || mapOrGeoModel;
-
-            // @ts-ignore FIXME:TS fix the "compatible with each other"?
-            const itemStyleModel = regionModel.getModel('itemStyle');
-            // @ts-ignore FIXME:TS fix the "compatible with each other"?
-            const emphasisModel = regionModel.getModel('emphasis');
-            const emphasisItemStyleModel = emphasisModel.getModel('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 emphasisItemStyle = getFixedItemStyle(emphasisItemStyleModel);
-            const blurItemStyle = getFixedItemStyle(blurItemStyleModel);
-            const selectItemStyle = getFixedItemStyle(selectItemStyleModel);
-
-            let dataIdx;
-            // Use the itemStyle in data if has data
-            if (data) {
-                dataIdx = data.indexOfName(region.name);
-                // Only visual color of each item will be used. It can be encoded by visualMap
-                // But visual color of series is used in symbol drawing
-                //
-                // Visual color for each series is for the symbol draw
-                const style = data.getItemVisual(dataIdx, 'style');
-                const decal = data.getItemVisual(dataIdx, 'decal');
-                if (isVisualEncodedByVisualMap && style.fill) {
-                    itemStyle.fill = style.fill;
-                }
-                if (decal) {
-                    itemStyle.decal = createOrUpdatePatternFromDecal(decal, api);
-                }
-            }
-
-            const transformPoint = function (point: number[]): number[] {
-                return [
-                    point[0] * transformInfoRaw.scaleX + transformInfoRaw.x,
-                    point[1] * transformInfoRaw.scaleY + transformInfoRaw.y
-                ];
-            };
-
             zrUtil.each(region.geometries, function (geometry) {
                 if (geometry.type !== 'polygon') {
                     return;
@@ -243,149 +238,218 @@ class MapDraw {
                 }
             });
 
-            compoundPath.setStyle(itemStyle);
-            compoundPath.style.strokeNoScale = true;
-            compoundPath.culling = true;
-
-            compoundPath.ensureState('emphasis').style = emphasisItemStyle;
-            compoundPath.ensureState('blur').style = blurItemStyle;
-            compoundPath.ensureState('select').style = selectItemStyle;
-
-            let showLabel = false;
-            for (let i = 0; i < DISPLAY_STATES.length; i++) {
-                const stateName = DISPLAY_STATES[i];
-                // @ts-ignore FIXME:TS fix the "compatible with each other"?
-                if (regionModel.get(
-                    stateName === 'normal' ? ['label', 'show'] : [stateName, 'label', 'show']
-                )) {
-                    showLabel = true;
-                    break;
-                }
-            }
+            const centerPt = transformPoint(region.center);
 
-            const isDataNaN = data && isNaN(data.get(data.mapDimension('value'), dataIdx) as number);
-            const itemLayout = data && data.getItemLayout(dataIdx);
-
-            // In the following cases label will be drawn
-            // 1. In map series and data value is NaN
-            // 2. In geo component
-            // 4. Region has no series legendSymbol, which will be add a showLabel flag in mapSymbolLayout
-            if (
-                (isGeo || isDataNaN && (showLabel))
-                || (itemLayout && itemLayout.showLabel)
-            ) {
-                const query = !isGeo ? dataIdx : region.name;
-                let labelFetcher;
-
-                // Consider dataIdx not found.
-                if (!data || dataIdx >= 0) {
-                    labelFetcher = mapOrGeoModel;
-                }
+            this._resetSingleRegionGraphic(
+                viewBuildCtx, compoundPath, regionGroup, region.name, centerPt, null
+            );
 
-                const centerPt = transformPoint(region.center);
-                const textEl = new graphic.Text({
-                    x: centerPt[0],
-                    y: centerPt[1],
-                    z2: 10,
-                    silent: true
-                });
-                textEl.afterUpdate = labelTextAfterUpdate;
-
-                setLabelStyle<typeof query>(
-                    textEl, getLabelStatesModels(regionModel),
-                    {
-                        labelFetcher: labelFetcher,
-                        labelDataIndex: query,
-                        defaultText: region.name
-                    },
-                    { normal: {
-                        align: 'center',
-                        verticalAlign: 'middle'
-                    } }
-                );
-
-                compoundPath.setTextContent(textEl);
-                compoundPath.setTextConfig({
-                    local: true
-                });
-
-                (compoundPath as ECElement).disableLabelAnimation = true;
+            regionsGroup.add(regionGroup);
 
-            }
+        }, this);
+    }
+
+    private _buildSVG(viewBuildCtx: ViewBuildContext): void {
+        const mapName = viewBuildCtx.geo.map;
+        const transformInfoRaw = viewBuildCtx.transformInfoRaw;
+
+        this._svgGroup.x = transformInfoRaw.x;
+        this._svgGroup.y = transformInfoRaw.y;
+        this._svgGroup.scaleX = transformInfoRaw.scaleX;
+        this._svgGroup.scaleY = transformInfoRaw.scaleY;
+
+        if (this._svgResourceChanged(mapName)) {
+            this._freeSVG();
+            this._useSVG(mapName);
+        }
 
-            // setItemGraphicEl, setHoverStyle after all polygons and labels
-            // are added to the rigionGroup
-            if (data) {
-                data.setItemGraphicEl(dataIdx, regionGroup);
+        zrUtil.each(this._svgNamedElements, function (namedElement) {
+            this._resetSingleRegionGraphic(
+                viewBuildCtx, namedElement, namedElement, namedElement.name, [0, 0], 'inside'
+            );
+        }, this);
+    }
+
+    private _resetSingleRegionGraphic(
+        viewBuildCtx: ViewBuildContext,
+        displayable: Displayable,
+        elForStateChange: Element,
+        regionName: string,
+        labelXY: number[],
+        labelPosition: ElementTextConfig['position']
+    ): void {
+
+        const mapOrGeoModel = viewBuildCtx.mapOrGeoModel;
+        const data = viewBuildCtx.data;
+        const isVisualEncodedByVisualMap = viewBuildCtx.isVisualEncodedByVisualMap;
+        const isGeo = viewBuildCtx.isGeo;
+
+        const regionModel = mapOrGeoModel.getRegionModel(regionName) || mapOrGeoModel;
+
+        // @ts-ignore FIXME:TS fix the "compatible with each other"?
+        const itemStyleModel = regionModel.getModel('itemStyle');
+        // @ts-ignore FIXME:TS fix the "compatible with each other"?
+        const emphasisModel = regionModel.getModel('emphasis');
+        const emphasisItemStyleModel = emphasisModel.getModel('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 emphasisItemStyle = getFixedItemStyle(emphasisItemStyleModel);
+        const blurItemStyle = getFixedItemStyle(blurItemStyleModel);
+        const selectItemStyle = getFixedItemStyle(selectItemStyleModel);
+
+        let dataIdx;
+        // Use the itemStyle in data if has data
+        if (data) {
+            dataIdx = data.indexOfName(regionName);
+            // Only visual color of each item will be used. It can be encoded by visualMap
+            // But visual color of series is used in symbol drawing
+            //
+            // Visual color for each series is for the symbol draw
+            const style = data.getItemVisual(dataIdx, 'style');
+            const decal = data.getItemVisual(dataIdx, 'decal');
+            if (isVisualEncodedByVisualMap && style.fill) {
+                itemStyle.fill = style.fill;
             }
-            else {
-                const regionModel = mapOrGeoModel.getRegionModel(region.name);
-                // Package custom mouse event for geo component
-                getECData(compoundPath).eventData = {
-                    componentType: 'geo',
-                    componentIndex: mapOrGeoModel.componentIndex,
-                    geoIndex: mapOrGeoModel.componentIndex,
-                    name: region.name,
-                    region: (regionModel && regionModel.option) || {}
-                };
+            if (decal) {
+                itemStyle.decal = createOrUpdatePatternFromDecal(decal, viewBuildCtx.api);
             }
+        }
 
+        displayable.setStyle(itemStyle);
+        displayable.style.strokeNoScale = true;
+        displayable.culling = true;
+
+        displayable.ensureState('emphasis').style = emphasisItemStyle;
+        displayable.ensureState('blur').style = blurItemStyle;
+        displayable.ensureState('select').style = selectItemStyle;
+
+
+        let showLabel = false;
+        for (let i = 0; i < DISPLAY_STATES.length; i++) {
+            const stateName = DISPLAY_STATES[i];
             // @ts-ignore FIXME:TS fix the "compatible with each other"?
-            regionGroup.highDownSilentOnTouch = !!mapOrGeoModel.get('selectedMode');
-            enableHoverEmphasis(regionGroup, emphasisModel.get('focus'), emphasisModel.get('blurScope'));
+            if (regionModel.get(
+                stateName === 'normal' ? ['label', 'show'] : [stateName, 'label', 'show']
+            )) {
+                showLabel = true;
+                break;
+            }
+        }
 
-            regionsGroup.add(regionGroup);
-        });
+        const isDataNaN = data && isNaN(data.get(data.mapDimension('value'), dataIdx) as number);
+        const itemLayout = data && data.getItemLayout(dataIdx);
+
+        // In the following cases label will be drawn
+        // 1. In map series and data value is NaN
+        // 2. In geo component
+        // 4. Region has no series legendSymbol, which will be add a showLabel flag in mapSymbolLayout
+        if (
+            (isGeo || isDataNaN && (showLabel))
+            || (itemLayout && itemLayout.showLabel)
+        ) {
+            const query = !isGeo ? dataIdx : regionName;
+            let labelFetcher;
+
+            // Consider dataIdx not found.
+            if (!data || dataIdx >= 0) {
+                labelFetcher = mapOrGeoModel;
+            }
 
-        this._updateController(mapOrGeoModel, ecModel, api);
+            const textEl = new graphic.Text({
+                x: labelXY[0],
+                y: labelXY[1],
+                z2: 10,
+                silent: true
+            });
+            textEl.afterUpdate = labelTextAfterUpdate;
+
+            setLabelStyle<typeof query>(
+                textEl, getLabelStatesModels(regionModel),
+                {
+                    labelFetcher: labelFetcher,
+                    labelDataIndex: query,
+                    defaultText: regionName
+                },
+                { normal: {
+                    align: 'center',
+                    verticalAlign: 'middle'
+                } }
+            );
+
+            displayable.setTextContent(textEl);
+            displayable.setTextConfig({
+                local: true,
+                insideFill: textEl.style.fill,
+                position: labelPosition
+            });
+
+            (displayable as ECElement).disableLabelAnimation = true;
+        }
+
+
+        // setItemGraphicEl, setHoverStyle after all polygons and labels
+        // are added to the rigionGroup
+        if (data) {
+            data.setItemGraphicEl(dataIdx, elForStateChange);
+        }
+        else {
+            const regionModel = mapOrGeoModel.getRegionModel(regionName);
+            // Package custom mouse event for geo component
+            getECData(displayable).eventData = {
+                componentType: 'geo',
+                componentIndex: mapOrGeoModel.componentIndex,
+                geoIndex: mapOrGeoModel.componentIndex,
+                name: regionName,
+                region: (regionModel && regionModel.option) || {}
+            };
+        }
+
+        // @ts-ignore FIXME:TS fix the "compatible with each other"?
+        elForStateChange.highDownSilentOnTouch = !!mapOrGeoModel.get('selectedMode');
+        enableHoverEmphasis(elForStateChange, emphasisModel.get('focus'), emphasisModel.get('blurScope'));
 
-        this._updateMapSelectHandler(mapOrGeoModel, regionsGroup, api, fromView);
     }
 
     remove(): void {
         this._regionsGroup.removeAll();
         this._svgGroup.removeAll();
         this._controller.dispose();
-        this._freeSVG(this._mapName);
-        this._mapName = null;
+        this._freeSVG();
         this._controllerHost = null;
     }
 
-    private _updateSVG(geo: Geo, transformInfoRaw: ViewCoordSysTransformInfoPart): void {
-        const mapName = geo.map;
-
-        this._svgGroup.x = transformInfoRaw.x;
-        this._svgGroup.y = transformInfoRaw.y;
-        this._svgGroup.scaleX = transformInfoRaw.scaleX;
-        this._svgGroup.scaleY = transformInfoRaw.scaleY;
-
-        if (this._mapName !== mapName) {
-            this._freeSVG(this._mapName);
-            this._useSVG(mapName);
-            this._mapName = mapName;
-        }
+    private _svgResourceChanged(mapName: string): boolean {
+        return this._svgMapName !== mapName;
     }
 
-    private _useSVG(mapName: string) {
-        if (mapName == null) {
-            return;
-        }
+    private _useSVG(mapName: string): void {
         const resource = geoSourceManager.getGeoResource(mapName);
         if (resource && resource.type === 'svg') {
             const svgGraphic = (resource as GeoSVGResource).useGraphic(this.uid);
             this._svgGroup.add(svgGraphic.root);
+            this._svgNamedElements = svgGraphic.namedElements;
+            this._svgMapName = mapName;
         }
     }
 
-    private _freeSVG(mapName: string) {
+    private _freeSVG(): void {
+        const mapName = this._svgMapName;
         if (mapName == null) {
             return;
         }
         const resource = geoSourceManager.getGeoResource(mapName);
         if (resource && resource.type === 'svg') {
             (resource as GeoSVGResource).freeGraphic(this.uid);
-            this._svgGroup.removeAll();
         }
+        this._svgGroup.removeAll();
+        this._svgNamedElements = null;
+        this._svgMapName = null;
     }
 
     private _updateController(
diff --git a/src/coord/geo/GeoModel.ts b/src/coord/geo/GeoModel.ts
index 3705304..78054c6 100644
--- a/src/coord/geo/GeoModel.ts
+++ b/src/coord/geo/GeoModel.ts
@@ -163,7 +163,6 @@ class GeoModel extends ComponentModel<GeoOption> {
         },
 
         itemStyle: {
-            // color: 各异,
             borderWidth: 0.5,
             borderColor: '#444',
             color: '#eee'
diff --git a/src/coord/geo/GeoSVGResource.ts b/src/coord/geo/GeoSVGResource.ts
index 0a3a4ec..43c18fa 100644
--- a/src/coord/geo/GeoSVGResource.ts
+++ b/src/coord/geo/GeoSVGResource.ts
@@ -24,11 +24,11 @@ import {assert, createHashMap, HashMap} from 'zrender/src/core/util';
 import BoundingRect from 'zrender/src/core/BoundingRect';
 import { GeoResource, GeoSVGSourceInput } from './geoTypes';
 import { parseXML } from 'zrender/src/tool/parseXML';
-import Element from 'zrender/src/Element';
+import Displayable from 'zrender/src/graphic/Displayable';
 
 export interface GeoSVGGraphic {
     root: Group;
-    namedElements: Element[];
+    namedElements: Displayable[];
 }
 
 export class GeoSVGResource implements GeoResource {
@@ -115,7 +115,7 @@ function buildGraphic(
 ): {
     root: Group;
     boundingRect: BoundingRect;
-    namedElements: Element[]
+    namedElements: Displayable[]
 } {
     let result;
     let root;
diff --git a/test/geo-svg.html b/test/geo-svg.html
new file mode 100644
index 0000000..d7568d5
--- /dev/null
+++ b/test/geo-svg.html
@@ -0,0 +1,170 @@
+<!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" />
+    </head>
+    <body>
+        <style>
+        </style>
+
+
+
+        <div id="main0"></div>
+        <div id="main1"></div>
+
+
+
+
+
+
+        <script>
+        require(['echarts'/*, 'map/js/china' */], function (echarts) {
+            const testGeoJson1 = {
+                'type': 'FeatureCollection',
+                'features': [
+                    {
+                        'type': 'Feature',
+                        'geometry': {
+                            'type': 'Polygon',
+                            'coordinates': [
+                                [[2000, 2000], [5000, 2000], [5000, 5000], [2000, 5000]]
+                            ]
+                        },
+                        'properties': {
+                            'name': 'Afghanistan',
+                            'childNum': 1
+                        }
+                    }
+                ]
+            };
+
+            echarts.registerMap('testGeoJson1', testGeoJson1);
+
+            option = {
+                geo: {
+                    map: 'testGeoJson1',
+                    roam: true,
+                    // height: '100%',
+                    // center
+                    // layoutCenter: ['30%', 40],
+                    // layoutSize: 40,
+                    // boundingCoords
+                    zoom: 1,
+                    aspectScale: 1
+                }
+            };
+
+            var chart = testHelper.create(echarts, 'main0', {
+                title: [
+                    'geoJSON location:',
+                    'Should be a square and 80% of canvas height.',
+                    'At the center of the canvas.'
+                ],
+                option: option,
+                height: 300
+            });
+
+
+        });
+        </script>
+
+
+
+        <script>
+        require(['echarts'/*, 'map/js/china' */], function (echarts) {
+            var option;
+            $.ajax({
+                url: '../../vis-data/map/svg/seats/seatmap-example.svg', // 剧场例子
+                // url: '../../vis-data/map/svg/seats/Ethiopian_Airlines_Flight_961_seating_plan.svg', // 飞机例子
+                // url: '../../vis-data/map/svg/seats/oracle-seating-map-2017-2.svg', // 渲染错误
+                // url: '../../vis-data/map/svg/seats/DC-10-30_seat_configuration_chart.svg', // 渲染错误
+                // url: '../../vis-data/map/svg/seats/Airbus_A300B4-622R_seat_configuration_chart.svg', // 渲染错误
+                dataType: 'text'
+            }).done(function (svg) {
+
+                echarts.registerMap('seatmap', {
+                    svg: svg
+                });
+
+                option = {
+                    geo: {
+                        map: 'seatmap',
+                        roam: true,
+                        // height: 100,
+                        // zoom: 1.5
+                        emphasis: {
+                            // itemStyle: {
+                            //     color: 'red'
+                            // },
+                            label: {
+                                // color: '#fff',
+                                textBorderColor: '#fff',
+                                textBorderWidth: 2
+                            }
+                        },
+                        // itemStyle: {
+                        //     color: 'red'
+                        // },
+                        // label: {
+                        //     color: '#fff'
+                        // }
+                    },
+                    // series: {
+                    //     type: 'scatter',
+                    //     coordinateSystem: 'geo',
+                    //     // ?????????????????????????
+                    //     geoIndex: 0,
+                    //     data: [[11, 22], [33, 44]]
+                    // }
+                };
+
+                var chart = testHelper.create(echarts, 'main1', {
+                    title: [
+                        'Test Case Description of main0',
+                        '(Muliple lines and **emphasis** are supported in description)'
+                    ],
+                    option: option,
+                    height: 300
+                    // buttons: [{text: 'btn-txt', onclick: function () {}}],
+                    // recordCanvas: true,
+                });
+
+            });
+
+        });
+        </script>
+
+
+
+
+    </body>
+</html>
+


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