思路:
data:function(){
return {
//多边形覆盖物
plateOverlays:[],
//栅格默认的参数
blockDefaultParams:{
southWest: { lng: 112.963588, lat: 22.515978 },
northEast: { lng: 114.075063, lat: 23.945013 },
dataBlockSize: 5000,
},
//接口返回的栅格的数组
blockData:[]
}
},
methods:{
//根据地图上的多边形覆盖物轮廓获得最大的经度纬度作为东北角,最小的经度纬度作为西南角
updateBlockDefaultParams:function(){
var _this = this;
var points = [];
var plateOverlays = _this.plateOverlays;
for (var i in plateOverlays) {
var polygon = plateOverlays[i];
points = points.concat(polygon.getPath());//返回多边形覆盖物的点数组
}
//取多边形覆盖物各点中的最大的经度纬度作为东北角,最小的经度纬度作为西南角
//所绘的矩形完全包括了多边形覆盖物
var lngArr = [],
latArr = [];
points.map(function(item){
lngArr.push(item.lng);
latArr.push(item.lat);
})
var maxLng = lngArr.reduce(function(a , b){
return b > a ? b : a;
});
var maxLat = latArr.reduce(function(a , b){
return b > a ? b : a;
});
var minLng = lngArr.reduce(function(a , b){
return b < a ? b : a;
});
var minLat = latArr.reduce(function(a , b){
return b < a ? b : a;
});
var southWest = {
lng: minLng,
lat: minLat
}
var northEast = {
lng: maxLng,
lat: maxLat
}
_this.blockDefaultParams.southWest = southWest;
_this.blockDefaultParams.northEast = northEast;
_this.$nextTick(function(){
_this.getBlock();
})
},
getNearestPoint :function (tp, lngLatInterval, max) {
var _this = this;
var nearestPoint = {};
//分别获得经纬度上栅格的数量
var xLengthVal = tp.lng / lngLatInterval[0];
var yLengthVal = tp.lat / lngLatInterval[1];
//对栅格数量进行取整
var xLength = '',
yLength = '';
if (max) {
xLength = parseInt(Math.ceil(xLengthVal));
yLength = parseInt(Math.ceil(yLengthVal));
}else{
xLength = parseInt(Math.floor(xLengthVal));
yLength = parseInt(Math.floor(yLengthVal));
}
//获得能够使栅格数量为整数的西南角和东北角的经纬度坐标
nearestPoint.lng = lngLatInterval[0] * xLength;
nearestPoint.lat = lngLatInterval[1] * yLength;
return nearestPoint;
},
//栅格尺寸大小转化为经纬度距离
distanceToLngLat : function (distance) {
var _this = this;
var values = new Array(2);
values[0] = distance * 0.00000978;
values[1] = distance * 0.00000899;
return values;
},
//渲染网格
getBlock:function(){
var _this = this;
var dp = _this.blockDefaultParams;
// 网格的格子大小
var blockSize = dp.dataBlockSize;
//将网格大小转换为经纬度上的距离
var lngLatInterval = _this.distanceToLngLat(blockSize);
//对西南角和东北角的经纬度进行处理,返回能够得到整数数量网格的西南角和东北角经纬度
var defaultSouthWest = _this.getNearestPoint(dp.southWest, lngLatInterval, false);
var defaultNorthEast = _this.getNearestPoint(dp.northEast, lngLatInterval, true);
//网格数量
var colLength = parseInt((defaultNorthEast.lng - defaultSouthWest.lng) / lngLatInterval[0]) ;
var rowLength = parseInt((defaultNorthEast.lat - defaultSouthWest.lat) / lngLatInterval[1]) ;
var data = [];//最终渲染的网格的数据
var blockData = _this.blockData;//接口返回的网格数组
//获得(0,0)到西南角的网格数量,作为网格的位置
var colStart = defaultSouthWest.lng / lngLatInterval[0];
var rowStart = defaultSouthWest.lat / lngLatInterval[1];
var polygons = _this.plateOverlays;
for (var col = 0; col < colLength; col++) {
for (var row = 0; row < rowLength; row++) {
//相当于网格id
var uCode = "col" + (col + colStart) + "-row" + (row + rowStart);
//遍历接口返回的数组,判断是否有匹配的网格
var block = null;
blockData.map(function(item){
if(item.blockId == uCode){
block = item;
}
})
//获得网格的中心点
var lng = defaultSouthWest.lng + col * lngLatInterval[0] + lngLatInterval[0] * 0.5;
var lat = defaultSouthWest.lat + row * lngLatInterval[1] + lngLatInterval[1] * 0.5;
var point = new BMap.Point(lng, lat);
//判断栅格的中心点是否在多边形覆盖物内
var inside = false;
if (polygons != null && polygons.length > 0) {
for (var i in polygons) {
var polygon = polygons[i];
if (BMapLib.GeoUtils.isPointInPolygon(point, polygon)) {
inside = true;
break;
}
}
}
var colorVal = -1;//colorValue用来判断是否要绘制,在多边形覆盖物区域内则绘制,在多边形覆盖物区域外则不绘制
var value = 0;//color是热力的值
if (inside) {
colorVal = 0;
if (block != null) {
value = block.val;
}
}
data.push({
value:[col, row,colorVal,value, uCode, point]
});
}
}
//渲染每个网格
function renderItem(params, api) {
var context = params.context;
var lngIndex = api.value(0);
var latIndex = api.value(1);
var pointLeftTop = getCoord(params, api, lngIndex, latIndex);
var pointRightBottom = getCoord(params, api, lngIndex + 1, latIndex + 1);
//如果是-1,即在区域外,则不绘制
var colorVal = api.value(2);
if (colorVal == -1) {
context = '';
lngIndex = '';
latIndex = '';
pointLeftTop = '';
pointRightBottom = '';
}
return {
type: 'rect',
shape: {
x: pointLeftTop[0],
y: pointLeftTop[1],
width: pointRightBottom[0] - pointLeftTop[0],
height: pointRightBottom[1] - pointLeftTop[1]
},
style: api.style({
stroke: 'rgba(73,208,180,0.9)',//网格的边线颜色
}),
styleEmphasis: api.styleEmphasis()
};
}
//经度和纬度方向
var lngExtent = [defaultSouthWest.lat, defaultNorthEast.lat];
var latExtent = [defaultSouthWest.lng, defaultNorthEast.lng];
var cellSizeCoord = [
lngLatInterval[0],
lngLatInterval[1]
];
function getCoord(params, api, lngIndex, latIndex) {
var coords = params.context.coords || (params.context.coords = []);
var key = lngIndex + '-' + latIndex;
return coords[key] || (coords[key] = api.coord([
+(latExtent[0] + lngIndex * cellSizeCoord[0]).toFixed(6),
+(lngExtent[0] + latIndex * cellSizeCoord[1]).toFixed(6)
]));
}
var option = {
visualMap:{
type: 'piecewise',
show: false,
pieces:[
{
min:35000,max:40000,color:'#435DFF',opacity:0.8
},
{
min:40000,color:'#503EFF',opacity:0.8
}
]
},
series:[
{
type: 'custom',
coordinateSystem: 'bmap',
renderItem: renderItem,
animation: false,
encode: {
tooltip: 2
},
data: data
}
]
}
_this.echartsModel.setOption(option);
}
}
这种实现方式,首先需要根据轮廓来绘制出一个矩形的全部栅格;然后再调用方法判断栅格是否在轮廓范围内,在则渲染,否则不渲染。这两步都非常耗时。
优化之后的方法:数据分析师那边算出需要渲染的栅格通过后台传到前端,返回什么渲染什么即可。(不再需要绘制全部的栅格和去判断是否在边界范围内,这些步骤交给数据分析师去做)
可以想象,由于知道了所渲染区域的最大最小经纬度,现在地图上有一个矩形,把它划分成一行行一列列;根据返回的栅格数据可以知道栅格的行和列,以此来排列渲染。
methdos:{
//渲染栅格
//需要的参数:所渲染区域的最大最小经纬度(数值类型)、所画栅格的经纬度大小(数值类型)、栅格数据(data=[[col,row,id,value],[col,row,id,value]])
renderGrid:function(result){
//所渲染区域的最大最小经纬度
var lngExtent = [result.city.minlat, result.city.maxlat];
var latExtent = [result.city.minlng, result.city.maxlng];
//所画栅格的经纬度大小
var cellSizeCoord = [
result.city.lnggap,
result.city.latgap
];
//栅格数据
var data = result.block;
//渲染每个网格
function renderItem(params, api) {
var context = params.context;
var lngIndex = api.value(0);
var latIndex = api.value(1);
var pointLeftTop = getCoord(params, api, lngIndex, latIndex);
var pointRightBottom = getCoord(params, api, lngIndex + 1, latIndex + 1);
return {
type: 'rect',
shape: {
x: pointLeftTop[0],
y: pointLeftTop[1],
width: pointRightBottom[0] - pointLeftTop[0],
height: pointRightBottom[1] - pointLeftTop[1]
},
style: api.style({
stroke: 'white',//网格的边线颜色
}),
styleEmphasis: api.styleEmphasis()
};
}
function getCoord(params, api, lngIndex, latIndex) {
var coords = params.context.coords || (params.context.coords = []);
var key = lngIndex + '-' + latIndex;
return coords[key] || (coords[key] = api.coord([
+(latExtent[0] + lngIndex * cellSizeCoord[0]).toFixed(6),
+(lngExtent[0] + latIndex * cellSizeCoord[1]).toFixed(6)
]));
}
var option = {
visualMap:{
type: 'piecewise',
show:false,
inRange: {
color: ["#FEEFAC", "#FEE199",'#FEC77F','#FEAD72','#FC8068','#EA5C5C','#D14D65','#A94A62'],
opacity: 0.8,
},
splitNumber:8,
min:0,
max:100
},
series:[
{
type: 'custom',
coordinateSystem: 'bmap',
renderItem: renderItem,
animation: false,
encode: {
tooltip: 2
},
data: data
}
]
}
this.echartsModel.setOption(option);
}
}