提交 68893b09 编写于 作者: S sushuang

support svg geo (part I)

上级 0711cdfb
......@@ -22,6 +22,8 @@ import RoamController from './RoamController';
import * as roamHelper from '../../component/helper/roamHelper';
import {onIrrelevantElement} from '../../component/helper/cursorHelper';
import * as graphic from '../../util/graphic';
import geoSourceManager from '../../coord/geo/geoSourceManager';
import {getUID} from '../../util/component';
function getFixedItemStyle(model, scale) {
var itemStyle = model.getItemStyle();
......@@ -36,17 +38,17 @@ function getFixedItemStyle(model, scale) {
return itemStyle;
}
function updateMapSelectHandler(mapDraw, mapOrGeoModel, group, api, fromView) {
group.off('click');
group.off('mousedown');
function updateMapSelectHandler(mapDraw, mapOrGeoModel, regionsGroup, api, fromView) {
regionsGroup.off('click');
regionsGroup.off('mousedown');
if (mapOrGeoModel.get('selectedMode')) {
group.on('mousedown', function () {
regionsGroup.on('mousedown', function () {
mapDraw._mouseDownFlag = true;
});
group.on('click', function (e) {
regionsGroup.on('click', function (e) {
if (!mapDraw._mouseDownFlag) {
return;
}
......@@ -73,14 +75,14 @@ function updateMapSelectHandler(mapDraw, mapOrGeoModel, group, api, fromView) {
api.dispatchAction(action);
updateMapSelected(mapOrGeoModel, group);
updateMapSelected(mapOrGeoModel, regionsGroup);
});
}
}
function updateMapSelected(mapOrGeoModel, group) {
function updateMapSelected(mapOrGeoModel, regionsGroup) {
// FIXME
group.eachChild(function (otherRegionEl) {
regionsGroup.eachChild(function (otherRegionEl) {
zrUtil.each(otherRegionEl.__regions, function (region) {
otherRegionEl.trigger(mapOrGeoModel.isSelected(region.name) ? 'emphasis' : 'normal');
});
......@@ -96,6 +98,12 @@ function MapDraw(api, updateGroup) {
var group = new graphic.Group();
/**
* @type {string}
* @private
*/
this.uid = getUID('ec_map_draw');
/**
* @type {module:echarts/component/helper/RoamController}
* @private
......@@ -127,6 +135,26 @@ function MapDraw(api, updateGroup) {
* @type {booelan}
*/
this._mouseDownFlag;
/**
* @type {string}
*/
this._mapName;
/**
* @type {boolean}
*/
this._initialized;
/**
* @type {module:zrender/container/Group}
*/
group.add(this._regionsGroup = new graphic.Group());
/**
* @type {module:zrender/container/Group}
*/
group.add(this._backgroundGroup = new graphic.Group());
}
MapDraw.prototype = {
......@@ -148,23 +176,26 @@ MapDraw.prototype = {
var geo = mapOrGeoModel.coordinateSystem;
this._updateBackground(geo);
var regionsGroup = this._regionsGroup;
var group = this.group;
var scale = geo.scale;
var groupNewProp = {
var transform = {
position: geo.position,
scale: scale
};
// No animation when first draw or in action
if (!group.childAt(0) || payload) {
group.attr(groupNewProp);
if (!regionsGroup.childAt(0) || payload) {
group.attr(transform);
}
else {
graphic.updateProps(group, groupNewProp, mapOrGeoModel);
graphic.updateProps(group, transform, mapOrGeoModel);
}
group.removeAll();
regionsGroup.removeAll();
var itemStyleAccessPath = ['itemStyle'];
var hoverItemStyleAccessPath = ['emphasis', 'itemStyle'];
......@@ -306,22 +337,37 @@ MapDraw.prototype = {
{hoverSilentOnTouch: !!mapOrGeoModel.get('selectedMode')}
);
group.add(regionGroup);
regionsGroup.add(regionGroup);
});
this._updateController(mapOrGeoModel, ecModel, api);
updateMapSelectHandler(this, mapOrGeoModel, group, api, fromView);
updateMapSelectHandler(this, mapOrGeoModel, regionsGroup, api, fromView);
updateMapSelected(mapOrGeoModel, group);
updateMapSelected(mapOrGeoModel, regionsGroup);
},
remove: function () {
this.group.removeAll();
this._regionsGroup.removeAll();
this._backgroundGroup.removeAll();
this._controller.dispose();
this._mapName && geoSourceManager.removeGraphic(this._mapName, this.uid);
this._mapName = null;
this._controllerHost = {};
},
_updateBackground: function (geo) {
var mapName = geo.map;
if (this._mapName !== mapName) {
zrUtil.each(geoSourceManager.makeGraphic(mapName, this.uid), function (root) {
this._backgroundGroup.add(root);
}, this);
}
this._mapName = mapName;
},
_updateController: function (mapOrGeoModel, ecModel, api) {
var geo = mapOrGeoModel.coordinateSystem;
var controller = this._controller;
......@@ -366,9 +412,8 @@ MapDraw.prototype = {
}));
if (this._updateGroup) {
var group = this.group;
var scale = group.scale;
group.traverse(function (el) {
var scale = this.group.scale;
this._regionsGroup.traverse(function (el) {
if (el.type === 'text') {
el.attr('scale', [1 / scale[0], 1 / scale[1]]);
}
......
......@@ -19,33 +19,22 @@
import * as zrUtil from 'zrender/src/core/util';
import BoundingRect from 'zrender/src/core/BoundingRect';
import parseGeoJson from './parseGeoJson';
import View from '../View';
import geoSourceManager from './geoSourceManager';
import fixNanhai from './fix/nanhai';
import fixTextCoord from './fix/textCoord';
import fixGeoCoord from './fix/geoCoord';
import fixDiaoyuIsland from './fix/diaoyuIsland';
// Geo fix functions
var geoFixFuncs = [
fixNanhai,
fixTextCoord,
fixGeoCoord,
fixDiaoyuIsland
];
/**
* [Geo description]
* @param {string} name Geo name
* For backward compatibility, the orginal interface:
* `name, map, geoJson, specialAreas, nameMap` is kept.
*
* @param {string|Object} name
* @param {string} map Map type
* @param {Object} geoJson
* @param {Object} [specialAreas]
* Specify the positioned areas by left, top, width, height
* @param {Object.<string, string>} [nameMap]
* Specify name alias
*/
function Geo(name, map, geoJson, specialAreas, nameMap) {
function Geo(name, map, nameMap) {
View.call(this, name);
......@@ -55,9 +44,20 @@ function Geo(name, map, geoJson, specialAreas, nameMap) {
*/
this.map = map;
this._nameCoordMap = zrUtil.createHashMap();
var source = geoSourceManager.load(map, nameMap);
this._nameCoordMap = source.nameCoordMap;
this._regionsMap = source.nameCoordMap;
/**
* @readOnly
*/
this.regions = source.regions;
this.loadGeoJson(geoJson, specialAreas, nameMap);
/**
* @type {module:zrender/src/core/BoundingRect}
*/
this._rect = source.boundingRect;
}
Geo.prototype = {
......@@ -86,61 +86,23 @@ Geo.prototype = {
}
return false;
},
/**
* @param {Object} geoJson
* @param {Object} [specialAreas]
* Specify the positioned areas by left, top, width, height
* @param {Object.<string, string>} [nameMap]
* Specify name alias
* @override
*/
loadGeoJson: function (geoJson, specialAreas, nameMap) {
// https://jsperf.com/try-catch-performance-overhead
try {
this.regions = geoJson ? parseGeoJson(geoJson) : [];
}
catch (e) {
throw 'Invalid geoJson format\n' + e.message;
}
specialAreas = specialAreas || {};
nameMap = nameMap || {};
var regions = this.regions;
var regionsMap = zrUtil.createHashMap();
for (var i = 0; i < regions.length; i++) {
var regionName = regions[i].name;
// Try use the alias in nameMap
regionName = nameMap.hasOwnProperty(regionName) ? nameMap[regionName] : regionName;
regions[i].name = regionName;
regionsMap.set(regionName, regions[i]);
// Add geoJson
this.addGeoCoord(regionName, regions[i].center);
// Some area like Alaska in USA map needs to be tansformed
// to look better
var specialArea = specialAreas[regionName];
if (specialArea) {
regions[i].transformTo(
specialArea.left, specialArea.top, specialArea.width, specialArea.height
);
}
}
this._regionsMap = regionsMap;
this._rect = null;
zrUtil.each(geoFixFuncs, function (fixFunc) {
fixFunc(this);
}, this);
},
// Overwrite
transformTo: function (x, y, width, height) {
var rect = this.getBoundingRect();
// FIXME
// Should not name it as invertLng.
var invertLng = this.invertLng;
rect = rect.clone();
// Longitute is inverted
rect.y = -rect.y - rect.height;
if (invertLng) {
// Longitute is inverted
rect.y = -rect.y - rect.height;
}
var rawTransformable = this._rawTransformable;
......@@ -150,8 +112,10 @@ Geo.prototype = {
rawTransformable.decomposeTransform();
var scale = rawTransformable.scale;
scale[1] = -scale[1];
if (invertLng) {
var scale = rawTransformable.scale;
scale[1] = -scale[1];
}
rawTransformable.updateTransform();
......@@ -193,21 +157,11 @@ Geo.prototype = {
return this._nameCoordMap.get(name);
},
// Overwrite
/**
* @override
*/
getBoundingRect: function () {
if (this._rect) {
return this._rect;
}
var rect;
var regions = this.regions;
for (var i = 0; i < regions.length; i++) {
var regionRect = regions[i].getBoundingRect();
rect = rect || regionRect.clone();
rect.union(regionRect);
}
// FIXME Always return new ?
return (this._rect = rect || new BoundingRect(0, 0, 0, 0));
return this._rect;
},
/**
......@@ -227,12 +181,12 @@ Geo.prototype = {
},
/**
* @inheritDoc
* @override
*/
convertToPixel: zrUtil.curry(doConvert, 'dataToPoint'),
/**
* @inheritDoc
* @override
*/
convertFromPixel: zrUtil.curry(doConvert, 'pointToData')
......
......@@ -78,7 +78,9 @@ var GeoModel = ComponentModel.extend({
// Aspect is width / height. Inited to be geoJson bbox aspect
// This parameter is used for scale this aspect
aspectScale: 0.75,
// If svg used, aspectScale is 1 by default.
// aspectScale: 0.75,
aspectScale: null,
///// Layout with center and size
// If you wan't to put map in a fixed size box with right aspect ratio
......@@ -86,7 +88,6 @@ var GeoModel = ComponentModel.extend({
// layoutCenter: [50%, 50%]
// layoutSize: 100
silent: false,
// Map type
......
......@@ -27,7 +27,7 @@ import * as vec2 from 'zrender/src/core/vector';
import * as polygonContain from 'zrender/src/contain/polygon';
/**
* @param {string} name
* @param {string|Region} name
* @param {Array} geometries
* @param {Array.<number>} cp
*/
......@@ -168,6 +168,14 @@ Region.prototype = {
rect.x + rect.width / 2,
rect.y + rect.height / 2
];
},
cloneShallow: function (name) {
name == null && (name = this.name);
var newRegion = new Region(name, this.geometries, this.center);
newRegion._rect = this._rect;
newRegion.transformTo = null; // Simply avoid to be called.
return newRegion;
}
};
......
......@@ -34,15 +34,11 @@ var points = [
]
];
export default function (geo) {
if (geo.map === 'china') {
for (var i = 0, len = geo.regions.length; i < len; ++i) {
if (geo.regions[i].name === '台湾') {
geo.regions[i].geometries.push({
type: 'polygon',
exterior: points[0]
});
}
}
export default function (mapType, region) {
if (mapType === 'china' && region.name === '台湾') {
region.geometries.push({
type: 'polygon',
exterior: points[0]
});
}
}
\ No newline at end of file
......@@ -17,21 +17,19 @@
* under the License.
*/
import * as zrUtil from 'zrender/src/core/util';
var geoCoordMap = {
'Russia': [100, 60],
'United States': [-99, 38],
'United States of America': [-99, 38]
};
export default function (geo) {
zrUtil.each(geo.regions, function (region) {
export default function (mapType, region) {
if (mapType === 'world') {
var geoCoord = geoCoordMap[region.name];
if (geoCoord) {
var cp = region.center;
cp[0] = geoCoord[0];
cp[1] = geoCoord[1];
}
});
}
}
\ No newline at end of file
......@@ -51,9 +51,9 @@ for (var i = 0; i < points.length; i++) {
}
}
export default function (geo) {
if (geo.map === 'china') {
geo.regions.push(new Region(
export default function (mapType, regions) {
if (mapType === 'china') {
regions.push(new Region(
'南海诸岛',
zrUtil.map(points, function (exterior) {
return {
......
......@@ -17,8 +17,6 @@
* under the License.
*/
import * as zrUtil from 'zrender/src/core/util';
var coordsOffsetMap = {
'南海诸岛' : [32, 80],
// 全国
......@@ -29,13 +27,13 @@ var coordsOffsetMap = {
'天津': [5, 5]
};
export default function (geo) {
zrUtil.each(geo.regions, function (region) {
export default function (mapType, region) {
if (mapType === 'china') {
var coordFix = coordsOffsetMap[region.name];
if (coordFix) {
var cp = region.center;
cp[0] += coordFix[0] / 10.5;
cp[1] += -coordFix[1] / (10.5 / 0.75);
}
});
}
}
\ No newline at end of file
......@@ -23,6 +23,8 @@ import * as zrUtil from 'zrender/src/core/util';
import Geo from './Geo';
import * as layout from '../../util/layout';
import * as numberUtil from '../../util/number';
import geoSourceManager from './geoSourceManager';
import mapDataStorage from './mapDataStorage';
/**
* Resize method bound to the geo
......@@ -55,8 +57,7 @@ function resizeGeo(geoModel, api) {
var viewWidth = api.getWidth();
var viewHeight = api.getHeight();
var aspectScale = geoModel.get('aspectScale') || 0.75;
var aspect = rect.width / rect.height * aspectScale;
var aspect = rect.width / rect.height * this.aspectScale;
var useCenterAndSize = false;
......@@ -122,12 +123,6 @@ function setGeoCoords(geo, model) {
});
}
if (__DEV__) {
var mapNotExistsError = function (name) {
console.error('Map ' + name + ' not exists. You can download map file on http://echarts.baidu.com/download-map.html');
};
}
var geoCreator = {
// For deciding which dimensions to use when creating list data
......@@ -139,17 +134,8 @@ var geoCreator = {
// FIXME Create each time may be slow
ecModel.eachComponent('geo', function (geoModel, idx) {
var name = geoModel.get('map');
var mapData = echarts.getMap(name);
if (__DEV__) {
if (!mapData) {
mapNotExistsError(name);
}
}
var geo = new Geo(
name + idx, name,
mapData && mapData.geoJson, mapData && mapData.specialAreas,
geoModel.get('nameMap')
);
var geo = new Geo(name + idx, name, geoModel.get('nameMap'));
geo.zoomLimit = geoModel.get('scaleLimit');
geoList.push(geo);
......@@ -158,6 +144,20 @@ var geoCreator = {
geoModel.coordinateSystem = geo;
geo.model = geoModel;
// FIXME ???
var aspectScale = geoModel.get('aspectScale');
var invertLng = true;
var mapRecords = mapDataStorage.retrieveMap(name);
if (mapRecords && mapRecords[0] && mapRecords[0].type === 'svg') {
aspectScale == null && (aspectScale = 1);
invertLng = false;
}
else {
aspectScale == null && (aspectScale = 0.75);
}
geo.aspectScale = aspectScale;
geo.invertLng = invertLng;
// Inject resize method
geo.resize = resizeGeo;
......@@ -184,21 +184,11 @@ var geoCreator = {
});
zrUtil.each(mapModelGroupBySeries, function (mapSeries, mapType) {
var mapData = echarts.getMap(mapType);
if (__DEV__) {
if (!mapData) {
mapNotExistsError(mapSeries[0].get('map'));
}
}
var nameMapList = zrUtil.map(mapSeries, function (singleMapSeries) {
return singleMapSeries.get('nameMap');
});
var geo = new Geo(
mapType, mapType,
mapData && mapData.geoJson, mapData && mapData.specialAreas,
zrUtil.mergeAll(nameMapList)
);
var geo = new Geo(mapType, mapType, zrUtil.mergeAll(nameMapList));
geo.zoomLimit = zrUtil.retrieve.apply(null, zrUtil.map(mapSeries, function (singleMapSeries) {
return singleMapSeries.get('scaleLimit');
}));
......@@ -229,34 +219,18 @@ var geoCreator = {
getFilledRegions: function (originRegionArr, mapName, nameMap) {
// Not use the original
var regionsArr = (originRegionArr || []).slice();
nameMap = nameMap || {};
var map = echarts.getMap(mapName);
var geoJson = map && map.geoJson;
if (!geoJson) {
if (__DEV__) {
mapNotExistsError(mapName);
}
return originRegionArr;
}
var dataNameMap = zrUtil.createHashMap();
var features = geoJson.features;
for (var i = 0; i < regionsArr.length; i++) {
dataNameMap.set(regionsArr[i].name, regionsArr[i]);
}
for (var i = 0; i < features.length; i++) {
var name = features[i].properties.name;
if (!dataNameMap.get(name)) {
if (nameMap.hasOwnProperty(name)) {
name = nameMap[name];
}
regionsArr.push({
name: name
});
}
}
var source = geoSourceManager.load(mapName, nameMap);
zrUtil.each(source.regions, function (region) {
var name = region.name;
!dataNameMap.get(name) && regionsArr.push({name: name});
});
return regionsArr;
}
};
......
/*
* 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 {each} from 'zrender/src/core/util';
import parseGeoJson from './parseGeoJson';
import {makeInner} from '../../util/model';
// Built-in GEO fixer.
import fixNanhai from './fix/nanhai';
import fixTextCoord from './fix/textCoord';
import fixGeoCoord from './fix/geoCoord';
import fixDiaoyuIsland from './fix/diaoyuIsland';
var inner = makeInner();
export default {
/**
* @param {string} mapName
* @param {Object} mapRecord {specialAreas, geoJSON}
* @return {Object} {regions, boundingRect}
*/
load: function (mapName, mapRecord) {
var parsed = inner(mapRecord).parsed;
if (parsed) {
return parsed;
}
var specialAreas = mapRecord.specialAreas || {};
var geoJSON = mapRecord.geoJSON;
var regions;
// https://jsperf.com/try-catch-performance-overhead
try {
regions = geoJSON ? parseGeoJson(geoJSON) : [];
}
catch (e) {
throw new Error('Invalid geoJson format\n' + e.message);
}
each(regions, function (region) {
var regionName = region.name;
fixTextCoord(mapName, region);
fixGeoCoord(mapName, region);
fixDiaoyuIsland(mapName, region);
// Some area like Alaska in USA map needs to be tansformed
// to look better
var specialArea = specialAreas[regionName];
if (specialArea) {
region.transformTo(
specialArea.left, specialArea.top, specialArea.width, specialArea.height
);
}
});
fixNanhai(mapName, regions);
return (inner(mapRecord).parsed = {
regions: regions,
boundingRect: getBoundingRect(regions)
});
}
};
function getBoundingRect(regions) {
var rect;
for (var i = 0; i < regions.length; i++) {
var regionRect = regions[i].getBoundingRect();
rect = rect || regionRect.clone();
rect.union(regionRect);
}
return rect;
}
/*
* 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 {parseSVG, makeViewBoxTransform} from 'zrender/src/tool/parseSVG';
import Group from 'zrender/src/container/Group';
import Rect from 'zrender/src/graphic/shape/Rect';
import {assert, createHashMap} from 'zrender/src/core/util';
import BoundingRect from 'zrender/src/core/BoundingRect';
import {makeInner} from '../../util/model';
var inner = makeInner();
export default {
/**
* @param {string} mapName
* @param {Object} mapRecord {specialAreas, geoJSON}
* @return {Object} {root, boundingRect}
*/
load: function (mapName, mapRecord) {
var originRoot = inner(mapRecord).originRoot;
if (originRoot) {
return {
root: originRoot,
boundingRect: inner(mapRecord).boundingRect
};
}
var graphic = buildGraphic(mapRecord);
inner(mapRecord).originRoot = graphic.root;
inner(mapRecord).boundingRect = graphic.boundingRect;
return graphic;
},
makeGraphic: function (mapName, mapRecord, hostKey) {
// For performance consideration (in large SVG), graphic only maked
// when necessary and reuse them according to hostKey.
var field = inner(mapRecord);
var rootMap = field.rootMap || (field.rootMap = createHashMap());
var root = rootMap.get(hostKey);
if (root) {
return root;
}
var originRoot = field.originRoot;
var boundingRect = field.boundingRect;
// For performance, if originRoot is not used by a view,
// assign it to a view, but not reproduce graphic elements.
if (!field.originRootHostKey) {
field.originRootHostKey = hostKey;
root = originRoot;
}
else {
root = buildGraphic(mapRecord, boundingRect).root;
}
return rootMap.set(hostKey, root);
},
removeGraphic: function (mapName, mapRecord, hostKey) {
var field = inner(mapRecord);
var rootMap = field.rootMap;
rootMap && rootMap.removeKey(hostKey);
if (hostKey === field.originRootHostKey) {
field.originRootHostKey = null;
}
}
};
function buildGraphic(mapRecord, boundingRect) {
var svgXML = mapRecord.svgXML;
var result;
var root;
try {
result = svgXML && parseSVG(svgXML, {
ignoreViewBox: true,
ignoreRootClip: true
}) || {};
root = result.root;
assert(root != null);
}
catch (e) {
throw new Error('Invalid svg format\n' + e.message);
}
var svgWidth = result.width;
var svgHeight = result.height;
var viewBoxRect = result.viewBoxRect;
if (!boundingRect) {
boundingRect = (svgWidth == null || svgHeight == null)
// If svg width / height not specified, calculate
// bounding rect as the width / height
? root.getBoundingRect()
: new BoundingRect(0, 0, 0, 0);
if (svgWidth != null) {
boundingRect.width = svgWidth;
}
if (svgHeight != null) {
boundingRect.height = svgHeight;
}
}
if (viewBoxRect) {
var viewBoxTransform = makeViewBoxTransform(viewBoxRect, boundingRect.width, boundingRect.height);
var elRoot = root;
root = new Group();
root.add(elRoot);
elRoot.scale = viewBoxTransform.scale;
elRoot.position = viewBoxTransform.position;
}
root.setClipPath(new Rect({
shape: boundingRect.plain()
}));
return {
root: root,
boundingRect: boundingRect
};
}
/*
* 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 {__DEV__} from '../../config';
import {each, createHashMap} from 'zrender/src/core/util';
import mapDataStorage from './mapDataStorage';
import geoJSONLoader from './geoJSONLoader';
import geoSVGLoader from './geoSVGLoader';
import BoundingRect from 'zrender/src/core/BoundingRect';
var loaders = {
geoJSON: geoJSONLoader,
svg: geoSVGLoader
};
export default {
/**
* @param {string} mapName
* @param {Object} nameMap
* @return {Object} source {regions, regionsMap, nameCoordMap, boundingRect}
*/
load: function (mapName, nameMap) {
var regions = [];
var regionsMap = createHashMap();
var nameCoordMap = createHashMap();
var boundingRect;
var mapRecords = retrieveMap(mapName);
each(mapRecords, function (record) {
var singleSource = loaders[record.type].load(mapName, record);
each(singleSource.regions, function (region) {
var regionName = region.name;
// Try use the alias in geoNameMap
if (nameMap && nameMap.hasOwnProperty(regionName)) {
region = region.cloneShallow(regionName = nameMap[regionName]);
}
regions.push(region);
regionsMap.set(regionName, region);
nameCoordMap.set(regionName, region.center);
});
var rect = singleSource.boundingRect;
if (rect) {
boundingRect
? boundingRect.union(rect)
: (boundingRect = rect.clone());
}
});
return {
regions: regions,
regionsMap: regionsMap,
nameCoordMap: nameCoordMap,
// FIXME Always return new ?
boundingRect: boundingRect || new BoundingRect(0, 0, 0, 0)
};
},
/**
* @param {string} mapName
* @param {string} hostKey For cache.
* @return {Array.<module:zrender/Element>} Roots.
*/
makeGraphic: makeInvoker('makeGraphic'),
/**
* @param {string} mapName
* @param {string} hostKey For cache.
*/
removeGraphic: makeInvoker('removeGraphic')
};
function makeInvoker(methodName) {
return function (mapName, hostKey) {
var mapRecords = retrieveMap(mapName);
var results = [];
each(mapRecords, function (record) {
var method = loaders[record.type][methodName];
method && results.push(method(mapName, record, hostKey));
});
return results;
};
}
function mapNotExistsError(mapName) {
if (__DEV__) {
console.error(
'Map ' + mapName + ' not exists. You can download map file on http://echarts.baidu.com/download-map.html'
);
}
}
function retrieveMap(mapName) {
var mapRecords = mapDataStorage.retrieveMap(mapName) || [];
if (__DEV__) {
if (!mapRecords.length) {
mapNotExistsError(mapName);
}
}
return mapRecords;
}
/*
* 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 {__DEV__} from '../../config';
import {createHashMap, isString, isArray, each, assert} from 'zrender/src/core/util';
import {parseXML} from 'zrender/src/tool/parseSVG';
var storage = createHashMap();
// For minimize the code size of common echarts package,
// do not put too much logic in this module.
export default {
// The format of record: see `echarts.registerMap`.
// Compatible with previous `echarts.registerMap`.
registerMap: function (mapName, rawGeoJson, rawSpecialAreas) {
var records;
if (isArray(rawGeoJson)) {
records = rawGeoJson;
}
else if (rawGeoJson.svg) {
records = [{
type: 'svg',
source: rawGeoJson.svg,
specialAreas: rawGeoJson.specialAreas
}];
}
else {
// Backward compatibility.
if (rawGeoJson.geoJson && !rawGeoJson.features) {
rawSpecialAreas = rawGeoJson.specialAreas;
rawGeoJson = rawGeoJson.geoJson;
}
records = [{
type: 'geoJSON',
source: rawGeoJson,
specialAreas: rawSpecialAreas
}];
}
each(records, function (record) {
var type = record.type;
type === 'geoJson' && (type = record.type = 'geoJSON');
var parse = parsers[type];
if (__DEV__) {
assert(parse, 'Illegal map type: ' + type);
}
parse(record);
});
return storage.set(mapName, records);
},
retrieveMap: function (mapName) {
return storage.get(mapName);
}
};
var parsers = {
geoJSON: function (record) {
var source = record.source;
record.geoJSON = !isString(source)
? source
: (typeof JSON !== 'undefined' && JSON.parse)
? JSON.parse(source)
: (new Function('return (' + source + ');'))();
},
// Only perform parse to XML object here, which might be time
// consiming for large SVG.
// Although convert XML to zrender element is also time consiming,
// if we do it here, the clone of zrender elements has to be
// required. So we do it once for each geo instance, util real
// performance issues call for optimizing it.
svg: function (record) {
record.svgXML = parseXML(record.source);
}
};
......@@ -43,6 +43,7 @@ import Scheduler from './stream/Scheduler';
import lightTheme from './theme/light';
import darkTheme from './theme/dark';
import './component/dataset';
import mapDataStorage from './coord/geo/mapDataStorage';
var assert = zrUtil.assert;
var each = zrUtil.each;
......@@ -1720,8 +1721,6 @@ var idBase = new Date() - 0;
var groupIdBase = new Date() - 0;
var DOM_ATTRIBUTE_KEY = '_echarts_instance_';
var mapDataStores = {};
function enableConnect(chart) {
var STATUS_PENDING = 0;
var STATUS_UPDATING = 1;
......@@ -2115,10 +2114,10 @@ export function setCanvasCreator(creator) {
/**
* @param {string} mapName
* @param {Object|string} geoJson
* @param {Array.<Object>|Object|string} geoJson
* @param {Object} [specialAreas]
*
* @example
* @example GeoJSON
* $.get('USA.json', function (geoJson) {
* echarts.registerMap('USA', geoJson);
* // Or
......@@ -2127,20 +2126,20 @@ export function setCanvasCreator(creator) {
* specialAreas: {}
* })
* });
*
* $.get('airport.svg', function (svg) {
* echarts.registerMap('airport', {
* svg: svg
* }
* });
*
* echarts.registerMap('eu', [
* {svg: eu-topographic.svg},
* {geoJSON: eu.json}
* ])
*/
export function registerMap(mapName, geoJson, specialAreas) {
if (geoJson.geoJson && !geoJson.features) {
specialAreas = geoJson.specialAreas;
geoJson = geoJson.geoJson;
}
if (typeof geoJson === 'string') {
geoJson = (typeof JSON !== 'undefined' && JSON.parse)
? JSON.parse(geoJson) : (new Function('return (' + geoJson + ');'))();
}
mapDataStores[mapName] = {
geoJson: geoJson,
specialAreas: specialAreas
};
mapDataStorage.registerMap(mapName, geoJson, specialAreas);
}
/**
......@@ -2148,7 +2147,12 @@ export function registerMap(mapName, geoJson, specialAreas) {
* @return {Object}
*/
export function getMap(mapName) {
return mapDataStores[mapName];
// For backward compatibility, only return the first one.
var records = mapDataStorage.retrieveMap(mapName);
return records && records[0] && {
geoJson: records[0].geoJSON,
specialAreas: records[0].specialAreas
};
}
registerVisual(PRIORITY_VISUAL_GLOBAL, seriesColor);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册