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/31 22:36:48 UTC
[echarts] 02/02: featrue: [geo] (1) support name on . (2) some
refactor.
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 8235095d6547ca062086bacccdc3963c9e92ed08
Author: 100pah <su...@gmail.com>
AuthorDate: Thu Apr 1 06:35:56 2021 +0800
featrue: [geo]
(1) support name on <g>.
(2) some refactor.
---
src/component/helper/MapDraw.ts | 497 ++++++++++++++++++++++++----------------
src/coord/geo/Geo.ts | 2 +-
src/coord/geo/GeoSVGResource.ts | 171 ++++++++------
src/coord/geo/geoTypes.ts | 18 --
src/core/echarts.ts | 40 ++--
test/geo-svg-demo.html | 298 +++++++++++++++++++++---
test/geo-svg.html | 249 ++++++++++----------
7 files changed, 818 insertions(+), 457 deletions(-)
diff --git a/src/component/helper/MapDraw.ts b/src/component/helper/MapDraw.ts
index c589119..22caaeb 100644
--- a/src/component/helper/MapDraw.ts
+++ b/src/component/helper/MapDraw.ts
@@ -26,7 +26,8 @@ import {
enableHoverEmphasis,
DISPLAY_STATES,
enableComponentHighDownFeatures,
- setDefaultStateProxy
+ setDefaultStateProxy,
+ SPECIAL_STATES
} from '../../util/states';
import geoSourceManager from '../../coord/geo/geoSourceManager';
import {getUID} from '../../util/component';
@@ -39,7 +40,7 @@ import GeoView from '../geo/GeoView';
import MapView from '../../chart/map/MapView';
import Geo from '../../coord/geo/Geo';
import Model from '../../model/Model';
-import { setLabelStyle, getLabelStatesModels } from '../../label/labelStyle';
+import { setLabelStyle, getLabelStatesModels, createTextConfig } from '../../label/labelStyle';
import { getECData } from '../../util/innerStore';
import { createOrUpdatePatternFromDecal } from '../../util/decal';
import { ViewCoordSysTransformInfoPart } from '../../coord/View';
@@ -48,14 +49,16 @@ import Displayable from 'zrender/src/graphic/Displayable';
import Element, { ElementTextConfig } from 'zrender/src/Element';
import List from '../../data/List';
import { GeoJSONRegion } from '../../coord/geo/Region';
-import { RegionGraphic } from '../../coord/geo/geoTypes';
-import { ItemStyleProps } from '../../model/mixin/itemStyle';
-import { LineStyleProps } from '../../model/mixin/lineStyle';
+import { SVGNodeTagLower } from 'zrender/src/tool/parseSVG';
interface RegionsGroup extends graphic.Group {
}
+type RegionModel = ReturnType<GeoModel['getRegionModel']> | ReturnType<MapSeries['getRegionModel']>;
+
+type MapOrGeoModel = GeoModel | MapSeries;
+
interface ViewBuildContext {
api: ExtensionAPI;
geo: Geo;
@@ -70,6 +73,26 @@ interface GeoStyleableOption {
itemStyle?: GeoItemStyleOption;
lineStyle?: LineStyleOption;
}
+type RegionName = string;
+
+/**
+ * Only these tags enable use `itemStyle` if they are named in SVG.
+ * Other tags like <text> <tspan> <image> might not suitable for `itemStyle`.
+ * They will not be considered to be styled until some requirements come.
+ */
+const OPTION_STYLE_ENABLED_TAGS: SVGNodeTagLower[] = [
+ 'rect', 'circle', 'line', 'ellipse', 'polygon', 'polyline', 'path'
+];
+const OPTION_STYLE_ENABLED_TAG_MAP = zrUtil.createHashMap<number, SVGNodeTagLower>(
+ OPTION_STYLE_ENABLED_TAGS
+);
+const STATE_TRIGGER_TAG_MAP = zrUtil.createHashMap<number, SVGNodeTagLower>(
+ OPTION_STYLE_ENABLED_TAGS.concat(['g']) as SVGNodeTagLower[]
+);
+const LABEL_HOST_MAP = zrUtil.createHashMap<number, SVGNodeTagLower>(
+ OPTION_STYLE_ENABLED_TAGS.concat(['g']) as SVGNodeTagLower[]
+);
+
function getFixedItemStyle(model: Model<GeoItemStyleOption>) {
const itemStyle = model.getItemStyle();
@@ -115,6 +138,10 @@ class MapDraw {
private _svgGraphicRecord: GeoSVGGraphicRecord;
+ // A name may correspond to multiple graphics.
+ // Used as event dispatcher.
+ private _svgDispatcherMap: zrUtil.HashMap<Element[], RegionName>;
+
constructor(api: ExtensionAPI) {
const group = new graphic.Group();
@@ -199,6 +226,8 @@ class MapDraw {
const nameMap = this._regionsGroupByName = zrUtil.createHashMap<RegionsGroup>();
const regionsGroup = this._regionsGroup;
const transformInfoRaw = viewBuildCtx.transformInfoRaw;
+ const mapOrGeoModel = viewBuildCtx.mapOrGeoModel;
+ const data = viewBuildCtx.data;
const transformPoint = function (point: number[]): number[] {
return [
@@ -211,14 +240,31 @@ class MapDraw {
// Only when the resource is GeoJSON, there is `geo.regions`.
zrUtil.each(viewBuildCtx.geo.regions, function (region: GeoJSONRegion) {
+ const regionName = region.name;
+ const regionModel = mapOrGeoModel.getRegionModel(regionName);
+ const dataIdx = data ? data.indexOfName(regionName) : null;
// Consider in GeoJson properties.name may be duplicated, for example,
// there is multiple region named "United Kindom" or "France" (so many
// colonies). And it is not appropriate to merge them in geo, which
// will make them share the same label and bring trouble in label
// location calculation.
- const regionGroup = nameMap.get(region.name)
- || nameMap.set(region.name, new graphic.Group() as RegionsGroup);
+ let regionGroup = nameMap.get(regionName);
+
+ if (!regionGroup) {
+ regionGroup = nameMap.set(regionName, new graphic.Group() as RegionsGroup);
+ regionsGroup.add(regionGroup);
+
+ resetEventTriggerForRegion(
+ viewBuildCtx, regionGroup, regionName, regionModel, mapOrGeoModel, dataIdx
+ );
+ resetTooltipForRegion(
+ viewBuildCtx, regionGroup, regionName, regionModel, mapOrGeoModel
+ );
+ resetStateTriggerForRegion(
+ viewBuildCtx, regionGroup, regionName, regionModel, mapOrGeoModel
+ );
+ }
const compoundPath = new graphic.CompoundPath({
segmentIgnoreThreshold: 1,
@@ -258,18 +304,18 @@ class MapDraw {
}
});
+ applyOptionStyleForRegion(
+ viewBuildCtx, compoundPath, dataIdx, regionModel
+ );
+
+ if (compoundPath instanceof Displayable) {
+ compoundPath.culling = true;
+ }
+
const centerPt = transformPoint(region.getCenter());
- const regionGraphic: RegionGraphic = {
- name: region.name,
- el: compoundPath,
- optionStyleEnabled: true,
- stateTrigger: regionGroup,
- eventTrigger: regionGroup,
- useLabel: true
- };
- this._resetSingleRegionGraphic(viewBuildCtx, regionGraphic, centerPt, null, false);
-
- regionsGroup.add(regionGroup);
+ resetLabelForRegion(
+ viewBuildCtx, compoundPath, regionName, regionModel, mapOrGeoModel, dataIdx, centerPt
+ );
}, this);
}
@@ -288,22 +334,69 @@ class MapDraw {
this._useSVG(mapName);
}
+ const svgDispatcherMap = this._svgDispatcherMap = zrUtil.createHashMap<Element[], RegionName>();
+
let focusSelf = false;
- zrUtil.each(this._svgGraphicRecord.regionGraphics, function (regionGraphic) {
+ zrUtil.each(this._svgGraphicRecord.named, function (namedItem) {
// Note that we also allow different elements have the same name.
// For example, a glyph of a city and the label of the city have
// the same name and their tooltip info can be defined in a single
// region option.
- const focus = this._resetSingleRegionGraphic(
- viewBuildCtx, regionGraphic, [0, 0], 'inside',
- // We do not know how the SVG like so we'd better not to change z2.
- // Otherwise it might bring some unexpected result. For example,
- // an area hovered that make some inner city can not be clicked.
- true
- );
- if (focus === 'self') {
- focusSelf = true;
+
+ const regionName = namedItem.name;
+ const mapOrGeoModel = viewBuildCtx.mapOrGeoModel;
+ const data = viewBuildCtx.data;
+ const svgNodeTagLower = namedItem.svgNodeTagLower;
+ const el = namedItem.el;
+
+ const dataIdx = data ? data.indexOfName(regionName) : null;
+ const regionModel = mapOrGeoModel.getRegionModel(regionName);
+
+ if (OPTION_STYLE_ENABLED_TAG_MAP.get(svgNodeTagLower) != null
+ && (el instanceof Displayable)
+ ) {
+ applyOptionStyleForRegion(viewBuildCtx, el, dataIdx, regionModel);
+ }
+
+ if (el instanceof Displayable) {
+ el.culling = true;
+ }
+
+ // We do not know how the SVG like so we'd better not to change z2.
+ // Otherwise it might bring some unexpected result. For example,
+ // an area hovered that make some inner city can not be clicked.
+ (el as ECElement).z2EmphasisLift = 0;
+
+ // If self named, that is, if tag is inside a named <g> (where `namedFrom` does not exists):
+ if (!namedItem.namedFrom) {
+ // label should batter to be displayed based on the center of <g>
+ // if it is named rather than displayed on each child.
+ if (LABEL_HOST_MAP.get(svgNodeTagLower) != null) {
+ resetLabelForRegion(
+ viewBuildCtx, el, regionName, regionModel, mapOrGeoModel, dataIdx, [0, 0]
+ );
+ }
+
+ resetEventTriggerForRegion(
+ viewBuildCtx, el, regionName, regionModel, mapOrGeoModel, dataIdx
+ );
+
+ resetTooltipForRegion(
+ viewBuildCtx, el, regionName, regionModel, mapOrGeoModel
+ );
+
+ if (STATE_TRIGGER_TAG_MAP.get(svgNodeTagLower) != null) {
+ const focus = resetStateTriggerForRegion(
+ viewBuildCtx, el, regionName, regionModel, mapOrGeoModel
+ );
+ if (focus === 'self') {
+ focusSelf = true;
+ }
+ const els = svgDispatcherMap.get(regionName) || svgDispatcherMap.set(regionName, []);
+ els.push(el);
+ }
}
+
}, this);
// It's a little complicated to support blurring the entire geoSVG in series-map.
@@ -334,157 +427,6 @@ class MapDraw {
}
}
- private _resetSingleRegionGraphic(
- viewBuildCtx: ViewBuildContext,
- regionGraphic: RegionGraphic,
- labelXY: number[],
- labelPosition: ElementTextConfig['position'],
- noZ2EmphasisLift: boolean
- ): InnerFocus {
-
- const regionName = regionGraphic.name;
- const mapOrGeoModel = viewBuildCtx.mapOrGeoModel;
- const data = viewBuildCtx.data;
- const isGeo = viewBuildCtx.isGeo;
-
- const dataIdx = data ? data.indexOfName(regionName) : null;
- const regionModel = mapOrGeoModel.getRegionModel(regionName);
-
- applyOptionStyleForRegion(viewBuildCtx, regionGraphic, dataIdx, regionModel);
-
- if (regionGraphic.el instanceof Displayable) {
- regionGraphic.el.culling = true;
- }
- if (noZ2EmphasisLift) {
- (regionGraphic.el as ECElement).z2EmphasisLift = 0;
- }
-
- 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 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
- // 3. Region has no series legendSymbol, which will be add a showLabel flag in mapSymbolLayout
- if (
- regionGraphic.useLabel
- && (
- ((isGeo || isDataNaN) && showLabel)
- || (itemLayout && itemLayout.showLabel)
- )
- ) {
- const query = !isGeo ? dataIdx : regionName;
- let labelFetcher;
-
- // Consider dataIdx not found.
- if (!data || dataIdx >= 0) {
- labelFetcher = mapOrGeoModel;
- }
-
- 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'
- } }
- );
-
- regionGraphic.el.setTextContent(textEl);
- regionGraphic.el.setTextConfig({
- local: true,
- insideFill: textEl.style.fill,
- position: labelPosition
- });
- (regionGraphic.el as ECElement).disableLabelAnimation = true;
- }
- else {
- regionGraphic.el.removeTextContent();
- regionGraphic.el.removeTextConfig();
- (regionGraphic.el as ECElement).disableLabelAnimation = null;
- }
-
- // setItemGraphicEl, setHoverStyle after all polygons and labels
- // are added to the rigionGroup
- if (data) {
- // FIXME: when series-map use a SVG map, and there are duplicated name specified
- // on different SVG elements, after `data.setItemGraphicEl(...)`:
- // (1) all of them will be mounted with `dataIndex`, `seriesIndex`, so that tooltip
- // can be triggered only mouse hover. That's correct.
- // (2) only the last element will be kept in `data`, so that if trigger tooltip
- // by `dispatchAction`, only the last one can be found and triggered. That might be
- // not correct. We will fix it in future if anyone demanding that.
- data.setItemGraphicEl(dataIdx, regionGraphic.eventTrigger);
- }
- // series-map will not trigger "geoselectchange" no matter it is
- // based on a declared geo component. Becuause series-map will
- // trigger "selectchange". If it trigger both the two events,
- // If users call `chart.dispatchAction({type: 'toggleSelect'})`,
- // it not easy to also fire event "geoselectchanged".
- else {
- // Package custom mouse event for geo component
- getECData(regionGraphic.eventTrigger).eventData = {
- componentType: 'geo',
- componentIndex: mapOrGeoModel.componentIndex,
- geoIndex: mapOrGeoModel.componentIndex,
- name: regionName,
- region: (regionModel && regionModel.option) || {}
- };
- }
-
- if (!data) {
- graphic.setTooltipConfig({
- el: regionGraphic.el,
- componentModel: mapOrGeoModel,
- itemName: regionName,
- // @ts-ignore FIXME:TS fix the "compatible with each other"?
- itemTooltipOption: regionModel.get('tooltip')
- });
- }
-
- let focus;
- const stateTrigger = regionGraphic.stateTrigger;
- if (stateTrigger) {
- // @ts-ignore FIXME:TS fix the "compatible with each other"?
- stateTrigger.highDownSilentOnTouch = !!mapOrGeoModel.get('selectedMode');
- // @ts-ignore FIXME:TS fix the "compatible with each other"?
- const emphasisModel = regionModel.getModel('emphasis');
- focus = emphasisModel.get('focus');
- enableHoverEmphasis(
- stateTrigger, focus, emphasisModel.get('blurScope')
- );
- if (isGeo) {
- enableComponentHighDownFeatures(stateTrigger, mapOrGeoModel as GeoModel, regionName);
- }
- }
-
- return focus;
- }
-
remove(): void {
this._regionsGroup.removeAll();
this._regionsGroupByName = null;
@@ -509,7 +451,7 @@ class MapDraw {
}
}
else if (geo.resourceType === 'geoSVG') {
- return this._svgGraphicRecord.regionElementMap.get(name) || [];
+ return this._svgDispatcherMap && this._svgDispatcherMap.get(name) || [];
}
}
@@ -538,6 +480,7 @@ class MapDraw {
(resource as GeoSVGResource).freeGraphic(this.uid);
}
this._svgGraphicRecord = null;
+ this._svgDispatcherMap = null;
this._svgGroup.removeAll();
this._svgMapName = null;
}
@@ -641,7 +584,7 @@ function labelTextAfterUpdate(this: graphic.Text) {
function applyOptionStyleForRegion(
viewBuildCtx: ViewBuildContext,
- regionGraphic: RegionGraphic,
+ el: Displayable,
dataIndex: number,
regionModel: Model<
GeoStyleableOption & {
@@ -651,14 +594,6 @@ function applyOptionStyleForRegion(
}
>
): void {
-
- if (
- !regionGraphic.optionStyleEnabled
- || !(regionGraphic.el instanceof Displayable)
- ) {
- return;
- }
-
// All of the path are using `itemStyle`, becuase
// (1) Some SVG also use fill on polyline (The different between
// polyline and polygon is "open" or "close" but not fill or not).
@@ -698,11 +633,185 @@ function applyOptionStyleForRegion(
// SVG text, tspan and image can be named but not supporeted
// to be styled by region option yet.
- regionGraphic.el.setStyle(normalStyle);
- regionGraphic.el.style.strokeNoScale = true;
- regionGraphic.el.ensureState('emphasis').style = emphasisStyle;
- regionGraphic.el.ensureState('select').style = selectStyle;
- regionGraphic.el.ensureState('blur').style = blurStyle;
+ el.setStyle(normalStyle);
+ el.style.strokeNoScale = true;
+ el.ensureState('emphasis').style = emphasisStyle;
+ el.ensureState('select').style = selectStyle;
+ el.ensureState('blur').style = blurStyle;
+}
+
+function resetLabelForRegion(
+ viewBuildCtx: ViewBuildContext,
+ el: Element,
+ regionName: string,
+ regionModel: RegionModel,
+ mapOrGeoModel: MapOrGeoModel,
+ // Exist only if `viewBuildCtx.data` exists.
+ dataIdx: number,
+ labelXY: number[]
+): void {
+ const data = viewBuildCtx.data;
+ const isGeo = viewBuildCtx.isGeo;
+
+ 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 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
+ // 3. 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;
+ }
+
+ const textEl = new graphic.Text({
+ x: labelXY[0],
+ y: labelXY[1],
+ z2: 10,
+ silent: true
+ });
+ textEl.afterUpdate = labelTextAfterUpdate;
+
+ const labelStateModels = getLabelStatesModels(regionModel);
+ setLabelStyle<typeof query>(
+ textEl,
+ labelStateModels,
+ {
+ labelFetcher: labelFetcher,
+ labelDataIndex: query,
+ defaultText: regionName
+ },
+ { normal: {
+ align: 'center',
+ verticalAlign: 'middle'
+ } }
+ );
+
+ // PENDING: use `setLabelStyle` entirely.
+ el.setTextContent(textEl);
+
+ const textConfig = createTextConfig(labelStateModels.normal, null, false);
+ // Need to apply the `translate`.
+ textConfig.local = true;
+ textConfig.insideFill = textEl.style.fill;
+ el.setTextConfig(textConfig);
+
+ for (let i = 0; i < SPECIAL_STATES.length; i++) {
+ const stateName = SPECIAL_STATES[i];
+ // Hover label only work when `emphasis` state ensured.
+ const state = el.ensureState(stateName);
+
+ const textConfig = state.textConfig = createTextConfig(labelStateModels[stateName], null, true);
+ // Need to apply the `translate`.
+ textConfig.local = true;
+ textConfig.insideFill = textEl.style.fill;
+ }
+
+ (el as ECElement).disableLabelAnimation = true;
+ }
+ else {
+ el.removeTextContent();
+ el.removeTextConfig();
+ (el as ECElement).disableLabelAnimation = null;
+ }
+}
+
+function resetEventTriggerForRegion(
+ viewBuildCtx: ViewBuildContext,
+ eventTrigger: Element,
+ regionName: string,
+ regionModel: RegionModel,
+ mapOrGeoModel: MapOrGeoModel,
+ // Exist only if `viewBuildCtx.data` exists.
+ dataIdx: number
+): void {
+ // setItemGraphicEl, setHoverStyle after all polygons and labels
+ // are added to the rigionGroup
+ if (viewBuildCtx.data) {
+ // FIXME: when series-map use a SVG map, and there are duplicated name specified
+ // on different SVG elements, after `data.setItemGraphicEl(...)`:
+ // (1) all of them will be mounted with `dataIndex`, `seriesIndex`, so that tooltip
+ // can be triggered only mouse hover. That's correct.
+ // (2) only the last element will be kept in `data`, so that if trigger tooltip
+ // by `dispatchAction`, only the last one can be found and triggered. That might be
+ // not correct. We will fix it in future if anyone demanding that.
+ viewBuildCtx.data.setItemGraphicEl(dataIdx, eventTrigger);
+ }
+ // series-map will not trigger "geoselectchange" no matter it is
+ // based on a declared geo component. Becuause series-map will
+ // trigger "selectchange". If it trigger both the two events,
+ // If users call `chart.dispatchAction({type: 'toggleSelect'})`,
+ // it not easy to also fire event "geoselectchanged".
+ else {
+ // Package custom mouse event for geo component
+ getECData(eventTrigger).eventData = {
+ componentType: 'geo',
+ componentIndex: mapOrGeoModel.componentIndex,
+ geoIndex: mapOrGeoModel.componentIndex,
+ name: regionName,
+ region: (regionModel && regionModel.option) || {}
+ };
+ }
+}
+
+function resetTooltipForRegion(
+ viewBuildCtx: ViewBuildContext,
+ el: Element,
+ regionName: string,
+ regionModel: RegionModel,
+ mapOrGeoModel: MapOrGeoModel
+): void {
+ if (!viewBuildCtx.data) {
+ graphic.setTooltipConfig({
+ el: el,
+ componentModel: mapOrGeoModel,
+ itemName: regionName,
+ // @ts-ignore FIXME:TS fix the "compatible with each other"?
+ itemTooltipOption: regionModel.get('tooltip')
+ });
+ }
+}
+
+function resetStateTriggerForRegion(
+ viewBuildCtx: ViewBuildContext,
+ el: Element,
+ regionName: string,
+ regionModel: RegionModel,
+ mapOrGeoModel: MapOrGeoModel
+): InnerFocus {
+ // @ts-ignore FIXME:TS fix the "compatible with each other"?
+ el.highDownSilentOnTouch = !!mapOrGeoModel.get('selectedMode');
+ // @ts-ignore FIXME:TS fix the "compatible with each other"?
+ const emphasisModel = regionModel.getModel('emphasis');
+ const focus = emphasisModel.get('focus');
+ enableHoverEmphasis(
+ el, focus, emphasisModel.get('blurScope')
+ );
+ if (viewBuildCtx.isGeo) {
+ enableComponentHighDownFeatures(el, mapOrGeoModel as GeoModel, regionName);
+ }
+
+ return focus;
}
export default MapDraw;
diff --git a/src/coord/geo/Geo.ts b/src/coord/geo/Geo.ts
index 430bdf4..a2e96cc 100644
--- a/src/coord/geo/Geo.ts
+++ b/src/coord/geo/Geo.ts
@@ -169,7 +169,7 @@ class Geo extends View {
return this._nameCoordMap.get(name) || (region && region.getCenter());
}
- dataToPoint(data: number[], noRoam?: boolean, out?: number[]): number[] {
+ dataToPoint(data: number[] | string, noRoam?: boolean, out?: number[]): number[] {
if (typeof data === 'string') {
// Map area name to geoCoord
data = this.getGeoCoord(data);
diff --git a/src/coord/geo/GeoSVGResource.ts b/src/coord/geo/GeoSVGResource.ts
index 79455c3..93d9c2f 100644
--- a/src/coord/geo/GeoSVGResource.ts
+++ b/src/coord/geo/GeoSVGResource.ts
@@ -17,38 +17,54 @@
* under the License.
*/
-import { parseSVG, makeViewBoxTransform, SVGNodeTagLower } from 'zrender/src/tool/parseSVG';
+import { parseSVG, makeViewBoxTransform, SVGNodeTagLower, SVGParserResultNamedItem } from 'zrender/src/tool/parseSVG';
import Group from 'zrender/src/graphic/Group';
import Rect from 'zrender/src/graphic/shape/Rect';
-import {assert, createHashMap, HashMap} from 'zrender/src/core/util';
+import {assert, createHashMap, each, HashMap} from 'zrender/src/core/util';
import BoundingRect from 'zrender/src/core/BoundingRect';
-import { GeoResource, GeoSVGGraphicRoot, GeoSVGSourceInput, RegionGraphic } from './geoTypes';
+import { GeoResource, GeoSVGGraphicRoot, GeoSVGSourceInput } from './geoTypes';
import { parseXML } from 'zrender/src/tool/parseXML';
import { GeoSVGRegion } from './Region';
import Element from 'zrender/src/Element';
-type RegionName = string;
export interface GeoSVGGraphicRecord {
root: Group;
boundingRect: BoundingRect;
- regionGraphics: RegionGraphic[];
- // A name may correspond to multiple graphics.
- regionElementMap: HashMap<Element[], RegionName>;
+ named: SVGParserResultNamedItem[];
}
+/**
+ * "region available" means that: enable users to set attribute `name="xxx"` on those tags
+ * to make it be a region.
+ * 1. region styles and its label styles can be defined in echarts opton:
+ * ```js
+ * geo: {
+ * regions: [{
+ * name: 'xxx',
+ * itemStyle: { ... },
+ * label: { ... }
+ * }, {
+ * ...
+ * },
+ * ...]
+ * };
+ * ```
+ * 2. name can be duplicated in different SVG tag. All of the tags with the same name share
+ * a region option. For exampel if there are two <path> representing two lung lobes. They have
+ * no common parents but both of them need to display label "lung" inside.
+ */
const REGION_AVAILABLE_SVG_TAG_MAP = createHashMap<number, SVGNodeTagLower>([
- 'rect', 'circle', 'line', 'ellipse', 'polygon', 'polyline', 'text', 'tspan', 'path'
+ 'rect', 'circle', 'line', 'ellipse', 'polygon', 'polyline', 'path',
+ // <text> <tspan> are also enabled becuase some SVG might paint text itself,
+ // but still need to trigger events or tooltip.
+ 'text', 'tspan',
+ // <g> is also enabled because this case: if multiple tags share one name
+ // and need label displayed, every tags will display the name, which is not
+ // expected. So we can put them into a <g name="xxx">. Thereby only one label
+ // displayed and located based on the bounding rect of the <g>.
+ 'g'
]);
-const OPTION_STYLE_ENABLED_TAG_MAP = createHashMap<number, SVGNodeTagLower>([
- 'rect', 'circle', 'line', 'ellipse', 'polygon', 'polyline', 'path'
-]);
-
-const LABEL_HOST_MAP = createHashMap<number, SVGNodeTagLower>([
- 'rect', 'circle', 'line', 'ellipse', 'polygon', 'polyline', 'path'
-]);
-
-
export class GeoSVGResource implements GeoResource {
readonly type = 'geoSVG';
@@ -57,9 +73,9 @@ export class GeoSVGResource implements GeoResource {
private _firstGraphic: GeoSVGGraphicRecord;
private _boundingRect: BoundingRect;
- private _regions: GeoSVGRegion[] = [];
+ private _regions: GeoSVGRegion[];
// Key: region.name
- private _regionsMap: HashMap<GeoSVGRegion> = createHashMap<GeoSVGRegion>();
+ private _regionsMap: HashMap<GeoSVGRegion>;
// All used graphics. key: hostKey, value: root
private _usedGraphicMap: HashMap<GeoSVGGraphicRecord> = createHashMap();
@@ -98,21 +114,14 @@ export class GeoSVGResource implements GeoResource {
this._boundingRect = this._firstGraphic.boundingRect.clone();
- const regionGraphics = firstGraphic.regionGraphics;
// PENDING: `nameMap` will not be supported until some real requirement come.
// if (nameMap) {
- // regionGraphics = applyNameMap(regionGraphics, nameMap);
+ // named = applyNameMap(named, nameMap);
// }
- // Create resions only for the first graphic.
- for (let i = 0; i < regionGraphics.length; i++) {
- const regionGraphic = regionGraphics[i];
- const region = new GeoSVGRegion(regionGraphic.name, regionGraphic.el);
- // PENDING: if `nameMap` supported, this region can not be mounted on
- // `this`, but can only be created each time `load()` called.
- this._regions.push(region);
- this._regionsMap.set(regionGraphic.name, region);
- }
+ const { regions, regionsMap } = createRegions(firstGraphic.named);
+ this._regions = regions;
+ this._regionsMap = regionsMap;
}
return {
@@ -148,10 +157,10 @@ export class GeoSVGResource implements GeoResource {
// PENDING: `nameMap` will not be supported until some real requirement come.
// `nameMap` can only be obtained from echarts option.
- // The original `regionGraphics` must not be modified.
+ // The original `named` must not be modified.
// if (nameMap) {
// svgGraphic = extend({}, svgGraphic);
- // svgGraphic.regionGraphics = applyNameMap(svgGraphic.regionGraphics, nameMap);
+ // svgGraphic.named = applyNameMap(svgGraphic.named, nameMap);
// }
return svgGraphic;
@@ -227,59 +236,75 @@ function buildGraphic(
(root as GeoSVGGraphicRoot).isGeoSVGGraphicRoot = true;
- const regionGraphics = [] as GeoSVGGraphicRecord['regionGraphics'];
- const regionElementMap = createHashMap<Element[], RegionName>();
- const named = result.named;
- for (let i = 0; i < named.length; i++) {
- const namedItem = named[i];
- const svgNodeTagLower = namedItem.svgNodeTagLower;
-
- if (REGION_AVAILABLE_SVG_TAG_MAP.get(svgNodeTagLower) != null) {
- const optionStyleEnabled = OPTION_STYLE_ENABLED_TAG_MAP.get(svgNodeTagLower);
- const el = namedItem.el;
- const name = namedItem.name;
-
- regionGraphics.push({
- name: name,
- el: el,
- optionStyleEnabled: optionStyleEnabled != null,
- stateTrigger: optionStyleEnabled != null ? el : null,
- // text/tspan/image do not suport style but support event.
- eventTrigger: el,
- useLabel: LABEL_HOST_MAP.get(svgNodeTagLower) != null
- });
-
- const els = regionElementMap.get(name) || regionElementMap.set(name, []);
- els.push(el);
-
- // Only named element has silent: false, other elements should
- // act as background and has no user interaction.
- el.silent = false;
- // text|tspan will be converted to group.
- if (el.isGroup) {
- el.traverse(child => {
- child.silent = false;
- });
- }
+ const named = [] as GeoSVGGraphicRecord['named'];
+
+ each(result.named, namedItem => {
+ if (REGION_AVAILABLE_SVG_TAG_MAP.get(namedItem.svgNodeTagLower) != null) {
+ named.push(namedItem);
+ setSilent(namedItem.el);
}
+ });
+
+ return { root, boundingRect, named };
+}
+
+function setSilent(el: Element): void {
+ // Only named element has silent: false, other elements should
+ // act as background and has no user interaction.
+ el.silent = false;
+ // text|tspan will be converted to group.
+ if (el.isGroup) {
+ el.traverse(child => {
+ child.silent = false;
+ });
}
+}
+
+function createRegions(
+ named: SVGParserResultNamedItem[]
+): {
+ regions: GeoSVGRegion[];
+ regionsMap: HashMap<GeoSVGRegion>;
+} {
+
+ const regions: GeoSVGRegion[] = [];
+ const regionsMap = createHashMap<GeoSVGRegion>();
+
+ // Create resions only for the first graphic.
+ each(named, namedItem => {
+ // Region has feature to calculate center for tooltip or other features.
+ // If there is a <g name="xxx">, the center should be the center of the
+ // bounding rect of the g.
+ if (namedItem.namedFrom != null) {
+ return;
+ }
- return { root, boundingRect, regionGraphics, regionElementMap: regionElementMap };
+ const region = new GeoSVGRegion(namedItem.name, namedItem.el);
+ // PENDING: if `nameMap` supported, this region can not be mounted on
+ // `this`, but can only be created each time `load()` called.
+ regions.push(region);
+ // PENDING: if multiple tag named with the same name, only one will be
+ // found by `_regionsMap`. `_regionsMap` is used to find a coordinate
+ // by name. We use `region.getCenter()` as the coordinate.
+ regionsMap.set(namedItem.name, region);
+ });
+
+ return { regions, regionsMap };
}
// PENDING: `nameMap` will not be supported until some real requirement come.
// /**
// * Use the alias in geoNameMap.
-// * The input `regionGraphics` must not be modified.
+// * The input `named` must not be modified.
// */
// function applyNameMap(
-// regionGraphics: GeoSVGGraphicRecord['regionGraphics'],
+// named: GeoSVGGraphicRecord['named'],
// nameMap: NameMap
-// ): GeoSVGGraphicRecord['regionGraphics'] {
-// const result = [] as GeoSVGGraphicRecord['regionGraphics'];
-// for (let i = 0; i < regionGraphics.length; i++) {
-// let regionGraphic = regionGraphics[i];
+// ): GeoSVGGraphicRecord['named'] {
+// const result = [] as GeoSVGGraphicRecord['named'];
+// for (let i = 0; i < named.length; i++) {
+// let regionGraphic = named[i];
// const name = regionGraphic.name;
// if (nameMap && nameMap.hasOwnProperty(name)) {
// regionGraphic = extend({}, regionGraphic);
diff --git a/src/coord/geo/geoTypes.ts b/src/coord/geo/geoTypes.ts
index 8674218..e98de49 100644
--- a/src/coord/geo/geoTypes.ts
+++ b/src/coord/geo/geoTypes.ts
@@ -140,21 +140,3 @@ export interface GeoResource {
export interface GeoSVGGraphicRoot extends Group {
isGeoSVGGraphicRoot: boolean;
}
-
-export type RegionGraphic = {
- // Region name. Can not be null/undefined.
- name: string;
- // Main el.
- el: Element;
- // If it specified, use it to trigger state
- // style change (emphasis/select/blur)
- // Can be null/undefined.
- stateTrigger: Element;
- // If it specified, use it to trigger event to users
- // Can be null/undefined.
- eventTrigger: Element;
- // Whether to set label on `el.textContent`.
- useLabel: boolean;
- // Whether to be enabled to set style via in echarts option.
- optionStyleEnabled: boolean;
-};
diff --git a/src/core/echarts.ts b/src/core/echarts.ts
index 2f652a3..10fc41b 100644
--- a/src/core/echarts.ts
+++ b/src/core/echarts.ts
@@ -36,8 +36,6 @@ import ChartView, {ChartViewConstructor} from '../view/Chart';
import * as graphic from '../util/graphic';
import {getECData} from '../util/innerStore';
import {
- enterEmphasisWhenMouseOver,
- leaveEmphasisWhenMouseOut,
isHighDownDispatcher,
HOVER_STATE_EMPHASIS,
HOVER_STATE_BLUR,
@@ -1484,24 +1482,28 @@ class ECharts extends Eventful<ECEventDefinition> {
ecModel && ecModel.eachComponent(condition, function (model) {
if (!excludeSeriesIdMap || excludeSeriesIdMap.get(model.id) == null) {
if (isHighDownPayload(payload)) {
- if (payload.type === HIGHLIGHT_ACTION_TYPE) {
- if (model instanceof SeriesModel) {
- !payload.notBlur && blurSeriesFromHighlightPayload(model, payload, ecIns._api);
+ if (model instanceof SeriesModel) {
+ if (payload.type === HIGHLIGHT_ACTION_TYPE && !payload.notBlur) {
+ blurSeriesFromHighlightPayload(model, payload, ecIns._api);
+ }
+ }
+ else {
+ const { focusSelf, dispatchers } = findComponentHighDownDispatchers(
+ model.mainType, model.componentIndex, payload.name, ecIns._api
+ );
+ if (payload.type === HIGHLIGHT_ACTION_TYPE && focusSelf && !payload.notBlur) {
+ blurComponent(model.mainType, model.componentIndex, ecIns._api);
}
- else {
- const { focusSelf, dispatchers } = findComponentHighDownDispatchers(
- model.mainType, model.componentIndex, payload.name, ecIns._api
- );
- if (focusSelf && !payload.notBlur) {
- blurComponent(model.mainType, model.componentIndex, ecIns._api);
- }
- // PENDING:
- // Whether to put this "enter emphasis" code in `ComponentView`,
- // which will be the same as `ChartView` but might be not necessary
- // and will be far from this logic.
- if (dispatchers) {
- each(dispatchers, dispatcher => enterEmphasis(dispatcher));
- }
+ // PENDING:
+ // Whether to put this "enter emphasis" code in `ComponentView`,
+ // which will be the same as `ChartView` but might be not necessary
+ // and will be far from this logic.
+ if (dispatchers) {
+ each(dispatchers, dispatcher => {
+ payload.type === HIGHLIGHT_ACTION_TYPE
+ ? enterEmphasis(dispatcher)
+ : leaveEmphasis(dispatcher);
+ });
}
}
}
diff --git a/test/geo-svg-demo.html b/test/geo-svg-demo.html
index ed5afe8..85ad1b0 100644
--- a/test/geo-svg-demo.html
+++ b/test/geo-svg-demo.html
@@ -38,8 +38,8 @@ under the License.
<div id="main_geo_svg_organ"></div>
- <!-- <div id="main_geo_svg_organ1"></div> -->
-
+ <div id="main_geo_svg_regions"></div>
+ <div id="main_geo_svg_line_path"></div>
@@ -99,6 +99,8 @@ under the License.
tooltip: {
},
geo: {
+ left: 10,
+ right: '50%',
map: 'seatmap',
roam: true,
selectedMode: 'multiple',
@@ -107,18 +109,16 @@ under the License.
emphasis: {
focus: 'self',
itemStyle: {
- // color: null
+ color: null
},
label: {
- show: false,
+ position: 'bottom',
+ distance: 20,
textBorderColor: '#fff',
textBorderWidth: 2
}
},
blur: {
- // itemStyle: {
- // opacity: 0.3
- // }
},
select: {
itemStyle: {
@@ -130,7 +130,25 @@ under the License.
textBorderWidth: 2
}
}
- }
+ },
+ grid: {
+ left: '60%'
+ },
+ xAxis: {
+ splitLine: {
+ show: false
+ }
+ },
+ yAxis: {
+ data: ['heart', 'large-intestine', 'small-intestine', 'spleen', 'kidney', 'lung', 'liver']
+ },
+ series: [{
+ type: 'bar',
+ emphasis: {
+ focus: 'self'
+ },
+ data: [121, 321, 141, 52, 198, 289, 139]
+ }]
};
var chart = testHelper.create(echarts, 'main_geo_svg_organ', {
@@ -149,9 +167,34 @@ under the License.
listenAndPrintEvent(chart);
if (chart) {
- chart.on('highlight', function () {
- console.log('agsd');
+ chart.on('mouseover', { seriesIndex: 0 }, function (event) {
+ chart.dispatchAction({
+ type: 'highlight',
+ geoIndex: 0,
+ name: event.name
+ });
+ });
+ chart.on('mouseout', { seriesIndex: 0 }, function (event) {
+ chart.dispatchAction({
+ type: 'downplay',
+ geoIndex: 0,
+ name: event.name
+ });
});
+ // chart.on('mouseover', { geoIndex: 0 }, function (event) {
+ // chart.dispatchAction({
+ // type: 'highlight',
+ // seriesIndex: 0,
+ // name: event.name
+ // });
+ // });
+ // chart.on('mouseout', { geoIndex: 0 }, function (event) {
+ // chart.dispatchAction({
+ // type: 'downplay',
+ // seriesIndex: 0,
+ // name: event.name
+ // });
+ // });
}
});
@@ -162,36 +205,54 @@ under the License.
-<!--
+
<script>
require(['echarts'/*, 'map/js/china' */], function (echarts) {
var option;
+
$.ajax({
- url: '../../vis-data/map/svg/organ/Veins_Medical_Diagram_clip_art.svg',
+ url: '../../vis-data/map/svg/geo-topo/Sicily_prehellenic_topographic_map.svg',
dataType: 'text'
}).done(function (svg) {
- echarts.registerMap('seatmap', {
+ echarts.registerMap('sicily', {
svg: svg
});
option = {
tooltip: {
},
- series: {
- type: 'map',
- map: 'seatmap',
+ geo: [{
+ map: 'sicily',
roam: true,
selectedMode: 'multiple',
- // height: 100,
- // zoom: 1.5
+ itemStyle: {
+ color: null
+ },
+ tooltip: {
+ show: true,
+ confine: true,
+ formatter: function (params) {
+ return [
+ 'This is the introduction:',
+ 'xxxxxxxxxxxxxxxxxxxxx',
+ 'xxxxxxxxxxxxxxxxxxxxx',
+ 'xxxxxxxxxxxxxxxxxxxxx',
+ 'xxxxxxxxxxxxxxxxxxxxx',
+ 'xxxxxxxxxxxxxxxxxxxxx',
+ 'xxxxxxxxxxxxxxxxxxxxx',
+ 'xxxxxxxxxxxxxxxxxxxxx',
+ 'xxxxxxxxxxxxxxxxxxxxx',
+ 'xxxxxxxxxxxxxxxxxxxxx',
+ 'xxxxxxxxxxxxxxxxxxxxx'
+ ].join('<br>');
+ }
+ },
emphasis: {
- focus: 'self',
label: {
- textBorderColor: '#fff',
- textBorderWidth: 2
+ show: false
}
},
select: {
@@ -199,39 +260,202 @@ under the License.
color: '#b50205'
},
label: {
- show: false,
- textBorderColor: '#fff',
- textBorderWidth: 2
+ show: false
}
- }
- }
+ },
+ regions: [{
+ name: 'Sikeloi',
+ tooltip: {
+ formatter: 'Sikeloi',
+ textStyle: { color: '#555' },
+ backgroundColor: '#ccc'
+ }
+ }, {
+ name: 'Sikanoi',
+ tooltip: {
+ formatter: 'Sikanoi',
+ textStyle: { color: '#555' },
+ backgroundColor: '#ccc'
+ }
+ }, {
+ name: 'Elymoi',
+ tooltip: {
+ formatter: 'Elymoi',
+ textStyle: { color: '#555' },
+ backgroundColor: '#ccc'
+ }
+ }],
+ z: 0
+ }]
};
- var chart = testHelper.create(echarts, 'main_geo_svg_organ1', {
+ var chart = testHelper.create(echarts, 'main_geo_svg_regions', {
title: [
- 'pure geo component with svg resource',
- 'click seat: check **allSelected** correct.'
+ 'symbol and label use the same name in SVG.',
+ 'Hover each symbol and text, tooltip should be displayed.',
+ 'Hover the three area, tooltip should be displayed.',
+ 'Click, check **selected**.'
],
option: option,
info: {},
infoKey: 'event',
height: 500
- // buttons: [{text: 'btn-txt', onclick: function () {}}],
- // recordCanvas: true,
});
listenAndPrintEvent(chart);
- if (chart) {
- chart.on('highlight', function () {
- console.log('agsd');
- });
- }
+ });
+
+ });
+ </script>
+
+
+
+
+
+
+
+
+
+
+ <script>
+ require(['echarts'/*, 'map/js/china' */], function (echarts) {
+ var option;
+
+ $.ajax({
+ url: '../../vis-data/map/svg/geo-topo/Map_of_Iceland.svg',
+ dataType: 'text'
+ }).done(function (svg) {
+
+ echarts.registerMap('Map_of_Iceland', {
+ svg: svg
+ });
+
+ option = {
+ tooltip: {
+ alwaysShowContent: true,
+ enterable: true,
+ extraCssText: 'user-select: text'
+ },
+ geo: [{
+ map: 'Map_of_Iceland',
+ roam: true,
+ selectedMode: 'single',
+ tooltip: {
+ show: true,
+ // confine: true
+ },
+ label: {
+ fontSize: 20,
+ textBorderColor: '#fff',
+ textBorderWidth: 2
+ },
+ emphasis: {
+ itemStyle: {
+ color: null,
+ borderColor: '#b50805',
+ borderWidth: 5
+ }
+ },
+ select: {
+ itemStyle: {
+ color: null,
+ borderColor: '#b50205',
+ borderWidth: 5
+ }
+ },
+ regions: [{
+ name: 'trip1',
+ label: {
+ formatter: 'Western Trip'
+ },
+ tooltip: {
+ position: 'right',
+ formatter: [
+ 'Western Trip:',
+ 'xxxxxxxxxxxxxxxxxxxxxxxxxxx',
+ 'xxxxxxxxxxxxxxxxxxxxxxxxxxx',
+ 'xxxxxxxxxxxxxxxxxxxxxxxxxxx',
+ 'xxxxxxxxxxxxxxxxxxxxxxxxxxx',
+ 'xxxxxxxxxxxxxxxxxxxxxxxxxxx'
+ ].join('<br>')
+ }
+ }, {
+ name: 'trip2',
+ label: {
+ formatter: 'Eastern Trip'
+ },
+ tooltip: {
+ position: 'left',
+ formatter: [
+ 'Western Trip:',
+ 'xxxxxxxxxxxx',
+ 'xxxxxxxxxxxx',
+ 'xxxxxxxxxxxx',
+ 'xxxxxxxxxxxx',
+ 'xxxxxxxxxxxx',
+ 'xxxxxxxxxxxx',
+ 'xxxxxxxxxxxx',
+ 'xxxxxxxxxxxx',
+ 'xxxxxxxxxxxx',
+ 'xxxxxxxxxxxx',
+ 'xxxxxxxxxxxx'
+ ].join('<br>')
+ }
+ }]
+ }]
+ };
+
+ var chart = testHelper.create(echarts, 'main_geo_svg_line_path', {
+ title: [
+ 'Select some route in SVG via API.',
+ 'Some route should be highlighted (check selectedMode **single**).',
+ 'label should be displayed.'
+ ],
+ option: option,
+ info: {},
+ infoKey: 'event',
+ height: 500,
+ buttons: [{
+ text: 'highlight trip1',
+ onclick: function () {
+ chart.dispatchAction({
+ type: 'geoSelect',
+ geoIndex: 0,
+ name: 'trip1'
+ });
+ chart.dispatchAction({
+ type: 'showTip',
+ geoIndex: 0,
+ name: 'trip1'
+ });
+ }
+ }, {
+ text: 'highlight trip2',
+ onclick: function () {
+ chart.dispatchAction({
+ type: 'geoSelect',
+ geoIndex: 0,
+ name: 'trip2'
+ });
+ chart.dispatchAction({
+ type: 'showTip',
+ geoIndex: 0,
+ name: 'trip2'
+ });
+ }
+ }]
+ });
+
+ listenAndPrintEvent(chart);
});
});
- </script> -->
+ </script>
+
+
+
diff --git a/test/geo-svg.html b/test/geo-svg.html
index 2d52f33..45ec6e4 100644
--- a/test/geo-svg.html
+++ b/test/geo-svg.html
@@ -39,10 +39,10 @@ under the License.
<div id="main_simple_geo_json"></div>
<div id="main_simple_geo_svg"></div>
+ <div id="main_geo_svg_emphasis_select"></div>
<div id="main_pure_geo_svg"></div>
<div id="main_pure_map_svg"></div>
<div id="main_map_geo_svg"></div>
- <div id="main_geo_svg_regions"></div>
@@ -135,7 +135,7 @@ under the License.
option: option,
info: {},
infoKey: 'event',
- height: 300
+ height: 200
});
listenAndPrintEvent(chart);
@@ -187,7 +187,7 @@ under the License.
option: option,
info: {},
infoKey: 'event',
- height: 300
+ height: 200
});
listenAndPrintEvent(chart);
@@ -199,6 +199,129 @@ under the License.
+ <script>
+ require(['echarts'/*, 'map/js/china' */], function (echarts) {
+ const svg = [
+ '<?xml version="1.0" encoding="utf-8"?>',
+ '<svg xmlns="http://www.w3.org/2000/svg" xmlns:ooo="http://xml.openoffice.org/svg/export" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.2" fill-rule="evenodd" xml:space="preserve">',
+ '<path name="a" d="M 0,0 L 0,100 100,100 100,0 Z" fill="rgb(16,193,138)" stroke="green" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>',
+ '<path name="a" d="M 110,0 L 110,100 210,100 210,0 Z" fill="rgb(16,193,138)" stroke="green" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>',
+ '<g name="b">',
+ '<path d="M 0,110 L 0,210 100,110 Z" fill="rgb(16,193,138)" stroke="green" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>',
+ '<path d="M 110,110 L 110,210 210,110 Z" fill="rgb(16,193,138)" stroke="green" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>',
+ '</g>',
+ '<radialGradient id="XMLID_1_" cx="0" cy="220" r="59.4363" gradientUnits="userSpaceOnUse">',
+ '<stop offset="0" style="stop-color:#E6E6E6"/>',
+ '<stop offset="1" style="stop-color:#4D4D4D"/>',
+ '</radialGradient>',
+ '<path name="c" d="M 0,220 L 0,320 100,220 Z" fill="url(#XMLID_1_)" stroke="green" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>',
+ '<radialGradient id="XMLID_2_" cx="110" cy="220" r="59.4363" gradientUnits="userSpaceOnUse">',
+ '<stop offset="0" style="stop-color:#E6E6E6"/>',
+ '<stop offset="1" style="stop-color:#4D4D4D"/>',
+ '</radialGradient>',
+ '<path name="c" d="M 110,220 L 110,320 210,220 Z" fill="url(#XMLID_2_)" stroke="green" stroke-width="2" stroke-linecap="square" stroke-linejoin="miter"/>',
+ '</svg>'
+ ].join('')
+
+ echarts.registerMap('testGeoSVG_select_hover', { svg: svg });
+
+ option = {
+ // tooltip: {
+ // },
+ geo: {
+ map: 'testGeoSVG_select_hover',
+ roam: true,
+ selectedMode: 'single',
+ // height: '100%',
+ // center
+ // layoutCenter: ['30%', 40],
+ // layoutSize: 40,
+ // boundingCoords
+ zoom: 1,
+ aspectScale: 1,
+ label: {
+ show: true
+ },
+ emphasis: {
+ label: {
+ show: true,
+ fontSize: 100
+ }
+ },
+ select: {
+ itemStyle: {
+ color: 'red'
+ }
+ }
+ }
+ };
+
+ var chart = testHelper.create(echarts, 'main_geo_svg_emphasis_select', {
+ title: [
+ 'click buttons',
+ 'hover check'
+ ],
+ option: option,
+ info: {},
+ infoKey: 'event',
+ height: 200,
+ button: [{
+ text: 'highlight a',
+ onclick: function () {
+ chart.dispatchAction({ type: 'highlight', geoIndex: 0, name: 'a' });
+ }
+ }, {
+ text: 'downplay a',
+ onclick: function () {
+ chart.dispatchAction({ type: 'downplay', geoIndex: 0, name: 'a' });
+ }
+ }, {
+ text: 'select a',
+ onclick: function () {
+ chart.dispatchAction({ type: 'geoSelect', geoIndex: 0, name: 'a' });
+ }
+ }, {
+ text: 'unselect a',
+ onclick: function () {
+ chart.dispatchAction({ type: 'geoUnSelect', geoIndex: 0, name: 'a' });
+ }
+ }, {
+ text: 'highlight b',
+ onclick: function () {
+ chart.dispatchAction({ type: 'highlight', geoIndex: 0, name: 'b' });
+ }
+ }, {
+ text: 'downplay b',
+ onclick: function () {
+ chart.dispatchAction({ type: 'downplay', geoIndex: 0, name: 'b' });
+ }
+ }, {
+ text: 'select b',
+ onclick: function () {
+ chart.dispatchAction({ type: 'geoSelect', geoIndex: 0, name: 'b' });
+ }
+ }, {
+ text: 'unselect b',
+ onclick: function () {
+ chart.dispatchAction({ type: 'geoUnSelect', geoIndex: 0, name: 'b' });
+ }
+ }]
+ });
+
+ listenAndPrintEvent(chart);
+
+ if (chart) {
+ chart.on('highlight', function () {
+ });
+ }
+
+ });
+ </script>
+
+
+
+
+
<script>
@@ -220,6 +343,9 @@ under the License.
map: 'seatmap',
roam: true,
selectedMode: 'multiple',
+ tooltip: {
+ show: true
+ },
// height: 100,
// zoom: 1.5
emphasis: {
@@ -251,7 +377,8 @@ under the License.
var chart = testHelper.create(echarts, 'main_pure_geo_svg', {
title: [
'pure geo component with svg resource',
- 'click seat: check **allSelected** correct.'
+ 'click seat: check **allSelected** correct.',
+ 'hover seat: check **tooltip** and **label** correct.'
],
option: option,
info: {},
@@ -359,6 +486,9 @@ under the License.
selectedMode: 'multiple',
// height: 100,
// zoom: 1.5
+ tooltip: {
+ show: true
+ },
emphasis: {
label: {
textBorderColor: '#fff',
@@ -407,118 +537,7 @@ under the License.
- <script>
- require(['echarts'/*, 'map/js/china' */], function (echarts) {
- var option;
- $.ajax({
- url: '../../vis-data/map/svg/geo-topo/Sicily_prehellenic_topographic_map.svg',
- dataType: 'text'
- }).done(function (svg) {
-
- echarts.registerMap('sicily', {
- svg: svg
- });
-
- option = {
- tooltip: {
- },
- geo: [{
- map: 'sicily',
- roam: true,
- selectedMode: 'multiple',
- itemStyle: {
- color: null
- },
- tooltip: {
- show: true,
- confine: true,
- formatter: function (params) {
- return [
- 'This is the introduction:',
- 'xxxxxxxxxxxxxxxxxxxxx',
- 'xxxxxxxxxxxxxxxxxxxxx',
- 'xxxxxxxxxxxxxxxxxxxxx',
- 'xxxxxxxxxxxxxxxxxxxxx',
- 'xxxxxxxxxxxxxxxxxxxxx',
- 'xxxxxxxxxxxxxxxxxxxxx',
- 'xxxxxxxxxxxxxxxxxxxxx',
- 'xxxxxxxxxxxxxxxxxxxxx',
- 'xxxxxxxxxxxxxxxxxxxxx',
- 'xxxxxxxxxxxxxxxxxxxxx'
- ].join('<br>');
- }
- },
- emphasis: {
- label: {
- show: false
- }
- },
- select: {
- itemStyle: {
- color: '#b50205'
- },
- label: {
- show: false
- }
- },
- regions: [{
- name: 'Sikeloi',
- tooltip: {
- formatter: 'Sikeloi',
- textStyle: { color: '#555' },
- backgroundColor: '#ccc'
- }
- }, {
- name: 'Sikanoi',
- tooltip: {
- formatter: 'Sikanoi',
- textStyle: { color: '#555' },
- backgroundColor: '#ccc'
- }
- }, {
- name: 'Elymoi',
- tooltip: {
- formatter: 'Elymoi',
- textStyle: { color: '#555' },
- backgroundColor: '#ccc'
- }
- }],
- z: 0
- }],
- // series: {
- // type: 'map',
- // selectedMode: 'multiple',
- // coordinateSystem: 'geo',
- // geoIndex: 0
- // }
- };
-
- var chart = testHelper.create(echarts, 'main_geo_svg_regions', {
- title: [
- 'symbol and label use the same name in SVG.',
- 'Hover each symbol and text, tooltip should be displayed.',
- 'Hover the three area, tooltip should be displayed.',
- 'Click, check **selected**.'
- ],
- option: option,
- info: {},
- infoKey: 'event',
- height: 500
- });
-
- listenAndPrintEvent(chart);
-
- if (chart) {
- chart.on('georoam', function (params) {
- // console.log(params);
- });
- }
-
- });
-
- });
- </script>
</body>
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org