blob: aedc2c80d9c358c5ded9b2df1a2686859f67671d [file] [log] [blame]
import * as zrUtil from 'zrender/src/core/util';
import BoundingRect from 'zrender/src/core/BoundingRect';
import parseGeoJson from './parseGeoJson';
import View from '../View';
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
* @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) {
View.call(this, name);
/**
* Map type
* @type {string}
*/
this.map = map;
this._nameCoordMap = zrUtil.createHashMap();
this.loadGeoJson(geoJson, specialAreas, nameMap);
}
Geo.prototype = {
constructor: Geo,
type: 'geo',
/**
* @param {Array.<string>}
* @readOnly
*/
dimensions: ['lng', 'lat'],
/**
* If contain given lng,lat coord
* @param {Array.<number>}
* @readOnly
*/
containCoord: function (coord) {
var regions = this.regions;
for (var i = 0; i < regions.length; i++) {
if (regions[i].contain(coord)) {
return true;
}
}
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
*/
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();
rect = rect.clone(); // Longitute is inverted
rect.y = -rect.y - rect.height;
var viewTransform = this._viewTransform;
viewTransform.transform = rect.calculateTransform(new BoundingRect(x, y, width, height));
viewTransform.decomposeTransform();
var scale = viewTransform.scale;
scale[1] = -scale[1];
viewTransform.updateTransform();
this._updateTransform();
},
/**
* @param {string} name
* @return {module:echarts/coord/geo/Region}
*/
getRegion: function (name) {
return this._regionsMap.get(name);
},
getRegionByCoord: function (coord) {
var regions = this.regions;
for (var i = 0; i < regions.length; i++) {
if (regions[i].contain(coord)) {
return regions[i];
}
}
},
/**
* Add geoCoord for indexing by name
* @param {string} name
* @param {Array.<number>} geoCoord
*/
addGeoCoord: function (name, geoCoord) {
this._nameCoordMap.set(name, geoCoord);
},
/**
* Get geoCoord by name
* @param {string} name
* @return {Array.<number>}
*/
getGeoCoord: function (name) {
return this._nameCoordMap.get(name);
},
// Overwrite
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);
},
/**
* @param {string|Array.<number>} data
* @return {Array.<number>}
*/
dataToPoint: function (data) {
if (typeof data === 'string') {
// Map area name to geoCoord
data = this.getGeoCoord(data);
}
if (data) {
return View.prototype.dataToPoint.call(this, data);
}
},
/**
* @inheritDoc
*/
convertToPixel: zrUtil.curry(doConvert, 'dataToPoint'),
/**
* @inheritDoc
*/
convertFromPixel: zrUtil.curry(doConvert, 'pointToData')
};
zrUtil.mixin(Geo, View);
function doConvert(methodName, ecModel, finder, value) {
var geoModel = finder.geoModel;
var seriesModel = finder.seriesModel;
var coordSys = geoModel ? geoModel.coordinateSystem : seriesModel ? seriesModel.coordinateSystem // For map.
|| (seriesModel.getReferringComponents('geo')[0] || {}).coordinateSystem : null;
return coordSys === this ? coordSys[methodName](value) : null;
}
export default Geo;