少小白学前端——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/leaflet@1.9.3/dist/leaflet.css"
integrity="sha256-kLaT2GOSpHechhsozzB+flnD+zUyjE2LlfWPgU04xyI="
crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"
integrity="sha256-WBkoXOwTeyKclOHuWtc+i2uENFpDZ9YPdf5Hf+D7ewM="
crossorigin=""></script>
<script src="https://cdn.jsdelivr.net/npm/leaflet.chinesetmsproviders@1.0.22/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,则须要引入一下:
// 引入leaflet
import L from '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: ,
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.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
之后,我们便可以看到效果图了:
https://i-blog.csdnimg.cn/direct/02e957b79ea34731bb4970abae2ad7cc.png
别的: 假如利用的是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标签,其中还有一些空的,这是由于舆图是由很多图层构成的,不同的功能渲染在不同的图层中,以此来实现各种功能。而空的,则是由于还没有添加对应的功能。
https://i-blog.csdnimg.cn/direct/e37a7c98a9f24e409bd0012e77ca24ef.png
上面的舆图画布,属于栅格图层,这一图层有很多Tile(点开后,可以看到现实就是舆图底层的各种区域图片),接下来将先容其他图层及方法。
三、leaflet的图层及方法
1、标记(UI 图层)
也就是我们常见的定位,如下图(左):
https://i-blog.csdnimg.cn/direct/d57b7c0b1ed04a4aa2d4da8a24376122.png https://i-blog.csdnimg.cn/direct/a5fa9f75de94438d93b8db319b238e86.png
创建非常简单,跟map一样,会返回一个对象,可以为其绑定popup(上图右)、move、拖拽事件等。
const marker = L.marker().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';
// 解决图标不正常显示bug
L.Marker.prototype.options.icon = L.icon({
iconUrl: icon,
iconAnchor:
});
iconAnchor为的是修正图标的位置,由于手动绑定会有一点点偏移。
既然能手动绑定icon,当然也能更改其样式了,而且marker方法还答应icon作为参数传入进去。
为此,我们准备两张图片(官方建议,一张marker,一张shadow,留意背景要透明),然后便可以创建一个icon对象了:
import leafGreen from './leaf-green.png'
import leafShadow from './leaf-shadow.png'
// 自定义icon
const customIcon = L.icon({
iconUrl: leafGreen,// icon的url
shadowUrl: leafShadow,// shadow的url
iconSize: ,
shadowSize: ,
iconAnchor: ,
shadowAnchor: ,
popupAnchor:[-1.5, -38]
});
L.marker(, {icon: customIcon}).addTo(map);
效果如下(右边的树叶便是新加的marker):
https://i-blog.csdnimg.cn/direct/4d731086f75d4008a2d44cdab6216877.png
除此之外,还可以用类来快速创建相似的图标,这里我就直接引用官方代码了:
var LeafIcon = L.Icon.extend({
options: {
shadowUrl: 'leaf-shadow.png',
iconSize: ,
shadowSize: ,
iconAnchor: ,
shadowAnchor: ,
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(, {
color: 'red',
fillColor: '#11ea11',
fillOpacity: 0.5,
radius: 800
}).addTo(map);
// 多边形
const polygon = L.polygon([
,
,
,
], {color: '#48adec'}).addTo(map);
circle()第一个参数,为中心位置,同样是经纬度,第二个参数则是圆的options,包罗描边颜色,填充颜色,填充的不透明度,重要的是radius,是圆的半径,单位是米。
polygon()第一个参数则是各个点,三个点绘制三角形,四个点则是四边形……第二个参数同样是options,除了radius外,圆的其他属性polygon同样拥有。
https://i-blog.csdnimg.cn/direct/cbe6979fedd24adf81deca0ee7f3d5c2.png https://i-blog.csdnimg.cn/direct/6e44f56bb6144d3480048984eb99a792.png
别的,还有折线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":
}
};
这是一个简单的GeoJSON格式数据(判断格式是否精确,可以利用GeoJson格式数据在线验证工具),我们可以将其添加到舆图上,可以看到当前效果跟marker比较类似。
L.geoJSON(geojsonFeature).addTo(map);
https://i-blog.csdnimg.cn/direct/b11b16f4b7024b7eaccffa70843b9233.png
特别留意: GeoJSON格式中,coordinates里的坐标,与leaflet利用方式的是 不同的,leaflet用的是“[纬度,经度]”,而GeoJSON格式中是“[经度,纬度]”。
为了更方便的代入数据,我们可以先创建一个空的GeoJSON图层,然后再向其添加数据。
// 创建空的geoJSON图层
const myLayer = L.geoJSON().addTo(map);
// 数据
const myLines = [{
"type": "LineString",
"coordinates": [, , ,]
}, {
"type": "LineString",
"coordinates": [, , , ]
}];
myLayer.addData(myLines);
效果如下:
https://i-blog.csdnimg.cn/direct/07404b2e28604bdbba3e9bc0dce7b0a2.png
我们还可以向GeoJSON中添加样式,方式如下:
const options = {
style: function(feature) {
console.log('feature111:', feature)
return {color: feature.geometry.color || 'yellow'}
},
filter: function(feature, layer) {
console.log('feature222:', feature)
return true;
}
}
L.geoJSON(myLines, options).addTo(map);
这里,style控制样式,filter控制是否表现,均可写成函数形式。有一点不解的是,两个打印,先执行的竟是第二个,而且feature结构略有不同(style的函数中多了一层)。
https://i-blog.csdnimg.cn/direct/f52375087f3f444ebe04a2bb212ec68c.png
https://i-blog.csdnimg.cn/direct/cba557062e0d4eb88cf5fda7c3b07987.png
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,以是两种比例默认都会表现出来。)
(未完待续……)
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]