2012-03-07 13:45:48 +08:00
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
// Node
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
|
|
* Node constructor. Nodes are entities that can move around
|
|
|
|
* and have events bound to them. They are the building blocks of a KineticJS
|
|
|
|
* application
|
|
|
|
* @constructor
|
|
|
|
* @param {Object} config
|
|
|
|
*/
|
|
|
|
Kinetic.Node = function(config) {
|
|
|
|
this.visible = true;
|
|
|
|
this.isListening = true;
|
|
|
|
this.name = undefined;
|
|
|
|
this.alpha = 1;
|
|
|
|
this.x = 0;
|
|
|
|
this.y = 0;
|
|
|
|
this.scale = {
|
|
|
|
x: 1,
|
|
|
|
y: 1
|
|
|
|
};
|
|
|
|
this.rotation = 0;
|
|
|
|
this.centerOffset = {
|
|
|
|
x: 0,
|
|
|
|
y: 0
|
|
|
|
};
|
|
|
|
this.eventListeners = {};
|
2012-03-18 01:28:25 +08:00
|
|
|
this.dragConstraint = 'none';
|
2012-03-14 13:11:22 +08:00
|
|
|
this.dragBounds = {};
|
|
|
|
this._draggable = false;
|
2012-03-07 13:45:48 +08:00
|
|
|
|
|
|
|
// set properties from config
|
|
|
|
if(config) {
|
|
|
|
for(var key in config) {
|
|
|
|
// handle special keys
|
|
|
|
switch (key) {
|
2012-03-18 01:28:25 +08:00
|
|
|
case 'draggable':
|
2012-03-07 13:45:48 +08:00
|
|
|
this.draggable(config[key]);
|
|
|
|
break;
|
2012-03-18 01:28:25 +08:00
|
|
|
case 'listen':
|
2012-03-07 13:45:48 +08:00
|
|
|
this.listen(config[key]);
|
|
|
|
break;
|
2012-03-18 01:28:25 +08:00
|
|
|
case 'rotationDeg':
|
2012-03-07 13:45:48 +08:00
|
|
|
this.rotation = config[key] * Math.PI / 180;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
this[key] = config[key];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-03-25 11:52:17 +08:00
|
|
|
|
|
|
|
// overrides
|
|
|
|
if(this.centerOffset.x === undefined) {
|
|
|
|
this.centerOffset.x = 0;
|
|
|
|
}
|
|
|
|
if(this.centerOffset.y === undefined) {
|
|
|
|
this.centerOffset.y = 0;
|
|
|
|
}
|
2012-03-07 13:45:48 +08:00
|
|
|
};
|
|
|
|
/*
|
|
|
|
* Node methods
|
|
|
|
*/
|
|
|
|
Kinetic.Node.prototype = {
|
|
|
|
/**
|
|
|
|
* bind events to the node. KineticJS supports mouseover, mousemove,
|
|
|
|
* mouseout, mousedown, mouseup, click, dblclick, touchstart, touchmove,
|
|
|
|
* touchend, dbltap, dragstart, dragmove, and dragend. Pass in a string
|
|
|
|
* of event types delimmited by a space to bind multiple events at once
|
2012-03-18 01:28:25 +08:00
|
|
|
* such as 'mousedown mouseup mousemove'. include a namespace to bind an
|
|
|
|
* event by name such as 'click.foobar'.
|
2012-03-07 13:45:48 +08:00
|
|
|
* @param {String} typesStr
|
|
|
|
* @param {function} handler
|
|
|
|
*/
|
|
|
|
on: function(typesStr, handler) {
|
2012-03-18 01:28:25 +08:00
|
|
|
var types = typesStr.split(' ');
|
2012-03-07 13:45:48 +08:00
|
|
|
/*
|
|
|
|
* loop through types and attach event listeners to
|
2012-03-18 01:28:25 +08:00
|
|
|
* each one. eg. 'click mouseover.namespace mouseout'
|
2012-03-07 13:45:48 +08:00
|
|
|
* will create three event bindings
|
|
|
|
*/
|
|
|
|
for(var n = 0; n < types.length; n++) {
|
|
|
|
var type = types[n];
|
|
|
|
var event = (type.indexOf('touch') === -1) ? 'on' + type : type;
|
2012-03-18 01:28:25 +08:00
|
|
|
var parts = event.split('.');
|
2012-03-07 13:45:48 +08:00
|
|
|
var baseEvent = parts[0];
|
2012-03-18 01:28:25 +08:00
|
|
|
var name = parts.length > 1 ? parts[1] : '';
|
2012-03-07 13:45:48 +08:00
|
|
|
|
|
|
|
if(!this.eventListeners[baseEvent]) {
|
|
|
|
this.eventListeners[baseEvent] = [];
|
|
|
|
}
|
|
|
|
|
|
|
|
this.eventListeners[baseEvent].push({
|
|
|
|
name: name,
|
|
|
|
handler: handler
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* remove event bindings from the node. Pass in a string of
|
|
|
|
* event types delimmited by a space to remove multiple event
|
2012-03-18 01:28:25 +08:00
|
|
|
* bindings at once such as 'mousedown mouseup mousemove'.
|
2012-03-07 13:45:48 +08:00
|
|
|
* include a namespace to remove an event binding by name
|
2012-03-18 01:28:25 +08:00
|
|
|
* such as 'click.foobar'.
|
2012-03-07 13:45:48 +08:00
|
|
|
* @param {String} typesStr
|
|
|
|
*/
|
|
|
|
off: function(typesStr) {
|
2012-03-18 01:28:25 +08:00
|
|
|
var types = typesStr.split(' ');
|
2012-03-07 13:45:48 +08:00
|
|
|
|
|
|
|
for(var n = 0; n < types.length; n++) {
|
|
|
|
var type = types[n];
|
|
|
|
var event = (type.indexOf('touch') === -1) ? 'on' + type : type;
|
2012-03-18 01:28:25 +08:00
|
|
|
var parts = event.split('.');
|
2012-03-07 13:45:48 +08:00
|
|
|
var baseEvent = parts[0];
|
|
|
|
|
|
|
|
if(this.eventListeners[baseEvent] && parts.length > 1) {
|
|
|
|
var name = parts[1];
|
|
|
|
|
|
|
|
for(var i = 0; i < this.eventListeners[baseEvent].length; i++) {
|
|
|
|
if(this.eventListeners[baseEvent][i].name === name) {
|
|
|
|
this.eventListeners[baseEvent].splice(i, 1);
|
|
|
|
if(this.eventListeners[baseEvent].length === 0) {
|
|
|
|
this.eventListeners[baseEvent] = undefined;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-03-14 12:16:25 +08:00
|
|
|
}
|
|
|
|
else {
|
2012-03-07 13:45:48 +08:00
|
|
|
this.eventListeners[baseEvent] = undefined;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* show node
|
|
|
|
*/
|
|
|
|
show: function() {
|
|
|
|
this.visible = true;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* hide node
|
|
|
|
*/
|
|
|
|
hide: function() {
|
|
|
|
this.visible = false;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get zIndex
|
|
|
|
*/
|
|
|
|
getZIndex: function() {
|
|
|
|
return this.index;
|
|
|
|
},
|
2012-04-01 06:17:36 +08:00
|
|
|
/**
|
|
|
|
* get absolute z-index by taking into account
|
|
|
|
* all parent and sibling indices
|
|
|
|
*/
|
|
|
|
getAbsoluteZIndex: function() {
|
|
|
|
var level = this.getLevel();
|
|
|
|
var stage = this.getStage();
|
|
|
|
var that = this;
|
|
|
|
var index = 0;
|
|
|
|
function addChildren(children) {
|
|
|
|
var nodes = [];
|
|
|
|
for(var n = 0; n < children.length; n++) {
|
|
|
|
var child = children[n];
|
|
|
|
index++;
|
|
|
|
|
|
|
|
if(child.className !== 'Shape') {
|
|
|
|
nodes = nodes.concat(child.getChildren());
|
|
|
|
}
|
|
|
|
|
|
|
|
if(child.id === that.id) {
|
|
|
|
n = children.length;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(nodes.length > 0 && nodes[0].getLevel() <= level) {
|
|
|
|
addChildren(nodes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(that.className !== 'Stage') {
|
|
|
|
addChildren(that.getStage().getChildren());
|
|
|
|
}
|
|
|
|
|
|
|
|
return index;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get node level in node tree
|
|
|
|
*/
|
|
|
|
getLevel: function() {
|
|
|
|
var level = 0;
|
|
|
|
var parent = this.parent;
|
|
|
|
while(parent) {
|
|
|
|
level++;
|
|
|
|
parent = parent.parent;
|
|
|
|
}
|
|
|
|
return level;
|
|
|
|
},
|
2012-03-07 13:45:48 +08:00
|
|
|
/**
|
|
|
|
* set node scale. If only one parameter is passed in,
|
|
|
|
* then both scaleX and scaleY are set with that parameter
|
|
|
|
* @param {Number} scaleX
|
|
|
|
* @param {Number} scaleY
|
|
|
|
*/
|
|
|
|
setScale: function(scaleX, scaleY) {
|
|
|
|
if(scaleY) {
|
|
|
|
this.scale.x = scaleX;
|
|
|
|
this.scale.y = scaleY;
|
2012-03-14 12:16:25 +08:00
|
|
|
}
|
|
|
|
else {
|
2012-03-07 13:45:48 +08:00
|
|
|
this.scale.x = scaleX;
|
|
|
|
this.scale.y = scaleX;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get scale
|
|
|
|
*/
|
|
|
|
getScale: function() {
|
|
|
|
return this.scale;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* set node position
|
|
|
|
* @param {Number} x
|
|
|
|
* @param {Number} y
|
|
|
|
*/
|
|
|
|
setPosition: function(x, y) {
|
|
|
|
this.x = x;
|
|
|
|
this.y = y;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get node position relative to container
|
|
|
|
*/
|
|
|
|
getPosition: function() {
|
|
|
|
return {
|
|
|
|
x: this.x,
|
|
|
|
y: this.y
|
|
|
|
};
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get absolute position relative to stage
|
|
|
|
*/
|
|
|
|
getAbsolutePosition: function() {
|
2012-03-25 11:52:17 +08:00
|
|
|
return this.getAbsoluteTransform().getTranslation();
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* move node by an amount
|
|
|
|
* @param {Number} x
|
|
|
|
* @param {Number} y
|
|
|
|
*/
|
|
|
|
move: function(x, y) {
|
|
|
|
this.x += x;
|
|
|
|
this.y += y;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* set node rotation in radians
|
|
|
|
* @param {Number} theta
|
|
|
|
*/
|
|
|
|
setRotation: function(theta) {
|
|
|
|
this.rotation = theta;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* set node rotation in degrees
|
|
|
|
* @param {Number} deg
|
|
|
|
*/
|
|
|
|
setRotationDeg: function(deg) {
|
|
|
|
this.rotation = (deg * Math.PI / 180);
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get rotation in radians
|
|
|
|
*/
|
|
|
|
getRotation: function() {
|
|
|
|
return this.rotation;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get rotation in degrees
|
|
|
|
*/
|
|
|
|
getRotationDeg: function() {
|
|
|
|
return this.rotation * 180 / Math.PI;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* rotate node by an amount in radians
|
|
|
|
* @param {Number} theta
|
|
|
|
*/
|
|
|
|
rotate: function(theta) {
|
|
|
|
this.rotation += theta;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* rotate node by an amount in degrees
|
|
|
|
* @param {Number} deg
|
|
|
|
*/
|
|
|
|
rotateDeg: function(deg) {
|
|
|
|
this.rotation += (deg * Math.PI / 180);
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* listen or don't listen to events
|
|
|
|
* @param {Boolean} isListening
|
|
|
|
*/
|
|
|
|
listen: function(isListening) {
|
|
|
|
this.isListening = isListening;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* move node to top
|
|
|
|
*/
|
|
|
|
moveToTop: function() {
|
|
|
|
var index = this.index;
|
|
|
|
this.parent.children.splice(index, 1);
|
|
|
|
this.parent.children.push(this);
|
|
|
|
this.parent._setChildrenIndices();
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* move node up
|
|
|
|
*/
|
|
|
|
moveUp: function() {
|
|
|
|
var index = this.index;
|
|
|
|
this.parent.children.splice(index, 1);
|
|
|
|
this.parent.children.splice(index + 1, 0, this);
|
|
|
|
this.parent._setChildrenIndices();
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* move node down
|
|
|
|
*/
|
|
|
|
moveDown: function() {
|
|
|
|
var index = this.index;
|
|
|
|
if(index > 0) {
|
|
|
|
this.parent.children.splice(index, 1);
|
|
|
|
this.parent.children.splice(index - 1, 0, this);
|
|
|
|
this.parent._setChildrenIndices();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* move node to bottom
|
|
|
|
*/
|
|
|
|
moveToBottom: function() {
|
|
|
|
var index = this.index;
|
|
|
|
this.parent.children.splice(index, 1);
|
|
|
|
this.parent.children.unshift(this);
|
|
|
|
this.parent._setChildrenIndices();
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* set zIndex
|
2012-03-12 14:01:23 +08:00
|
|
|
* @param {int} zIndex
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
|
|
|
setZIndex: function(zIndex) {
|
|
|
|
var index = this.index;
|
|
|
|
this.parent.children.splice(index, 1);
|
|
|
|
this.parent.children.splice(zIndex, 0, this);
|
|
|
|
this.parent._setChildrenIndices();
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* set alpha. Alpha values range from 0 to 1.
|
|
|
|
* A node with an alpha of 0 is fully transparent, and a node
|
|
|
|
* with an alpha of 1 is fully opaque
|
|
|
|
* @param {Object} alpha
|
|
|
|
*/
|
|
|
|
setAlpha: function(alpha) {
|
|
|
|
this.alpha = alpha;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get alpha. Alpha values range from 0 to 1.
|
|
|
|
* A node with an alpha of 0 is fully transparent, and a node
|
|
|
|
* with an alpha of 1 is fully opaque
|
|
|
|
*/
|
|
|
|
getAlpha: function() {
|
|
|
|
return this.alpha;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get absolute alpha
|
|
|
|
*/
|
|
|
|
getAbsoluteAlpha: function() {
|
|
|
|
var absAlpha = 1;
|
|
|
|
var node = this;
|
|
|
|
// traverse upwards
|
2012-03-18 01:28:25 +08:00
|
|
|
while(node.className !== 'Stage') {
|
2012-03-07 13:45:48 +08:00
|
|
|
absAlpha *= node.alpha;
|
|
|
|
node = node.parent;
|
|
|
|
}
|
|
|
|
return absAlpha;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* enable or disable drag and drop
|
2012-03-14 13:11:22 +08:00
|
|
|
* @param {Boolean} isDraggable
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
2012-03-14 13:11:22 +08:00
|
|
|
draggable: function(isDraggable) {
|
|
|
|
if(this.draggable !== isDraggable) {
|
2012-04-02 01:06:00 +08:00
|
|
|
if(isDraggable) {
|
2012-03-07 13:45:48 +08:00
|
|
|
this._initDrag();
|
|
|
|
}
|
2012-03-14 13:11:22 +08:00
|
|
|
else {
|
|
|
|
this._dragCleanup();
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
2012-03-14 13:11:22 +08:00
|
|
|
this._draggable = isDraggable;
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* determine if node is currently in drag and drop mode
|
|
|
|
*/
|
|
|
|
isDragging: function() {
|
|
|
|
var go = Kinetic.GlobalObject;
|
|
|
|
return go.drag.node !== undefined && go.drag.node.id === this.id && go.drag.moving;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* move node to another container
|
2012-03-12 14:01:23 +08:00
|
|
|
* @param {Container} newContainer
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
|
|
|
moveTo: function(newContainer) {
|
|
|
|
var parent = this.parent;
|
|
|
|
// remove from parent's children
|
|
|
|
parent.children.splice(this.index, 1);
|
|
|
|
parent._setChildrenIndices();
|
|
|
|
|
|
|
|
// add to new parent
|
|
|
|
newContainer.children.push(this);
|
|
|
|
this.index = newContainer.children.length - 1;
|
|
|
|
this.parent = newContainer;
|
|
|
|
newContainer._setChildrenIndices();
|
|
|
|
|
|
|
|
// update children hashes
|
|
|
|
if(this.name) {
|
|
|
|
parent.childrenNames[this.name] = undefined;
|
|
|
|
newContainer.childrenNames[this.name] = this;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get parent container
|
|
|
|
*/
|
|
|
|
getParent: function() {
|
|
|
|
return this.parent;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get layer associated to node
|
|
|
|
*/
|
|
|
|
getLayer: function() {
|
|
|
|
if(this.className === 'Layer') {
|
|
|
|
return this;
|
2012-03-14 12:16:25 +08:00
|
|
|
}
|
|
|
|
else {
|
2012-03-07 13:45:48 +08:00
|
|
|
return this.getParent().getLayer();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get stage associated to node
|
|
|
|
*/
|
|
|
|
getStage: function() {
|
2012-03-13 13:41:09 +08:00
|
|
|
if(this.className === 'Stage') {
|
|
|
|
return this;
|
2012-03-14 12:16:25 +08:00
|
|
|
}
|
|
|
|
else {
|
2012-03-13 13:41:09 +08:00
|
|
|
return this.getParent().getStage();
|
|
|
|
}
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get name
|
|
|
|
*/
|
|
|
|
getName: function() {
|
|
|
|
return this.name;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* set center offset
|
|
|
|
* @param {Number} x
|
|
|
|
* @param {Number} y
|
|
|
|
*/
|
|
|
|
setCenterOffset: function(x, y) {
|
|
|
|
this.centerOffset.x = x;
|
|
|
|
this.centerOffset.y = y;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get center offset
|
|
|
|
*/
|
|
|
|
getCenterOffset: function() {
|
|
|
|
return this.centerOffset;
|
|
|
|
},
|
2012-03-13 13:41:09 +08:00
|
|
|
/**
|
2012-03-14 12:16:25 +08:00
|
|
|
* transition node to another state. Any property that can accept a real
|
2012-03-20 13:44:42 +08:00
|
|
|
* number can be transitioned, including x, y, rotation, alpha, strokeWidth,
|
|
|
|
* radius, scale.x, scale.y, centerOffset.x, centerOffset.y, etc.
|
2012-03-13 13:41:09 +08:00
|
|
|
* @param {Object} config
|
2012-03-20 13:44:42 +08:00
|
|
|
* @config {Number} [duration] duration that the transition runs in seconds
|
2012-04-02 01:06:00 +08:00
|
|
|
* @config {String} [easing] easing function. can be linear, ease-in, ease-out, or ease-in-out.
|
|
|
|
* linear is the default
|
2012-03-20 13:44:42 +08:00
|
|
|
* @config {Function} [callback] callback function to be executed when
|
|
|
|
* transition completes
|
2012-03-13 13:41:09 +08:00
|
|
|
*/
|
|
|
|
transitionTo: function(config) {
|
|
|
|
var layer = this.getLayer();
|
|
|
|
var that = this;
|
2012-03-14 12:16:25 +08:00
|
|
|
var duration = config.duration * 1000;
|
2012-03-20 12:09:13 +08:00
|
|
|
var starts = {};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* clear transition if one is currenlty running.
|
|
|
|
* This make it easy to start new transitions without
|
|
|
|
* having to explicitly cancel old ones
|
|
|
|
*/
|
2012-03-21 13:46:54 +08:00
|
|
|
Kinetic.GlobalObject._clearTransition(this);
|
2012-03-14 12:16:25 +08:00
|
|
|
|
2012-03-13 13:41:09 +08:00
|
|
|
for(var key in config) {
|
2012-03-20 13:36:30 +08:00
|
|
|
if(config.hasOwnProperty(key) && key !== 'duration' && key !== 'easing' && key !== 'callback') {
|
2012-03-14 12:16:25 +08:00
|
|
|
if(config[key].x !== undefined || config[key].y !== undefined) {
|
2012-03-20 12:09:13 +08:00
|
|
|
starts[key] = {};
|
2012-03-18 01:28:25 +08:00
|
|
|
var propArray = ['x', 'y'];
|
2012-03-14 12:16:25 +08:00
|
|
|
for(var n = 0; n < propArray.length; n++) {
|
|
|
|
var prop = propArray[n];
|
|
|
|
if(config[key][prop] !== undefined) {
|
2012-03-20 12:09:13 +08:00
|
|
|
starts[key][prop] = this[key][prop];
|
2012-03-14 12:16:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2012-03-20 12:09:13 +08:00
|
|
|
starts[key] = this[key];
|
2012-03-14 12:16:25 +08:00
|
|
|
}
|
2012-03-13 13:41:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
layer.transitions.push({
|
|
|
|
id: layer.transitionIdCounter++,
|
|
|
|
time: 0,
|
|
|
|
config: config,
|
|
|
|
node: this,
|
2012-03-20 12:09:13 +08:00
|
|
|
starts: starts
|
2012-03-13 13:41:09 +08:00
|
|
|
});
|
2012-03-20 12:09:13 +08:00
|
|
|
|
2012-03-19 10:50:20 +08:00
|
|
|
Kinetic.GlobalObject._handleAnimation();
|
2012-03-13 13:41:09 +08:00
|
|
|
},
|
2012-03-14 13:11:22 +08:00
|
|
|
/**
|
|
|
|
* set drag constraint
|
|
|
|
* @param {String} constraint
|
|
|
|
*/
|
|
|
|
setDragConstraint: function(constraint) {
|
|
|
|
this.dragConstraint = constraint;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get drag constraint
|
|
|
|
*/
|
|
|
|
getDragConstraint: function() {
|
|
|
|
return this.dragConstraint;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* set drag bounds
|
|
|
|
* @param {Object} bounds
|
|
|
|
* @config {Number} [left] left bounds position
|
|
|
|
* @config {Number} [top] top bounds position
|
|
|
|
* @config {Number} [right] right bounds position
|
|
|
|
* @config {Number} [bottom] bottom bounds position
|
|
|
|
*/
|
|
|
|
setDragBounds: function(bounds) {
|
|
|
|
this.dragBounds = bounds;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get drag bounds
|
|
|
|
*/
|
|
|
|
getDragBounds: function() {
|
|
|
|
return this.dragBounds;
|
|
|
|
},
|
2012-03-24 14:39:54 +08:00
|
|
|
/**
|
2012-03-25 01:03:28 +08:00
|
|
|
* get transform of the node while taking into
|
|
|
|
* account the transforms of its parents
|
2012-03-24 14:39:54 +08:00
|
|
|
*/
|
2012-03-25 01:03:28 +08:00
|
|
|
getAbsoluteTransform: function() {
|
|
|
|
// absolute transform
|
|
|
|
var am = new Kinetic.Transform();
|
2012-03-24 14:39:54 +08:00
|
|
|
|
|
|
|
var family = [];
|
|
|
|
var parent = this.parent;
|
|
|
|
|
|
|
|
family.unshift(this);
|
|
|
|
while(parent) {
|
|
|
|
family.unshift(parent);
|
|
|
|
parent = parent.parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(var n = 0; n < family.length; n++) {
|
|
|
|
var node = family[n];
|
2012-03-25 01:03:28 +08:00
|
|
|
var m = node.getTransform();
|
2012-03-24 14:39:54 +08:00
|
|
|
am.multiply(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
return am;
|
|
|
|
},
|
|
|
|
/**
|
2012-03-25 01:03:28 +08:00
|
|
|
* get transform of the node while not taking
|
|
|
|
* into account the transforms of its parents
|
2012-03-24 14:39:54 +08:00
|
|
|
*/
|
2012-03-25 01:03:28 +08:00
|
|
|
getTransform: function() {
|
|
|
|
var m = new Kinetic.Transform();
|
2012-03-23 04:47:37 +08:00
|
|
|
|
|
|
|
if(this.x !== 0 || this.y !== 0) {
|
|
|
|
m.translate(this.x, this.y);
|
|
|
|
}
|
|
|
|
if(this.rotation !== 0) {
|
|
|
|
m.rotate(this.rotation);
|
|
|
|
}
|
|
|
|
if(this.scale.x !== 1 || this.scale.y !== 1) {
|
|
|
|
m.scale(this.scale.x, this.scale.y);
|
|
|
|
}
|
|
|
|
if(this.centerOffset.x !== 0 || this.centerOffset.y !== 0) {
|
|
|
|
m.translate(-1 * this.centerOffset.x, -1 * this.centerOffset.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
return m;
|
|
|
|
},
|
2012-03-07 13:45:48 +08:00
|
|
|
/**
|
|
|
|
* initialize drag and drop
|
|
|
|
*/
|
|
|
|
_initDrag: function() {
|
2012-04-02 10:38:30 +08:00
|
|
|
this._dragCleanup();
|
2012-03-07 13:45:48 +08:00
|
|
|
var go = Kinetic.GlobalObject;
|
|
|
|
var that = this;
|
2012-03-18 01:28:25 +08:00
|
|
|
this.on('mousedown.initdrag touchstart.initdrag', function(evt) {
|
2012-03-07 13:45:48 +08:00
|
|
|
var stage = that.getStage();
|
|
|
|
var pos = stage.getUserPosition();
|
|
|
|
|
|
|
|
if(pos) {
|
2012-03-25 01:03:28 +08:00
|
|
|
var m = that.getTransform().getTranslation();
|
|
|
|
var am = that.getAbsoluteTransform().getTranslation();
|
2012-03-07 13:45:48 +08:00
|
|
|
go.drag.node = that;
|
2012-03-25 11:52:17 +08:00
|
|
|
go.drag.offset.x = pos.x - that.getAbsoluteTransform().getTranslation().x;
|
|
|
|
go.drag.offset.y = pos.y - that.getAbsoluteTransform().getTranslation().y;
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* remove drag and drop event listener
|
|
|
|
*/
|
|
|
|
_dragCleanup: function() {
|
2012-03-18 01:28:25 +08:00
|
|
|
this.off('mousedown.initdrag');
|
|
|
|
this.off('touchstart.initdrag');
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* handle node events
|
|
|
|
* @param {String} eventType
|
|
|
|
* @param {Event} evt
|
|
|
|
*/
|
|
|
|
_handleEvents: function(eventType, evt) {
|
2012-03-26 03:45:46 +08:00
|
|
|
if(this.className === 'Shape') {
|
|
|
|
evt.shape = this;
|
|
|
|
}
|
2012-03-19 02:24:57 +08:00
|
|
|
var stage = this.getStage();
|
|
|
|
this._handleEvent(this, stage.mouseoverShape, stage.mouseoutShape, eventType, evt);
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* handle node event
|
|
|
|
*/
|
|
|
|
_handleEvent: function(node, mouseoverNode, mouseoutNode, eventType, evt) {
|
|
|
|
var el = node.eventListeners;
|
|
|
|
var okayToRun = true;
|
2012-03-07 13:45:48 +08:00
|
|
|
|
2012-03-19 02:24:57 +08:00
|
|
|
/*
|
|
|
|
* determine if event handler should be skipped by comparing
|
|
|
|
* parent nodes
|
|
|
|
*/
|
|
|
|
if(eventType === 'onmouseover' && mouseoutNode && mouseoutNode.id === node.id) {
|
|
|
|
okayToRun = false;
|
|
|
|
}
|
|
|
|
else if(eventType === 'onmouseout' && mouseoverNode && mouseoverNode.id === node.id) {
|
|
|
|
okayToRun = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(el[eventType] && okayToRun) {
|
|
|
|
var events = el[eventType];
|
|
|
|
for(var i = 0; i < events.length; i++) {
|
|
|
|
events[i].handler.apply(node, [evt]);
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
|
|
|
}
|
2012-03-19 02:24:57 +08:00
|
|
|
|
|
|
|
var mouseoverParent = mouseoverNode ? mouseoverNode.parent : undefined;
|
|
|
|
var mouseoutParent = mouseoutNode ? mouseoutNode.parent : undefined;
|
|
|
|
|
|
|
|
// simulate event bubbling
|
|
|
|
if(!evt.cancelBubble && node.parent.className !== 'Stage') {
|
|
|
|
this._handleEvent(node.parent, mouseoverParent, mouseoutParent, eventType, evt);
|
|
|
|
}
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
2012-03-12 14:01:23 +08:00
|
|
|
};
|