本文不讲技术,不撸代码,只讲思路。
在Openlayers中展示风速风向图,共分为以下两个阶段:
加载PNG图片→加载SVG图片
问题 在Openlayer3中直接加载PNG图片,在API中提供了ImageStatic可以将图片展示出来,但是如何设置图片的imageExtent让图片能够在地图的正确位置展示成了问题的关键。
解决 首先,看到官方的demo里面有个加载ImageStatic的例子,于是就看了一下,官方的例子是通过proj定义了图片的坐标,这样通过坐标转换的方式将静态图片叠加到了地图上。(此过程,我的理解遥感里面做影像的纠正的原理类似。)
有了上面代码的思路,我就想如果我的输出的图片是按照地图的坐标输出的话是不是就可以直接叠加上去而不用做图片的投影了。接下来,就在Arcmap里面打开了一个tif数据,将其直接通过Export Data导出为PNG,并查看其属性获取到图象的四至。
再在代码里面根据输出的PNG和四至信息做测试,哎,思路是对的,能够完美的叠加到地图上。
实现代码
var bounds = [63.9796331669,14.7451916725, 140.181255914,55.4673388687];
var projection = new ol.proj.Projection({
code: 'EPSG:4326',
units: 'degrees'
});
var image = new ol.layer.Image({
source: new ol.source.ImageStatic({
url: "img/china.png",
imageExtent: bounds
})
});
有了上面的测试,终于明白了OL3中StaticImage的加载逻辑。
由于是PNG图片,在地图放大后会有马赛克现象,特别影像视觉效果,所以为了让展示的效果更加美观,所以就考虑将PNG图片换乘SVG图片。换完之后,首先是在Leaflet中做的测试,比PNG的效果好很多。可当我将SVGyizhi到Openlayers中的时候傻眼了,效果如下:
这个不是臣妾想要的,我想要高清,不要模糊!!!
所以,就开始了研究如何展示SVG。百度、谷歌、必应了一圈后,发现Openlayers的开发者给大家的回复是OL3的版本没法加载SVG!WHAT???没法加载,这不是逗我呢??不过呢,我想这个问题我一定可以解决的!!
后来一直在思考这个问题,有一天突然灵光一现:我可以在地图上面那直接叠加一层SVG的,类似于曾经做过的OL3和echat的结合的逻辑,再绑定地图的事件刷新不就OK了,没错,就是这个思路,哦,此时觉的我就是个天才!
可是当我写好代码,运行代码的时候,发现地图动不了了?怎么办???怎么办???可不能这样啊!!!还好我机智,瞄了一眼OL4的源码,发现地图的时间是在Map这个div上面触发的,所以我就想到了把这个img放到map div里面,代码如下:
self.image = new Image();
self.image.src = self._url;
self._map.getViewport().appendChild(self.image);
再测试,哈哈,妥了,再加点地图事件,就搞定了!此刻深深的被我的聪明才智折服。
但是,我就是这样一个perfect的人,为了更加好用所以我将此扩展成了一个类,源码如下:
/**
* @author lzugis
* 2017-10-20
* @param option, 默认参数如下
{
map:null,
extent:[],
url:"",
opacity:1,
visible:true
}
*/
ol.layer.SvgImageLayer = function(option){
this._option = {
map:null,
extent:[],
url:"",
opacity:1,
visible:true
};
this._init(option);
};
ol.layer.SvgImageLayer.prototype = {
image:null,
_init:function(option){
//将option合并
for(var opt in option){
this._option[opt] = option[opt];
}
this._map = this._option.map;
this._extent = this._option.extent;
this._url = this._option.url;
this._opacity = this._option.opacity;
this._visible = this._option.visible;
},
addToMap:function(){
if(this._map) {
var self = this;
self.image = new Image();
self.image.src = self._url;
self._map.getViewport().appendChild(self.image);
self._updateImgStyle();
self._addMapEvent();
}
else{
alert("map参数定义不正确!");
}
},
updateImage: function(option){
this._init(option);
if(option.url)this.image.src = this._url;
this._updateImgStyle();
},
hide: function(){
this.image.style.display = "none";
},
show: function(){
this.image.style.display = "";
},
destroy: function(){
this.image.remove();
},
_updateImgStyle: function(){
var self = this;
var _min = [self._extent[0], self._extent[1]],
_max = [self._extent[2], self._extent[3]],
_topLeft = [self._extent[0], self._extent[3]];
var _scrMin = self._toScreenPoint(_min),
_scrMax = self._toScreenPoint(_max),
_scrTopLeft = self._toScreenPoint(_topLeft);
var _w = Math.round(_scrMax[0] - _scrMin[0]),
_h = Math.round(_scrMin[1] - _scrMax[1]),
_left = _scrTopLeft[0],
_top = _scrTopLeft[1];
var cssText = "";
var styles = {
"opacity": self._opacity,
"z-index": 0,
"position":"absolute",
"width":_w+"px",
"height":_h+"px",
"top":_top+"px",
"left":_left+"px"
};
for(var style in styles){
cssText+=style+":"+styles[style]+";"
}
self.image.style.cssText = cssText;
self._visible?self.show():self.hide();
},
_addMapEvent:function(){
var self = this;
self._map.on("precompose",function(evt){
evt.stopPropagation();
self._updateImgStyle();
});
},
_toScreenPoint: function(mapPoint){
var srcPoint = this._map.getPixelFromCoordinate(mapPoint);
return srcPoint;
}
};
ol.inherits(ol.layer.SvgImageLayer, ol.layer.base);
实现后,效果如下,心理满满的成就感。。。
正当我沉溺在满满的成就感的时候,有一天,突然发现,我的WMS图层怎么被盖住了???Oh, NO!!!!Kill me!!OL4中map所有的图层都是绘制在一个canvas画布里面的,我叠上去一个图层势必会挡住的,肿么办?what can I do for you??不行,我不能坐以待毙,要是让客户发现这个问题就惨了,客户是我们的衣食父母,这个时候就必须体现我们的专业性和我的钻研性了。
于是乎,上git,扒源码,看了好一阵,都没找到头绪,怎么办,我可不是就此放手的人。恩,先看看API再说,突然,看到了imageSize,凭我的直觉,他应该就是我要找的,这个时候就又不得不发挥我的主观能动性了,计算了一个大小就贴上去,wonderful!!!
附上源码如下:
var bounds = [12836027.844390793, 4745190.4650304755, 13098185.245208949, 5069741.1276835548];
var source = new ol.source.ImageStatic({
url: "bjoutput/wind.svg",
imageExtent: bounds,
imageSize:getImageSize(bounds)
});
image.setSource(source);
//获取图片大小
function getImageSize(bounds){
var _min = [bounds[0], bounds[1]],
_max = [bounds[2], bounds[3]],
_topLeft = [bounds[0], bounds[3]];
var _scrMin = map.getPixelFromCoordinate(_min),
_scrMax = map.getPixelFromCoordinate(_max);
var _w = Math.round(_scrMax[0] - _scrMin[0]),
_h = Math.round(_scrMin[1] - _scrMax[1]);
return [_w, _h];
}
写此篇的目的是为了告诉大家姿势的正确解锁方式,要善于思考,勤于动手,问题才会解决。