JS图形编辑器实现标尺功能示例详解.docx
第
JS图形编辑器实现标尺功能示例详解
项目地址:
/F-star/suik
线上体验:
blog.fstars.wang/app/suika/
标尺指的是画布上边和左边的两个有刻度的尺子,作用让用户知道他正在编辑的视口所在位置范围。
我们的需求是:间隔特定的长度,绘制一个刻度,并显示这个刻度在X轴或Y轴上的位置。
先看最终实现效果:
标尺功能演示
可以看到,视口移动后,标尺上的刻度能正确地改变。此外缩放画布,标尺的步长会发生改变,保持一个比较适合的密度。
总体实现思路:
确定刻度尺的步长(step)。步长是和画布缩放比(zoom)相关的,zoom越大,step就越小;
计算出需要绘制的所有刻度。分别为从视口从左侧到右侧,从上边到下边的范围;
绘制。绘制上也是有考量的,先绘制背景,然后绘制刻度,最后绘制分界线。
步长会根据zoom进行设置,目的是让视口中的标尺能绘制适宜密度的刻度。
假设我们的步长固定为50,不跟随zoom改变,在100%看起来效果不错:
但当你缩小时,会变成下面这样:
密度过大,导致数字重叠。同样,放大时则过于稀疏,刻度很难才见到一个,没能发挥标尺的效用。
步长怎么计算呢?
理论上步长可以是50,那么51好像也行,3也行。但更建议使用5的倍数、2的倍数、25的倍数这些作为步长。
因为没有什么理论参考,所以我还是选择参考市面上的设计工具的步长变化设计。
比如figma,zoom落在[100%,200%)的步长为50,[200%,500%)则是10等等。
我的实现为:
constgetStepByZoom=(zoom:number)={
//可用的步长列表
conststeps=[1,2,5,10,25,50,100,250,500,1000,2500,5000];
//看着figma的step变化想出的一个奇怪的规律
//然后找出可选步长列表最近的并大于它的step作为最终步长
conststep=50/zoom;
for(leti=0,len=steps.length;ilen;i++){
if(steps[i]=step)returnsteps[i];
returnsteps[0];
conststep=getStepByZoom(zoom);
这里我讲解水平(x轴)方向的情况。垂直方向同理,就不赘叙了。
首先计算出视口最左侧和最右侧的x坐标值。
需要视口坐标转场景坐标的知识,如果你不懂,看我这篇文章:
《图形编辑器:场景坐标、视口坐标以及它们之间的转换》
letstartXInScene=viewport.x+startXInViewport/zoom;//视口坐标转场景
letendXInScene=viewport.width+startYInViewport/zoom;//视口坐标转场景
然后找离它们最近的落在刻度上的值。
对此,我实现了一个getClosestVal方法。
*找出离value最近的segment的倍数值
constgetClosestVal=(value:number,segment:number)={
constn=Math.floor(value/segment);
constleft=segment*n;
constright=segment*(n+1);
returnvalue-left=right-valueleft:right;
startXInScene=getClosestVal(startXInScene,step);
endXInScene=getClosestVal(endXInScene,step);
得到起点和终点,我们可以开始循环了,从startXInScene开始,每次循环加一个step,直至达到末尾为止。
ctx.textAlign=center//文字水平居中对齐
while(startXInScene=endXInScene){
ctx.st