image
** 百度地图 这个名气太大了, 功能很多并且现在对3d的支持也很不错, 注意GL版v1.0 与之前 v2.0版本地图的api有点不一样别掉坑里. 缺点也比较明显, 比如你想要一份干干净净的地图, 上面没有店铺没有任何标识的时候我就建议你用echarts来玩了, 因为百度地图带的东西比较多. 想要使用百度地图的同学可以看这里, 超级简单就可以完成注册用玩耍. 使用非常简单
** hcharts 非常牛非常好用, 但是它部分功能是要收费的, 使用之前要让公司帮你买好相应的功能才能用于商用哦. 由于我们公司地图库是自己研发的最后也就没有这种网上付费的. 详情地址
** echarts 这个库前端无人不知了, 在需求很简单的情况下建议用这个技术来做, 大部分时候项目中需要绘制柱状图或折线图的时候已经引入了echarts此时不用重复引用来节省空间. echarts画的地图
** 我们公司自己的2d, 3d地图组件库 这个在这里就不做过多详细介绍了, 一些公司也会有自主研发的地图组件, 设计的思想上可能与上面三个不太相同, 接下来我也会聊到.
这里我新建了一个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.registerMap("world", mapData);
可以理解为把这个数据命名为'world', 方便以后的切换(这里的数据我下面会讲).效果图
我们可以看得出来, 地图的绘制也没什么'特殊'的, 最主要的就是那个 mapData
数据, 这个数据一般叫它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)
{
"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
image
单击图形可以出现如图所示的操作框.
image
** 有没有发现咱们使用的地图在放大的时候,区域都是一个方块一个方块的被加载成图像的. ** 如果你打开控制台的network还可以看到有好多png的请求. ** 地图这种超大的数据, 超多细节是如何做到快速渲染的? ** 下面是现在比较主流的两种地图的绘制模式.
顾名思义图片像是瓦片一样堆叠起来的格子状成为地图, 有点像拼图, 是不是感觉一点也不高大上.... 但这里也是有很多问题要解决的, 比如你在俯视世界的视角看地图, 那么出现的就是世界的瓦片图片, 当高度小于一定的数值时就采用另一套相应的瓦片, 在某个高度范围内是采用放大瓦片图片的方式模拟视野的下降, 每次请求瓦片图片都需要传递: 1: 当前视口所在坐标(经纬度) 2: 当前视口宽高 3: 当前视角高度.
栅格瓦片以 256 256 或 512 512 大小的图片为介质,这种技术通常是在服务端预先将图片渲染好,前端根据地图的缩放等级,按需加载图片加以拼接,目前依旧在大规模使用,但这种方式存在一些劣势:
受到网络带宽开销和存储空间限制的影响大,离线化部署成本高,单套主题将近 500 多 G(中国)。 样式编辑完后端渲染需要时间长。 无三维的建筑数据,在 3D 场景中无高度信息。 数据保密性差。
顾名思义就是矢量绘制出图形, 只要不是照片肯定会小很多, 对于矢量为什么轻量并且不失真可以参考的上篇文章svg的分享svg实战
矢量瓦片采用和栅格瓦片相同的分级切割方案,不同的是,瓦片数据传输的是地理数据,包括道路、土地、建筑等,通过在前端做地图的渲染,具有如下优势:
极少占用服务器空间,降低网络开销,本地化部署只需5G空间(中国)。 地图的底图样式更换简单. 因为具有了地理数据本身,可在数据基础上做三维空间的延伸,例如 3D 建筑。 数据保密性强。
** 地球本身是个椭球体, 要把它以平面的方式绘制在一个矩形上也真的不好办, 现在有不少绘制的方式但是都有各自的优缺点, 感兴趣的朋友可以查查看具体的细节, 我这里就简单介绍下比较常见的方式.
火星坐标是国家测绘局为了国家安全在原始坐标的基础上进行偏移得到的坐标,基本国内的电子地图、导航设备都是采用的这一坐标系或在这一坐标的基础上进行二次加密得到的。 火星坐标的真实名称应该是 GCJ-02 坐标,基本上所有的国内的电子地图采用的都是火星坐标系甚至 Google 地图中国部分都特意为中国政府做了偏移。
火星坐标是在国际标准坐标 WGS-84 上进行的一次加密,由于国内的电子地图都要至少使用火星坐标进行一次加密,百度直接就任性一些,直接自己又研究了一套加密算法,来了个 二次加密,这就是我们所熟知的百度坐标 BD-09,当然只有百度地图使用的是百度坐标
1 . 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是一种新的编码方式,文件体积更小,启动速度更快,运行速度也更快,与使用JavaScript构建的Web应用相比,性能提升明显。它是多种编程语言的编译器目标,包括C++、C、Rust等。 WebAssembly 是由主流浏览器厂商组成的 W3C 社区团体 制定的一个新的规范。**
WebAssembly 可以明显的提升计算的速率, 还挺适合用在地图库里面的
编译和优化 - 编译和优化所需的时间较少,因为在将文件推送到服务器之前已经进行了更多优化,JavaScript 需要为动态类型多次编译代码 重新优化 - WebAssembly 代码不需要重新优化,因为编译器有足够的信息可以在第一次运行时获得正确的代码 执行 - 执行可以更快,WebAssembly 指令更接近机器码 垃圾回收 - 目前 WebAssembly 不直接支持垃圾回收,垃圾回收都是手动控制的,所以比自动垃圾回收效率更高。目前浏览器中的 MVP(最小化可行产品) 已经很快了。在接下来的几年里,随着浏览器的发展和新功能的增加,它将在未来几年内变得更快。
说了这些都是概念, 接下来我们就一起实战一下go
中文官网 官网的实现还需要配置环境啥的搞得很正式, 入门级别其实我们更想的是尝尝鲜, 只要你会点c++就能用我接下来的方法实现.
在线生成 在线生成
image
引用文件
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())
});
开发成本
这里我在组内展示一下我编写的两个项目的代码结构与遇到的问题, 就不在这里展开了毕竟涉及保密问题, 但大体思路就是把地图分成世界, 国家, 省, 市, 区 几个等级(省市区是中国的分法), 相当于一个状态机, 然后在每个状态下做相应的事比如打点与连线, 每次变换图层状态都会隐藏其他图层展示相应视野的图层.
地图方面也属于前端比较有用的一环, 我今年刚接触地图相关项目也是一脸蒙, 但是详细学习了geojson等知识之后再用地图相关组件库就非常顺畅了. 这次就是这样, 希望和你一起进步.
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8