在物流系统中有路径规划场景可用osrm路径规划
路径规划部署
version: '3'
services:
osrm:
image: osrm/osrm-backend
container_name: osrm-china
ports:
- "5000:5000"
volumes:
- D:\data:/data
command: >
bash -c "
osrm-extract -p /opt/car.lua /data/china-latest.osm.pbf &&
osrm-partition /data/china-latest.osrm &&
osrm-customize /data/china-latest.osrm &&
osrm-routed --algorithm mld /data/china-latest.osrm
"
示例
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>地址生成物流轨迹</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<style>
body, html { margin: 0; padding: 0; height: 100%; }
#map { height: 90%; }
#form {
height: 10%; padding: 8px; display: flex;
gap: 10px; align-items: center; background: #f5f5f5;
}
input { padding: 6px; flex: 1; position: relative; }
button { padding: 6px 12px; }
.suggestions {
position: absolute;
background: white;
border: 1px solid #ccc;
max-height: 160px;
overflow-y: auto;
z-index: 1000;
width: 100%;
}
.suggestions div {
padding: 6px;
cursor: pointer;
}
.suggestions div:hover {
background: #eee;
}
.input-wrapper {
position: relative;
flex: 1;
}
</style>
</head>
<body>
<div id="form">
<div class="input-wrapper">
<input id="from" placeholder="请输入发货地,如 广州市" oninput="showSuggestions(this, 'from')" />
<div id="from-suggestions" class="suggestions" style="display:none;"></div>
</div>
<div class="input-wrapper">
<input id="to" placeholder="请输入收货地,如 北京市" oninput="showSuggestions(this, 'to')" />
<div id="to-suggestions" class="suggestions" style="display:none;"></div>
</div>
<button onclick="genRoute()">生成轨迹</button>
</div>
<div id="map"></div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
const map = L.map('map').setView([30.5, 114.3], 6);
const gaodeKey = '1111111111111111111111111111111';
L.tileLayer('https://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}&key=' + gaodeKey, {
attribution: '© 高德地图',
maxZoom: 18
}).addTo(map);
let fromMarker = null, toMarker = null, polyline = null;
async function geocode(address) {
const url = `https://restapi.amap.com/v3/geocode/geo?key=${gaodeKey}&address=${encodeURIComponent(address)}&output=JSON`;
const res = await fetch(url);
const data = await res.json();
if (data.status !== '1' || data.geocodes.length === 0) {
throw new Error(`高德找不到地址: ${address}`);
}
const location = data.geocodes[0].location; // "lng,lat"
const [lng, lat] = location.split(',').map(parseFloat);
return { lat, lng };
}
async function showSuggestions(inputElem, type) {
const val = inputElem.value.trim();
const sugBox = document.getElementById(`${type}-suggestions`);
if (!val) {
sugBox.style.display = 'none';
return;
}
const url = `https://restapi.amap.com/v3/assistant/inputtips?key=${gaodeKey}&keywords=${encodeURIComponent(val)}&datatype=all&output=JSON`;
const res = await fetch(url);
const data = await res.json();
sugBox.innerHTML = '';
if (data.tips && data.tips.length > 0) {
data.tips.forEach(tip => {
if (tip.name) {
const div = document.createElement('div');
div.textContent = tip.name;
div.onclick = () => {
inputElem.value = tip.name;
sugBox.style.display = 'none';
};
sugBox.appendChild(div);
}
});
sugBox.style.display = 'block';
} else {
sugBox.style.display = 'none';
}
}
async function genRoute() {
const fromInput = document.getElementById('from').value.trim();
const toInput = document.getElementById('to').value.trim();
if (!fromInput || !toInput) {
alert('请输入发货地和收货地');
return;
}
try {
const from = await geocode(fromInput);
const to = await geocode(toInput);
if (fromMarker) map.removeLayer(fromMarker);
if (toMarker) map.removeLayer(toMarker);
if (polyline) map.removeLayer(polyline);
fromMarker = L.marker([from.lat, from.lng]).addTo(map).bindPopup('发货地').openPopup();
toMarker = L.marker([to.lat, to.lng]).addTo(map).bindPopup('收货地');
const fromStr = `${from.lng},${from.lat}`;
const toStr = `${to.lng},${to.lat}`;
const res = await fetch(`map?from=${fromStr}&to=${toStr}`);
const data = await res.json();
const latlngs = data.map(p => [p.lat, p.lng]);
polyline = L.polyline(latlngs, { color: 'blue' }).addTo(map);
map.fitBounds(latlngs);
} catch (err) {
alert(err.message);
console.error(err);
}
}
// 关闭建议框(点击外部)
document.addEventListener('click', (e) => {
if (!e.target.closest('.input-wrapper')) {
document.querySelectorAll('.suggestions').forEach(el => el.style.display = 'none');
}
});
</script>
</body>
</html>
路径规划调用
public function map(){
// 起点和终点经纬度,格式:lng,lat
$from = $_GET['from'] ?? '113.2644,23.1291'; // 广州
$to = $_GET['to'] ?? '116.4074,39.9042'; // 北京
//http://服务地址:15000/route/v1/driving
$osrm = config("OSRM");
$url = $osrm.'/'.$from.';'.$to."?overview=full&geometries=geojson";
$response = file_get_contents($url);
$data = json_decode($response, true);
if (!isset($data['routes'][0]['geometry']['coordinates']))
{
http_response_code(500);
echo json_encode(['error' => '路径规划失败']);
exit;
}
$coords = $data['routes'][0]['geometry']['coordinates'];
$baseTime = time();
$track = [];
foreach ($coords as $i => $pt) {
$track[] = [
'time' => date('Y-m-d H:i:s', $baseTime + $i * 1800),
'lng' => $pt[0],
'lat' => $pt[1],
'status' => $i == 0 ? '发货' : ($i == count($coords) - 1 ? '签收' : '运输中')
];
}
header('Content-Type: application/json');
echo json_encode($track, JSON_UNESCAPED_UNICODE);
}