高德setCenter过度效果-模仿mapox效果

下面是优化过度的效果

高德镜头效果-center切换镜头抬起

可以看到如果两个点距离很近的话则正常过度,如果较远则抬起镜头过度,更符合观感,废话不多说。

主要思路

首先来分析抬起镜头的逻辑判断是什么,实际的米数?显然不是,如果在一个很小的zoom的情况下两点都在屏幕内的话,距离就不管用了,所以这里我觉得采用两点的像素距比较合适,像素距离也就是在屏幕内距离是多少像素,并且是否同时在屏幕内,满足这两个条件触发抬起镜头才合适,

所以这里设定 :

let x = 屏幕宽度  ,  if 两点的像素距离  >  x  &&  两点不同时在屏幕内  , 触发。

 好的,知道逻辑那就开干。

1、获取点信息,获取屏幕宽度,将经纬度转为像素坐标和是否在包围盒(屏幕)内

const cameraMoveTarget = (position) => {
	loca.animate.start();

	const curZoom = map.getZoom();
	const curPitch = map.getPitch();
	const curRotation = map.getRotation();
	const curCenter = [map.getCenter().lng, map.getCenter().lat];

	const targZoom = 17; 
	const targPitch = 0;
	const targRotation = 0;
	const targCenter = position;//目标点位

	const point1 = curCenter;   //当前地图的中心点
	const point2 = targCenter;  // 需要跳过去的点位

	// 获取地图容器尺寸
	const container = map.getContainer();
	const screenWidth = container.clientWidth;

	// 转换地理坐标为像素坐标
	const pixelPoint1 = map.lngLatToContainer(new AMap.LngLat(point1[0], point1[1]));
	const pixelPoint2 = map.lngLatToContainer(new AMap.LngLat(point2[0], point2[1]));

	// 计算像素距离
	const pixelDistance = Math.sqrt(Math.pow(pixelPoint1.getX() - pixelPoint2.getX(), 2) + Math.pow(pixelPoint1.getY() - pixelPoint2.getY(), 2));

	// 判断点是否在屏幕内
	const isPoint1InView = map.getBounds().contains(new AMap.LngLat(point1[0], point1[1]));
	const isPoint2InView = map.getBounds().contains(new AMap.LngLat(point2[0], point2[1]));

    



}

2、通过线性插值计算新的缩放级别

maxZoomOutLevel是自己调整的,想让镜头抬起的幅度多大

function calculateLiftZoom(pixelDistance, screenWidth, curZoom) {
	// 假设最小和最大抬起缩放级别差异
	const maxZoomOutLevel = 3; // 可根据需要调整
	const minZoomOutLevel = 0;

	// 计算像素距离与屏幕宽度的比例
	let distanceRatio = pixelDistance / screenWidth;
	distanceRatio = Math.min(Math.max(distanceRatio, 0), 1);

	// 通过线性插值计算新的缩放级别
	const liftZoom = curZoom - (maxZoomOutLevel - minZoomOutLevel) * distanceRatio;

	return liftZoom;
}

3、使用loca镜头控制器控制视角

//loca是加载好了的
await AMapLoader.load({
		key: AMAP_KEY,
		version: AMAP_VERSION,
		Loca: {
			version: "2.0.0",
		},
		plugins: AMAP_PLUGINS.concat(["Loca"]),
	}).then((AMap) => {
		instance = AMap;

		map = new instance.Map(mapRef.value, {
			...AMAP_DEFAULT_THEME,
			zoom: 14,
			showLabel: false,
			pitch: 0,
			center: [117.260355, 31.875092],
			viewMode: "2D",
			skyColor: "#0D121F",
		});

		

		

		// 创建 Loca 容器
		loca = new Loca.Container({
			map: map,
		});

	});
};


//主要代码
const cameraMoveTarget = (position) => {
	loca.animate.start();

	const curZoom = map.getZoom();
	const curPitch = map.getPitch();
	const curRotation = map.getRotation();
	const curCenter = [map.getCenter().lng, map.getCenter().lat];

	const targZoom = 17;
	const targPitch = 0;
	const targRotation = 0;
	const targCenter = position;

	const point1 = curCenter;
	const point2 = targCenter;

	// 获取地图容器尺寸
	const container = map.getContainer();
	const screenWidth = container.clientWidth;

	// 转换地理坐标为像素坐标
	const pixelPoint1 = map.lngLatToContainer(new AMap.LngLat(point1[0], point1[1]));
	const pixelPoint2 = map.lngLatToContainer(new AMap.LngLat(point2[0], point2[1]));

	// 计算像素距离
	const pixelDistance = Math.sqrt(Math.pow(pixelPoint1.getX() - pixelPoint2.getX(), 2) + Math.pow(pixelPoint1.getY() - pixelPoint2.getY(), 2));

	// 判断点是否在屏幕内
	const isPoint1InView = map.getBounds().contains(new AMap.LngLat(point1[0], point1[1]));
	const isPoint2InView = map.getBounds().contains(new AMap.LngLat(point2[0], point2[1]));

	// 决定是否抬起镜头
	let newZoom = targZoom;
	let zoomControl;
	let timingCurve;
	let zoomDuration;
	let centerDuration;
	let centerCurve;

	if (pixelDistance > screenWidth && !(isPoint1InView && isPoint2InView)) {
		newZoom = calculateLiftZoom(pixelDistance, screenWidth, curZoom);
		zoomControl = [
			[0, curZoom],
			[0.5, newZoom],
			[1, targZoom],
		];
		timingCurve = [0.0, 0.52, 0.315, 1.0];
		zoomDuration = 3000;
		centerDuration = 2000;
		centerCurve = [0.15, 0.39, 0.315, 1];
		console.log("抬起");
	} else {
		zoomControl = [
			[0, curZoom],
			[1, targZoom],
		];
		timingCurve = [0.13, 0.31, 0.105, 1];
		zoomDuration = 1500;
		centerDuration = 1500;
		centerCurve = [0.13, 0.31, 0.105, 1];
	}

	const route = [
		{
			pitch: {
				value: targPitch,
				duration: 1000,
				control: [
					[0, curPitch],
					[1, targPitch],
				],
				timing: [0.23, 1.0, 0.32, 1.0],
			},
			zoom: {
				value: targZoom,
				duration: 2000,
				control: zoomControl,
				timing: timingCurve,
			},
			rotation: {
				value: targRotation,
				duration: 1000,
				control: [
					[0, curRotation],
					[1, targRotation],
				],
				timing: [0.23, 1.0, 0.32, 1.0],
			},
			center: {
				value: targCenter,
				duration: centerDuration,
				control: [curCenter, targCenter],
				timing: centerCurve,
			},
		},
	];

	loca.viewControl.addAnimates(route, () => {
		console.log("动画结束");
	});
};

function calculateLiftZoom(pixelDistance, screenWidth, curZoom) {
	// 假设最小和最大抬起缩放级别差异
	const maxZoomOutLevel = 3; // 可根据需要调整
	const minZoomOutLevel = 0;

	// 计算像素距离与屏幕宽度的比例
	let distanceRatio = pixelDistance / screenWidth;
	distanceRatio = Math.min(Math.max(distanceRatio, 0), 1);

	// 通过线性插值计算新的缩放级别
	const liftZoom = curZoom - (maxZoomOutLevel - minZoomOutLevel) * distanceRatio;

	return liftZoom;
}

ok完成,不懂得评论区问就行,我尽量回答

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值