记录--写一个高德地图巡航功能的小DEMO
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
风格设置
加载地图
使用AMapLoader.load
加载地图,从 控制台 申请一个属于自己的key
import AMapLoader from '@amap/amap-jsapi-loader'; ... const AMap = await AMapLoader.load({ "key": "您自己申请的KEY", // 申请好的Web端开发者Key,首次调用 load 时必填 "version": "2.0", "plugins": ["AMap.Walking", "AMap.Driving"], // 需要使用的的插件列表,如比例尺'AMap.Scale'等 "Loca": { version: '2.0.0' } })
使用new AMap.Map
实例化地图,并设置mapStyle
为"amap://styles/grey"
,也可以在官网上自己设计属于自己的风格,主要讲的不是这部分所以大概交代一下就过去了,实例化Map后返回一个map实例,后续的操作都需要用到。
添加GLCustomLayer图层
new AMap.GLCustomLayer({ zIndex: 100, init:()=>{}, render: ()=>{} })
threejs的加载和创建需要在init
属性的方法里操作,render主要是用来渲染一些镜头信息和 WebGLRenderer
的重绘。
在init方法中创建一个THREEJS的透视相机
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 100, 1 << 30);
镜头信息的获取
前文实例化Map后获取一个map的实例,其中提供了customCoords
数据转换的工具,可以从这里获取到镜头信息,后续转化经纬度到3D世界坐标时候也会用到,转换工具需要提前获取到,方便后续的工作。
var { near, far, fov, up, lookAt, position } = customCoords.getCameraParams();
转换工具提供一个getCameraParams
方法,其中包含相机位置等其他属性
fov — 摄像机视锥体垂直视野角度
near — 摄像机视锥体近端面
far — 摄像机视锥体远端面
其中大部分属性都和threejs的透视相机属性相同,在render方法中更新相机,这样做的作用就是在后续做巡航功能时会实时更新相机位置
camera.near = near; camera.far = far; camera.fov = fov; camera.position.set(...position); camera.up.set(...up); camera.lookAt(...lookAt); camera.updateProjectionMatrix();
初始化loca
可视化图层需要用到Loca
容器,需要在地图外绘制的图层,需要在可视化图层上绘制,
创建可视化作品前,首先要创建一个 Loca 容器,这个容器可以帮您加载高德地图作为底图,或者帮您关联已有的高德地图作为底图。
在使用地图的时,您可以使用任何一个 JS API 已有的功能,Loca 容器不会影响原有地图的任何功能和特性。这里创建的 Loca 容器您可以理解为是可视化图层的管理器。
注意:创建地图时候 Loca 版本要和map的版本一致,否则会报错
var loca = new (window as any).Loca.Container({ map, zIndex: 9 });
AMap.GLCustomLayer
添加到map图层const customLayer = await createGLCustomLayer(AMap, customCoords) map.add(customLayer);
createGLCustomLayer
方法就是之前定义的初始化AMap.GLCustomLayer
方法。返回一个GLCustomLayer
实例,这样就可以在地图内插入可视化内容。
加载模型
回到new AMap.GLCustomLayer
提供的init属性中,创建一个3d场景并把模型加载到场景中,
renderer = new THREE.WebGLRenderer({ context: gl, // 地图的 gl 上下文 }); // 自动清空画布这里必须设置为 false,否则地图底图将无法显示 renderer.autoClear = false; scene = new THREE.Scene();
gltfloder
api,加载方法返回一个promise,再使用// 初始化模型 function initGltf(): Promise<THREE.Object3D> { return new Promise((resolve, reject) => { var loader = new GLTFLoader(); loader.load('https://a.amap.com/jsapi_demos/static/gltf/Duck.gltf', (gltf: any) => { let object = gltf.scene; resolve(object) }); }) }
模型添加到场景
const { x, y, z } = setRotation(new THREE.Vector3(90, 90, 0)) object.scale.set(15, 15, 15); group.add(object) group.add(new THREE.AxesHelper(100)) scene.add(group) object.name = 'duck'
我在模型上添加了一个AxesHelper
辅助线,官网上表示蓝色代表z轴,但是放在地图中发生了坐标方向不一致的问题,threejs的向上方向是y轴,地图中z是向上方向,这一点可能要注意一下了
用于简单模拟3个坐标轴的对象.
红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.
旋转模型
const { x, y, z } = setRotation(new THREE.Vector3(90, -90, 0)) group.rotation.set(x, y, z)
export function setRotation(rotation: THREE.Vector3) { var x = Math.PI / 180 * (rotation.x || 0); var y = Math.PI / 180 * (rotation.y || 0); var z = Math.PI / 180 * (rotation.z || 0); return new THREE.Vector3(x, y, z) }
计算轨迹
使用viewControl
现在模型已经加载好,接下来就是要获取轨迹数据,镜头跟踪在Loca中有相应的apiviewControl
,使用这个api调用addTrackAnimate
方法,提供对应参数即可;
loca.viewControl.addTrackAnimate({ path: pathArr, // 镜头轨迹,二维数组,支持海拔 duration: 120000, // 时长 timing: [[0, 0.3], [1, 0.7]], // 速率控制器 rotationSpeed: 1800, // 每秒旋转多少度 }, function () { console.log('完成',); });
pathArr
是一个轨迹数组,const pathArr = [[116.310348, 39.89702], [116.310541, 39.884855], [116.320963, 39.889154], [116.322894, 39.889608], [116.325542, 39.889822], [116.328074, 39.889761], [116.349104, 39.889429], [116.348517, 39.89747], [116.355205, 39.898413], [116.35656, 39.90021], [116.355802, 39.93225]]
// 导航线 var polyline = new AMap.Polyline({ path: pathArr, // 设置线覆盖物路径 showDir: true, strokeColor: '#3366bb', // 线颜色 strokeWeight: 10, // 线宽 zIndex: 1 }); map.add(polyline)
以上工作做完后,需要调用一下loca.animate.start();
方法,否则可视化图层不会更新,相应数据也获取不到,现在画面变成这样了
除了以上这种方法去实现镜头的移动,还可以通过插入坐标的方式去实现,也是传统threejs中使用的方法,就是利用tweenjs
的动画,运动过程中改变map.setCenter
,实现跟踪,这部分代码在changeObject
方法中,感兴趣的可以去 仓库 查看,
镜头跟踪
移动模型
利用requestAnimationFrame
函数写一个循环渲染的方法,在调用的同时获取镜头中心坐标,通过customCoords
转换工具将经纬度转为3D世界的坐标,并将该坐标赋值给object模型,再通过map提供的getRotation
方法,获取地图的旋转角度,并将该角度赋值给object模型的y轴,使模型沿着y轴旋转,至于旋转的速度,在前面定义addTrackAnimate
时的rotationSpeed
属性定义的
const render = () => { requestAnimationFrame(() => { render() }) if (object) { const center = map.getCenter() var position = customCoords.lngLatsToCoords([ [center.lng, center.lat] ])[0]; const v3 = new THREE.Vector3(position[1], 0, position[0]) object.position.copy(v3) const rotation = map.getRotation() object.rotation.y = rotation * Math.PI / 180 } map.render(); TWEEN && TWEEN.update() }
以上文章内容有一些关于threejs的基础知识,可以先提前了解一下,否则有很多好玩有趣的效果实现不出来。
其他
关于飞线,只是作为装饰,显得画面不那么呆板,在官网上也有案例,简单贴一个代码吧
// 飞线 var geo = new (window as any).Loca.GeoJSONSource({ url: 'https://a.amap.com/Loca/static/loca-v2/demos/mock_data/bj_bus.json', }); var layer = new (window as any).Loca.PulseLineLayer({ // loca, zIndex: 10, opacity: 1, visible: true, zooms: [1, 30], }); var headColors = ['#EFBB51', '#7F3CFF', '#4CC19B', '#0B5D74', '#E06AC4', '#223F9B', '#F15C1A', '#7A0FA6']; layer.setSource(geo); layer.setStyle({ altitude: 0, lineWidth: 2, // 脉冲头颜色 headColor: (_, feature) => { return headColors[feature.properties.type - 1]; }, // 脉冲尾颜色 trailColor: 'rgba(128, 128, 128, 0.5)', // 脉冲长度,0.25 表示一段脉冲占整条路的 1/4 interval: 0.25, // 脉冲线的速度,几秒钟跑完整段路,可以通过计算距离动态改变时间 duration: 5000, }); // 飞线结束 loca.add(layer);
热门相关:倾心之恋:总裁的妻子 道君 前任无双 前任无双 道君