Vue地图 移动缩放功能

Vue地图 移动缩放功能,第1张

Vue 地图demo开发记录 思路规划 基础构成:

1.用于被显示的base地图,可以用svg等矢量图形文件来表示。

2.用于控制地图缩放的“放大”,“缩小”按钮组件。

3.用于控制地图显示视图移动的“↑”,“↓”,“←”,“→”按钮组件。

构成总结:根据以上的素材,或者用更贴合vue框架的语言来说,拥有以上组件,可以完成一个地图组件所需的基本功能,即:

地图显示地图缩放地图视图移动

由此脑海里已经有了一个大致的地图组件的雏形(大概长这样)

实际在项目中遇到的情况很可能就是从这一步开始的,按照画面的式样去做需求分析,这里为了记叙一个完整的思路,所以引进一下前面的构思做铺垫。

目录结构设计:

有了画面和初步的功能分析,现在来思考一下具体实现的框架。
由于现在这个地图充其量不过是画面的一个组件,或者通俗一点说是画面的一个小的功能,所以整体还是采用画面包含组件的结构来部署资源,如下:

画面文件夹 组件文件夹 Map.vueMoveUpButton.vueMoveDownButton.vue…(左右按钮)ZoomInButton.vueZoomOutButton.vue ShowMapPage.vue

到此为止需求分析明确了,目录结构也很清晰,可以着手实现功能了。

功能作成(coding) 分析功能

在着手做以前,最好脑子里可以先过一遍,我到底需要实现几个功能,尤其是试做一个全新的机能,让自己先有点谱,比做到哪里算哪里要有建设性的多。
为了做这样的一个可以完成显示,移动控制和缩放功能的地图,我需要提出疑问:
1.固定大小的矢量图形地图,如何缩放?
2.如何来控制显示区域的移动?

带着疑问,根据拿到的素材,即svg文件做了简单分析。
svg的显示原理是其实是通过viewBox属性去控制的,本身只是一个固定像素的矢量图形。
这时只要简单地百度一下就会知道viewBox的显示原理。好记性不如烂笔头,这里也记录一下我的分析和理解。
做一个简单的svg画布,宽为1000,高为800
放一些用于标记位置坐标的矩形,宽高都为200,并在对应的矩形中写上当前矩形右下角到画布起点(左上角)的横向距离和纵向距离,目的是为了标定了画布起点到该矩形的范围。


浏览器预览效果如下:

可以看到现在viewBox=“0 0 1000 800”,其中这四个参数分别代表了
0:从svg横坐标为0的点开始显示
0:从svg纵坐标为0的点开始显示
1000:显示宽度为1000
800:显示高度为800
通过设定viewBox的前两个参数可以控制整个svg画布的显示起始位置
->同理可以控制地图的显示起始位置
->让地图看起来向各个方向移动
举例
修改viewBox="0 0 1000 800"为viewBox=“200 0 1000 800”
即从画布横向距离为200,纵向距离为0的点开始,取一个宽为1000,高为200的范围进行显示。
效果如下:

可以看到之前靠左侧宽度为200的一列矩形消失不见了,取而代之现在顶格显示的是原先距离左上角横向距离200,显示范围为400x200的矩形,即显示画布的视图向右边移动了200。
举例
同理修改viewBox="0 0 1000 800"为viewBox=“0 200 1000 800”,即纵坐标向下200。就可得到视图向下移动200的效果
效果如下:

移动的原理说到这里已经可以理解了,接着要着手看缩放的原理。
之前也提到了viewBox的后两位参数是用来控制显示画布的范围,当画布上的地图1:1显示时,显示区域应该等于地图的实际大小。
但如果要放大地图,就等同于显示的窗口大小不变,显示的范围缩小了,从原本可以看到地图的全貌变成只能看到地图放大以后的一部分。
svg会将这部分视图重新显示在固定高宽的窗口中,不过既然显示的视图变小了,svg需要对这部分图形做扩充,从而让看到的内容还是充满整个窗口的。由于svg是矢量图形,扩充以后也不会失真,从而达到了视图上的“放大”的效果。
理解完毕以后来实 *** 一下。
举例
修改viewBox="0 0 1000 800"为viewBox=“0 0 500 400”,即将显示的区域缩小为原先的1/2。就可得到放大1倍的视图效果
效果如下:

通过标记的每个矩形的显示范围也可以看出,当前窗口显示了高为400,宽为500的画布大小。

分析功能总结

由此之前的两个疑问,即如何达成地图视图的移动和缩放就完成了。

代码分块

快乐的写函数时间(假的,这一步没有之前的功能分析,很容易写的很乱,增熵行为在协同coding是大忌)
大概列出需要的函数:

MapMoveUp()
MapMoveDown()
...其余两个move函数
MapZoomIn()
MapzoomOut()
DisplayMap()

根据这些函数可以列出需要的data:

iDisplayTop
iDisplayiLeft
iDisplayHeight
iDisplayWidth
↑需要向地图组件传的参数
iMapShowScale
iMapMoveXStep
iMapMoveYStep
↑ *** 作以后带来的自变量
具体功能实现

在每个函数中做好自己的一小部分就好,时刻注意代码的框架管理。以下举几个例子,主要要记住每个函数 *** 作的关键data是谁,不要浪费脑细胞去想不相关的。

DisplayMap()
{	
this.$ref.refMapName.SetMapData(this.iDisplayiLeft,this.iDisplayTop,this.iDisplayHeight,this.iDisplayWidth);
}

↑在Display函数中只需要直接影响地图显示的4个量,
最多涉及4个量的相关转换,具体各个量的变化应该放在相关的触发函数里去做。

MapMoveUp()
{
	if(this.iDisplayTop <= 0 )
	{
		this.iDisplayTop = 0;
	}
	else
	{
		this.iDisplayTop = this.iDisplayTop - this.iMapMoveYStep;
	}
	this.DisplayMap();
}

向上的按钮实则在改变的就是显示视图的纵坐标,每次按下则上移(减去)固定的步长。不过视图不可能一直上移,当iDisplayTop小于0,即显示的纵坐标已经跑到地图上面,则需要限制它为0,不然就会无止境的上移。
凝练一下每个Move函数在做的内容其实就是

控制iDisplayLeft或iDisplayTop 通过+或-移动距离来改变iDisplayTop(或iDisplayLeft)限制iDisplayTop和iDisplayLeft不超过地图的最大宽和高

这也符合上面说的函数只关心自己的关键data这点。

同理MapMoveLeft()也可如法炮制,但在做MapMoveDown()和MapMoveRight()的时候要注意,向右或向下移动时,iDisplayTop和iDisplayLeft的范围限制会随着显示视图缩小的倍率 发生变化。究竟是怎么一回事儿呢?可以来思考一下:
1倍的视图下,并不能下移或者右移,当然也不能左移或者上移。
后者很简单,因为有iShowTop和iShowLeft的<0的条件限制,前者是为什么呢?因为当前的显示区域等于地图的实际大小,也就是说没有多余的可以向右或者向下移动的空间了,但是当显示区域减小(地图视觉效果放大)时,一部分的地图超出了显示区域,这就是当前可以右移或者下移的空间。
如图:

所以这段随着地图缩放的区域的大小限制了视图最大的右移和下移,即限制iDisplayLeft和iDisplayTop的条件。那就来看看不同倍率下,iDisplayLeft可以达到的最大值为多少,如图:

通过图示法不难发现,iDisplayLeft可以达到的最大值即iDisplayMaxLeft=iMapWidth - 当前显示区域的宽度(iDisplayWidth)
同理iDisplayMaxTop=iMapHeight - 当前显示区域的高度(iDisplayHeight)
很显然iDisplayWidth和iDisplayHeight是随iDisplayScale自变量产生的应变量,这不应该被定义在data的成员变量中,而是可以通过iMapHeight/iMapScale 和 iMapWidth/iMapSale 得到的。
那么剩下两个Move函数也可以得到了,以MapMoveRight()为例:

MapMoveRight()
{	
	let iDisplayMaxLeft = iMapwidth - iMapWidth/iMapScale;
	if(iDisplayLeft >= iDisplayMapMaxLeft)
	{
		iDisplayLeft = iDisplayMapMaxLeft  ;
	}
	else
	{	
 		iDisplayLeft = iDisplayLeft + iMapMoveXStep;
	}
	this.DisplayMap();
}

控制移动的函数到此为止基本完成,速速把缩放的功能也写了,这一步依然牢记控制的关键data,很简单,每一次缩放只针对iMapScale做倍乘而已,当然不可能一味放大或缩小,和之前一样缩放函数中要做的还是两点,或者说一点:

控制iMapScale 控制iMapScale的范围让iMapScale倍乘或倍除某个值达到缩放的效果

而改变地图的高宽,即对地图缩放显示的并不在此处理,统一放在显示地图的DIsplayMap()中处理。此函数里只关心iMapSale,最多涉及其他与地图4个主要参数无关但相应产生的应变量,例如iMaxDisplayLeft。
它在之前的data定义中没有定义,而是通过每一次进入函数申请临时变量,通过进一步计算来取得,但如果在后续的处理中需要很方便的获取它,也可以进行定义,并在缩放函数中去进行刷新。
举例

iMaxLeftDisplayLeft : 0,
UpdateDisplayMaxTopLeft()
{
	this.iMaxDisplayLeft = this.iMapWidth - this.iMapWidth/this.iMapScale;
	this.iMaxDisplayTop = this.iMapHeight - this.iMapHeight/this.iMapScale;
}
MapZoomIn()
{
	if(this.iMapScale >= 8)//以8倍为例,实际可以定义最大的倍率常量,方便后续很容易的更改
	{
		this.iMapScale = 8;
	}
	else
	{	
		this.iMapScale = this.iMapScale * 2;//以2为例,实际可以定义倍率步进,方便后续很容易的更改
	}
	this.UpdateDisplayMaxTopLeft();
	this.DisplayMap();
}

而此时不要忘了,地图的显示处理中,要将刚刚变化的iMapScale绑定进去。

DisplauMap()
{
	this.iDisplayHeight = this.iDisplayHeight/this.iMapScale;
	this.iDisplayWidrh = this.iDispWidrh/this.iMapScale;
	this.$ref.refMapName.SetMapData(this.iDisplayiLeft,this.iDisplayTop,this.iDisplayHeight,this.iDisplayWidth);
}

由此,基本的地图控制基本完成。

优化及改进

在实际测试时,我发现,当在8倍大的缩放情况下挪至地图最右端后,再按下缩小键,显示区域明显超过了当前地图的范围,也就是当前的iDisplayLeft > iMaxDisplayLeft,这是由于在较大的倍率时,可以移动的范围比较小倍率时要多,所以从大倍率回到小倍率时,已经在大倍率下最大left位置的视图就会在小倍率视图中相对偏移出地图。
所以需要做进一步的显示控制,这就涉及到DisplayTop和iDisplayLeft的check,前面说了,地图的显示统一做在DisplayMap()中,这里容易混淆的点是,是否因为点击了放大缩小按钮,画面显示不正确,所以要在缩放按钮里做判断。从一开始就提到的每个函数要有一个关键的data处理可以得到结论,这样做完全不符合对数据的保密性和单一控制性,缩放最关心的依旧还是iMapScale,而不是其他,这里要完善的措施应该做在显示地图时,即DisplayMap()中添加如下部分代码:



	if(this.iDisplayTop > this.iMaxDisplayTop)
	{
		this.iDisplayTop = this.iMaxDisplayTop;
	}
	if(this.iDisplayLeft > this.iMaxDisplayLeft)
	{
		this.iDisplayLeft = this.iMaxDisplayLeft;
	}

	

最新的DisplayMap()应该是这样:

DisplauMap()
{
	if(this.iDisplayTop > this.iMaxDisplayTop)
	{
		this.iDisplayTop = this.iMaxDisplayTop;
	}
	if(this.iDisplayLeft > this.iMaxDisplayLeft)
	{
		this.iDisplayLeft = this.iMaxDisplayLeft;
	}
	this.iDisplayHeight = this.iDisplayHeight/this.iMapScale;
	this.iDisplayWidrh = this.iDispWidrh/this.iMapScale;
	this.$ref.refMapName.SetMapData(this.iDisplayiLeft,this.iDisplayTop,this.iDisplayHeight,this.iDisplayWidth);
}

改善部分可以对按钮的式样做一些调整,比如设置按钮的活性非活性,由于之前创建的变量已经足够支撑条件判断,在这一步的函数会很简单,只需要判断当前的iDisplayTop和iDisplayLeft是否超过其边界值,如果没有则可以压下,超过则不可压下,而完全不需要对这些控制地图显示的变量进行任何 *** 作,这块函数只关心是否要把按钮的状态设为true或者false,仅此而已。

总结

以上就是一次开发的思路记录,搭积木就是宏观的规划,不堆积不必要的,永远关注这一块稳不稳固,有无精简的可能,及时调整不合理的地方,从小到大,逐步完善。希望自己在以后的开发实践中也能贯彻这样的思路,写出不仅能跑还能各种变更也不会头昏眼花的好coding。bug或许永远改不完,但若能控制它生长的范围,是一件听上去很有希望的好事儿。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1321335.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-12
下一篇 2022-06-12

发表评论

登录后才能评论

评论列表(0条)

保存