Leaflet使用Canvas加载wms服务

503 阅读1分钟

这是我参与 8 月更文挑战的第 2 天,活动详情查看:8 月更文挑战

WMS 协议

实现思路

继承Leaflet自带的 L.Canvas

每次视图更新都发送 GetMap 获取图片,然后把图片渲染到canvas上面。

监听canvas上的click事件 , 触发 GetFeatureInfo 请求,获取该点的属性。

扩展 L.Canvas 图层

L.GridLayer.CanvasWmsLayer = L.Canvas.extend({

    initialize: function (url, options ) {
        
    },
    _onClick(e) {  //每次 click 发送 GetFeatureInfo 请求获得所在点的属性
        this.doGetFeatureInfo()
    },

    _update() {  //视图更新时会触发
        this.doGetMap() //发送 GetMap 请求获得新图像
    },

    doGetMap() {

    },

    doGetFeatureInfo(point) {

    },

    onAdd: function () {  
        L.DomEvent.on(canvas, 'click', this._onClick, this) //绑定 Click 事件
    },

});

发送 GetMap 请求

        L.GridLayer.CanvasWmsLayer = L.Canvas.extend({
            options: {
                padding: 0
            },
            initialize: function (url, options, projection) {
                let defaultWmsParams = {
                    service: 'WMS',
                    layers: '',
                    styles: '',
                    format: 'image/png',
                    transparent: false,
                    version: '1.1.1'
                }
                this._url = url;
                this.wmsParams = { ...defaultWmsParams, ...options };
                this.projection = projection || L.CRS.EPSG4326
            },

            onAdd: function () {
                L.Canvas.prototype.onAdd.call(this);
            },

            _update() {
                if (this._map._animatingZoom && this._bounds) { return; }
                L.Renderer.prototype._update.call(this);
                var b = this._bounds,
                    container = this._container,
                    size = b.getSize(),
                    m = L.Browser.retina ? 2 : 1;

                L.DomUtil.setPosition(container, b.min);

                container.width = m * size.x;
                container.height = m * size.y;
                container.style.width = size.x + 'px';
                container.style.height = size.y + 'px';
                this.doGetMap()
            },

            genRequestParame() {
                let map = this._map;
                let bounds = map.getBounds();
                let projection = this.projection;
                let size = map.getSize();

                let sw = bounds.getSouthWest();
                let ne = bounds.getNorthEast();
                let _sw = projection.project(sw);
                let _ne = projection.project(ne);
                let bbox = [_sw.x, _sw.y, _ne.x, _ne.y].join(",");

                let { version } = this.wmsParams
                return ({
                    ...this.wmsParams,
                    bbox,
                    width: size.x,
                    height: size.y,
                    [version === '1.3.0' ? 'crs' : 'srs']: this.projection.code
                })
            },

            doGetMap() {

                let obj = {
                    request: 'GetMap',
                    ...this.genRequestParame()
                }

                let url = this._buildImageURL(obj)

                if(this.image){  //取消未成功发送的请求
                    this.image.src= ''
                }

                let ctx = this._ctx;

                let image = new Image();
                image.crossOrigin = "anonymous";
                image.onload = function () {
                    ctx.drawImage(image, 0, 0, image.width, image.height);
                    this.image = null
                };
                image.src = url;

                this.image = image
            },


            _buildImageURL(params) {
                let version = params.version || '1.1.1'
                const baseParams = this.wmsParams
                const opt = {
                    ...baseParams, ...params
                }
                let url = this._url + L.Util.getParamString(params);
                return url;
            }

        });

demo-1 发送GetMap

发送 GetFeatureInfo 请求

        L.GridLayer.CanvasWmsLayer = L.Canvas.extend({
            _onClick(e) {
                //console.log('_onClick')

                clearTimeout(timer)
                timer = setTimeout(()=>{
                    let point = this._map.mouseEventToLayerPoint(e);
                    this.doGetFeatureInfo(point)
                },300)

            },

            _identify(e) {
                this.doGetFeatureInfo(e)
            },



            genRequestParame() {
                let map = this._map;
                let bounds = map.getBounds();
                let projection = this.projection;
                let size = map.getSize();

                let sw = bounds.getSouthWest();
                let ne = bounds.getNorthEast();
                let _sw = projection.project(sw);
                let _ne = projection.project(ne);
                let bbox = [_sw.x, _sw.y, _ne.x, _ne.y].join(",");

                let { version } = this.wmsParams
                return ({
                    ...this.wmsParams,
                    bbox,
                    width: size.x,
                    height: size.y,

                    [version === '1.3.0' ? 'crs' : 'srs']: this.projection.code
                })
            },



            doGetFeatureInfo(point) {

                let { version } = this.wmsParams
                let obj = {
                    request: 'GetFeatureInfo',
                    query_layers: this.wmsParams.layers,
                    info_format: 'application/json',


                    ...this.genRequestParame(),
                    [version === '1.3.0' ? 'i' : 'x']: point.x,
                    [version === '1.3.0' ? 'j' : 'y']: point.y,
                }
                let url = this._buildImageURL(obj)


                const p = this.sendGet(url);

                p.then((text)=>{

                    const json = JSON.parse(text);
                    console.log(json)
                })
            },


            sendGet(url) {

                return new Promise((resolve, reject) => {

                    var xhr = new XMLHttpRequest();
                    xhr.onreadystatechange = function () {
                        if (xhr.readyState == 4   ) {

                            if(xhr.status == 200){
                            //获取服务器响应
                                let innerHTML = xhr.responseText;
                                resolve(innerHTML)
                                return
                            }
                            reject()
                        }
                    };

                    //发送异步请求
                    xhr.open("GET", url, true);
                    //发送请求
                    xhr.send();
                })
            },

            _buildImageURL(params) {
                let version = params.version || '1.1.1'
                const baseParams = this.wmsParams
                const opt = {
                    ...baseParams, ...params
                }
                let url = this._url + L.Util.getParamString(params);
                return url;
            },
            onAdd: function () {
                L.Canvas.prototype.onAdd.call(this);
                const canvas = this._ctx.canvas;

                L.DomEvent.on(canvas, 'click', this._onClick, this)


            },

        });

demo-2 发送 GetFeatureInfo