美文网首页GIS加油站
ol5里面实现相册地图

ol5里面实现相册地图

作者: 牛老师讲webgis | 来源:发表于2019-03-23 10:55 被阅读5次

    概述

    如下图,在手机里面有一个这样的功能,我称之为“相册地图”,本文讲述的是通过扩展ol.style的类,来实现“相册地图”这个功能。


    相册地图

    关键点

    要实现这个功能有两个关键点:1、地图聚合;2、图片样式。有关地图聚类的在很早之前的文章里面已经涉及到过,所以本文重点讲述图片样式。

    实现效果

    相册地图 选中后放大

    实现

    1、扩展ol.style.Photo
    /**
     * @classdesc
     * Set Photo style for vector features.
     *
     * @constructor
     * @param {} options
     *  @param { default | square | round | anchored | folio } options.kind
     *  @param {boolean} options.crop crop within square, default is false
     *  @param {Number} options.radius symbol size
     *  @param {boolean} options.shadow drop a shadow
     *  @param {ol.style.Stroke} options.stroke
     *  @param {String} options.src image src
     *  @param {String} options.crossOrigin The crossOrigin attribute for loaded images. Note that you must provide a crossOrigin value if you want to access pixel data with the Canvas renderer.
     *  @param {Number} options.offsetX Horizontal offset in pixels. Default is 0.
     *  @param {Number} options.offsetY Vertical offset in pixels. Default is 0.
     *  @param {function} options.onload callback when image is loaded (to redraw the layer)
     * @extends {ol.style.RegularShape}
     * @implements {ol.structs.IHasChecksum}
     * @api
     */
    ol.style.Photo = function(options)
    {   options = options || {};
      this.sanchor_ = options.kind=="anchored" ? 8:0;
      this.shadow_ = Number(options.shadow) || 0;
      if (!options.stroke)
      { options.stroke = new ol.style.Stroke({ width: 0, color: "#000"})
      }
      var strokeWidth = options.stroke.getWidth();
      if (strokeWidth<0) strokeWidth = 0;
      if (options.kind=='folio') strokeWidth += 6;
      options.stroke.setWidth(strokeWidth);
      ol.style.RegularShape.call (this,
        {   radius: options.radius + strokeWidth + this.sanchor_/2 + this.shadow_/2,
          points:0
          //    fill:new ol.style.Fill({color:"red"}) // No fill to create a hit detection Image
        });
      // Hack to get the hit detection Image (no API exported)
      if (!this.hitDetectionCanvas_)
      { var img = this.getImage();
        for (var i in this)
        {   if (this[i] && this[i].getContext && this[i]!==img)
        {   this.hitDetectionCanvas_ = this[i];
          break;
        }
        }
      }
    
      this.stroke_ = options.stroke;
      this.fill_ = options.fill;
      this.crop_ = options.crop;
      this.crossOrigin_ = options.crossOrigin;
      this.kind_ = options.kind || "default";
    
      this.radius_ = options.radius;
      this.src_ = options.src;
    
      this.offset_ = [options.offsetX ? options.offsetX :0, options.offsetY ? options.offsetY :0];
    
      this.onload_ = options.onload;
    
      if (typeof(options.opacity)=='number') this.setOpacity(options.opacity);
      if (typeof(options.rotation)=='number') this.setRotation(options.rotation);
      this.renderPhoto_();
    };
    ol.inherits(ol.style.Photo, ol.style.RegularShape);
    
    
    /**
     * Clones the style.
     * @return {ol.style.Photo}
     */
    ol.style.Photo.prototype.clone = function()
    {   return new ol.style.Photo(
      { stroke: this.stroke_,
        fill: this.fill_,
        shadow: this.shadow_,
        crop: this.crop_,
        crossOrigin: this.crossOrigin_,
        kind: this.kind_,
        radius: this.radius_,
        src: this.src_,
        offsetX: this.offset_[0],
        offsetY: this.offset_[1],
        opacity: this.getOpacity(),
        rotation: this.getRotation()
      });
    };
    
    /**
     * Draws a rounded rectangle using the current state of the canvas.
     * Draw a rectangle if the radius is null.
     * @param {Number} x The top left x coordinate
     * @param {Number} y The top left y coordinate
     * @param {Number} width The width of the rectangle
     * @param {Number} height The height of the rectangle
     * @param {Number} radius The corner radius.
     */
    CanvasRenderingContext2D.prototype.roundRect = function (x, y, w, h, r)
    {   if (!r) this.rect(x,y,w,h);
    else
    {   if (w < 2 * r) r = w / 2;
      if (h < 2 * r) r = h / 2;
      this.beginPath();
      this.moveTo(x+r, y);
      this.arcTo(x+w, y, x+w, y+h, r);
      this.arcTo(x+w, y+h, x, y+h, r);
      this.arcTo(x, y+h, x, y, r);
      this.arcTo(x, y, x+w, y, r);
      this.closePath();
    }
      return this;
    }
    
    
    /**
     * Draw the form without the image
     * @private
     */
    ol.style.Photo.prototype.drawBack_ = function(context, color, strokeWidth)
    {   var canvas = context.canvas;
      context.beginPath();
      context.fillStyle = color;
      context.clearRect(0, 0, canvas.width, canvas.height);
      switch (this.kind_)
      { case 'square':
        context.rect(0,0,canvas.width-this.shadow_, canvas.height-this.shadow_);
        break;
        case 'circle':
          context.arc(this.radius_+strokeWidth, this.radius_+strokeWidth, this.radius_+strokeWidth, 0, 2 * Math.PI, false);
          break;
        case 'folio':
          var offset = 6;
          strokeWidth -= offset;
          context.strokeStyle = 'rgba(0,0,0,0.5)';
          var w = canvas.width-this.shadow_-2*offset;
          var a = Math.atan(6/w);
          context.save();
          context.rotate(-a);
          context.translate(-6,2);
          context.beginPath();
          context.rect(offset,offset,w,w);
          context.stroke();
          context.fill();
          context.restore();
          context.save();
          context.translate(6,-1);
          context.rotate(a);
          context.beginPath();
          context.rect(offset,offset,w,w);
          context.stroke();
          context.fill();
          context.restore();
          context.beginPath();
          context.rect(offset,offset,w,w);
          context.stroke();
          break;
        case 'anchored':
          context.roundRect(this.sanchor_/2,0,canvas.width-this.sanchor_-this.shadow_, canvas.height-this.sanchor_-this.shadow_, strokeWidth);
          context.moveTo(canvas.width/2-this.sanchor_-this.shadow_/2,canvas.height-this.sanchor_-this.shadow_);
          context.lineTo(canvas.width/2+this.sanchor_-this.shadow_/2,canvas.height-this.sanchor_-this.shadow_);
          context.lineTo(canvas.width/2-this.shadow_/2,canvas.height-this.shadow_);break;
        default: /* roundrect */
          context.roundRect(0,0,canvas.width-this.shadow_, canvas.height-this.shadow_, strokeWidth);
          break;
      }
      context.closePath();
    }
    
    
    /**
     * @private
     */
    ol.style.Photo.prototype.renderPhoto_ = function()
    {
      var strokeStyle;
      var strokeWidth = 0;
      if (this.stroke_)
      { strokeStyle = ol.color.asString(this.stroke_.getColor());
        strokeWidth = this.stroke_.getWidth();
      }
      var canvas = this.getImage();
    
      // Draw hitdetection image
      var context = this.hitDetectionCanvas_.getContext('2d');
      this.drawBack_(context,"#000",strokeWidth);
      context.fill();
    
      // Draw the image
      context = canvas.getContext('2d');
      this.drawBack_(context,strokeStyle,strokeWidth);
    
      // Draw a shadow
      if (this.shadow_)
      { context.shadowColor = 'rgba(0,0,0,0.5)';
        context.shadowBlur = this.shadow_/2;
        context.shadowOffsetX = this.shadow_/2;
        context.shadowOffsetY = this.shadow_/2;
      }
      context.fill();
      context.shadowColor = 'transparent';
    
      var self = this;
      var img = this.img_ = new Image();
      if (this.crossOrigin_) img.crossOrigin = this.crossOrigin_;
      img.src = this.src_;
    
      // Draw image
      if (img.width) self.drawImage_(img);
      else img.onload = function()
      { self.drawImage_(img);
        // Force change (?!)
        // self.setScale(1);
        if (self.onload_) self.onload_();
      };
    
      // Set anchor
      var a = this.getAnchor();
      a[0] = (canvas.width - this.shadow_)/2;
      a[1] = (canvas.height - this.shadow_)/2;
      if (this.sanchor_)
      { a[1] = canvas.height - this.shadow_;
      }
    }
    
    /**
     * Draw an timage when loaded
     * @private
     */
    ol.style.Photo.prototype.drawImage_ = function(img)
    {   var canvas = this.getImage();
      // Remove the circle on the canvas
      var context = (canvas.getContext('2d'));
    
      var strokeWidth = 0;
      if (this.stroke_) strokeWidth = this.stroke_.getWidth();
      var size = 2*this.radius_;
    
      context.save();
      if (this.kind_=='circle')
      { context.beginPath();
        context.arc(this.radius_+strokeWidth, this.radius_+strokeWidth, this.radius_, 0, 2 * Math.PI, false);
        context.clip();
      }
      var s, x, y, w, h, sx, sy, sw, sh;
      // Crop the image to a square vignette
      if (this.crop_)
      { s = Math.min (img.width/size, img.height/size);
        sw = sh = s*size;
        sx = (img.width-sw)/2;
        sy = (img.height-sh)/2;
    
        x = y = 0;
        w = h = size+1;
      }
      // Fit the image to the size
      else
      { s = Math.min (size/img.width, size/img.height);
        sx = sy = 0;
        sw = img.width;
        sh = img.height;
    
        w = s*sw;
        h = s*sh;
        x = (size-w)/2;
        y = (size-h)/2;
      }
      x += strokeWidth + this.sanchor_/2;
      y += strokeWidth;
    
      context.drawImage(img, sx, sy, sw, sh, x, y, w, h);
      context.restore();
    
      // Draw a circle to avoid aliasing on clip
      if (this.kind_=='circle' && strokeWidth)
      { context.beginPath();
        context.strokeStyle = ol.color.asString(this.stroke_.getColor());
        context.lineWidth = strokeWidth/4;
        context.arc(this.radius_+strokeWidth, this.radius_+strokeWidth, this.radius_, 0, 2 * Math.PI, false);
        context.stroke();
      }
    }
    
    
    /**
     * @inheritDoc
     */
    ol.style.Photo.prototype.getChecksum = function()
    {
      var strokeChecksum = (this.stroke_!==null) ?
        this.stroke_.getChecksum() : '-';
      var fillChecksum = (this.fill_!==null) ?
        this.fill_.getChecksum() : '-';
    
      var recalculate = (this.checksums_===null) ||
        (strokeChecksum != this.checksums_[1] ||
          fillChecksum != this.checksums_[2] ||
          this.radius_ != this.checksums_[3]);
    
      if (recalculate) {
        var checksum = 'c' + strokeChecksum + fillChecksum
          + ((this.radius_ !== void 0) ? this.radius_.toString() : '-');
        this.checksums_ = [checksum, strokeChecksum, fillChecksum, this.radius_];
      }
    
      return this.checksums_[0];
    };
    

    做扩展的目的主要是为了以后少写几行代码,其实原生的方式也是可以实现该效果的。

    2、调用
    var vectorSource = new ol.source.Vector({
      url:"data/capital.geojson",
      format: new ol.format.GeoJSON()
    });
    var vector = new ol.layer.Vector({
      source: vectorSource,
      style: styleFunc
    });
    map.addLayer(vector);
    
    var id = 0;
    map.on("pointermove", function (e) {
      if(map.hasFeatureAtPixel(e.pixel)){
        map.getTargetElement().style.cursor = 'pointer';
      } else {
        map.getTargetElement().style.cursor = 'default';
      }
    });
    map.on("click", function (e) {
      if(map.hasFeatureAtPixel(e.pixel)){
        var features = map.getFeaturesAtPixel(e.pixel);
        var img = features[0].get('img');
        document.getElementById('photo').setAttribute('src', img);
        id = features[0].get('id');
        vector.setStyle(styleFunc);
      }
    });
    function styleFunc (feature){
      // var src = 'http://img18.3lian.com/d/file/201712/20/414dc24ceba7436ac6895d9e413ed2cc.png';
      var src = feature.get("img");
      return new ol.style.Style ({
        image: new ol.style.Photo({
          src: src,
          radius: 25,
          shadow: 2,
          kind: 'anchored', //default,square,circle,anchored,folio
          onload: function() { vector.changed(); },
          stroke: new ol.style.Stroke({
            width: 3,
            color: id ===feature.get('id') ? '#ffbcc8' : '#ffffff'
          })
        })
      })
    }   
    

    技术博客
    CSDN:http://blog.csdn.NET/gisshixisheng
    在线教程
    https://edu.csdn.net/course/detail/799
    https://edu.csdn.net/course/detail/7471
    联系方式

    类型 内容
    qq 1004740957
    公众号 lzugis15
    e-mail niujp08@qq.com
    webgis群 452117357
    Android群 337469080
    GIS数据可视化群 458292378
    LZUGIS

    相关文章

      网友评论

        本文标题:ol5里面实现相册地图

        本文链接:https://www.haomeiwen.com/subject/iuijvqtx.html