OpenLayers学习笔记(八)— 类似比例尺的距离环(二)
openlayers 3 地图上创建一个距离环,始终以地图中心为中心,每个环之间的距离类似比例尺,随地图缩放而变化。
添加具有覆盖整个范围的特征的虚拟层,其可以被设置为围绕地图中心的环。
这篇是上一篇距离环文章的拓展和完善
GitHub:八至
作者:狐狸家的鱼
这是模仿openlayers插件库ol-ext新出的canvas距离环功能,简直雪中送炭。
代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>距离环</title> <link rel="stylesheet" href="css/ol.css" type="text/css"> <script src="build/jquery.js"></script> <script src="build/ol.js"></script> <style> html, body { height: 100%; width: 100%; padding: 0px; margin: 0px; } .map { height: 100%; width: 100%; } </style> </head> <body> <div id="map"></div> <script> var map = new ol.Map({ layers: [ new ol.layer.Tile({ source: new ol.source.OSM(), }) ], target: 'map', view: new ol.View() }); ol.control.CanvasScaleLine = function(options) { ol.control.ScaleLine.call(this, options); this.scaleHeight_ = 6; // Get style options if (!options) options={}; if (!options.style) options.style = new ol.style.Style(); this.setStyle(options.style); } ol.inherits(ol.control.CanvasScaleLine, ol.control.ScaleLine); ol.control.CanvasScaleLine.prototype.setMap = function (map) { var oldmap = this.getMap(); if (this._listener) ol.Observable.unByKey(this._listener); this._listener = null; ol.control.ScaleLine.prototype.setMap.call(this, map); if (oldmap) oldmap.renderSync(); // Add postcompose on the map if (map) { this._listener = map.on('postcompose', this.drawScale_.bind(this)); } // Hide the default DOM element this.element.style.visibility = 'hidden'; this.olscale = this.element.querySelector(".ol-scale-line-inner"); } ol.control.CanvasScaleLine.prototype.setStyle = function (style) { var stroke = style.getStroke(); this.strokeStyle_ = stroke ? ol.color.asString(stroke.getColor()) : "#000"; this.strokeWidth_ = stroke ? stroke.getWidth() : 2; var fill = style.getFill(); this.fillStyle_ = fill ? ol.color.asString(fill.getColor()) : "#fff"; var text = style.getText(); this.font_ = text ? text.getFont() : "10px Arial"; stroke = text ? text.getStroke() : null; fill = text ? text.getFill() : null; this.fontStrokeStyle_ = stroke ? ol.color.asString(stroke.getColor()) : this.fillStyle_; this.fontStrokeWidth_ = stroke ? stroke.getWidth() : 3; this.fontFillStyle_ = fill ? ol.color.asString(fill.getColor()) : this.strokeStyle_; // refresh if (this.getMap()) this.getMap().render(); } ol.control.CanvasScaleLine.prototype.drawScale_ = function(e) { if ( this.element.style.visibility!=="hidden" ) return; var ctx = e.context; // Get size of the scale div var scalewidth = parseInt(this.olscale.style.width); if (!scalewidth) return; var text = this.olscale.textContent; var position = {left: this.element.offsetLeft, top: this.element.offsetTop}; // Retina device var ratio = e.frameState.pixelRatio; ctx.save(); ctx.scale(ratio,ratio); // Position if transform:scale() var container = this.getMap().getTargetElement(); var scx = container.offsetWidth / container.getBoundingClientRect().width; var scy = container.offsetHeight / container.getBoundingClientRect().height; position.left *= scx; position.top *= scy; // On top position.top += this.element.clientHeight - this.scaleHeight_; // Draw scale text ctx.beginPath(); ctx.strokeStyle = this.fontStrokeStyle_; ctx.fillStyle = this.fontFillStyle_; ctx.lineWidth = this.fontStrokeWidth_; ctx.textAlign = "center"; ctx.textBaseline ="bottom"; ctx.font = this.font_; ctx.strokeText(text, position.left+scalewidth/2, position.top); ctx.fillText(text, position.left+scalewidth/2, position.top); ctx.closePath(); // Draw scale bar position.top += 2; ctx.lineWidth = this.strokeWidth_; ctx.strokeStyle = this.strokeStyle_; var max = 4; var n = parseInt(text); while (n%10 === 0) n/=10; if (n%5 === 0) max = 5; for (var i=0; i<max; i++) { ctx.beginPath(); ctx.fillStyle = i%2 ? this.fillStyle_ : this.strokeStyle_; ctx.rect(position.left+i*scalewidth/max, position.top, scalewidth/max, this.scaleHeight_); ctx.stroke(); ctx.fill(); ctx.closePath(); } // Calculate and draw rings corresponding to scale line var map = this.getMap(); var proj = map.getView().getProjection(); var center = ol.proj.transform(map.getView().getCenter(), proj, 'EPSG:4326'); var sphere = ol.Sphere ? new ol.Sphere(6371008.8) : undefined; var t = text.split(' '); var multiplier = t[0]/max; switch (t[1]) { case 'km': multiplier *= 1000; break; case 'm': multiplier *= 1; break; case 'mm': multiplier *= 0.001; break; default: } for (var i=0; i<max; i++) { var geometry = sphere ? ol.geom.Polygon.circular(sphere, center, (i+1)*multiplier, 128).transform('EPSG:4326', proj) : ol.geom.Polygon.circular(center, (i+1)*multiplier, 128).transform('EPSG:4326', proj); var coordinates = geometry.getCoordinates()[0]; var pixels = []; var top = [0, Infinity]; coordinates.forEach( function(coordinate) { var pixel = map.getPixelFromCoordinate(coordinate); pixels.push(pixel); if (pixel[1] < top[1]) { top = pixel; } }); ctx.moveTo(pixels[0][0], pixels[0][1]); for (var j=1; j<pixels.length; j++) { ctx.lineTo(pixels[j][0], pixels[j][1]); } ctx.lineWidth = this.strokeWidth_; ctx.strokeStyle = this.strokeStyle_; ctx.stroke(); } // Draw scale text above the rings ctx.beginPath(); ctx.strokeStyle = this.fontStrokeStyle_; ctx.fillStyle = this.fontFillStyle_; ctx.lineWidth = this.fontStrokeWidth_; ctx.textAlign = "center"; ctx.textBaseline ="bottom"; ctx.font = this.font_; ctx.strokeText(text, top[0], top[1]-this.strokeWidth_); ctx.fillText(text, top[0], top[1]-this.strokeWidth_); ctx.closePath(); ctx.restore(); } var proj = map.getView().getProjection(); map.getView().setCenter(ol.proj.transform([-38, 75.9], 'EPSG:4326', proj)); map.getView().setZoom(2); map.addControl(new ol.control.CanvasScaleLine()); </script> </body> </html>