共计 9337 个字符,预计需要花费 24 分钟才能阅读完成。
记一次前端 ” 揭开绘制地图的神秘面纱 ” 分享会
记录了我在组内的技术分享, 有同样需要的同学能够参考一下
分享全程下来工夫大概 70 分钟
一. 为什么要分享前端相干的 ” 地图 ” 常识
- (大屏展现)很多公司都会有相应的大屏幕展现零碎, 例如中国或者全世界的客户与资产分布图.
- (活泼描述)用地图的角度来展现天文方面的关系, 让人看着比单纯的文字更直观
- (场景多)比方往年的各类疫情重大状况的分布图.
- 总的来说还是看起来比拟炫酷, 能够晋升一点点 b 格, 并且这个只是也是属于前端的领域, 那么咱们就有必要弄懂它.
二. 做地图相干技术简介
这里我只介绍几款我罕用的
** 百度地图
这个名气太大了, 性能很多并且当初对 3d 的反对也很不错, 留神 GL 版 v1.0 与之前 v2.0 版本地图的 api 有点不一样别掉坑里.
毛病也比拟显著, 比方你想要一份干干净净的地图, 下面没有店铺没有任何标识的时候我就倡议你用 echarts 来玩了, 因为百度地图带的货色比拟多.
想要应用百度地图的同学能够看这里, 超级简略就能够实现注册用游玩.
应用非常简单
** hcharts
十分牛十分好用, 然而它局部性能是要免费的, 应用之前要让公司帮你买好相应的性能能力用于商用哦.
因为咱们公司地图库是本人研发的最初也就没有这种网上付费的.
详情地址
** echarts
这个库前端无人不知了, 在需要很简略的状况下倡议用这个技术来做, 大部分时候我的项目中须要绘制柱状图或折线图的时候曾经引入了 echarts 此时不必反复援用来节俭空间.
echarts 画的地图
** 咱们公司本人的 2d, 3d 地图组件库
这个在这里就不做过多具体介绍了, 一些公司也会有自主研发的地图组件, 设计的思维上可能与下面三个不太雷同, 接下来我也会聊到.
三.echarts 实现根底地图
以 echarts 为例是因为这个最好弄 …
这里我新建了一个 vue 工程
<template>
<div class="home">
<div id="map"></div>
</div>
</template>
<script>
import echarts from "echarts";
import mapData from "./geo";
export default {
name: "Home",
data() {
return {myChart: null,};
},
methods: {initMap() {this.myChart = echarts.init(document.getElementById("map"));
echarts.registerMap("world", mapData); // 定义名称上面要用, 这样做的益处就是能够很不便的实现切换地图的成果
this.myChart.setOption({
series: [
{
type: "map",
mapType: "world", // 自定义扩大图表类型
label: {show: false,},
},
],
});
},
},
mounted() {this.initMap();
}
};
</script>
- 像咱们平时应用 echarts 一样先初始化
- 接下来有点不同须要
echarts.registerMap("world", mapData);
能够了解为把这个数据命名为 ’world’, 不便当前的切换(这里的数据我上面会讲). - 在 option 的配置外面设置类型是地图, 应用下面定义好的 ’world’ 类型.
效果图
咱们能够看得出来, 地图的绘制也没什么 ’ 非凡 ’ 的, 最次要的就是那个 mapData
数据, 这个数据个别叫它 geojson 数据, 那么接下来咱们认识一下它.
四.geojson 数据到底是什么
- geojson 是用 json 的语法表白和存储天文数据,能够说是 json 的子集, 它不是专门 js 应用的这点要分明.
- 地图上有山川, 河流, 陆地等等的地理信息, 那么如何形容一条河? 这个时候就要应用 geojson 格局的文件来描述.
- 并不是必须用 geojson, geojson 只是一套标准, 各大解析器用这套标准来解析生成对应的风景, 咱们齐全能够制订本人的标准来实现这些, 无非是兼容性不好须要本人写绘制的解析器.
五.geojson 具体介绍
英语好的能够先撸网站
1. 根本构造
{ // 能够包含点线面, 一个大的汇合
"type": "FeatureCollection", // 定义这个是个 geojson 文件, 这里还能够是其余值上面会说
"features": [] // 这里放要绘制的数据}
当前咱们看到 "type": "FeatureCollection"
这样一行就阐明这个文件是 geojson 标准的文件
2. 形容一个点 (Feature)
地图上的打点数据
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature", // 示意这个对象是一个因素
"properties": {}, // 这里放款式, 前面会专门说
"geometry": { // 这外面放具体的数据
"type": "Point", // 专指画点
"coordinates": [105.380859375, 31.57853542647338] // 默认是经度与纬度, 三维的话就是 xyz 三个值, 当然这里也不肯定是经纬度 (不同的坐标体系) 中会讲为什么
}
},
]
}
3. 形容多个点(FeatureCollection)
** 长处
- 写法简洁
- 这些点款式能够共用
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "MultiPoint", // 多点, 也就是间断画多个同样的点
"coordinates": [[105.380859375, 31.57853542647338],
[105.580859375, 31.52853542647338]
]
}
},
]
}
4. 形容一条线(LineString)
- 这里还是描述每一个点, 但这些点会连贯在一起造成线
- 地图上的连线数据
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "LineString", // 这里所有的点会连贯在一起造成线
"coordinates": [[105.6005859375, 30.65681556429287],
[107.95166015624999, 31.98944183792288],
[109.3798828125, 30.031055426540206],
[107.7978515625, 29.935895213372444]]
}
},
]
}
5. 形容多条线(MultiLineString)
- 这里第二组与第一组的线, 能够分隔开不会首尾相连.
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "MultiLineString",
"coordinates":
[
[[105.6005859375, 30.65681556429287],
[107.95166015624999, 31.98944183792288],
[109.3798828125, 30.031055426540206],
[107.7978515625, 29.935895213372444]
],
[[109.3798828125, 30.031055426540206],
[107.1978515625, 31.235895213372444]
]
]
}
},
]
}
6. 形容一个面(Polygon, 也叫多边形)
- 第一个点与最初一个点要雷同, 这样能力实现闭环!!
- 三维数组的格局须要留神
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon", // 留神这里是三维数组
"coordinates": [
[[106.10595703125, 33.33970700424026],
[106.32568359375, 32.41706632846282],
[108.03955078125, 32.2313896627376],
[108.25927734375, 33.15594830078649],
[106.10595703125, 33.33970700424026]
]
]
}
},
]
}
7. 一个面外面有多个面(Polygon)
- 这种繁多的 ’Polygon’ 外面呈现多个形态, 会呈现中空的状况, 相似布尔运算, 这样就能够在地图中形容那种圈型的国家
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-39.7265625,
-3.162455530237848
],
[
127.96875,
-3.162455530237848
],
[
127.96875,
74.1160468394894
],
[
-39.7265625,
74.1160468394894
],
[
-39.7265625,
-3.162455530237848
]
],
[
[
-22.5,
15.961329081596647
],
[
110.74218749999999,
15.961329081596647
],
[
110.74218749999999,
70.8446726342528
],
[
-22.5,
70.8446726342528
],
[
-22.5,
15.961329081596647
]
]
]
}
}
]
}
成果如下:
8. 形容多个面 (MultiPolygon)
劣势:
- 写法简洁
- 这些点款式能够共用
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[
-39.7265625,
-3.162455530237848
],
[
127.96875,
-3.162455530237848
],
[
127.96875,
74.1160468394894
],
[
-39.7265625,
74.1160468394894
],
[
-39.7265625,
-3.162455530237848
]
]
],
[
[
[
-22.5,
15.961329081596647
],
[
110.74218749999999,
15.961329081596647
],
[
110.74218749999999,
70.8446726342528
],
[
-22.5,
70.8446726342528
],
[
-22.5,
15.961329081596647
]
]
]
]
}
}
]
}
这里如果重叠了就是色彩的叠加了如图所示:
9. 形容一个组(geometries)
- 比方咱们为了示意一种特定的地貌那么咱们能够把这个地貌数据独立起来
{
"type": "FeatureCollection",
"features": [
{ // 能够包含点线面, 一个独立的汇合
"type": "GeometryCollection",
"geometries": [
{
"type": "Point",
"coordinates": [108.62, 31.02819]
}, {
"type": "LineString",
"coordinates": [[108.896484375, 30.1071178870],
[108.2184375, 30.91717870],
[109.5184375, 31.2175780]]
}
]
}
]
}
10. 不同的款式(properties)
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": { // 专门放属性
"stroke": "#fa9661", // 外边色彩
"stroke-width": 4.1, // 外边宽
"stroke-opacity": 0.7, // 外边透明度
"fill": "#9e290c", // 填充色
"fill-opacity": 0.7 // 填充色透明度
},
"geometry": {
"type": "Point", // 画点
"coordinates": [105.380859375, 31.57853542647338]
}
},
]
}
六. geojson 的相干网站与工具的应用
** 展现水灵灵的数据大家看着不起劲, 这里我举荐一个绘制 geojson 的超棒网站地址
那么我来介绍一下如何应用这个网站高效的生成, 以及调试 geojson
- 也就是最初生成的 geojson, 这里的变动能够实时影响图像, 并且会有谬误提醒很不便编写.
- 绘制直线
- 绘制多边形也就是面, 这里留神要首位相连.
- 绘制矩形, 这里应该是专门封装的办法绘制矩形.
- 绘制点, 这里会为咱们在地图上 mark 一下, 具体的图片须要咱们本人在我的项目中援用.
- 点击之后进入编辑模式, 鼠标在图形上会呈现小手标识, 此时能够拖动图形挪动, 操作能够抉择是否保留.
- 删除模式, 点击能够删除指定图形, 操作能够抉择是否保留.
单击图形能够呈现如图所示的操作框.
- 增加款式属性, 上方展现的是以后款式属性
- 保留你的更改
- 删除这个图形
- 点击 open 能够应用本地的 geojson 文件进行导入绘制.
- save 上面点击 geojson 能够把生成的代码文件下载到本地.
七. 自制 geojson 解析绘制工具的思路
- 咱们能够只做一个转换器, 也就是你轻易写认为不错的格局, 最初转换成 geojson 的格局.
- 间接用你喜爱的格局来绘制图形
- 如果用 canvas 来实现就是绘制对应的图形就好了, 就是图形叠加那里须要非凡解决一下, 款式间接读取 properties 外面的数据进行设置.
- 绘制经纬度也是个问题, 毕竟在立体上不好计算经纬度(接下地图绘制章节会讲相干常识).
- 所以综上看来是不是绘制一张立体版的地图也没那么艰难, 只有数据对了就胜利一小半了.
八. 地图的基本概念 (瓦片地图, 矢量地图)
** 有没有发现咱们应用的地图在放大的时候, 区域都是一个方块一个方块的被加载成图像的.
** 如果你关上控制台的 network 还能够看到有好多 png 的申请.
** 地图这种超大的数据, 超多细节是如何做到疾速渲染的?
** 上面是当初比拟支流的两种地图的绘制模式.
栅格瓦片地图
顾名思义图片像是瓦片一样重叠起来的格子状成为地图, 有点像拼图, 是不是感觉一点也不高大上 ….
但这里也是有很多问题要解决的, 比方你在仰视世界的视角看地图, 那么呈现的就是世界的瓦片图片, 当高度小于肯定的数值时就采纳另一套相应的瓦片, 在某个高度范畴内是采纳放大瓦片图片的形式模仿视线的降落, 每次申请瓦片图片都须要传递: 1: 以后视口所在坐标(经纬度) 2: 以后视口宽高 3: 以后视角高度.
栅格瓦片以 256 256 或 512 512 大小的图片为介质,这种技术通常是在服务端事后将图片渲染好,前端依据地图的缩放等级,按需加载图片加以拼接,目前仍旧在大规模应用,但这种形式存在一些劣势:
受到网络带宽开销和存储空间限度的影响大,离线化部署老本高,单套主题将近 500 多 G(中国)。
款式编辑完后端渲染须要工夫长。
无三维的修建数据,在 3D 场景中无高度信息。
数据保密性差。
矢量地图
顾名思义就是矢量绘制出图形, 只有不是照片必定会小很多, 对于矢量为什么轻量并且不失真能够参考的上篇文章 svg 的分享 svg 实战
矢量瓦片采纳和栅格瓦片雷同的分级切割计划,不同的是,瓦片数据传输的是天文数据,包含路线、土地、修建等,通过在前端做地图的渲染,具备如下劣势:
极少占用服务器空间,升高网络开销,本地化部署只需 5G 空间 (中国)。
地图的底图款式更换简略.
因为具备了天文数据自身,可在数据根底上做三维空间的延长,例如 3D 修建。
数据保密性强。
九. 不同的坐标系
** 地球自身是个椭球体, 要把它以立体的形式绘制在一个矩形上也真的不好办, 当初有不少绘制的形式然而都有各自的优缺点, 感兴趣的敌人能够查查看具体的细节, 我这里就简略介绍下比拟常见的形式.
- 经纬度 EPSG:4326 也就是地图的默认坐标
当初球体上定义好经纬度, 而后在正方形纸上画出刻度, 对应的绘制 - 墨卡托投影 (EPSG:3785)
把地球放在一个圆筒外面, 假如地球外部有个光源, 那么地球在圆柱上的投影就是地图 - 火星坐标系
火星坐标是国家测绘局为了国家平安在原始坐标的根底上进行偏移失去的坐标,根本国内的电子地图、导航设施都是采纳的这一坐标系或在这一坐标的根底上进行二次加密失去的。
火星坐标的实在名称应该是 GCJ-02 坐标,基本上所有的国内的电子地图采纳的都是火星坐标系甚至 Google 地图中国局部都特意为中国政府做了偏移。
- 百度坐标系
火星坐标是在国际标准坐标 WGS-84 上进行的一次加密,因为国内的电子地图都要至多应用火星坐标进行一次加密,百度间接就任性一些,间接本人又钻研了一套加密算法,来了个 二次加密,这就是咱们所熟知的百度坐标 BD-09,当然只有百度地图应用的是百度坐标
- WGS-84 坐标系
GS-84 坐标是一个国内的规范,个别卫星导航,原始的 GPS 设施中的数据都是采纳这一坐标系。国外的 GoogleMap、OpenStreetMap、MapBox、OpenLayer 等采纳的都是这一坐标。
geojson 设置坐标系
因为坐标系的不同, 那么就算绘制一个点的坐标也都不会完全相同了, 那么就须要咱们来通知应用 geojson 的人按哪种坐标系进行解析
{
"type": "FeatureCollection",
"crs": {// 定义坐标系 (如果不写就是应用经纬度的坐标系) 默认为 EPSG:4326。"type": "name", // "type" 和 "properties"。为强制领有
"properties": {"name": "urn: ogc: def: crs: EPSG: 54013" // 这里定义具体的规定}
},
"features": [{},
]
}
应用上线的规定
{
"type": "FeatureCollection",
"crs": {
"type": "link", // 这里变成了 link
"properties": {
"href": "http://example.com/crs/42", // 这里是你设置的资源链接
"type": "proj4" // "proj4","ogcwkt",esriwkt" 只能这三种格局
}
},
"features": [{},
]
}
十. 更快的前端数据 -> WebAssembly
**WebAssembly 是一种新的编码方式,文件体积更小,启动速度更快,运行速度也更快,与应用 JavaScript 构建的 Web 利用相比,性能晋升显著。它是多种编程语言的编译器指标,包含 C ++、C、Rust 等。
WebAssembly 是由支流浏览器厂商组成的 W3C 社区个人 制订的一个新的标准。**
WebAssembly 能够显著的晋升计算的速率, 还挺适宜用在地图库外面的
- WebAssembly 和 JavaScript 联合应用, 短时间并不会代替 js
- .wasm 文件结尾的文件来标识.
- WebAssembly 有一套残缺的语义,实际上 wasm 是体积小且加载快的二进制格局,其指标就是充分发挥硬件能力以达到原生执行效率
WebAssembly 运行在一个沙箱化的执行环境中,甚至能够在现有的 JavaScript 虚拟机中实现。在 web 环境中,WebAssembly 将会严格遵守同源策略以及浏览器安全策略。
WebAssembly 设计了一个十分规整的文本格式用来、调试、测试、试验、优化、学习、教学或者编写程序。能够以这种文本格式在 web 页面上查看 wasm 模块的源码。
WebAssembly 在 web 中被设计成无版本、个性可测试、向后兼容的。WebAssembly 能够被 JavaScript 调用,进入 JavaScript 上下文,也能够像 Web API 一样调用浏览器的性能。当然,WebAssembly 不仅能够运行在浏览器上,也能够运行在非 web 环境下。 - 解析 – 解码 WebAssembly 比解析 JavaScript 要快
编译和优化 – 编译和优化所需的工夫较少,因为在将文件推送到服务器之前曾经进行了更多优化,JavaScript 须要为动静类型屡次编译代码
从新优化 – WebAssembly 代码不须要从新优化,因为编译器有足够的信息能够在第一次运行时取得正确的代码
执行 – 执行能够更快,WebAssembly 指令更靠近机器码
垃圾回收 – 目前 WebAssembly 不间接反对垃圾回收,垃圾回收都是手动管制的,所以比主动垃圾回收效率更高。目前浏览器中的 MVP(最小化可行产品)曾经很快了。在接下来的几年里,随着浏览器的倒退和新性能的减少,它将在将来几年内变得更快。
说了这些都是概念, 接下来咱们就一起实战一下 go
十一. hello 级别的 WebAssembly
中武官网
官网的实现还须要配置环境啥的搞得很正式, 入门级别其实咱们更想的是尝尝鲜, 只有你会点 c ++ 就能用我接下来的办法实现.
在线生成
在线生成
- 点击转换 c ++ 代码为 WebAssembly 格局
- 点击下载转换好的文件
- 下载到的是个二进制文件
援用文件
fetch("/test.wasm")
.then((res) => res.arrayBuffer()) // 拿到 Buffer 格局
.then((bytes) => WebAssembly.compile(bytes)) // 转字节码
.then((mod) => {const instance = new WebAssembly.Instance(mod);
const exp = instance.exports;
console.log(exp._Z7showNumv())
});
- exp._Z7showNumv 而不是 exp.showNum, 这个咱们能够在 Wat 那一栏批改一下, 然而代码多了批改起来也不容易应该有禁止转换时批改名称的选项这里就不过多开展了.
- 留神这里会跨域, 因为属于文件协定, 你能够本地启个服务.
开发成本
- 须要的不只是前端技术了.
- bug 略微有点多, 比方不好调试, 还有的同学遇到了每次编译后果不同等问题.
- 社区不欠缺
- 倡议这门技术先应用在封装度较高, 计算量很大的模块上.
十二.(组内篇)我写的 2d 与 3d 工程的代码介绍
这里我在组内展现一下我编写的两个我的项目的代码构造与遇到的问题, 就不在这里开展了毕竟波及窃密问题, 但大体思路就是把地图分成世界, 国家, 省, 市, 区 几个等级(省市区是中国的分法), 相当于一个状态机, 而后在每个状态下做相应的事比方打点与连线, 每次变换图层状态都会暗藏其余图层展现相应视线的图层.
end.
地图方面也属于前端比拟有用的一环, 我往年刚接触地图相干我的项目也是一脸蒙, 然而具体学习了 geojson 等常识之后再用地图相干组件库就十分顺畅了.
这次就是这样, 心愿和你一起提高.