大家好,我是前端西瓜哥。
当天咱们来钻研一下Figma是如何示意图形的,这里以矩形为切入点启动钻研。
明确最便捷的矩形的示意后,钻研其余的图形就可以举一反三。
矩形的普通表白
假设让我设计一个矩形图形的物理属性,我会怎样设计?
我张口就来:x、y、width、height、rotation。
对一些便捷的图形编辑操作,这些属性基本上是够用的,比如白板工具,假设你
不思考或许不宿愿图形可以翻转(flip)
的话。
Figma须要思考翻转的状况的,此外还有斜切的状况。
翻转的场景:
还有斜切的场景,在选中多个图形而后缩放时有出现。
这些表白光靠上方的几个属性是不够的,咱们看看Figma为了表白这些成果,是怎样去设计矩形的。
Figma矩形物理属性
与物理消息相关的属性如下:
{"size":{"x":100,"y":100},"transform":{"m00":1,"m01":3,"m02":5,"m10":2,"m11":4,"m12":6},//省略其余有关属性}
没有位置属性,这个属性自动是(0,0),实践它转移到transform的矩阵的位移子矩阵上了。
size示意宽高,但属性名用的是x(宽)和y(高),通常上width和height语义更好,这样应该是用了矢量类型。
size示意宽高,通常上width和height语义更好,这样应该是用了平面矢量类型的结构体,所以是x和y。
transform示意一个3×3的变换矩阵。
m00|m01|m02m10|m11|m120|0|1
上方的transform属性的值所对应的矩阵为:
1|3|52|4|60|0|1
属性面板
再看看这些属性对应的右侧属性面板。
x、y区分是5和6,它是(0,0)启动transform后的结果,这个间接对应transform.m02和tansfrom.m12。
import{Matrix}from"pixi.js";constmatrix=newMatrix(1,2,3,4,5,6);consttopLeft=matrix.apply({x:0,y:0});//{x:5,y:6}//或间接点consttopLeft={x:5,y:6}
而后这里的width和height,是223.61和500,怎样来的?
它们对应的是矩形的两条边变形后的长度,如下:
uiWidth为(0,0)和(width,0)启动矩阵变换后坐标点之间的距离。
constdistance=(p1,p2)=>{consta=p1.x-p2.x;constb=p1.y-p2.y;returnMath.sqrt(a*a+b*b);};constmatrix=newMatrix(1,2,3,4,5,6);consttopLeft={x:5,y:6}consttopRight=matrix.apply({x:100,y:0});distance(topRight,topLeft);//223.60679774997897
最后计算出223.60679774997897,四舍五入获取223.61。
高度计算同理。
uiHeight为(0,0)和(0,height)启动矩阵变换后坐标点之间的距离。
constmatrix=newMatrix(1,2,3,4,5,6);consttopLeft={x:5,y:6}constbottomLeft=matrix.apply({x:0,y:100});distance(bottomLeft,topLeft);//500
旋转角度
最后是旋转角度,它是宽度对应的矩形边向量,逆时针旋转90度的向量所对应的角度。
先计算宽边向量,而后逆时针旋转90度获取旋转向量,最后计算旋转向量对应的角度。
constwSideVec={x:topRight.x-topLeft.x,y:topRight.y-topLeft.y};//逆时针旋转90度,获取旋转向量constrotationMatrix=newMatrix(0,-1,1,0,0,0);constrotationVec=rotationMatrix.apply(wSideVec);constrad=calcVectorRadian(rotationVec);constdeg=rad2Deg(rad);//
这里用了几个工具函数。
//计算和(0,-1)的夹角constcalcVectorRadian=(vec)=>{consta=[vec.x,vec.y];constb=[0,-1];//这个是基准角度//经常使用点积公式计算夹脚constdotProduct=a[0]*b[0]+a[1]*b[1];constd=Math.sqrt(a[0]*a[0]+a[1]*a[1])*Math.sqrt(b[0]*b[0]+b[1]*b[1]);letrad=Math.acos(dotProduct/d);if(vec.x>0){//假设x>0,则rad转为(-PI,0)之间的值rad=-rad;}returnrad;}//弧度转角度constrad2Deg=(rad)=>(rad*180)/Math.PI;
Figma的角度示意比拟顺当。
特色为:基准角度朝上,对应向量为(0,-1),角度方向为逆时针,角度范围限定为
(-180,180]
,计算向量角度时要留意这个特色启动调整。
完整代码成功
线上demo:
代码成功:
import{Matrix}from"pixi.js";//计算和(0,-1)的夹角constcalcVectorRadian=(vec)=>{consta=[vec.x,vec.y];constb=[0,-1];constdotProduct=a[0]*b[0]+a[1]*b[1];constd=Math.sqrt(a[0]*a[0]+a[1]*a[1])*Math.sqrt(b[0]*b[0]+b[1]*b[1]);letrad=Math.acos(dotProduct/d);if(vec.x>0){//假设x>0,则rad为(-PI,0)之间的值rad=-rad;}returnrad;}//弧度转角度constrad2Deg=(rad)=>(rad*180)/Math.PI;constdistance=(p1,p2)=>{consta=p1.x-p2.x;constb=p1.y-p2.y;returnMath.sqrt(a*a+b*b);};constgetAttrs=(size,transform)=>{constwidth=size.x;constheight=size.y;constmatrix=newMatrix(transform.m00,//1transform.m10,//2transform.m01,//3transform.m11,//4transform.m02,//5transform.m12//6);consttopLeft={x:transform.m02,y:transform.m12};console.log("x:",topLeft.x)console.log("y:",topLeft.y)consttopRight=matrix.apply({x:width,y:0});console.log("width:",distance(topRight,topLeft));//223.60679774997897constbottomLeft=matrix.apply({x:0,y:height});console.log("height:",distance(bottomLeft,topLeft));//500constwSideVec={x:topRight.x-topLeft.x,y:topRight.y-topLeft.y};//逆时针旋转90度,获取旋转向量constrotationMatrix=newMatrix(0,-1,1,0,0,0);constrotationVec=rotationMatrix.apply(wSideVec);constrad=calcVectorRadian(rotationVec);constdeg=rad2Deg(rad);console.log("rotation:",deg);//-63.43494882292201};getAttrs(//宽高{x:100,y:100},//变换矩阵{m00:1,m01:3,m02:5,m10:2,m11:4,m12:6,});
运转一下,结果和属性面板分歧。
开头
Figma只用宽高和变换矩阵来表白矩形,在数据层可以用精简的数据表白丰盛的变形,此内在渲染的时刻也能将矩阵运算交给GPU启动并行运算,是不错的做法。