作为一个刚开始学习 mapvthree 的小白,今天要学习地图视野控制了!听说这个模块可以控制地图的视角、缩放、旋转等,还能转换坐标!想想就激动!
今天在文档里看到了 engine.map 这个词,一开始我还以为是地图本身,结果查了一下才知道,原来这是用来控制地图视野的模块!
文档说地图视野控制可以:
我的理解:简单说就是控制"怎么看地图",比如看哪里、看多远、从什么角度看!就像控制相机一样!
作为一个初学者,我习惯先看看引擎有哪些属性。文档说 engine.map 就是地图管理器!
我的发现:原来引擎创建后,就自动有了一个地图管理器对象!不需要手动创建,直接用就行!
import * as mapvthree from '@baidumap/mapv-three';
const container = document.getElementById('container');
const engine = new mapvthree.Engine(container);
// 地图管理器已经自动创建了!
console.log(engine.map); // 可以访问地图管理器我的理解:engine.map 就是地图视野控制的入口,所有视野相关的操作都通过它来完成。
文档说可以通过 engine.map.setCenter() 来设置地图的中心点。我试了试:
// 设置中心点为北京天安门
engine.map.setCenter([116.404, 39.915]);我的发现:设置中心点后,地图会立即移动到指定位置!
我的尝试:我写了个简单的测试:
import * as mapvthree from '@baidumap/mapv-three';
const container = document.getElementById('container');
const engine = new mapvthree.Engine(container, {
map: {
center: [116.404, 39.915], // 初始中心点
range: 1000,
pitch: 60,
},
});
// 切换到上海
engine.map.setCenter([121.473, 31.230]);我的观察:地图从北京跳到了上海!虽然有点突然,但是位置确实变了!
我的理解:setCenter() 接受一个经纬度数组 [经度, 纬度],地图会立即移动到该位置。
看到可以设置中心点后,我开始好奇:能不能获取当前的中心点?
文档说可以用 engine.map.getCenter() 来获取!
// 获取当前中心点
const center = engine.map.getCenter();
console.log(center); // [116.404, 39.915]我的发现:可以获取当前的经纬度坐标!
我的想法:如果做位置记录功能,可以用这个方法来保存当前位置!
看到中心点控制后,我想:能不能控制地图的缩放?
文档说可以通过 engine.map.setRange() 来控制视野距离地面的距离!
// 设置视野距离为 1000 米(比较近)
engine.map.setRange(1000);
// 设置视野距离为 10000 米(比较远)
engine.map.setRange(10000);我的理解:range 是相机距离地面的高度(米),值越小越近,值越大越远。
我的尝试:
// 拉近视野(1000 米)
engine.map.setRange(1000);
// 拉远视野(10000 米)
engine.map.setRange(10000);我的发现:
range = 1000:视野很近,能看到细节range = 10000:视野很远,能看到更大的范围我的想法:如果做缩放功能,可以用这个方法来控制视野距离!
文档还说可以用 setZoom() 来控制缩放级别!
// 设置缩放级别
engine.map.setZoom(14);我的理解:zoom 是缩放级别,数字越大越近,数字越小越远。
我的尝试:
// 放大(级别 18)
engine.map.setZoom(18);
// 缩小(级别 10)
engine.map.setZoom(10);我的发现:setZoom() 和 setRange() 都能控制缩放,但是 setZoom() 更直观!
我的想法:如果做缩放按钮,可以用 zoomIn() 和 zoomOut() 方法!
// 放大
engine.map.zoomIn();
// 缩小
engine.map.zoomOut();我的发现:这两个方法更方便,不需要知道具体的缩放级别!
看到缩放控制后,我想:能不能控制地图的旋转?
文档说可以通过 engine.map.setHeading() 来设置旋转角度!
// 设置旋转角度(0 度是正北)
engine.map.setHeading(0);
// 设置旋转角度(90 度是正东)
engine.map.setHeading(90);我的理解:heading 是旋转角度,以正北为 0 度,逆时针方向递增。
我的尝试:
// 正北方向
engine.map.setHeading(0);
// 正东方向
engine.map.setHeading(90);
// 正南方向
engine.map.setHeading(180);
// 正西方向
engine.map.setHeading(270);我的发现:地图会旋转到指定方向!
我的想法:如果做指南针功能,可以用这个方法来控制方向!
文档说可以用 getHeading() 来获取当前的旋转角度!
// 获取当前旋转角度
const heading = engine.map.getHeading();
console.log(heading); // 例如:45我的发现:可以获取当前的旋转角度,这样就能知道地图朝向哪个方向了!
看到旋转控制后,我想:能不能控制地图的俯仰角?
文档说可以通过 engine.map.setPitch() 来设置俯仰角!
// 设置俯仰角(0 度是垂直向下看)
engine.map.setPitch(0);
// 设置俯仰角(90 度是水平看)
engine.map.setPitch(90);我的理解:pitch 是俯仰角,0 度是垂直向下看,90 度是水平看。
我的尝试:
// 垂直向下看(俯视)
engine.map.setPitch(0);
// 45 度俯视
engine.map.setPitch(45);
// 水平看(平视)
engine.map.setPitch(90);我的发现:
pitch = 0:完全俯视,像从正上方看pitch = 45:斜向下看,能看到侧面pitch = 90:水平看,像站在地面上看我的想法:如果做视角切换功能,可以用这个方法来控制俯仰角!
文档说可以用 getPitch() 来获取当前的俯仰角!
// 获取当前俯仰角
const pitch = engine.map.getPitch();
console.log(pitch); // 例如:60我的发现:可以获取当前的俯仰角,这样就能知道地图的视角了!
看到可以分别设置中心点、缩放、旋转、俯仰角后,我想:能不能一次性设置所有参数?
文档说可以用 engine.map.lookAt() 来一次性设置视野!
engine.map.lookAt(
[116.404, 39.915], // 中心点
{
heading: 0, // 旋转角度
pitch: 60, // 俯仰角
range: 1000, // 视野距离
}
);我的理解:lookAt() 可以一次性设置中心点、旋转角度、俯仰角和视野距离,更方便!
我的尝试:
// 飞到天安门,正北方向,60 度俯视,1000 米高度
engine.map.lookAt(
[116.404, 39.915],
{
heading: 0,
pitch: 60,
range: 1000,
}
);我的发现:地图会立即切换到指定视野,所有参数一次性设置!
我的想法:如果做场景切换功能,可以用这个方法来快速切换视野!
看到 lookAt() 后,我想:能不能让视野切换有动画效果?
文档说可以用 engine.map.flyTo() 来实现平滑的动画过渡!
engine.map.flyTo(
[116.404, 39.915], // 目标位置
{
heading: 0,
pitch: 60,
range: 1000,
duration: 2000, // 动画持续时间(毫秒)
}
);我的理解:flyTo() 和 lookAt() 功能类似,但是 flyTo() 有平滑的动画效果!
我的尝试:
// 平滑飞到天安门
engine.map.flyTo(
[116.404, 39.915],
{
heading: 0,
pitch: 60,
range: 1000,
duration: 2000, // 2 秒动画
}
);我的发现:地图会平滑地飞到目标位置,有动画效果,看起来很舒服!
我的感受:flyTo() 比 lookAt() 更友好,用户体验更好!
我的想法:如果做场景切换,应该用 flyTo() 而不是 lookAt()!
文档说 flyTo() 还支持回调函数!
engine.map.flyTo(
[116.404, 39.915],
{
duration: 2000,
complete: () => {
console.log('动画完成!');
},
cancel: () => {
console.log('动画取消!');
},
}
);我的发现:可以在动画完成或取消时执行回调函数,这样就能做更多操作了!
我的想法:如果做场景切换,可以在动画完成后加载数据或显示信息!
看到视野控制后,我开始好奇:什么是坐标转换?
文档说可以通过 projectCoordinate() 和 unprojectCoordinate() 来转换坐标!
我的理解:地理坐标(经纬度)和投影坐标(米)之间可以互相转换!
import * as THREE from 'three';
// 地理坐标(经纬度)
const geoCoord = new THREE.Vector3(116.404, 39.915, 0);
// 投影坐标(米)
const projCoord = new THREE.Vector3();
engine.map.projectCoordinate(geoCoord, projCoord);
console.log(projCoord); // 投影坐标我的理解:projectCoordinate() 把地理坐标转换为投影坐标。
我的发现:投影坐标是三维坐标(x, y, z),单位是米,可以用来放置 3D 物体!
import * as THREE from 'three';
// 投影坐标(米)
const projCoord = new THREE.Vector3(12960000, 4850000, 0);
// 地理坐标(经纬度)
const geoCoord = new THREE.Vector3();
engine.map.unprojectCoordinate(projCoord, geoCoord);
console.log(geoCoord); // 地理坐标我的理解:unprojectCoordinate() 把投影坐标转换为地理坐标。
我的发现:可以从投影坐标转换回经纬度,这样就能知道 3D 物体对应的地理位置了!
文档还说可以用 projectArrayCoordinate() 来转换数组格式的坐标!
// 地理坐标数组
const geoArray = [116.404, 39.915];
// 投影坐标数组
const projArray = engine.map.projectArrayCoordinate(geoArray, []);
console.log(projArray); // [x, y, z]我的发现:数组格式更方便,不需要创建 Vector3 对象!
我的想法:如果做批量坐标转换,可以用数组格式!
看到坐标转换后,我开始好奇:什么是投影?
文档说可以通过 engine.map.projection 来获取投影方式!
我的理解:投影是把地球的球面坐标转换为平面坐标的方法。
文档说支持三种投影方式:
我的尝试:
const engine = new mapvthree.Engine(container, {
map: {
projection: 'EPSG:3857', // Web 墨卡托投影(默认)
center: [116.404, 39.915],
range: 1000,
},
});我的发现:可以在初始化时设置投影方式!
我的理解:
EPSG:4326:适合显示经纬度坐标EPSG:3857:适合显示平面地图(默认)EPSG:4978:适合显示 3D 地球我的想法:如果做 3D 地球效果,应该用 EPSG:4978!
看到坐标转换后,我想:能不能限制地图的可拖动范围?
文档说可以用 engine.map.setBounds() 来设置视野范围!
// 设置视野范围(左下角和右上角坐标)
engine.map.setBounds([
[116.0, 39.0], // 左下角
[117.0, 40.0], // 右上角
]);我的理解:setBounds() 限制地图只能在指定区域内拖动。
我的尝试:
// 限制在北京范围内
engine.map.setBounds([
[116.0, 39.5], // 左下角
[117.0, 40.5], // 右上角
]);我的发现:设置后,地图只能在指定区域内拖动,超出范围会自动限制!
我的想法:如果做区域展示,可以用这个方法来限制视野范围!
文档说可以用 getBounds() 来获取当前的视野范围!
// 获取当前视野范围
const bounds = engine.map.getBounds();
console.log(bounds); // Box3 对象我的发现:可以获取当前可视区域的边界,这样就能知道地图显示的范围了!
看到视野范围后,我想:能不能根据一组坐标自动调整视野?
文档说可以用 engine.map.setViewport() 来根据坐标数组设置视野!
// 根据坐标数组设置视野
engine.map.setViewport(
[
[116.404, 39.915],
[116.414, 39.925],
[116.424, 39.935],
],
{
range: 5000, // 视野距离
}
);我的理解:setViewport() 会根据坐标数组自动计算合适的视野,让所有坐标都在视野内。
我的尝试:
// 显示多个点的视野
const points = [
[116.404, 39.915], // 点 1
[116.414, 39.925], // 点 2
[116.424, 39.935], // 点 3
];
engine.map.setViewport(points, {
range: 5000,
});我的发现:地图会自动调整视野,让所有点都在视野内!
我的想法:如果做数据展示,可以用这个方法来自动调整视野,显示所有数据点!
看到 setViewport() 后,我想:能不能缩放到某个 3D 对象的范围?
文档说可以用 engine.map.zoomTo() 来缩放到对象范围!
import * as THREE from 'three';
// 创建一个 3D 对象
const geometry = new THREE.BoxGeometry(100, 100, 100);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const mesh = new THREE.Mesh(geometry, material);
engine.add(mesh);
// 缩放到对象范围
engine.map.zoomTo(mesh, {
range: 1000,
});我的理解:zoomTo() 会自动调整视野,让指定的 3D 对象在视野内。
我的发现:地图会自动调整视野,让对象在视野中心!
我的想法:如果做模型查看功能,可以用这个方法来自动调整视野!
看到视野控制后,我想:能不能限制视野的最大最小距离?
文档说可以用 setMaxRange() 和 setMinRange() 来设置视野限制!
// 设置最大视野距离(不能拉得太远)
engine.map.setMaxRange(100000);
// 设置最小视野距离(不能拉得太近)
engine.map.setMinRange(100);我的理解:setMaxRange() 和 setMinRange() 限制视野的距离范围。
我的尝试:
// 限制视野在 100 米到 10000 米之间
engine.map.setMinRange(100);
engine.map.setMaxRange(10000);我的发现:设置后,用户无法将视野拉得太近或太远,会被限制在指定范围内!
我的想法:如果做特定场景,可以用这个方法来限制视野范围!
看到视野控制后,我想:能不能获取当前相机的位置?
文档说可以用 engine.map.getCameraLocation() 来获取相机位置!
import * as THREE from 'three';
// 获取相机位置
const cameraPos = new THREE.Object3D();
const location = engine.map.getCameraLocation(cameraPos);
console.log(location); // 相机位置的经纬度和高度我的发现:可以获取当前相机的经纬度坐标和高度!
我的想法:如果做相机位置记录,可以用这个方法来保存相机位置!
我想写一个完整的示例,把学到的都用上:
import * as mapvthree from '@baidumap/mapv-three';
const container = document.getElementById('container');
const engine = new mapvthree.Engine(container, {
map: {
center: [116.404, 39.915],
range: 1000,
pitch: 60,
heading: 0,
},
});
// 创建按钮控制视野
document.getElementById('flyToBtn').addEventListener('click', () => {
// 平滑飞到天安门
engine.map.flyTo(
[116.404, 39.915],
{
heading: 0,
pitch: 60,
range: 1000,
duration: 2000,
complete: () => {
console.log('到达天安门!');
},
}
);
});
document.getElementById('lookAtBtn').addEventListener('click', () => {
// 立即切换到上海
engine.map.lookAt(
[121.473, 31.230],
{
heading: 0,
pitch: 60,
range: 2000,
}
);
});
document.getElementById('zoomInBtn').addEventListener('click', () => {
// 放大
engine.map.zoomIn();
});
document.getElementById('zoomOutBtn').addEventListener('click', () => {
// 缩小
engine.map.zoomOut();
});
// 获取当前视野信息
const center = engine.map.getCenter();
const range = engine.map.getRange();
const heading = engine.map.getHeading();
const pitch = engine.map.getPitch();
console.log('中心点:', center);
console.log('视野距离:', range);
console.log('旋转角度:', heading);
console.log('俯仰角:', pitch);我的感受:写一个完整的示例,把学到的都用上,感觉很有成就感!
我的发现:
虽然代码还很简单,但是已经能做出一个基本的地图视野控制系统了!
作为一个初学者,我踩了不少坑,记录下来避免再犯:
原因:经纬度顺序写反了,或者格式不对。
解决:坐标格式是 [经度, 纬度],经度在前,纬度在后。
原因:不知道什么时候用 flyTo,什么时候用 lookAt。
解决:
lookAt:立即切换视野,没有动画flyTo:平滑切换视野,有动画效果原因:不知道 range 和 zoom 的区别。
解决:
range:视野距离地面的高度(米),值越小越近zoom:缩放级别,数字越大越近原因:投影方式设置错误,导致坐标转换失败。
解决:根据需求选择合适的投影方式,默认是 EPSG:3857。
原因:坐标转换时没有创建输出对象。
解决:坐标转换需要提供输出对象,比如 new THREE.Vector3()。
经过这一天的学习,我掌握了:
setCenter() 设置setRange() 或 setZoom() 控制setHeading() 设置旋转角度setPitch() 设置俯仰角lookAt() 或 flyTo() 切换projectCoordinate() 和 unprojectCoordinate() 转换setBounds() 限制视野范围setViewport() 根据坐标数组自动调整我的感受:地图视野控制真的很强大!虽然功能很多,但是用起来其实不难。关键是要理解每个方法的作用,然后根据需求选择合适的方法!
下一步计划:
学习笔记就到这里啦!作为一个初学者,我觉得地图视野控制虽然功能很多,但是用起来其实不难。关键是要理解每个方法的作用,然后根据需求选择合适的方法!希望我的笔记能帮到其他初学者!大家一起加油!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。