全国免费咨询:

13245491521

VR图标白色 VR图标黑色
X

中高端软件定制开发服务商

与我们取得联系

13245491521     13245491521

2023-11-14_大屏地图:从瓦片到引擎,再到手把手实战

您的位置:首页 >> 新闻 >> 行业资讯

大屏地图:从瓦片到引擎,再到手把手实战 点击小卡片参与粉丝专属福利 ??阅读本文,你将了解 mapbox-gl 和 maplibre-gl 这两款地图引擎的长短了解 「天地图」 这一权威地图平台的使用进行一个 「瓦片风」 地图的开发实战关于 「锤子」 的隐喻有人说: ?“手里捏着锤子的人,看什么都像钉子。” ?虽然有点挖苦的意思,但其实也可以理解为一种解决问题的方法和思路:“先把各种难题转换为自己熟悉的问题,然后就可以用自己熟悉的方式解决问题了。” 当然,这思路可能有 「缘木求鱼」 的挖苦意味在里面。 但是,有没有一种可能: ?“我手里是一把多功能锤子!” ?噢,对于我而言,mapbox-gl/maplibre-gl 就是我面对各种大屏地图开发需求的那把 「多功能锤子」。 让我们看看这把锤子,究竟如何。 一、地图引擎的选择谈到 GIS,就很难绕开 Mapbox 这家公司,毕竟目前世界上最广泛使用的 「矢量瓦片标准」 MAPBOX CECTOR TILE SPECIFICATION 正是这家公司发布制定的。 除此之外, mapbox 还提供了非常完全的地理信息服务、非常多的地图开发工具,其中就包括一款在前端开发者圈中非常热门的地图渲染引擎: ?mapbox-gl。 ?这也是我日常进行地图开发,所选择的地图引擎。 1.1 认识 mapbox-glmapbox-gl 是一款开源地图引擎。 它的 npmjs 地址:https://www.npmjs.com/package/mapbox-gl 它的 github 官网:https://github.com/mapbox/mapbox-gl-js 它的使用文档:https://docs.mapbox.com/mapbox-gl-js/ 首先,我们要认识这个库,就要认识它的能力和边界,以下是我的个人使用总结: mapbox是一款地图引擎,「它能做什么?」 能通过各种投影系进行地图瓦片的投影。支持在地图瓦片上叠加各种图层,支持 geojson、图片、文本 等多种信息在图层上进行加载显示。支持自定义 Style (矢量瓦片)支持 2.5D 视角旋转及显示支持加载 3D 模型支持通过 DOM 的方式添加 HTML 元素支持 web-gl 能力进行图形渲染支持进行 3D 形式的球星地理渲染和星空背景渲染尤其是其 "2.5D 视角旋转及显示"、"加载 3D 模型" 这两点,是非常亮眼的,相比于 OpenLayers 和 Leaflet 这两款竞品,这也是它最为吸引人的地方所在。 但也不能盲目乐观,我也总结了使用中感受到不足的点: 无法支持 「地下管网开挖」 这种形式的页面展示(相比于 Cesium)3D 支持上能力比较弱(相比于 Cesium)不够 open“「不够 open ?」” 想必你也有这样的困惑吧,为什么我会这样说? ?mapbox-gl 开源,但很可惜,它也不是纯粹的 「开源作品」,虽然它确实 「开源」。 ?这得从它的 accessToken 和账号注册 说起。 1.2 使用 mapbox?可能没那么容易不久前,我曾在掘金发过一篇文章介绍 mapbox-gl: 《【一库】mapbox-gl!一款开箱即用的地图引擎》 但文章发布后,却收到很多小伙伴的反馈:"「注册 mapbox 账号居然需要国际信用卡...」" 我去试了试:「还真是」! ?这是 mapbox 在 2022年6月 新出的规定,注册账号必须绑定一张国际信用卡。这个要求,就让很多国内小伙伴想试用的成本大大提升了。 ?那么,可能有人就会问了:“mapbox 不是开源产品吗?不注册它们官方的账号,难道用不了吗?”问的很好,也很合理。 但是: ?抱歉,真的用不了。 ?纳尼?引用一段 stackoverflow.com 上小伙伴对其的评价吧: ?Mapbox have now changed mapbox-gl-js in version 2 to no longer be Open, you will have to have a key going forward. ?翻译一下: ?Mapbox 在 mapbox-gl-js@2.0 版本开始,已经不再开放。你必须有它家的 accessToken 才能进行下一步。 ?没错,没有国际信用卡,不能注册 mapbox,没有 mapbox 账号用不了 mapbox-gl的 v2 版本。 好家伙,它是懂资本的。 那么?我的意思是:别用 mapbox-gl 了吗? 「并不是,我只是要推荐一下它的孪生弟弟:」 ?maplibre-gl ?1.3 maplibre-gl:我比哥哥更开放如果你想尝试 mapbox-gl 的各种炫酷能力,但你不想(能)注册 Mapbox 官网账号,现在,有了一个更好的选择: ?maplibre-gl ?它的 npmjs 地址:https://www.npmjs.com/package/maplibre-gl 它的 github 官网:https://github.com/maplibre/maplibre-gl-js 简单介绍一下:它就是 mapbox-gl 仓库 fork 出来的开放版本,无需 accessToken 就能品尝 mapbox-gl 的强大能力。 其他介绍?不用了,参照本文关于 mapbox-gl 的相关介绍即可。 1.4 一个简单的选择原则到底是用 mapbox-gl 还是使用 maplibre-gl? 我提供一个我自己的简单原则: 如果你希望使用 Mapbox 官方提供的瓦片服务,那选 mapbox-gl 就完事了。如果你只是希望使用其地图引擎的相关能力,并不打算使用 Mapbox 官方的瓦片服务,很好,你可以选择maplibre-gl 这款更加 Open 的开源引擎。按照这个原则,本系列涉及到的各类 Demo 都会以 maplibre-gl 作为地图引擎进行开发。 二、 大屏的地图一般怎么玩?在各种各样场景的大屏开发中,关于地图的展示,一般存在两种常见的玩法: 「线框风格」 地图 「瓦片风格」 地图 一款大屏到底选取哪种风格作为地图样式,通常是由 「业务特点」 决定的: 如果业务方并不在意具体的业务地理位置,只在乎自己在每个省的营收关系、投资情况等粗粒度的数据展示及分析,那天然适合 「线框风」 地图。没有瓦片带来的地理信息细节干扰,展示上也更加清爽明白。 但如果业务方非常在意实际的地理业务数据,关心自己的辖区在 XX街道XX区域,区域与区域之间的关联,事件在地理位置上的准确显示,那则适合选用 「瓦片风」 地图,提供精准的参考和地理信息。 maplibre-gl 最擅长的便是 「瓦片风格」 的地图,但不必担心,作为一款 「多功能锤子」,它也能轻松驾驭 「线框风」 的地图场景。 三、通过 "天地图" 获取在线瓦片服务?"天地图" 是由 "国家基础地理信息中心" 提供的一个地理信息服务平台。 ?通过 "天地图",我们能够获得免费、权威的地理信息数据,也是很多人获取地图瓦片的首选方案。 官网:https://www.tianditu.gov.cn/ 注册完成后,访问控制台(https://console.tianditu.gov.cn/api/key),申请 「称为个人开发者」,然后注册一个应用。 这样,你就能够获得一个自动生成的 key(密钥)。 这个 key 就是你后期请求瓦片的一个重要凭证。 //在文本后续的代码引用中,我都会用全局变量MY_KEY来代替我申请到的这个`key`,这是为了避免你图方便把它用到了项目中。那对你而言是一件危险的事情。 window.MY_KEY='88******************2030' 有了这个密钥后,访问 「地图服务清单」(http://lbs.tianditu.gov.cn/server/MapService.html),查看天地图提供的各类地图服务: 各类地图瓦片、标注瓦片,应有尽有。 通过这些提供的瓦片,你将可以快速搭建一个完全免费、且完全权威的地图页面,并且把业务数据展示其上。 四、用引擎显示地图3.1 安装地图引擎按照本文第 1.4 节【一个简单的选择原则】中所说,我们要使用 「天地图」 的瓦片,因此我们选用 maplibre-gl: yarnaddmaplibre-gl@latest 或者通过 cdn 的形式完成代码引入。 scriptsrc='https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.js'/script linkhref='https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.css'rel='stylesheet'/ 3.1 渲染天地图瓦片的地图在 mapbox 的设计思路中,“地图” 是一个对象,你可以通过使用如下 API 快速初始化一个地图实例: template divref="mapEl"class="map"/div /template scriptsetup importmapboxglfrom'maplibre-gl'; import'maplibre-gl/dist/maplibre-gl.css'; import{onMounted,ref}from'vue' constmapEl=ref(null) constinitOption={ style:{ "version":8, "id":"43f36e14-e3f5-43c1-84c0-50a9c80dc5c7", "sources":{ "tdt-vec":{ "type":"raster", "tiles":[`https://t0.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=${MY_KEY}`], "tileSize":256 } }, "layers":[{ "id":"tdt-tiles-layer", "type":"raster", "source":"tdt-vec", }] }, } onMounted(()={ constmap=newmapboxgl.Map({ container:mapEl.value, ...initOption, }) /script stylelang="scss"scoped .map{ width:600px; height:300px; } /style 通过以上代码,就能快速渲染一个基于 「墨卡托投影」、「天地图瓦片」 的平面 「瓦片风」 二维地图。 发现没,不仅可以正确加载天地图的瓦片服务,还可以完成 2.5D 的视角倾斜。 上面代码中,所做的,正是简单生成了一个地图实例,其中最核心的代码在这里: "tiles":[`https://t0.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=${MY_KEY}`], 声明了天地图瓦片资源的请求方式。 在码上掘金中你也可以试试: 代码片段 效果实现了,代码有了,但你想必还是一脸懵逼: ?为什么要这么写呢? ?这要说到 mapbox 系框架的基本 API 思路了:「图层与资源」。 图层(Layers): 我们所能看到的绝大部分内容都属于图层,这和 PhotoShop 里的图层概念很相似,图层间有层级关系;图层上可以设置各种布局(layout)属性和绘制(paint)属性,用来规定自己的显示特点。但归根结底,一张图层上显示什么,还是取决于它所引用的 「资源(source)」。 资源(Sources): 瓦片是资源,GeoJSON是资源,图片也是资源。资源是影响显示的第一要素。 所以,我们可以理解,如果在 mapbox 系中,要显示一个内容,起码需要两步: //step1:添加资源 map.addSource(...) //step2:添加图层 map.addLayer(...) 当然,上面生效的这段代码,是通过在初始化阶段把 「资源」 和 「图层」 注入到了地图实例当中,我们完全可以换一种写法,同样能实现相关功能: map.on('load',()={ map.addSource('tdt-vec',{ "type":"raster", "tiles":[`https://t0.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=${MY_KEY}`], "tileSize":256 }) map.addLayer({ "id":'tdt-tiles-layer', "type":"raster", "source":"tdt-vec", }) }) 思路上是一致,只是添加资源及图层的时机不同罢了。 3.2 添加标注层只有地理瓦片,对于很多人而言依然不足以表达出足够的地理信息,比如: ?当前看到的是什么省、什么市、什么街道? ?因此,在一张健全的地图上,「地图标注」 也是必要而关键的。 在 3.1 节示例代码的基础上,我们按照解释说明的思路,再添加 「一个标注资源」 和 「一个标注图层」: "sources":{ //...上一节内容省略 "tdt-cva":{ "type":"raster", "tiles":[`https://t0.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=${MY_KEY}`], "tileSize":256 } }, "layers":[ //...上一节内容省略 { "id":"tdt-cva-layer", "type":"raster", "source":"tdt-cva", }, ] 这样一来,我们的地图就不再单调了: 在码上掘金里亲手尝试吧: 代码片段 3.3 对地图颜色进行微调通常来说,大屏是以深色作为主色调的,目前市面上最常见的大屏主题,前三排名为: 科技蓝科技蓝还TM是科技蓝因此,如果地图底色过于鲜亮,可能会和 「科技蓝」 风格不搭,此时,你可以选择通过 layers.raster.paint 提供的一些配置,进行色相转换,满足自己的审美诉求。 比如,修改底图 layer 为: { "id":"tdt-tiles-layer", "type":"raster", "source":"tdt-vec", "paint":{ "raster-brightness-max":0.7,//最大亮度 "raster-brightness-min":0.3,//最小亮度 "raster-hue-rotate":20,//色相变换的角度 "raster-saturation":0.7//饱和度 } }, 如果这种风格还不能满足你的诉求,你可以选择 "天地图 影像底图" 作为背景进行展示,修改底图和标注的来源为: "tdt-vec":{ "type":"raster", "tiles":[`https://t0.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=${MY_KEY}`], "tileSize":256 }, "tdt-cva":{ "type":"raster", "tiles":[`https://t0.tianditu.gov.cn/cia_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=${MY_KEY}`], "tileSize":256 } 两相对比: 很显然,影像底图会具备更好的在大屏上展示的效果。 四、加载业务信息甲方要的不是世界地图,而是业务地图。 没有业务属性的地图,对于甲方而言,并无价值。 4.1 加载多边形块假设我在地图上绘制了两个多边形,形成了一个 FeatureCollection 的 GeoJSON 数据。 ?你问我什么是 GeoJSON ? 你是不是还没看过上一篇基础知识篇?看紧去补补:《前端开发大屏地图?必知必会的基本知识》 ?那么,我应该如何把它们在地图上绘制出来,表现出两块区域的形状呢? map.on('style.load',()={ map.addSource('geojson-area-source',{ type:'geojson', data:geojsonArea//你得到的geojson }) map.addLayer({ id:'geojson-area-layer', type:'fill', source:'geojson-area-source', layout:{}, paint:{ 'fill-color':'red', 'fill-opacity':0.5, }, }) }) 没错,就是这么容易,还是我们之前总结的两步走: 添加资源添加图层4.2 加载图标及文本假设,我们现在又 3 位靓仔正在地图上玩躲猫猫,我们希望标注出他们的位置,以及名称,我们应该怎么做? 记住两步走的法则:「先加资源,再加图层」。 资源1:头像分别创建了三个人的头像: { zhuren:'https://pic.zhangshichun.top/pic/20221129-12.png' bao:'https://pic.zhangshichun.top/pic/20221129-10.png' nan:'https://pic.zhangshichun.top/pic/20221129-11.png' } 资源2:三位靓仔的坐标和信息{ "type":"FeatureCollection", "features":[ { "type":"Feature", "properties":{ "name":"德育处主任", "icon":"zhuren" }, "geometry":{ "coordinates":[ 114.34495622042738, 30.51879704948628 ], "type":"Point" } }, { "type":"Feature", "properties":{ "name":"战场小包", "icon":"bao" }, "geometry":{ "coordinates":[ 114.46248908403493, 30.52385942598788 ], "type":"Point" } }, { "type":"Feature", "properties":{ "name":"南方者", "icon":"nan" }, "geometry":{ "coordinates":[ 114.4188340204089, 30.481906063384173 ], "type":"Point" } } ] } 开始编码! 首先,先定义一个方法,简化 maplibre 的挂在图片的逻辑: //注册图片的方法 constloadImages=async(imgs)={ awaitPromise.all( Object.entries(imgs).map( ([key,url])= newPromise((resolve)={ map.loadImage(url,(error,res)={ if(error)throwerror; map.addImage(key,res); resolve(res); }), ), }; 然后,两步走(先加资源,再加图层): //加载图片 awaitloadImages(images) //添加位置资源 map.addSource('boys-source',{ type:'geojson', data:boys }) //添加ICON图层 map.addLayer({ id:'boys-icon-layer', type:'symbol', source:'boys-source', layout:{ 'icon-image':'{icon}', 'icon-size':0.2, 'icon-anchor':'center', 'icon-rotation-alignment':'viewport', 'icon-allow-overlap':true } }) //添加名字图层 map.addLayer({ id:'boys-name-layer', "type":"symbol", source:'boys-source', "layout":{ "text-field":'{name}', "text-size":14, 'text-offset':[0,2.4],//名字要设置便宜,避免被头像挡住 'text-allow-overlap':true }, "paint":{ "text-color":"white", }, }) 效果达成: 可以在码上掘金里亲自尝试: 代码片段 总体上来说,业务信息的加载,都是同样的逻辑,只要记住两步走的基本方针,就能完成绝大多数的业务需求。 五、总结在本篇文章,我们系统性地了解了: mapbox-gl 和 maplibre-gl 两个库的使用范畴。学习了天地图的使用方法并且实战了几个简单的业务场景碰到 「瓦片风」 的大屏地图开发,想必不会再难倒你了。 下一章,我们将继续学习如何开发 「线框风」 的大屏地图! 如果文章对你有帮助的话欢迎「关注+点赞+收藏」 阅读原文

上一篇:2023-03-30_一夜爆红,教皇,你是懂时尚的!Midjourney 太牛啦! 下一篇:2025-06-29_打破长视频理解瓶颈:HoPE混合位置编码提升VLM长度泛化能力

TAG标签:

15
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设网站改版域名注册主机空间手机网站建设网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。
项目经理在线

相关阅读 更多>>

猜您喜欢更多>>

我们已经准备好了,你呢?
2022我们与您携手共赢,为您的企业营销保驾护航!

不达标就退款

高性价比建站

免费网站代备案

1对1原创设计服务

7×24小时售后支持

 

全国免费咨询:

13245491521

业务咨询:13245491521 / 13245491521

节假值班:13245491521()

联系地址:

Copyright © 2019-2025      ICP备案:沪ICP备19027192号-6 法律顾问:律师XXX支持

在线
客服

技术在线服务时间:9:00-20:00

在网站开发,您对接的直接是技术员,而非客服传话!

电话
咨询

13245491521
7*24小时客服热线

13245491521
项目经理手机

微信
咨询

加微信获取报价