这一章,咱们来说鼠标如何选择变换后的图形。
首先给大家举个栗子:在2029年末世之战的时候,终结者想干掉人类领袖大壮,可是大壮太强,而且其实力需要复杂运算才能知晓。所以终结者就想回到1997年,在大壮实力弱小、且已知的情况下将其干掉。这样根据物质不易法则,2029年末世之战中的人类领袖大壮也就不会存在。

接下来给大家解密终结者穿梭时间的方法。

终结者需要知道数据:

  • 1997年大壮的初始属性,比如构成大壮轮廓的顶点集合;
  • 大壮从1997到2029的变换信息,比如其大壮移动了多少、旋转了多少、长大了多少。

根据物质不易法则:物质不变,空间不变;空间不变,时间不变。
将物质不易法则逆推,依旧成立:物质改变,空间改变;空间改变,时间改变。
所以终结者想要回到1997 年,只要根据大壮的变换规则逆向变换自己的位置就可以回到1997年。

比如:

  • 从1997年到2029年,大壮沿x 轴移动了100,沿y 轴移动了200,旋转了90度,变大了2倍。
  • 终结者(鼠标点位)就要沿x 轴移动了-100,沿y 轴移动了-200,旋转-90度,点位到圆心点的距离缩小2倍。

注意:终结者的变换顺序要和大壮的变换顺序一致;终结者改变的只是点位,点没有尺寸,其点位变换本质是在目标对象所在的canvas画布的坐标系的位移。只有如此,当终结者穿梭到1997年的时候,才可以精准定位大壮。
图示:
image.png

接下来我们就在代码里走一下这个原理:
先画了一颗爱心,其所在的canvas 画布坐标系在x、y方向分别位移了(300,400)

const poly=new Poly({
    position:new Vector2(300,400),
    stroke:true,
    close:true,
    crtPath:function(ctx){
        ctx.beginPath();
        ctx.moveTo(0,0);
        ctx.bezierCurveTo(-200,-50,-180,-300,0,-200);
        ctx.bezierCurveTo(180,-300,200,-50,0,0);
    }
});
poly.draw(ctx);

image.png

若我的鼠标想要选择这颗爱心,那它的位置就要基于爱心的变换信息反向变换:x、y方向分别位移(-300,-400)。代码如下:

const mousePos=getMousePos(event,canvas);
poly.crtPath(ctx);
const [nx,ny]=[
    mousePos.x-poly.position.x,
    mousePos.y-poly.position.y
];
const bool=ctx.isPointInPath(nx,ny);

图形变换中的位移说完了,那它的旋转、缩放也是同样道理,就是让鼠标位置基于图形的变换信息反向变换。
下面我直接将所有变换的方法封装到了获取鼠标点位的方法里,即getMousePos(event,poly) ,event是事件,poly 是图形。
代码如下:

const getMousePos=function(event,canvas,obj=null){
    //获取鼠标位置
    const {clientX,clientY}=event;
    //获取canvas 边界位置
    const {top,left}=canvas.getBoundingClientRect();
    //计算鼠标在canvas 中的位置
    const x=clientX-left;
    const y=clientY-top;
    const mousePos=new Vector2(x,y);
    if(obj){
        const {position,scale,rotation}=obj;
        mousePos.sub(position);
        mousePos.rotate(-rotation);
        mousePos.divide(scale);
    }
    return mousePos;
};

mousePos 是一个Vector2 对象,其中封装了关于向量的常用方法。如:

export default class Vector2{
    constructor(x=0,y=0){
        this.x=x;
        this.y=y;
    }
    //减法
    sub(v){
        this.x -= v.x;
        this.y -= v.y;
        return this;
    }
    //基于原点旋转
    rotate(angle){
        const c = Math.cos( angle ), s = Math.sin( angle );
        const {x,y}=this;
        this.x = x * c - y * s;
        this.y = x * s + y * c;
        return this;
    }
    //向量除法
    divide ( v ) {
       this.x /= v.x;
       this.y /= v.y;
       return this;
    }
    //...
}

好啦,关于变换后的图形选择我们就说到这。
其实图形图形选择的方法是有很多的,下一章我再跟大家说一个图形选择的方法:图形选择-网格选择

注:物质不易是我从修仙小说上课看的,没有科学依据,只为辅助大家理解代码。

源码地址


已注销
148 声望9 粉丝