Take the 2-minute tour ×

Is it possible to constrain an object (like an Image) to the stroke of a Polygon?

jsfiddle: http://jsfiddle.net/CZzpZ/

In the JSfiddle, I'll like the Yoda Image to has its drag constrained to the stroke of the polygon poly. Looked into the Complex Drag Bounds KineticJS tutorial but didnt get any clue on constraining to a path, only constraining within a region.

share|improve this question
I was able to slap together a shoddy hack (otherwise this would be an answer, not a comment) which seems to work, but it fails when the group offset is anything other than (0, 0). I suppose the problem stems from the fact that I do not know if the points obtained from poly.getPoints are absolute or respective to the group. Still, I suppose this is something to start with: jsfiddle.net/7H2sj/7 –  Rikonator Dec 23 '12 at 22:24

1 Answer 1

up vote 1 down vote accepted

One way to do this is to, in dragBoundFunc, get the points of the Polygon, and then apply some basic vector math to find out which point on the polygon the position is closest to.


I must point out, that I did not like that for each possible drag-able image, you would have to set a different dragBoundFunc, since they would have different polygons. So, I made a generic function polyStrokeBoundDragFunc(imaginative, right?) and had it assume that the polygon was passed as an argument.

So, the dragBoundFunc looks like


dragBoundFunc: function(pos) {
            return polyStrokeBoundDragFunc(pos, poly, group);

The group is included here because we need the group of the polygon as well to convert the position from absolute to local. This is required since, if the polygon is in a group, polygon.getPoints will give the local points. And the position passed to dragBoundFunc seems to be absolute.

Now, the meat of the issue, which still is pretty raw(because it's unoptimized meat, you see)! This function finds out the nearest point on each side to the given position, then compares the distances. The side with the minimum distance from the position is selected.

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.   
        //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

This seems to work, but I still feel that the solution is somewhat messy. There might be a better way, which I can't think of.

share|improve this answer
Thank you Rikonator, you're a GENIUS!! –  Nyxynyx Dec 24 '12 at 3:08

Your Answer


