Javascript 将图像约束到KineticJS中的路径

Javascript 将图像约束到KineticJS中的路径,javascript,jquery,html,canvas,kineticjs,Javascript,Jquery,Html,Canvas,Kineticjs,是否可以将对象(如图像)约束到多边形的笔划 jsfiddle: 在JSfiddle中,我希望Yoda图像将其拖动约束到多边形多边形的笔划。查看了KineticJS教程,但没有得到任何关于约束到路径的线索,只在一个区域内进行约束。一种方法是,在dragBoundFunc中,获取多边形的点,然后应用一些基本的向量数学,找出该位置最接近多边形上的点 我必须指出,我不喜欢对每个可能的可拖动图像设置不同的dragBoundFunc,因为它们具有不同的多边形。因此,我创建了一个通用函数polyStroke

是否可以将对象(如
图像
)约束到
多边形的笔划

jsfiddle:


在JSfiddle中,我希望Yoda
图像
将其拖动约束到多边形
多边形
的笔划。查看了KineticJS教程,但没有得到任何关于约束到路径的线索,只在一个区域内进行约束。

一种方法是,在
dragBoundFunc
中,获取
多边形的点,然后应用一些基本的向量数学,找出该位置最接近多边形上的点

我必须指出,我不喜欢对每个可能的可拖动图像设置不同的
dragBoundFunc
,因为它们具有不同的多边形。因此,我创建了一个通用函数
polyStrokeBoundDragFunc
(想象,对吧?),并假设多边形作为参数传递

因此,
dragBoundFunc
看起来像

...

dragBoundFunc: function(pos) {
            return polyStrokeBoundDragFunc(pos, poly, group);
        }
...
这里包含该组,因为我们还需要多边形组来将位置从绝对位置转换为局部位置。这是必需的,因为如果多边形在一个组中,
polygon.getPoints
将给出局部点。传递给
dragBoundFunc
的位置似乎是绝对的

现在,肉的问题,这仍然是相当生的(因为它是未优化的肉,你看)!此函数用于找出每侧距离给定位置最近的点,然后比较距离。选择距离该位置最小的一侧

var polyStrokeBoundDragFunc = function(pos, poly, group) {
    //Check if the poly is usable as a polygon
    if(!poly || !poly.getPoints) {
        return pos;
    }

    //Convert the drag position from absolute to local to the group
    //if, of course, there is a group
    if(group && group.getAbsolutePosition) {
        pos.x = pos.x - group.getAbsolutePosition().x;
        pos.y = pos.y - group.getAbsolutePosition().y;
    }

    var newX = pos.x, newY = pos.y,
        diff = 9999;   //A bloated diff, for minimum comparision

    //Get the list of points from the polygon
    var points = poly.getPoints();

    //The algorithm is simple, iterate through the list of points
    //and select a pair which forms a side of the polygon.
    //For this side, pick a main point. Find the direction vector
    //with respect to this main point, and find the position vector
    //from this main point to the drag position.
    //Dot product of position vector and direction vector give us
    //the projection of the point on the current side.
    //A simple bounds checking to ensure that the projection is on
    //the side, then a distance calculation.
    //If the distance found is less than the current minimum difference
    //update diff, newX and newY.   
    for(var i=0; i<points.length; i++) {
        //Get point pair.
        var p1 = points[i];
        var p2 = points[(i+1)%points.length];

        //Find the bounds for checking projection bounds later on        
        var minX = (p1.x < p2.x ? p1.x : p2.x),
            minY = (p1.y < p2.y ? p1.y : p2.y),
            maxX = (p1.x > p2.x ? p1.x : p2.x),
            maxY = (p1.y > p2.y ? p1.y : p2.y);

        //Select p2 as the main point.
        //Find the direction vector and normalize it.       
        var dir = {x: p1.x - p2.x, y: p1.y - p2.y};
        var m = Math.sqrt(dir.x*dir.x + dir.y*dir.y);
        if(m !== 0) {
            dir.x = dir.x/m;
            dir.y = dir.y/m;
        }

        //Find the position vector        
        var pVec = {x: pos.x - p2.x, y: pos.y - p2.y};

        //Dot product        
        var dot = pVec.x * dir.x + pVec.y * dir.y;

        //Find the projection along the current side        
        var p = {x: p2.x + dir.x*dot, y: p2.y + dir.y*dot};       

        //Bounds checking to ensure projection remains
        //between the point pair.       
        if(p.x < minX)
            p.x = minX;
        else if(p.x > maxX)
            p.x = maxX;

        if(p.y < minY)
            p.y = minY;
        else if(p.y > maxY)
            p.y = maxY;

         //Distance calculation.
         //Could have simply used squared distance, but I figured 9999 may
         //not be bloated enough for that.       
         var d = Math.sqrt((p.x-pos.x)*(p.x-pos.x) + (p.y-pos.y)*(p.y-pos.y));

         //Minimum comparision.       
         if(d < diff) {
              diff = d;
              newX = p.x;
              newY = p.y;
         }
    }

    //If in a group's local, convert back to absolute    
    if(group && group.getAbsolutePosition) {
        newX += group.getAbsolutePosition().x;
        newY += group.getAbsolutePosition().y;
    }

    //Return updated drag position.
    return {
        x: newX, 
        y: newY
    }
};
var polyStrokeBoundDragFunc=函数(位置、多边形、组){
//检查多边形是否可用作多边形
如果(!poly | |!poly.getPoints){
返回pos;
}
//将拖动位置从绝对位置转换为组的局部位置
//当然,如果有一组
if(group&&group.getAbsolutePosition){
pos.x=pos.x-group.getAbsolutePosition().x;
pos.y=pos.y-group.getAbsolutePosition().y;
}
变量newX=pos.x,newY=pos.y,
diff=9999;//膨胀的diff,用于最小比较
//从多边形中获取点列表
var points=poly.getPoints();
//该算法很简单,可以遍历点列表
//并选择一对形成多边形的边。
//对于这一边,选择一个主要点,找到方向向量
//关于这个要点,找到位置向量
//从该要点到拖动位置。
//位置向量和方向向量的点积给我们
//点在当前边上的投影。
//一个简单的边界检查,以确保投影处于打开状态
//侧边,然后计算距离。
//如果找到的距离小于当前最小差值
//更新diff、newX和newY。
对于(变量i=0;i p2.x?p1.x:p2.x),
maxY=(p1.y>p2.y?p1.y:p2.y);
//选择p2作为主要点。
//找到方向向量并将其规格化。
var dir={x:p1.x-p2.x,y:p1.y-p2.y};
var m=Math.sqrt(dir.x*dir.x+dir.y*dir.y);
如果(m!==0){
dir.x=dir.x/m;
dir.y=dir.y/m;
}
//找到位置向量
var pVec={x:pos.x-p2.x,y:pos.y-p2.y};
//点积
var dot=pVec.x*dir.x+pVec.y*dir.y;
//查找沿当前边的投影
var p={x:p2.x+dir.x*dot,y:p2.y+dir.y*dot};
//边界检查以确保投影保持不变
//在点对之间。
如果(p.xmaxX)
p、 x=最大x;
如果(p.y最大值)
p、 y=最大值;
//距离计算。
//可以简单地使用平方距离,但我认为9999可能
//你还不够臃肿。
变量d=数学sqrt((p.x-pos.x)*(p.x-pos.x)+(p.y-pos.y)*(p.y-pos.y));
//最小比较。
if(d

这似乎有效,但我仍然觉得解决方案有些混乱。可能有更好的方法,我想不出来。

我能够拼凑出一个劣质的黑客(否则这将是一个答案,而不是一个评论),这似乎是可行的,但当组偏移量不是(0,0)时,它就失败了。我想问题是因为我不知道从
poly.getPoints
获得的点是绝对的还是与组相对的。不过,我想这是一个开始:谢谢你,里科纳特,你是个天才!!