正如markE 所说, Eric(KineticJS 的创建者)教程网站上的本教程是 KineticJS 中所有自由转换的基础。
我将详细介绍实际的自由变换逻辑,主要有两个功能:
function addAnchor(group, x, y, name) {
var stage = group.getStage();
var layer = group.getLayer();
//Create the anchor shape
var anchor = new Kinetic.Circle({
x: x,
y: y,
stroke: '#666',
fill: '#ddd',
strokeWidth: 2,
radius: 8,
name: name,
draggable: true,
dragOnTop: false
});
//Calls the update function which handles the transform logic
anchor.on('dragmove', function() {
update(this);
layer.draw();
});
//When the anchor is selected, we want to turn dragging off for the group
//This is so that only the anchor is draggable, and we can transform instead of drag
anchor.on('mousedown touchstart', function() {
group.setDraggable(false);
this.moveToTop();
});
//Turn back on draggable for the group
anchor.on('dragend', function() {
group.setDraggable(true);
layer.draw();
});
// add hover styling
anchor.on('mouseover', function() {
var layer = this.getLayer();
document.body.style.cursor = 'pointer';
this.setStrokeWidth(4);
layer.draw();
});
anchor.on('mouseout', function() {
var layer = this.getLayer();
document.body.style.cursor = 'default';
this.setStrokeWidth(2);
layer.draw();
});
group.add(anchor);
}
就像名字所说的那样,该addAnchor
函数将单个锚点(或自由变换句柄)添加到Kinetic.Group
. 默认情况下它使用 aKinetic.Circle
但实际上你可以使用任何你想要的形状。
group
- 要将锚添加到的组
x
- 锚点的 x 位置
y
- 锚点的 y 位置
name
- 锚的名称(通常描述锚所代表的位置,如topLeft或bottomRight
您会注意到一堆events
附加到新创建的锚点,其中大多数都非常简单,但您要注意的是dragmove
事件 - 这个事件是调用处理所有逻辑update
的函数的事件转换组/节点。需要注意的update
是,对于拖动锚点的每个像素都会调用该函数。
本教程使用 4 个角锚(因此每个组/节点调用 addAnchor 4 次),但如果您想要 8 个锚(4 个角 - 4 个边),那么您只需调整逻辑以正确定位锚并移动锚转换时正确。
顺便说一句,我们将 Anchors 添加到 Group 的原因是因为我们需要它们与相关节点进行分组,并通过拖动和转换来坚持每个节点。
第二种方法是update
函数:
function update(activeAnchor) {
var group = activeAnchor.getParent();
//Get each anchor inside the group, by name. Keep a standard set of names for every anchor you use and note they have to be names not ids because there will be multiple anchors named .topLeft in your app
var topLeft = group.get('.topLeft')[0];
var topRight = group.get('.topRight')[0];
var bottomRight = group.get('.bottomRight')[0];
var bottomLeft = group.get('.bottomLeft')[0];
var image = group.get('.image')[0];
var anchorX = activeAnchor.getX();
var anchorY = activeAnchor.getY();
// update anchor positions
switch (activeAnchor.getName()) {
case 'topLeft':
//When topLeft is being dragged, topRight has to update in the Y-axis
//And bottomLeft has to update in the X-axis
topRight.setY(anchorY);
bottomLeft.setX(anchorX);
break;
case 'topRight':
topLeft.setY(anchorY);
bottomRight.setX(anchorX);
break;
case 'bottomRight':
bottomLeft.setY(anchorY);
topRight.setX(anchorX);
break;
case 'bottomLeft':
bottomRight.setY(anchorY);
topLeft.setX(anchorX);
break;
}
image.setPosition(topLeft.getPosition());
//New height and width are calculated with a little math
//by calculating the distance between the update anchor positions.
var width = topRight.getX() - topLeft.getX();
var height = bottomLeft.getY() - topLeft.getY();
if(width && height) {
image.setSize(width, height);
}
}
该update
函数只接受一个参数:activeAnchor
被拖动的锚点。
之后,它会选择组内的其他锚点(使用您需要为每个节点提供的静态名称并在整个应用程序中保持一致),以便我们可以activeAnchor
在拖动时转换它们的位置。
如果您使用 8 个锚点而不是 4 个锚点,switch 语句可能会变得非常大。这是因为您需要考虑在拖动其中一个锚点时翻译几乎所有其他锚点。
以 8 个锚点为例:如果拖动topLeft
锚点,则需要更新锚点的y位置、topRight
锚点的x位置,bottomLeft
对于topMid
和leftMid
锚点,您需要调整x、y值以保持在其他锚。
更新锚位置后,该函数处理调整形状大小的逻辑。请注意,形状是由var image = group.get('.image')[0];
但是选择的,您可以做的是使用该get
功能按类型选择并执行以下操作:
var shape = group.get('Shape')[0];
显然,如果每组只有 1 个形状(用于变换)+ 4 或 8 个锚点,这将最有效。
如果您有任何其他问题或意见,请告诉我!祝你好运!