2012-03-07 13:45:48 +08:00
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
// Node
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
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-04 03:07:27 +08:00
|
|
|
Kinetic.Node = Kinetic.Class.extend({
|
|
|
|
init: function(config) {
|
|
|
|
this.defaultNodeAttrs = {
|
|
|
|
visible: true,
|
|
|
|
listening: true,
|
|
|
|
name: undefined,
|
|
|
|
alpha: 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
|
|
|
|
},
|
|
|
|
dragConstraint: 'none',
|
|
|
|
dragBounds: {},
|
|
|
|
draggable: false
|
|
|
|
};
|
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-06-10 07:13:25 +08:00
|
|
|
|
2012-07-04 03:07:27 +08:00
|
|
|
// bind events
|
|
|
|
this.on('draggableChange.kinetic', function() {
|
2012-07-15 07:25:56 +08:00
|
|
|
this._onDraggableChange();
|
2012-07-04 03:07:27 +08:00
|
|
|
});
|
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-15 07:25:56 +08:00
|
|
|
|
|
|
|
this._onDraggableChange();
|
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,
|
|
|
|
* mouseout, mousedown, mouseup, click, dblclick, touchstart, touchmove,
|
2012-06-04 03:48:13 +08:00
|
|
|
* touchend, tap, dbltap, dragstart, dragmove, and dragend. Pass in a string
|
2012-03-07 13:45:48 +08:00
|
|
|
* of event types delimmited by a space to bind multiple events at once
|
2012-03-18 01:28:25 +08:00
|
|
|
* such as 'mousedown mouseup mousemove'. include a namespace to bind an
|
|
|
|
* event by name such as 'click.foobar'.
|
2012-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
|
|
|
|
* event types delimmited by a space to remove multiple event
|
2012-03-18 01:28:25 +08:00
|
|
|
* bindings at once such as 'mousedown mouseup mousemove'.
|
2012-03-07 13:45:48 +08:00
|
|
|
* include a namespace to remove an event binding by name
|
2012-03-18 01:28:25 +08:00
|
|
|
* such as 'click.foobar'.
|
2012-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];
|
|
|
|
|
|
|
|
if(this.eventListeners[baseEvent] && parts.length > 1) {
|
|
|
|
var name = parts[1];
|
|
|
|
|
|
|
|
for(var i = 0; i < this.eventListeners[baseEvent].length; i++) {
|
|
|
|
if(this.eventListeners[baseEvent][i].name === name) {
|
|
|
|
this.eventListeners[baseEvent].splice(i, 1);
|
|
|
|
if(this.eventListeners[baseEvent].length === 0) {
|
2012-06-10 01:53:47 +08:00
|
|
|
delete this.eventListeners[baseEvent];
|
|
|
|
break;
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
2012-06-10 01:53:47 +08:00
|
|
|
i--;
|
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-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
|
|
|
/**
|
|
|
|
* set default attrs
|
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-07-04 13:08:59 +08:00
|
|
|
var type = Kinetic.Type;
|
2012-05-20 12:14:04 +08:00
|
|
|
var that = this;
|
2012-04-13 14:02:55 +08:00
|
|
|
// set properties from config
|
2012-05-20 12:14:04 +08:00
|
|
|
if(config !== undefined) {
|
2012-06-10 07:13:25 +08:00
|
|
|
function setAttrs(obj, c, level) {
|
2012-05-20 12:14:04 +08:00
|
|
|
for(var key in c) {
|
|
|
|
var val = c[key];
|
2012-07-14 11:06:28 +08:00
|
|
|
var oldVal = obj[key];
|
2012-04-28 10:42:04 +08:00
|
|
|
|
2012-07-15 07:25:56 +08:00
|
|
|
/*
|
|
|
|
* only fire change event for root
|
|
|
|
* level attrs
|
|
|
|
*/
|
|
|
|
if(level === 0) {
|
|
|
|
that._fireBeforeChangeEvent(key, oldVal, val);
|
|
|
|
}
|
|
|
|
|
2012-05-27 01:57:56 +08:00
|
|
|
// if obj doesn't have the val property, then create it
|
2012-06-28 10:50:32 +08:00
|
|
|
if(obj[key] === undefined && val !== undefined) {
|
2012-05-27 01:57:56 +08:00
|
|
|
obj[key] = {};
|
|
|
|
}
|
|
|
|
|
2012-05-20 12:14:04 +08:00
|
|
|
/*
|
2012-05-27 09:31:13 +08:00
|
|
|
* if property is a pure object (no methods), then add an empty object
|
2012-05-20 12:14:04 +08:00
|
|
|
* to the node and then traverse
|
|
|
|
*/
|
2012-07-04 13:08:59 +08:00
|
|
|
if(type._isObject(val) && !type._isArray(val) && !type._isElement(val) && !type._hasMethods(val)) {
|
2012-06-13 00:57:29 +08:00
|
|
|
/*
|
|
|
|
* since some properties can be strings or objects, e.g.
|
|
|
|
* fill, we need to first check that obj is an object
|
|
|
|
* before setting properties. If it's not an object,
|
|
|
|
* overwrite obj with an object literal
|
|
|
|
*/
|
2012-07-04 13:08:59 +08:00
|
|
|
if(!Kinetic.Type._isObject(obj[key])) {
|
2012-05-20 12:14:04 +08:00
|
|
|
obj[key] = {};
|
|
|
|
}
|
2012-06-13 00:57:29 +08:00
|
|
|
|
2012-06-10 07:13:25 +08:00
|
|
|
setAttrs(obj[key], val, level + 1);
|
2012-05-20 12:14:04 +08:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* add all other object types to attrs object
|
|
|
|
*/
|
|
|
|
else {
|
|
|
|
// handle special keys
|
|
|
|
switch (key) {
|
|
|
|
case 'rotationDeg':
|
2012-06-09 12:56:33 +08:00
|
|
|
that._setAttr(obj, 'rotation', c[key] * Math.PI / 180);
|
2012-06-10 01:53:47 +08:00
|
|
|
// override key for change event
|
|
|
|
key = 'rotation';
|
2012-05-20 12:14:04 +08:00
|
|
|
break;
|
2012-05-27 01:57:56 +08:00
|
|
|
/*
|
|
|
|
* includes:
|
2012-06-10 07:13:25 +08:00
|
|
|
* - node offset
|
2012-05-27 07:37:37 +08:00
|
|
|
* - fill pattern offset
|
2012-05-27 01:57:56 +08:00
|
|
|
* - shadow offset
|
|
|
|
*/
|
2012-05-20 12:14:04 +08:00
|
|
|
case 'offset':
|
2012-07-04 13:08:59 +08:00
|
|
|
var pos = type._getXY(val);
|
2012-06-09 12:56:33 +08:00
|
|
|
that._setAttr(obj[key], 'x', pos.x);
|
|
|
|
that._setAttr(obj[key], 'y', pos.y);
|
2012-05-20 12:14:04 +08:00
|
|
|
break;
|
|
|
|
case 'scale':
|
2012-07-04 13:08:59 +08:00
|
|
|
var pos = type._getXY(val);
|
2012-06-09 12:56:33 +08:00
|
|
|
that._setAttr(obj[key], 'x', pos.x);
|
|
|
|
that._setAttr(obj[key], 'y', pos.y);
|
2012-05-20 12:14:04 +08:00
|
|
|
break;
|
|
|
|
case 'points':
|
2012-07-04 13:08:59 +08:00
|
|
|
that._setAttr(obj, key, type._getPoints(val));
|
2012-05-20 12:14:04 +08:00
|
|
|
break;
|
|
|
|
case 'crop':
|
2012-07-04 13:08:59 +08:00
|
|
|
var pos = type._getXY(val);
|
|
|
|
var size = type._getSize(val);
|
2012-06-09 12:56:33 +08:00
|
|
|
that._setAttr(obj[key], 'x', pos.x);
|
|
|
|
that._setAttr(obj[key], 'y', pos.y);
|
|
|
|
that._setAttr(obj[key], 'width', size.width);
|
|
|
|
that._setAttr(obj[key], 'height', size.height);
|
2012-05-20 12:14:04 +08:00
|
|
|
break;
|
|
|
|
default:
|
2012-06-18 07:50:04 +08:00
|
|
|
that._setAttr(obj, key, val);
|
2012-05-20 12:14:04 +08:00
|
|
|
break;
|
|
|
|
}
|
2012-07-01 15:19:56 +08:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* only fire change event for root
|
|
|
|
* level attrs
|
|
|
|
*/
|
|
|
|
if(level === 0) {
|
2012-07-14 11:06:28 +08:00
|
|
|
that._fireChangeEvent(key, oldVal, val);
|
2012-04-28 10:42:04 +08:00
|
|
|
}
|
2012-04-13 14:02:55 +08:00
|
|
|
}
|
|
|
|
}
|
2012-06-10 07:13:25 +08:00
|
|
|
setAttrs(this.attrs, config, 0);
|
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
|
|
|
|
* if it's visible and all of its ancestors are visible. If one 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-06-10 06:31:25 +08:00
|
|
|
this.setAttrs({
|
|
|
|
visible: true
|
|
|
|
});
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* hide node
|
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-06-10 06:31:25 +08:00
|
|
|
this.setAttrs({
|
|
|
|
visible: 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
|
|
|
/**
|
|
|
|
* get absolute z-index by taking into account
|
|
|
|
* all parent and sibling 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-04-28 14:57:01 +08:00
|
|
|
* @param {Object} point
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
2012-04-28 14:57:01 +08:00
|
|
|
setPosition: function() {
|
2012-07-04 13:08:59 +08:00
|
|
|
var pos = Kinetic.Type._getXY(Array.prototype.slice.call(arguments));
|
2012-05-26 11:18:05 +08:00
|
|
|
this.setAttrs(pos);
|
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
|
|
|
};
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get absolute position relative to stage
|
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
|
|
|
/**
|
|
|
|
* set absolute position relative to stage
|
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-07-04 13:08:59 +08:00
|
|
|
var pos = Kinetic.Type._getXY(Array.prototype.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-03-07 13:45:48 +08:00
|
|
|
*/
|
2012-06-10 06:31:25 +08:00
|
|
|
move: function() {
|
2012-07-04 13:08:59 +08:00
|
|
|
var pos = Kinetic.Type._getXY(Array.prototype.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;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.setAttrs({
|
|
|
|
x: x,
|
|
|
|
y: 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-04-06 14:48:58 +08:00
|
|
|
return this.attrs.rotation * 180 / Math.PI;
|
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-06-10 06:31:25 +08:00
|
|
|
this.setAttrs({
|
|
|
|
rotation: 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-06-10 06:31:25 +08:00
|
|
|
this.setAttrs({
|
|
|
|
rotation: this.getRotation() + (deg * Math.PI / 180)
|
|
|
|
});
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* move node to top
|
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();
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
this.parent.children.splice(index, 1);
|
|
|
|
this.parent.children.splice(index + 1, 0, this);
|
|
|
|
this.parent._setChildrenIndices();
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* 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();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* move node to bottom
|
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;
|
|
|
|
this.parent.children.splice(index, 1);
|
|
|
|
this.parent.children.unshift(this);
|
|
|
|
this.parent._setChildrenIndices();
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* set zIndex
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name setZIndex
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-03-12 14:01:23 +08:00
|
|
|
* @param {int} zIndex
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
|
|
|
setZIndex: function(zIndex) {
|
|
|
|
var index = this.index;
|
|
|
|
this.parent.children.splice(index, 1);
|
|
|
|
this.parent.children.splice(zIndex, 0, this);
|
|
|
|
this.parent._setChildrenIndices();
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get absolute alpha
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name getAbsoluteAlpha
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
|
|
|
getAbsoluteAlpha: function() {
|
|
|
|
var absAlpha = 1;
|
|
|
|
var node = this;
|
|
|
|
// traverse upwards
|
2012-04-05 13:57:36 +08:00
|
|
|
while(node.nodeType !== 'Stage') {
|
2012-04-06 14:48:58 +08:00
|
|
|
absAlpha *= node.attrs.alpha;
|
2012-03-07 13:45:48 +08:00
|
|
|
node = node.parent;
|
|
|
|
}
|
|
|
|
return absAlpha;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* determine if node is currently in drag and drop mode
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name isDragging
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
|
|
|
isDragging: function() {
|
2012-07-04 13:08:59 +08:00
|
|
|
var go = Kinetic.Global;
|
2012-04-08 11:32:24 +08:00
|
|
|
return go.drag.node !== undefined && go.drag.node._id === this._id && go.drag.moving;
|
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();
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* 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-04-05 13:57:36 +08:00
|
|
|
if(this.nodeType === 'Layer') {
|
2012-03-07 13:45:48 +08:00
|
|
|
return this;
|
2012-03-14 12:16:25 +08:00
|
|
|
}
|
|
|
|
else {
|
2012-03-07 13:45:48 +08:00
|
|
|
return this.getParent().getLayer();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
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-06-23 10:36:37 +08:00
|
|
|
if(this.nodeType !== 'Stage' && this.getParent()) {
|
|
|
|
return this.getParent().getStage();
|
|
|
|
}
|
|
|
|
else if(this.nodeType === 'Stage') {
|
2012-03-13 13:41:09 +08:00
|
|
|
return this;
|
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
|
|
|
|
*/
|
|
|
|
simulate: function(eventType) {
|
2012-06-09 11:57:20 +08:00
|
|
|
this._handleEvent(eventType, {});
|
2012-06-02 15:21:49 +08:00
|
|
|
},
|
2012-03-13 13:41:09 +08:00
|
|
|
/**
|
2012-03-14 12:16:25 +08:00
|
|
|
* transition node to another state. Any property that can accept a real
|
2012-03-20 13:44:42 +08:00
|
|
|
* number can be transitioned, including x, y, rotation, alpha, strokeWidth,
|
2012-06-10 07:13:25 +08:00
|
|
|
* radius, scale.x, scale.y, offset.x, offset.y, etc.
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name transitionTo
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-03-13 13:41:09 +08:00
|
|
|
* @param {Object} config
|
2012-03-20 13:44:42 +08:00
|
|
|
* @config {Number} [duration] duration that the transition runs in seconds
|
2012-04-04 14:00:35 +08:00
|
|
|
* @config {String} [easing] easing function. can be linear, ease-in, ease-out, ease-in-out,
|
|
|
|
* back-ease-in, back-ease-out, back-ease-in-out, elastic-ease-in, elastic-ease-out,
|
|
|
|
* elastic-ease-in-out, bounce-ease-out, bounce-ease-in, bounce-ease-in-out,
|
|
|
|
* strong-ease-in, strong-ease-out, or strong-ease-in-out
|
2012-04-02 01:06:00 +08:00
|
|
|
* linear is the default
|
2012-03-20 13:44:42 +08:00
|
|
|
* @config {Function} [callback] callback function to be executed when
|
|
|
|
* transition completes
|
2012-03-13 13:41:09 +08:00
|
|
|
*/
|
|
|
|
transitionTo: function(config) {
|
2012-07-04 14:00:52 +08:00
|
|
|
var a = Kinetic.Animation;
|
2012-04-29 08:45:13 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* clear transition if one is currently running for this
|
|
|
|
* node
|
|
|
|
*/
|
2012-07-08 12:39:03 +08:00
|
|
|
if(this.transAnim) {
|
2012-07-04 14:00:52 +08:00
|
|
|
a._removeAnimation(this.transAnim);
|
2012-07-08 12:39:03 +08:00
|
|
|
this.transAnim = null;
|
2012-04-29 08:45:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* create new transition
|
|
|
|
*/
|
2012-04-05 13:57:36 +08:00
|
|
|
var node = this.nodeType === 'Stage' ? this : this.getLayer();
|
2012-03-13 13:41:09 +08:00
|
|
|
var that = this;
|
2012-04-04 13:23:13 +08:00
|
|
|
var trans = new Kinetic.Transition(this, config);
|
2012-04-04 14:00:35 +08:00
|
|
|
var anim = {
|
2012-04-04 13:23:13 +08:00
|
|
|
func: function() {
|
2012-06-04 01:36:50 +08:00
|
|
|
trans._onEnterFrame();
|
2012-04-04 13:23:13 +08:00
|
|
|
},
|
2012-04-04 14:00:35 +08:00
|
|
|
node: node
|
|
|
|
};
|
2012-04-05 13:57:36 +08:00
|
|
|
|
2012-04-29 08:45:13 +08:00
|
|
|
// store reference to transition animation
|
|
|
|
this.transAnim = anim;
|
|
|
|
|
2012-04-04 14:00:35 +08:00
|
|
|
/*
|
|
|
|
* adding the animation with the addAnimation
|
|
|
|
* method auto generates an id
|
|
|
|
*/
|
2012-07-04 14:00:52 +08:00
|
|
|
a._addAnimation(anim);
|
2012-04-04 13:23:13 +08:00
|
|
|
|
2012-04-04 14:00:35 +08:00
|
|
|
// subscribe to onFinished for first tween
|
2012-04-29 10:52:45 +08:00
|
|
|
trans.onFinished = function() {
|
|
|
|
// remove animation
|
2012-07-04 14:00:52 +08:00
|
|
|
a._removeAnimation(anim);
|
2012-07-08 12:39:03 +08:00
|
|
|
that.transAnim = null;
|
2012-04-29 10:52:45 +08:00
|
|
|
|
|
|
|
// callback
|
2012-04-04 14:00:35 +08:00
|
|
|
if(config.callback !== undefined) {
|
|
|
|
config.callback();
|
|
|
|
}
|
2012-04-29 10:52:45 +08:00
|
|
|
|
|
|
|
anim.node.draw();
|
2012-04-04 14:00:35 +08:00
|
|
|
};
|
|
|
|
// auto start
|
2012-04-04 13:23:13 +08:00
|
|
|
trans.start();
|
2012-03-13 13:41:09 +08:00
|
|
|
|
2012-07-04 14:00:52 +08:00
|
|
|
a._handleAnimation();
|
2012-04-04 14:00:35 +08:00
|
|
|
|
|
|
|
return trans;
|
2012-03-13 13:41:09 +08:00
|
|
|
},
|
2012-03-24 14:39:54 +08:00
|
|
|
/**
|
2012-03-25 01:03:28 +08:00
|
|
|
* get transform of the node while taking into
|
|
|
|
* account the transforms of its parents
|
2012-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-03-25 01:03:28 +08:00
|
|
|
* get transform of the node while not taking
|
|
|
|
* into account the transforms of its parents
|
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-11 02:28:42 +08:00
|
|
|
if(this.attrs.offset.x !== 0 || this.attrs.offset.y !== 0) {
|
|
|
|
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-08 05:43:12 +08:00
|
|
|
* @param {Object} config used to override cloned
|
|
|
|
* 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];
|
|
|
|
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;
|
|
|
|
},
|
2012-07-15 07:25:56 +08:00
|
|
|
/**
|
|
|
|
* save image data
|
2012-07-17 15:32:26 +08:00
|
|
|
* @name saveImageData
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-07-15 07:25:56 +08:00
|
|
|
*/
|
2012-07-20 14:30:59 +08:00
|
|
|
saveImageData: function(width, height) {
|
2012-07-17 15:32:26 +08:00
|
|
|
try {
|
2012-07-20 14:30:59 +08:00
|
|
|
var canvas;
|
|
|
|
if(width && height) {
|
|
|
|
canvas = new Kinetic.Canvas(width, height);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
var stage = this.getStage();
|
|
|
|
canvas = stage.bufferCanvas;
|
|
|
|
}
|
|
|
|
|
|
|
|
var context = canvas.getContext();
|
|
|
|
canvas.clear();
|
|
|
|
this._draw(canvas);
|
|
|
|
var imageData = context.getImageData(0, 0, canvas.getWidth(), canvas.getHeight());
|
2012-07-17 15:32:26 +08:00
|
|
|
this.imageData = imageData;
|
|
|
|
}
|
|
|
|
catch(e) {
|
|
|
|
Kinetic.Global.warn('Image data could not saved because canvas is dirty.');
|
|
|
|
}
|
2012-07-15 07:25:56 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* clear image data
|
2012-07-17 15:32:26 +08:00
|
|
|
* @name clearImageData
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-07-15 07:25:56 +08:00
|
|
|
*/
|
|
|
|
clearImageData: function() {
|
|
|
|
delete this.imageData;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get image data
|
2012-07-17 15:32:26 +08:00
|
|
|
* @name getImageData
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-07-15 07:25:56 +08:00
|
|
|
*/
|
|
|
|
getImageData: function() {
|
|
|
|
return this.imageData;
|
|
|
|
},
|
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
|
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
|
|
|
* @param {String} [mimeType]
|
|
|
|
* @param {Number} [quality]
|
|
|
|
*/
|
|
|
|
toDataURL: function(mimeType, quality) {
|
2012-07-19 14:28:45 +08:00
|
|
|
var bufferCanvas = this.getStage().bufferCanvas;
|
|
|
|
var bufferContext = bufferCanvas.getContext();
|
|
|
|
bufferCanvas.clear();
|
|
|
|
this._draw(bufferCanvas);
|
2012-07-22 04:29:22 +08:00
|
|
|
return bufferCanvas.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-15 14:41:16 +08:00
|
|
|
*/
|
2012-07-16 11:12:18 +08:00
|
|
|
toImage: function(callback) {
|
|
|
|
Kinetic.Type._getImage(this.toDataURL(), function(img) {
|
|
|
|
callback(img);
|
|
|
|
});
|
2012-07-15 14:41:16 +08:00
|
|
|
},
|
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
|
|
|
_setImageData: function(imageData) {
|
|
|
|
if(imageData && imageData.data) {
|
|
|
|
this.imageData = imageData;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_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-06-09 12:56:33 +08:00
|
|
|
_setAttr: function(obj, attr, val) {
|
|
|
|
if(val !== undefined) {
|
2012-06-28 10:50:32 +08:00
|
|
|
if(obj === undefined) {
|
|
|
|
obj = {};
|
|
|
|
}
|
2012-06-09 12:56:33 +08:00
|
|
|
obj[attr] = val;
|
|
|
|
}
|
|
|
|
},
|
2012-05-27 15:07:36 +08:00
|
|
|
_listenDrag: function() {
|
2012-04-02 10:38:30 +08:00
|
|
|
this._dragCleanup();
|
2012-07-04 13:08:59 +08:00
|
|
|
var go = Kinetic.Global;
|
2012-03-07 13:45:48 +08:00
|
|
|
var that = this;
|
2012-07-08 05:43:12 +08:00
|
|
|
this.on('mousedown.kinetic touchstart.kinetic', function(evt) {
|
2012-06-02 15:21:49 +08:00
|
|
|
that._initDrag();
|
2012-03-07 13:45:48 +08:00
|
|
|
});
|
|
|
|
},
|
2012-05-27 15:07:36 +08:00
|
|
|
_initDrag: function() {
|
2012-07-04 13:08:59 +08:00
|
|
|
var go = Kinetic.Global;
|
2012-05-27 15:07:36 +08:00
|
|
|
var stage = this.getStage();
|
|
|
|
var pos = stage.getUserPosition();
|
2012-06-08 15:42:48 +08:00
|
|
|
|
2012-05-27 15:07:36 +08:00
|
|
|
if(pos) {
|
|
|
|
var m = this.getTransform().getTranslation();
|
|
|
|
var am = this.getAbsoluteTransform().getTranslation();
|
2012-07-19 14:28:45 +08:00
|
|
|
var ap = this.getAbsolutePosition();
|
2012-05-27 15:07:36 +08:00
|
|
|
go.drag.node = this;
|
2012-07-19 14:28:45 +08:00
|
|
|
go.drag.offset.x = pos.x - ap.x;
|
|
|
|
go.drag.offset.y = pos.y - ap.y;
|
2012-05-27 15:07:36 +08:00
|
|
|
}
|
|
|
|
},
|
2012-07-15 07:25:56 +08:00
|
|
|
_onDraggableChange: function() {
|
|
|
|
if(this.attrs.draggable) {
|
|
|
|
this._listenDrag();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// remove event listeners
|
|
|
|
this._dragCleanup();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* force drag and drop to end
|
|
|
|
* if this node is currently in
|
|
|
|
* drag and drop mode
|
|
|
|
*/
|
|
|
|
var stage = this.getStage();
|
|
|
|
var go = Kinetic.Global;
|
|
|
|
if(stage && go.drag.node && go.drag.node._id === this._id) {
|
|
|
|
stage._endDrag();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2012-03-07 13:45:48 +08:00
|
|
|
/**
|
|
|
|
* remove drag and drop event listener
|
|
|
|
*/
|
|
|
|
_dragCleanup: function() {
|
2012-07-08 05:43:12 +08:00
|
|
|
this.off('mousedown.kinetic');
|
|
|
|
this.off('touchstart.kinetic');
|
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-06-08 15:42:48 +08:00
|
|
|
_handleEvent: function(eventType, evt) {
|
2012-04-05 13:57:36 +08:00
|
|
|
if(this.nodeType === 'Shape') {
|
2012-03-26 03:45:46 +08:00
|
|
|
evt.shape = this;
|
|
|
|
}
|
2012-06-08 15:42:48 +08:00
|
|
|
|
2012-03-19 02:24:57 +08:00
|
|
|
var stage = this.getStage();
|
2012-07-06 15:27:55 +08:00
|
|
|
var mover = stage ? stage.mouseoverShape : null;
|
|
|
|
var mout = stage ? stage.mouseoutShape : null;
|
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-03-19 02:24:57 +08:00
|
|
|
/*
|
|
|
|
* determine if event handler should be skipped by comparing
|
|
|
|
* parent nodes
|
|
|
|
*/
|
2012-07-06 15:27:55 +08:00
|
|
|
if(eventType === 'mouseover' && mout && mout._id === this._id) {
|
2012-03-19 02:24:57 +08:00
|
|
|
okayToRun = false;
|
|
|
|
}
|
2012-07-06 15:27:55 +08:00
|
|
|
else if(eventType === 'mouseout' && mover && mover._id === this._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
|
|
|
if(stage && mover && mout) {
|
|
|
|
stage.mouseoverShape = mover.parent;
|
|
|
|
stage.mouseoutShape = mout.parent;
|
|
|
|
}
|
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-07-06 15:27:55 +08:00
|
|
|
this._handleEvent.call(this.parent, eventType, evt);
|
|
|
|
}
|
2012-03-19 02:24:57 +08:00
|
|
|
}
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
2012-07-04 03:07:27 +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);
|
|
|
|
constructor.prototype[method] = function() {
|
|
|
|
if(arguments.length == 1) {
|
|
|
|
arg = arguments[0];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
arg = Array.prototype.slice.call(arguments);
|
|
|
|
}
|
|
|
|
var obj = {};
|
|
|
|
obj[attr] = arg;
|
|
|
|
this.setAttrs(obj);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
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];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
// add getters setters
|
|
|
|
Kinetic.Node.addGettersSetters(Kinetic.Node, ['x', 'y', 'scale', 'detectionType', 'rotation', 'alpha', 'name', 'id', 'offset', 'draggable', 'dragConstraint', 'dragBounds', 'listening']);
|
|
|
|
Kinetic.Node.addSetters(Kinetic.Node, ['rotationDeg']);
|
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 detection type
|
2012-06-14 17:19:51 +08:00
|
|
|
* @name setDetectionType
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-06-11 04:07:09 +08:00
|
|
|
* @param {String} type can be "path" or "pixel"
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* set alpha. Alpha values range from 0 to 1.
|
|
|
|
* A node with an alpha of 0 is fully transparent, and a node
|
|
|
|
* with an alpha of 1 is fully opaque
|
2012-06-14 17:19:51 +08:00
|
|
|
* @name setAlpha
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-06-11 04:07:09 +08:00
|
|
|
* @param {Object} alpha
|
|
|
|
*/
|
|
|
|
|
2012-06-19 13:02:13 +08:00
|
|
|
/**
|
|
|
|
* set draggable
|
|
|
|
* @name setDraggable
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {String} draggable
|
|
|
|
*/
|
|
|
|
|
2012-06-11 04:07:09 +08:00
|
|
|
/**
|
|
|
|
* set drag constraint
|
2012-06-14 17:19:51 +08:00
|
|
|
* @name setDragConstraint
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-06-11 04:07:09 +08:00
|
|
|
* @param {String} constraint
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* set drag bounds
|
2012-06-14 17:19:51 +08:00
|
|
|
* @name setDragBounds
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-06-11 04:07:09 +08:00
|
|
|
* @param {Object} bounds
|
|
|
|
* @config {Number} [left] left bounds position
|
|
|
|
* @config {Number} [top] top bounds position
|
|
|
|
* @config {Number} [right] right bounds position
|
|
|
|
* @config {Number} [bottom] bottom bounds position
|
|
|
|
*/
|
|
|
|
|
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-06-24 09:09:10 +08:00
|
|
|
/**
|
|
|
|
* set node rotation in degrees
|
|
|
|
* @name setRotationDeg
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {Number} deg
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* set offset
|
|
|
|
* @name setOffset
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
* @param {Number} x
|
|
|
|
* @param {Number} y
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* set node scale.
|
|
|
|
* @name setScale
|
|
|
|
* @param {Number|Array|Object|List} scale
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
|
2012-06-11 04:07:09 +08:00
|
|
|
/**
|
|
|
|
* get scale
|
2012-06-14 17:19:51 +08:00
|
|
|
* @name getScale
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
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 detection type
|
2012-06-14 17:19:51 +08:00
|
|
|
* @name getDetectionType
|
|
|
|
* @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
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* get alpha. Alpha values range from 0 to 1.
|
|
|
|
* A node with an alpha of 0 is fully transparent, and a node
|
|
|
|
* with an alpha of 1 is fully opaque
|
2012-06-14 17:19:51 +08:00
|
|
|
* @name getAlpha
|
|
|
|
* @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-06-14 17:19:51 +08:00
|
|
|
* get offset
|
|
|
|
* @name getOffset
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-06-11 04:07:09 +08:00
|
|
|
*/
|
|
|
|
|
2012-06-19 13:02:13 +08:00
|
|
|
/**
|
|
|
|
* get draggable
|
|
|
|
* @name getDraggable
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
|
|
|
*/
|
|
|
|
|
2012-06-11 04:07:09 +08:00
|
|
|
/**
|
|
|
|
* get drag constraint
|
2012-06-14 17:19:51 +08:00
|
|
|
* @name getDragConstraint
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-06-11 04:07:09 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* get drag bounds
|
2012-06-14 17:19:51 +08:00
|
|
|
* @name getDragBounds
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-06-19 14:12:56 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* determine if listening to events or not
|
|
|
|
* @name getListening
|
|
|
|
* @methodOf Kinetic.Node.prototype
|
2012-06-11 04:07:09 +08:00
|
|
|
*/
|