物流轨迹展示是物流类产品的标配功能。本文以丰图地图JS SDK为例,演示如何从零搭建一个可交互的物流车辆轨迹展示页面,涵盖地图初始化、轨迹绘制、标记点添加和轨迹回放等核心功能。

一、环境准备
1.1 获取AppKey
前往丰图开放平台(lbs.sfmap.com.cn)注册开发者账号,创建应用后获取ApiKey。
1.2 引入SDK
在HTML页面中通过script标签引入SDK:
html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>物流轨迹展示</title>
<style>
#map-container {
width: 100%;
height: 600px;
}
</style>
</head>
<body>
<div id="map-container"></div>
<script src="https://lbs.sfmap.com.cn/sfmapsdk/map?ak=YOUR_APP_KEY"></script>
<script>
// SDK加载完成后执行
</script>
</body>
</html>
对比其他平台:
- 丰图:
https://lbs.sfmap.com.cn/sfmapsdk/map?ak=YOUR_KEY&v=3.1 - 高德:
https://webapi.amap.com/maps?v=2.0&key=YOUR_KEY - 百度:
https://api.map.baidu.com/api?type=webgl&v=3.0&ak=YOUR_AK - 腾讯:
https://map.qq.com/api/gljs?v=1.exp&key=YOUR_KEY
引入方式基本一致,都是script标签+ApiKey参数。
二、初始化地图
javascript
// 丰图地图初始化
const map = new SFMap.Map('map-container', {
center: [116.397428, 39.90923], // [经度, 纬度]
zoom: 12,
ak: 'YOUR_APP_KEY' // 支持 '2D' 和 '3D'
});
各平台初始化对比:
| 功能 | 丰图 | 高德 | 百度 | 腾讯 |
|---|---|---|---|---|
| 初始化类 | SFMap.Map |
AMap.Map |
BMapGL.Map |
TMap.Map |
| 中心点格式 | [lng, lat] |
[lng, lat] |
new Point(lng, lat) |
{lat, lng} |
| 2D/3D切换 | 2D模式 | viewMode |
初始化时选择 | 自动 |
| 坐标系 | GCJ-02 | GCJ-02 | BD-09 | GCJ-02 |
注意坐标系差异:百度使用BD-09,其他三家使用GCJ-02。跨平台迁移时坐标转换是常见坑点。
三、绘制物流轨迹
假设从后端获取了一组GPS坐标点:
javascript
// 物流轨迹数据([经度, 纬度]数组)
const trackPoints = [
[116.397428, 39.90923],
[116.407428, 39.91923],
[116.417428, 39.92923],
[116.427428, 39.93923],
[116.437428, 39.94923]
];
// 创建线图层数据源
const lineSource = new SFMap.GeoJSONSource({
type: 'FeatureCollection',
features: [{
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: trackPoints
}
}]
});
// 添加线图层
const lineLayer = new SFMap.FtLine({
source: lineSource,
layout: {
'line-cap': 'round',
'line-join': 'round'
},
paint: {
'line-color': '#0066ff',
'line-width': 4,
'line-opacity': 0.8
}
});
map.addLayer(lineLayer);
// 自动调整视野以完整显示轨迹
map.fitBounds(lineSource.getBounds());
各平台折线绘制API:
| 平台 | 折线类 | 添加到地图 |
|---|---|---|
| 丰图 | SFMap.FtLine |
map.addLayer() |
| 高德 | AMap.Polyline |
map.add() |
| 百度 | BMapGL.Polyline |
map.addOverlay() |
| 腾讯 | TMap.MultiPolyline |
初始化时设置 |
丰图采用图层化架构(类似Mapbox),需要先创建数据源再添加图层;高德百度腾讯采用覆盖物模式,直接创建折线对象添加到地图。
四、添加起止点标记
javascript
// 起点标记(绿色)
const startMarker = new SFMap.Marker({
position: trackPoints[0],
content: '<div style="background:#00cc66;color:white;padding:4px 8px;border-radius:4px;font-size:12px;">起点</div>',
offset: new SFMap.Pixel(-20, -40)
});
// 终点标记(红色)
const endMarker = new SFMap.Marker({
position: trackPoints[trackPoints.length - 1],
content: '<div style="background:#ff3333;color:white;padding:4px 8px;border-radius:4px;font-size:12px;">终点</div>',
offset: new SFMap.Pixel(-20, -40)
});
map.add([startMarker, endMarker]);
Marker的content属性支持自定义HTML,可以灵活定制标记样式。也可以使用icon属性指定图标URL。
五、轨迹回放功能
实现动态的轨迹回放效果:
javascript
// 创建车辆标记
const truckMarker = new SFMap.Marker({
position: trackPoints[0],
content: '<div style="font-size:20px;">🚚</div>',
offset: new SFMap.Pixel(-15, -30)
});
map.add(truckMarker);
// 回放控制
let currentIndex = 0;
let isPlaying = false;
let timer = null;
function startReplay() {
if (isPlaying) return;
isPlaying = true;
currentIndex = 0;
timer = setInterval(() => {
if (currentIndex >= trackPoints.length) {
stopReplay();
return;
}
truckMarker.setPosition(trackPoints[currentIndex]);
currentIndex++;
}, 500); // 每500ms移动一步
}
function stopReplay() {
isPlaying = false;
clearInterval(timer);
}
// 播放/暂停按钮
document.getElementById('play-btn').onclick = () => {
if (isPlaying) {
stopReplay();
document.getElementById('play-btn').textContent = '播放';
} else {
startReplay();
document.getElementById('play-btn').textContent = '暂停';
}
};
六、完整代码
将以上代码组合,一个完整的物流轨迹展示页面:
html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>物流轨迹展示Demo</title>
<style>
body { margin: 0; padding: 20px; font-family: sans-serif; }
#map-container { width: 100%; height: 600px; border: 1px solid #ddd; }
.controls { margin: 10px 0; }
button { padding: 8px 16px; cursor: pointer; }
</style>
</head>
<body>
<h2>物流轨迹展示</h2>
<div class="controls">
<button id="play-btn">播放</button>
<button id="reset-btn">重置</button>
</div>
<div id="map-container"></div>
<script src="https://lbs.sfmap.com.cn/sfmapsdk/map?ak=YOUR_APP_KEY"></script>
<script>
// 轨迹数据
const trackPoints = [
[116.397428, 39.90923],
[116.407428, 39.91923],
[116.417428, 39.92923],
[116.427428, 39.93923],
[116.437428, 39.94923]
];
// 初始化地图
const map = new SFMap.Map('map-container', {
center: [116.397428, 39.90923],
zoom: 12,
ak: 'YOUR_APP_KEY'
});
// 绘制轨迹(图层化方式)
const lineSource = new SFMap.GeoJSONSource({
type: 'FeatureCollection',
features: [{
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: trackPoints
}
}]
});
const lineLayer = new SFMap.FtLine({
source: lineSource,
paint: {
'line-color': '#0066ff',
'line-width': 4
}
});
map.addLayer(lineLayer);
// 起点终点标记
const startMarker = new SFMap.Marker({
position: trackPoints[0],
content: '<div style="background:#00cc66;color:white;padding:4px 8px;border-radius:4px;">起点</div>'
});
const endMarker = new SFMap.Marker({
position: trackPoints[trackPoints.length - 1],
content: '<div style="background:#ff3333;color:white;padding:4px 8px;border-radius:4px;">终点</div>'
});
map.add([startMarker, endMarker]);
// 车辆标记
const truckMarker = new SFMap.Marker({
position: trackPoints[0],
content: '<div style="font-size:20px;">🚚</div>'
});
map.add(truckMarker);
map.setFitView([polyline]);
// 回放控制逻辑(同上)
let currentIndex = 0;
let isPlaying = false;
let timer = null;
document.getElementById('play-btn').onclick = function() {
if (isPlaying) {
isPlaying = false;
clearInterval(timer);
this.textContent = '播放';
} else {
isPlaying = true;
this.textContent = '暂停';
timer = setInterval(() => {
if (currentIndex >= trackPoints.length) {
isPlaying = false;
clearInterval(timer);
document.getElementById('play-btn').textContent = '播放';
return;
}
truckMarker.setPosition(trackPoints[currentIndex]);
currentIndex++;
}, 500);
}
};
document.getElementById('reset-btn').onclick = function() {
stopReplay();
currentIndex = 0;
truckMarker.setPosition(trackPoints[0]);
document.getElementById('play-btn').textContent = '播放';
};
</script>
</body>
</html>
这个Demo展示的是基础能力,但丰图在物流场景的几个差异化能力值得留意:
100个途经点的路径规划。高德支持16个,百度支持18个,丰图支持100个。对于配送路线优化、多站点调度这类场景,这个数字差异直接影响功能能不能做。
地址服务能力。智能地址填写、四级地址解析------物流场景里地址解析的准确率直接影响配送效率,丰图在这方面有比较深的积累。
价格。对于中小团队,丰图2万/年的项目版(纯授权证书)+按需搭配接口的模式,比5万/年的全家桶更容易接受。
从初始化地图到绘制轨迹、添加标记、实现回放,整个流程大概50行代码。如果你的产品核心场景是物流轨迹展示、地址管理这类需求,值得一试。