0
点赞
收藏
分享

微信扫一扫

canvas模拟实现高德地图的部分功能

兔八哥软件爱分享 2022-01-09 阅读 39
csscss3html

星图(星星+星空)的拖拽、双指缩放、星星的反缩放、星星的动效及动效优化

基本概念:

画布、视窗(物理上的手机屏幕)、笔触原点(图片的左上角)

画布的大小等于视窗的大小,但我们所有的操作都在手机屏幕上进行,即我们可以感知到的操作点都是视窗上的坐标点;但笔触所有的坐标点对应的都是画布的原点,所以需要将两者区别对待
在这里插入图片描述

拖拽绘制过程:

drawImage()、translate
向左拖拽1px—>笔触原点坐标(-1,0)----->清空整个画布----->绘制并渲染----->视觉效果向左移动1px

开发过程中修正节流参数的截图(未清空画布,未处理边界问题)这两天某音有个互动小游戏,这应该是其中一种实现方式
开发过程中修正节流参数的截图,未清空画布,未处理边界情景

双指缩放绘制过程:
缩放
注意点
1、双指缩放使用ontouchmove判断非ontouchstart;
说明:使用ontouchstart判断是否为双指,是通过接触点的数量是否为2确定的。但实际情况中我们很难两只手指在同一时刻接触到手机屏幕,所以我们改为判定在某一时刻中屏幕上同时有两个接触点即认为触发了双指缩放。
2、判断是缩还是放,并计算缩放中心点
3、确定一个适当的倍数差值后进行计算并移动笔触

计算过程:
1)获取到屏幕两个接触点的坐标后,计算缩放中心点和两点距离。
举例:触点1坐标(a,b),触点2坐标(c,d),
缩放中心点坐标(x1,x2):
x 1 = ( a + c ) / 2 x1= (a+c)/2 x1=(a+c)/2 x 2 = ( b + d ) / 2 x2= (b+d)/2 x2=(b+d)/2

两点距离: d 2 = ( a − c ) 2 + ( b − d ) 2 d^2= (a-c)^2+(b-d)^2 d2=(ac)2+(bd)2

2)通过d的实时变化进行缩放,一开始的距离/现在的距离=应该缩放的比例,

3)将视窗的缩放中心点对应到画布上,计算缩放后画布的偏移距离,将笔触原点反向移动相应的偏移距离后,再次将画布的缩放中心点和视窗的缩放中心点对应上,即可实现按照中心点缩放
简单理解:
在这里插入图片描述
如上图所示,A(x,y)点是缩放中心,放大n倍后对应的点跑到了A1(x1,y1),要想保证缩放的中心点看起来位置不动,我们需要将A1点移动到A点,即偏移(x1-x,y1-y)的距离

实际实现:
实际中我们需要把视窗考虑进去,因为我们能获取到的缩放中心点都是相对于手机屏幕来说的,我们需要把这个位置对应到画布上(当前缩放倍数下的单位距离和当前视窗的单位距离不一致),但画布的缩放移动又完全不影响视窗,所以我们需要维护两套坐标系。最终需要确定的偏移量为:每次缩放之后的图像相对于初始大小下初始位置的偏移值
具体代码:

// 先缩放再位移
			const translateX =
				((((x - this.lastTransform.x * this.lastTransform.scale) / this.lastTransform.scale) * scale -
					x) /
					scale) *
				-1;
			const translateY =
				((((y - this.lastTransform.y * this.lastTransform.scale) / this.lastTransform.scale) * scale -
					y) /
					scale) *
				-1;

解释说明:
(本次屏幕缩放中心点-之前的偏移值*之前的倍数)/倍数=相对于初始大小下的具体坐标

(初始大小下的坐标*新要缩放的倍数-屏幕缩放中心)/新要缩放的倍数=新要偏移的值(相对于最初始的位置)

4)进行绘制

	ctx.scale(this.newTransform.scale, this.newTransform.scale);
	ctx.translate(this.newTransform.x, this.newTransform.y);
	ctx.drawImage(this.image, 0, 0);

注意要先缩放后移动,canvas缩放的原理是把整个坐标轴的距离拉长,但坐标不变,这也是为什么我们最终每次要求的偏移量是相对初始大小来说的

5)处理边界情况
设定一个最小的缩放值和一个最大的缩放值,以及校验偏移量。确定画布永远把视窗包含在其中(页面中不会留白)

6)优化渲染频率
以上解释的所有计算步骤只是其中一帧的绘制过程,我们既要保证缩放效果的流畅,又要尽可能的降低计算频率,所以我们需要对缩放的触发频率稍微优化一下尽量和画面的刷新频率保持一致(60HZ,部分手机可能不一致)

星星的展示:
1)反缩放
因为我们整个星图使用的是canvas,所以星星的反缩放就比较容易实现,在绘制下一帧之前我们已经拿到了画布的缩放比例,只需要告诉绘制星星的这个笔触进行反比例的放大和缩小就行了。

2)隐藏
因为星星不会跟随星空缩放,防止视觉区域内星星过于密集,星图要求在较小的倍率下隐藏一部分较小的星星。处理方式:在缩放到临界倍数的下一帧时,读取配置文件中的设计同学精心计算好要隐藏的星座坐标,控制相应坐标的笔触忽略本次星星的绘制。只是不展示了,但他依然真实在星空上存在。

3)点击
不同于传统的dom可以直接在相应的元素上绑定事件,canvas每一帧绘制完成的结果本质上是张图片。所以我们获取到屏幕上的点击位置后,也要将其转换为画布上的坐标(又用到了我们之前维护的画布和视窗相转换的坐标系)。获取到画布上的坐标后,遍历所有星星的坐标和其附近相应的热区,匹配上之后即认为我们点击的是这颗星星。同时我们也能处理即使是当前缩放倍率下未展示的星星,我们依然可以定位到他的位置。

星星的动效及动效优化
星星的动效全部采用svga资源进行绘制,为了节省开销,相同等级之间的星星均采用同一svga资源,并保持相同的动画频率。

最终效果:
请添加图片描述
todo:补充流程图+canvas基本概念和优劣

以上是实现过程中的部分细节,如果有类似开发需求的同学欢迎一起探讨和交流。

举报

相关推荐

0 条评论