2012-07-09 12:56:52 +08:00
|
|
|
/**
|
|
|
|
* Node constructor. Nodes are entities that can be transformed, layered,
|
|
|
|
* and have events bound to them. They are the building blocks of a KineticJS
|
|
|
|
* application
|
|
|
|
* @constructor
|
|
|
|
* @param {Object} config
|
2012-07-24 13:39:55 +08:00
|
|
|
* @param {Number} [config.x]
|
|
|
|
* @param {Number} [config.y]
|
|
|
|
* @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
|
2012-08-14 14:06:29 +08:00
|
|
|
* @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1
|
2012-07-24 13:39:55 +08:00
|
|
|
* @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
|
|
|
|
* @param {Object} [config.offset] offsets default position point and rotation point
|
|
|
|
* @param {Number} [config.offset.x]
|
|
|
|
* @param {Number} [config.offset.y]
|
|
|
|
* @param {Boolean} [config.draggable]
|
2012-08-14 04:44:08 +08:00
|
|
|
* @param {Function} [config.dragBoundFunc] dragBoundFunc(pos, evt) should return new position
|
2012-07-09 12:56:52 +08:00
|
|
|
*/
|
2012-08-23 14:13:09 +08:00
|
|
|
Kinetic.Node = function(config) {
|
2012-08-26 13:26:25 +08:00
|
|
|
this._nodeInit(config);
|
2012-08-23 14:13:09 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
Kinetic.Node.prototype = {
|
|
|
|
_nodeInit: function(config) {
|
2012-07-04 03:07:27 +08:00
|
|
|
this.defaultNodeAttrs = {
|
|
|
|
visible: true,
|
|
|
|
listening: true,
|
|
|
|
name: undefined,
|
2012-08-14 14:06:29 +08:00
|
|
|
opacity: 1,
|
2012-04-29 03:55:18 +08:00
|
|
|
x: 0,
|
2012-07-04 03:07:27 +08:00
|
|
|
y: 0,
|
|
|
|
scale: {
|
|
|
|
x: 1,
|
|
|
|
y: 1
|
|
|
|
},
|
|
|
|
rotation: 0,
|
|
|
|
offset: {
|
|
|
|
x: 0,
|
|
|
|
y: 0
|
|
|
|
},
|
2012-08-09 15:01:21 +08:00
|
|
|
draggable: false
|
2012-07-04 03:07:27 +08:00
|
|
|
};
|
2012-03-07 13:45:48 +08:00
|
|
|
|
2012-07-04 03:07:27 +08:00
|
|
|
this.setDefaultAttrs(this.defaultNodeAttrs);
|
|
|
|
this.eventListeners = {};
|
|
|
|
this.setAttrs(config);
|
2012-08-26 13:26:25 +08:00
|
|
|
|
2012-07-04 03:07:27 +08:00
|
|
|
// bind events
|
2012-07-14 12:24:38 +08:00
|
|
|
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-07-04 03:07:27 +08:00
|
|
|
},
|
2012-03-07 13:45:48 +08:00
|
|
|
/**
|
|
|
|
* bind events to the node. KineticJS supports mouseover, mousemove,
|
2012-07-23 14:30:56 +08:00
|
|
|
* mouseout, mousedown, mouseup, click, dblclick, touchstart, touchmove,
|
|
|
|
* touchend, tap, dbltap, dragstart, dragmove, and dragend. Pass in a string
|
|
|
|
* of event types delimmited by a space to bind multiple events at once
|
|
|
|
* such as 'mousedown mouseup mousemove'. include a namespace to bind an
|
|
|
|
* event by name such as 'click.foobar'.
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name on
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
* @param {String} typesStr
|
2012-05-14 02:32:26 +08:00
|
|
|
* @param {Function} handler
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
|
|
|
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];
|
2012-06-02 15:21:49 +08:00
|
|
|
var event = 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
|
2012-07-23 14:30: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
|
2012-10-04 06:50:04 +08:00
|
|
|
* such as 'click.foobar'. If you only give a name like '.foobar',
|
|
|
|
* all events in that namespace will be removed.
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name off
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
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];
|
2012-06-02 15:21:49 +08:00
|
|
|
//var event = (type.indexOf('touch') === -1) ? 'on' + type : type;
|
|
|
|
var event = 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-10-04 06:50:04 +08:00
|
|
|
if(parts.length > 1) {
|
2012-10-04 10:38:12 +08:00
|
|
|
if(baseEvent) {
|
|
|
|
if(this.eventListeners[baseEvent]) {
|
2012-10-04 06:50:04 +08:00
|
|
|
this._off(baseEvent, parts[1]);
|
|
|
|
}
|
2012-10-04 10:38:12 +08:00
|
|
|
}
|
|
|
|
else {
|
2012-10-04 06:50:04 +08:00
|
|
|
for(var type in this.eventListeners) {
|
|
|
|
this._off(type, parts[1]);
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
|
|
|
}
|
2012-03-14 12:16:25 +08:00
|
|
|
}
|
|
|
|
else {
|
2012-06-10 01:53:47 +08:00
|
|
|
delete this.eventListeners[baseEvent];
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2012-09-27 03:50:08 +08:00
|
|
|
/**
|
|
|
|
* remove child from container
|
|
|
|
* @name remove
|
|
|
|
* @methodOf Kinetic.Container.prototype
|
|
|
|
* @param {Node} child
|
|
|
|
*/
|
|
|
|
remove: function() {
|
2012-10-04 10:38:12 +08:00
|
|
|
var parent = this.getParent();
|
2012-09-27 03:50:08 +08:00
|
|
|
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();
|
|
|
|
|
|
|
|
// remove children
|
|
|
|
while(this.children && this.children.length > 0) {
|
|
|
|
this.children[0].remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2012-04-08 09:50:53 +08:00
|
|
|
/**
|
|
|
|
* get attrs
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name getAttrs
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-04-08 09:50:53 +08:00
|
|
|
*/
|
|
|
|
getAttrs: function() {
|
|
|
|
return this.attrs;
|
|
|
|
},
|
2012-04-29 03:55:18 +08:00
|
|
|
/**
|
2012-07-23 14:30:56 +08:00
|
|
|
* set default attrs. This method should only be used if
|
|
|
|
* you're creating a custom node
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name setDefaultAttrs
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-04-29 03:55:18 +08:00
|
|
|
* @param {Object} confic
|
|
|
|
*/
|
|
|
|
setDefaultAttrs: function(config) {
|
|
|
|
// create attrs object if undefined
|
|
|
|
if(this.attrs === undefined) {
|
|
|
|
this.attrs = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
if(config) {
|
|
|
|
for(var key in config) {
|
2012-05-13 06:15:42 +08:00
|
|
|
/*
|
|
|
|
* 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-04-29 03:55:18 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2012-04-13 14:02:55 +08:00
|
|
|
/**
|
|
|
|
* set attrs
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name setAttrs
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-04-13 14:02:55 +08:00
|
|
|
* @param {Object} config
|
|
|
|
*/
|
2012-06-30 15:40:54 +08:00
|
|
|
setAttrs: function(config) {
|
2012-09-26 04:38:36 +08:00
|
|
|
if(config) {
|
|
|
|
for(var key in config) {
|
|
|
|
var method = 'set' + key.charAt(0).toUpperCase() + key.slice(1);
|
|
|
|
// use setter if available
|
|
|
|
if(Kinetic.Type._isFunction(this[method])) {
|
|
|
|
this[method](config[key]);
|
|
|
|
}
|
|
|
|
// otherwise set directly
|
|
|
|
else {
|
|
|
|
this.setAttr(key, config[key]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-04-13 14:02:55 +08:00
|
|
|
},
|
2012-04-15 03:04:45 +08:00
|
|
|
/**
|
2012-06-03 10:12:06 +08:00
|
|
|
* determine if shape is visible or not. Shape is visible only
|
2012-07-23 14:30:56 +08:00
|
|
|
* if it's visible and all of its ancestors are visible. If an ancestor
|
|
|
|
* is invisible, this means that the shape is also invisible
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name isVisible
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-04-15 03:04:45 +08:00
|
|
|
*/
|
|
|
|
isVisible: function() {
|
2012-07-04 03:59:31 +08:00
|
|
|
if(this.attrs.visible && this.getParent() && !this.getParent().isVisible()) {
|
2012-06-03 10:12:06 +08:00
|
|
|
return false;
|
|
|
|
}
|
2012-04-15 03:04:45 +08:00
|
|
|
return this.attrs.visible;
|
|
|
|
},
|
2012-03-07 13:45:48 +08:00
|
|
|
/**
|
|
|
|
* show node
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name show
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
|
|
|
show: function() {
|
2012-09-25 11:34:23 +08:00
|
|
|
this.setVisible(true);
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
|
|
|
/**
|
2012-07-23 14:30:56 +08:00
|
|
|
* hide node. Hidden nodes are no longer detectable
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name hide
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
|
|
|
hide: function() {
|
2012-09-25 11:34:23 +08:00
|
|
|
this.setVisible(false);
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get zIndex
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name getZIndex
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
|
|
|
getZIndex: function() {
|
|
|
|
return this.index;
|
|
|
|
},
|
2012-04-01 06:17:36 +08:00
|
|
|
/**
|
2012-07-23 14:30:56 +08:00
|
|
|
* get absolute z-index which takes into account sibling
|
|
|
|
* and parent indices
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name getAbsoluteZIndex
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-04-01 06:17:36 +08:00
|
|
|
*/
|
|
|
|
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++;
|
|
|
|
|
2012-04-05 13:57:36 +08:00
|
|
|
if(child.nodeType !== 'Shape') {
|
2012-04-01 06:17:36 +08:00
|
|
|
nodes = nodes.concat(child.getChildren());
|
|
|
|
}
|
|
|
|
|
2012-04-08 11:32:24 +08:00
|
|
|
if(child._id === that._id) {
|
2012-04-01 06:17:36 +08:00
|
|
|
n = children.length;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(nodes.length > 0 && nodes[0].getLevel() <= level) {
|
|
|
|
addChildren(nodes);
|
|
|
|
}
|
|
|
|
}
|
2012-04-05 13:57:36 +08:00
|
|
|
if(that.nodeType !== 'Stage') {
|
2012-04-01 06:17:36 +08:00
|
|
|
addChildren(that.getStage().getChildren());
|
|
|
|
}
|
|
|
|
|
|
|
|
return index;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get node level in node tree
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name getLevel
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-04-01 06:17:36 +08:00
|
|
|
*/
|
|
|
|
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 position
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name setPosition
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-07-23 14:30:56 +08:00
|
|
|
* @param {Number} x
|
|
|
|
* @param {Number} y
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
2012-04-28 14:57:01 +08:00
|
|
|
setPosition: function() {
|
2012-09-25 11:34:23 +08:00
|
|
|
var pos = Kinetic.Type._getXY([].slice.call(arguments));
|
|
|
|
this.setAttr('x', pos.x);
|
|
|
|
this.setAttr('y', pos.y);
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get node position relative to container
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name getPosition
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
|
|
|
getPosition: function() {
|
|
|
|
return {
|
2012-04-06 14:48:58 +08:00
|
|
|
x: this.attrs.x,
|
|
|
|
y: this.attrs.y
|
2012-03-07 13:45:48 +08:00
|
|
|
};
|
|
|
|
},
|
|
|
|
/**
|
2012-07-23 14:30:56 +08:00
|
|
|
* get absolute position
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name getAbsolutePosition
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
|
|
|
getAbsolutePosition: function() {
|
2012-07-19 14:28:45 +08:00
|
|
|
var trans = this.getAbsoluteTransform();
|
|
|
|
var o = this.getOffset();
|
|
|
|
trans.translate(o.x, o.y);
|
|
|
|
return trans.getTranslation();
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
2012-04-15 01:40:54 +08:00
|
|
|
/**
|
2012-07-23 14:30:56 +08:00
|
|
|
* set absolute position
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name setAbsolutePosition
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-04-15 07:27:00 +08:00
|
|
|
* @param {Object} pos object containing an x and
|
|
|
|
* y property
|
2012-04-15 01:40:54 +08:00
|
|
|
*/
|
2012-04-28 14:57:01 +08:00
|
|
|
setAbsolutePosition: function() {
|
2012-09-25 11:34:23 +08:00
|
|
|
var pos = Kinetic.Type._getXY([].slice.call(arguments));
|
2012-07-20 14:30:59 +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;
|
2012-04-15 01:40:54 +08:00
|
|
|
|
|
|
|
// unravel transform
|
|
|
|
var it = this.getAbsoluteTransform();
|
2012-07-19 14:28:45 +08:00
|
|
|
|
2012-04-15 01:40:54 +08:00
|
|
|
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);
|
2012-07-20 14:30:59 +08:00
|
|
|
this._setTransform(trans);
|
2012-04-15 01:40:54 +08:00
|
|
|
},
|
2012-03-07 13:45:48 +08:00
|
|
|
/**
|
|
|
|
* move node by an amount
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name move
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-07-23 14:30:56 +08:00
|
|
|
* @param {Number} x
|
|
|
|
* @param {Number} y
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
2012-06-10 06:31:25 +08:00
|
|
|
move: function() {
|
2012-09-25 11:34:23 +08:00
|
|
|
var pos = Kinetic.Type._getXY([].slice.call(arguments));
|
2012-06-10 06:31:25 +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-26 04:38:36 +08:00
|
|
|
this.setPosition(x, y);
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get rotation in degrees
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name getRotationDeg
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
|
|
|
getRotationDeg: function() {
|
2012-09-25 11:34:23 +08:00
|
|
|
return this.getRotation() * 180 / Math.PI;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* set rotation in degrees
|
|
|
|
* @name setRotationDeg
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {Number} rotDeg
|
|
|
|
*/
|
|
|
|
setRotationDeg: function(rotDeg) {
|
|
|
|
this.setRotation(rotDeg * Math.PI / 180);
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* rotate node by an amount in radians
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name rotate
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
* @param {Number} theta
|
|
|
|
*/
|
|
|
|
rotate: function(theta) {
|
2012-09-26 04:38:36 +08:00
|
|
|
this.setRotation(this.getRotation() + theta);
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* rotate node by an amount in degrees
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name rotateDeg
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
* @param {Number} deg
|
|
|
|
*/
|
|
|
|
rotateDeg: function(deg) {
|
2012-09-25 11:34:23 +08:00
|
|
|
this.setRotation(this.getRotation() + (deg * Math.PI / 180));
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
|
|
|
/**
|
2012-07-23 14:30:56 +08:00
|
|
|
* move node to the top of its siblings
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name moveToTop
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
|
|
|
moveToTop: function() {
|
|
|
|
var index = this.index;
|
|
|
|
this.parent.children.splice(index, 1);
|
|
|
|
this.parent.children.push(this);
|
|
|
|
this.parent._setChildrenIndices();
|
2012-09-26 06:57:57 +08:00
|
|
|
return true;
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* move node up
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name moveUp
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
|
|
|
moveUp: function() {
|
|
|
|
var index = this.index;
|
2012-08-26 13:26:25 +08:00
|
|
|
if(index < this.parent.getChildren().length - 1) {
|
|
|
|
this.parent.children.splice(index, 1);
|
|
|
|
this.parent.children.splice(index + 1, 0, this);
|
|
|
|
this.parent._setChildrenIndices();
|
2012-09-26 06:57:57 +08:00
|
|
|
return true;
|
2012-08-26 13:26:25 +08:00
|
|
|
}
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* move node down
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name moveDown
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
|
|
|
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();
|
2012-09-26 06:57:57 +08:00
|
|
|
return true;
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
2012-07-23 14:30:56 +08:00
|
|
|
* move node to the bottom of its siblings
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name moveToBottom
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
|
|
|
moveToBottom: function() {
|
|
|
|
var index = this.index;
|
2012-09-18 13:49:24 +08:00
|
|
|
if(index > 0) {
|
|
|
|
this.parent.children.splice(index, 1);
|
|
|
|
this.parent.children.unshift(this);
|
|
|
|
this.parent._setChildrenIndices();
|
2012-09-26 06:57:57 +08:00
|
|
|
return true;
|
2012-08-26 13:26:25 +08:00
|
|
|
}
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* set zIndex
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name setZIndex
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-07-23 14:30:56 +08:00
|
|
|
* @param {Integer} 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();
|
|
|
|
},
|
|
|
|
/**
|
2012-08-14 14:06:29 +08:00
|
|
|
* get absolute opacity
|
|
|
|
* @name getAbsoluteOpacity
|
2012-07-09 12:56:52 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
2012-08-14 14:06:29 +08:00
|
|
|
getAbsoluteOpacity: function() {
|
2012-10-01 06:55:12 +08:00
|
|
|
var absOpacity = this.getOpacity();
|
2012-10-11 09:48:08 +08:00
|
|
|
if(this.getParent()) {
|
2012-10-01 06:55:12 +08:00
|
|
|
absOpacity *= this.getParent().getAbsoluteOpacity();
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
2012-08-14 14:06:29 +08:00
|
|
|
return absOpacity;
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* move node to another container
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name moveTo
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
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();
|
|
|
|
},
|
2012-10-04 10:38:12 +08:00
|
|
|
/**
|
|
|
|
* convert Node into an object for serialization
|
|
|
|
* @name toObject
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
toObject: function() {
|
|
|
|
var obj = {};
|
|
|
|
var type = Kinetic.Type;
|
|
|
|
|
|
|
|
obj.attrs = {};
|
|
|
|
|
|
|
|
// serialize only attributes that are not function, image, DOM, or objects with methods
|
|
|
|
for(var key in this.attrs) {
|
|
|
|
var val = this.attrs[key];
|
|
|
|
if(!type._isFunction(val) && !type._isElement(val) && !(type._isObject(val) && type._hasMethods(val))) {
|
|
|
|
obj.attrs[key] = val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
obj.nodeType = this.nodeType;
|
|
|
|
obj.shapeType = this.shapeType;
|
2012-10-04 11:38:29 +08:00
|
|
|
|
2012-10-04 10:38:12 +08:00
|
|
|
return obj;
|
|
|
|
},
|
|
|
|
toJSON: function() {
|
|
|
|
return JSON.stringify(this.toObject());
|
|
|
|
},
|
2012-03-07 13:45:48 +08:00
|
|
|
/**
|
|
|
|
* get parent container
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name getParent
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
|
|
|
getParent: function() {
|
|
|
|
return this.parent;
|
|
|
|
},
|
|
|
|
/**
|
2012-07-09 12:56:52 +08:00
|
|
|
* get layer that contains the node
|
|
|
|
* @name getLayer
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
|
|
|
getLayer: function() {
|
2012-09-26 06:57:57 +08:00
|
|
|
return this.getParent().getLayer();
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
|
|
|
/**
|
2012-07-09 12:56:52 +08:00
|
|
|
* get stage that contains the node
|
|
|
|
* @name getStage
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
|
|
|
getStage: function() {
|
2012-09-26 06:57:57 +08:00
|
|
|
if(this.getParent()) {
|
2012-06-23 10:36:37 +08:00
|
|
|
return this.getParent().getStage();
|
|
|
|
}
|
2012-03-14 12:16:25 +08:00
|
|
|
else {
|
2012-06-23 10:36:37 +08:00
|
|
|
return undefined;
|
2012-03-13 13:41:09 +08:00
|
|
|
}
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
2012-06-02 15:21:49 +08:00
|
|
|
/**
|
|
|
|
* simulate event
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name simulate
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-06-02 15:21:49 +08:00
|
|
|
* @param {String} eventType
|
2012-11-02 19:59:17 +08:00
|
|
|
* @param {Object} event attribute
|
2012-06-02 15:21:49 +08:00
|
|
|
*/
|
2012-11-02 19:59:17 +08:00
|
|
|
simulate: function(eventType, evt) {
|
|
|
|
this._handleEvent(eventType, evt || {});
|
2012-06-02 15:21:49 +08:00
|
|
|
},
|
2012-03-24 14:39:54 +08:00
|
|
|
/**
|
2012-07-23 14:30:56 +08:00
|
|
|
* get absolute transform of the node which takes into
|
|
|
|
* account its parent transforms
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name getAbsoluteTransform
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
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-07-23 14:30:56 +08:00
|
|
|
* get transform of the node
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name getTransform
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
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
|
|
|
|
2012-04-06 14:48:58 +08:00
|
|
|
if(this.attrs.x !== 0 || this.attrs.y !== 0) {
|
|
|
|
m.translate(this.attrs.x, this.attrs.y);
|
2012-03-23 04:47:37 +08:00
|
|
|
}
|
2012-04-06 14:48:58 +08:00
|
|
|
if(this.attrs.rotation !== 0) {
|
|
|
|
m.rotate(this.attrs.rotation);
|
2012-03-23 04:47:37 +08:00
|
|
|
}
|
2012-04-06 14:48:58 +08:00
|
|
|
if(this.attrs.scale.x !== 1 || this.attrs.scale.y !== 1) {
|
|
|
|
m.scale(this.attrs.scale.x, this.attrs.scale.y);
|
2012-03-23 04:47:37 +08:00
|
|
|
}
|
2012-07-22 12:09:02 +08:00
|
|
|
if(this.attrs.offset && (this.attrs.offset.x !== 0 || this.attrs.offset.y !== 0)) {
|
2012-07-11 02:28:42 +08:00
|
|
|
m.translate(-1 * this.attrs.offset.x, -1 * this.attrs.offset.y);
|
|
|
|
}
|
2012-03-23 04:47:37 +08:00
|
|
|
|
|
|
|
return m;
|
|
|
|
},
|
2012-07-08 05:43:12 +08:00
|
|
|
/**
|
|
|
|
* clone node
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name clone
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-07-23 14:30:56 +08:00
|
|
|
* @param {Object} attrs override attrs
|
2012-07-08 05:43:12 +08:00
|
|
|
*/
|
|
|
|
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];
|
|
|
|
for(var n = 0; n < allListeners.length; 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// apply attr overrides
|
|
|
|
node.setAttrs(obj);
|
|
|
|
return node;
|
|
|
|
},
|
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
|
|
|
/**
|
|
|
|
* 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
|
2012-07-19 14:28:45 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-07-22 06:38:25 +08:00
|
|
|
* @param {Object} config
|
2012-07-23 14:30:56 +08:00
|
|
|
* @param {String} [config.mimeType] mime type. can be "image/png" or "image/jpeg".
|
|
|
|
* "image/png" is the default
|
|
|
|
* @param {Number} [config.width] data url image width
|
|
|
|
* @param {Number} [config.height] data url image height
|
|
|
|
* @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() 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
|
|
|
toDataURL: function(config) {
|
2012-07-23 14:30:56 +08:00
|
|
|
var mimeType = config && config.mimeType ? config.mimeType : null;
|
2012-07-22 06:38:25 +08:00
|
|
|
var quality = config && config.quality ? config.quality : null;
|
|
|
|
var canvas;
|
2012-10-08 10:14:14 +08:00
|
|
|
|
|
|
|
//if width and height are defined, create new canvas to draw on, else reuse stage buffer canvas
|
2012-07-22 06:38:25 +08:00
|
|
|
if(config && config.width && config.height) {
|
|
|
|
canvas = new Kinetic.Canvas(config.width, config.height);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
canvas = this.getStage().bufferCanvas;
|
2012-10-08 10:14:14 +08:00
|
|
|
canvas.clear();
|
2012-07-22 06:38:25 +08:00
|
|
|
}
|
|
|
|
|
2012-10-08 10:14:14 +08:00
|
|
|
this.draw(canvas);
|
2012-07-22 06:38:25 +08:00
|
|
|
return canvas.toDataURL(mimeType, quality);
|
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-15 14:41:16 +08:00
|
|
|
/**
|
2012-07-16 11:12:18 +08:00
|
|
|
* converts node into an image. Since the toImage
|
|
|
|
* method is asynchronous, a callback is required
|
|
|
|
* @name toImage
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
2012-07-22 06:38:25 +08:00
|
|
|
* @param {Object} config
|
2012-07-23 14:30:56 +08:00
|
|
|
* @param {Function} callback since the toImage() method is asynchonrous, the
|
|
|
|
* resulting image object is passed into the callback function
|
|
|
|
* @param {String} [config.mimeType] mime type. can be "image/png" or "image/jpeg".
|
|
|
|
* "image/png" is the default
|
|
|
|
* @param {Number} [config.width] data url image width
|
|
|
|
* @param {Number} [config.height] data url image height
|
|
|
|
* @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
|
2012-07-15 14:41:16 +08:00
|
|
|
*/
|
2012-07-22 06:38:25 +08:00
|
|
|
toImage: function(config) {
|
|
|
|
Kinetic.Type._getImage(this.toDataURL(config), function(img) {
|
|
|
|
config.callback(img);
|
2012-07-16 11:12:18 +08:00
|
|
|
});
|
2012-07-15 14:41:16 +08:00
|
|
|
},
|
2012-09-25 11:34:23 +08:00
|
|
|
/**
|
2012-09-26 04:38:36 +08:00
|
|
|
* 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-25 11:34:23 +08:00
|
|
|
setOffset: function() {
|
2012-09-26 04:38:36 +08:00
|
|
|
var pos = Kinetic.Type._getXY([].slice.call(arguments));
|
|
|
|
if(pos.x === undefined) {
|
|
|
|
pos.x = this.getOffset().x;
|
2012-09-25 11:34:23 +08:00
|
|
|
}
|
2012-09-26 04:38:36 +08:00
|
|
|
if(pos.y === undefined) {
|
|
|
|
pos.y = this.getOffset().y;
|
2012-09-25 11:34:23 +08:00
|
|
|
}
|
|
|
|
this.setAttr('offset', pos);
|
|
|
|
},
|
|
|
|
/**
|
2012-09-26 04:38:36 +08:00
|
|
|
* set scale.
|
|
|
|
* @name setScale
|
|
|
|
* @param {Number} x
|
|
|
|
* @param {Number} y
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
2012-09-25 11:34:23 +08:00
|
|
|
setScale: function() {
|
2012-09-26 04:38:36 +08:00
|
|
|
var pos = Kinetic.Type._getXY([].slice.call(arguments));
|
|
|
|
|
|
|
|
if(pos.x === undefined) {
|
|
|
|
pos.x = this.getScale().x;
|
2012-09-25 11:34:23 +08:00
|
|
|
}
|
2012-09-26 04:38:36 +08:00
|
|
|
if(pos.y === undefined) {
|
|
|
|
pos.y = this.getScale().y;
|
2012-09-25 11:34:23 +08:00
|
|
|
}
|
|
|
|
this.setAttr('scale', pos);
|
2012-09-26 04:38:36 +08:00
|
|
|
|
2012-09-25 11:34:23 +08:00
|
|
|
},
|
2012-10-11 09:48:08 +08:00
|
|
|
/**
|
|
|
|
* set size
|
|
|
|
* @name setSize
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {Number} width
|
|
|
|
* @param {Number} height
|
|
|
|
*/
|
|
|
|
setSize: function() {
|
|
|
|
// set stage dimensions
|
|
|
|
var size = Kinetic.Type._getSize(Array.prototype.slice.call(arguments));
|
|
|
|
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;
|
|
|
|
},
|
2012-10-07 05:35:46 +08:00
|
|
|
_get: function(selector) {
|
|
|
|
return this.nodeType === selector ? [this] : [];
|
|
|
|
},
|
2012-10-04 06:50:04 +08:00
|
|
|
_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--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2012-07-20 14:30:59 +08:00
|
|
|
_clearTransform: function() {
|
|
|
|
var trans = {
|
|
|
|
x: this.attrs.x,
|
|
|
|
y: this.attrs.y,
|
|
|
|
rotation: this.attrs.rotation,
|
|
|
|
scale: {
|
|
|
|
x: this.attrs.scale.x,
|
|
|
|
y: this.attrs.scale.y
|
|
|
|
},
|
|
|
|
offset: {
|
|
|
|
x: this.attrs.offset.x,
|
|
|
|
y: this.attrs.offset.y
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
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
|
|
|
|
};
|
|
|
|
|
|
|
|
return trans;
|
|
|
|
},
|
|
|
|
_setTransform: function(trans) {
|
|
|
|
for(var key in trans) {
|
|
|
|
this.attrs[key] = trans[key];
|
|
|
|
}
|
|
|
|
},
|
2012-07-15 07:25:56 +08:00
|
|
|
_fireBeforeChangeEvent: function(attr, oldVal, newVal) {
|
|
|
|
this._handleEvent('before' + attr.toUpperCase() + 'Change', {
|
|
|
|
oldVal: oldVal,
|
|
|
|
newVal: newVal
|
|
|
|
});
|
|
|
|
},
|
2012-07-14 11:06:28 +08:00
|
|
|
_fireChangeEvent: function(attr, oldVal, newVal) {
|
|
|
|
this._handleEvent(attr + 'Change', {
|
|
|
|
oldVal: oldVal,
|
|
|
|
newVal: newVal
|
|
|
|
});
|
2012-06-09 16:47:41 +08:00
|
|
|
},
|
2012-09-25 11:34:23 +08:00
|
|
|
setAttr: function(key, val) {
|
2012-09-26 04:38:36 +08:00
|
|
|
if(val !== undefined) {
|
|
|
|
var oldVal = this.attrs[key];
|
|
|
|
this._fireBeforeChangeEvent(key, oldVal, val);
|
|
|
|
this.attrs[key] = val;
|
|
|
|
this._fireChangeEvent(key, oldVal, val);
|
|
|
|
}
|
2012-06-09 12:56:33 +08:00
|
|
|
},
|
2012-03-07 13:45:48 +08:00
|
|
|
/**
|
2012-06-08 15:42:48 +08:00
|
|
|
* handle node event
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
2012-08-17 13:03:39 +08:00
|
|
|
_handleEvent: function(eventType, evt, compareShape) {
|
2012-04-05 13:57:36 +08:00
|
|
|
if(this.nodeType === 'Shape') {
|
2012-03-26 03:45:46 +08:00
|
|
|
evt.shape = this;
|
|
|
|
}
|
2012-03-19 02:24:57 +08:00
|
|
|
var stage = this.getStage();
|
2012-06-08 15:42:48 +08:00
|
|
|
var el = this.eventListeners;
|
2012-03-19 02:24:57 +08:00
|
|
|
var okayToRun = true;
|
2012-03-07 13:45:48 +08:00
|
|
|
|
2012-10-04 01:53:09 +08:00
|
|
|
if(eventType === 'mouseenter' && compareShape && this._id === compareShape._id) {
|
2012-03-19 02:24:57 +08:00
|
|
|
okayToRun = false;
|
|
|
|
}
|
2012-10-04 01:53:09 +08:00
|
|
|
else if(eventType === 'mouseleave' && compareShape && this._id === compareShape._id) {
|
2012-03-19 02:24:57 +08:00
|
|
|
okayToRun = false;
|
|
|
|
}
|
|
|
|
|
2012-07-06 15:27:55 +08:00
|
|
|
if(okayToRun) {
|
|
|
|
if(el[eventType]) {
|
|
|
|
var events = el[eventType];
|
|
|
|
for(var i = 0; i < events.length; i++) {
|
|
|
|
events[i].handler.apply(this, [evt]);
|
|
|
|
}
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
2012-03-19 02:24:57 +08:00
|
|
|
|
2012-07-06 15:27:55 +08:00
|
|
|
// simulate event bubbling
|
2012-07-08 02:52:04 +08:00
|
|
|
if(Kinetic.Global.BUBBLE_WHITELIST.indexOf(eventType) >= 0 && !evt.cancelBubble && this.parent) {
|
2012-08-17 13:03:39 +08:00
|
|
|
if(compareShape && compareShape.parent) {
|
|
|
|
this._handleEvent.call(this.parent, eventType, evt, compareShape.parent);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this._handleEvent.call(this.parent, eventType, evt);
|
|
|
|
}
|
2012-07-06 15:27:55 +08:00
|
|
|
}
|
2012-03-19 02:24:57 +08:00
|
|
|
}
|
2012-08-20 11:44:45 +08:00
|
|
|
},
|
2012-10-08 10:14:14 +08:00
|
|
|
_shouldDraw: function(canvas) {
|
|
|
|
return (this.isVisible() && (!canvas || canvas.name !== 'buffer' || this.getListening()));
|
2012-09-24 09:29:15 +08:00
|
|
|
}
|
2012-08-23 14:13:09 +08:00
|
|
|
};
|
2012-06-11 04:07:09 +08:00
|
|
|
|
2012-07-04 03:07:27 +08:00
|
|
|
// add getter and setter methods
|
|
|
|
Kinetic.Node.addSetters = function(constructor, arr) {
|
|
|
|
for(var n = 0; n < arr.length; n++) {
|
|
|
|
var attr = arr[n];
|
|
|
|
this._addSetter(constructor, attr);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
Kinetic.Node.addGetters = function(constructor, arr) {
|
|
|
|
for(var n = 0; n < arr.length; n++) {
|
|
|
|
var attr = arr[n];
|
|
|
|
this._addGetter(constructor, attr);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
Kinetic.Node.addGettersSetters = function(constructor, arr) {
|
|
|
|
this.addSetters(constructor, arr);
|
|
|
|
this.addGetters(constructor, arr);
|
|
|
|
};
|
|
|
|
Kinetic.Node._addSetter = function(constructor, attr) {
|
|
|
|
var that = this;
|
|
|
|
var method = 'set' + attr.charAt(0).toUpperCase() + attr.slice(1);
|
2012-09-25 11:34:23 +08:00
|
|
|
constructor.prototype[method] = function(val) {
|
|
|
|
this.setAttr(attr, val);
|
2012-07-04 03:07:27 +08:00
|
|
|
};
|
|
|
|
};
|
|
|
|
Kinetic.Node._addGetter = function(constructor, attr) {
|
|
|
|
var that = this;
|
|
|
|
var method = 'get' + attr.charAt(0).toUpperCase() + attr.slice(1);
|
|
|
|
constructor.prototype[method] = function(arg) {
|
|
|
|
return this.attrs[attr];
|
|
|
|
};
|
|
|
|
};
|
2012-10-04 11:38:29 +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(),
|
|
|
|
* and setImage()
|
|
|
|
* @name create
|
|
|
|
* @methodOf Kinetic.Node
|
|
|
|
* @param {String} JSON string
|
|
|
|
*/
|
|
|
|
Kinetic.Node.create = function(json, container) {
|
|
|
|
return this._createNode(JSON.parse(json), container);
|
|
|
|
};
|
|
|
|
Kinetic.Node._createNode = function(obj, container) {
|
|
|
|
var type;
|
|
|
|
|
|
|
|
// determine type
|
|
|
|
if(obj.nodeType === 'Shape') {
|
|
|
|
// add custom shape
|
|
|
|
if(obj.shapeType === undefined) {
|
|
|
|
type = 'Shape';
|
|
|
|
}
|
|
|
|
// add standard shape
|
|
|
|
else {
|
|
|
|
type = obj.shapeType;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
type = obj.nodeType;
|
|
|
|
}
|
2012-10-11 09:48:08 +08:00
|
|
|
|
2012-10-04 11:38:29 +08:00
|
|
|
// if container was passed in, add it to attrs
|
2012-10-11 09:48:08 +08:00
|
|
|
if(container) {
|
|
|
|
obj.attrs.container = container;
|
2012-10-04 11:38:29 +08:00
|
|
|
}
|
2012-10-11 09:48:08 +08:00
|
|
|
|
2012-10-04 11:38:29 +08:00
|
|
|
var no = new Kinetic[type](obj.attrs);
|
|
|
|
if(obj.children) {
|
|
|
|
for(var n = 0; n < obj.children.length; n++) {
|
|
|
|
no.add(this._createNode(obj.children[n]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return no;
|
|
|
|
};
|
2012-07-04 03:07:27 +08:00
|
|
|
// add getters setters
|
2012-10-15 09:46:04 +08:00
|
|
|
Kinetic.Node.addGettersSetters(Kinetic.Node, ['x', 'y', 'rotation', 'opacity', 'name', 'id', 'listening', 'visible']);
|
2012-09-25 11:34:23 +08:00
|
|
|
Kinetic.Node.addGetters(Kinetic.Node, ['scale', 'offset']);
|
2012-10-11 09:48:08 +08:00
|
|
|
Kinetic.Node.addSetters(Kinetic.Node, ['width', 'height']);
|
2012-06-11 04:07:09 +08:00
|
|
|
|
2012-09-24 07:06:44 +08:00
|
|
|
// mappings
|
|
|
|
/**
|
|
|
|
* determine if listening to events or not. Alias of getListening()
|
|
|
|
* @name isListening
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
Kinetic.Node.prototype.isListening = Kinetic.Node.prototype.getListening;
|
|
|
|
|
2012-09-26 04:38:36 +08:00
|
|
|
// collection mappings
|
|
|
|
(function() {
|
|
|
|
var collectionMappings = ['on', 'off'];
|
|
|
|
for(var n = 0; n < collectionMappings.length; 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-06-11 04:07:09 +08:00
|
|
|
/**
|
|
|
|
* set node x position
|
2012-06-14 17:19:51 +08:00
|
|
|
* @name setX
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-06-11 04:07:09 +08:00
|
|
|
* @param {Number} x
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* set node y position
|
2012-06-14 17:19:51 +08:00
|
|
|
* @name setY
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-06-11 04:07:09 +08:00
|
|
|
* @param {Number} y
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* set node rotation in radians
|
2012-06-14 17:19:51 +08:00
|
|
|
* @name setRotation
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-06-11 04:07:09 +08:00
|
|
|
* @param {Number} theta
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
2012-08-14 14:06:29 +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-06-14 17:19:51 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-08-14 14:06:29 +08:00
|
|
|
* @param {Object} opacity
|
2012-06-11 04:07:09 +08:00
|
|
|
*/
|
|
|
|
|
2012-06-19 13:02:13 +08:00
|
|
|
/**
|
2012-10-08 12:12:45 +08:00
|
|
|
* set name
|
|
|
|
* @name setName
|
2012-06-19 13:02:13 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-10-08 12:12:45 +08:00
|
|
|
* @param {String} name
|
2012-06-19 13:02:13 +08:00
|
|
|
*/
|
|
|
|
|
2012-06-11 04:07:09 +08:00
|
|
|
/**
|
2012-10-08 12:12:45 +08:00
|
|
|
* set id
|
|
|
|
* @name setId
|
2012-06-14 17:19:51 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-10-08 12:12:45 +08:00
|
|
|
* @param {String} id
|
2012-06-11 04:07:09 +08:00
|
|
|
*/
|
|
|
|
|
2012-06-19 14:12:56 +08:00
|
|
|
/**
|
|
|
|
* listen or don't listen to events
|
|
|
|
* @name setListening
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {Boolean} listening
|
|
|
|
*/
|
|
|
|
|
2012-10-11 09:48:08 +08:00
|
|
|
/**
|
2012-10-08 12:12:45 +08:00
|
|
|
* set visible
|
|
|
|
* @name setVisible
|
2012-10-11 09:48:08 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-10-08 12:12:45 +08:00
|
|
|
* @param {Boolean} visible
|
2012-10-11 09:48:08 +08:00
|
|
|
*/
|
|
|
|
|
2012-06-11 04:07:09 +08:00
|
|
|
/**
|
|
|
|
* get node x position
|
2012-06-14 17:19:51 +08:00
|
|
|
* @name getX
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-06-11 04:07:09 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* get node y position
|
2012-06-14 17:19:51 +08:00
|
|
|
* @name getY
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-06-11 04:07:09 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* get rotation in radians
|
2012-06-14 17:19:51 +08:00
|
|
|
* @name getRotation
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-06-11 04:07:09 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
2012-08-14 14:06:29 +08:00
|
|
|
* get opacity.
|
|
|
|
* @name getOpacity
|
2012-06-14 17:19:51 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-06-11 04:07:09 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* get name
|
2012-06-14 17:19:51 +08:00
|
|
|
* @name getName
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-06-11 04:07:09 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* get id
|
2012-06-14 17:19:51 +08:00
|
|
|
* @name getId
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-06-11 04:07:09 +08:00
|
|
|
*/
|
|
|
|
|
2012-10-08 12:12:45 +08:00
|
|
|
/**
|
|
|
|
* get scale
|
|
|
|
* @name getScale
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
|
2012-06-11 04:07:09 +08:00
|
|
|
/**
|
2012-06-14 17:19:51 +08:00
|
|
|
* get offset
|
|
|
|
* @name getOffset
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-06-11 04:07:09 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
2012-10-08 12:12:45 +08:00
|
|
|
* determine if listening to events or not
|
|
|
|
* @name getListening
|
2012-06-14 17:19:51 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-06-11 04:07:09 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
2012-10-08 12:12:45 +08:00
|
|
|
* determine if visible or not
|
|
|
|
* @name getVisible
|
2012-06-14 17:19:51 +08:00
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-10-11 09:48:08 +08:00
|
|
|
*/
|