前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ol5里面实现相册地图

ol5里面实现相册地图

作者头像
牛老师讲GIS
发布2019-04-09 15:37:59
7280
发布2019-04-09 15:37:59
举报
文章被收录于专栏:跟牛老师一起学WEBGIS

概述

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

关键点

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

实现效果

实现

1、扩展ol.style.Photo
代码语言:javascript
复制
/**
 * @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、调用
代码语言:javascript
复制
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'
      })
    })
  })
}	

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019年03月23日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • 关键点
  • 实现效果
  • 实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档