今天跟大家分享一下popup、标注、以及canvas,到这里基本上mapbox的基本内容也就告一段落,后续根据我在工作中遇到的问题再做相关的分享。
一、标注(marker)
Markers and controls | Mapbox GL JS | Mapbox
首先记住标记不是图层,他只是作为一个单独的对象,被添加到地图上了。
核心api
marker.addTo(map); | 地图添加标记 |
marker.remove(); | 移除标记 |
1、如何向地图添加标记
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>Document</title>
<!-- 导入依赖 -->
<!-- openlayer mapbox cesium js+css -->
<script src="https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.js"></script>
<link
href="https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.css"
rel="stylesheet"
/>
<script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.2.2/mapbox-gl-draw.js"></script>
<link
rel="stylesheet"
href="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.2.2/mapbox-gl-draw.css"
type="text/css"
/>
<style>
* {
margin: 0;
padding: 0;
}
#map {
width: 100vw;
height: 100vh;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
//token
mapboxgl.accessToken = '你的token'
const gaode = {
version: 8,
sources: {
'raster-tiles': {
type: 'raster',
tiles: ['http://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}'],
tileSize: 256
}
},
layers: [
{
id: 'simple-tiles',
type: 'raster',
source: 'raster-tiles',
minzoom: 0,
maxzoom: 22
}
]
}
const map = new mapboxgl.Map({
container: 'map', // container ID
style: gaode, // style URL
center: [114.3, 30.5], // starting position [lng, lat]
zoom: 9 // starting zoom
})
const marker = new mapboxgl.Marker({
//标记颜色
color: 'red',
//标记是否可以拖动
draggable: true
})
.setLngLat([114.3, 30.5])//设置标记坐标
.addTo(map)//向地图添加标记
//监听标记
marker.on('dragend', function () {
//打印标记坐标
console.log(marker.getLngLat())
})
</script>
</body>
</html>
2、自定义标记
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>Document</title>
<!-- 导入依赖 -->
<!-- openlayer mapbox cesium js+css -->
<script src="https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.js"></script>
<link
href="https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.css"
rel="stylesheet"
/>
<script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.2.2/mapbox-gl-draw.js"></script>
<link
rel="stylesheet"
href="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.2.2/mapbox-gl-draw.css"
type="text/css"
/>
<style>
* {
margin: 0;
padding: 0;
}
#map {
width: 100vw;
height: 100vh;
}
//标记样式
#marker {
width: 100px;
height: 100px;
background-color: #333;
border-radius: 50%;
color: #fff;
line-height: 100px;
text-align: center;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
//token
mapboxgl.accessToken = '你的token'
const gaode = {
version: 8,
sources: {
'raster-tiles': {
type: 'raster',
tiles: ['http://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}'],
tileSize: 256
}
},
layers: [
{
id: 'simple-tiles',
type: 'raster',
source: 'raster-tiles',
minzoom: 0,
maxzoom: 22
}
]
}
const map = new mapboxgl.Map({
container: 'map', // container ID
style: gaode, // style URL
center: [114.3, 30.5], // starting position [lng, lat]
zoom: 9 // starting zoom
})
//创建标记
let element = document.createElement('div')
element.id = 'marker'
element.innerHTML = 'marker'
const marker = new mapboxgl.Marker(
//将自定义标记添加到marker中
element,
color: 'red',
draggable: true
).setLngLat([114.3, 30.5]).addTo(map)
map.on('click', (e) => {
//清除标记
marker.remove()
})
</script>
</body>
</html>
3、一次性清除所有标注
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link href="https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.js"></script>
<script src='https://lib.baomitu.com/jquery/3.6.3/jquery.min.js'></script>
<style>
html,
body {
overflow: hidden;
margin: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
#marker {
background-image: url('https://img.gejiba.com/images/db6e7706e2c3dcae834e44b0e888c767.jpg');
background-size: cover;
width: 50px;
height: 50px;
border-radius: 50%;
cursor: pointer;
}
#clear {
position: absolute;
z-index: 100;
right: 10px;
top: 10px;
height: 50px;
width: 200px;
}
</style>
</head>
<body>
<button id="clear">清除所有标记</button>
<div id="map"></div>
<script>
mapboxgl.accessToken = '你的token';
const map = new mapboxgl.Map({
container: 'map', // container ID
style: 'mapbox://styles/mapbox/streets-v12', // style URL
center: [114.30, 30.50],
zoom: 12,
projection: 'globe'
});
var labels = []
function addLabel(center) {
let marker = new mapboxgl.Marker({
draggable: true,
}).setLngLat(center);
labels.push(marker);
marker.addTo(map);
}
map.on("click", (evt) => {
// addLabel();
var { lng, lat } = evt.lngLat;
var center = [lng, lat]
addLabel(center)
});
$("#clear").click(function () {
labels.forEach(item => {
item.remove()
})
})
</script>
</body>
</html>
二、popup
Markers and controls | Mapbox GL JS | Mapbox
1、popup和marker结合使用
var popup = new mapboxgl.Popup({ offset: 25 }).setText("中地数码");
var marker = new mapboxgl.Marker({
color: "#652e80"
}).setLngLat([114.30, 30.50]).setPopup(popup);
map.on("load", () => {
marker.addTo(map)
});
2、属性
offset | 偏移 |
closeButton | 默认是true |
3、方法
setText() | 设置文字 |
setHTML() | 可以写html结构 |
setLngLat() | 设置经纬度 |
addTo() | 添加到地图 |
4、例子
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Create a hover effect</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<link href="https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.js"></script>
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
// TO MAKE THE MAP APPEAR YOU MUST
// ADD YOUR ACCESS TOKEN FROM
// https://account.mapbox.com
mapboxgl.accessToken = '你的token';
const map = new mapboxgl.Map({
container: 'map',
// Choose from Mapbox's core styles, or make your own style with Mapbox Studio
style: 'mapbox://styles/mapbox/streets-v12',
center: [114.30, 30.50],
zoom: 4
});
let hoveredStateId = null;
var data = {
type: "FeatureCollection",
features: [
{
type: 'Feature',
geometry: {
type: "Point",
coordinates: [114.30, 30.50]
},
properties: {
id: 1001,
name: "武昌"
}
},
{
type: 'Feature',
geometry: {
type: "Point",
coordinates: [114.30, 31.50]
},
properties: {
id: 1002,
name: "汉阳"
}
}
]
}
map.on('load', () => {
map.setFog({
})
map.addLayer({
id: "city",
type: "circle",
source: {
type: "geojson",
data
},
paint: {
'circle-color': "#ff2d51",
'circle-radius': 10
}
})
map.on("click", "city", evt => {
console.log(evt.features[0]);
if (evt) {
var feature = evt.features[0]
var name = feature.properties.name;
var center = feature.geometry.coordinates;
let popup = new mapboxgl.Popup()
.setText(name)
.setLngLat(center)
.addTo(map);
}
})
});
</script>
</body>
</html>
三、layout——自定义图层样式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 导入依赖 -->
<script src='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.js'></script>
<link href='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.css' rel='stylesheet' />
<style>
* {
margin: 0;
padding: 0;
}
#map {
width: 100vw;
height: 100vh;
}
</style>
</head>
<body>
<div id="map">
</div>
<script>
/* token */
mapboxgl.accessToken = '你的token'
/* 实例化地图 */
const map = new mapboxgl.Map({
/* ol target */
container: 'map', // container ID
/* style--layers 图层 */
/* vue2 data vue3 ref */
style: 'mapbox://styles/mapbox/streets-v12', // style URL
center: [114.30, 30.50], // starting position [lng, lat]
zoom: 1 // starting zoom
});
let data = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Point",
"coordinates": [114.562025, 30.820826]
}
}
]
}
map.on('load', () => {
/* 1、加载图片 */
map.loadImage('/data/位置.png', (error, image) => {
if (error) throw error;
map.addImage('icon-style', image); //样式设置给图层
/* layout {'icon-image':'icon-style'} */
map.addSource("source", {
type: "geojson",
data
})
map.addLayer({
id: "layer",
source: "source",
type: "symbol",
layout: {
// 加载图片的id
"icon-image": "icon-style",
}
})
})
})
</script>
</body>
</html>
四、canvas动画
1、设置canvas动画
核心逻辑:把canvas动画与layout结合添加到图层中设置图层样式
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Add an animated icon to the map</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<link href="https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.js"></script>
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
mapboxgl.accessToken = '你的token';
const map = new mapboxgl.Map({
container: 'map',
center: [114.30, 30.50],
zoom: 2,
// Choose from Mapbox's core styles, or make your own style with Mapbox Studio
style: 'mapbox://styles/mapbox/streets-v12'
});
const size = 200;
// This implements `StyleImageInterface`
// to draw a pulsing dot icon on the map.
const pulsingDot = {
width: size,
height: size,
data: new Uint8Array(size * size * 4),
// When the layer is added to the map,
// get the rendering context for the map canvas.
onAdd: function () {
const canvas = document.createElement('canvas');
canvas.width = this.width;
canvas.height = this.height;
this.context = canvas.getContext('2d');
},
// Call once before every frame where the icon will be used.
render: function () {
const duration = 1000;
const t = (performance.now() % duration) / duration;
const radius = (size / 2) * 0.3;
const outerRadius = (size / 2) * 0.7 * t + radius;
const context = this.context;
// Draw the outer circle.
context.clearRect(0, 0, this.width, this.height);
context.beginPath();
context.arc(
this.width / 2,
this.height / 2,
outerRadius,
0,
Math.PI * 2
);
context.fillStyle = `rgba(255, 200, 200, ${1 - t})`;
context.fill();
// Draw the inner circle.
context.beginPath();
context.arc(
this.width / 2,
this.height / 2,
radius,
0,
Math.PI * 2
);
context.fillStyle = 'rgba(255, 100, 100, 1)';
context.strokeStyle = 'white';
context.lineWidth = 2 + 4 * (1 - t);
context.fill();
context.stroke();
// Update this image's data with data from the canvas.
this.data = context.getImageData(
0,
0,
this.width,
this.height
).data;
// Continuously repaint the map, resulting
// in the smooth animation of the dot.
map.triggerRepaint();
// Return `true` to let the map know that the image was updated.
return true;
}
};
map.on('load', () => {
map.addImage('pulsing-dot', pulsingDot, { pixelRatio: 2 });
map.addSource('dot-point', {
'type': 'geojson',
'data': {
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [114.30, 30.50] // icon position [lng, lat]
}
}
]
}
});
map.addLayer({
'id': 'layer-with-pulsing-dot',
'type': 'symbol',
'source': 'dot-point',
'layout': {
'icon-image': 'pulsing-dot'
}
});
});
</script>
</body>
</html>
2、封装canvas动画
function setCanvasStyle({
map,
size
}) {
// This implements `StyleImageInterface`
// to draw a pulsing dot icon on the map.
const pulsingDot = {
width: size,
height: size,
data: new Uint8Array(size * size * 4),
// When the layer is added to the map,
// get the rendering context for the map canvas.
onAdd: function () {
const canvas = document.createElement('canvas');
canvas.width = this.width;
canvas.height = this.height;
this.context = canvas.getContext('2d');
},
// Call once before every frame where the icon will be used.
render: function () {
const duration = 1000;
const t = (performance.now() % duration) / duration;
const radius = (size / 2) * 0.3;
const outerRadius = (size / 2) * 0.7 * t + radius;
const context = this.context;
// Draw the outer circle.
context.clearRect(0, 0, this.width, this.height);
context.beginPath();
context.arc(
this.width / 2,
this.height / 2,
outerRadius,
0,
Math.PI * 2
);
context.fillStyle = `rgba(255, 200, 200, ${1 - t})`;
context.fill();
// Draw the inner circle.
context.beginPath();
context.arc(
this.width / 2,
this.height / 2,
radius,
0,
Math.PI * 2
);
context.fillStyle = 'rgba(255, 100, 100, 1)';
context.strokeStyle = 'white';
context.lineWidth = 2 + 4 * (1 - t);
context.fill();
context.stroke();
// Update this image's data with data from the canvas.
this.data = context.getImageData(
0,
0,
this.width,
this.height
).data;
// Continuously repaint the map, resulting
// in the smooth animation of the dot.
/* map.render() */
map.triggerRepaint();
// Return `true` to let the map know that the image was updated.
return true;
}
};
map.addImage('canvas-style', pulsingDot, { pixelRatio: 2 });
}
3、通过点击事件添加canvas动画
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 1、导入mapbox的依赖 js+css -->
<script src='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.js'></script>
<link href='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.css' rel='stylesheet' />
<script src="https://lib.baomitu.com/jquery/2.2.4/jquery.js"></script>
<script src="./utils/setCanvas.js"></script>
<style>
* {
margin: 0;
padding: 0
}
#map {
width: 100vw;
height: 100vh;
}
#clearAll {
position: fixed;
z-index: 100;
top: 10px;
right: 10px;
width: 200px;
height: 50px;
}
</style>
</head>
<body>
<button id="clearAll">清除所有的点</button>
<!-- 2、设置地图容器的挂载点 -->
<div id="map">
</div>
<script>
/* 3、实例化地图 */
mapboxgl.accessToken = '你的token';
const map = new mapboxgl.Map({
/* 将地图挂载到对应的DOM上 相当于ol的target */
container: "map",
/* 相当于ol的layers */
style: "mapbox://styles/mapbox/streets-v12",
center: [114.30, 30.50],
zoom: 6
})
let data = {
type: "FeatureCollection",
features: [
]
}
map.on("style.load", () => {
map.addImage('pulsing-dot', setCanvas({ map }), { pixelRatio: 2 });
map.setFog({
})
/* 空的图层 */
map.addSource("point-source", {
type: "geojson",
/* 相当于openlayers的features */
data
})
map.addLayer({
id: "point-layer",
'type': 'symbol',
source: "point-source",
'layout': {
'icon-image': 'pulsing-dot'
}
})
})
map.on("click", (evt) => {
var { lng, lat } = evt.lngLat;
let feature = {
type: "Feature",
geometry: {
type: "Point",
coordinates: [lng, lat]
}
}
data.features.push(feature);
/* 获取source */
let source = map.getSource("point-source")
/* setData 相当于openlayers addFeature */
source.setData(data);
})
$("#clearAll").click(function () {
let source = map.getSource("point-source")
data.features = [];
source.setData(data);
})
</script>
</body>
</html>
五、图文标注
1、map.loadImage()加载图片
2、map.addImage()添加图片
3、map.addLayer()添加图层
但是我觉得不好用,文字标注底图必须用mapbox官方的
map.on('load', () => {
map.loadImage('./images/police.png', (error, image) => {
if (error) throw error;
map.addImage('location', image);
map.addLayer({
"id": "points",
"type": "symbol",
"source": {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
// 图片在地图中的坐标
"coordinates": [114.30, 30.50]
}
}]
}
},
"layout": {
// 加载图片的id
"icon-image": "location",
"text-field": "测绘工程",
// 图片大小
"icon-size": 0.5,
// 设置图片偏移
"icon-offset": [0, 0]
}
});
})
})
六、控制图层的显示和隐藏
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link href="https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.js"></script>
<script src='https://lib.baomitu.com/jquery/2.2.4/jquery.js'></script>
<style>
html,
body {
overflow: hidden;
margin: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
mapboxgl.accessToken = '你的token';
const map = new mapboxgl.Map({
container: 'map', // container ID
style: 'mapbox://styles/mapbox/streets-v12', // style URL
center: [114.30, 30.50],
zoom: 12,
projection: 'globe'
});
map.on("load", function () {
map.addSource('point', {
type: 'geojson',
data: {
"type": "Feature",
"geometry": {
"type": 'Point',
"coordinates": [114.30, 30.50]
}
}
})
map.addLayer({
id: 'Point',
type: "circle",
//设置数据源
source: 'point',
//绘制参数
paint: {
'circle-opacity': 0.8,
"circle-radius": 15,
"circle-color": "#ff2d51",
"circle-stroke-width": 4,
//设置边线颜色
"circle-stroke-color": '#ffcc33',
'circle-opacity': 0.5
},
layout: {
'visibility': "visible"
}
})
})
map.on("click", () => {
let result = map.getLayoutProperty("Point", "visibility");
if (result == "visible") {
map.setLayoutProperty("Point", "visibility", "none");
} else {
map.setLayoutProperty("Point", "visibility", "visible");
}
})
</script>
</body>
</html>
七、空间分析
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 1、导入依赖 -->
<script src='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.js'></script>
<link href='https://api.mapbox.com/mapbox-gl-js/v2.12.0/mapbox-gl.css' rel='stylesheet' />
<!-- 导入画笔 -->
<link rel="stylesheet"
href="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.4.0/mapbox-gl-draw.css" />
<script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.4.0/mapbox-gl-draw.js"></script>
<script src="https://lib.baomitu.com/jquery/2.2.4/jquery.js"></script>
<script src="https://lib.baomitu.com/Turf.js/latest/turf.min.js"></script>
<style>
* {
margin: 0;
padding: 0
}
#map {
width: 100vw;
height: 100vh;
}
#activeDraw {
width: 200px;
height: 50px;
position: fixed;
top: 20px;
left: 50px;
z-index: 100;
}
#clearDraw {
width: 200px;
height: 50px;
position: fixed;
top: 20px;
left: 250px;
z-index: 100;
}
</style>
</head>
<body>
<!-- 2、设置地图容器的挂载点 -->
<button id="activeDraw">激活画笔</button>
<button id="clearDraw">删除</button>
<div id="map">
</div>
<script>
/* 3、实例化地图 */
mapboxgl.accessToken = '你的token'
const map = new mapboxgl.Map({
container: 'map', // container ID
/* style-layer */
style: {
"version": 8,
"sources": {
"raster-tiles": {
"type": "raster",
"tiles": ["http://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}"],
"tileSize": 256
}
},
"layers": [{
"id": "simple-tiles",
"type": "raster",
"source": "raster-tiles",
"minzoom": 0,
"maxzoom": 22
}]
},
center: [114.30, 30.50], // starting position [lng, lat]
zoom: 6, // starting zoom
pitch: 60
});
map.on("style.load", () => {
map.addSource("geo-source", {
type: "geojson",
data: '/data/query.json'
})
map.addLayer({
id: "geo-layer",
source: "geo-source",
type: "circle",
paint: {
'circle-radius': 10
}
})
})
/* 1、添加画笔控件到地图 */
var draw = new MapboxDraw({
displayControlsDefault: false,
controls: {
}
});
//将绘制控件添加到左上角
map.addControl(draw, 'top-left');
/* 2、点击按键,激活画笔 */
var btn = document.getElementById("activeDraw");
$("#activeDraw").click(function () {
/* 激活画笔 */
draw.changeMode('draw_polygon');
/* 设置按钮为不能点击的状态 */
btn.disabled = true;
btn.style.cursor = "no-drop"
})
/* 3、获取坐标,测算面积 */
map.on("draw.create", handleDraw)
function handleDraw(evt) {
var data = evt.features[0];
// console.log(data)
var sourceData = map.querySourceFeatures('geo-source');
sourceData.forEach(item => {
if (turf.booleanContains(data, item)) {
console.log(item)
}
})
/* 绘制完成重置按钮 */
btn.disabled = false;
btn.style.cursor = "pointer"
}
$("#clearDraw").click(() => {
/* 清除画笔的数据 */
draw.deleteAll();
})
</script>
</body>
</html>
好吧,到这里,mapbox就算完结告一段落啦!如果觉得写的不错,请点点赞
标签:map,style,框架,data,地图,width,context,mapbox,type From: https://blog.csdn.net/qq_45751819/article/details/143616281