使用openlayers扩展插件ol-ext设置地图指定区域高亮

 

最近要实现一个从底图向上发光的功能,着实纠结了好久,起初像是使用polygon 颜色透明度来实现,但毕竟底图不亮,增加图层效果不理想呀

一、ui设计是这样

在这里插入图片描述

二、绘制面

为底图增加一个MultiPolygon来实现效果,

代码片段
    import {styleSwitch} from '@/components/common/set_style';
        
    mapInit(){
       this.mapObj = new Map({
              target: el,
              view: view
          });
     // 初始geoJson
     var vectorSource = new VectorSource({
         features: (new GeoJSON()).readFeatures(self.geojsonObject)
     });

     var vectorLayer = new VectorLayer({
         renderMode: "image",
         source:vectorSource,
         style:self.styleFunction,
         maxResolution: 2,
         zIndex:2
     });
      this.mapObj.addLayer(vectorLayer);
    },
    styleFunction(feature, resolution) {

        return styleSwitch(feature.getGeometry().getType(), resolution, feature)
    },

 

set_style.js
import {Fill, Stroke, Style, RegularShape, Text, Icon,Circle,} from 'ol/style';
    import { DEVICE_PIXEL_RATIO } from "ol/has";
    /**
     * 主要景区 polygon ,multipolygon, line , multiline 样式设置
     * 根据geojson类型设置地图样式
     * @param type
     * @param resolution
     * @param feature
     * @return {string}
     */
    export function styleSwitch(type, resolution, feature) {
        let canvas = document.createElement("canvas");
        let context = canvas.getContext("2d");
        // Generate a rainbow gradient
        let gradient = (() => {
            let grad = context.createLinearGradient(
                220*DEVICE_PIXEL_RATIO,20*DEVICE_PIXEL_RATIO,4220*DEVICE_PIXEL_RATIO,220*DEVICE_PIXEL_RATIO
            );
            // 设置开始结束颜色
            grad.addColorStop(0, "rgba(0,192,50,0.4)");
            grad.addColorStop(0.5, "rgba(0,192,50,0.2)");
            grad.addColorStop(1, "rgba(1,134,82,0.5)");
    
            return grad;
        })();
    
        var text = resolution < 0.0054931640625 ? feature.get('name') : '';    //根据分辨率控制文字显示级别
        let styleItem = [];
        switch (type) {
            case 'Point':
            case 'MultiPoint':
                styleItem = [
                    new Style({
                        image: new Icon({
                            src: 'images/left_module/police/police_topSmallIcon_second.png',
                            size: [24, 26],
                            color: '#ff0000'
                        }),
                        text: new Text({
                            offsetX: 14,
                            offsetY: 10,
                            font: '12px Calibri,sans-serif',
                            text: text,
                            fill: new Fill({
                                color: '#DC143C'
                            }),
                            stroke: new Stroke({
                                color: '#fff',
                                width: 3
                            })
                        })
                    })
                ]
                break;
            case 'MultiLineString':
            case 'LineString':
                styleItem = [
                    new Style({
                        stroke: new Stroke({
                            color: 'rgba(247,246,46, 0.2)',
                            lineDash: [5],
                            width: 8
                        })
                    }),
                    new Style({
                        stroke: new Stroke({
                            color: "rgba(247,246,46, 1)",
                            lineDash: [5],
                            width: 3
                        }),
                    })
                ]
                break;
            case  'Polygon':
            case 'MultiPolygon':
    
                styleItem = [
                    new Style({
                        // fill: new Fill({
                        //     color: gradient
                        // }),
                        stroke: new Stroke({
                            color: "rgba(255,255,255,0.1)",
                            width: 2
                        }),
                        zIndex: 0
                    }),
                    new Style({
                        stroke: new Stroke({
                            color: 'rgba(245,255,250, 0.2)',
                            lineCap: 'round',
                            lineJoin:'bevel',
                            width: 10
                        })
                    }),
                    new Style({
                        stroke: new Stroke({
                            color: "rgba(0,149,32,0.1)",
                            lineCap: 'round',
                            lineJoin:'bevel',
                            width: 2
                        })
                    }),
    
                    // new Style({
                    //     fill: new Fill({
                    //         color: [0,149,32, 0.8]
                    //     })
                    // }),
                ]
                break;
            case  'GeometryCollection':
                styleItem = [
                    new Style({
                        stroke: new Stroke({
                            color: 'magenta',
                            width: 2
                        }),
                        fill: new Fill({
                            color: 'magenta'
                        }),
                        image: new Icon({
                            src: 'images/left_module/police/police_topSmallIcon_second.png',
                            size: [24, 26],
                            color: '#ff0000'
                        }),
                        text: new Text({
                            font: '12px Calibri,sans-serif',
                            text: text,
                            fill: new Fill({
                                color: '#DC143C'
                            }),
                            stroke: new Stroke({
                                color: '#fff',
                                width: 3
                            })
                        })
                    })
                ]
                break;
            case 'Circle':
                styleItem = [
                    new Style({
                        stroke: new Stroke({
                            color: 'red',
                            width: 2
                        }),
                        fill: new Fill({
                            color: 'rgba(255,0,0,0.2)'
                        }),
                        image: new Icon({
                            src: 'images/left_module/police/police_topSmallIcon_second.png',
                            size: [24, 26],
                            color: '#ff0000'
                        }),
                        text: new Text({
                            font: '12px Calibri,sans-serif',
                            text: text,
                            fill: new Fill({
                                color: '#DC143C'
                            }),
                            stroke: new Stroke({
                                color: '#fff',
                                width: 3
                            })
                        })
                    })];
                break;
        }
    
        return styleItem;
    }

 

效果如下

在这里插入图片描述

三、使用.Render3D

后来想是否少了3D效果 ? 这又引用了ol-ext.layer.Render3D

效果如下

在这里插入图片描述

四、使用.Colorize

看还是相距胜远;于是想到了为底图增加透明色,于是引入了ol-ext.filter.Colorize,

效果如下

在这里插入图片描述
颜色是着上了,可是 看源码得知

    ol_filter_Colorize.prototype.postcompose = function(e) {
        // Set back color hue
        var ctx = e.context;
        var canvas = ctx.canvas;
    
        
        ctx.save();
            if (this.get('operation')=='enhance')
            {    var v = this.get('value');
                if (v)
                {    var w = canvas.width;
                    var h = canvas.height;
                    ctx.globalCompositeOperation = 'color-burn'
                    ctx.globalAlpha = v;
                    ctx.drawImage (canvas, 0, 0, w, h);
                    ctx.drawImage (canvas, 0, 0, w, h);
                    ctx.drawImage (canvas, 0, 0, w, h);
                }
            }
            else
            {    ctx.globalCompositeOperation = this.get('operation');
                ctx.fillStyle = this.get('color');
                ctx.fillRect(0,0,canvas.width,canvas.height);  
            }
        ctx.restore();
    }

 

五、 使用.Mask 加 .Crop

这直接是使用canvas绘制的一个面,很明显是方的了,最后想来想去想到使用ol-ext.filter.Colorize来为底图着色,再使用ol-ext.filter.Maskol-ext.filter.Crop来根据坐标绘制凸显的面同时为地图增加蒙层,但是又遇到了ol-ext.filter.Mask绘制的面和layerVector位置不合问题

预览效果是这样的
canvas绘制和layerVector绘制的面偏移较多
但地图缩放时更明显
但地图缩放时更明显
代码片段
    <script type="text/ecmascript-6">
        import 'ol/ol.css';
        import Map from 'ol/Map';
        import View from 'ol/View';
        import {XYZ, Vector as VectorSource} from 'ol/source';
        import {Fill} from 'ol/style';
        import Point from 'ol/geom/Point';
        import Feature from 'ol/Feature';
        import GeoJSON from 'ol/format/GeoJSON';
        import olExtColorize from 'ol-ext/filter/Colorize'
        import olExtCrop from 'ol-ext/filter/Crop'
        import olExtMask from 'ol-ext/filter/Mask'
        import MultiPolygon from 'ol/geom/MultiPolygon';
        
        export default = {
            methods:{
               mapInit(polygonCoordiantes) {
                    let self = this;
                    let proj = 'EPSG:4326';
                    let el = this.$refs.map;
                    let padLeft = (val, num, radix) => {
                        let str = val.toString(radix || 10);
                        return (new Array(num).join('0') + str).slice(-num);
                    }
                    var view = new View({
                        projection: proj,
                        center: [103.37324413479338, 29.544684360197113],
                        minZoom: 10,
                        zoom: 13,
                        maxZoom: 15,
                        extent: [102.1000671387,28.7086486816,104.7244262695,30.0448608398],
                    });

                     this.mapObj = new Map({
                           target: el,
                           view: view
                     });
                     
                    var leshan_tile = this.initLeshanTile(proj, padLeft);
        
                    this.mapObj.addLayer(leshan_tile);
                        // 點亮地圖
                    this.lingUpTheMap(leshan_tile);
        
                    this.drawPolygonAndAddMask(leshan_tile,polygonCoordiantes)
            },
           /**
            *
            * 乐山瓦片加载
            */
           initLeshanTile(proj, padLeft) {
               // 乐山 瓦片图层
               let layers_leshan = new TileLayer({
                   source: new XYZ({
                       crossOrigin: "anonymous",
                       projection: proj,
                       url: 'http://localhost:808/image_map/_alllayers/',
        
                       tileUrlFunction: function (tileCoord, pixelRatio, proj) {
                           var x = 'C' + padLeft(tileCoord[1], 8, 16);
                           var y = 'R' + padLeft(tileCoord[2] -1, 8, 16);
                           var z = 'L' + padLeft(tileCoord[0], 2, 10);
                           var Newurl = 'http://localhost:808/image_map/_alllayers/' + z + '/' + y + '/' + x + '.png';
                           return Newurl;
                       }
                   }),
                   visible: true
               });
        
               return layers_leshan;
           },
              /**
               *
               * 點亮地圖
               */
              lingUpTheMap(osm,){
                  // Enhance filter
                  var enhance = new olExtColorize({ operation:'enhance'});
                  osm.addFilter(enhance);
        
                  // Custom filter
                  var filter = new olExtColorize();
                  osm.addFilter(filter);
        
                  enhance.setActive(false);
                  filter.setActive(true);
                  filter.setFilter({
                      operation:'color',
                      red:Number('0'),
                      green: Number('192'), blue: Number('50'),
                      value: Number('1'),
                  });
              },
              /**
               * 绘制面,同时增加蒙层
               * @param osm {Object} tile 对象
               * @param coordinatesOfPolygon {Array[[]]} 面的坐标数据
               */
              drawPolygonAndAddMask(osm,coordinatesOfPolygon){
        
                  var f = new Feature(new MultiPolygon(coordinatesOfPolygon));
                  var crop = new olExtCrop({
                      feature: f,
                      inner: false
                  });
                  osm.addFilter(crop);
                  var mask = new olExtMask({
                      feature: f,
                      inner: false,
                      fill: new Fill({
                          color: [255, 255, 255, 0.8]
                      })
                  });
                  osm.addFilter(mask);
        
                  mask.set('inner',false);
                  crop.set('inner', false);
                  mask.fillColor_ = 'rgba(0,0,0,0.8)';
                  // Activate
                  mask.set('active', true);
                  crop.set('active', false);
              },
            }
            
        }
    </script>

 

六、处理canvas 绘制偏移问题

如上虽然实现了底图着色但是绘制的元素偏移这么多,这显然不是我想要的结果

后来测试了不知道多少遍,查了不知道多少资料没有一个是我要的答案!

最后没办法再次查看ol-ext.filter.Mask.js源码

一遍又一遍看其中重要 的drawFeaturePath_ 属性方法

/** Draw the feature into canvas */
    ol_filter_Mask.prototype.drawFeaturePath_ = function(e, out)
    {    var ctx = e.context;
        var canvas = ctx.canvas;
        var ratio = e.frameState.pixelRatio;
        // Transform
        var m = e.frameState.coordinateToPixelTransform;
        var tr = function(pt)
        {    return [
                (pt[0]*m[0]+pt[1]*m[1]+m[4])*ratio,
                (pt[0]*m[2]+pt[1]*m[3]+m[5])*ratio
            ];
        }
        // Old ol version
        if (!m)
        {    m = e.frameState.coordinateToPixelMatrix;
            tr = function(pt)
            {    return [
                    (pt[0]*m[0]+pt[1]*m[1]+m[12])*ratio,
                    (pt[0]*m[4]+pt[1]*m[5]+m[13])*ratio
                ];
            }
        }
        // Geometry
        var ll = this.feature_.getGeometry().getCoordinates();
        if (this.feature_.getGeometry().getType()=="Polygon") ll = [ll];
        ctx.beginPath();
            if (out)
            {    ctx.moveTo (0,0);
                ctx.lineTo (canvas.width, 0);
                ctx.lineTo (canvas.width, canvas.height);
                ctx.lineTo (0, canvas.height);
                ctx.lineTo (0, 0);
            }
            for (var l=0; l<ll.length; l++)
            {    var c = ll[l];
                for (var i=0; i<c.length; i++) 
                {    var pt = tr(c[i][0]);
                    ctx.moveTo (pt[0], pt[1]);
                    for (var j=1; j<c[i].length; j++) 
                    {    pt = tr(c[i][j]);
                        ctx.lineTo (pt[0], pt[1]);
                    }
                }
            }
    }

 

如下这句代码引起了我的注意

var ratio = e.frameState.pixelRatio;

  

查看API
在这里插入图片描述
大概意思是 帧的像素比率

这个方法明细是使用canvas 根据当前feature的坐标结合当前像素 帧 来绘制元素的, 然 帧的像素比率 会根据地图缩放而发生改变,所以绘制的面元素也随着像素变法不停发生偏移,最后想得到不根据帧的像素比率 来绘制元素他的位置不就对了吗!最后去掉 ratio;修噶代码为

    // Transform
    var m = e.frameState.coordinateToPixelTransform;
    var tr = function(pt)
    {    return [
            (pt[0]*m[0]+pt[1]*m[1]+m[4]),
            (pt[0]*m[2]+pt[1]*m[3]+m[5])
        ];
    }

 

再运行看效果

在这里插入图片描述

 

这次效果终于要好点了,但是还有待改进,毕竟离ui设计图还有一些距离,加油继续…

 

最后附上官网地址便于查阅

 

posted @ 2020-01-04 22:00  奔跑的痕迹  阅读(2186)  评论(0编辑  收藏  举报