オブジェクト(のようなImage
)を?のストロークに制限することは可能Polygon
ですか?
jsfiddle: http: //jsfiddle.net/CZzpZ/
JSfiddleでは、ヨーダのImage
ドラッグをポリゴンのストロークに制限するようにしますpoly
。Complex Drag Bounds KineticJSチュートリアルを調べましたが、パスへの制約についての手がかりは得られず、リージョン内でのみ制約しました。
オブジェクト(のようなImage
)を?のストロークに制限することは可能Polygon
ですか?
jsfiddle: http: //jsfiddle.net/CZzpZ/
JSfiddleでは、ヨーダのImage
ドラッグをポリゴンのストロークに制限するようにしますpoly
。Complex Drag Bounds KineticJSチュートリアルを調べましたが、パスへの制約についての手がかりは得られず、リージョン内でのみ制約しました。
これを行う1つの方法は、でdragBoundFunc
、のポイントを取得し、Polygon
基本的なベクトル計算を適用して、ポリゴン上のどのポイントに位置が最も近いかを見つけることです。
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
}
};
これはうまくいくようですが、それでも解決策はやや厄介だと感じています。もっと良い方法があるかもしれませんが、私には考えられません。