本文基于openlayers2现有api扩展html5的支持绘制10W+的四边形,当然样式简单死板,只为说明通过H5也
可以为ol带来不菲的性能(默认自带vector图层中添加feature超过2K+数据后就会出现卡顿)。
-- 2017-04-13 :GridLayer.Source天假bc属性为格子边框颜色,如果存在边框颜色则绘制边框
废话不多说直接上代码,
1、创建一个对象,标明每个待绘制元素的基本信息,目前主要包含左上和右下的经纬度还有待显示的颜色:
/**
* Class: GridLayer.Source
创建一个数据源的类型,一个格子中需要包含左上右下的经纬度还有要显示的颜色
*/
GridLayer = {};
/**
* Class: GridLayer.Source
*/
GridLayer.Source = OpenLayers.Class({
/**
* 左上经纬度
* {OpenLayers.LonLat} 左上经纬度
*/
l: null,
/**
* 栅格右下角经纬度
*/
r:null ,
/**
* 栅格显示颜色
*/
c:null ,
/**
* 边框显示颜色
*/
bc:null,
initialize: function(leftLonLat, rightLonLat ,color,boderColor ) {
this.l = leftLonLat;
this.r = rightLonLat;
this.c = color ;
this.bc = boderColor;
},
CLASS_NAME: 'GridLayer.Source'
});
/**
* Class: GridLayer.Layer
* 栅格图层
* Inherits from:
* -
*/
GridLayer.Layer = OpenLayers.Class(OpenLayers.Layer, {
/**
* Property: 所有的格点信息
* {Array(
*/
points: null,
/**
* Property: H5画布
* {DOMElement} Canvas element.
*/
canvas: null,
/**
* Constructor: GridLayer.Layer
* Create a GridLayer layer.
*
* Parameters:
* name - {String} Name of the Layer
* options - {Object} Hashtable of extra options to tag onto the layer
*/
initialize: function(name, options) {
OpenLayers.Layer.prototype.initialize.apply(this, arguments);
this.points = [];
this.canvas = document.createElement('canvas');
this.canvas.style.position = 'absolute';
// For some reason OpenLayers.Layer.setOpacity assumes there is
// an additional div between the layer's div and its contents.
var sub = document.createElement('div');
sub.appendChild(this.canvas);
this.div.appendChild(sub);
},
/**
* APIMethod: addSource
* 添加一个格子元素
*
* Parameters:
* source - {
*/
addSource: function(source) {
this.points.push(source);
},
/**
* 添加所有的数据源
*/
putSource: function(sources) {
this.points = sources ;
},
clear:function() {
this.points = [];
},
/**
* 删除一个格子元素
* Parameters:
* source - {
*/
removeSource: function(source) {
if (this.points && this.points.length) {
OpenLayers.Util.removeItem(this.points, source);
}
},
/**
* Method: moveTo
* 地图移动时候回重绘地图,主要方法
* Parameters:
* bounds - {
* zoomChanged - {Boolean}
* dragging - {Boolean}
*/
moveTo: function(bounds, zoomChanged, dragging) {
OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
if (dragging)
return;
//偏移
var someLoc = new OpenLayers.LonLat(0,0);
var offsetX = this.map.getViewPortPxFromLonLat(someLoc).x -
this.map.getLayerPxFromLonLat(someLoc).x;
var offsetY = this.map.getViewPortPxFromLonLat(someLoc).y -
this.map.getLayerPxFromLonLat(someLoc).y;
var w = this.map.getSize().w;
var h = this.map.getSize().h ;
this.canvas.width = w;
this.canvas.height = h;
var ctx = this.canvas.getContext('2d');
ctx.save(); // Workaround for a bug in Google Chrome
ctx.fillStyle = 'transparent';
ctx.fillRect(0, 0, w, h);
ctx.restore();
//得出当前画布的左上右下经纬度数据 对于超过这个界限的数据 当前画布忽略绘制
var left = new OpenLayers. Pixel(0,0);
var right = new OpenLayers. Pixel(w,h);
var leftlonlat = this.map.getLonLatFromPixel(left);
var rightlonlat = this.map.getLonLatFromPixel(right);
for (var i in this.points) {
var src = this.points[i];
//判断数据是否已经超越当前canvas 如果超越 直接跳过
if(src.r.lon < leftlonlat.lon || src.r.lat > leftlonlat.lat
|| src.l.lon > rightlonlat.lon || src.l < rightlonlat .lat) {
continue;
}
//坐标
var leftpos = this.map.getLayerPxFromLonLat(src.l);
var rightpos = this.map.getLayerPxFromLonLat(src.r);
if(leftpos == null || rightpos == null) continue ;
var minlon = leftpos.x ;
var maxlat = leftpos.y;
var maxlon = rightpos.x;
var minlat = rightpos.y;
var x = maxlon - minlon ;
var y = minlat - maxlat ;
//颜色
//判断是否为shuzi
ctx.fillStyle= src.c;
ctx.fillRect(minlon + offsetX ,maxlat + offsetY,x ,y );
ctx.fillStyle = 'transparent';
//判断是否有边框颜色,如果有则绘制边框
if(src.bc) {
//border
ctx.strokeStyle = src.bc ;
ctx.strokeRect(minlon + offsetX ,maxlat + offsetY,x ,y );
ctx.strokeStyle = 'transparent';
}
}
var dat = ctx.getImageData(0, 0, this.canvas.width, this.canvas.height);
ctx.putImageData(dat, 0, 0);
this.canvas.style.left = (-offsetX) + 'px';
this.canvas.style.top = (-offsetY) + 'px';
},
/**
* 图层extent
* Returns:
* {
*/
getDataExtent: function () {
var maxExtent = null;
if (this.points && (this.points.length > 0)) {
var maxExtent = new OpenLayers.Bounds();
for(var i = 0, len = this.points.length; i < len; ++i) {
var point = this.points[i];
maxExtent.extend(point.l);
}
}
return maxExtent;
},
CLASS_NAME: 'GridLayer.Layer'
});
3、 调用
调用的时候直接引用后提供带渲染的数据即可,例如:
var gridLayer = new GridLayer.Layer("grid");
var index = 0 ;
//循环经度
for(var i = 120 ; i<121.1 ; i+=0.002) {
var lon = i;
//循环纬度
for(var j = 30 ; j < 30.5 ; j+=0.002) {
var lat = j ;
var leftlonlat = new OpenLayers.LonLat(lon,lat);
//根据中心点偏移左上和右下
var rightlonlat = new OpenLayers.LonLat(lon + 0.001, lat - 0.001);
//坐标系
leftlonlat.transform(map.displayProjection, map.projection);
rightlonlat.transform(map.displayProjection, map.projection);
//一个datasource
var grid = new GridLayer.Source(leftlonlat, rightlonlat , '#FF0000' );
gridLayer.addSource(grid);
index++;
}
}
console.log('size : ' + index);
//设置图层透明度
gridLayer.setOpacity(0.5);
//加入map
map.addLayer(gridLayer);
4、 说明
实际使用中数据如果从后台查询过来的话可能加载不了这么大的数据量,另外实际业务中的应用一般比这个复杂,此次扩展主要针对应用简单的业务(和我们当前公司业务很类似,N多个经纬度直接打在地图上,按照规则渲染颜色)。
5、 实际效果如图: