Openlayer animate动效优化

一、问题产生

问题产生很简单。公司要做一个需求,定位飞行功能,即,点击定位,获取经纬度,一个飞行的动画,飞到目标点和层级。拿到这个需求的时候,心里想,这简单啊。直接查OpenLayer API.找到了这样的一个函数:

view.animate(var_args)

于是手气刀落,敲下了这样一段代码:

//获取目标定位点等函数省略
this.map.getView().animate({
    
    center: center, zoom: 13}) // 同时移动和放大

顺带提一下。注意参数不同,表现也是不同的。

  • 同时配置了center和zoom,那么表现就是同时移动和放大。
  • 先配置center,再配置zoom,那么表现就是先平移,再缩放
  • 反之,先配置zoom,再配置center,表现是先缩放,再平移

问题来了:
在这里插入图片描述

没错。跨地区过快的平移速度会导致瓦片加载跟不上屏幕移动的速度,用户体验很差。

二、问题分析:

可以采用先拉伸视角,再平移,再缩放视角的方式解决。于是我们就有了这样一段代码:

this.map.getView().animate({
    
    zoom: 7,duration:2000}, {
    
    center: center,duration:2000},{
    
    zoom:13,duration:3000});

吼吼。对于跨地区的场景表现确实很完美。

在这里插入图片描述

然而。对于本身就在附近的定位点,定位起来确很恶心。

在这里插入图片描述

对。即使在附近,也要拉伸再缩放一下。这感觉真是太难受了。。。

三、问题解决

直接上代码。同样的处理流程,不过做了优化算法。封装了一个smooth_animate函数,核心是内部判断当前中心点和目标中心点之间的距离,再通过设定瓦片加载速度,计算出一个拉伸的zoom,在不影响瓦片加载的情况下进行平移操作。开放了3个配置项.

  • load_speed:4, //–一秒钟可以加载几张瓦片,服务器越好,这个值可以越大
  • move_time_limit:3, //–平移时间必须在3s以内
  • level_change_time: 200 //–拉升一级(缩放一级)需要多少毫秒
import * as turf from '@turf/turf';
/**
 * 地图视角由一个地方缓缓转向另外一个地方.
 * 主要原理是计算瓦片距离,控制拉升到某个层级进行平移,达到瓦片能够在这个层级平移的时候,加载速度跟得上平移速度
 * @param {ol.Map} map 
 * @param {Array[lon,lat]} target_location  目标的经纬度
 * @param {Number} target_zoom  目标的层级
 * @param {Object} options  
 * @author daiyujie
 *      load_speed:4,    //--一秒钟可以加载几张瓦片
 *		move_time_limit:3, //--平移时间必须在3s以内
 *		level_change_time: 200 //--拉升一级(缩放一级)需要多少毫秒
 */
export const smooth_animate = function(map,target_location,target_zoom,options){
    
    

	var defaults = {
    
    
		load_speed:4,    //--一秒钟可以加载几张瓦片
		move_time_limit:3, //--平移时间必须在3s以内
		level_change_time: 200 //--拉升一级(缩放一级)需要多少毫秒
	}

	var opts = Object.assign({
    
    }, defaults, options || {
    
    });
	var view = map.getView();
	var cur_zoom =  view.getZoom();
	var cur_center=  view.getCenter();
	var min_zoom = Math.min(cur_zoom,target_zoom);
	var distance = turf.distance(cur_center,target_location);

	var pull_up_zoom = min_zoom;
	var max_tile_num = opts.load_speed * opts.move_time_limit;
	//--核心逻辑在这里
	while(view.getResolutionForZoom(pull_up_zoom)*256*max_tile_num*100 < distance){
    
    
		pull_up_zoom--;
	}
	
	var pull_up_subs_zoom = cur_zoom - pull_up_zoom;
	var duration_pull_up = pull_up_subs_zoom * opts.level_change_time;

	var pull_down_subs_zoom = target_zoom -  pull_up_zoom;
	var duration_pull_down = pull_down_subs_zoom * opts.level_change_time;
	
	view.animate(
	{
    
    
		zoom:pull_up_zoom,
		duration:duration_pull_up
	},
	{
    
    
		center: target_location,
		duration:opts.move_time_limit*1000
	},
	{
    
    
		zoom:target_zoom,
		duration:duration_pull_down
	},
	)
	return new Promise((resolve, reject) => {
    
    
		setTimeout(() => {
    
    
			resolve();
		},duration_pull_down+duration_pull_up+opts.move_time_limit*1000 + 100)
	})
	
}

使用上面函数之后,对于同级别距离的地点转移,不会再进行先拉升后缩放的操作,因为计算出来的拉升的zoom就等于target_zoom。

猜你喜欢

转载自blog.csdn.net/qq_29722281/article/details/103834483