2012-11-27 12:42:01 +08:00
|
|
|
(function() {
|
2012-11-14 15:22:56 +08:00
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* Node constructor. Nodes are entities that can be transformed, layered,
|
|
|
|
* and have bound events. The stage, layers, groups, and shapes all extend Node.
|
2012-11-14 15:22:56 +08:00
|
|
|
* @constructor
|
|
|
|
* @param {Object} config
|
|
|
|
* @param {Number} [config.x]
|
|
|
|
* @param {Number} [config.y]
|
2012-11-27 11:12:02 +08:00
|
|
|
* @param {Number} [config.width]
|
|
|
|
* @param {Number} [config.height]
|
2012-11-14 15:22:56 +08:00
|
|
|
* @param {Boolean} [config.visible]
|
|
|
|
* @param {Boolean} [config.listening] whether or not the node is listening for events
|
|
|
|
* @param {String} [config.id] unique id
|
|
|
|
* @param {String} [config.name] non-unique name
|
|
|
|
* @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1
|
|
|
|
* @param {Object} [config.scale]
|
|
|
|
* @param {Number} [config.scale.x]
|
|
|
|
* @param {Number} [config.scale.y]
|
|
|
|
* @param {Number} [config.rotation] rotation in radians
|
|
|
|
* @param {Number} [config.rotationDeg] rotation in degrees
|
2012-11-27 11:12:02 +08:00
|
|
|
* @param {Object} [config.offset] offset from center point and rotation point
|
2012-11-14 15:22:56 +08:00
|
|
|
* @param {Number} [config.offset.x]
|
|
|
|
* @param {Number} [config.offset.y]
|
|
|
|
* @param {Boolean} [config.draggable]
|
2012-11-27 11:12:02 +08:00
|
|
|
* @param {Function} [config.dragBoundFunc]
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
2012-11-27 12:42:01 +08:00
|
|
|
Kinetic.Node = function(config) {
|
2012-11-14 15:22:56 +08:00
|
|
|
this._nodeInit(config);
|
|
|
|
};
|
|
|
|
|
2012-11-27 12:42:01 +08:00
|
|
|
Kinetic.Node.prototype = {
|
2012-11-14 15:22:56 +08:00
|
|
|
_nodeInit: function(config) {
|
|
|
|
this.defaultNodeAttrs = {
|
|
|
|
visible: true,
|
|
|
|
listening: true,
|
|
|
|
name: undefined,
|
|
|
|
opacity: 1,
|
2012-07-04 03:07:27 +08:00
|
|
|
x: 0,
|
2012-11-14 15:22:56 +08:00
|
|
|
y: 0,
|
|
|
|
scale: {
|
|
|
|
x: 1,
|
|
|
|
y: 1
|
|
|
|
},
|
|
|
|
rotation: 0,
|
|
|
|
offset: {
|
|
|
|
x: 0,
|
|
|
|
y: 0
|
|
|
|
},
|
|
|
|
draggable: false
|
|
|
|
};
|
2012-03-07 13:45:48 +08:00
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
this.setDefaultAttrs(this.defaultNodeAttrs);
|
|
|
|
this.eventListeners = {};
|
|
|
|
this.setAttrs(config);
|
|
|
|
|
|
|
|
// bind events
|
|
|
|
var that = this;
|
|
|
|
this.on('idChange.kinetic', function(evt) {
|
|
|
|
var stage = that.getStage();
|
|
|
|
if(stage) {
|
|
|
|
stage._removeId(evt.oldVal);
|
|
|
|
stage._addId(that);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
this.on('nameChange.kinetic', function(evt) {
|
|
|
|
var stage = that.getStage();
|
|
|
|
if(stage) {
|
|
|
|
stage._removeName(evt.oldVal, that._id);
|
|
|
|
stage._addName(that);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* bind events to the node. KineticJS supports mouseover, mousemove,
|
|
|
|
* mouseout, mouseenter, mouseleave, mousedown, mouseup, click, dblclick, touchstart, touchmove,
|
|
|
|
* touchend, tap, dbltap, dragstart, dragmove, and dragend events. Pass in a string
|
|
|
|
* of events delimmited by a space to bind multiple events at once
|
|
|
|
* such as 'mousedown mouseup mousemove'. Include a namespace to bind an
|
2012-11-14 15:22:56 +08:00
|
|
|
* event by name such as 'click.foobar'.
|
|
|
|
* @name on
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-11-27 11:12:02 +08:00
|
|
|
* @param {String} typesStr e.g. 'click', 'mousedown touchstart', 'mousedown.foo touchstart.foo'
|
|
|
|
* @param {Function} handler The handler function is passed an event object
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
on: function(typesStr, handler) {
|
|
|
|
var types = typesStr.split(' ');
|
|
|
|
/*
|
|
|
|
* loop through types and attach event listeners to
|
|
|
|
* each one. eg. 'click mouseover.namespace mouseout'
|
|
|
|
* will create three event bindings
|
|
|
|
*/
|
|
|
|
var len = types.length;
|
|
|
|
for(var n = 0; n < len; n++) {
|
|
|
|
var type = types[n];
|
|
|
|
var event = type;
|
|
|
|
var parts = event.split('.');
|
|
|
|
var baseEvent = parts[0];
|
|
|
|
var name = parts.length > 1 ? parts[1] : '';
|
|
|
|
|
|
|
|
if(!this.eventListeners[baseEvent]) {
|
|
|
|
this.eventListeners[baseEvent] = [];
|
|
|
|
}
|
2012-08-26 13:26:25 +08:00
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
this.eventListeners[baseEvent].push({
|
|
|
|
name: name,
|
|
|
|
handler: handler
|
|
|
|
});
|
2012-07-14 12:24:38 +08:00
|
|
|
}
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* remove event bindings from the node. Pass in a string of
|
2012-11-14 15:22:56 +08:00
|
|
|
* event types delimmited by a space to remove multiple event
|
|
|
|
* bindings at once such as 'mousedown mouseup mousemove'.
|
|
|
|
* include a namespace to remove an event binding by name
|
|
|
|
* such as 'click.foobar'. If you only give a name like '.foobar',
|
|
|
|
* all events in that namespace will be removed.
|
|
|
|
* @name off
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-11-27 11:12:02 +08:00
|
|
|
* @param {String} typesStr e.g. 'click', 'mousedown touchstart', '.foobar'
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
off: function(typesStr) {
|
|
|
|
var types = typesStr.split(' ');
|
|
|
|
var len = types.length;
|
|
|
|
for(var n = 0; n < len; n++) {
|
|
|
|
var type = types[n];
|
|
|
|
//var event = (type.indexOf('touch') === -1) ? 'on' + type : type;
|
|
|
|
var event = type;
|
|
|
|
var parts = event.split('.');
|
|
|
|
var baseEvent = parts[0];
|
|
|
|
|
|
|
|
if(parts.length > 1) {
|
|
|
|
if(baseEvent) {
|
|
|
|
if(this.eventListeners[baseEvent]) {
|
|
|
|
this._off(baseEvent, parts[1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for(var type in this.eventListeners) {
|
|
|
|
this._off(type, parts[1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
delete this.eventListeners[baseEvent];
|
|
|
|
}
|
2012-07-14 12:24:38 +08:00
|
|
|
}
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* remove child from container
|
|
|
|
* @name remove
|
|
|
|
* @methodOf Kinetic.Container.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
2012-11-14 15:22:56 +08:00
|
|
|
remove: function() {
|
|
|
|
var parent = this.getParent();
|
|
|
|
if(parent && this.index !== undefined && parent.children[this.index]._id == this._id) {
|
|
|
|
var stage = parent.getStage();
|
|
|
|
/*
|
|
|
|
* remove event listeners and references to the node
|
|
|
|
* from the ids and names hashes
|
|
|
|
*/
|
|
|
|
if(stage) {
|
|
|
|
stage._removeId(this.getId());
|
|
|
|
stage._removeName(this.getName(), this._id);
|
|
|
|
}
|
|
|
|
|
|
|
|
Kinetic.Global._removeTempNode(this);
|
|
|
|
parent.children.splice(this.index, 1);
|
|
|
|
parent._setChildrenIndices();
|
|
|
|
|
2012-12-13 16:01:24 +08:00
|
|
|
// remove from DD
|
|
|
|
var dd = Kinetic.DD;
|
|
|
|
if(dd && dd.node && dd.node._id === this._id) {
|
|
|
|
delete Kinetic.DD.node;
|
|
|
|
}
|
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
// remove children
|
|
|
|
while(this.children && this.children.length > 0) {
|
|
|
|
this.children[0].remove();
|
|
|
|
}
|
2012-11-25 15:19:16 +08:00
|
|
|
delete this.parent;
|
2012-11-14 15:22:56 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get attrs
|
|
|
|
* @name getAttrs
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
getAttrs: function() {
|
|
|
|
return this.attrs;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* set default attrs. This method should only be used if
|
|
|
|
* you're creating a custom node
|
|
|
|
* @name setDefaultAttrs
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {Object} confic
|
|
|
|
*/
|
|
|
|
setDefaultAttrs: function(config) {
|
|
|
|
// create attrs object if undefined
|
|
|
|
if(this.attrs === undefined) {
|
|
|
|
this.attrs = {};
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
if(config) {
|
|
|
|
for(var key in config) {
|
|
|
|
/*
|
|
|
|
* only set the attr if it's undefined in case
|
|
|
|
* a developer writes a custom class that extends
|
|
|
|
* a Kinetic Class such that their default property
|
|
|
|
* isn't overwritten by the Kinetic Class default
|
|
|
|
* property
|
|
|
|
*/
|
|
|
|
if(this.attrs[key] === undefined) {
|
|
|
|
this.attrs[key] = config[key];
|
2012-10-04 06:50:04 +08:00
|
|
|
}
|
2012-10-04 10:38:12 +08:00
|
|
|
}
|
2012-11-14 15:22:56 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* set attrs
|
|
|
|
* @name setAttrs
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-11-27 11:12:02 +08:00
|
|
|
* @param {Object} config object containing key value pairs
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
setAttrs: function(config) {
|
|
|
|
if(config) {
|
|
|
|
for(var key in config) {
|
|
|
|
var method = 'set' + key.charAt(0).toUpperCase() + key.slice(1);
|
|
|
|
// use setter if available
|
2012-11-14 15:48:30 +08:00
|
|
|
if(Kinetic.Type._isFunction(this[method])) {
|
2012-11-14 15:22:56 +08:00
|
|
|
this[method](config[key]);
|
|
|
|
}
|
|
|
|
// otherwise set directly
|
|
|
|
else {
|
|
|
|
this.setAttr(key, config[key]);
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
|
|
|
}
|
2012-03-14 12:16:25 +08:00
|
|
|
}
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* determine if node is visible or not. Node is visible only
|
|
|
|
* if it's visible and all of its ancestors are visible. If an ancestor
|
|
|
|
* is invisible, this means that the node is also invisible
|
|
|
|
* @name getVisible
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
getVisible: function() {
|
2012-11-14 16:07:59 +08:00
|
|
|
var visible = this.attrs.visible, parent = this.getParent();
|
|
|
|
if(visible && parent && !parent.getVisible()) {
|
2012-11-14 15:22:56 +08:00
|
|
|
return false;
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
2012-11-14 16:07:59 +08:00
|
|
|
return visible;
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* determine if node is listening or not. Node is listening only
|
|
|
|
* if it's listening and all of its ancestors are listening. If an ancestor
|
|
|
|
* is not listening, this means that the node is also not listening
|
|
|
|
* @name getListening
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
getListening: function() {
|
2012-11-14 16:07:59 +08:00
|
|
|
var listening = this.attrs.listening, parent = this.getParent();
|
|
|
|
if(listening && parent && !parent.getListening()) {
|
2012-11-14 15:22:56 +08:00
|
|
|
return false;
|
|
|
|
}
|
2012-11-14 16:07:59 +08:00
|
|
|
return listening;
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* show node
|
|
|
|
* @name show
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
show: function() {
|
|
|
|
this.setVisible(true);
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* hide node. Hidden nodes are no longer detectable
|
|
|
|
* @name hide
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
hide: function() {
|
|
|
|
this.setVisible(false);
|
|
|
|
},
|
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* get zIndex relative to the node's siblings who share the same parent
|
2012-11-14 15:22:56 +08:00
|
|
|
* @name getZIndex
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
getZIndex: function() {
|
|
|
|
return this.index;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get absolute z-index which takes into account sibling
|
2012-11-27 11:12:02 +08:00
|
|
|
* and ancestor indices
|
2012-11-14 15:22:56 +08:00
|
|
|
* @name getAbsoluteZIndex
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
getAbsoluteZIndex: function() {
|
|
|
|
var level = this.getLevel();
|
|
|
|
var stage = this.getStage();
|
|
|
|
var that = this;
|
|
|
|
var index = 0;
|
|
|
|
function addChildren(children) {
|
|
|
|
var nodes = [];
|
|
|
|
var len = children.length;
|
|
|
|
for(var n = 0; n < len; n++) {
|
|
|
|
var child = children[n];
|
|
|
|
index++;
|
|
|
|
|
|
|
|
if(child.nodeType !== 'Shape') {
|
|
|
|
nodes = nodes.concat(child.getChildren());
|
|
|
|
}
|
|
|
|
|
|
|
|
if(child._id === that._id) {
|
|
|
|
n = len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(nodes.length > 0 && nodes[0].getLevel() <= level) {
|
|
|
|
addChildren(nodes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(that.nodeType !== 'Stage') {
|
|
|
|
addChildren(that.getStage().getChildren());
|
|
|
|
}
|
|
|
|
|
|
|
|
return index;
|
|
|
|
},
|
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* get node level in node tree. Returns an integer.<br><br>
|
2012-11-30 12:15:01 +08:00
|
|
|
* e.g. Stage level will always be 0. Layers will always be 1. Groups and Shapes will always
|
2012-11-27 11:12:02 +08:00
|
|
|
* be >= 2
|
2012-11-14 15:22:56 +08:00
|
|
|
* @name getLevel
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
getLevel: function() {
|
|
|
|
var level = 0;
|
|
|
|
var parent = this.parent;
|
|
|
|
while(parent) {
|
|
|
|
level++;
|
|
|
|
parent = parent.parent;
|
|
|
|
}
|
|
|
|
return level;
|
|
|
|
},
|
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* set node position relative to parent
|
2012-11-14 15:22:56 +08:00
|
|
|
* @name setPosition
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {Number} x
|
|
|
|
* @param {Number} y
|
|
|
|
*/
|
|
|
|
setPosition: function() {
|
2012-11-14 15:48:30 +08:00
|
|
|
var pos = Kinetic.Type._getXY([].slice.call(arguments));
|
2012-11-14 15:22:56 +08:00
|
|
|
this.setAttr('x', pos.x);
|
|
|
|
this.setAttr('y', pos.y);
|
|
|
|
},
|
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* get node position relative to parent
|
2012-11-14 15:22:56 +08:00
|
|
|
* @name getPosition
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
getPosition: function() {
|
2012-11-14 16:07:59 +08:00
|
|
|
var attrs = this.attrs;
|
2012-11-14 15:22:56 +08:00
|
|
|
return {
|
2012-11-14 16:07:59 +08:00
|
|
|
x: attrs.x,
|
|
|
|
y: attrs.y
|
2012-11-14 15:22:56 +08:00
|
|
|
};
|
|
|
|
},
|
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* get absolute position relative to the top left corner of the stage container div
|
2012-11-14 15:22:56 +08:00
|
|
|
* @name getAbsolutePosition
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
getAbsolutePosition: function() {
|
|
|
|
var trans = this.getAbsoluteTransform();
|
|
|
|
var o = this.getOffset();
|
|
|
|
trans.translate(o.x, o.y);
|
|
|
|
return trans.getTranslation();
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* set absolute position
|
|
|
|
* @name setAbsolutePosition
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-11-27 11:12:02 +08:00
|
|
|
* @param {Number} x
|
|
|
|
* @param {Number} y
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
setAbsolutePosition: function() {
|
2012-11-14 15:48:30 +08:00
|
|
|
var pos = Kinetic.Type._getXY([].slice.call(arguments));
|
2012-11-14 15:22:56 +08:00
|
|
|
var trans = this._clearTransform();
|
|
|
|
// don't clear translation
|
|
|
|
this.attrs.x = trans.x;
|
|
|
|
this.attrs.y = trans.y;
|
|
|
|
delete trans.x;
|
|
|
|
delete trans.y;
|
|
|
|
|
|
|
|
// unravel transform
|
|
|
|
var it = this.getAbsoluteTransform();
|
|
|
|
|
|
|
|
it.invert();
|
|
|
|
it.translate(pos.x, pos.y);
|
|
|
|
pos = {
|
|
|
|
x: this.attrs.x + it.getTranslation().x,
|
|
|
|
y: this.attrs.y + it.getTranslation().y
|
|
|
|
};
|
|
|
|
|
|
|
|
this.setPosition(pos.x, pos.y);
|
|
|
|
this._setTransform(trans);
|
|
|
|
},
|
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* move node by an amount relative to its current position
|
2012-11-14 15:22:56 +08:00
|
|
|
* @name move
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {Number} x
|
|
|
|
* @param {Number} y
|
|
|
|
*/
|
|
|
|
move: function() {
|
2012-11-14 15:48:30 +08:00
|
|
|
var pos = Kinetic.Type._getXY([].slice.call(arguments));
|
2012-11-14 15:22:56 +08:00
|
|
|
var x = this.getX();
|
|
|
|
var y = this.getY();
|
|
|
|
|
|
|
|
if(pos.x !== undefined) {
|
|
|
|
x += pos.x;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(pos.y !== undefined) {
|
|
|
|
y += pos.y;
|
2012-09-27 03:50:08 +08:00
|
|
|
}
|
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
this.setPosition(x, y);
|
|
|
|
},
|
2012-12-31 17:47:49 +08:00
|
|
|
_eachAncestorReverse: function(func, includeSelf) {
|
2012-12-31 15:14:23 +08:00
|
|
|
var family = [], parent = this.getParent();
|
|
|
|
|
|
|
|
// build family by traversing ancestors
|
2012-12-31 17:47:49 +08:00
|
|
|
if(includeSelf) {
|
|
|
|
family.unshift(this);
|
|
|
|
}
|
2012-12-31 15:14:23 +08:00
|
|
|
while(parent) {
|
|
|
|
family.unshift(parent);
|
|
|
|
parent = parent.parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
var len = family.length;
|
|
|
|
for(var n = 0; n < len; n++) {
|
2012-12-31 15:48:46 +08:00
|
|
|
func(family[n]);
|
2012-12-31 15:14:23 +08:00
|
|
|
}
|
|
|
|
},
|
2012-11-14 15:22:56 +08:00
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* rotate node by an amount in radians relative to its current rotation
|
2012-11-14 15:22:56 +08:00
|
|
|
* @name rotate
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {Number} theta
|
|
|
|
*/
|
|
|
|
rotate: function(theta) {
|
|
|
|
this.setRotation(this.getRotation() + theta);
|
|
|
|
},
|
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* rotate node by an amount in degrees relative to its current rotation
|
2012-11-14 15:22:56 +08:00
|
|
|
* @name rotateDeg
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {Number} deg
|
|
|
|
*/
|
|
|
|
rotateDeg: function(deg) {
|
2012-11-30 12:15:01 +08:00
|
|
|
this.setRotation(this.getRotation() + Kinetic.Type._degToRad(deg));
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* move node to the top of its siblings
|
|
|
|
* @name moveToTop
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
moveToTop: function() {
|
|
|
|
var index = this.index;
|
|
|
|
this.parent.children.splice(index, 1);
|
|
|
|
this.parent.children.push(this);
|
|
|
|
this.parent._setChildrenIndices();
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* move node up
|
|
|
|
* @name moveUp
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
moveUp: function() {
|
|
|
|
var index = this.index;
|
|
|
|
var len = this.parent.getChildren().length;
|
|
|
|
if(index < len - 1) {
|
|
|
|
this.parent.children.splice(index, 1);
|
|
|
|
this.parent.children.splice(index + 1, 0, this);
|
|
|
|
this.parent._setChildrenIndices();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* move node down
|
|
|
|
* @name moveDown
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
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();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* move node to the bottom of its siblings
|
|
|
|
* @name moveToBottom
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
moveToBottom: function() {
|
|
|
|
var index = this.index;
|
|
|
|
if(index > 0) {
|
|
|
|
this.parent.children.splice(index, 1);
|
|
|
|
this.parent.children.unshift(this);
|
|
|
|
this.parent._setChildrenIndices();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* set zIndex relative to siblings
|
2012-11-14 15:22:56 +08:00
|
|
|
* @name setZIndex
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {Integer} zIndex
|
|
|
|
*/
|
|
|
|
setZIndex: function(zIndex) {
|
|
|
|
var index = this.index;
|
|
|
|
this.parent.children.splice(index, 1);
|
|
|
|
this.parent.children.splice(zIndex, 0, this);
|
|
|
|
this.parent._setChildrenIndices();
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get absolute opacity
|
|
|
|
* @name getAbsoluteOpacity
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
getAbsoluteOpacity: function() {
|
|
|
|
var absOpacity = this.getOpacity();
|
|
|
|
if(this.getParent()) {
|
|
|
|
absOpacity *= this.getParent().getAbsoluteOpacity();
|
|
|
|
}
|
|
|
|
return absOpacity;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* move node to another container
|
|
|
|
* @name moveTo
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {Container} newContainer
|
|
|
|
*/
|
|
|
|
moveTo: function(newContainer) {
|
|
|
|
var parent = this.parent;
|
|
|
|
// remove from parent's children
|
2012-09-27 03:50:08 +08:00
|
|
|
parent.children.splice(this.index, 1);
|
|
|
|
parent._setChildrenIndices();
|
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
// add to new parent
|
|
|
|
newContainer.children.push(this);
|
|
|
|
this.index = newContainer.children.length - 1;
|
|
|
|
this.parent = newContainer;
|
|
|
|
newContainer._setChildrenIndices();
|
|
|
|
},
|
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* convert Node into an object for serialization. Returns an object.
|
2012-11-14 15:22:56 +08:00
|
|
|
* @name toObject
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
toObject: function() {
|
2012-11-14 16:07:59 +08:00
|
|
|
var type = Kinetic.Type, obj = {}, attrs = this.attrs;
|
2012-04-29 03:55:18 +08:00
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
obj.attrs = {};
|
|
|
|
|
|
|
|
// serialize only attributes that are not function, image, DOM, or objects with methods
|
2012-11-14 16:07:59 +08:00
|
|
|
for(var key in attrs) {
|
|
|
|
var val = attrs[key];
|
|
|
|
if(!type._isFunction(val) && !type._isElement(val) && !(type._isObject(val) && type._hasMethods(val))) {
|
2012-11-14 15:22:56 +08:00
|
|
|
obj.attrs[key] = val;
|
2012-05-13 06:15:42 +08:00
|
|
|
}
|
2012-04-29 03:55:18 +08:00
|
|
|
}
|
2012-11-14 15:22:56 +08:00
|
|
|
|
|
|
|
obj.nodeType = this.nodeType;
|
|
|
|
obj.shapeType = this.shapeType;
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
},
|
2012-11-27 11:12:02 +08:00
|
|
|
/**
|
|
|
|
* convert Node into a JSON string. Returns a JSON string.
|
|
|
|
* @name toJSON
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
2012-11-14 15:22:56 +08:00
|
|
|
toJSON: function() {
|
|
|
|
return JSON.stringify(this.toObject());
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get parent container
|
|
|
|
* @name getParent
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
getParent: function() {
|
|
|
|
return this.parent;
|
|
|
|
},
|
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* get layer ancestor
|
2012-11-14 15:22:56 +08:00
|
|
|
* @name getLayer
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
getLayer: function() {
|
|
|
|
return this.getParent().getLayer();
|
|
|
|
},
|
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* get stage ancestor
|
2012-11-14 15:22:56 +08:00
|
|
|
* @name getStage
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
getStage: function() {
|
|
|
|
if(this.getParent()) {
|
|
|
|
return this.getParent().getStage();
|
2012-09-26 04:38:36 +08:00
|
|
|
}
|
2012-11-14 15:22:56 +08:00
|
|
|
else {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* simulate event with event bubbling
|
|
|
|
* @name simulate
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {String} eventType
|
|
|
|
* @param {EventObject} evt event object
|
|
|
|
*/
|
|
|
|
simulate: function(eventType, evt) {
|
|
|
|
this._handleEvent(eventType, evt || {});
|
|
|
|
},
|
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* synthetically fire an event. The event object will not bubble up the Node tree. You can also pass in custom properties
|
2012-11-14 15:22:56 +08:00
|
|
|
* @name fire
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {String} eventType
|
|
|
|
* @param {Object} obj optional object which can be used to pass parameters
|
|
|
|
*/
|
|
|
|
fire: function(eventType, obj) {
|
|
|
|
this._executeHandlers(eventType, obj || {});
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get absolute transform of the node which takes into
|
2012-11-27 11:12:02 +08:00
|
|
|
* account its ancestor transforms
|
2012-11-14 15:22:56 +08:00
|
|
|
* @name getAbsoluteTransform
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
getAbsoluteTransform: function() {
|
|
|
|
// absolute transform
|
|
|
|
var am = new Kinetic.Transform();
|
|
|
|
|
2012-12-31 17:47:49 +08:00
|
|
|
this._eachAncestorReverse(function(node) {
|
2012-11-14 15:22:56 +08:00
|
|
|
var m = node.getTransform();
|
|
|
|
am.multiply(m);
|
2012-12-31 17:47:49 +08:00
|
|
|
}, true);
|
2012-11-14 15:22:56 +08:00
|
|
|
return am;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get transform of the node
|
|
|
|
* @name getTransform
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
getTransform: function() {
|
2012-11-14 16:07:59 +08:00
|
|
|
var m = new Kinetic.Transform(), attrs = this.attrs, x = attrs.x, y = attrs.y, rotation = attrs.rotation, scale = attrs.scale, scaleX = scale.x, scaleY = scale.y, offset = attrs.offset, offsetX = offset.x, offsetY = offset.y;
|
2012-11-14 15:22:56 +08:00
|
|
|
|
2012-11-14 16:07:59 +08:00
|
|
|
if(x !== 0 || y !== 0) {
|
|
|
|
m.translate(x, y);
|
2012-11-14 15:22:56 +08:00
|
|
|
}
|
2012-11-14 16:07:59 +08:00
|
|
|
if(rotation !== 0) {
|
|
|
|
m.rotate(rotation);
|
2012-11-14 15:22:56 +08:00
|
|
|
}
|
2012-11-14 16:07:59 +08:00
|
|
|
if(scaleX !== 1 || scaleY !== 1) {
|
|
|
|
m.scale(scaleX, scaleY);
|
2012-11-14 15:22:56 +08:00
|
|
|
}
|
2012-11-14 16:07:59 +08:00
|
|
|
if(offsetX !== 0 || offsetY !== 0) {
|
|
|
|
m.translate(-1 * offsetX, -1 * offsetY);
|
2012-11-14 15:22:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return m;
|
|
|
|
},
|
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* clone node. Returns a new Node instance with identical attributes
|
2012-11-14 15:22:56 +08:00
|
|
|
* @name clone
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {Object} attrs override attrs
|
|
|
|
*/
|
|
|
|
clone: function(obj) {
|
|
|
|
// instantiate new node
|
|
|
|
var classType = this.shapeType || this.nodeType;
|
|
|
|
var node = new Kinetic[classType](this.attrs);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* copy over user listeners
|
|
|
|
*/
|
|
|
|
for(var key in this.eventListeners) {
|
|
|
|
var allListeners = this.eventListeners[key];
|
|
|
|
var len = allListeners.length;
|
|
|
|
for(var n = 0; n < len; n++) {
|
|
|
|
var listener = allListeners[n];
|
|
|
|
/*
|
|
|
|
* don't include kinetic namespaced listeners because
|
|
|
|
* these are generated by the constructors
|
|
|
|
*/
|
|
|
|
if(listener.name.indexOf('kinetic') < 0) {
|
|
|
|
// if listeners array doesn't exist, then create it
|
|
|
|
if(!node.eventListeners[key]) {
|
|
|
|
node.eventListeners[key] = [];
|
|
|
|
}
|
|
|
|
node.eventListeners[key].push(listener);
|
|
|
|
}
|
2012-04-01 06:17:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
// apply attr overrides
|
|
|
|
node.setAttrs(obj);
|
|
|
|
return node;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Creates a composite data URL. If MIME type is not
|
|
|
|
* specified, then "image/png" will result. For "image/jpeg", specify a quality
|
|
|
|
* level as quality (range 0.0 - 1.0)
|
|
|
|
* @name toDataURL
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {Object} config
|
2012-12-17 12:52:07 +08:00
|
|
|
* @param {Function} config.callback function executed when the composite has completed
|
|
|
|
* @param {String} [config.mimeType] can be "image/png" or "image/jpeg".
|
2012-11-14 15:22:56 +08:00
|
|
|
* "image/png" is the default
|
2012-12-17 12:52:07 +08:00
|
|
|
* @param {Number} [config.x] x position of canvas section
|
|
|
|
* @param {Number} [config.y] y position of canvas section
|
|
|
|
* @param {Number} [config.width] width of canvas section
|
|
|
|
* @param {Number} [config.height] height of canvas section
|
2012-11-14 15:22:56 +08:00
|
|
|
* @param {Number} [config.quality] jpeg quality. If using an "image/jpeg" mimeType,
|
|
|
|
* you can specify the quality from 0 to 1, where 0 is very poor quality and 1
|
|
|
|
* is very high quality
|
|
|
|
*/
|
|
|
|
toDataURL: function(config) {
|
2012-12-11 16:08:59 +08:00
|
|
|
config = config || {};
|
|
|
|
var mimeType = config.mimeType || null, quality = config.quality || null, canvas, context, x = config.x || 0, y = config.y || 0;
|
2012-11-14 15:22:56 +08:00
|
|
|
|
2012-12-11 16:08:59 +08:00
|
|
|
//if width and height are defined, create new canvas to draw on, else reuse stage buffer canvas
|
|
|
|
if(config.width && config.height) {
|
2012-12-10 01:52:33 +08:00
|
|
|
canvas = new Kinetic.SceneCanvas(config.width, config.height);
|
2012-11-14 15:22:56 +08:00
|
|
|
}
|
|
|
|
else {
|
2012-11-19 11:50:50 +08:00
|
|
|
canvas = this.getStage().bufferCanvas;
|
2012-11-14 15:22:56 +08:00
|
|
|
canvas.clear();
|
2012-04-01 06:17:36 +08:00
|
|
|
}
|
2012-12-11 16:08:59 +08:00
|
|
|
context = canvas.getContext();
|
|
|
|
context.save();
|
2012-12-22 14:51:57 +08:00
|
|
|
canvas._counterPixelRatio();
|
2012-12-31 15:14:23 +08:00
|
|
|
|
2012-12-11 16:08:59 +08:00
|
|
|
if(x || y) {
|
|
|
|
context.translate(-1 * x, -1 * y);
|
|
|
|
}
|
|
|
|
this.drawScene(canvas);
|
|
|
|
context.restore();
|
2012-04-01 06:17:36 +08:00
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
return canvas.toDataURL(mimeType, quality);
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* converts node into an image. Since the toImage
|
2012-11-27 11:12:02 +08:00
|
|
|
* method is asynchronous, a callback is required. toImage is most commonly used
|
|
|
|
* to cache complex drawings as an image so that they don't have to constantly be redrawn
|
2012-11-14 15:22:56 +08:00
|
|
|
* @name toImage
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {Object} config
|
2012-12-17 12:52:07 +08:00
|
|
|
* @param {Function} config.callback function executed when the composite has completed
|
|
|
|
* @param {String} [config.mimeType] can be "image/png" or "image/jpeg".
|
2012-11-14 15:22:56 +08:00
|
|
|
* "image/png" is the default
|
2012-12-17 12:52:07 +08:00
|
|
|
* @param {Number} [config.x] x position of canvas section
|
|
|
|
* @param {Number} [config.y] y position of canvas section
|
|
|
|
* @param {Number} [config.width] width of canvas section
|
|
|
|
* @param {Number} [config.height] height of canvas section
|
2012-11-14 15:22:56 +08:00
|
|
|
* @param {Number} [config.quality] jpeg quality. If using an "image/jpeg" mimeType,
|
|
|
|
* you can specify the quality from 0 to 1, where 0 is very poor quality and 1
|
|
|
|
* is very high quality
|
|
|
|
*/
|
|
|
|
toImage: function(config) {
|
2012-11-14 15:48:30 +08:00
|
|
|
Kinetic.Type._getImage(this.toDataURL(config), function(img) {
|
2012-11-14 15:22:56 +08:00
|
|
|
config.callback(img);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* set size
|
|
|
|
* @name setSize
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {Number} width
|
|
|
|
* @param {Number} height
|
|
|
|
*/
|
|
|
|
setSize: function() {
|
|
|
|
// set stage dimensions
|
2012-11-14 15:48:30 +08:00
|
|
|
var size = Kinetic.Type._getSize(Array.prototype.slice.call(arguments));
|
2012-11-14 15:22:56 +08:00
|
|
|
this.setWidth(size.width);
|
|
|
|
this.setHeight(size.height);
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get size
|
|
|
|
* @name getSize
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
getSize: function() {
|
|
|
|
return {
|
|
|
|
width: this.getWidth(),
|
|
|
|
height: this.getHeight()
|
|
|
|
};
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get width
|
|
|
|
* @name getWidth
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
getWidth: function() {
|
|
|
|
return this.attrs.width || 0;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get height
|
|
|
|
* @name getHeight
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
getHeight: function() {
|
|
|
|
return this.attrs.height || 0;
|
|
|
|
},
|
|
|
|
_get: function(selector) {
|
|
|
|
return this.nodeType === selector ? [this] : [];
|
|
|
|
},
|
|
|
|
_off: function(type, name) {
|
|
|
|
for(var i = 0; i < this.eventListeners[type].length; i++) {
|
|
|
|
if(this.eventListeners[type][i].name === name) {
|
|
|
|
this.eventListeners[type].splice(i, 1);
|
|
|
|
if(this.eventListeners[type].length === 0) {
|
|
|
|
delete this.eventListeners[type];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_clearTransform: function() {
|
2012-11-14 16:07:59 +08:00
|
|
|
var attrs = this.attrs, scale = attrs.scale, offset = attrs.offset;
|
2012-11-14 15:22:56 +08:00
|
|
|
var trans = {
|
2012-11-14 16:07:59 +08:00
|
|
|
x: attrs.x,
|
|
|
|
y: attrs.y,
|
|
|
|
rotation: attrs.rotation,
|
2012-11-14 15:22:56 +08:00
|
|
|
scale: {
|
2012-11-14 16:07:59 +08:00
|
|
|
x: scale.x,
|
|
|
|
y: scale.y
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
offset: {
|
2012-11-14 16:07:59 +08:00
|
|
|
x: offset.x,
|
|
|
|
y: offset.y
|
2012-11-14 15:22:56 +08:00
|
|
|
}
|
|
|
|
};
|
2012-06-10 06:31:25 +08:00
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
this.attrs.x = 0;
|
|
|
|
this.attrs.y = 0;
|
|
|
|
this.attrs.rotation = 0;
|
|
|
|
this.attrs.scale = {
|
|
|
|
x: 1,
|
|
|
|
y: 1
|
|
|
|
};
|
|
|
|
this.attrs.offset = {
|
|
|
|
x: 0,
|
|
|
|
y: 0
|
|
|
|
};
|
2012-06-10 06:31:25 +08:00
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
return trans;
|
|
|
|
},
|
|
|
|
_setTransform: function(trans) {
|
|
|
|
for(var key in trans) {
|
|
|
|
this.attrs[key] = trans[key];
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_fireBeforeChangeEvent: function(attr, oldVal, newVal) {
|
|
|
|
this._handleEvent('before' + attr.toUpperCase() + 'Change', {
|
|
|
|
oldVal: oldVal,
|
|
|
|
newVal: newVal
|
|
|
|
});
|
|
|
|
},
|
|
|
|
_fireChangeEvent: function(attr, oldVal, newVal) {
|
|
|
|
this._handleEvent(attr + 'Change', {
|
|
|
|
oldVal: oldVal,
|
|
|
|
newVal: newVal
|
|
|
|
});
|
|
|
|
},
|
|
|
|
setAttr: function(key, val) {
|
|
|
|
if(val !== undefined) {
|
|
|
|
var oldVal = this.attrs[key];
|
|
|
|
this._fireBeforeChangeEvent(key, oldVal, val);
|
|
|
|
this.attrs[key] = val;
|
|
|
|
this._fireChangeEvent(key, oldVal, val);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_handleEvent: function(eventType, evt, compareShape) {
|
|
|
|
if(evt && this.nodeType === 'Shape') {
|
|
|
|
evt.shape = this;
|
|
|
|
}
|
|
|
|
var stage = this.getStage();
|
|
|
|
var el = this.eventListeners;
|
|
|
|
var okayToRun = true;
|
|
|
|
|
|
|
|
if(eventType === 'mouseenter' && compareShape && this._id === compareShape._id) {
|
|
|
|
okayToRun = false;
|
|
|
|
}
|
|
|
|
else if(eventType === 'mouseleave' && compareShape && this._id === compareShape._id) {
|
|
|
|
okayToRun = false;
|
|
|
|
}
|
2012-06-10 06:31:25 +08:00
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
if(okayToRun) {
|
|
|
|
if(el[eventType]) {
|
|
|
|
this.fire(eventType, evt);
|
|
|
|
}
|
|
|
|
|
|
|
|
// simulate event bubbling
|
|
|
|
if(evt && !evt.cancelBubble && this.parent) {
|
|
|
|
if(compareShape && compareShape.parent) {
|
|
|
|
this._handleEvent.call(this.parent, eventType, evt, compareShape.parent);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this._handleEvent.call(this.parent, eventType, evt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_executeHandlers: function(eventType, evt) {
|
|
|
|
var events = this.eventListeners[eventType];
|
|
|
|
var len = events.length;
|
|
|
|
for(var i = 0; i < len; i++) {
|
|
|
|
events[i].handler.apply(this, [evt]);
|
|
|
|
}
|
2012-06-10 06:31:25 +08:00
|
|
|
}
|
2012-11-14 15:22:56 +08:00
|
|
|
};
|
2012-06-10 06:31:25 +08:00
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
// add getter and setter methods
|
2012-11-27 12:42:01 +08:00
|
|
|
Kinetic.Node.addSetters = function(constructor, arr) {
|
2012-11-14 15:22:56 +08:00
|
|
|
var len = arr.length;
|
|
|
|
for(var n = 0; n < len; n++) {
|
|
|
|
var attr = arr[n];
|
|
|
|
this._addSetter(constructor, attr);
|
2012-08-26 13:26:25 +08:00
|
|
|
}
|
2012-11-14 15:22:56 +08:00
|
|
|
};
|
2013-01-02 15:54:02 +08:00
|
|
|
Kinetic.Node.addPointSetters = function(constructor, arr) {
|
|
|
|
var len = arr.length;
|
|
|
|
for(var n = 0; n < len; n++) {
|
|
|
|
var attr = arr[n];
|
|
|
|
this._addPointSetter(constructor, attr);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
Kinetic.Node.addRotationSetters = function(constructor, arr) {
|
|
|
|
var len = arr.length;
|
|
|
|
for(var n = 0; n < len; n++) {
|
|
|
|
var attr = arr[n];
|
|
|
|
this._addRotationSetter(constructor, attr);
|
|
|
|
}
|
|
|
|
};
|
2012-11-27 12:42:01 +08:00
|
|
|
Kinetic.Node.addGetters = function(constructor, arr) {
|
2012-11-14 15:22:56 +08:00
|
|
|
var len = arr.length;
|
|
|
|
for(var n = 0; n < len; n++) {
|
|
|
|
var attr = arr[n];
|
|
|
|
this._addGetter(constructor, attr);
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
2012-11-14 15:22:56 +08:00
|
|
|
};
|
2013-01-02 15:54:02 +08:00
|
|
|
Kinetic.Node.addRotationGetters = function(constructor, arr) {
|
|
|
|
var len = arr.length;
|
|
|
|
for(var n = 0; n < len; n++) {
|
|
|
|
var attr = arr[n];
|
|
|
|
this._addRotationGetter(constructor, attr);
|
|
|
|
}
|
|
|
|
};
|
2012-11-27 12:42:01 +08:00
|
|
|
Kinetic.Node.addGettersSetters = function(constructor, arr) {
|
2012-11-14 15:22:56 +08:00
|
|
|
this.addSetters(constructor, arr);
|
|
|
|
this.addGetters(constructor, arr);
|
|
|
|
};
|
2013-01-02 15:54:02 +08:00
|
|
|
Kinetic.Node.addPointGettersSetters = function(constructor, arr) {
|
|
|
|
this.addPointSetters(constructor, arr);
|
|
|
|
this.addGetters(constructor, arr);
|
|
|
|
};
|
|
|
|
Kinetic.Node.addRotationGettersSetters = function(constructor, arr) {
|
|
|
|
this.addRotationSetters(constructor, arr);
|
|
|
|
this.addRotationGetters(constructor, arr);
|
|
|
|
};
|
2012-11-27 12:42:01 +08:00
|
|
|
Kinetic.Node._addSetter = function(constructor, attr) {
|
2012-11-14 15:22:56 +08:00
|
|
|
var that = this;
|
|
|
|
var method = 'set' + attr.charAt(0).toUpperCase() + attr.slice(1);
|
|
|
|
constructor.prototype[method] = function(val) {
|
|
|
|
this.setAttr(attr, val);
|
|
|
|
};
|
|
|
|
};
|
2013-01-02 15:54:02 +08:00
|
|
|
Kinetic.Node._addPointSetter = function(constructor, attr) {
|
|
|
|
var that = this;
|
|
|
|
var method = 'set' + attr.charAt(0).toUpperCase() + attr.slice(1);
|
|
|
|
constructor.prototype[method] = function() {
|
|
|
|
var pos = Kinetic.Type._getXY([].slice.call(arguments));
|
|
|
|
if(pos && pos.x === undefined) {
|
|
|
|
pos.x = this.attrs[attr].x;
|
|
|
|
}
|
|
|
|
if(pos && pos.y === undefined) {
|
|
|
|
pos.y = this.attrs[attr].y;
|
|
|
|
}
|
|
|
|
this.setAttr(attr, pos);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
Kinetic.Node._addRotationSetter = function(constructor, attr) {
|
|
|
|
var that = this;
|
|
|
|
var method = 'set' + attr.charAt(0).toUpperCase() + attr.slice(1);
|
|
|
|
// radians
|
|
|
|
constructor.prototype[method] = function(val) {
|
|
|
|
this.setAttr(attr, val);
|
|
|
|
};
|
|
|
|
// degrees
|
|
|
|
constructor.prototype[method + 'Deg'] = function(deg) {
|
|
|
|
this.setAttr(attr, Kinetic.Type._degToRad(deg));
|
|
|
|
};
|
|
|
|
};
|
2012-11-27 12:42:01 +08:00
|
|
|
Kinetic.Node._addGetter = function(constructor, attr) {
|
2012-11-14 15:22:56 +08:00
|
|
|
var that = this;
|
|
|
|
var method = 'get' + attr.charAt(0).toUpperCase() + attr.slice(1);
|
|
|
|
constructor.prototype[method] = function(arg) {
|
|
|
|
return this.attrs[attr];
|
|
|
|
};
|
|
|
|
};
|
2013-01-02 15:54:02 +08:00
|
|
|
Kinetic.Node._addRotationGetter = function(constructor, attr) {
|
|
|
|
var that = this;
|
|
|
|
var method = 'get' + attr.charAt(0).toUpperCase() + attr.slice(1);
|
|
|
|
// radians
|
|
|
|
constructor.prototype[method] = function() {
|
|
|
|
return this.attrs[attr];
|
|
|
|
};
|
|
|
|
// degrees
|
|
|
|
constructor.prototype[method + 'Deg'] = function() {
|
|
|
|
return Kinetic.Type._radToDeg(this.attrs[attr])
|
|
|
|
};
|
|
|
|
};
|
2012-03-07 13:45:48 +08:00
|
|
|
/**
|
2012-11-14 15:22:56 +08:00
|
|
|
* create node with JSON string. De-serializtion does not generate custom
|
|
|
|
* shape drawing functions, images, or event handlers (this would make the
|
|
|
|
* serialized object huge). If your app uses custom shapes, images, and
|
|
|
|
* event handlers (it probably does), then you need to select the appropriate
|
|
|
|
* shapes after loading the stage and set these properties via on(), setDrawFunc(),
|
2012-11-27 11:12:02 +08:00
|
|
|
* and setImage() methods
|
2012-11-14 15:22:56 +08:00
|
|
|
* @name create
|
|
|
|
* @methodOf Kinetic.Node
|
|
|
|
* @param {String} JSON string
|
2012-11-30 12:15:01 +08:00
|
|
|
* @param {DomElement} [container] optional container dom element used only if you're
|
2012-11-27 11:12:02 +08:00
|
|
|
* creating a stage node
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
2012-11-27 12:42:01 +08:00
|
|
|
Kinetic.Node.create = function(json, container) {
|
2012-11-14 15:22:56 +08:00
|
|
|
return this._createNode(JSON.parse(json), container);
|
|
|
|
};
|
2012-11-27 12:42:01 +08:00
|
|
|
Kinetic.Node._createNode = function(obj, container) {
|
2012-11-14 15:22:56 +08:00
|
|
|
var type;
|
|
|
|
|
|
|
|
// determine type
|
|
|
|
if(obj.nodeType === 'Shape') {
|
|
|
|
// add custom shape
|
|
|
|
if(obj.shapeType === undefined) {
|
|
|
|
type = 'Shape';
|
|
|
|
}
|
|
|
|
// add standard shape
|
|
|
|
else {
|
|
|
|
type = obj.shapeType;
|
|
|
|
}
|
2012-08-26 13:26:25 +08:00
|
|
|
}
|
2012-11-14 15:22:56 +08:00
|
|
|
else {
|
|
|
|
type = obj.nodeType;
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
2012-10-04 10:38:12 +08:00
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
// if container was passed in, add it to attrs
|
|
|
|
if(container) {
|
|
|
|
obj.attrs.container = container;
|
|
|
|
}
|
2012-10-04 10:38:12 +08:00
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
var no = new Kinetic[type](obj.attrs);
|
|
|
|
if(obj.children) {
|
|
|
|
var len = obj.children.length;
|
|
|
|
for(var n = 0; n < len; n++) {
|
|
|
|
no.add(this._createNode(obj.children[n]));
|
2012-10-04 10:38:12 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
return no;
|
|
|
|
};
|
|
|
|
// add getters setters
|
2013-01-02 15:54:02 +08:00
|
|
|
Kinetic.Node.addGettersSetters(Kinetic.Node, ['x', 'y', 'opacity', 'name', 'id']);
|
|
|
|
Kinetic.Node.addRotationGettersSetters(Kinetic.Node, ['rotation']);
|
|
|
|
Kinetic.Node.addPointGettersSetters(Kinetic.Node, ['scale', 'offset']);
|
2012-11-27 12:42:01 +08:00
|
|
|
Kinetic.Node.addSetters(Kinetic.Node, ['width', 'height', 'listening', 'visible']);
|
2013-01-02 15:54:02 +08:00
|
|
|
|
|
|
|
|
2012-11-27 11:12:02 +08:00
|
|
|
// aliases
|
2012-03-07 13:45:48 +08:00
|
|
|
/**
|
2012-11-14 15:22:56 +08:00
|
|
|
* Alias of getListening()
|
|
|
|
* @name isListening
|
2012-07-09 12:56:52 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
2012-11-27 12:42:01 +08:00
|
|
|
Kinetic.Node.prototype.isListening = Kinetic.Node.prototype.getListening;
|
2012-03-07 13:45:48 +08:00
|
|
|
/**
|
2012-11-14 15:22:56 +08:00
|
|
|
* Alias of getVisible()
|
|
|
|
* @name isVisible
|
2012-07-09 12:56:52 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
2012-11-27 12:42:01 +08:00
|
|
|
Kinetic.Node.prototype.isVisible = Kinetic.Node.prototype.getVisible;
|
2012-11-14 15:22:56 +08:00
|
|
|
|
|
|
|
// collection mappings
|
|
|
|
var collectionMappings = ['on', 'off'];
|
|
|
|
for(var n = 0; n < 2; n++) {
|
|
|
|
// induce scope
|
|
|
|
(function(i) {
|
|
|
|
var method = collectionMappings[i];
|
|
|
|
Kinetic.Collection.prototype[method] = function() {
|
|
|
|
var args = [].slice.call(arguments);
|
|
|
|
args.unshift(method);
|
|
|
|
this.apply.apply(this, args);
|
|
|
|
};
|
|
|
|
})(n);
|
|
|
|
}
|
|
|
|
|
2012-03-07 13:45:48 +08:00
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* set x position
|
2012-11-14 15:22:56 +08:00
|
|
|
* @name setX
|
2012-07-09 12:56:52 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-11-14 15:22:56 +08:00
|
|
|
* @param {Number} x
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
2012-11-14 15:22:56 +08:00
|
|
|
|
2012-06-02 15:21:49 +08:00
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* set y position
|
2012-11-14 15:22:56 +08:00
|
|
|
* @name setY
|
2012-07-09 12:56:52 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-11-14 15:22:56 +08:00
|
|
|
* @param {Number} y
|
2012-06-02 15:21:49 +08:00
|
|
|
*/
|
2012-11-14 15:22:56 +08:00
|
|
|
|
2012-11-04 08:19:21 +08:00
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* set rotation in radians
|
2012-11-14 15:22:56 +08:00
|
|
|
* @name setRotation
|
2012-11-04 08:19:21 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-11-14 15:22:56 +08:00
|
|
|
* @param {Number} theta
|
2012-11-04 08:19:21 +08:00
|
|
|
*/
|
2012-11-14 15:22:56 +08:00
|
|
|
|
2012-03-24 14:39:54 +08:00
|
|
|
/**
|
2012-11-14 15:22:56 +08:00
|
|
|
* set opacity. Opacity values range from 0 to 1.
|
|
|
|
* A node with an opacity of 0 is fully transparent, and a node
|
|
|
|
* with an opacity of 1 is fully opaque
|
|
|
|
* @name setOpacity
|
2012-07-09 12:56:52 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-11-14 15:22:56 +08:00
|
|
|
* @param {Object} opacity
|
2012-03-24 14:39:54 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
2012-11-14 15:22:56 +08:00
|
|
|
* set name
|
|
|
|
* @name setName
|
2012-07-09 12:56:52 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-11-14 15:22:56 +08:00
|
|
|
* @param {String} name
|
2012-03-24 14:39:54 +08:00
|
|
|
*/
|
2012-03-23 04:47:37 +08:00
|
|
|
|
2012-07-08 05:43:12 +08:00
|
|
|
/**
|
2012-11-14 15:22:56 +08:00
|
|
|
* set id
|
|
|
|
* @name setId
|
2012-07-09 12:56:52 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-11-14 15:22:56 +08:00
|
|
|
* @param {String} id
|
2012-07-08 05:43:12 +08:00
|
|
|
*/
|
2012-11-30 12:15:01 +08:00
|
|
|
|
2012-11-27 11:12:02 +08:00
|
|
|
/**
|
|
|
|
* set width
|
|
|
|
* @name setWidth
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {Number} width
|
|
|
|
*/
|
2012-11-30 12:15:01 +08:00
|
|
|
|
2012-11-27 11:12:02 +08:00
|
|
|
/**
|
|
|
|
* set height
|
|
|
|
* @name setHeight
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {Number} height
|
|
|
|
*/
|
2012-07-08 05:43:12 +08:00
|
|
|
|
toDataURL() is now synchronous, and works with all nodes, including the stage, layers, groups, and shapes. This also sets things up nicely for node caching. You can now cache anything, including the whole stage, layers, groups, or shapes, manifested as Kinetic Images that were instantiated with data urls
2012-07-15 09:10:37 +08:00
|
|
|
/**
|
2012-11-14 15:22:56 +08:00
|
|
|
* listen or don't listen to events
|
|
|
|
* @name setListening
|
2012-07-19 14:28:45 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-11-14 15:22:56 +08:00
|
|
|
* @param {Boolean} listening
|
toDataURL() is now synchronous, and works with all nodes, including the stage, layers, groups, and shapes. This also sets things up nicely for node caching. You can now cache anything, including the whole stage, layers, groups, or shapes, manifested as Kinetic Images that were instantiated with data urls
2012-07-15 09:10:37 +08:00
|
|
|
*/
|
2012-07-22 06:38:25 +08:00
|
|
|
|
2012-07-15 14:41:16 +08:00
|
|
|
/**
|
2012-11-14 15:22:56 +08:00
|
|
|
* set visible
|
|
|
|
* @name setVisible
|
2012-11-04 07:08:29 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-11-14 15:22:56 +08:00
|
|
|
* @param {Boolean} visible
|
2012-07-15 14:41:16 +08:00
|
|
|
*/
|
2012-11-14 15:22:56 +08:00
|
|
|
|
2012-09-25 11:34:23 +08:00
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* get x position
|
2012-11-14 15:22:56 +08:00
|
|
|
* @name getX
|
2012-09-26 04:38:36 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
2012-11-14 15:22:56 +08:00
|
|
|
|
2012-09-25 11:34:23 +08:00
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* get y position
|
2012-11-14 15:22:56 +08:00
|
|
|
* @name getY
|
2012-09-26 04:38:36 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
|
2012-10-11 09:48:08 +08:00
|
|
|
/**
|
2012-11-14 15:22:56 +08:00
|
|
|
* get rotation in radians
|
|
|
|
* @name getRotation
|
2012-10-11 09:48:08 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
2012-11-14 15:22:56 +08:00
|
|
|
|
2012-10-11 09:48:08 +08:00
|
|
|
/**
|
2012-11-14 15:22:56 +08:00
|
|
|
* get opacity.
|
|
|
|
* @name getOpacity
|
2012-10-11 09:48:08 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
2012-11-14 15:22:56 +08:00
|
|
|
|
2012-10-11 09:48:08 +08:00
|
|
|
/**
|
2012-11-14 15:22:56 +08:00
|
|
|
* get name
|
|
|
|
* @name getName
|
2012-10-11 09:48:08 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
2012-11-14 15:22:56 +08:00
|
|
|
|
2012-10-11 09:48:08 +08:00
|
|
|
/**
|
2012-11-14 15:22:56 +08:00
|
|
|
* get id
|
|
|
|
* @name getId
|
2012-10-11 09:48:08 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
2012-07-20 14:30:59 +08:00
|
|
|
|
2012-03-07 13:45:48 +08:00
|
|
|
/**
|
2012-11-14 15:22:56 +08:00
|
|
|
* get scale
|
|
|
|
* @name getScale
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
2012-10-11 09:48:08 +08:00
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
/**
|
|
|
|
* get offset
|
|
|
|
* @name getOffset
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
2013-01-02 15:54:02 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* get rotation in degrees
|
|
|
|
* @name getRotationDeg
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* set rotation in degrees
|
|
|
|
* @name setRotationDeg
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {Number} deg
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* set scale.
|
|
|
|
* @name setScale
|
|
|
|
* @param {Number} x
|
|
|
|
* @param {Number} y
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* set offset. A node's offset defines the position and rotation point
|
|
|
|
* @name setOffset
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {Number} x
|
|
|
|
* @param {Number} y
|
|
|
|
*/
|
2012-09-26 04:38:36 +08:00
|
|
|
})();
|