當我們遇到問題的時候改如何解決

本文不講技術,不擼代碼,只講思路。

一、問題

在Openlayers中展示風速風向圖,共分爲以下兩個階段:

加載PNG圖片→加載SVG圖片

二、解決

1、加載PNG圖片

問題 在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的加載邏輯。

2、加載SVG圖片

由於是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];
}

三、總結

寫此篇的目的是爲了告訴大家姿勢的正確解鎖方式,要善於思考,勤於動手,問題纔會解決。


山重水複疑無路,柳暗花明又一村
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章