You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1643 lines
64 KiB
1643 lines
64 KiB
4 years ago
|
/**
|
||
|
* echarts图表类:地图
|
||
|
*
|
||
|
* @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。
|
||
|
* @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
|
||
|
*
|
||
|
*/
|
||
|
define(function (require) {
|
||
|
var ChartBase = require('./base');
|
||
|
|
||
|
// 图形依赖
|
||
|
var TextShape = require('zrender/shape/Text');
|
||
|
var PathShape = require('zrender/shape/Path');
|
||
|
var CircleShape = require('zrender/shape/Circle');
|
||
|
var RectangleShape = require('zrender/shape/Rectangle');
|
||
|
var LineShape = require('zrender/shape/Line');
|
||
|
var PolygonShape = require('zrender/shape/Polygon');
|
||
|
var EllipseShape = require('zrender/shape/Ellipse');
|
||
|
// 组件依赖
|
||
|
require('../component/dataRange');
|
||
|
require('../component/roamController');
|
||
|
|
||
|
var ecConfig = require('../config');
|
||
|
// 地图默认参数
|
||
|
ecConfig.map = {
|
||
|
zlevel: 0, // 一级层叠
|
||
|
z: 2, // 二级层叠
|
||
|
mapType: 'china', // 各省的mapType暂时都用中文
|
||
|
//mapLocation: {
|
||
|
// x: 'center' | 'left' | 'right' | 'x%' | {number},
|
||
|
// y: 'center' | 'top' | 'bottom' | 'x%' | {number}
|
||
|
// width // 自适应
|
||
|
// height // 自适应
|
||
|
//},
|
||
|
// mapValueCalculation: 'sum', // 数值合并方式,默认加和,可选为:
|
||
|
// 'sum' | 'average' | 'max' | 'min'
|
||
|
mapValuePrecision: 0, // 地图数值计算结果小数精度
|
||
|
showLegendSymbol: true, // 显示图例颜色标识(系列标识的小圆点),存在legend时生效
|
||
|
// selectedMode: false, // 选择模式,默认关闭,可选single,multiple
|
||
|
dataRangeHoverLink: true,
|
||
|
hoverable: true,
|
||
|
clickable: true,
|
||
|
// roam: false, // 是否开启缩放及漫游模式
|
||
|
// scaleLimit: null,
|
||
|
itemStyle: {
|
||
|
normal: {
|
||
|
// color: 各异,
|
||
|
borderColor: 'rgba(0,0,0,0)',
|
||
|
borderWidth: 1,
|
||
|
areaStyle: {
|
||
|
color: '#ccc'
|
||
|
},
|
||
|
label: {
|
||
|
show: false,
|
||
|
textStyle: {
|
||
|
color: 'rgb(139,69,19)'
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
emphasis: { // 也是选中样式
|
||
|
// color: 各异,
|
||
|
borderColor: 'rgba(0,0,0,0)',
|
||
|
borderWidth: 1,
|
||
|
areaStyle: {
|
||
|
color: 'rgba(255,215,0,0.8)'
|
||
|
},
|
||
|
label: {
|
||
|
show: false,
|
||
|
textStyle: {
|
||
|
color: 'rgb(100,0,0)'
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var ecData = require('../util/ecData');
|
||
|
var zrUtil = require('zrender/tool/util');
|
||
|
var zrConfig = require('zrender/config');
|
||
|
var zrEvent = require('zrender/tool/event');
|
||
|
|
||
|
var _mapParams = require('../util/mapData/params').params;
|
||
|
var _textFixed = require('../util/mapData/textFixed');
|
||
|
var _geoCoord = require('../util/mapData/geoCoord');
|
||
|
|
||
|
/**
|
||
|
* 构造函数
|
||
|
* @param {Object} messageCenter echart消息中心
|
||
|
* @param {ZRender} zr zrender实例
|
||
|
* @param {Object} series 数据
|
||
|
* @param {Object} component 组件
|
||
|
*/
|
||
|
function Map(ecTheme, messageCenter, zr, option, myChart){
|
||
|
// 图表基类
|
||
|
ChartBase.call(this, ecTheme, messageCenter, zr, option, myChart);
|
||
|
|
||
|
var self = this;
|
||
|
self._onmousewheel = function(params) {
|
||
|
return self.__onmousewheel(params);
|
||
|
};
|
||
|
self._onmousedown = function(params) {
|
||
|
return self.__onmousedown(params);
|
||
|
};
|
||
|
self._onmousemove = function(params) {
|
||
|
return self.__onmousemove(params);
|
||
|
};
|
||
|
self._onmouseup = function(params) {
|
||
|
return self.__onmouseup(params);
|
||
|
};
|
||
|
self._onroamcontroller = function(params) {
|
||
|
return self.__onroamcontroller(params);
|
||
|
};
|
||
|
self._ondrhoverlink = function(params) {
|
||
|
return self.__ondrhoverlink(params);
|
||
|
};
|
||
|
|
||
|
this._isAlive = true; // 活着标记
|
||
|
this._selectedMode = {}; // 选择模式
|
||
|
this._activeMapType = {}; // 当前活跃的地图类型
|
||
|
this._clickable = {}; // 悬浮高亮模式,索引到图表
|
||
|
this._hoverable = {}; // 悬浮高亮模式,索引到图表
|
||
|
this._showLegendSymbol = {}; // 显示图例颜色标识
|
||
|
this._selected = {}; // 地图选择状态
|
||
|
this._mapTypeMap = {}; // 图例类型索引
|
||
|
this._mapDataMap = {}; // 根据地图类型索引bbox,transform,path
|
||
|
this._nameMap = {}; // 个性化地名
|
||
|
this._specialArea = {}; // 特殊
|
||
|
this._refreshDelayTicket; // 滚轮缩放时让refresh飞一会
|
||
|
this._mapDataRequireCounter; // 异步回调计数器
|
||
|
this._markAnimation = false;
|
||
|
this._hoverLinkMap = {};
|
||
|
|
||
|
// 漫游相关信息
|
||
|
this._roamMap = {};
|
||
|
this._scaleLimitMap = {};
|
||
|
this._mx;
|
||
|
this._my;
|
||
|
this._mousedown;
|
||
|
this._justMove; // 避免移动响应点击
|
||
|
this._curMapType; // 当前移动的地图类型
|
||
|
|
||
|
this.refresh(option);
|
||
|
|
||
|
this.zr.on(zrConfig.EVENT.MOUSEWHEEL, this._onmousewheel);
|
||
|
this.zr.on(zrConfig.EVENT.MOUSEDOWN, this._onmousedown);
|
||
|
messageCenter.bind(ecConfig.EVENT.ROAMCONTROLLER, this._onroamcontroller);
|
||
|
messageCenter.bind(ecConfig.EVENT.DATA_RANGE_HOVERLINK, this._ondrhoverlink);
|
||
|
}
|
||
|
|
||
|
Map.prototype = {
|
||
|
type : ecConfig.CHART_TYPE_MAP,
|
||
|
/**
|
||
|
* 绘制图形
|
||
|
*/
|
||
|
_buildShape : function () {
|
||
|
var series = this.series;
|
||
|
this.selectedMap = {}; // 系列
|
||
|
this._activeMapType = {}; // 当前活跃的地图类型
|
||
|
|
||
|
var legend = this.component.legend;
|
||
|
var seriesName;
|
||
|
var valueData = {};
|
||
|
var mapType;
|
||
|
var data;
|
||
|
var name;
|
||
|
var mapSeries = {};
|
||
|
var mapValuePrecision = {};
|
||
|
var valueCalculation = {};
|
||
|
for (var i = 0, l = series.length; i < l; i++) {
|
||
|
if (series[i].type == ecConfig.CHART_TYPE_MAP) { // map
|
||
|
series[i] = this.reformOption(series[i]);
|
||
|
mapType = series[i].mapType;
|
||
|
mapSeries[mapType] = mapSeries[mapType] || {};
|
||
|
mapSeries[mapType][i] = true;
|
||
|
mapValuePrecision[mapType] = mapValuePrecision[mapType]
|
||
|
|| series[i].mapValuePrecision;
|
||
|
this._scaleLimitMap[mapType] = this._scaleLimitMap[mapType] || {};
|
||
|
series[i].scaleLimit
|
||
|
&& zrUtil.merge(this._scaleLimitMap[mapType], series[i].scaleLimit, true);
|
||
|
|
||
|
this._roamMap[mapType] = series[i].roam || this._roamMap[mapType];
|
||
|
|
||
|
if (this._hoverLinkMap[mapType] == null || this._hoverLinkMap[mapType]) {
|
||
|
// false 1票否决
|
||
|
this._hoverLinkMap[mapType] = series[i].dataRangeHoverLink;
|
||
|
}
|
||
|
|
||
|
this._nameMap[mapType] = this._nameMap[mapType] || {};
|
||
|
series[i].nameMap
|
||
|
&& zrUtil.merge(this._nameMap[mapType], series[i].nameMap, true);
|
||
|
this._activeMapType[mapType] = true;
|
||
|
|
||
|
if (series[i].textFixed) {
|
||
|
zrUtil.merge(
|
||
|
_textFixed, series[i].textFixed, true
|
||
|
);
|
||
|
}
|
||
|
if (series[i].geoCoord) {
|
||
|
zrUtil.merge(
|
||
|
_geoCoord, series[i].geoCoord, true
|
||
|
);
|
||
|
}
|
||
|
|
||
|
this._selectedMode[mapType] = this._selectedMode[mapType]
|
||
|
|| series[i].selectedMode;
|
||
|
if (this._hoverable[mapType] == null || this._hoverable[mapType]) {
|
||
|
// false 1票否决
|
||
|
this._hoverable[mapType] = series[i].hoverable;
|
||
|
}
|
||
|
if (this._clickable[mapType] == null || this._clickable[mapType]) {
|
||
|
// false 1票否决
|
||
|
this._clickable[mapType] = series[i].clickable;
|
||
|
}
|
||
|
if (this._showLegendSymbol[mapType] == null
|
||
|
|| this._showLegendSymbol[mapType]
|
||
|
) {
|
||
|
// false 1票否决
|
||
|
this._showLegendSymbol[mapType] = series[i].showLegendSymbol;
|
||
|
}
|
||
|
|
||
|
valueCalculation[mapType] = valueCalculation[mapType]
|
||
|
|| series[i].mapValueCalculation;
|
||
|
|
||
|
seriesName = series[i].name;
|
||
|
this.selectedMap[seriesName] = legend
|
||
|
? legend.isSelected(seriesName)
|
||
|
: true;
|
||
|
if (this.selectedMap[seriesName]) {
|
||
|
valueData[mapType] = valueData[mapType] || {};
|
||
|
data = series[i].data;
|
||
|
for (var j = 0, k = data.length; j < k; j++) {
|
||
|
name = this._nameChange(mapType, data[j].name);
|
||
|
valueData[mapType][name] = valueData[mapType][name]
|
||
|
|| {
|
||
|
seriesIndex : [],
|
||
|
valueMap: {}
|
||
|
};
|
||
|
for (var key in data[j]) {
|
||
|
if (key != 'value') {
|
||
|
valueData[mapType][name][key] =
|
||
|
data[j][key];
|
||
|
}
|
||
|
else if (!isNaN(data[j].value)) {
|
||
|
// value
|
||
|
valueData[mapType][name].value == null
|
||
|
&& (valueData[mapType][name].value = 0);
|
||
|
|
||
|
valueData[mapType][name].value += (+data[j].value);
|
||
|
valueData[mapType][name].valueMap[i] = +data[j].value;
|
||
|
}
|
||
|
}
|
||
|
//索引有该区域的系列样式
|
||
|
valueData[mapType][name].seriesIndex.push(i);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this._mapDataRequireCounter = 0;
|
||
|
for (var mt in valueData) {
|
||
|
this._mapDataRequireCounter++;
|
||
|
}
|
||
|
//清空
|
||
|
this._clearSelected();
|
||
|
if (this._mapDataRequireCounter === 0) {
|
||
|
this.clear();
|
||
|
this.zr && this.zr.delShape(this.lastShapeList);
|
||
|
this.lastShapeList = [];
|
||
|
}
|
||
|
for (var mt in valueData) {
|
||
|
if (valueCalculation[mt] && valueCalculation[mt] == 'average') {
|
||
|
for (var k in valueData[mt]) {
|
||
|
valueData[mt][k].value =
|
||
|
(valueData[mt][k].value / valueData[mt][k].seriesIndex.length)
|
||
|
.toFixed(
|
||
|
mapValuePrecision[mt]
|
||
|
) - 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this._mapDataMap[mt] = this._mapDataMap[mt] || {};
|
||
|
|
||
|
if (this._mapDataMap[mt].mapData) {
|
||
|
// 已经缓存了则直接用
|
||
|
this._mapDataCallback(mt, valueData[mt], mapSeries[mt])(
|
||
|
this._mapDataMap[mt].mapData
|
||
|
);
|
||
|
}
|
||
|
else if (_mapParams[mt.replace(/\|.*/, '')].getGeoJson) {
|
||
|
// 特殊区域
|
||
|
this._specialArea[mt] =
|
||
|
_mapParams[mt.replace(/\|.*/, '')].specialArea
|
||
|
|| this._specialArea[mt];
|
||
|
_mapParams[mt.replace(/\|.*/, '')].getGeoJson(
|
||
|
this._mapDataCallback(mt, valueData[mt], mapSeries[mt])
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @param {string} mt mapType
|
||
|
* @parma {Object} vd valueData
|
||
|
* @param {Object} ms mapSeries
|
||
|
*/
|
||
|
_mapDataCallback : function (mt, vd, ms) {
|
||
|
var self = this;
|
||
|
return function (md) {
|
||
|
if (!self._isAlive || self._activeMapType[mt] == null) {
|
||
|
// 异步地图数据回调时有可能实例已经被释放
|
||
|
return;
|
||
|
}
|
||
|
// 缓存这份数据
|
||
|
if (mt.indexOf('|') != -1) {
|
||
|
// 子地图,加工一份新的mapData
|
||
|
md = self._getSubMapData(mt, md);
|
||
|
}
|
||
|
self._mapDataMap[mt].mapData = md;
|
||
|
|
||
|
if (md.firstChild) {
|
||
|
self._mapDataMap[mt].rate = 1;
|
||
|
self._mapDataMap[mt].projection = require('../util/projection/svg');
|
||
|
}
|
||
|
else {
|
||
|
self._mapDataMap[mt].rate = 0.75;
|
||
|
self._mapDataMap[mt].projection = require('../util/projection/normal');
|
||
|
}
|
||
|
|
||
|
self._buildMap(
|
||
|
mt, // 类型
|
||
|
self._getProjectionData(mt, md, ms), // 地图数据
|
||
|
vd, // 用户数据
|
||
|
ms // 系列
|
||
|
);
|
||
|
self._buildMark(mt, ms);
|
||
|
if (--self._mapDataRequireCounter <= 0) {
|
||
|
self.addShapeList();
|
||
|
self.zr.refreshNextFrame();
|
||
|
}
|
||
|
};
|
||
|
},
|
||
|
|
||
|
_clearSelected : function() {
|
||
|
for (var k in this._selected) {
|
||
|
if (!this._activeMapType[this._mapTypeMap[k]]) {
|
||
|
delete this._selected[k];
|
||
|
delete this._mapTypeMap[k];
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_getSubMapData : function (mapType, mapData) {
|
||
|
var subType = mapType.replace(/^.*\|/, '');
|
||
|
var features = mapData.features;
|
||
|
for (var i = 0, l = features.length; i < l; i++) {
|
||
|
if (features[i].properties
|
||
|
&& features[i].properties.name == subType
|
||
|
) {
|
||
|
features = features[i];
|
||
|
if (subType == 'United States of America'
|
||
|
&& features.geometry.coordinates.length > 1 // 未被简化
|
||
|
) {
|
||
|
features = {
|
||
|
geometry: {
|
||
|
coordinates: features.geometry
|
||
|
.coordinates.slice(5,6),
|
||
|
type: features.geometry.type
|
||
|
},
|
||
|
id: features.id,
|
||
|
properties: features.properties,
|
||
|
type: features.type
|
||
|
};
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return {
|
||
|
'type' : 'FeatureCollection',
|
||
|
'features':[
|
||
|
features
|
||
|
]
|
||
|
};
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 按需加载相关地图
|
||
|
*/
|
||
|
_getProjectionData : function (mapType, mapData, mapSeries) {
|
||
|
var normalProjection = this._mapDataMap[mapType].projection;
|
||
|
var province = [];
|
||
|
|
||
|
// bbox永远不变
|
||
|
var bbox = this._mapDataMap[mapType].bbox
|
||
|
|| normalProjection.getBbox(
|
||
|
mapData, this._specialArea[mapType]
|
||
|
);
|
||
|
//console.log(bbox)
|
||
|
|
||
|
var transform;
|
||
|
//console.log(1111,transform)
|
||
|
if (!this._mapDataMap[mapType].hasRoam) {
|
||
|
// 第一次或者发生了resize,需要判断
|
||
|
transform = this._getTransform(
|
||
|
bbox,
|
||
|
mapSeries,
|
||
|
this._mapDataMap[mapType].rate
|
||
|
);
|
||
|
}
|
||
|
else {
|
||
|
//经过用户漫游不再响应resize
|
||
|
transform = this._mapDataMap[mapType].transform;
|
||
|
}
|
||
|
//console.log(bbox,transform)
|
||
|
var lastTransform = this._mapDataMap[mapType].lastTransform
|
||
|
|| {scale:{}};
|
||
|
|
||
|
var pathArray;
|
||
|
if (transform.left != lastTransform.left
|
||
|
|| transform.top != lastTransform.top
|
||
|
|| transform.scale.x != lastTransform.scale.x
|
||
|
|| transform.scale.y != lastTransform.scale.y
|
||
|
) {
|
||
|
// 发生过变化,需要重新生成pathArray
|
||
|
// 一般投射
|
||
|
//console.log(transform)
|
||
|
pathArray = normalProjection.geoJson2Path(
|
||
|
mapData, transform, this._specialArea[mapType]
|
||
|
);
|
||
|
lastTransform = zrUtil.clone(transform);
|
||
|
}
|
||
|
else {
|
||
|
transform = this._mapDataMap[mapType].transform;
|
||
|
pathArray = this._mapDataMap[mapType].pathArray;
|
||
|
}
|
||
|
|
||
|
this._mapDataMap[mapType].bbox = bbox;
|
||
|
this._mapDataMap[mapType].transform = transform;
|
||
|
this._mapDataMap[mapType].lastTransform = lastTransform;
|
||
|
this._mapDataMap[mapType].pathArray = pathArray;
|
||
|
|
||
|
//console.log(pathArray)
|
||
|
var position = [transform.left, transform.top];
|
||
|
for (var i = 0, l = pathArray.length; i < l; i++) {
|
||
|
/* for test
|
||
|
console.log(
|
||
|
mapData.features[i].properties.cp, // 经纬度度
|
||
|
pathArray[i].cp // 平面坐标
|
||
|
);
|
||
|
console.log(
|
||
|
this.pos2geo(mapType, pathArray[i].cp), // 平面坐标转经纬度
|
||
|
this.geo2pos(mapType, mapData.features[i].properties.cp)
|
||
|
)
|
||
|
*/
|
||
|
province.push(this._getSingleProvince(
|
||
|
mapType, pathArray[i], position
|
||
|
));
|
||
|
}
|
||
|
|
||
|
if (this._specialArea[mapType]) {
|
||
|
for (var area in this._specialArea[mapType]) {
|
||
|
province.push(this._getSpecialProjectionData(
|
||
|
mapType, mapData,
|
||
|
area, this._specialArea[mapType][area],
|
||
|
position
|
||
|
));
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// 中国地图加入南海诸岛
|
||
|
if (mapType == 'china') {
|
||
|
var leftTop = this.geo2pos(
|
||
|
mapType,
|
||
|
_geoCoord['南海诸岛'] || _mapParams['南海诸岛'].textCoord
|
||
|
);
|
||
|
// scale.x : width = 10.51 : 64
|
||
|
var scale = transform.scale.x / 10.5;
|
||
|
var textPosition = [
|
||
|
32 * scale + leftTop[0],
|
||
|
83 * scale + leftTop[1]
|
||
|
];
|
||
|
if (_textFixed['南海诸岛']) {
|
||
|
textPosition[0] += _textFixed['南海诸岛'][0];
|
||
|
textPosition[1] += _textFixed['南海诸岛'][1];
|
||
|
}
|
||
|
province.push({
|
||
|
name : this._nameChange(mapType, '南海诸岛'),
|
||
|
path : _mapParams['南海诸岛'].getPath(leftTop, scale),
|
||
|
position : position,
|
||
|
textX : textPosition[0],
|
||
|
textY : textPosition[1]
|
||
|
});
|
||
|
|
||
|
}
|
||
|
//console.log(JSON.stringify(province));
|
||
|
//console.log(JSON.stringify(this._mapDataMap[mapType].transform));
|
||
|
return province;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 特殊地区投射数据
|
||
|
*/
|
||
|
_getSpecialProjectionData : function (mapType, mapData, areaName, mapSize, position) {
|
||
|
//console.log('_getSpecialProjectionData--------------')
|
||
|
// 构造单独的geoJson地图数据
|
||
|
mapData = this._getSubMapData('x|' + areaName, mapData);
|
||
|
|
||
|
// bbox
|
||
|
var normalProjection = require('../util/projection/normal');
|
||
|
var bbox = normalProjection.getBbox(mapData);
|
||
|
//console.log('bbox', bbox)
|
||
|
|
||
|
// transform
|
||
|
var leftTop = this.geo2pos(
|
||
|
mapType,
|
||
|
[mapSize.left, mapSize.top]
|
||
|
);
|
||
|
var rightBottom = this.geo2pos(
|
||
|
mapType,
|
||
|
[mapSize.left + mapSize.width, mapSize.top + mapSize.height]
|
||
|
);
|
||
|
//console.log('leftright' , leftTop, rightBottom);
|
||
|
var width = Math.abs(rightBottom[0] - leftTop[0]);
|
||
|
var height = Math.abs(rightBottom[1] - leftTop[1]);
|
||
|
var mapWidth = bbox.width;
|
||
|
var mapHeight = bbox.height;
|
||
|
//var minScale;
|
||
|
var xScale = (width / 0.75) / mapWidth;
|
||
|
var yScale = height / mapHeight;
|
||
|
if (xScale > yScale) {
|
||
|
xScale = yScale * 0.75;
|
||
|
width = mapWidth * xScale;
|
||
|
}
|
||
|
else {
|
||
|
yScale = xScale;
|
||
|
xScale = yScale * 0.75;
|
||
|
height = mapHeight * yScale;
|
||
|
}
|
||
|
var transform = {
|
||
|
OffsetLeft : leftTop[0],
|
||
|
OffsetTop : leftTop[1],
|
||
|
//width: width,
|
||
|
//height: height,
|
||
|
scale : {
|
||
|
x : xScale,
|
||
|
y : yScale
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//console.log('**',areaName, transform)
|
||
|
var pathArray = normalProjection.geoJson2Path(
|
||
|
mapData, transform
|
||
|
);
|
||
|
|
||
|
//console.log(pathArray)
|
||
|
return this._getSingleProvince(
|
||
|
mapType, pathArray[0], position
|
||
|
);
|
||
|
},
|
||
|
|
||
|
_getSingleProvince : function (mapType, path, position) {
|
||
|
var textPosition;
|
||
|
var name = path.properties.name;
|
||
|
var textFixed = _textFixed[name] || [0, 0];
|
||
|
if (_geoCoord[name]) {
|
||
|
// 经纬度直接定位不加textFixed
|
||
|
textPosition = this.geo2pos(
|
||
|
mapType,
|
||
|
_geoCoord[name]
|
||
|
);
|
||
|
}
|
||
|
else if (path.cp) {
|
||
|
textPosition = [
|
||
|
path.cp[0] + textFixed[0],
|
||
|
path.cp[1] + textFixed[1]
|
||
|
];
|
||
|
}
|
||
|
else {
|
||
|
var bbox = this._mapDataMap[mapType].bbox;
|
||
|
textPosition = this.geo2pos(
|
||
|
mapType,
|
||
|
[bbox.left + bbox.width / 2, bbox.top + bbox.height / 2]
|
||
|
);
|
||
|
textPosition[0] += textFixed[0];
|
||
|
textPosition[1] += textFixed[1];
|
||
|
}
|
||
|
|
||
|
//console.log(textPosition)
|
||
|
path.name = this._nameChange(mapType, name);
|
||
|
path.position = position;
|
||
|
path.textX = textPosition[0];
|
||
|
path.textY = textPosition[1];
|
||
|
return path;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 获取缩放
|
||
|
*/
|
||
|
_getTransform : function (bbox, mapSeries, rate) {
|
||
|
var series = this.series;
|
||
|
var mapLocation;
|
||
|
var x;
|
||
|
var cusX;
|
||
|
var y;
|
||
|
var cusY;
|
||
|
var width;
|
||
|
var height;
|
||
|
var zrWidth = this.zr.getWidth();
|
||
|
var zrHeight = this.zr.getHeight();
|
||
|
//上下左右留空
|
||
|
var padding = Math.round(Math.min(zrWidth, zrHeight) * 0.02);
|
||
|
for (var key in mapSeries) {
|
||
|
mapLocation = series[key].mapLocation || {};
|
||
|
cusX = mapLocation.x || cusX;
|
||
|
cusY = mapLocation.y || cusY;
|
||
|
width = mapLocation.width || width;
|
||
|
height = mapLocation.height || height;
|
||
|
}
|
||
|
|
||
|
//x = isNaN(cusX) ? padding : cusX;
|
||
|
x = this.parsePercent(cusX, zrWidth);
|
||
|
x = isNaN(x) ? padding : x;
|
||
|
//y = isNaN(cusY) ? padding : cusY;
|
||
|
y = this.parsePercent(cusY, zrHeight);
|
||
|
y = isNaN(y) ? padding : y;
|
||
|
|
||
|
width = width == null
|
||
|
? (zrWidth - x - 2 * padding)
|
||
|
: (this.parsePercent(width, zrWidth));
|
||
|
height = height == null
|
||
|
? (zrHeight - y - 2 * padding)
|
||
|
: (this.parsePercent(height, zrHeight));
|
||
|
|
||
|
var mapWidth = bbox.width;
|
||
|
var mapHeight = bbox.height;
|
||
|
//var minScale;
|
||
|
var xScale = (width / rate) / mapWidth;
|
||
|
var yScale = height / mapHeight;
|
||
|
if (xScale > yScale) {
|
||
|
//minScale = yScale;
|
||
|
xScale = yScale * rate;
|
||
|
width = mapWidth * xScale;
|
||
|
}
|
||
|
else {
|
||
|
//minScale = xScale;
|
||
|
yScale = xScale;
|
||
|
xScale = yScale * rate;
|
||
|
height = mapHeight * yScale;
|
||
|
}
|
||
|
//console.log(minScale)
|
||
|
//width = mapWidth * minScale;
|
||
|
//height = mapHeight * minScale;
|
||
|
|
||
|
if (isNaN(cusX)) {
|
||
|
cusX = cusX || 'center';
|
||
|
switch (cusX + '') {
|
||
|
case 'center' :
|
||
|
x = Math.floor((zrWidth - width) / 2);
|
||
|
break;
|
||
|
case 'right' :
|
||
|
x = zrWidth - width;
|
||
|
break;
|
||
|
//case 'left' :
|
||
|
//x = padding;
|
||
|
}
|
||
|
}
|
||
|
//console.log(cusX,x,zrWidth,width,'kener')
|
||
|
if (isNaN(cusY)) {
|
||
|
cusY = cusY || 'center';
|
||
|
switch (cusY + '') {
|
||
|
case 'center' :
|
||
|
y = Math.floor((zrHeight - height) / 2);
|
||
|
break;
|
||
|
case 'bottom' :
|
||
|
y = zrHeight - height;
|
||
|
break;
|
||
|
//case 'top' :
|
||
|
//y = padding;
|
||
|
}
|
||
|
}
|
||
|
//console.log(x,y,width,height)
|
||
|
return {
|
||
|
left : x,
|
||
|
top : y,
|
||
|
width: width,
|
||
|
height: height,
|
||
|
//scale : minScale * 50, // wtf 50
|
||
|
baseScale : 1,
|
||
|
scale : {
|
||
|
x : xScale,
|
||
|
y : yScale
|
||
|
}
|
||
|
//translate : [x + width / 2, y + height / 2]
|
||
|
};
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 构建地图
|
||
|
* @param {Object} mapData 图形数据
|
||
|
* @param {Object} valueData 用户数据
|
||
|
*/
|
||
|
_buildMap : function (mapType, mapData, valueData, mapSeries) {
|
||
|
var series = this.series;
|
||
|
var legend = this.component.legend;
|
||
|
var dataRange = this.component.dataRange;
|
||
|
var seriesName;
|
||
|
var name;
|
||
|
var data;
|
||
|
var value;
|
||
|
var queryTarget;
|
||
|
|
||
|
var color;
|
||
|
var font;
|
||
|
var style;
|
||
|
var highlightStyle;
|
||
|
|
||
|
var shape;
|
||
|
var textShape;
|
||
|
for (var i = 0, l = mapData.length; i < l; i++) {
|
||
|
style = zrUtil.clone(mapData[i]);
|
||
|
highlightStyle = {
|
||
|
name : style.name,
|
||
|
path : style.path,
|
||
|
position : zrUtil.clone(style.position)
|
||
|
};
|
||
|
name = style.name;
|
||
|
data = valueData[name]; // 多系列合并后的数据
|
||
|
if (data) {
|
||
|
queryTarget = [data]; // level 3
|
||
|
seriesName = '';
|
||
|
for (var j = 0, k = data.seriesIndex.length; j < k; j++) {
|
||
|
// level 2
|
||
|
queryTarget.push(series[data.seriesIndex[j]]);
|
||
|
seriesName += series[data.seriesIndex[j]].name + ' ';
|
||
|
if (legend
|
||
|
&& this._showLegendSymbol[mapType]
|
||
|
&& legend.hasColor(series[data.seriesIndex[j]].name)
|
||
|
) {
|
||
|
this.shapeList.push(new CircleShape({
|
||
|
zlevel : this.getZlevelBase(),
|
||
|
z : this.getZBase() + 1,
|
||
|
position : zrUtil.clone(style.position),
|
||
|
_mapType : mapType,
|
||
|
/*
|
||
|
_geo : this.pos2geo(
|
||
|
mapType, [style.textX + 3 + j * 7, style.textY - 10]
|
||
|
),
|
||
|
*/
|
||
|
style : {
|
||
|
x : style.textX + 3 + j * 7,
|
||
|
y : style.textY - 10,
|
||
|
r : 3,
|
||
|
color : legend.getColor(
|
||
|
series[data.seriesIndex[j]].name
|
||
|
)
|
||
|
},
|
||
|
hoverable : false
|
||
|
}));
|
||
|
}
|
||
|
}
|
||
|
value = data.value;
|
||
|
}
|
||
|
else {
|
||
|
data = {
|
||
|
name: name,
|
||
|
value: '-'
|
||
|
};
|
||
|
seriesName = '';
|
||
|
queryTarget = [];
|
||
|
for (var key in mapSeries) {
|
||
|
queryTarget.push(series[key]);
|
||
|
}
|
||
|
value = '-';
|
||
|
}
|
||
|
this.ecTheme.map && queryTarget.push(this.ecTheme.map); // level 1
|
||
|
queryTarget.push(ecConfig); // level 1
|
||
|
|
||
|
// 值域控件控制
|
||
|
color = (dataRange && !isNaN(value))
|
||
|
? dataRange.getColor(value)
|
||
|
: null;
|
||
|
|
||
|
// 常规设置
|
||
|
style.color = style.color
|
||
|
|| color
|
||
|
|| this.getItemStyleColor(
|
||
|
this.deepQuery(queryTarget, 'itemStyle.normal.color'),
|
||
|
data.seriesIndex, -1, data
|
||
|
)
|
||
|
|| this.deepQuery(
|
||
|
queryTarget, 'itemStyle.normal.areaStyle.color'
|
||
|
);
|
||
|
style.strokeColor = style.strokeColor
|
||
|
|| this.deepQuery(queryTarget, 'itemStyle.normal.borderColor');
|
||
|
style.lineWidth = style.lineWidth
|
||
|
|| this.deepQuery(queryTarget, 'itemStyle.normal.borderWidth');
|
||
|
|
||
|
// 高亮
|
||
|
highlightStyle.color = this.getItemStyleColor(
|
||
|
this.deepQuery(queryTarget, 'itemStyle.emphasis.color'),
|
||
|
data.seriesIndex, -1, data
|
||
|
)
|
||
|
|| this.deepQuery(
|
||
|
queryTarget, 'itemStyle.emphasis.areaStyle.color'
|
||
|
)
|
||
|
|| style.color;
|
||
|
highlightStyle.strokeColor = this.deepQuery(
|
||
|
queryTarget, 'itemStyle.emphasis.borderColor'
|
||
|
)
|
||
|
|| style.strokeColor;
|
||
|
highlightStyle.lineWidth = this.deepQuery(
|
||
|
queryTarget, 'itemStyle.emphasis.borderWidth'
|
||
|
)
|
||
|
|| style.lineWidth;
|
||
|
|
||
|
style.brushType = highlightStyle.brushType = style.brushType || 'both';
|
||
|
style.lineJoin = highlightStyle.lineJoin = 'round';
|
||
|
style._name = highlightStyle._name = name;
|
||
|
|
||
|
font = this.deepQuery(queryTarget, 'itemStyle.normal.label.textStyle');
|
||
|
// 文字标签避免覆盖单独一个shape
|
||
|
textShape = {
|
||
|
zlevel : this.getZlevelBase(),
|
||
|
z : this.getZBase() + 1,
|
||
|
//hoverable: this._hoverable[mapType],
|
||
|
//clickable: this._clickable[mapType],
|
||
|
position : zrUtil.clone(style.position),
|
||
|
_mapType : mapType,
|
||
|
_geo : this.pos2geo(
|
||
|
mapType, [style.textX, style.textY]
|
||
|
),
|
||
|
style : {
|
||
|
brushType : 'fill',
|
||
|
x : style.textX,
|
||
|
y : style.textY,
|
||
|
text : this.getLabelText(name, value, queryTarget, 'normal'),
|
||
|
_name : name,
|
||
|
textAlign : 'center',
|
||
|
color : this.deepQuery(queryTarget, 'itemStyle.normal.label.show')
|
||
|
? this.deepQuery(
|
||
|
queryTarget,
|
||
|
'itemStyle.normal.label.textStyle.color'
|
||
|
)
|
||
|
: 'rgba(0,0,0,0)',
|
||
|
textFont : this.getFont(font)
|
||
|
}
|
||
|
};
|
||
|
textShape._style = zrUtil.clone(textShape.style);
|
||
|
|
||
|
textShape.highlightStyle = zrUtil.clone(textShape.style);
|
||
|
if (this.deepQuery(queryTarget, 'itemStyle.emphasis.label.show')) {
|
||
|
textShape.highlightStyle.text = this.getLabelText(
|
||
|
name, value, queryTarget, 'emphasis'
|
||
|
);
|
||
|
textShape.highlightStyle.color = this.deepQuery(
|
||
|
queryTarget,
|
||
|
'itemStyle.emphasis.label.textStyle.color'
|
||
|
) || textShape.style.color;
|
||
|
font = this.deepQuery(
|
||
|
queryTarget,
|
||
|
'itemStyle.emphasis.label.textStyle'
|
||
|
) || font;
|
||
|
textShape.highlightStyle.textFont = this.getFont(font);
|
||
|
}
|
||
|
else {
|
||
|
textShape.highlightStyle.color = 'rgba(0,0,0,0)';
|
||
|
}
|
||
|
|
||
|
shape = {
|
||
|
zlevel : this.getZlevelBase(),
|
||
|
z : this.getZBase(),
|
||
|
//hoverable: this._hoverable[mapType],
|
||
|
//clickable: this._clickable[mapType],
|
||
|
position : zrUtil.clone(style.position),
|
||
|
style : style,
|
||
|
highlightStyle : highlightStyle,
|
||
|
_style: zrUtil.clone(style),
|
||
|
_mapType: mapType
|
||
|
};
|
||
|
if (style.scale != null) {
|
||
|
shape.scale = zrUtil.clone(style.scale);
|
||
|
}
|
||
|
|
||
|
textShape = new TextShape(textShape);
|
||
|
switch (shape.style.shapeType) {
|
||
|
case 'rectangle' :
|
||
|
shape = new RectangleShape(shape);
|
||
|
break;
|
||
|
case 'line' :
|
||
|
shape = new LineShape(shape);
|
||
|
break;
|
||
|
case 'circle' :
|
||
|
shape = new CircleShape(shape);
|
||
|
break;
|
||
|
case 'polygon' :
|
||
|
shape = new PolygonShape(shape);
|
||
|
break;
|
||
|
case 'ellipse':
|
||
|
shape = new EllipseShape(shape);
|
||
|
break;
|
||
|
default :
|
||
|
shape = new PathShape(shape);
|
||
|
if (shape.buildPathArray) {
|
||
|
shape.style.pathArray = shape.buildPathArray(shape.style.path);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (this._selectedMode[mapType] &&
|
||
|
this._selected[name]
|
||
|
|| (data.selected && this._selected[name] !== false)
|
||
|
) {
|
||
|
textShape.style = textShape.highlightStyle;
|
||
|
shape.style = shape.highlightStyle;
|
||
|
}
|
||
|
|
||
|
textShape.clickable = shape.clickable =
|
||
|
this._clickable[mapType]
|
||
|
&& (data.clickable == null || data.clickable);
|
||
|
|
||
|
if (this._selectedMode[mapType]) {
|
||
|
this._selected[name] = this._selected[name] != null
|
||
|
? this._selected[name]
|
||
|
: data.selected;
|
||
|
this._mapTypeMap[name] = mapType;
|
||
|
|
||
|
if (data.selectable == null || data.selectable) {
|
||
|
shape.clickable = textShape.clickable = true;
|
||
|
shape.onclick = textShape.onclick = this.shapeHandler.onclick;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (this._hoverable[mapType]
|
||
|
&& (data.hoverable == null || data.hoverable)
|
||
|
) {
|
||
|
textShape.hoverable = shape.hoverable = true;
|
||
|
shape.hoverConnect = textShape.id;
|
||
|
textShape.hoverConnect = shape.id;
|
||
|
}
|
||
|
else {
|
||
|
textShape.hoverable = shape.hoverable = false;
|
||
|
}
|
||
|
|
||
|
// console.log(name,shape);
|
||
|
ecData.pack(
|
||
|
textShape,
|
||
|
{
|
||
|
name: seriesName,
|
||
|
tooltip: this.deepQuery(queryTarget, 'tooltip')
|
||
|
},
|
||
|
0,
|
||
|
data, 0,
|
||
|
name
|
||
|
);
|
||
|
this.shapeList.push(textShape);
|
||
|
|
||
|
ecData.pack(
|
||
|
shape,
|
||
|
{
|
||
|
name: seriesName,
|
||
|
tooltip: this.deepQuery(queryTarget, 'tooltip')
|
||
|
},
|
||
|
0,
|
||
|
data, 0,
|
||
|
name
|
||
|
);
|
||
|
this.shapeList.push(shape);
|
||
|
}
|
||
|
//console.log(this._selected);
|
||
|
},
|
||
|
|
||
|
// 添加标注
|
||
|
_buildMark : function (mapType, mapSeries) {
|
||
|
this._seriesIndexToMapType = this._seriesIndexToMapType || {};
|
||
|
this.markAttachStyle = this.markAttachStyle || {};
|
||
|
var position = [
|
||
|
this._mapDataMap[mapType].transform.left,
|
||
|
this._mapDataMap[mapType].transform.top
|
||
|
];
|
||
|
if (mapType == 'none') {
|
||
|
position = [0, 0];
|
||
|
}
|
||
|
for (var sIdx in mapSeries) {
|
||
|
this._seriesIndexToMapType[sIdx] = mapType;
|
||
|
this.markAttachStyle[sIdx] = {
|
||
|
position : position,
|
||
|
_mapType : mapType
|
||
|
};
|
||
|
this.buildMark(sIdx);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// 位置转换
|
||
|
getMarkCoord : function (seriesIndex, mpData) {
|
||
|
return (mpData.geoCoord || _geoCoord[mpData.name])
|
||
|
? this.geo2pos(
|
||
|
this._seriesIndexToMapType[seriesIndex],
|
||
|
mpData.geoCoord || _geoCoord[mpData.name]
|
||
|
)
|
||
|
: [0, 0];
|
||
|
},
|
||
|
|
||
|
getMarkGeo : function(mpData) {
|
||
|
return mpData.geoCoord || _geoCoord[mpData.name];
|
||
|
},
|
||
|
|
||
|
_nameChange : function (mapType, name) {
|
||
|
return this._nameMap[mapType][name] || name;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 根据lable.format计算label text
|
||
|
*/
|
||
|
getLabelText : function (name, value, queryTarget, status) {
|
||
|
var formatter = this.deepQuery(
|
||
|
queryTarget,
|
||
|
'itemStyle.' + status + '.label.formatter'
|
||
|
);
|
||
|
if (formatter) {
|
||
|
if (typeof formatter == 'function') {
|
||
|
return formatter.call(
|
||
|
this.myChart,
|
||
|
name,
|
||
|
value
|
||
|
);
|
||
|
}
|
||
|
else if (typeof formatter == 'string') {
|
||
|
formatter = formatter.replace('{a}','{a0}')
|
||
|
.replace('{b}','{b0}');
|
||
|
formatter = formatter.replace('{a0}', name)
|
||
|
.replace('{b0}', value);
|
||
|
return formatter;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
return name;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_findMapTypeByPos : function (mx, my) {
|
||
|
var transform;
|
||
|
var left;
|
||
|
var top;
|
||
|
var width;
|
||
|
var height;
|
||
|
for (var mapType in this._mapDataMap) {
|
||
|
transform = this._mapDataMap[mapType].transform;
|
||
|
if (!transform || !this._roamMap[mapType] || !this._activeMapType[mapType]) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
left = transform.left;
|
||
|
top = transform.top;
|
||
|
width = transform.width;
|
||
|
height = transform.height;
|
||
|
if (mx >= left
|
||
|
&& mx <= (left + width)
|
||
|
&& my >= top
|
||
|
&& my <= (top + height)
|
||
|
) {
|
||
|
return mapType;
|
||
|
}
|
||
|
}
|
||
|
return;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 滚轮缩放
|
||
|
*/
|
||
|
__onmousewheel : function (params) {
|
||
|
if (this.shapeList.length <= 0) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (var i = 0, l = this.shapeList.length; i < l; i++) {
|
||
|
var shape = this.shapeList[i];
|
||
|
// If any shape is still animating
|
||
|
if (shape.__animating) {
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var event = params.event;
|
||
|
var mx = zrEvent.getX(event);
|
||
|
var my = zrEvent.getY(event);
|
||
|
var delta;
|
||
|
var eventDelta = zrEvent.getDelta(event);
|
||
|
//eventDelta = eventDelta > 0 ? (-1) : 1;
|
||
|
var mapType;
|
||
|
var mapTypeControl = params.mapTypeControl;
|
||
|
if (!mapTypeControl) {
|
||
|
mapTypeControl = {};
|
||
|
mapType = this._findMapTypeByPos(mx, my);
|
||
|
if (mapType && this._roamMap[mapType] && this._roamMap[mapType] != 'move') {
|
||
|
mapTypeControl[mapType] = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function scalePolyline(shapeStyle, delta) {
|
||
|
for (var i = 0; i < shapeStyle.pointList.length; i++) {
|
||
|
var point = shapeStyle.pointList[i];
|
||
|
point[0] *= delta;
|
||
|
point[1] *= delta;
|
||
|
}
|
||
|
//If smoothness > 0
|
||
|
var controlPointList = shapeStyle.controlPointList;
|
||
|
if (controlPointList) {
|
||
|
for (var i = 0; i < controlPointList.length; i++) {
|
||
|
var point = controlPointList[i];
|
||
|
point[0] *= delta;
|
||
|
point[1] *= delta;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function scaleMarkline(shapeStyle, delta) {
|
||
|
shapeStyle.xStart *= delta;
|
||
|
shapeStyle.yStart *= delta;
|
||
|
shapeStyle.xEnd *= delta;
|
||
|
shapeStyle.yEnd *= delta;
|
||
|
if (shapeStyle.cpX1 != null) {
|
||
|
shapeStyle.cpX1 *= delta;
|
||
|
shapeStyle.cpY1 *= delta;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var haveScale = false;
|
||
|
for (mapType in mapTypeControl) {
|
||
|
if (mapTypeControl[mapType]) {
|
||
|
haveScale = true;
|
||
|
var transform = this._mapDataMap[mapType].transform;
|
||
|
var left = transform.left;
|
||
|
var top = transform.top;
|
||
|
var width = transform.width;
|
||
|
var height = transform.height;
|
||
|
// 位置转经纬度
|
||
|
var geoAndPos = this.pos2geo(mapType, [mx - left, my - top]);
|
||
|
if (eventDelta > 0) {
|
||
|
delta = 1.2; // 放大
|
||
|
if (this._scaleLimitMap[mapType].max != null
|
||
|
&& transform.baseScale >= this._scaleLimitMap[mapType].max
|
||
|
) {
|
||
|
continue; // 缩放限制
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
delta = 1 / 1.2; // 缩小
|
||
|
if (this._scaleLimitMap[mapType].min != null
|
||
|
&& transform.baseScale <= this._scaleLimitMap[mapType].min
|
||
|
) {
|
||
|
continue; // 缩放限制
|
||
|
}
|
||
|
}
|
||
|
|
||
|
transform.baseScale *= delta;
|
||
|
transform.scale.x *= delta;
|
||
|
transform.scale.y *= delta;
|
||
|
transform.width = width * delta;
|
||
|
transform.height = height * delta;
|
||
|
|
||
|
this._mapDataMap[mapType].hasRoam = true;
|
||
|
this._mapDataMap[mapType].transform = transform;
|
||
|
// 经纬度转位置
|
||
|
geoAndPos = this.geo2pos(mapType, geoAndPos);
|
||
|
// 保持视觉中心
|
||
|
transform.left -= geoAndPos[0] - (mx - left);
|
||
|
transform.top -= geoAndPos[1] - (my - top);
|
||
|
this._mapDataMap[mapType].transform = transform;
|
||
|
|
||
|
this.clearEffectShape(true);
|
||
|
for (var i = 0, l = this.shapeList.length; i < l; i++) {
|
||
|
var shape = this.shapeList[i];
|
||
|
if(shape._mapType == mapType) {
|
||
|
var shapeType = shape.type;
|
||
|
var shapeStyle = shape.style;
|
||
|
shape.position[0] = transform.left;
|
||
|
shape.position[1] = transform.top;
|
||
|
|
||
|
switch (shapeType) {
|
||
|
case 'path':
|
||
|
case 'symbol':
|
||
|
case 'circle':
|
||
|
case 'rectangle':
|
||
|
case 'polygon':
|
||
|
case 'line':
|
||
|
case 'ellipse':
|
||
|
shape.scale[0] *= delta;
|
||
|
shape.scale[1] *= delta;
|
||
|
break;
|
||
|
case 'mark-line':
|
||
|
scaleMarkline(shapeStyle, delta);
|
||
|
break;
|
||
|
case 'polyline':
|
||
|
scalePolyline(shapeStyle, delta);
|
||
|
break;
|
||
|
case 'shape-bundle':
|
||
|
for (var j = 0; j < shapeStyle.shapeList.length; j++) {
|
||
|
var subShape = shapeStyle.shapeList[j];
|
||
|
if (subShape.type == 'mark-line') {
|
||
|
scaleMarkline(subShape.style, delta);
|
||
|
}
|
||
|
else if (subShape.type == 'polyline') {
|
||
|
scalePolyline(subShape.style, delta);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case 'icon':
|
||
|
case 'image':
|
||
|
geoAndPos = this.geo2pos(mapType, shape._geo);
|
||
|
shapeStyle.x = shapeStyle._x =
|
||
|
geoAndPos[0] - shapeStyle.width / 2;
|
||
|
shapeStyle.y = shapeStyle._y =
|
||
|
geoAndPos[1] - shapeStyle.height / 2;
|
||
|
break;
|
||
|
default:
|
||
|
geoAndPos = this.geo2pos(mapType, shape._geo);
|
||
|
shapeStyle.x = geoAndPos[0];
|
||
|
shapeStyle.y = geoAndPos[1];
|
||
|
if (shapeType == 'text') {
|
||
|
shape._style.x = shape.highlightStyle.x
|
||
|
= geoAndPos[0];
|
||
|
shape._style.y = shape.highlightStyle.y
|
||
|
= geoAndPos[1];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.zr.modShape(shape.id);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (haveScale) {
|
||
|
zrEvent.stop(event);
|
||
|
this.zr.refreshNextFrame();
|
||
|
|
||
|
var self = this;
|
||
|
clearTimeout(this._refreshDelayTicket);
|
||
|
this._refreshDelayTicket = setTimeout(
|
||
|
function(){
|
||
|
self && self.shapeList && self.animationEffect();
|
||
|
},
|
||
|
100
|
||
|
);
|
||
|
|
||
|
this.messageCenter.dispatch(
|
||
|
ecConfig.EVENT.MAP_ROAM,
|
||
|
params.event,
|
||
|
{type : 'scale'},
|
||
|
this.myChart
|
||
|
);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
__onmousedown : function (params) {
|
||
|
if (this.shapeList.length <= 0) {
|
||
|
return;
|
||
|
}
|
||
|
var target = params.target;
|
||
|
if (target && target.draggable) {
|
||
|
return;
|
||
|
}
|
||
|
var event = params.event;
|
||
|
var mx = zrEvent.getX(event);
|
||
|
var my = zrEvent.getY(event);
|
||
|
var mapType = this._findMapTypeByPos(mx, my);
|
||
|
if (mapType && this._roamMap[mapType] && this._roamMap[mapType] != 'scale') {
|
||
|
this._mousedown = true;
|
||
|
this._mx = mx;
|
||
|
this._my = my;
|
||
|
this._curMapType = mapType;
|
||
|
this.zr.on(zrConfig.EVENT.MOUSEUP, this._onmouseup);
|
||
|
var self = this;
|
||
|
setTimeout(function (){
|
||
|
self.zr.on(zrConfig.EVENT.MOUSEMOVE, self._onmousemove);
|
||
|
},100);
|
||
|
}
|
||
|
|
||
|
},
|
||
|
|
||
|
__onmousemove : function (params) {
|
||
|
if (!this._mousedown || !this._isAlive) {
|
||
|
return;
|
||
|
}
|
||
|
var event = params.event;
|
||
|
var mx = zrEvent.getX(event);
|
||
|
var my = zrEvent.getY(event);
|
||
|
var transform = this._mapDataMap[this._curMapType].transform;
|
||
|
transform.hasRoam = true;
|
||
|
transform.left -= this._mx - mx;
|
||
|
transform.top -= this._my - my;
|
||
|
this._mx = mx;
|
||
|
this._my = my;
|
||
|
this._mapDataMap[this._curMapType].transform = transform;
|
||
|
|
||
|
for (var i = 0, l = this.shapeList.length; i < l; i++) {
|
||
|
if(this.shapeList[i]._mapType == this._curMapType) {
|
||
|
this.shapeList[i].position[0] = transform.left;
|
||
|
this.shapeList[i].position[1] = transform.top;
|
||
|
this.zr.modShape(this.shapeList[i].id);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.messageCenter.dispatch(
|
||
|
ecConfig.EVENT.MAP_ROAM,
|
||
|
params.event,
|
||
|
{type : 'move'},
|
||
|
this.myChart
|
||
|
);
|
||
|
|
||
|
this.clearEffectShape(true);
|
||
|
this.zr.refreshNextFrame();
|
||
|
|
||
|
this._justMove = true;
|
||
|
zrEvent.stop(event);
|
||
|
},
|
||
|
|
||
|
__onmouseup : function (params) {
|
||
|
var event = params.event;
|
||
|
this._mx = zrEvent.getX(event);
|
||
|
this._my = zrEvent.getY(event);
|
||
|
this._mousedown = false;
|
||
|
var self = this;
|
||
|
setTimeout(function (){
|
||
|
self._justMove && self.animationEffect();
|
||
|
self._justMove = false;
|
||
|
self.zr.un(zrConfig.EVENT.MOUSEMOVE, self._onmousemove);
|
||
|
self.zr.un(zrConfig.EVENT.MOUSEUP, self._onmouseup);
|
||
|
},120);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 漫游组件事件响应
|
||
|
*/
|
||
|
__onroamcontroller: function(params) {
|
||
|
var event = params.event;
|
||
|
event.zrenderX = this.zr.getWidth() / 2;
|
||
|
event.zrenderY = this.zr.getHeight() / 2;
|
||
|
var mapTypeControl = params.mapTypeControl;
|
||
|
var top = 0;
|
||
|
var left = 0;
|
||
|
var step = params.step;
|
||
|
|
||
|
switch(params.roamType) {
|
||
|
case 'scaleUp':
|
||
|
event.zrenderDelta = 1;
|
||
|
this.__onmousewheel({
|
||
|
event: event,
|
||
|
mapTypeControl: mapTypeControl
|
||
|
});
|
||
|
return;
|
||
|
case 'scaleDown':
|
||
|
event.zrenderDelta = -1;
|
||
|
this.__onmousewheel({
|
||
|
event: event,
|
||
|
mapTypeControl: mapTypeControl
|
||
|
});
|
||
|
return;
|
||
|
case 'up':
|
||
|
top = -step;
|
||
|
break;
|
||
|
case 'down':
|
||
|
top = step;
|
||
|
break;
|
||
|
case 'left':
|
||
|
left = -step;
|
||
|
break;
|
||
|
case 'right':
|
||
|
left = step;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
var transform;
|
||
|
var curMapType;
|
||
|
for (curMapType in mapTypeControl) {
|
||
|
if (!this._mapDataMap[curMapType] || !this._activeMapType[curMapType]) {
|
||
|
continue;
|
||
|
}
|
||
|
transform = this._mapDataMap[curMapType].transform;
|
||
|
transform.hasRoam = true;
|
||
|
transform.left -= left;
|
||
|
transform.top -= top;
|
||
|
this._mapDataMap[curMapType].transform = transform;
|
||
|
}
|
||
|
for (var i = 0, l = this.shapeList.length; i < l; i++) {
|
||
|
curMapType = this.shapeList[i]._mapType;
|
||
|
if (!mapTypeControl[curMapType] || !this._activeMapType[curMapType]) {
|
||
|
continue;
|
||
|
}
|
||
|
transform = this._mapDataMap[curMapType].transform;
|
||
|
this.shapeList[i].position[0] = transform.left;
|
||
|
this.shapeList[i].position[1] = transform.top;
|
||
|
this.zr.modShape(this.shapeList[i].id);
|
||
|
}
|
||
|
|
||
|
this.messageCenter.dispatch(
|
||
|
ecConfig.EVENT.MAP_ROAM,
|
||
|
params.event,
|
||
|
{type : 'move'},
|
||
|
this.myChart
|
||
|
);
|
||
|
|
||
|
this.clearEffectShape(true);
|
||
|
this.zr.refreshNextFrame();
|
||
|
|
||
|
clearTimeout(this.dircetionTimer);
|
||
|
var self = this;
|
||
|
this.dircetionTimer = setTimeout(function() {
|
||
|
self.animationEffect();
|
||
|
}, 150);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* dataRange hoverlink 事件响应
|
||
|
*/
|
||
|
__ondrhoverlink : function(param) {
|
||
|
var curMapType;
|
||
|
var value;
|
||
|
for (var i = 0, l = this.shapeList.length; i < l; i++) {
|
||
|
curMapType = this.shapeList[i]._mapType;
|
||
|
if (!this._hoverLinkMap[curMapType] || !this._activeMapType[curMapType]) {
|
||
|
continue;
|
||
|
}
|
||
|
value = ecData.get(this.shapeList[i], 'value');
|
||
|
if (value != null && value >= param.valueMin && value <= param.valueMax) {
|
||
|
this.zr.addHoverShape(this.shapeList[i]);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 点击响应
|
||
|
*/
|
||
|
onclick : function (params) {
|
||
|
if (!this.isClick || !params.target || this._justMove || params.target.type == 'icon') {
|
||
|
// 没有在当前实例上发生点击直接返回
|
||
|
return;
|
||
|
}
|
||
|
this.isClick = false;
|
||
|
|
||
|
var target = params.target;
|
||
|
var name = target.style._name;
|
||
|
var len = this.shapeList.length;
|
||
|
var mapType = target._mapType || '';
|
||
|
|
||
|
if (this._selectedMode[mapType] == 'single') {
|
||
|
for (var p in this._selected) {
|
||
|
// 同一地图类型
|
||
|
if (this._selected[p] && this._mapTypeMap[p] == mapType) {
|
||
|
// 复位那些生效shape(包括文字)
|
||
|
for (var i = 0; i < len; i++) {
|
||
|
if (this.shapeList[i].style._name == p
|
||
|
&& this.shapeList[i]._mapType == mapType
|
||
|
) {
|
||
|
this.shapeList[i].style = this.shapeList[i]._style;
|
||
|
this.zr.modShape(this.shapeList[i].id);
|
||
|
}
|
||
|
}
|
||
|
p != name && (this._selected[p] = false);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this._selected[name] = !this._selected[name];
|
||
|
|
||
|
// 更新当前点击shape(包括文字)
|
||
|
for (var i = 0; i < len; i++) {
|
||
|
if (this.shapeList[i].style._name == name
|
||
|
&& this.shapeList[i]._mapType == mapType
|
||
|
) {
|
||
|
if (this._selected[name]) {
|
||
|
this.shapeList[i].style = this.shapeList[i].highlightStyle;
|
||
|
}
|
||
|
else {
|
||
|
this.shapeList[i].style = this.shapeList[i]._style;
|
||
|
}
|
||
|
this.zr.modShape(this.shapeList[i].id);
|
||
|
}
|
||
|
}
|
||
|
this.messageCenter.dispatch(
|
||
|
ecConfig.EVENT.MAP_SELECTED,
|
||
|
params.event,
|
||
|
{
|
||
|
selected : this._selected,
|
||
|
target : name
|
||
|
},
|
||
|
this.myChart
|
||
|
);
|
||
|
this.zr.refreshNextFrame();
|
||
|
|
||
|
var self = this;
|
||
|
setTimeout(function(){
|
||
|
self.zr.trigger(
|
||
|
zrConfig.EVENT.MOUSEMOVE,
|
||
|
params.event
|
||
|
);
|
||
|
},100);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 刷新
|
||
|
*/
|
||
|
refresh : function (newOption) {
|
||
|
if (newOption) {
|
||
|
this.option = newOption;
|
||
|
this.series = newOption.series;
|
||
|
}
|
||
|
|
||
|
if (this._mapDataRequireCounter > 0) {
|
||
|
this.clear();
|
||
|
}
|
||
|
else {
|
||
|
this.backupShapeList();
|
||
|
}
|
||
|
this._buildShape();
|
||
|
this.zr.refreshHover();
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 值域响应
|
||
|
* @param {Object} param
|
||
|
* @param {Object} status
|
||
|
*/
|
||
|
ondataRange : function (param, status) {
|
||
|
if (this.component.dataRange) {
|
||
|
this.refresh();
|
||
|
status.needRefresh = true;
|
||
|
}
|
||
|
return;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 平面坐标转经纬度
|
||
|
*/
|
||
|
pos2geo : function (mapType, p) {
|
||
|
if (!this._mapDataMap[mapType].transform) {
|
||
|
return null;
|
||
|
}
|
||
|
return this._mapDataMap[mapType].projection.pos2geo(
|
||
|
this._mapDataMap[mapType].transform, p
|
||
|
);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 公开接口 : 平面坐标转经纬度
|
||
|
*/
|
||
|
getGeoByPos : function (mapType, p) {
|
||
|
if (!this._mapDataMap[mapType].transform) {
|
||
|
return null;
|
||
|
}
|
||
|
var position = [
|
||
|
this._mapDataMap[mapType].transform.left,
|
||
|
this._mapDataMap[mapType].transform.top
|
||
|
];
|
||
|
if (p instanceof Array) {
|
||
|
p[0] -= position[0];
|
||
|
p[1] -= position[1];
|
||
|
}
|
||
|
else {
|
||
|
p.x -= position[0];
|
||
|
p.y -= position[1];
|
||
|
}
|
||
|
return this.pos2geo(mapType, p);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 经纬度转平面坐标
|
||
|
* @param {Object} p
|
||
|
*/
|
||
|
geo2pos : function (mapType, p) {
|
||
|
if (!this._mapDataMap[mapType].transform) {
|
||
|
return null;
|
||
|
}
|
||
|
return this._mapDataMap[mapType].projection.geo2pos(
|
||
|
this._mapDataMap[mapType].transform, p
|
||
|
);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 公开接口 : 经纬度转平面坐标
|
||
|
*/
|
||
|
getPosByGeo : function (mapType, p) {
|
||
|
if (!this._mapDataMap[mapType].transform) {
|
||
|
return null;
|
||
|
}
|
||
|
var pos = this.geo2pos(mapType, p);
|
||
|
pos[0] += this._mapDataMap[mapType].transform.left;
|
||
|
pos[1] += this._mapDataMap[mapType].transform.top;
|
||
|
return pos;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 公开接口 : 地图参考坐标
|
||
|
*/
|
||
|
getMapPosition : function (mapType) {
|
||
|
if (!this._mapDataMap[mapType].transform) {
|
||
|
return null;
|
||
|
}
|
||
|
return [
|
||
|
this._mapDataMap[mapType].transform.left,
|
||
|
this._mapDataMap[mapType].transform.top
|
||
|
];
|
||
|
},
|
||
|
|
||
|
/*
|
||
|
appendShape : function (mapType, shapeList) {
|
||
|
shapeList = shapeList instanceof Array
|
||
|
? shapeList : [shapeList];
|
||
|
for (var i = 0, l = shapeList.length; i < l; i++) {
|
||
|
if (typeof shapeList[i].zlevel == 'undefined') {
|
||
|
shapeList[i].zlevel = this.getZlevelBase();
|
||
|
shapeList[i].z = this.getZBase() + 1;
|
||
|
}
|
||
|
shapeList[i]._mapType = mapType;
|
||
|
this.shapeList.push(shapeList[i]);
|
||
|
this.zr.addShape(shapeList[i]);
|
||
|
}
|
||
|
this.zr.refresh();
|
||
|
},
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* 释放后实例不可用
|
||
|
*/
|
||
|
onbeforDispose : function () {
|
||
|
this._isAlive = false;
|
||
|
this.zr.un(zrConfig.EVENT.MOUSEWHEEL, this._onmousewheel);
|
||
|
this.zr.un(zrConfig.EVENT.MOUSEDOWN, this._onmousedown);
|
||
|
this.messageCenter.unbind(
|
||
|
ecConfig.EVENT.ROAMCONTROLLER, this._onroamcontroller
|
||
|
);
|
||
|
this.messageCenter.unbind(
|
||
|
ecConfig.EVENT.DATA_RANGE_HOVERLINK, this._ondrhoverlink
|
||
|
);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
zrUtil.inherits(Map, ChartBase);
|
||
|
|
||
|
// 图表注册
|
||
|
require('../chart').define('map', Map);
|
||
|
|
||
|
return Map;
|
||
|
});
|