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>

 

posted @ 2019-01-21 09:56  狐狸家的鱼  阅读(677)  评论(0编辑  收藏  举报