• 使用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',
                                     3
                                })
                            })
                        })
                    ]
                    break;
                case 'MultiLineString':
                case 'LineString':
                    styleItem = [
                        new Style({
                            stroke: new Stroke({
                                color: 'rgba(247,246,46, 0.2)',
                                lineDash: [5],
                                 8
                            })
                        }),
                        new Style({
                            stroke: new Stroke({
                                color: "rgba(247,246,46, 1)",
                                lineDash: [5],
                                 3
                            }),
                        })
                    ]
                    break;
                case  'Polygon':
                case 'MultiPolygon':
        
                    styleItem = [
                        new Style({
                            // fill: new Fill({
                            //     color: gradient
                            // }),
                            stroke: new Stroke({
                                color: "rgba(255,255,255,0.1)",
                                 2
                            }),
                            zIndex: 0
                        }),
                        new Style({
                            stroke: new Stroke({
                                color: 'rgba(245,255,250, 0.2)',
                                lineCap: 'round',
                                lineJoin:'bevel',
                                 10
                            })
                        }),
                        new Style({
                            stroke: new Stroke({
                                color: "rgba(0,149,32,0.1)",
                                lineCap: 'round',
                                lineJoin:'bevel',
                                 2
                            })
                        }),
        
                        // new Style({
                        //     fill: new Fill({
                        //         color: [0,149,32, 0.8]
                        //     })
                        // }),
                    ]
                    break;
                case  'GeometryCollection':
                    styleItem = [
                        new Style({
                            stroke: new Stroke({
                                color: 'magenta',
                                 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',
                                     3
                                })
                            })
                        })
                    ]
                    break;
                case 'Circle':
                    styleItem = [
                        new Style({
                            stroke: new Stroke({
                                color: 'red',
                                 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',
                                     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设计图还有一些距离,加油继续…

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

  • 相关阅读:
    STL之vector
    bubble_sort(归并排序)
    just_sort
    单调队列(数列中长度不超过k的子序列和的最值)
    两数组中寻找两个数的某种关系
    删除一个数字之后数列gcd最大
    实现二叉树(search)
    简单的树(summary)
    H5页面,按钮点击效果(信用卡还款项目)
    vue路由相关知识收集
  • 原文地址:https://www.cnblogs.com/dengxiaoning/p/12168862.html
Copyright © 2020-2023  润新知