首页 > 其他分享 >Leaflet实现极地坐标投影

Leaflet实现极地坐标投影

时间:2024-03-01 14:47:31浏览次数:12  
标签:map textNode text 投影 Leaflet 极地 ._ var options

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>Leaflet Polar Graticule - Arctic</title>
	<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css"/>
	<style type="text/css">
		html,
		body,
		#map {
			width: 100%;
			height: 100%;
			margin: 0;
			background: #fff;
		}
	</style>
</head>
<body>
	<div id='map'>
		<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
		<script src="https://unpkg.com/[email protected]/lib/proj4-compressed.js"></script>
		<script src="https://unpkg.com/[email protected]/src/proj4leaflet.js"></script>
		<script type="text/javascript" src="../L.Graticule.min.js"></script>
		<script type="text/javascript">
			const crs = new L.Proj.CRS('EPSG:3413', '+proj=stere +lat_0=90 +lat_ts=70 +lon_0=-45 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs', {
				resolutions: [16184, 8192, 4096, 2048, 1024, 512, 256],
				origin: [-4194304, 4194304],
				bounds: L.bounds(
					[-4194304, -4194304],
					[4194304, 4194304]
				)
			});

			var map = L.map('map', {
				crs: crs,
				maxZoom: 5,
				center: [90, 0],
				zoom: 0,
                attributionControl: false
			});

			// coastlines
			L.tileLayer.wms('http://10.31.14.83:9090/geoserver/polar/wms', {
				layers: 'polar:coastN10',
				format: 'image/png',
				transparent: true,
				height: 256,
				width: 256
			}).addTo(map);

			L.graticule({
				intervalLat: 10,
				intervalLng: 30,
				latBounds: [45, 90],
				// centerLonLabels: true
			}).addTo(map);

		</script>
	</div>
</body>

</html>

https://github.com/anton-seaice/Leaflet.PolarGraticule

点击查看L.Graticule.js代码
(function () {
    'use strict';

    /*
     * Leaflet.TextPath - Shows text along a polyline
     * Inspired by Tom Mac Wright article :
     * http://mapbox.com/osmdev/2012/11/20/getting-serious-about-svg/
     */

    (function () {

    var __onAdd = L.Polyline.prototype.onAdd,
        __onRemove = L.Polyline.prototype.onRemove,
        __updatePath = L.Polyline.prototype._updatePath,
        __bringToFront = L.Polyline.prototype.bringToFront;


    var PolylineTextPath = {

        onAdd: function (map) {
            __onAdd.call(this, map);
            this._textRedraw();
        },

        onRemove: function (map) {
            map = map || this._map;
            if (map && this._textNode && map._renderer._container)
                map._renderer._container.removeChild(this._textNode);
            __onRemove.call(this, map);
        },

        bringToFront: function () {
            __bringToFront.call(this);
            this._textRedraw();
        },

        _updatePath: function () {
            __updatePath.call(this);
            this._textRedraw();
        },

        _textRedraw: function () {
            var text = this._text,
                options = this._textOptions;
            if (text) {
                this.setText(null).setText(text, options);
            }
        },

        setText: function (text, options) {
            this._text = text;
            this._textOptions = options;

            /* If not in SVG mode or Polyline not added to map yet return */
            /* setText will be called by onAdd, using value stored in this._text */
            if (!L.Browser.svg || typeof this._map === 'undefined') {
              return this;
            }

            var defaults = {
                repeat: false,
                fillColor: 'black',
                attributes: {},
                below: false,
            };
            options = L.Util.extend(defaults, options);

            /* If empty text, hide */
            if (!text) {
                if (this._textNode && this._textNode.parentNode) {
                    this._map._renderer._container.removeChild(this._textNode);
                    
                    /* delete the node, so it will not be removed a 2nd time if the layer is later removed from the map */
                    delete this._textNode;
                }
                return this;
            }

            text = text.replace(/ /g, '\u00A0');  // Non breakable spaces
            var id = 'pathdef-' + L.Util.stamp(this);
            var svg = this._map._renderer._container;
            this._path.setAttribute('id', id);

            if (options.repeat) {
                /* Compute single pattern length */
                var pattern = L.SVG.create('text');
                for (var attr in options.attributes)
                    pattern.setAttribute(attr, options.attributes[attr]);
                pattern.appendChild(document.createTextNode(text));
                svg.appendChild(pattern);
                var alength = pattern.getComputedTextLength();
                svg.removeChild(pattern);

                /* Create string as long as path */
                text = new Array(Math.ceil(isNaN(this._path.getTotalLength() / alength) ? 0 : this._path.getTotalLength() / alength)).join(text);
            }

            /* Put it along the path using textPath */
            var textNode = L.SVG.create('text'),
                textPath = L.SVG.create('textPath');

            var dy = options.offset || this._path.getAttribute('stroke-width');

            textPath.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", '#'+id);
            textNode.setAttribute('dy', dy);
            for (var attr in options.attributes)
                textNode.setAttribute(attr, options.attributes[attr]);
            textPath.appendChild(document.createTextNode(text));
            textNode.appendChild(textPath);
            this._textNode = textNode;

            if (options.below) {
                svg.insertBefore(textNode, svg.firstChild);
            }
            else {
                svg.appendChild(textNode);
            }

            /* Center text according to the path's bounding box */
            if (options.center) {
                var textLength = textNode.getComputedTextLength();
                var pathLength = this._path.getTotalLength();
                /* Set the position for the left side of the textNode */
                textNode.setAttribute('dx', ((pathLength / 2) - (textLength / 2)));
            }

            /* Change label rotation (if required) */
            if (options.orientation) {
                var rotateAngle = 0;
                switch (options.orientation) {
                    case 'flip':
                        rotateAngle = 180;
                        break;
                    case 'perpendicular':
                        rotateAngle = 90;
                        break;
                    default:
                        rotateAngle = options.orientation;
                }

                var rotatecenterX = (textNode.getBBox().x + textNode.getBBox().width / 2);
                var rotatecenterY = (textNode.getBBox().y + textNode.getBBox().height / 2);
                textNode.setAttribute('transform','rotate(' + rotateAngle + ' '  + rotatecenterX + ' ' + rotatecenterY + ')');
            }

            /* Initialize mouse events for the additional nodes */
            if (this.options.interactive) {
                if (L.Browser.svg || !L.Browser.vml) {
                    textPath.setAttribute('class', 'leaflet-interactive');
                }

                var events = ['click', 'dblclick', 'mousedown', 'mouseover',
                              'mouseout', 'mousemove', 'contextmenu'];
                for (var i = 0; i < events.length; i++) {
                    L.DomEvent.on(textNode, events[i], this.fire, this);
                }
            }

            return this;
        }
    };

    L.Polyline.include(PolylineTextPath);

    L.LayerGroup.include({
        setText: function(text, options) {
            for (var layer in this._layers) {
                if (typeof this._layers[layer].setText === 'function') {
                    this._layers[layer].setText(text, options);
                }
            }
            return this;
        }
    });



    })();

    /*
     Graticule plugin for Leaflet powered maps.
    */
    L.Graticule = L.GeoJSON.extend({

        options: {
            style: {
                color: '#333',
                weight: 1
            },
            intervalLat: 10 ,
            intervalLng: 10 ,
            latBounds:[-90,90],
            lngBounds:[-180,180] ,
            centerLatLabels: true ,
            centerLonLabels: false ,
            zIndex: 99999,
            onEachFeature: function (feature, layer) {
    			if (feature.properties.name.match('W')) {
    				layer.setText(
    					feature.properties.name,
    					{offset:-3, orientation:0, center: layer.options.centerLonLabels, attributes:{class:'grat-labels'}}
    				);
    			} else if (feature.properties.name.match('E')) {
                    layer.setText(
    					feature.properties.name,
    					{offset:-3, orientation:180, center: layer.options.centerLonLabels, attributes:{class:'grat-labels'}}
    				);
                } else if (feature.properties.name.match('S')) {
    				layer.setText(
    					feature.properties.name,
    					{offset:-3, center: layer.options.centerLatLabels, attributes:{class:'grat-labels'}}
    				);
    			} else if (feature.properties.name.match('N')) {
    				layer.setText(
    					feature.properties.name,
    					{offset:-3, center: layer.options.centerLatLabels, attributes:{class:'grat-labels'}}
    				);
    			}
            }   

        },

        initialize: function (options) {

            L.Util.setOptions(this, options);
            this.options.style={...this.options.style, interactive:false};
            this._layers = {};

            this.addData(this._getGraticule());
        },

        _getGraticule: function () {
            var features = []; 

            //round the starting point to a multiple of the lng interval
            let lng = this.options.intervalLng*Math.round(this.options.lngBounds[0]/this.options.intervalLng);

            // Meridians
            for (lng ; lng < this.options.lngBounds[1]; lng += this.options.intervalLng) {
                if (lng >=0) {
                    features.push(this._getFeature(this._getMeridian(lng), {
                    "name": (lng) ? lng.toString() + "° E" : "0° E"
                    })); 
                }
                else if (lng < 0) {
                    features.push(this._getFeature(this._getMeridian(lng), {
                        "name": (-lng).toString() + "° W"
                    }));
                }
            }

            //round the starting point to a multiple of the lat interval
            let lat = this.options.intervalLat*Math.round(this.options.latBounds[0]/this.options.intervalLat);

            // Parallels
            for (lat; lat < this.options.latBounds[1]; lat = lat + this.options.intervalLat) {
                if (lat>=0) {
                    features.push(this._getFeature(this._getParallel(lat), {
                        "name": (lat) ? lat.toString() + "° N" : "0° N"
                    }));
                }
                else if (lat < 0) {
                    features.push(this._getFeature(this._getParallel(lat), {
                        "name": (-lat).toString() + "° S"
                    }));
                }
            }

            return {
                "type": "FeatureCollection",
                "features": features
            };
        },

        _getMeridian: function (lng) {
            lng = this._lngFix(lng);
            var coords = [];

            // for convenience with labelling, we are going to draw lines towards the poles
            if (this.options.latBounds[0]<-this.options.latBounds[1]) {
                // lines start at max and go towards the min (e.g.. from -30 towards -90)
                for (var lat = this.options.latBounds[1]; lat >= this.options.latBounds[0]; lat--) {
                    coords.push([lng, lat]);
                }
            } else {
                // lines start at min and go towards max (e.g. from 0 towards 90)
                for (var lat = this.options.latBounds[0]; lat <= this.options.latBounds[1]; lat++) {
                    coords.push([lng, lat]);
                }
            }
            return coords;
        },

        _getParallel: function (lat) {
            var coords = [];
            for (var lng = this.options.lngBounds[0]; lng <= this.options.lngBounds[1]; lng++) {
                coords.push([this._lngFix(lng), lat]);
            }
            return coords;
        },

        _getFeature: function (coords, prop) {
            return {
                "type": "Feature",
                "geometry": {
                    "type": "LineString",
                    "coordinates": coords
                },
                "properties": prop
            };
        },

        _lngFix: function (lng) {
            if (lng >= 180) return 179.999999;
            if (lng <= -180) return -179.999999;
            return lng;
        },

    });

    L.graticule = function (options) {
        return new L.Graticule(options);
    };

})();

标签:map,textNode,text,投影,Leaflet,极地,._,var,options
From: https://www.cnblogs.com/echohye/p/18047013

相关文章

  • Leaflet 实现自定义瓦片实现xyz信息和边框绘制到瓦片上
    Leaflet实现自定义瓦片的渲染,将一些信息和边框绘制到瓦片上。主要作用是创建一个Canvas元素作为Leaflet的瓦片,并在Canvas上绘制一些文本信息和边框。实现步骤:创建一个Canvas元素作为Leaflet的瓦片,并获取其2D绘图上下文。设置Canvas的大小为当前瓦片的大小。......
  • GIS基础知识 - 坐标系、投影、EPSG:4326、EPSG:3857(转)
    原文:https://www.cnblogs.com/haolb123/p/16553036.html作者:我命由我不由天—hao最近接手一个GIS项目,需要用到PostGIS,GeoServer,OpenLayers等工具组件,遇到一堆地理信息相关的术语名词,在这里做一个总结。1.大地测量学(Geodesy)大地测量学是一门量测和描绘地球表面的学科,也包......
  • WebGL之三维正射投影(高级)
    一,前言1,绘制一个正方体的数据,我们以前,上,右逆时针绘制,对面的用顺时针绘制。  2,数据准备cubeModel.js/***获得正方体所有顶点位置*@paramsideLength边长*/window.getCubeVertexesPosition=(sideLength)=>{//前constFRONT=[0.0,0.0,0.0......
  • 在vue2中使用leaflet.AnimatedMarker来移动某个目标
    需求是:点击某个按钮后让扫描仪沿着某条线移动进行扫描效果:  扫描仪是沿着河流移动的,河流的生成方式通过geojson数据生成,geojson里包含了河流的一些点位的经纬度,扫描仪根据经纬度来移动leaflet:1.9.4 leaflet.AnimatedMarker:1.0.0 1.引入 importLfrom'leaf......
  • GIS坐标系与投影
    GIS坐标系与投影笛卡尔坐标系空间直角坐标系空间直角坐标系是指坐标原点位于参考椭球的中心,Z轴指向参考椭球的北极,X轴指向起始子午面与赤道的交点,Y轴位于赤道面与X轴成90度夹角,并指向东,形成右手系。空间直角坐标系有右手系和左手系的区分:右手系右手系有两种表示方法,......
  • OpenLayers6使用天地图&ldquo;经纬度投影(CGCS2000)&rdquo;和&ldquo;球面墨卡托投影(E
    转自:https://blog.csdn.net/nudtcadet/article/details/1029084581.封装生成图层类/***@fileOverview天地图WMTS服务API*@author<ahref=”https://blog.csdn.net/nudtcadet”>老胡</a>*@version1.0*/import{getWidth,getTopLeft}from'ol/extent';impo......
  • Leaflet 使用图片作为地图
    Leaflet使用图片作为地图关键代码:L.CRS.Simple.transformation=newL.Transformation(1,0,1,0);//坐标原点切换为左上角varmap=newL.Map('map',{crs:L.CRS.Simple,//设置地图坐标模式为简单模式center:[0,0],//地图中心zoom:-0.5,//缩放......
  • 线段上离p最近的点 - 投影方式
    点到线段的最近距离判断依据1)投影结果<0,则线段端点a离p最近2)投影结果>线段ab的长度,则线段端点b离p最近3)否则p在线段上的垂点为最近点 p与ab不共线时1)p在线段两侧2-a)p在线段内侧2-b)p在线段内侧2 p与ab共线时1) p在线段两侧 2-a)p在线段内侧2-b......
  • Leaflet 使用图片作为地图
    Leaflet使用图片作为地图关键代码:L.CRS.Simple.transformation=newL.Transformation(1,0,1,0);//坐标原点切换为左上角varmap=newL.Map('map',{crs:L.CRS.Simple,//设置地图坐标模式为简单模式center:[0,0],//地图中心zoom:-0.5,//缩......
  • leaflet在vue2中标点 加载geoJSON
    lealfet版本1.9.4vue版本2.6引入:importLfrom'leaflet'  import'leaflet/dist/leaflet.css'  //记得引入样式不然加载瓦片图后地图会错乱1.初始化this.map=L.map(this.mapId,mapInitOptionNew)//this.mapId是容器的idletcenter=[32.666,129.547]const......