概述

如下图,在手机里面有一个这样的功能,我称之为“相册地图”,本文讲述的是通过扩展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 imagevar context = this.hitDetectionCanvas_.getContext('2d');this.drawBack_(context,"#000",strokeWidth);context.fill();// Draw the imagecontext = canvas.getContext('2d');this.drawBack_(context,strokeStyle,strokeWidth);// Draw a shadowif (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 imageif (img.width) self.drawImage_(img);else img.onload = function(){    self.drawImage_(img);// Force change (?!)// self.setScale(1);if (self.onload_) self.onload_();};// Set anchorvar 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 canvasvar 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 vignetteif (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 sizeelse{  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 clipif (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,folioonload: 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

ol5里面实现相册地图相关推荐

  1. 使用Folium制作相册地图

    使用Folium制作相册地图 folium是JavaScript上著名的交互式地图库leaflet.js为Python提供的接口,通过它,我们可以在Python端调用leaflet的相关功能. lea ...

  2. 独立产品灵感周刊 DecoHack #019 - Stack Overflow 发布2022 年度开发者调查结果

    本周刊记录有趣好玩的独立产品设计开发相关内容,每周发布,感兴趣的伙伴可以点击订阅我的周刊.为保证每期都能收到建议邮件订阅.欢迎通过 Twitter 私信推荐或投稿. 产品推荐 1. Music For ...

  3. android 地图相册,时光地图相册

    时光地图相册app,一款相册管理软件,下载该软件,用户可以一键备份所有照片和视频,无损备份保存,再也不用担心丢失美好记忆:在管理照片的时候,系统会自动进行场景识别,提取照片中的店,从而为您自动创建相关 ...

  4. android 地图相册,时光地图相册app下载-时光地图相册下载v1.0.2 安卓版-西西软件下载...

    时光地图相册app好用的主题相册内容,为你使用多个主题进行分类,根据地理位置整理足迹相册,让你的旅行痕迹遍布全国,记录每一个精彩的城市故事,还能根据时间进行整理,让你的每一刻美好都在时间长河中慢慢流动 ...

  5. android 地图相册,android开发实现view转bitmap保存到手机相册

    android开发实现view转bitmap保存到手机相册 直接贴代码,可以根据代码自行测试 //view转bitmap: public void SaveBitmapFromView(View vi ...

  6. Android Studio第14课百度地图,获取相册和拍照

  7. Hexo Next 博客添加相册瀑布流

    原文:https://rebootcat.com/2020/09/19/nextphotowall/ 前言 一直没有时间来整理下博客搭建的一些事情,现在补上一篇,给 Hexo Next 博客添加一个相 ...

  8. 微信小程序(canvas)画图保存到本地相册(wepy)

    html标签部分 因为这个需要用户授权 所以需要使用button,画布使用的是canvas,这个可以参考小程序官方文档,代码如下 <button class='btn' type="d ...

  9. swift 中高德地图随时读取坐标地点的写法

    自己写的方法  不比比  自己能看懂就行   只用作自己学习swift的总结 import UIKit typealias block = (String,String) ->() class ...

最新文章

  1. node.js写一个json服务
  2. 《数据结构与算法》实验报告——二叉树的遍历
  3. redis 一般启动几个 哨兵_Redis6.0主从、哨兵、集群搭建和原理
  4. 姑娘,你为什么要编程?
  5. java中异常注意问题(发生在多态是的异常问题)
  6. Shell——基本运算符
  7. ProtoBuf3语法指南(Protocol Buffers)_下
  8. 不同域名指向一个Web站点,ICP证如何设置
  9. 热点争议:Web设计师需要编程知识吗?
  10. 仿ofo首页眼睛跟随加速器移动效果
  11. Spring Boot 项目启动的七种方式
  12. Spring Cloud Ribbon
  13. KY-RTI分布仿真技术:第八章 Visual C#程序设计
  14. Javascript笔记大全01,会持续更新~
  15. CTFSHOW web入门 命令执行+文件包含+PHP特性
  16. NR基础篇上——均值滤波、高斯滤波、双边滤波、NLM
  17. 歌曲光辉岁月和弦走向探究
  18. maven仓库中查找依赖的步骤
  19. 为什么有些30岁的程序员代码敲着敲着就创业了
  20. signature=60f8eeca8788f5db0f874e2b9c785ab7,SIGNATURE EXPLORATION UPDATES FRIO SANDS TARGET IN TEXAS.

热门文章

  1. 论文参考文献管理软件推荐
  2. Command line is too long. Shorten command line for className
  3. kali详细安装教程
  4. Android中dpi 和density到底是什么关系?
  5. Mysql修改常用sql: 添加字段、修改字段、添加索引
  6. 这一代的书香:宽容与活跃
  7. 数字图像处理 博客目录索引
  8. 失联已久的博主又回来啦,今天给大家安利一个打地鼠游戏吧。
  9. python求方程组近似解_使用python的sympy解符号方程组后,如何将结果带入之后的符号表达式...
  10. IDEA在当前类中查找方法快捷键