入门 Leaflet 之小 Demo


写在前面 ---- WebGIS 开发基础之 Leaflet

  1. GIS 基本概念:GIS、Map、Layer、Feature、Geometry、Symbol、Data(Point、Polyline、Polygon)、Renderer、Scale、Project、Coordinates;
  2. GIS 开发概述:架构模式、常用平台和 SDK、二维三维
  3. 使用 Leaflet 开发常用功能
  • 地图加载(底图类型、切换):
  • 地图操作(缩放、平移、定位/书签、动画):
  • 图层管理(加载、移除、调整顺序):
  • 要素标绘(点/聚簇、线、面,符号化/静态动态):
  • 属性标注(字段可选、样式定制):
  • 专题地图(点、线、面,渲染):
  • 查询定位(属性查询、空间查询/周边搜索/缓冲区/面查点线面/点线查面、图属互查、综合查询):
  • 信息窗口(入口、Popup、定制):
  • 坐标转换(地理与投影、不同地理坐标系):
  • 空间运算(长度面积测量、点取坐标、缓冲区、相交包含关系):
  • 动态监控(固定点状态切换、车辆监控):
  1. Leaflet API

Demo 用到的库

  • Flat-UI Flat UI is based on Bootstrap, a comfortable, responsive, and functional framework that simplifies the development of websites.Flat-UI 是基于 Bootstrap 的一个扁平化风格 web 开发框架。
  • leaflet an open-source JavaScript library for mobile-friendly interactive maps.Leaflet 是一个为建设交互性好适用于移动设备地图,而开发的现代的、开源的 JavaScript 库。
  • Esri Leaflet A lightweight set of tools for using ArcGIS services with Leaflet.一个轻量级的工具,基于 leaflet 利用 ArcGIS 服务。

PART 1: 地图加载(底图类型、切换) Demo 1

  • 库引用
<link rel="stylesheet" type="text/css" href="./lib/Flat-UI-master/dist/css/vendor/bootstrap/css/bootstrap.min.css" /> <link rel="stylesheet" href="./lib/Flat-UI-master/dist/css/flat-ui.min.css"> <link rel="stylesheet" href="./lib/leaflet/leaflet.css">
<script src="./lib/Flat-UI-master/dist/js/vendor/jquery.min.js"></script> <script src="./lib/Flat-UI-master/dist/js/flat-ui.js"></script> <script src="./lib/leaflet/leaflet.js"></script> <script src="./js/urlTemplate.js"></script>
  • 地图加载与切换
const map = L.map("mapDiv", {crs: L.CRS.EPSG3857, //要使用的坐标参考系统,默认的坐标参考系,互联网地图主流坐标系 // crs: L.CRS.EPSG4326, //WGS 84坐标系,GPS默认坐标系 zoomControl: true, // minZoom: 1, attributionControl: true, }).setView([30.6268660000, 104.1528940000], 18);//定位在成都北纬N30°37′45.58″ 东经E104°09′1.44″ let Baselayer = L.tileLayer(urlTemplate.mapbox_Image, { maxZoom: 17, //最大视图 minZoom: 2, //最小视图 attribution: 'liuvigongzuoshi@foxmail.com &copy; <a href="https://github.com/liuvigongzuoshi/WebGIS-for-learnning/tree/master/Leaflet_Demo">WebGIS-for-learnning</a>' }).addTo(map); const setLayer = (ele) => { map.removeLayer(Baselayer) if (ele == "mapbox_Image") { Baselayer = L.tileLayer(urlTemplate.mapbox_Image, { maxZoom: 17, minZoom: 2 }).addTo(map); } else if (ele == "mapbox_Vector") { Baselayer = L.tileLayer(urlTemplate.mapbox_Vector, { maxZoom: 17, // minZoom: 2 }).addTo(map); console.log(Baselayer) } }

基于 Demo 1 利用 H5 Geolocation API 定位到当前位置 Demo 1.1

  • 库引用 如上 Demo 1
<!-- marker高亮显示库引用 -->
<link rel="stylesheet" href="./lib/leaflet.marker.highlight/leaflet.marker.highlight.css"> <script src="./lib/leaflet.marker.highlight/leaflet.marker.highlight.js"></script>
  • 判断浏览器是否支持
    let map;let Baselayer;// 使用H5 API定位 定位在当前位置if (navigator.geolocation) { console.log('/* 地理位置服务可用 */') navigator.geolocation.getCurrentPosition(h5ApiSuccess, h5ApiError); } else { console.log('/* 地理位置服务不可用 */') mapInit([30.374558, 104.09144]);//指定一个数据 定位在成都北纬N30°37′45.58″ 东经E104°09′1.44″ }
  • 定位成功或失败
    const h5ApiSuccess = (position) => {let latitude = position.coords.latitude; //纬度 let longitude = position.coords.longitude; //经度 console.log('你的经度纬度分别为' + longitude + ',' + latitude + '。') return mapInit([latitude, longitude]); }; const h5ApiError = () => { console.log('/* 地理位置请求失败 */') mapInit([30.374558, 104.09144]);//指定一个数据 定位在成都北纬N30°37′45.58″ 东经E104°09′1.44″ };
  • 成功后初始化底图
    const mapInit = (LatLng) => {map = L.map("mapDiv", { crs: L.CRS.EPSG3857, //要使用的坐标参考系统,默认的坐标参考系 // crs: L.CRS.EPSG4326, //国内的坐标参考系 zoomControl: true, // minZoom: 1, attributionControl: true, }).setView(LatLng, 18);//定位在当前位置 Baselayer = L.tileLayer(urlTemplate.mapbox_Image, { maxZoom: 17, //最大视图 minZoom: 2, //最小视图 attribution: 'liuvigongzuoshi@foxmail.com &copy; <a href="https://github.com/liuvigongzuoshi/WebGIS-for-learnning/tree/master/Leaflet_Demo">WebGIS-for-learnning</a>' }).addTo(map); L.marker(LatLng, { highlight: "permanent" //永久高亮显示 }).addTo(map); }
  • 更多了解 geolocation 对象,可参考MDN Web 文档
  • 更多了解使用 marker 高亮显示,可参考leaflet.marker.highlight插件
  • 基于 Demo 1 利用 leaflet 封装好的 H5 定位 API,定位到当前位置 Demo

PART 2: 地图操作(缩放、平移、定位/书签、动画) Demo 2

  • 库引用 如上 Demo 1
  • 设置地图缩放到指定图层
map.setZoom(10, {// animate: false
})  //设置地图缩放到
  • 图层往里进一个图层,放大
map.zoomIn() //图层往里进一个图层,放大
//map.zoomOut()  //图层往里出一个图层,缩小
  • 地图平移至中心点
map.panTo([37.91082, 128.73583], {animate: true }) //地图平移,默认就是true,将地图平移到给定的中心。如果新的中心点在屏幕内与现有的中心点不同则产生平移动作。
  • 地图飞到中心点
map.flyTo([36.52, 120.31]); // 点到点的抛物线动画,平移加缩放动画

注意:尽量避免 setZoom()等地图缩放方法与 flyTo、flyToBounds 一起合用,因为这两类地图操作方法都有各自的缩放值,造成动画不流畅、不能定位到目的点。

  • 地图飞到边界的合适的位置
map.flyToBounds(polygon.getBounds());   //getBounds(获取边界):返回地图视图的经纬度边界。//飞到这个多变形区域上面,自动判断区域块的大小,合适缩放图层,将地图视图尽可能大地设定在给定的地理边界内。let polygon = L.polygon([[37, -109.05], [41, -109.03], [41, -102.05], [37, -102.04]], [40.774, -74.125], { color: 'green', fillColor: '#f03', fillOpacity: 0.5 }).addTo(map); //地图上绘制一个多形
  • 地图定位到边界的合适的位置
map.fitBounds(polygon.getBounds());  //getBounds(获取边界):返回地图视图的经纬度边界。//平移到一个区域上面,自动判断区域块的大小,合适缩放图层let polygon = L.polygon([[37, -109.05], [41, -109.03], [41, -102.05], [37, -102.04]], [40.774, -74.125], { color: 'green', fillColor: '#f03', fillOpacity: 0.5 }).addTo(map); //地图上绘制一个多边形

PART 3: 图层管理(加载、移除、调整顺序): Demo 3

  • 库引用
<link rel="stylesheet" type="text/css" href="./lib/Flat-UI-master/dist/css/vendor/bootstrap/css/bootstrap.min.css" /> <link rel="stylesheet" href="./lib/Flat-UI-master/dist/css/flat-ui.min.css"> <link rel="stylesheet" href="./lib/leaflet/leaflet.css">
<script src="./lib/Flat-UI-master/dist/js/vendor/jquery.min.js"></script> <script src="./lib/Flat-UI-master/dist/js/flat-ui.js"></script> <script src="./lib/leaflet/leaflet.js"></script> <script src="./lib/esri-leaflet-v2.1.2/dist/esri-leaflet.js"></script> <!-- esri-leafleat插件 --> <script src="./js/urlTemplate.js"></script>
  • 使用 esri-leaflet 插件加载 ArcGIS 底图服务
let oMap = null;let oLayer = [];oMap = L.map('mapDiv', { crs: L.CRS.EPSG4326, zoomControl: false, minZoom: 7, attributionControl: false }).setView([29.59, 106.59], 12); //定位在重庆 oLayer.push(L.esri.tiledMapLayer({ url: urlTemplate.SYS_CQMap_IMG_MAPSERVER_PATH, maxZoom: 17, minZoom: 0, useCors: false, //是否浏览器在跨域的情况下使用GET请求。 }).addTo(oMap)); //加载第一个底图 oLayer.push(L.esri.tiledMapLayer({ url: urlTemplate.SYS_CQMap_IMG_LABEL_MAPSERVER_PATH, maxZoom: 17, minZoom: 0, useCors: false, }).addTo(oMap)); //加载第二个底图
  • 切换底图(移除及加载)
const setLayer = (layerUrls, maxZoom) => {for (let i = 0; i < oLayer.length; i++) { oMap.removeLayer(oLayer[i]) //将图层在地图上移除 } oLayer = [] //制空数组 layerUrls.map((item) => { oLayer.push(L.esri.tiledMapLayer({ url: item, useCors: false, maxZoom: maxZoom, // 设置最大放大图层值 }).addTo(oMap)); }) }

不同的底图可能图层数不一样,就可能造成浏览器去请求不存在的图层,以及给用户展示出空白区域的不好体验,所以切换图层时候应注意设置最大及最小缩放值。

PART 4: 要素标绘(点、线、面,符号化/静态动态) Demo 4

  • 库引用 如上 Demo 1
  • 画一个圆
// 画一个circle
const circle = L.circle([36.52, 120.31], { color: 'green', //描边色 fillColor: '#f03', //填充色 fillOpacity: 0.5, //透明度 radius: 10000 //半径,单位米 }).addTo(map); // 绑定一个提示标签 circle.bindTooltip('我是个圆');
  • Maker 及自定义 Maker
// 做一个maker
const marker = L.marker([36.52, 120.31]).addTo(map); // 绑定一个提示标签 marker.bindTooltip('这是个Marker', { direction: 'left' }).openTooltip(); //自定义一个maker const greenIcon = L.icon({ iconUrl: './icon/logo.png', iconSize: [300, 79], // size of the icon popupAnchor: [0, -10] // point from which the popup should open relative to the iconAnchor }); const oMarker = L.marker([36.52, 124.31], { icon: greenIcon }).addTo(map); // 绑定一个提示标签 oMarker.bindTooltip('这是个自定义Marker', { direction: 'left', offset: [-150, 0] });
  • 画一根线
//画一根线
const polyline = L.polyline([[45.51, -122.68], [37.77, -122.43], [34.04, -118.2]], { color: 'red' }).addTo(map); // 飞到这个线的位置 // map.fitBounds(polyline.getBounds());
  • 画一个多边形
// 画一个polygon
const polygon = L.polygon([[[37, -109.05], [41, -109.03], [41, -102.05], [37, -102.04]], // outer ring [[37.29, -108.58], [40.71, -108.58], [40.71, -102.50], [37.29, -102.50]] // hole ], { color: 'green', fillColor: '#f03', fillOpacity: 0.5 }).addTo(map); // 绑定一个提示标签 polygon.bindTooltip('this is 个多边形'); // 飞到这个多边形的位置 // map.fitBounds(polygon.getBounds());

PART 5: 信息窗口(入口、Popup、定制) Demo 5

  • 库引用 如上 Demo 1
  • 画一个 circle 并绑定一个 Popup
// 画一个circle
const circle = L.circle([36.92, 121.31], { color: 'green', //描边色 fillColor: '#f03', //填充色 fillOpacity: 0.5, //透明度 radius: 10000 //半径,单位米 }).addTo(map); // 绑定一个弹窗 circle.bindPopup('我是个圆');
  • 定位一个 marker,绑定一个自定义 Popup
// 定位一个maker
const marker = L.marker([36.52, 120.31]).addTo(map); //maker上自定义一个popup const html = '<p>Hello world!<br />This is a nice popup.</p>'; const popup = marker.bindPopup(html, { maxHeight: 250, maxWidth: 490, className: 'content', offset: [0, 0] }).on('popupopen', function (params) { console.log(params) });
  • 实现动态改变 Popup 的内容
const mypop = L.popup();map.on('click', function (e) { mypop.setLatLng(e.latlng) .setContent('你临幸了这个点:<br>' + e.latlng.toString()) .openOn(map); });

PART 6: geojson 数据绘制边界(坐标转换、渲染) Demo 6

  • 库引用 如上 Demo 1
  • 获得 geojson 并处理数据
// 请求geojson并处理数据
const population = () => { $.get("./js/geojson.json", function (response) { const poplData = response.data const PolygonsCenter = response.geopoint drawPolygons(poplData, PolygonsCenter) }); }

模拟后台返回的数据geojson

  • 绘制边界并添加图例
let oPolygon_VilPop = [];const legend = L.control({position: 'bottomright' }); const drawPolygons = (poplData, PolygonsCenter) => { for (const i in poplData) { poplData[i].geoJson = JSON.parse(poplData[i].geoJson) oPolygon_VilPop[i] = L.geoJSON(poplData[i].geoJson, { style: function () { return { color: 'white', fillColor: getBgColor(poplData[i].population), //获取边界的填充色 fillOpacity: 0.6, weight: 3, dashArray: '10' }; } }).bindTooltip(poplData[i].villageName + '<br><br>人口' + poplData[i].population + '人', { direction: 'top' }).on({ mouseover: highlight, //鼠标移动上去高亮 mouseout: resetHighlight, //鼠标移出恢复原样式 click: zoomTo //点击最大化 }).addTo(oMap); } // 添加图例 legend.onAdd = legendHtml; legend.addTo(oMap); // 定位到该界限的中心位置 oMap.flyToBounds(PolygonsCenter); } // 添加图例 legend.onAdd = legendHtml; legend.addTo(oMap); // 定位到该界限的中心位置 oMap.flyToBounds(PolygonsCenter); }
  • 返回边界的填充色及图列的样式
const getBgColor = (d) => {return d > 400 ? '#800026' : d > 300 ? '#BD0026' : d > 200 ? '#FC4E2A' : d > 100 ? '#FD8D3C' : d > 50 ? '#FED976' : '#FFEDA0'; } const legendHtml = (map) => { let div = L.DomUtil.create('div', 'legend locateVP_legend'), grades = [0, 50, 100, 200, 400], labels = [], from, to; for (let i = 0; i < grades.length; i++) { from = grades[i]; to = grades[i + 1]; labels.push( '<i style="background:' + getBgColor(from + 1) + '"></i> ' + from + (to ? ' &sim; ' + to + '人' : '以上')); } div.innerHTML = labels.join('<br>'); return div; };
  • 鼠标移动上去的事件、鼠标移出的事件、发生点击的事件
const highlight = (e) => {let layer = e.target; layer.setStyle({ weight: 6, color: '#fff', fillOpacity: 0.9, dashArray: '0' }) } const resetHighlight = (e) => { let layer = e.target; layer.setStyle({ color: 'white', weight: 3, fillOpacity: 0.6, dashArray: '10' }) } const zoomTo = (e) => { oMap.fitBounds(e.target.getBounds()); }

写在后面

国内常用地图服务资源加载插件

Leaflet.ChineseTmsProviders Provider for Chinese Tms Service

  • Leaflet 调用国内各种地图的功能十分复杂,幸好有 leaflet.ChineseTmsProviders 这个插件,这四种地图直接就可以加载进来,十分方便。
  • 使用方法很简单可点击上面链接去 GitHub 看使用说明,或拉这个 demo下来来瞧一瞧代码。

优化 marker 相关的插件

  • 提供了丰富多彩的图标 Leaflet.awesome-markers, See the demo map点击预览
  • 强大的集聚插件 Leaflet.markercluster, See the demo map
  • 优化的 label Leaflet.label, See the demo map
  • 优化重叠在一起的 markers OverlappingMarkerSpiderfier-Leaflet, See the demo map
  • 优化在边框上显示不在当前视野中的 marker Leaflet.EdgeMarker, See the demo map

模块化开发的加载包注意的问题

  • 引 leaflet 包的时候不要忘记引用包里的 css import 'leaflet/dist/leaflet.css';

关于 Leaflet 和 esri-leaflet 一起使用 L.esri.TiledMapLayer 加载 ArcGIS 服务切片底图时,控制台打印报错 Uncaught ReferenceError: proj4 is not defined

  • 查看了下源码 if (!proj4) { warn('L.esri.TiledMapLayer is using a non-mercator spatial reference. Support may be available through Proj4Leaflet http://esri.github.io/esri-leaflet/examples/non-mercator-projection.html');} 问题就出在这里,esri-leaflet 里的一个插件 proj4leaflet 依赖proj4,所以需要手动引入 proj4 这个包。
  • 这个 GitHub 上面的提问及回答 Github esri-leaflet Issues
  • 如果你是模块化开发,需要再npm i proj4 然后再引入进来好了 import * as proj4 from 'proj4'; window['proj4'] = proj4;
  • 如果你是常规开发,直接添加一个 script 标签引用 CDN 资源上托管的Proj4js就是了 <script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.4.4/proj4-src.js"></script>

Leaflet 学习资料整理

  • Leaflet-Develop-Guide ? -开发文档及常用插件小结

参考

  • GIS 制图乐园 esri-leaflet 入门教程(1)-leaflet 介绍
  • Awesome GIS(GIS Tech Stack 技术栈)
  • 麻辣 GIS Leaflet 学习笔记

转载于:https://www.cnblogs.com/Jeely/p/11132288.html

入门Leaflet之小Demo相关推荐

  1. python小项目实例流程-《Python编程:从入门到实践》DEMO实例代码

    这篇文章主要知识点是关于Python编程,从入门到实践,DEMO,,的内容,如果大家想对相关知识点有系统深入的学习,可以参阅以下电子书 前言 之前,项目后台基本都是使用 Java 的 SpringBo ...

  2. python 入门小demo

    # python 入门小demo# # eidogo.com 里的围棋定式的解析程序,用的是 python ,为了改写,初步接触了一下 python# # 写了个小 demo,涉及到文件操作,时间操作 ...

  3. 用Unity做一个小Demo入门Unity

    文章目录 前言 个人介绍 一.准备工作 1. unity下载安装 2. 个人许可证激活 3. 素材下载 二.项目准备 1. 项目创建 2. 素材导入 三.开始项目 1. 将素材变为精灵 2. 将精灵放 ...

  4. python代码示例-《Python编程:从入门到实践》DEMO实例代码

    这篇文章主要知识点是关于Python编程,从入门到实践,DEMO,,的内容,如果大家想对相关知识点有系统深入的学习,可以参阅以下电子书 前言 之前,项目后台基本都是使用 Java 的 SpringBo ...

  5. 视频教程-Layabox3D游戏开发入门-微信3D小游戏案例 -微信开发

    Layabox3D游戏开发入门-微信3D小游戏案例 有多年Unity程序开发经验,有策划和美术设计的经验.愿意在csdn这个平台和大家一起分享! 金龙 ¥29.00 立即订阅 扫码下载「CSDN程序员 ...

  6. springboot mybatis easyui 整合的一个小demo

    springboot mybatis easyui 整合的一个小demo 这是最终完成界面 话不多说 开整! 这是项目结构 数据库 表结构和数据库 (有点乱 之前本来是个正经图书表的 = =.) /* ...

  7. 【Java】Jsoup爬虫,一个简单获取京东商品信息的小Demo

    简单记录 - Jsoup爬虫入门实战 数据问题?数据库获取,消息队列中获取中,都可以成为数据源,爬虫! 爬取数据:(获取请求返回的页面信息,筛选出我们想要的数据就可以了!) 我们经常需要分析HTML网 ...

  8. html小Demo: js调用java后端提供的接口

    文章目录 html小Demo: js调用java后端提供的接口 html常用的一些标签(初级版)以及对html的一些理解的笔记 head常用标签 body常用标签 JavaScript Java sp ...

  9. 金融新手投标模块布局小Demo

    <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8" ...

最新文章

  1. 惯性制导精度是多少_什么叫惯性制导,惯性制导的重要性体现在哪里?
  2. 笨办法学python3-笨方法学Python3(21-44)
  3. 毕业设计记录(三)mysql的SQL语句
  4. Entityframework Code First 系列之项目搭建
  5. 聊天工具简单实现(python 半双工聊天)
  6. qt自定义插件creator不显示_让Qt Creator更懂我们的自定义模块
  7. Ubuntu 18.10安装MySql8.0.13
  8. TransactionTemplate和@Transactional注解的区别
  9. 一步步学习EF Core(1.DBFirst)
  10. 阿里云 超级码力在线编程大赛初赛 第3场 题目2. 房屋染色(DP)
  11. 没错,你离分布式搜索只差一个Elasticsearch入门!
  12. xtrabackup部分备份数据库 Partial Backups
  13. 对方服务器未响应,重新投递中 postfix手心,我配置的Postfix邮件服务器邮件发不出去,在mail.log里显示如下~请求帮助...
  14. 简单神经网络_mnist
  15. android平板电脑维修电路图,《图解windows10平板电脑电路原理和维修》大家可以读读看看...
  16. 一文读懂电子罗盘的原理、校准和应用
  17. 一键抓取网页的所有图片
  18. 阿里云服务器可选系统有哪些?如何选择?
  19. Linux 网桥功能使用
  20. Tableau 添加加权平均参考线

热门文章

  1. C#测试程序运行时间
  2. 关于去除2个inline-block之间的间距
  3. Log4j 2使用教程转
  4. think in java interview-高级开发人员面试宝典(二)
  5. HTTP Continuation or non-HTTP traffic
  6. 网络主机托管的特点和优点_主机托管有哪些特点和优点
  7. 以太网单播、组播、广播
  8. nodejs之express -- 1
  9. 数据库中char与varchar类型的区别
  10. 第二课 壳的介绍以及脱壳常用思路