一、基本概述
Mapbox 提供了一系列的工具和服务,用于构建各种与地图相关的应用,从简单的地图展示到复杂的地理信息系统(GIS)应用都可以实现。它支持多种编程语言和开发环境,包括 JavaScript、Python 等,并且提供了丰富的 SDK 和 API,方便开发者集成到自己的项目中。
二、初始化地图
pnpm install mapbox-gl
首先,需要引入 Mapbox GL JS 的库文件,并设置一个容器来显示地图。
import mapboxgl from "mapbox-gl";
import "mapbox-gl/dist/mapbox-gl.css";
mapboxgl.accessToken = "YOUR_ACCESS_TOKEN";
// 基础初始化
const map = new mapboxgl.Map({
container: 'map', // DOM容器ID
style: 'mapbox://styles/mapbox/streets-v12', // 地图样式
center: [114.29, 30.59], // 初始中心点 [经度, 纬度]
zoom: 10, // 缩放级别(0-22)
pitch: 45, // 倾斜角度(3D视图)
bearing: -17, // 旋转角度
projection: 'globe' // 使用球体投影
});
关键参数说明:
-
container
: 必须提前在HTML中创建对应id的div容器 -
style
: 支持内置样式或自定义样式URL -
projection
: 设为'globe'启用3D地球效果
三、地图样式
Mapbox 提供了多种内置地图样式,可以通过map.setStyle
方法来切换。在 HTML 中通过一个<select>
元素来选择不同的样式。
<select id="select">
<option value="standard">standard</option>
<option value="standard-satellite">standard-satellite</option>
<option value="streets-v12">streets-v12</option>
<option value="outdoors-v12">outdoors-v12</option>
<option value="light-v11">light-v11</option>
<option value="dark-v11">dark-v11</option>
<option value="satellite-v9">satellite-v9</option>
<option value="satellite-streets-v12">satellite-streets-v12</option>
<option value="navigation-day-v1">navigation-day-v1</option>
<option value="navigation-night-v1">navigation-night-v1</option>
</select>
const select = document.getElementById("select");
select.onchange = function () {
let value = this.value;
map.setStyle("mapbox://styles/mapbox/" + value);
};
常用内置样式:
-
streets-v12(街道图)
-
satellite-v9(卫星图)
-
light-v11(浅色主题)
-
dark-v11(深色主题)
四、加载高德底图
除了 Mapbox 提供的样式,还可以加载其他地图源,如高德地图。通过自定义地图样式的sources
和layers
来实现。
// 创建一个 Mapbox 地图实例
const map = new mapboxgl.Map({
container: "map",
zoom: 2,
center: [0, 0],
projection: "globe",
// 自定义地图样式
style: {
// 指定样式的版本为 8
version: 8,
// 定义地图数据源
sources: {
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}"
],
// 瓦片的尺寸为 256x256 像素
tileSize: 256
}
},
// 定义地图图层
layers: [
{
// 图层的唯一标识
id: "my-tiles",
// 图层使用的数据源
source: "tiles",
// 图层类型为栅格图层
type: "raster"
}
]
}
});
五、地球自转效果
通过不断改变地图中心点的经度,实现地球自转的动画效果。利用requestAnimationFrame
来持续更新地图状态。
// 定义一个函数来实现地球自转效果
function spinGlobe() {
// 获取当前地图的中心点
let center = map.getCenter();
// 将中心点的经度- 5,实现地球自西向东转动的效果
center.lng -= 5;
// 使用 easeTo 方法平滑地移动地图到新的中心点,动画持续时间为 500 毫秒
map.easeTo({ center: center, duration: 500 });
// 使用 requestAnimationFrame 方法在下一帧继续调用 spinGlobe 函数,实现连续的动画效果
requestAnimationFrame(spinGlobe);
}
// 调用 spinGlobe 函数,开始地球自转动画
spinGlobe();
六、视图动画
可以通过操作相机来实现地图的视图动画,如改变俯仰角、方位角,以及平移、旋转等操作。
<div id="map"></div>
<div class="btns">
<button>改变俯仰角</button>
<button>改变方位角</button>
<button>北京</button>
</div>
.btns{
position: fixed;
top: 10px;
right: 10px;
}
// 获取 HTML 中类名为 "btns" 的按钮组中的第一个按钮
const btn1 = document.querySelectorAll(".btns button")[0];
// 获取 HTML 中类名为 "btns" 的按钮组中的第二个按钮
const btn2 = document.querySelectorAll(".btns button")[1];
// 获取 HTML 中类名为 "btns" 的按钮组中的第三个按钮
const btn3 = document.querySelectorAll(".btns button")[2];
// 为第一个按钮的点击事件添加监听器
btn1.onclick = function () {
// 获取当前地图的俯仰角
let pitch = map.getPitch();
// 将俯仰角增加 2 度
pitch += 2;
// 使用 setPitch 方法设置地图的新俯仰角
map.setPitch(pitch);
};
// 为第二个按钮的点击事件添加监听器
btn2.onclick = function () {
// 获取当前地图的方位角
let bearing = map.getBearing();
// 将方位角增加 2 度
bearing += 2;
// 使用 setBearing 方法设置地图的新方位角
map.setBearing(bearing);
};
// 为第三个按钮的点击事件添加监听器
btn3.onclick = function () {
// 使用 panTo 方法将地图平移到指定的经纬度位置,动画持续时间为 1000 毫秒
map.panTo([116.46, 39.92], { duration: 1000 });
};
七、GeoJSON数据加载
可以从网络接口获取 GeoJSON 数据,并将其添加到地图上。通常用于加载矢量数据,如省份边界、城市等。
// 使用 fetch 函数从指定的 URL 获取 GeoJSON 数据
fetch("https://geo.datav.aliyun.com/areas_v3/bound/geojson?code=100000")
// 将响应数据转换为 JSON 格式
.then((res) => res.json())
// 处理转换后的 JSON 数据
.then((data) => {
// 向地图中添加一个新的数据源,名为 "china",类型为 GeoJSON,数据为获取到的 GeoJSON 数据
map.addSource("china", {
type: "geojson",
data: data
});
// 向地图中添加一个新的图层,名为 "china-layer"
map.addLayer({
// 图层的唯一标识
id: "china-layer",
// 图层类型为填充图层,用于显示面状要素
type: "fill",
// 图层使用的数据源
source: "china",
// 图层的绘制样式,这里设置填充颜色为半透明的红色
paint: {
"fill-color": "rgba(255,0,0,0.5)"
}
});
});
八、加载点要素
在地图上添加点要素,可以是自定义的图标或文本。需要先加载图片,然后通过map.addImage
方法将图片添加到地图,再通过map.addLayer
添加点要素图层。
// 加载指定路径的图片
map.loadImage("/logo.png", (e, image) => {
// 如果加载图片过程中出现错误,抛出错误
if (e) throw e;
// 将加载好的图片添加到地图中,命名为 "logo"
map.addImage("logo", image);
// 定义一个 GeoJSON 格式的点要素集合,包含一个武汉的点要素
const wuhan = {
type: "FeatureCollection",
features: [
{
type: "Feature",
properties: {
// 点要素的属性,这里设置名称为 "武汉"
name: "武汉"
},
geometry: {
type: "Point",
// 点要素的经纬度坐标
coordinates: [114.30246, 30.544783]
}
}
]
};
// 向地图中添加一个新的数据源,名为 "wuhan-logo",类型为 GeoJSON,数据为定义好的点要素集合
map.addSource("wuhan-logo", {
type: "geojson",
data: wuhan
});
// 向地图中添加一个新的图层,名为 "wuhan-layer"
map.addLayer({
id: "wuhan-layer",
// 图层类型为符号图层,用于显示点要素
type: "symbol",
source: "wuhan-logo",
layout: {
// 使用之前添加的图片作为图标
"icon-image": "logo",
// 显示点要素的名称属性
"text-field": ["get", "name"],
// 文本的大小为 20 像素
"text-size": 20,
// 文本相对于图标的偏移量
"text-offset": [0, 1.5]
}
});
});
九、加载线要素
1.Turf.js
Turf.js
是一个强大的用于地理数据计算、处理、统计和分析的 JavaScript 库。
使用@turf/turf
库来创建线要素的 GeoJSON,然后添加到地图上显示。
# get all of turf
npm install @turf/turf
# or get individual packages
npm install @turf/helpers
npm install @turf/buffer
// 引入 @turf/turf 库中的 lineString 函数,用于创建线要素
import { lineString } from "@turf/turf";
// 使用 lineString 函数创建一个从武汉到上海的线要素
const wuhan_shanghai = lineString(
[
[114.29, 30.59],
[121.47, 31.22]
],
{ name: "武汉上海线" }
);
// 向地图中添加一个新的数据源,名为 "wuhan_shanghai_line",类型为 GeoJSON,数据为创建好的线要素
map.addSource("wuhan_shanghai_line", {
type: "geojson",
data: wuhan_shanghai
});
// 向地图中添加一个新的图层,名为 "line-layer"
map.addLayer({
id: "line-layer",
// 图层类型为线图层,用于显示线要素
type: "line",
source: "wuhan_shanghai_line",
paint: {
// 线的颜色为红色
"line-color": "red",
// 线的宽度为 10 像素
"line-width": 10
},
layout: {
// 线的端点样式为圆形
"line-cap": "round"
}
});
2.paint
属性
paint
属性主要用于定义图层的绘制样式,比如颜色、透明度、宽度等视觉效果相关的参数。不同类型的图层(如 fill
、line
、symbol
等)支持不同的 paint
属性。
填充图层(fill
类型)
map.addLayer({
id: "area-layer",
type: "fill",
source: "area",
paint: {
// 设置填充颜色为红色
"fill-color": "red",
// 设置填充的透明度为 0.5
"fill-opacity": 0.5
}
});
在上述代码中,对于一个填充图层(用于显示面要素),paint
属性中的 "fill-color"
定义了面的填充颜色,"fill-opacity"
定义了填充的透明度。
线图层(line
类型)
map.addLayer({
id: "line-layer",
type: "line",
source: "wuhan_shanghai_line",
paint: {
// 设置线的颜色为红色
"line-color": "red",
// 设置线的宽度为 10 像素
"line-width": 10,
// 设置线的透明度为 0.8
"line-opacity": 0.8
}
});
对于线图层,paint
属性中的 "line-color"
定义了线的颜色,"line-width"
定义了线的宽度,"line-opacity"
定义了线的透明度。
3.layout
属性
layout
属性主要用于控制图层的布局和排列方式,比如图标、文本的显示位置、大小、方向等。同样,不同类型的图层支持不同的 layout
属性。
符号图层(symbol
类型)
map.addLayer({
id: "wuhan-layer",
type: "symbol",
source: "wuhan-logo",
layout: {
// 使用名为 "logo" 的图标
"icon-image": "logo",
// 显示点要素的 "name" 属性作为文本
"text-field": ["get", "name"],
// 设置文本的字体大小为 20 像素
"text-size": 20,
// 设置文本相对于图标的偏移量,[0, 1] 表示在图标下方
"text-offset": [0, 1],
// 设置文本的旋转角度为 0 度,即不旋转
"text-rotate": 0
}
});
在符号图层中,layout
属性中的 "icon-image"
定义了要使用的图标,"text-field"
定义了要显示的文本内容,"text-size"
定义了文本的大小,"text-offset"
定义了文本相对于图标的偏移位置,"text-rotate"
定义了文本的旋转角度。
4.总结
paint
:侧重于图层的视觉绘制效果,控制颜色、透明度、宽度等与外观表现相关的属性。layout
:侧重于图层元素的布局和排列,控制图标、文本的显示位置、大小、方向等与布局相关的属性。
十、加载面要素
同样使用@turf/turf
库创建面要素的 GeoJSON,并添加到地图。面要素通常使用fill
类型的图层。
// 引入 @turf/turf 库中的 polygon 函数,用于创建面要素
import { polygon } from "@turf/turf";
// 使用 polygon 函数创建一个由武汉、上海、北京三个点围成的面要素
const area = polygon(
[
[
[114.29, 30.59],
[121.47, 31.22],
[116.46, 40.02],
[114.29, 30.59]
]
],
{
name: "area"
}
);
// 向地图中添加一个新的数据源,名为 "area",类型为 GeoJSON,数据为创建好的面要素
map.addSource("area", {
type: "geojson",
data: area
});
// 向地图中添加一个新的图层,名为 "area-layer"
map.addLayer({
id: "area-layer",
// 图层类型为填充图层,用于显示面要素
type: "fill",
source: "area",
paint: {
// 面的填充颜色为红色
"fill-color": "red"
}
});
十一、高级功能
1.加载静态图片
可以将静态图片添加到地图上,通过指定图片的 URL 和对应的地理坐标范围。
map.addSource('satellite-image', {
type: 'image',
url: 'image.png',
coordinates: [
[113.6545, 31.1774], // 左上
[115.4234, 31.1774], // 右上
[115.4234, 29.6061], // 右下
[113.6545, 29.6061] // 左下
]
});
map.addLayer({
id: 'overlay-image',
type: 'raster',
source: 'satellite-image'
});
2. 3D地形
// 添加一个地形数据源
map.addSource('mapbox-dem', { // 'mapbox-dem' 是数据源的唯一标识符
type: 'raster-dem', // 数据类型为栅格数字高程模型(DEM)
url: 'mapbox://mapbox.mapbox-terrain-dem-v1', // 使用Mapbox提供的地形数据
tileSize: 512 // 每个瓦片的大小为512x512像素
});
// 设置地图的地形效果
map.setTerrain({
source: 'mapbox-dem', // 使用上面定义的 'mapbox-dem' 数据源
exaggeration: 1.5 // 地形高度夸张系数,1.0为真实高度,1.5表示将地形高度放大1.5倍
});
map.addSource
-
作用:向地图中添加一个数据源。
-
参数:
-
'mapbox-dem'
:数据源的唯一标识符,后续可以通过这个名称引用该数据源。 -
type: 'raster-dem'
:指定数据类型为栅格数字高程模型(DEM),用于表示地形高度。 -
url: 'mapbox://mapbox.mapbox-terrain-dem-v1'
:指定数据源的URL,这里是Mapbox提供的地形数据服务。 -
tileSize: 512
:每个瓦片的大小为512x512像素,这是Mapbox地形数据的标准瓦片大小。
-
map.setTerrain
-
作用:启用地图的地形效果,使地图能够根据地形数据渲染3D地形。
-
参数:
-
source: 'mapbox-dem'
:指定使用哪个数据源作为地形数据,这里使用上面定义的mapbox-dem
。 -
exaggeration: 1.5
:地形高度的夸张系数。值为1.0时表示使用真实高度,大于1.0时会放大地形高度,小于1.0时会缩小地形高度。这里设置为1.5,表示地形高度会被放大1.5倍,使地形更加明显。
-
-
添加地形数据后,地图会根据地形高度渲染出3D效果,山脉、山谷等地形特征会更加明显。
-
通过调整
exaggeration
参数,可以控制地形的视觉效果。例如:-
exaggeration: 1.0
:真实地形高度。 -
exaggeration: 2.0
:地形高度放大2倍,视觉效果更夸张。 -
exaggeration: 0.5
:地形高度缩小为真实高度的一半,视觉效果更平缓。
-
// 初始化地图
const map = new mapboxgl.Map({
container: 'map', // DOM容器ID
style: 'mapbox://styles/mapbox/streets-v12', // 地图样式
center: [-122.42, 37.78], // 初始中心点(旧金山)
zoom: 12, // 缩放级别
pitch: 60, // 倾斜角度
bearing: -17 // 旋转角度
});
// 地图加载完成后执行
map.on('load', () => {
// 添加地形数据源
map.addSource('mapbox-dem', {
type: 'raster-dem',
url: 'mapbox://mapbox.mapbox-terrain-dem-v1',
tileSize: 512
});
// 启用地形效果
map.setTerrain({ source: 'mapbox-dem', exaggeration: 1.5 });
// 添加等高线图层(可选)
map.addSource('contours', {
type: 'vector',
url: 'mapbox://mapbox.mapbox-terrain-v2'
});
map.addLayer({
id: 'contours',
type: 'line',
source: 'contours',
'source-layer': 'contours',
paint: {
'line-color': '#877b59',
'line-width': 1
}
});
});
在这个示例中:
-
地图加载后会显示旧金山地区的地形效果。
-
通过
pitch
和bearing
参数设置地图的倾斜和旋转角度,使地形效果更加明显。 -
可选地添加了等高线图层,进一步增强地形可视化效果。
十二、标记和弹窗
通过监听地图的click
事件,在点击位置添加标记(Marker)或弹窗(Popup)。
// 为地图的点击事件添加监听器
map.on("click", function (e) {
// 创建一个新的弹窗实例,设置关闭按钮不可见
let popup = new mapboxgl.Popup({
closeButton: false
});
// 设置弹窗的位置为点击的经纬度位置
popup.setLngLat(e.lngLat)
// 设置弹窗的 HTML 内容,显示点击位置的经纬度
.setHTML(`<h1>你点击的位置是:${e.lngLat.toString()}</h1>`)
// 将弹窗添加到地图上
.addTo(map);
});
// 创建标记
const marker = new mapboxgl.Marker()
.setLngLat([114.30246, 30.544783])
.setPopup(new mapboxgl.Popup().setHTML('<h3>武汉市</h3>'))
.addTo(map);
// 点击事件弹窗
map.on('click', (e) => {
new mapboxgl.Popup()
.setLngLat(e.lngLat)
.setHTML(`坐标:${e.lngLat.lng.toFixed(4)}, ${e.lngLat.lat.toFixed(4)}`)
.addTo(map);
});
十三、常用插件
1. 绘图工具(Mapbox Draw)
Mapbox 提供了各种插件来扩展地图功能,如导航、绘制等。以@mapbox/mapbox-gl-draw
插件为例,用于在地图上绘制图形。
npm i @mapbox/mapbox-gl-draw
// 引入 Mapbox Draw 插件
import MapboxDraw from "@mapbox/mapbox-gl-draw";
// 引入 Mapbox Draw 插件的 CSS 样式
import "@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css";
// 创建一个 Mapbox Draw 实例
const draw = new MapboxDraw();
// 将 Mapbox Draw 插件添加到地图的右上角
map.addControl(draw, "top-right");
2. 路线规划(Directions)
<script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-directions/v4.3.1/mapbox-gl-directions.js"></script>
<link rel="stylesheet" href="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-directions/v4.3.1/mapbox-gl-directions.css" type="text/css">
<div id="map"></div>
const direction = new MapboxDirections({
accessToken: mapboxgl.accessToken,
});
map.addControl(direction, "top-left"); //添加一个导航栏
十四、应用场景
- Web 应用:可以在网站上嵌入交互式地图,为用户提供地理信息展示和查询功能。例如,房地产网站可以在地图上展示房屋的位置和相关信息。
- 移动应用:通过 Mapbox 的移动 SDK,可以在 iOS 和 Android 应用中集成地图功能。例如,打车应用可以使用地图来显示司机和乘客的位置,以及规划最佳路线。
- 地理信息系统(GIS):Mapbox 可以作为 GIS 应用的前端展示工具,与后端的 GIS 数据处理和分析系统相结合,实现更复杂的地理信息处理和分析功能。
十五、优势
- 易于使用:Mapbox 提供了简洁的 API 和丰富的文档,即使是初学者也能快速上手。
- 高性能:采用了先进的技术和算法,能够快速加载和渲染地图数据,提供流畅的用户体验。
- 可定制性强:开发者可以根据自己的需求定制地图的样式、功能和交互方式。
- 社区支持:拥有庞大的开发者社区,开发者可以在社区中分享经验、获取帮助和贡献代码。