0


少小白学前端——leaflet篇(Javascript 地图库)

废话少说,就是最近想了解一下gis开发,网上搜了一下,推荐了leaflet、OpenLayers等等,于是今天就练习了一下leaflet,并做出如下记录。

先上中文文档:https://leafletjs.cn/reference.html

一、安装

这里提供两种方式,npm和CDN引入。另外,还建议安装一个插件leaflet.chinesetmsproviders,使用这个插件可以将高德地图、百度地图等集成到leaflet中。

1、CDN引入

引入方式在中文文档中就有,代码如下:

<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css"
      integrity="sha256-kLaT2GOSpHechhsozzB+flnD+zUyjE2LlfWPgU04xyI="
      crossorigin=""/><script src="https://unpkg.com/[email protected]/dist/leaflet.js"
        integrity="sha256-WBkoXOwTeyKclOHuWtc+i2uENFpDZ9YPdf5Hf+D7ewM="
        crossorigin=""></script><script src="https://cdn.jsdelivr.net/npm/[email protected]/src/leaflet.ChineseTmsProviders.min.js"></script>

前两个是leaflet的CSS和JS文件,第三个则是插件的JS文件。

2、npm

// leaflet
 npm i leaflet --save
 // 插件
 npm install leaflet.chinesetmsproviders

二、使用

如果采用的是CDN的方式,此刻在window对象中,已经可以看到leaflet的属性和方法了。若使用的是npm,则需要引入一下:

// 引入leafletimportLfrom'leaflet';import'leaflet/dist/leaflet.css';// 引入插件import'leaflet.chinesetmsproviders';

注意:这里需要把CSS一起引入进来,否则无法正常显示。

1、创建地图画布

想要创建地图,需要先创建一个带有id的div标签作为地图容器,并设置好高度。然后便可以使用其提供的map()方法,进行渲染了。

<template><div id="map-id" style="height: 800px"></div></template><script setup>import{onMounted}from"vue";onMounted(()=>{// 初始化地图,并设置地理中心和缩放倍数let map =L.map('map-id',{
    center:[39.90,116.39],
    zoom:12});// 添加瓦片(Tile)图层L.tileLayer.chinaProvider('GaoDe.Normal.Map',{maxZoom:18,minZoom:5}).addTo(map);})</script>

需要注意的是,在VUE中,要等组件渲染完,才能进行挂载,因此相关函数要写到onMounted中。而在React框架中,则是要写在componentDidMount中,或是useEffect中。

这里,map()是leaflet的工厂函数,主要是将地图初始化,并返回一个地图对象。它有两个参数,第一个参数可以是容器id(string类型),也可以是容器实例(HTMLElement);第二个参数为options,可设置相关参数,其中center定义了地图的地理中心,用的是经纬度(小数点位数越多越精准);zoom则是地图初始的缩放倍数,其他属性可查询文档。

tileLayer会创建一个瓦片(Tile)图层,而chinaProvider则是插件提供的方法,使我们可以引用高德地图瓦片(Tile),也可使用其他瓦片(Tile):

GaoDe

  • GaoDe.Normal.Map (include Annotion)
  • GaoDe.Satellite.Map
  • GaoDe.Satellite.Annotion

Google

  • Google.Normal.Map (include Annotion)
  • Google.Satellite.Map (exclude Annotion)
  • Google.Satellite.Map (include Annotion)

Baidu

  • Baidu.Normal.Map
  • Baidu.Satellite.Map (exclude Annotion)
  • Baidu.Satellite.Annotion

之后,我们便可以看到效果图了:
在这里插入图片描述
另外: 如果使用的是React框架,还需要注意是否开启了严格模式,也就是是否使用了React.StrictMode标签,因为严格模式会渲染两次,导致导致map()方法执行两次,因此会提示Map container is already initialized.

解决方法1:取消严格模式

解决方法2:在map()方法执行前,将_leaflet_id置空

const container =L.DomUtil.get('map-id');if(container !==null){
  container._leaflet_id =null;}

补充: 地图渲染成功后,我们通过控制台可以发现,出现了很多div标签,其中还有一些空的,这是因为地图是由很多图层构成的,不同的功能渲染在不同的图层中,以此来实现各种功能。而空的,则是因为还没有添加对应的功能。
在这里插入图片描述
上面的地图画布,属于栅格图层,这一图层有很多Tile(点开后,可以看到实际就是地图底层的各种区域图片),接下来将介绍其他图层及方法。

三、leaflet的图层及方法

1、标记(UI 图层)

也就是我们常见的定位,如下图(左):
在这里插入图片描述在这里插入图片描述

创建非常简单,跟map一样,会返回一个对象,可以为其绑定popup(上图右)、move、拖拽事件等。

const marker =L.marker([38.7124,120.6580]).addTo(map);
marker.bindPopup("<b>Hello world!</b><br>I am a popup.").openPopup();

在这里,如果用的是npm的方式安装,可能会遇到一个问题,就是marker图标没有正常显示。解决方法就是将其手动引入进来:

import icon from'leaflet/dist/images/marker-icon.png';// 解决图标不正常显示bugL.Marker.prototype.options.icon =L.icon({
  iconUrl: icon,
  iconAnchor:[10,41]});

iconAnchor为的是修正图标的位置,因为手动绑定会有一点点偏移。

既然能手动绑定icon,当然也能更改其样式了,而且marker方法还允许icon作为参数传入进去。
为此,我们准备两张图片(官方建议,一张marker,一张shadow,注意背景要透明),然后便可以创建一个icon对象了:

import leafGreen from'./leaf-green.png'import leafShadow from'./leaf-shadow.png'// 自定义iconconst customIcon =L.icon({
      iconUrl: leafGreen,// icon的url
      shadowUrl: leafShadow,// shadow的url
      iconSize:[19,47.5],
      shadowSize:[25,32],
      iconAnchor:[11,47],
      shadowAnchor:[2,31],
      popupAnchor:[-1.5,-38]});L.marker([39.908815,116.40667],{icon: customIcon}).addTo(map);

效果如下(右边的树叶便是新加的marker):
在这里插入图片描述
除此之外,还可以用类来快速创建相似的图标,这里我就直接引用官方代码了:

var LeafIcon = L.Icon.extend({
    options: {
        shadowUrl: 'leaf-shadow.png',
        iconSize:     [38, 95],
        shadowSize:   [50, 64],
        iconAnchor:   [22, 94],
        shadowAnchor: [4, 62],
        popupAnchor:  [-3, -76]
    }
});
var greenIcon = new LeafIcon({iconUrl: 'leaf-green.png'}),
    redIcon = new LeafIcon({iconUrl: 'leaf-red.png'}),
    orangeIcon = new LeafIcon({iconUrl: 'leaf-orange.png'});

2、圆和多边形(矢量图层)

画圆和多边形,跟标记差不多,也会返回一个对象;

// 添加圆const circle =L.circle([39.881684,116.410832],{
  color:'red',
  fillColor:'#11ea11',
  fillOpacity:0.5,
  radius:800}).addTo(map);// 多边形const polygon =L.polygon([[39.92231,116.392078],[39.922639,116.401691],[39.913555,116.402292],[39.913028,116.39225]],{color:'#48adec'}).addTo(map);

circle()第一个参数,为中心位置,同样是经纬度,第二个参数则是圆的options,包括描边颜色,填充颜色,填充的不透明度,重要的是radius,是圆的半径,单位是米。

polygon()第一个参数则是各个点,三个点绘制三角形,四个点则是四边形……第二个参数同样是options,除了radius外,圆的其他属性polygon同样拥有。
在这里插入图片描述在这里插入图片描述

此外,还有折线Polyline、矩形Rectangle、圆形标记CircleMarker等。

区别主要在第一个参数上,折线坐标和多边形差不多,按点绘制即可,矩形则是标记边界(对角线的两个点,然后画一个垂直方向的矩形),圆形标记和圆相似,区别是圆形标记的radius单位为像素,且不受缩放影响。

3、GeoJSON 图层

GeoJSON是一种对各种地理数据结构进行编码的格式,一个 GeoJSON 对象可以代表一个空间区域(Geometry),一个有空间界限的实体(Feature),或者一个特征列表(FeatureCollection),且支持以下几何体类型:点、线字符串、多边形、多点、多线字符串、多多边形和几何体集合。

看到数据格式,是不是就立即想到了这是干什么用的,没错,可以接收服务器数据了。

const geojsonFeature ={"type":"Feature","properties":{"name":"Coors Field","amenity":"Baseball Stadium","popupContent":"This is where the Rockies play!"},"geometry":{"type":"Point","coordinates":[116.404674,39.913324]}};

这是一个简单的GeoJSON格式数据(判断格式是否正确,可以利用GeoJson格式数据在线验证工具),我们可以将其添加到地图上,可以看到当前效果跟marker比较类似。

L.geoJSON(geojsonFeature).addTo(map);

在这里插入图片描述
特别注意: GeoJSON格式中,coordinates里的坐标,与leaflet使用方式的是 不同的,leaflet用的是“**[纬度,经度]”,而GeoJSON格式中是“[经度,纬度]**”。

为了更方便的代入数据,我们可以先创建一个空的GeoJSON图层,然后再向其添加数据。

// 创建空的geoJSON图层const myLayer =L.geoJSON().addTo(map);// 数据const myLines =[{"type":"LineString","coordinates":[[116.404642,39.91376],[116.40417,39.913332],[116.405248,39.913328],[116.404642,39.91376]]},{"type":"LineString","coordinates":[[116.40439,39.913308],[116.404363,39.912896],[116.40506,39.912917],[116.405087,39.913287]]}];
    
    myLayer.addData(myLines);

效果如下:
在这里插入图片描述
我们还可以向GeoJSON中添加样式,方式如下:

const options ={style:function(feature){console.log('feature111:', feature)return{color: feature.geometry.color ||'yellow'}},filter:function(feature, layer){console.log('feature222:', feature)returntrue;}}L.geoJSON(myLines, options).addTo(map);

这里,style控制样式,filter控制是否显示,均可写成函数形式。有一点不解的是,两个打印,先执行的竟是第二个,而且feature结构略有不同(style的函数中多了一层)。

在这里插入图片描述
在这里插入图片描述

4、添加比例尺

L.control.scale({metric:true, imperial:false, position:'bottomright'}).addTo(map);

属性说明:
metric:是否显示公制比例线(米/公里),默认true。
imperial:是否显示英制比例线(英里/英尺),默认true。
position:显示位置。可选值 ‘topleft’、 ‘topright’、 ‘bottomleft’ 或 ‘bottomright’,默认bottomleft。
(因为metric和imperial默认值都为true,所以两种比例默认都会显示出来。)

(未完待续……)

标签: 前端 javascript

本文转载自: https://blog.csdn.net/Another_World_Naraku/article/details/141198666
版权归原作者 Another_World_Naraku 所有, 如有侵权,请联系我们删除。

“少小白学前端——leaflet篇(Javascript 地图库)”的评论:

还没有评论