预览
大概思路是:
- 获取高德地图的公交路线坐标数组
- 加载gltf模型
- 根据公交线路的坐标绘制轨迹
- 监听事件moving修改gltf模型的位置
获取公交线路坐标的代码如下(轨迹回放)
var transOptions = {
map: map,
city: "武汉市",
panel: "panel",
policy: AMap.TransferPolicy.LEAST_TIME, //乘车策略
};
var pointArr = []; // 存储公交经过的坐标,是一个二维数组
var transfer = new AMap.Transfer(transOptions);
transfer.search(
[
{ keyword: "园博园", city: "武汉" },
{ keyword: "金银潭地铁站", city: "武汉" },
],
function (status, result) {
if (status === "complete") {
for (var i = 0; i < result.plans[0].path.length; i++) {
pointArr.push([result.plans[0].path[i].lng, result.plans[0].path[i].lat]);
}
resolve(pointArr); // 异步操作完成,将结果传递给resolve函数
} else {
console.log("公交路线数据查询失败,错误代码:" + result);
reject("查询失败"); // 异步操作失败,将错误信息传递给reject函数
}
}
);
这里会得到公交线路的坐标,存储在pointArr
数组中,内容如下
pointArr = [[114.218315, 30.62306],
[114.218315, 30.622686],
[114.218315, 30.622087],
·····]
marker移动事件的监听
// 绑定移动事件监听器
marker.on("moving", function (e) {
var passedPath = e.passedPath, lastPosi = passedPath[passedPath.length - 1];
passedPolyline.setPath(passedPath);
var angle = calcAngle([passedPath[passedPath.length - 2][0], passedPath[passedPath.length - 2][1]], [lastPosi.lng, lastPosi.lat]);
// 判断角度变化的大小是否超过阈值(2度)
if (Math.abs(angle - previousAngle) >= 2) {
setAngle(angle);
previousAngle = angle;
}
startMove(lastPosi); // 移动gltf模型
});
完整代码
这里省略了map的创建等,只展示了关于公交车线路和模型的部分代码,其余代码需要读者自己补充
immediate_bus() {
function initGltf() {
var loader = new GLTFLoader();
loader.load("bus.glb", gltf => {
busobj = gltf.scene;
busobj.scale.set(10, 10, 10);
busobj.renderOrder = 999;
setRotation({ x: 90, y: 0, z: 0 });
setPosition(map_init_center);
scene.add(busobj);
});
}
function setRotation(rotation) {
var x = (Math.PI / 180) * (rotation.x || 0);
var y = (Math.PI / 180) * (rotation.y || 0);
var z = (Math.PI / 180) * (rotation.z || 0);
busobj.rotation.set(x, y, z);
}
function setPosition(lnglat) {
// 对模型的经纬度进行转换
var position = customCoords.lngLatsToCoords([lnglat])[0];
busobj.position.setX(position[0]);
busobj.position.setY(position[1]);
}
function setAngle(angle) {
var x = busobj.rotation.x;
var z = busobj.rotation.z;
var y = (Math.PI / 180) * angle;
busobj.rotation.set(x, y, z);
}
// 计算地图上两点间的角度
function calcAngle(start, end) {
var diff_lng = end[0] - start[0];
var diff_lat = end[1] - start[1];
return (360 * Math.atan2(diff_lat, diff_lng)) / (2 * Math.PI);
}
// 改变模型位置和角度
var xe = -5.341658, ye = 3.738671; // 坐标偏移量,因为坐标系原因,偏移量需要自己设定,(归根到底还是该死的火星坐标系)
function startMove(Position) {
var centerPoint = turf.point([Position.lng + xe, Position.lat + ye]);
var pos = turf.transformTranslate(centerPoint, 0.3, 0).geometry.coordinates;
setPosition(pos);
}
function init() {
marker = new AMap.Marker({
map: map,
position: lineArr[0],
// icon: "https://a.amap.com/jsapi_demos/static/demo-center-v2/car.png",
content: "<div style='display:none'></div>",
});
// 绘制轨迹
polyline = new AMap.Polyline({
map: map,
path: lineArr,
showDir: true,
strokeColor: "#28F", //线颜色
strokeOpacity: 0.3, //线透明度
strokeWeight: 6, //线宽
// strokeStyle: "solid" //线样式
});
// 经过的轨迹修改颜色
passedPolyline = new AMap.Polyline({
map: map,
strokeColor: "#AF5", //线颜色
strokeWeight: 6, //线宽
strokeOpacity: 0.3, //线透明度
});
// 声明一个变量用于存储上一次的角度
var previousAngle = 0;
// 绑定移动事件监听器
marker.on("moving", function (e) {
var passedPath = e.passedPath,
lastPosi = passedPath[passedPath.length - 1];
passedPolyline.setPath(passedPath);
var angle = calcAngle([passedPath[passedPath.length - 2][0], passedPath[passedPath.length - 2][1]], [lastPosi.lng, lastPosi.lat]);
// 判断角度变化的大小是否超过阈值(2度)
if (Math.abs(angle - previousAngle) >= 2) {
setAngle(angle);
previousAngle = angle;
}
startMove(lastPosi);
});
}
let origin_terminus = this;
function find_road() {
return new Promise(function (resolve, reject) { // 因为transfer.search是异步加载的,而我们需要等待查询结束后返回坐标。
var transOptions = {
map: map,
city: "武汉市",
panel: "panel",
policy: AMap.TransferPolicy.LEAST_TIME, //乘车策略
};
var pointArr = [];
var transfer = new AMap.Transfer(transOptions);
transfer.search(
[
{ keyword: origin_terminus.origin, city: "武汉" },
{ keyword: origin_terminus.terminus, city: "武汉" },
],
function (status, result) {
if (status === "complete") {
for (var i = 0; i < result.plans[0].path.length; i++) {
pointArr.push([result.plans[0].path[i].lng, result.plans[0].path[i].lat]);
}
resolve(pointArr); // 异步操作完成,将结果传递给resolve函数
} else {
console.log("公交路线数据查询失败,错误代码:" + result);
reject("查询失败"); // 异步操作失败,将错误信息传递给reject函数
}
}
);
})
.then(function (pointArr) {
if (pointArr.length === 0) { // 查询不到数据,返回默认坐标
return [
[114.218315, 30.62306],
[114.218315, 30.622686],
];
} else {
return pointArr;
}
})
.catch(function (error) {
console.log(error);
});
}
async function init_bus() { // 确保获取到公交线路的坐标后,在执行其他函数
lineArr = await find_road();
initGltf();
init();
map.add(marker);
scene.add(busobj);
map.add(polyline);
map.add(passedPolyline);
marker.moveAlong(lineArr, {
duration: 8000,
autoRotation: true,
});
}
init_bus();
},
如有不明白的地方可以留言,博主闲暇时会给与回答。