2012-11-27 12:42:01 +08:00
|
|
|
(function() {
|
2013-03-24 13:56:22 +08:00
|
|
|
// CONSTANTS
|
2013-08-11 02:55:52 +08:00
|
|
|
var ABSOLUTE_OPACITY = 'absoluteOpacity',
|
|
|
|
ABSOLUTE_TRANSFORM = 'absoluteTransform',
|
2013-03-24 13:56:22 +08:00
|
|
|
BEFORE = 'before',
|
|
|
|
CHANGE = 'Change',
|
2013-08-10 14:00:35 +08:00
|
|
|
CHILDREN = 'children',
|
|
|
|
DOT = '.',
|
|
|
|
EMPTY_STRING = '',
|
|
|
|
GET = 'get',
|
2013-03-24 13:56:22 +08:00
|
|
|
ID = 'id',
|
2013-08-10 14:00:35 +08:00
|
|
|
KINETIC = 'kinetic',
|
2013-08-11 07:19:33 +08:00
|
|
|
LISTENING = 'listening',
|
2013-12-10 02:07:08 +08:00
|
|
|
//LISTENING_ENABLED = 'listeningEnabled',
|
2013-03-24 13:56:22 +08:00
|
|
|
MOUSEENTER = 'mouseenter',
|
|
|
|
MOUSELEAVE = 'mouseleave',
|
2013-08-10 14:00:35 +08:00
|
|
|
NAME = 'name',
|
|
|
|
SET = 'set',
|
|
|
|
SHAPE = 'Shape',
|
|
|
|
SPACE = ' ',
|
2013-08-12 11:34:54 +08:00
|
|
|
STAGE = 'stage',
|
2013-08-10 12:09:06 +08:00
|
|
|
TRANSFORM = 'transform',
|
2013-08-12 11:34:54 +08:00
|
|
|
UPPER_STAGE = 'Stage',
|
2013-08-10 14:00:35 +08:00
|
|
|
VISIBLE = 'visible',
|
2013-08-11 04:04:02 +08:00
|
|
|
|
2013-12-06 14:29:50 +08:00
|
|
|
TRANSFORM_CHANGE_STR = [
|
2013-08-11 04:04:02 +08:00
|
|
|
'xChange.kinetic',
|
|
|
|
'yChange.kinetic',
|
|
|
|
'scaleXChange.kinetic',
|
|
|
|
'scaleYChange.kinetic',
|
|
|
|
'skewXChange.kinetic',
|
|
|
|
'skewYChange.kinetic',
|
|
|
|
'rotationChange.kinetic',
|
|
|
|
'offsetXChange.kinetic',
|
2013-12-12 14:34:02 +08:00
|
|
|
'offsetYChange.kinetic',
|
|
|
|
'transformsEnabledChange.kinetic'
|
2013-08-11 04:04:02 +08:00
|
|
|
].join(SPACE);
|
2013-08-10 15:58:53 +08:00
|
|
|
|
2013-05-08 14:51:02 +08:00
|
|
|
Kinetic.Util.addMethods(Kinetic.Node, {
|
2013-07-23 12:41:41 +08:00
|
|
|
_init: function(config) {
|
2013-08-12 11:34:54 +08:00
|
|
|
var that = this;
|
2013-09-09 13:02:04 +08:00
|
|
|
this._id = Kinetic.idCounter++;
|
2012-11-14 15:22:56 +08:00
|
|
|
this.eventListeners = {};
|
2013-07-23 13:05:21 +08:00
|
|
|
this.attrs = {};
|
2013-12-20 15:29:23 +08:00
|
|
|
this._cache = {};
|
2014-01-01 05:04:05 +08:00
|
|
|
this._filterUpToDate = false;
|
2012-11-14 15:22:56 +08:00
|
|
|
this.setAttrs(config);
|
2013-08-11 04:04:02 +08:00
|
|
|
|
|
|
|
// event bindings for cache handling
|
2013-12-06 14:29:50 +08:00
|
|
|
this.on(TRANSFORM_CHANGE_STR, function() {
|
2013-08-12 11:34:54 +08:00
|
|
|
this._clearCache(TRANSFORM);
|
2013-12-10 02:07:08 +08:00
|
|
|
that._clearSelfAndDescendantCache(ABSOLUTE_TRANSFORM);
|
2013-08-12 11:34:54 +08:00
|
|
|
});
|
|
|
|
this.on('visibleChange.kinetic', function() {
|
2013-12-10 02:07:08 +08:00
|
|
|
that._clearSelfAndDescendantCache(VISIBLE);
|
2013-08-12 11:34:54 +08:00
|
|
|
});
|
|
|
|
this.on('listeningChange.kinetic', function() {
|
2013-12-10 02:07:08 +08:00
|
|
|
that._clearSelfAndDescendantCache(LISTENING);
|
2013-08-12 11:34:54 +08:00
|
|
|
});
|
|
|
|
this.on('opacityChange.kinetic', function() {
|
2013-12-10 02:07:08 +08:00
|
|
|
that._clearSelfAndDescendantCache(ABSOLUTE_OPACITY);
|
2013-08-12 11:34:54 +08:00
|
|
|
});
|
|
|
|
},
|
2013-08-10 12:09:06 +08:00
|
|
|
_clearCache: function(attr){
|
2013-12-30 06:07:58 +08:00
|
|
|
if (attr) {
|
|
|
|
delete this._cache[attr];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this._cache = {};
|
|
|
|
}
|
2013-08-10 12:09:06 +08:00
|
|
|
},
|
2013-08-10 13:31:25 +08:00
|
|
|
_getCache: function(attr, privateGetter){
|
2013-12-20 15:29:23 +08:00
|
|
|
var cache = this._cache[attr];
|
2013-08-25 15:34:49 +08:00
|
|
|
|
2013-08-10 13:31:25 +08:00
|
|
|
// if not cached, we need to set it using the private getter method.
|
2013-08-10 14:00:35 +08:00
|
|
|
if (cache === undefined) {
|
2013-12-20 15:29:23 +08:00
|
|
|
this._cache[attr] = privateGetter.call(this);
|
2013-08-10 13:23:27 +08:00
|
|
|
}
|
2013-08-10 13:31:25 +08:00
|
|
|
|
2013-12-20 15:29:23 +08:00
|
|
|
return this._cache[attr];
|
2013-08-10 13:23:27 +08:00
|
|
|
},
|
2013-12-10 02:07:08 +08:00
|
|
|
/*
|
|
|
|
* when the logic for a cached result depends on ancestor propagation, use this
|
|
|
|
* method to clear self and children cache
|
|
|
|
*/
|
|
|
|
_clearSelfAndDescendantCache: function(attr) {
|
2013-08-12 11:34:54 +08:00
|
|
|
this._clearCache(attr);
|
|
|
|
|
|
|
|
if (this.children) {
|
|
|
|
this.getChildren().each(function(node) {
|
2013-12-10 02:38:01 +08:00
|
|
|
node._clearSelfAndDescendantCache(attr);
|
2013-08-12 11:34:54 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
2013-12-20 15:29:23 +08:00
|
|
|
/**
|
|
|
|
* clear cached canvas
|
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
|
|
|
* @returns {Kinetic.Node}
|
|
|
|
* @example
|
|
|
|
* node.clearCache();
|
|
|
|
*/
|
2013-12-30 06:07:58 +08:00
|
|
|
clearCache: function(attr) {
|
|
|
|
delete this._cache.canvas;
|
2013-12-20 15:29:23 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* cache node to improve drawing performance.
|
|
|
|
* NOTE: if you have filters applied to your node, your shape is already cached.
|
|
|
|
* explicitly calling cache() will override your filters.
|
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
|
|
|
* @returns {Kinetic.Node}
|
|
|
|
* @example
|
|
|
|
* node.cache();
|
|
|
|
*/
|
2014-01-01 05:04:05 +08:00
|
|
|
cache: function(b) {
|
|
|
|
var box = b || {},
|
|
|
|
x = box.x || 0,
|
2013-12-29 05:25:15 +08:00
|
|
|
y = box.y || 0,
|
2014-01-01 05:04:05 +08:00
|
|
|
width = box.width || this.width(),
|
|
|
|
height = box.height || this.height(),
|
2013-12-29 05:25:15 +08:00
|
|
|
sceneCanvasCache = new Kinetic.SceneCanvas({
|
|
|
|
pixelRatio: 1,
|
2014-01-01 05:04:05 +08:00
|
|
|
width: width,
|
|
|
|
height: height
|
2013-12-29 05:25:15 +08:00
|
|
|
}),
|
2014-01-01 05:04:05 +08:00
|
|
|
filterCanvasCache = new Kinetic.SceneCanvas({
|
2013-12-29 05:25:15 +08:00
|
|
|
pixelRatio: 1,
|
2014-01-01 05:04:05 +08:00
|
|
|
width: width,
|
|
|
|
height: height
|
|
|
|
}),
|
|
|
|
hitCanvasCache = new Kinetic.HitCanvas({
|
|
|
|
width: width,
|
|
|
|
height: height
|
2013-12-29 05:25:15 +08:00
|
|
|
}),
|
|
|
|
origTransEnabled = this.transformsEnabled(),
|
|
|
|
origX = this.x(),
|
|
|
|
origY = this.y();
|
|
|
|
|
|
|
|
this.transformsEnabled('position');
|
|
|
|
this.x(x * -1);
|
|
|
|
this.y(y * -1);
|
2013-12-20 15:29:23 +08:00
|
|
|
|
|
|
|
this.drawScene(sceneCanvasCache);
|
|
|
|
this.drawHit(hitCanvasCache);
|
|
|
|
|
2013-12-29 05:25:15 +08:00
|
|
|
this.x(origX);
|
|
|
|
this.y(origY);
|
|
|
|
this.transformsEnabled(origTransEnabled);
|
|
|
|
|
|
|
|
this._cache.canvas = {
|
|
|
|
scene: sceneCanvasCache,
|
2014-01-01 05:04:05 +08:00
|
|
|
filter: filterCanvasCache,
|
2013-12-29 05:25:15 +08:00
|
|
|
hit: hitCanvasCache,
|
|
|
|
x: x,
|
|
|
|
y: y
|
|
|
|
};
|
2013-12-31 06:34:57 +08:00
|
|
|
|
|
|
|
return this;
|
2013-12-20 15:29:23 +08:00
|
|
|
},
|
2014-01-01 05:04:05 +08:00
|
|
|
_drawCachedSceneCanvas: function(context) {
|
|
|
|
var filters = this.filters(),
|
|
|
|
cachedCanvas = this._cache.canvas,
|
|
|
|
sceneCanvas = cachedCanvas.scene,
|
|
|
|
filterCanvas = cachedCanvas.filter,
|
|
|
|
filterContext = filterCanvas.getContext(),
|
|
|
|
len, imageData, n, filter;
|
|
|
|
|
|
|
|
context.save();
|
|
|
|
context._applyTransform(this);
|
|
|
|
|
|
|
|
if (filters) {
|
|
|
|
if (!this._filterUpToDate) {
|
|
|
|
try {
|
|
|
|
len = filters.length;
|
|
|
|
filterContext.clear();
|
|
|
|
// copy cached canvas onto filter context
|
|
|
|
filterContext.drawImage(sceneCanvas._canvas, 0, 0);
|
|
|
|
imageData = filterContext.getImageData(0, 0, filterCanvas.getWidth(), filterCanvas.getHeight());
|
|
|
|
|
|
|
|
// apply filters to filter context
|
|
|
|
for (n=0; n<len; n++) {
|
|
|
|
filter = filters[n];
|
|
|
|
filter.call(this, imageData);
|
|
|
|
filterContext.putImageData(imageData, 0, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch(e) {
|
|
|
|
Kinetic.Util.warn('Unable to apply filter. ' + e.message);
|
|
|
|
}
|
|
|
|
|
|
|
|
this._filterUpToDate = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
context.drawImage(filterCanvas._canvas, 0, 0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
context.drawImage(sceneCanvas._canvas, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
context.restore();
|
|
|
|
},
|
2013-12-10 02:07:08 +08:00
|
|
|
/*
|
2013-12-10 02:41:53 +08:00
|
|
|
* the default isDraggable method returns false.
|
|
|
|
* if the DragAndDrop module is included, this is overwritten
|
|
|
|
*/
|
|
|
|
isDraggable: function() {
|
|
|
|
return false;
|
|
|
|
},
|
2012-11-14 15:22:56 +08:00
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* bind events to the node. KineticJS supports mouseover, mousemove,
|
|
|
|
* mouseout, mouseenter, mouseleave, mousedown, mouseup, click, dblclick, touchstart, touchmove,
|
2013-10-09 00:54:39 +08:00
|
|
|
* touchend, tap, dbltap, dragstart, dragmove, and dragend events. The Kinetic Stage supports
|
|
|
|
* contentMouseover, contentMousemove, contentMouseout, contentMousedown, contentMouseup,
|
|
|
|
* contentClick, contentDblclick, contentTouchstart, contentTouchmove, contentTouchend, contentTap,
|
|
|
|
* and contentDblTap. Pass in a string of events delimmited by a space to bind multiple events at once
|
2012-11-27 11:12:02 +08:00
|
|
|
* such as 'mousedown mouseup mousemove'. Include a namespace to bind an
|
2012-11-14 15:22:56 +08:00
|
|
|
* event by name such as 'click.foobar'.
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-07-25 13:56:21 +08:00
|
|
|
* @param {String} evtStr e.g. 'click', 'mousedown touchstart', 'mousedown.foo touchstart.foo'
|
2012-11-27 11:12:02 +08:00
|
|
|
* @param {Function} handler The handler function is passed an event object
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2013-05-16 00:27:22 +08:00
|
|
|
* @example
|
2013-05-18 02:46:06 +08:00
|
|
|
* // add click listener<br>
|
2013-05-16 00:27:22 +08:00
|
|
|
* node.on('click', function() {<br>
|
|
|
|
* console.log('you clicked me!');<br>
|
2013-05-18 01:51:56 +08:00
|
|
|
* });<br><br>
|
2013-07-22 11:14:09 +08:00
|
|
|
*
|
2013-05-18 02:46:06 +08:00
|
|
|
* // get the target node<br>
|
2013-05-18 01:51:56 +08:00
|
|
|
* node.on('click', function(evt) {<br>
|
|
|
|
* console.log(evt.targetNode);<br>
|
|
|
|
* });<br><br>
|
|
|
|
*
|
2013-05-18 02:46:06 +08:00
|
|
|
* // stop event propagation<br>
|
2013-05-18 01:51:56 +08:00
|
|
|
* node.on('click', function(evt) {<br>
|
2013-05-18 02:46:06 +08:00
|
|
|
* evt.cancelBubble = true;<br>
|
2013-05-18 01:51:56 +08:00
|
|
|
* });<br><br>
|
|
|
|
*
|
2013-05-18 02:46:06 +08:00
|
|
|
* // bind multiple listeners<br>
|
2013-05-18 01:51:56 +08:00
|
|
|
* node.on('click touchstart', function() {<br>
|
|
|
|
* console.log('you clicked/touched me!');<br>
|
|
|
|
* });<br><br>
|
|
|
|
*
|
2013-05-18 02:46:06 +08:00
|
|
|
* // namespace listener<br>
|
2013-05-18 01:51:56 +08:00
|
|
|
* node.on('click.foo', function() {<br>
|
|
|
|
* console.log('you clicked/touched me!');<br>
|
2013-05-16 15:28:49 +08:00
|
|
|
* });
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
2013-07-25 13:56:21 +08:00
|
|
|
on: function(evtStr, handler) {
|
|
|
|
var events = evtStr.split(SPACE),
|
|
|
|
len = events.length,
|
|
|
|
n, event, parts, baseEvent, name;
|
2013-07-22 11:14:09 +08:00
|
|
|
|
2013-03-24 13:56:22 +08:00
|
|
|
/*
|
2012-11-14 15:22:56 +08:00
|
|
|
* loop through types and attach event listeners to
|
|
|
|
* each one. eg. 'click mouseover.namespace mouseout'
|
|
|
|
* will create three event bindings
|
|
|
|
*/
|
2013-03-24 13:56:22 +08:00
|
|
|
for(n = 0; n < len; n++) {
|
2013-07-25 13:56:21 +08:00
|
|
|
event = events[n];
|
2013-03-24 13:56:22 +08:00
|
|
|
parts = event.split(DOT);
|
|
|
|
baseEvent = parts[0];
|
2013-07-25 13:56:21 +08:00
|
|
|
name = parts[1] || EMPTY_STRING;
|
2012-11-14 15:22:56 +08:00
|
|
|
|
2013-07-25 13:56:21 +08:00
|
|
|
// create events array if it doesn't exist
|
2012-11-14 15:22:56 +08:00
|
|
|
if(!this.eventListeners[baseEvent]) {
|
|
|
|
this.eventListeners[baseEvent] = [];
|
|
|
|
}
|
2012-08-26 13:26:25 +08:00
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
this.eventListeners[baseEvent].push({
|
|
|
|
name: name,
|
|
|
|
handler: handler
|
|
|
|
});
|
2013-12-10 02:07:08 +08:00
|
|
|
|
|
|
|
// NOTE: this flag is set to true when any event handler is added, even non
|
|
|
|
// mouse or touch gesture events. This improves performance for most
|
|
|
|
// cases where users aren't using events, but is still very light weight.
|
|
|
|
// To ensure perfect accuracy, devs can explicitly set listening to false.
|
|
|
|
/*
|
|
|
|
if (name !== KINETIC) {
|
|
|
|
this._listeningEnabled = true;
|
|
|
|
this._clearSelfAndAncestorCache(LISTENING_ENABLED);
|
|
|
|
}
|
|
|
|
*/
|
2012-07-14 12:24:38 +08:00
|
|
|
}
|
2013-12-10 02:07:08 +08:00
|
|
|
|
2013-03-15 06:07:35 +08:00
|
|
|
return this;
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* remove event bindings from the node. Pass in a string of
|
2012-11-14 15:22:56 +08:00
|
|
|
* event types delimmited by a space to remove multiple event
|
|
|
|
* bindings at once such as 'mousedown mouseup mousemove'.
|
|
|
|
* include a namespace to remove an event binding by name
|
|
|
|
* such as 'click.foobar'. If you only give a name like '.foobar',
|
|
|
|
* all events in that namespace will be removed.
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-07-25 13:56:21 +08:00
|
|
|
* @param {String} evtStr e.g. 'click', 'mousedown touchstart', '.foobar'
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2013-05-18 02:46:06 +08:00
|
|
|
* @example
|
|
|
|
* // remove listener<br>
|
|
|
|
* node.off('click');<br><br>
|
|
|
|
*
|
2013-05-18 06:35:21 +08:00
|
|
|
* // remove multiple listeners<br>
|
2013-05-18 02:46:06 +08:00
|
|
|
* node.off('click touchstart');<br><br>
|
|
|
|
*
|
|
|
|
* // remove listener by name<br>
|
|
|
|
* node.off('click.foo');
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
2013-07-25 13:56:21 +08:00
|
|
|
off: function(evtStr) {
|
|
|
|
var events = evtStr.split(SPACE),
|
|
|
|
len = events.length,
|
2013-12-10 02:38:01 +08:00
|
|
|
n, t, event, parts, baseEvent, name;
|
2013-07-22 11:14:09 +08:00
|
|
|
|
2013-03-24 13:56:22 +08:00
|
|
|
for(n = 0; n < len; n++) {
|
2013-07-25 13:56:21 +08:00
|
|
|
event = events[n];
|
2013-03-24 13:56:22 +08:00
|
|
|
parts = event.split(DOT);
|
|
|
|
baseEvent = parts[0];
|
2013-07-25 13:56:21 +08:00
|
|
|
name = parts[1];
|
2012-11-14 15:22:56 +08:00
|
|
|
|
2013-07-25 13:56:21 +08:00
|
|
|
if(baseEvent) {
|
|
|
|
if(this.eventListeners[baseEvent]) {
|
|
|
|
this._off(baseEvent, name);
|
2012-11-14 15:22:56 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2013-07-25 13:56:21 +08:00
|
|
|
for(t in this.eventListeners) {
|
|
|
|
this._off(t, name);
|
|
|
|
}
|
2012-11-14 15:22:56 +08:00
|
|
|
}
|
2012-07-14 12:24:38 +08:00
|
|
|
}
|
2013-03-15 06:07:35 +08:00
|
|
|
return this;
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
/**
|
2013-05-18 01:51:56 +08:00
|
|
|
* remove self from parent, but don't destroy
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2013-05-18 02:46:06 +08:00
|
|
|
* @example
|
|
|
|
* node.remove();
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
2012-11-14 15:22:56 +08:00
|
|
|
remove: function() {
|
|
|
|
var parent = this.getParent();
|
2013-07-22 11:14:09 +08:00
|
|
|
|
2013-01-13 14:01:12 +08:00
|
|
|
if(parent && parent.children) {
|
2012-11-14 15:22:56 +08:00
|
|
|
parent.children.splice(this.index, 1);
|
|
|
|
parent._setChildrenIndices();
|
2013-06-09 06:57:36 +08:00
|
|
|
delete this.parent;
|
2013-01-13 14:01:12 +08:00
|
|
|
}
|
2013-07-22 11:14:09 +08:00
|
|
|
|
2013-08-12 11:34:54 +08:00
|
|
|
// every cached attr that is calculated via node tree
|
2013-12-10 02:07:08 +08:00
|
|
|
// traversal must be cleared when removing a node
|
|
|
|
this._clearSelfAndDescendantCache(STAGE);
|
|
|
|
this._clearSelfAndDescendantCache(ABSOLUTE_TRANSFORM);
|
|
|
|
this._clearSelfAndDescendantCache(VISIBLE);
|
|
|
|
this._clearSelfAndDescendantCache(LISTENING);
|
|
|
|
this._clearSelfAndDescendantCache(ABSOLUTE_OPACITY);
|
2013-08-12 11:34:54 +08:00
|
|
|
|
2013-06-07 13:45:31 +08:00
|
|
|
return this;
|
2013-01-13 14:01:12 +08:00
|
|
|
},
|
|
|
|
/**
|
2013-05-18 01:51:56 +08:00
|
|
|
* remove and destroy self
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-05-18 02:46:06 +08:00
|
|
|
* @example
|
|
|
|
* node.destroy();
|
2013-01-13 14:01:12 +08:00
|
|
|
*/
|
|
|
|
destroy: function() {
|
2013-01-14 03:10:49 +08:00
|
|
|
// remove from ids and names hashes
|
2013-09-09 13:02:04 +08:00
|
|
|
Kinetic._removeId(this.getId());
|
|
|
|
Kinetic._removeName(this.getName(), this._id);
|
2013-01-13 14:01:12 +08:00
|
|
|
|
2013-01-14 11:59:35 +08:00
|
|
|
this.remove();
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
2013-03-15 23:33:05 +08:00
|
|
|
/**
|
|
|
|
* get attr
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-07-22 11:14:09 +08:00
|
|
|
* @param {String} attr
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Integer|String|Object|Array}
|
2013-05-18 02:46:06 +08:00
|
|
|
* @example
|
2013-05-19 01:40:05 +08:00
|
|
|
* var x = node.getAttr('x');
|
2013-03-15 23:33:05 +08:00
|
|
|
*/
|
|
|
|
getAttr: function(attr) {
|
2013-05-08 14:51:02 +08:00
|
|
|
var method = GET + Kinetic.Util._capitalize(attr);
|
|
|
|
if(Kinetic.Util._isFunction(this[method])) {
|
2013-04-28 11:50:42 +08:00
|
|
|
return this[method]();
|
|
|
|
}
|
|
|
|
// otherwise get directly
|
|
|
|
else {
|
|
|
|
return this.attrs[attr];
|
|
|
|
}
|
2013-03-15 23:33:05 +08:00
|
|
|
},
|
2013-08-10 15:58:53 +08:00
|
|
|
/**
|
|
|
|
* get ancestors
|
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Collection}
|
2013-08-10 15:58:53 +08:00
|
|
|
* @example
|
|
|
|
* shape.getAncestors().each(function(node) {
|
|
|
|
* console.log(node.getId());
|
|
|
|
* })
|
|
|
|
*/
|
|
|
|
getAncestors: function() {
|
|
|
|
var parent = this.getParent(),
|
|
|
|
ancestors = new Kinetic.Collection();
|
|
|
|
|
|
|
|
while (parent) {
|
|
|
|
ancestors.push(parent);
|
|
|
|
parent = parent.getParent();
|
|
|
|
}
|
|
|
|
|
|
|
|
return ancestors;
|
|
|
|
},
|
2012-11-14 15:22:56 +08:00
|
|
|
/**
|
2013-05-18 02:46:06 +08:00
|
|
|
* get attrs object literal
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Object}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
getAttrs: function() {
|
2013-03-15 23:33:05 +08:00
|
|
|
return this.attrs || {};
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
/**
|
2013-05-18 02:46:06 +08:00
|
|
|
* set multiple attrs at once using an object literal
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2012-11-27 11:12:02 +08:00
|
|
|
* @param {Object} config object containing key value pairs
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2013-05-18 02:46:06 +08:00
|
|
|
* @example
|
|
|
|
* node.setAttrs({<br>
|
|
|
|
* x: 5,<br>
|
|
|
|
* fill: 'red'<br>
|
|
|
|
* });<br>
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
setAttrs: function(config) {
|
2013-03-24 13:56:22 +08:00
|
|
|
var key, method;
|
2013-07-22 11:14:09 +08:00
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
if(config) {
|
2013-03-24 13:56:22 +08:00
|
|
|
for(key in config) {
|
2013-05-21 12:58:57 +08:00
|
|
|
if (key === CHILDREN) {
|
2013-07-22 11:14:09 +08:00
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
}
|
|
|
|
else {
|
2013-05-21 12:58:57 +08:00
|
|
|
method = SET + Kinetic.Util._capitalize(key);
|
|
|
|
// use setter if available
|
|
|
|
if(Kinetic.Util._isFunction(this[method])) {
|
|
|
|
this[method](config[key]);
|
|
|
|
}
|
|
|
|
// otherwise set directly
|
|
|
|
else {
|
|
|
|
this._setAttr(key, config[key]);
|
|
|
|
}
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
|
|
|
}
|
2012-03-14 12:16:25 +08:00
|
|
|
}
|
2013-06-07 13:45:31 +08:00
|
|
|
return this;
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
2013-08-11 07:19:33 +08:00
|
|
|
/**
|
2013-12-10 02:07:08 +08:00
|
|
|
* determine if node is listening for events by taking into account ancestors.
|
|
|
|
*
|
|
|
|
* Parent | Self | isListening
|
|
|
|
* listening | listening |
|
|
|
|
* ----------+-----------+------------
|
|
|
|
* T | T | T
|
|
|
|
* T | F | F
|
|
|
|
* F | T | T
|
|
|
|
* F | F | F
|
|
|
|
* ----------+-----------+------------
|
|
|
|
* T | I | T
|
|
|
|
* F | I | F
|
|
|
|
* I | I | T
|
|
|
|
*
|
2013-08-11 07:19:33 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:07:08 +08:00
|
|
|
* @returns {Boolean}
|
2013-08-11 07:19:33 +08:00
|
|
|
*/
|
|
|
|
isListening: function() {
|
2013-12-10 02:38:01 +08:00
|
|
|
return this._getCache(LISTENING, this._isListening);
|
2013-08-11 07:19:33 +08:00
|
|
|
},
|
|
|
|
_isListening: function() {
|
|
|
|
var listening = this.getListening(),
|
|
|
|
parent = this.getParent();
|
|
|
|
|
2013-12-10 02:07:08 +08:00
|
|
|
// the following conditions are a simplification of the truth table above.
|
|
|
|
// please modify carefully
|
|
|
|
if (listening === 'inherit') {
|
|
|
|
if (parent) {
|
|
|
|
return parent.isListening();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return listening;
|
2013-08-11 07:19:33 +08:00
|
|
|
}
|
2013-12-10 02:07:08 +08:00
|
|
|
},
|
|
|
|
/**
|
2013-12-11 23:46:49 +08:00
|
|
|
* determine if node is visible by taking into account ancestors.
|
|
|
|
*
|
|
|
|
* Parent | Self | isVisible
|
|
|
|
* visible | visible |
|
|
|
|
* ----------+-----------+------------
|
|
|
|
* T | T | T
|
|
|
|
* T | F | F
|
|
|
|
* F | T | T
|
|
|
|
* F | F | F
|
|
|
|
* ----------+-----------+------------
|
|
|
|
* T | I | T
|
|
|
|
* F | I | F
|
|
|
|
* I | I | T
|
|
|
|
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Boolean}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
2013-08-11 07:19:33 +08:00
|
|
|
isVisible: function() {
|
2013-12-10 02:38:01 +08:00
|
|
|
return this._getCache(VISIBLE, this._isVisible);
|
2013-08-10 14:00:35 +08:00
|
|
|
},
|
2013-08-11 07:19:33 +08:00
|
|
|
_isVisible: function() {
|
|
|
|
var visible = this.getVisible(),
|
2013-03-15 23:33:05 +08:00
|
|
|
parent = this.getParent();
|
2013-07-22 11:14:09 +08:00
|
|
|
|
2013-12-11 23:46:49 +08:00
|
|
|
// the following conditions are a simplification of the truth table above.
|
|
|
|
// please modify carefully
|
|
|
|
if (visible === 'inherit') {
|
|
|
|
if (parent) {
|
|
|
|
return parent.isVisible();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return true;
|
|
|
|
}
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
2013-12-11 23:46:49 +08:00
|
|
|
else {
|
|
|
|
return visible;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* determine if listening is enabled by taking into account descendants. If self or any children
|
2013-12-30 06:07:58 +08:00
|
|
|
* have _isListeningEnabled set to true, then self also has listening enabled.
|
2013-12-11 23:46:49 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
|
|
|
* @returns {Boolean}
|
|
|
|
*/
|
|
|
|
shouldDrawHit: function() {
|
|
|
|
var layer = this.getLayer();
|
|
|
|
return layer && layer.isHitGraphEnabled() && this.isListening() && this.isVisible() && !Kinetic.isDragging();
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* show node
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
show: function() {
|
|
|
|
this.setVisible(true);
|
2013-06-07 13:45:31 +08:00
|
|
|
return this;
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* hide node. Hidden nodes are no longer detectable
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
hide: function() {
|
|
|
|
this.setVisible(false);
|
2013-06-07 13:45:31 +08:00
|
|
|
return this;
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* get zIndex relative to the node's siblings who share the same parent
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Integer}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
getZIndex: function() {
|
2013-03-15 23:33:05 +08:00
|
|
|
return this.index || 0;
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get absolute z-index which takes into account sibling
|
2012-11-27 11:12:02 +08:00
|
|
|
* and ancestor indices
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Integer}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
getAbsoluteZIndex: function() {
|
2013-03-24 13:56:22 +08:00
|
|
|
var level = this.getLevel(),
|
|
|
|
that = this,
|
|
|
|
index = 0,
|
|
|
|
nodes, len, n, child;
|
2013-07-22 11:14:09 +08:00
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
function addChildren(children) {
|
2013-03-24 13:56:22 +08:00
|
|
|
nodes = [];
|
|
|
|
len = children.length;
|
|
|
|
for(n = 0; n < len; n++) {
|
|
|
|
child = children[n];
|
2012-11-14 15:22:56 +08:00
|
|
|
index++;
|
|
|
|
|
2013-03-24 13:56:22 +08:00
|
|
|
if(child.nodeType !== SHAPE) {
|
2013-05-20 12:07:43 +08:00
|
|
|
nodes = nodes.concat(child.getChildren().toArray());
|
2012-11-14 15:22:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if(child._id === that._id) {
|
|
|
|
n = len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(nodes.length > 0 && nodes[0].getLevel() <= level) {
|
|
|
|
addChildren(nodes);
|
|
|
|
}
|
|
|
|
}
|
2013-08-12 11:34:54 +08:00
|
|
|
if(that.nodeType !== UPPER_STAGE) {
|
2012-11-14 15:22:56 +08:00
|
|
|
addChildren(that.getStage().getChildren());
|
|
|
|
}
|
|
|
|
|
|
|
|
return index;
|
|
|
|
},
|
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* get node level in node tree. Returns an integer.<br><br>
|
2012-11-30 12:15:01 +08:00
|
|
|
* e.g. Stage level will always be 0. Layers will always be 1. Groups and Shapes will always
|
2012-11-27 11:12:02 +08:00
|
|
|
* be >= 2
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Integer}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
getLevel: function() {
|
2013-03-24 13:56:22 +08:00
|
|
|
var level = 0,
|
|
|
|
parent = this.parent;
|
2013-07-22 11:14:09 +08:00
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
while(parent) {
|
|
|
|
level++;
|
|
|
|
parent = parent.parent;
|
|
|
|
}
|
|
|
|
return level;
|
|
|
|
},
|
2013-12-02 15:47:24 +08:00
|
|
|
setPosition: function(pos) {
|
2013-05-08 15:18:29 +08:00
|
|
|
this.setX(pos.x);
|
|
|
|
this.setY(pos.y);
|
2013-06-07 13:45:31 +08:00
|
|
|
return this;
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
getPosition: function() {
|
|
|
|
return {
|
2013-03-15 23:33:05 +08:00
|
|
|
x: this.getX(),
|
|
|
|
y: this.getY()
|
2012-11-14 15:22:56 +08:00
|
|
|
};
|
|
|
|
},
|
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* get absolute position relative to the top left corner of the stage container div
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Object}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
getAbsolutePosition: function() {
|
2013-08-25 15:34:49 +08:00
|
|
|
var absoluteMatrix = this.getAbsoluteTransform().getMatrix(),
|
|
|
|
absoluteTransform = new Kinetic.Transform(),
|
2013-12-31 06:34:57 +08:00
|
|
|
offset = this.offset();
|
2013-07-22 11:14:09 +08:00
|
|
|
|
2013-08-25 15:34:49 +08:00
|
|
|
// clone the matrix array
|
|
|
|
absoluteTransform.m = absoluteMatrix.slice();
|
2013-12-31 06:34:57 +08:00
|
|
|
absoluteTransform.translate(offset.x, offset.y);
|
2013-08-25 15:34:49 +08:00
|
|
|
|
2013-08-12 18:00:08 +08:00
|
|
|
return absoluteTransform.getTranslation();
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* set absolute position
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-02 15:47:24 +08:00
|
|
|
* @param {Object} pos
|
|
|
|
* @param {Number} pos.x
|
|
|
|
* @param {Number} pos.y
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
2013-12-02 15:47:24 +08:00
|
|
|
setAbsolutePosition: function(pos) {
|
2013-12-29 05:25:15 +08:00
|
|
|
var origTrans = this._clearTransform(),
|
2013-03-24 13:56:22 +08:00
|
|
|
it;
|
2013-07-22 11:14:09 +08:00
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
// don't clear translation
|
2013-12-29 05:25:15 +08:00
|
|
|
this.attrs.x = origTrans.x;
|
|
|
|
this.attrs.y = origTrans.y;
|
|
|
|
delete origTrans.x;
|
|
|
|
delete origTrans.y;
|
2012-11-14 15:22:56 +08:00
|
|
|
|
|
|
|
// unravel transform
|
2013-03-24 13:56:22 +08:00
|
|
|
it = this.getAbsoluteTransform();
|
2012-11-14 15:22:56 +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
|
|
|
|
};
|
|
|
|
|
2013-12-05 01:55:17 +08:00
|
|
|
this.setPosition({x:pos.x, y:pos.y});
|
2013-12-29 05:25:15 +08:00
|
|
|
this._setTransform(origTrans);
|
|
|
|
|
2013-06-07 13:45:31 +08:00
|
|
|
return this;
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
2013-08-12 18:00:08 +08:00
|
|
|
_setTransform: function(trans) {
|
|
|
|
var key;
|
|
|
|
|
|
|
|
for(key in trans) {
|
|
|
|
this.attrs[key] = trans[key];
|
|
|
|
}
|
|
|
|
|
|
|
|
this._clearCache(TRANSFORM);
|
2013-12-10 02:07:08 +08:00
|
|
|
this._clearSelfAndDescendantCache(ABSOLUTE_TRANSFORM);
|
2013-08-12 18:00:08 +08:00
|
|
|
},
|
|
|
|
_clearTransform: function() {
|
|
|
|
var trans = {
|
|
|
|
x: this.getX(),
|
|
|
|
y: this.getY(),
|
|
|
|
rotation: this.getRotation(),
|
|
|
|
scaleX: this.getScaleX(),
|
|
|
|
scaleY: this.getScaleY(),
|
|
|
|
offsetX: this.getOffsetX(),
|
|
|
|
offsetY: this.getOffsetY(),
|
|
|
|
skewX: this.getSkewX(),
|
|
|
|
skewY: this.getSkewY()
|
|
|
|
};
|
|
|
|
|
|
|
|
this.attrs.x = 0;
|
|
|
|
this.attrs.y = 0;
|
|
|
|
this.attrs.rotation = 0;
|
|
|
|
this.attrs.scaleX = 1;
|
|
|
|
this.attrs.scaleY = 1;
|
|
|
|
this.attrs.offsetX = 0;
|
|
|
|
this.attrs.offsetY = 0;
|
|
|
|
this.attrs.skewX = 0;
|
|
|
|
this.attrs.skewY = 0;
|
|
|
|
|
|
|
|
this._clearCache(TRANSFORM);
|
2013-12-10 02:07:08 +08:00
|
|
|
this._clearSelfAndDescendantCache(ABSOLUTE_TRANSFORM);
|
2013-08-12 18:00:08 +08:00
|
|
|
|
2013-12-29 05:25:15 +08:00
|
|
|
// return original transform
|
2013-08-12 18:00:08 +08:00
|
|
|
return trans;
|
|
|
|
},
|
2012-11-14 15:22:56 +08:00
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* move node by an amount relative to its current position
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-02 15:47:24 +08:00
|
|
|
* @param {Object} change
|
|
|
|
* @param {Number} change.x
|
|
|
|
* @param {Number} change.y
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2013-05-18 02:46:06 +08:00
|
|
|
* @example
|
|
|
|
* // move node in x direction by 1px and y direction by 2px<br>
|
|
|
|
* node.move({<br>
|
2013-12-02 15:47:24 +08:00
|
|
|
* x: 1,<br>
|
|
|
|
* y: 2)<br>
|
2013-05-18 06:09:57 +08:00
|
|
|
* });
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
2013-12-02 15:47:24 +08:00
|
|
|
move: function(change) {
|
|
|
|
var changeX = change.x,
|
|
|
|
changeY = change.y,
|
2013-03-24 13:56:22 +08:00
|
|
|
x = this.getX(),
|
|
|
|
y = this.getY();
|
2012-11-14 15:22:56 +08:00
|
|
|
|
2013-12-02 15:47:24 +08:00
|
|
|
if(changeX !== undefined) {
|
|
|
|
x += changeX;
|
2012-11-14 15:22:56 +08:00
|
|
|
}
|
|
|
|
|
2013-12-02 15:47:24 +08:00
|
|
|
if(changeY !== undefined) {
|
|
|
|
y += changeY;
|
2012-09-27 03:50:08 +08:00
|
|
|
}
|
|
|
|
|
2013-12-03 13:25:20 +08:00
|
|
|
this.setPosition({x:x, y:y});
|
2013-06-07 13:45:31 +08:00
|
|
|
return this;
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
2012-12-31 17:47:49 +08:00
|
|
|
_eachAncestorReverse: function(func, includeSelf) {
|
2013-07-22 11:14:09 +08:00
|
|
|
var family = [],
|
2013-03-24 13:56:22 +08:00
|
|
|
parent = this.getParent(),
|
|
|
|
len, n;
|
2012-12-31 15:14:23 +08:00
|
|
|
|
|
|
|
// build family by traversing ancestors
|
2012-12-31 17:47:49 +08:00
|
|
|
if(includeSelf) {
|
|
|
|
family.unshift(this);
|
|
|
|
}
|
2012-12-31 15:14:23 +08:00
|
|
|
while(parent) {
|
|
|
|
family.unshift(parent);
|
|
|
|
parent = parent.parent;
|
|
|
|
}
|
|
|
|
|
2013-03-24 13:56:22 +08:00
|
|
|
len = family.length;
|
|
|
|
for(n = 0; n < len; n++) {
|
2012-12-31 15:48:46 +08:00
|
|
|
func(family[n]);
|
2012-12-31 15:14:23 +08:00
|
|
|
}
|
|
|
|
},
|
2012-11-14 15:22:56 +08:00
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* rotate node by an amount in radians relative to its current rotation
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2012-11-14 15:22:56 +08:00
|
|
|
* @param {Number} theta
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
rotate: function(theta) {
|
|
|
|
this.setRotation(this.getRotation() + theta);
|
2013-06-07 13:45:31 +08:00
|
|
|
return this;
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* rotate node by an amount in degrees relative to its current rotation
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2012-11-14 15:22:56 +08:00
|
|
|
* @param {Number} deg
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
rotateDeg: function(deg) {
|
2013-05-08 14:51:02 +08:00
|
|
|
this.setRotation(this.getRotation() + Kinetic.Util._degToRad(deg));
|
2013-06-07 13:45:31 +08:00
|
|
|
return this;
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* move node to the top of its siblings
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Boolean}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
moveToTop: function() {
|
|
|
|
var index = this.index;
|
|
|
|
this.parent.children.splice(index, 1);
|
|
|
|
this.parent.children.push(this);
|
|
|
|
this.parent._setChildrenIndices();
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* move node up
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Boolean}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
moveUp: function() {
|
2013-03-24 13:56:22 +08:00
|
|
|
var index = this.index,
|
|
|
|
len = this.parent.getChildren().length;
|
2012-11-14 15:22:56 +08:00
|
|
|
if(index < len - 1) {
|
|
|
|
this.parent.children.splice(index, 1);
|
|
|
|
this.parent.children.splice(index + 1, 0, this);
|
|
|
|
this.parent._setChildrenIndices();
|
|
|
|
return true;
|
|
|
|
}
|
2013-06-07 13:45:31 +08:00
|
|
|
return false;
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* move node down
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Boolean}
|
2012-11-14 15:22:56 +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();
|
|
|
|
return true;
|
|
|
|
}
|
2013-06-07 13:45:31 +08:00
|
|
|
return false;
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* move node to the bottom of its siblings
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Boolean}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
moveToBottom: function() {
|
|
|
|
var index = this.index;
|
|
|
|
if(index > 0) {
|
|
|
|
this.parent.children.splice(index, 1);
|
|
|
|
this.parent.children.unshift(this);
|
|
|
|
this.parent._setChildrenIndices();
|
|
|
|
return true;
|
|
|
|
}
|
2013-06-07 13:45:31 +08:00
|
|
|
return false;
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* set zIndex relative to siblings
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2012-11-14 15:22:56 +08:00
|
|
|
* @param {Integer} zIndex
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2012-11-14 15:22:56 +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();
|
2013-06-07 13:45:31 +08:00
|
|
|
return this;
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get absolute opacity
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Number}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
getAbsoluteOpacity: function() {
|
2013-08-11 02:55:52 +08:00
|
|
|
return this._getCache(ABSOLUTE_OPACITY, this._getAbsoluteOpacity);
|
|
|
|
},
|
|
|
|
_getAbsoluteOpacity: function() {
|
2012-11-14 15:22:56 +08:00
|
|
|
var absOpacity = this.getOpacity();
|
|
|
|
if(this.getParent()) {
|
|
|
|
absOpacity *= this.getParent().getAbsoluteOpacity();
|
|
|
|
}
|
|
|
|
return absOpacity;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* move node to another container
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2012-11-14 15:22:56 +08:00
|
|
|
* @param {Container} newContainer
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2013-05-18 02:46:06 +08:00
|
|
|
* @example
|
|
|
|
* // move node from current layer into layer2<br>
|
|
|
|
* node.moveTo(layer2);
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
moveTo: function(newContainer) {
|
2013-01-14 03:10:49 +08:00
|
|
|
Kinetic.Node.prototype.remove.call(this);
|
|
|
|
newContainer.add(this);
|
2013-06-07 13:45:31 +08:00
|
|
|
return this;
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* convert Node into an object for serialization. Returns an object.
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Object}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
toObject: function() {
|
2013-07-22 11:14:09 +08:00
|
|
|
var type = Kinetic.Util,
|
|
|
|
obj = {},
|
2013-03-24 13:56:22 +08:00
|
|
|
attrs = this.getAttrs(),
|
2013-11-28 00:47:52 +08:00
|
|
|
key, val, getter, defaultValue;
|
2012-04-29 03:55:18 +08:00
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
obj.attrs = {};
|
|
|
|
|
|
|
|
// serialize only attributes that are not function, image, DOM, or objects with methods
|
2013-03-24 13:56:22 +08:00
|
|
|
for(key in attrs) {
|
|
|
|
val = attrs[key];
|
2013-10-28 22:40:23 +08:00
|
|
|
if (!type._isFunction(val) && !type._isElement(val) && !(type._isObject(val) && type._hasMethods(val))) {
|
2013-11-28 00:47:52 +08:00
|
|
|
getter = this[GET + Kinetic.Util._capitalize(key)];
|
|
|
|
defaultValue = getter ? getter.call({attrs: {}}) : null;
|
2013-12-10 02:38:01 +08:00
|
|
|
if (defaultValue !== val) {
|
2013-10-28 22:40:23 +08:00
|
|
|
obj.attrs[key] = val;
|
|
|
|
}
|
2012-05-13 06:15:42 +08:00
|
|
|
}
|
2012-04-29 03:55:18 +08:00
|
|
|
}
|
2012-11-14 15:22:56 +08:00
|
|
|
|
2013-05-21 12:58:57 +08:00
|
|
|
obj.className = this.getClassName();
|
2012-11-14 15:22:56 +08:00
|
|
|
return obj;
|
|
|
|
},
|
2012-11-27 11:12:02 +08:00
|
|
|
/**
|
|
|
|
* convert Node into a JSON string. Returns a JSON string.
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {String}}
|
2012-11-27 11:12:02 +08:00
|
|
|
*/
|
2012-11-14 15:22:56 +08:00
|
|
|
toJSON: function() {
|
|
|
|
return JSON.stringify(this.toObject());
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get parent container
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
getParent: function() {
|
|
|
|
return this.parent;
|
|
|
|
},
|
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* get layer ancestor
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Layer}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
getLayer: function() {
|
2013-11-28 00:24:47 +08:00
|
|
|
var parent = this.getParent();
|
|
|
|
return parent ? parent.getLayer() : null;
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
/**
|
2012-11-27 11:12:02 +08:00
|
|
|
* get stage ancestor
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Stage}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
getStage: function() {
|
2013-08-12 11:34:54 +08:00
|
|
|
return this._getCache(STAGE, this._getStage);
|
|
|
|
},
|
|
|
|
_getStage: function() {
|
|
|
|
var parent = this.getParent();
|
|
|
|
if(parent) {
|
|
|
|
return parent.getStage();
|
2012-09-26 04:38:36 +08:00
|
|
|
}
|
2012-11-14 15:22:56 +08:00
|
|
|
else {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
2013-03-22 10:43:17 +08:00
|
|
|
* fire event
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-03-22 10:43:17 +08:00
|
|
|
* @param {String} eventType event type. can be a regular event, like click, mouseover, or mouseout, or it can be a custom event, like myCustomEvent
|
|
|
|
* @param {EventObject} evt event object
|
2013-07-22 11:14:09 +08:00
|
|
|
* @param {Boolean} bubble setting the value to false, or leaving it undefined, will result in the event
|
2013-05-13 23:56:09 +08:00
|
|
|
* not bubbling. Setting the value to true will result in the event bubbling.
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2013-05-18 02:46:06 +08:00
|
|
|
* @example
|
|
|
|
* // manually fire click event<br>
|
|
|
|
* node.fire('click');<br><br>
|
|
|
|
*
|
|
|
|
* // fire custom event<br>
|
|
|
|
* node.fire('foo');<br><br>
|
|
|
|
*
|
|
|
|
* // fire custom event with custom event object<br>
|
|
|
|
* node.fire('foo', {<br>
|
|
|
|
* bar: 10<br>
|
2013-05-18 06:09:57 +08:00
|
|
|
* });<br><br>
|
2013-05-18 02:46:06 +08:00
|
|
|
*
|
2013-05-19 01:40:05 +08:00
|
|
|
* // fire click event that bubbles<br>
|
|
|
|
* node.fire('click', null, true);
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
2013-05-13 23:56:09 +08:00
|
|
|
fire: function(eventType, evt, bubble) {
|
2013-03-22 10:43:17 +08:00
|
|
|
// bubble
|
2013-05-13 23:56:09 +08:00
|
|
|
if (bubble) {
|
|
|
|
this._fireAndBubble(eventType, evt || {});
|
|
|
|
}
|
|
|
|
// no bubble
|
2013-03-22 10:43:17 +08:00
|
|
|
else {
|
2013-05-13 23:56:09 +08:00
|
|
|
this._fire(eventType, evt || {});
|
2013-03-22 10:43:17 +08:00
|
|
|
}
|
2013-06-07 13:45:31 +08:00
|
|
|
return this;
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get absolute transform of the node which takes into
|
2012-11-27 11:12:02 +08:00
|
|
|
* account its ancestor transforms
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Transform}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
getAbsoluteTransform: function() {
|
2013-08-11 05:19:53 +08:00
|
|
|
return this._getCache(ABSOLUTE_TRANSFORM, this._getAbsoluteTransform);
|
2013-08-10 15:58:53 +08:00
|
|
|
},
|
|
|
|
_getAbsoluteTransform: function() {
|
2013-12-30 13:40:37 +08:00
|
|
|
var at = new Kinetic.Transform(),
|
|
|
|
transformsEnabled, trans;
|
2012-11-14 15:22:56 +08:00
|
|
|
|
2013-12-30 13:40:37 +08:00
|
|
|
// start with stage and traverse downwards to self
|
2012-12-31 17:47:49 +08:00
|
|
|
this._eachAncestorReverse(function(node) {
|
2013-12-30 13:40:37 +08:00
|
|
|
transformsEnabled = node.transformsEnabled();
|
|
|
|
trans = node.getTransform();
|
|
|
|
|
|
|
|
if (transformsEnabled === 'all') {
|
|
|
|
at.multiply(trans);
|
|
|
|
}
|
|
|
|
else if (transformsEnabled === 'position') {
|
|
|
|
at.translate(node.x(), node.y());
|
2013-12-12 14:34:02 +08:00
|
|
|
}
|
2012-12-31 17:47:49 +08:00
|
|
|
}, true);
|
2013-12-30 13:40:37 +08:00
|
|
|
return at;
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
2013-12-10 02:33:31 +08:00
|
|
|
/**
|
|
|
|
* get transform of the node
|
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
|
|
|
* @returns {Kinetic.Transform}
|
|
|
|
*/
|
|
|
|
getTransform: function() {
|
|
|
|
return this._getCache(TRANSFORM, this._getTransform);
|
|
|
|
},
|
2013-08-10 13:23:27 +08:00
|
|
|
_getTransform: function() {
|
2013-07-22 11:14:09 +08:00
|
|
|
var m = new Kinetic.Transform(),
|
|
|
|
x = this.getX(),
|
|
|
|
y = this.getY(),
|
2013-03-15 23:33:05 +08:00
|
|
|
rotation = this.getRotation(),
|
2013-07-22 11:14:09 +08:00
|
|
|
scaleX = this.getScaleX(),
|
|
|
|
scaleY = this.getScaleY(),
|
|
|
|
skewX = this.getSkewX(),
|
|
|
|
skewY = this.getSkewY(),
|
|
|
|
offsetX = this.getOffsetX(),
|
2013-05-02 01:56:01 +08:00
|
|
|
offsetY = this.getOffsetY();
|
2013-07-22 11:14:09 +08:00
|
|
|
|
2012-11-14 16:07:59 +08:00
|
|
|
if(x !== 0 || y !== 0) {
|
|
|
|
m.translate(x, y);
|
2012-11-14 15:22:56 +08:00
|
|
|
}
|
2012-11-14 16:07:59 +08:00
|
|
|
if(rotation !== 0) {
|
|
|
|
m.rotate(rotation);
|
2012-11-14 15:22:56 +08:00
|
|
|
}
|
2013-05-02 01:56:01 +08:00
|
|
|
if(skewX !== 0 || skewY !== 0) {
|
|
|
|
m.skew(skewX, skewY);
|
|
|
|
}
|
2012-11-14 16:07:59 +08:00
|
|
|
if(scaleX !== 1 || scaleY !== 1) {
|
|
|
|
m.scale(scaleX, scaleY);
|
2012-11-14 15:22:56 +08:00
|
|
|
}
|
2012-11-14 16:07:59 +08:00
|
|
|
if(offsetX !== 0 || offsetY !== 0) {
|
|
|
|
m.translate(-1 * offsetX, -1 * offsetY);
|
2012-11-14 15:22:56 +08:00
|
|
|
}
|
2013-07-22 11:14:09 +08:00
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
return m;
|
|
|
|
},
|
|
|
|
/**
|
2013-05-18 11:56:24 +08:00
|
|
|
* clone node. Returns a new Node instance with identical attributes. You can also override
|
|
|
|
* the node properties with an object literal, enabling you to use an existing node as a template
|
|
|
|
* for another node
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2012-11-14 15:22:56 +08:00
|
|
|
* @param {Object} attrs override attrs
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2013-05-18 02:46:06 +08:00
|
|
|
* @example
|
2013-05-18 11:56:24 +08:00
|
|
|
* // simple clone<br>
|
|
|
|
* var clone = node.clone();<br><br>
|
2013-05-18 02:46:06 +08:00
|
|
|
*
|
2013-05-18 11:56:24 +08:00
|
|
|
* // clone a node and override the x position<br>
|
|
|
|
* var clone = rect.clone({<br>
|
2013-05-18 02:46:06 +08:00
|
|
|
* x: 5<br>
|
|
|
|
* });
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
clone: function(obj) {
|
|
|
|
// instantiate new node
|
2013-05-20 12:48:48 +08:00
|
|
|
var className = this.getClassName(),
|
|
|
|
node = new Kinetic[className](this.attrs),
|
2013-03-24 13:56:22 +08:00
|
|
|
key, allListeners, len, n, listener;
|
2012-11-14 15:22:56 +08:00
|
|
|
|
2013-03-24 11:15:49 +08:00
|
|
|
// copy over listeners
|
2013-03-24 13:56:22 +08:00
|
|
|
for(key in this.eventListeners) {
|
|
|
|
allListeners = this.eventListeners[key];
|
|
|
|
len = allListeners.length;
|
|
|
|
for(n = 0; n < len; n++) {
|
|
|
|
listener = allListeners[n];
|
2012-11-14 15:22:56 +08:00
|
|
|
/*
|
|
|
|
* don't include kinetic namespaced listeners because
|
|
|
|
* these are generated by the constructors
|
|
|
|
*/
|
2013-03-24 13:56:22 +08:00
|
|
|
if(listener.name.indexOf(KINETIC) < 0) {
|
2012-11-14 15:22:56 +08:00
|
|
|
// if listeners array doesn't exist, then create it
|
|
|
|
if(!node.eventListeners[key]) {
|
|
|
|
node.eventListeners[key] = [];
|
|
|
|
}
|
|
|
|
node.eventListeners[key].push(listener);
|
|
|
|
}
|
2012-04-01 06:17:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
// apply attr overrides
|
|
|
|
node.setAttrs(obj);
|
|
|
|
return node;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* Creates a composite data URL. If MIME type is not
|
|
|
|
* specified, then "image/png" will result. For "image/jpeg", specify a quality
|
|
|
|
* level as quality (range 0.0 - 1.0)
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2012-11-14 15:22:56 +08:00
|
|
|
* @param {Object} config
|
2012-12-17 12:52:07 +08:00
|
|
|
* @param {Function} config.callback function executed when the composite has completed
|
|
|
|
* @param {String} [config.mimeType] can be "image/png" or "image/jpeg".
|
2012-11-14 15:22:56 +08:00
|
|
|
* "image/png" is the default
|
2012-12-17 12:52:07 +08:00
|
|
|
* @param {Number} [config.x] x position of canvas section
|
|
|
|
* @param {Number} [config.y] y position of canvas section
|
|
|
|
* @param {Number} [config.width] width of canvas section
|
|
|
|
* @param {Number} [config.height] height of canvas section
|
2012-11-14 15:22:56 +08:00
|
|
|
* @param {Number} [config.quality] jpeg quality. If using an "image/jpeg" mimeType,
|
|
|
|
* you can specify the quality from 0 to 1, where 0 is very poor quality and 1
|
|
|
|
* is very high quality
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {String}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
toDataURL: function(config) {
|
2013-06-02 13:03:02 +08:00
|
|
|
config = config || {};
|
|
|
|
|
2013-07-22 11:14:09 +08:00
|
|
|
var mimeType = config.mimeType || null,
|
2013-03-24 13:56:22 +08:00
|
|
|
quality = config.quality || null,
|
2013-04-15 00:41:59 +08:00
|
|
|
stage = this.getStage(),
|
2013-07-22 11:14:09 +08:00
|
|
|
x = config.x || 0,
|
2013-03-24 13:56:22 +08:00
|
|
|
y = config.y || 0,
|
2013-03-22 15:46:41 +08:00
|
|
|
canvas = new Kinetic.SceneCanvas({
|
2013-11-12 19:03:15 +08:00
|
|
|
width: config.width || this.getWidth() || (stage ? stage.getWidth() : 0),
|
|
|
|
height: config.height || this.getHeight() || (stage ? stage.getHeight() : 0),
|
2013-04-15 00:41:59 +08:00
|
|
|
pixelRatio: 1
|
|
|
|
}),
|
2013-09-03 12:16:26 +08:00
|
|
|
context = canvas.getContext();
|
2013-07-22 11:14:09 +08:00
|
|
|
|
2013-09-03 12:16:26 +08:00
|
|
|
context.save();
|
2012-12-31 15:14:23 +08:00
|
|
|
|
2012-12-11 16:08:59 +08:00
|
|
|
if(x || y) {
|
2013-09-03 12:16:26 +08:00
|
|
|
context.translate(-1 * x, -1 * y);
|
2012-12-11 16:08:59 +08:00
|
|
|
}
|
2013-04-15 00:41:59 +08:00
|
|
|
|
2012-12-11 16:08:59 +08:00
|
|
|
this.drawScene(canvas);
|
2013-09-03 12:16:26 +08:00
|
|
|
context.restore();
|
2012-04-01 06:17:36 +08:00
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
return canvas.toDataURL(mimeType, quality);
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* converts node into an image. Since the toImage
|
2012-11-27 11:12:02 +08:00
|
|
|
* method is asynchronous, a callback is required. toImage is most commonly used
|
|
|
|
* to cache complex drawings as an image so that they don't have to constantly be redrawn
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2012-11-14 15:22:56 +08:00
|
|
|
* @param {Object} config
|
2012-12-17 12:52:07 +08:00
|
|
|
* @param {Function} config.callback function executed when the composite has completed
|
|
|
|
* @param {String} [config.mimeType] can be "image/png" or "image/jpeg".
|
2012-11-14 15:22:56 +08:00
|
|
|
* "image/png" is the default
|
2012-12-17 12:52:07 +08:00
|
|
|
* @param {Number} [config.x] x position of canvas section
|
|
|
|
* @param {Number} [config.y] y position of canvas section
|
|
|
|
* @param {Number} [config.width] width of canvas section
|
|
|
|
* @param {Number} [config.height] height of canvas section
|
2012-11-14 15:22:56 +08:00
|
|
|
* @param {Number} [config.quality] jpeg quality. If using an "image/jpeg" mimeType,
|
|
|
|
* you can specify the quality from 0 to 1, where 0 is very poor quality and 1
|
|
|
|
* is very high quality
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Image}
|
2013-05-18 02:46:06 +08:00
|
|
|
* @example
|
|
|
|
* var image = node.toImage({<br>
|
|
|
|
* callback: function(img) {<br>
|
|
|
|
* // do stuff with img<br>
|
|
|
|
* }<br>
|
2013-05-18 06:09:57 +08:00
|
|
|
* });
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
toImage: function(config) {
|
2013-05-08 14:51:02 +08:00
|
|
|
Kinetic.Util._getImage(this.toDataURL(config), function(img) {
|
2012-11-14 15:22:56 +08:00
|
|
|
config.callback(img);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* set size
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-02 15:47:24 +08:00
|
|
|
* @param {Object} size
|
2012-11-14 15:22:56 +08:00
|
|
|
* @param {Number} width
|
|
|
|
* @param {Number} height
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
2013-12-02 15:47:24 +08:00
|
|
|
setSize: function(size) {
|
2012-11-14 15:22:56 +08:00
|
|
|
this.setWidth(size.width);
|
|
|
|
this.setHeight(size.height);
|
2013-06-07 13:45:31 +08:00
|
|
|
return this;
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get size
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Object}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
getSize: function() {
|
|
|
|
return {
|
|
|
|
width: this.getWidth(),
|
|
|
|
height: this.getHeight()
|
|
|
|
};
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get width
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Integer}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
getWidth: function() {
|
|
|
|
return this.attrs.width || 0;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get height
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Integer}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
|
|
|
getHeight: function() {
|
|
|
|
return this.attrs.height || 0;
|
|
|
|
},
|
2013-05-18 01:51:56 +08:00
|
|
|
/**
|
|
|
|
* get class name, which may return Stage, Layer, Group, or shape class names like Rect, Circle, Text, etc.
|
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {String}
|
2013-05-18 01:51:56 +08:00
|
|
|
*/
|
|
|
|
getClassName: function() {
|
2013-05-20 12:48:48 +08:00
|
|
|
return this.className || this.nodeType;
|
2013-05-18 01:51:56 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get the node type, which may return Stage, Layer, Group, or Node
|
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {String}
|
2013-05-18 01:51:56 +08:00
|
|
|
*/
|
|
|
|
getType: function() {
|
|
|
|
return this.nodeType;
|
|
|
|
},
|
2012-11-14 15:22:56 +08:00
|
|
|
_get: function(selector) {
|
|
|
|
return this.nodeType === selector ? [this] : [];
|
|
|
|
},
|
|
|
|
_off: function(type, name) {
|
2013-03-24 13:56:22 +08:00
|
|
|
var evtListeners = this.eventListeners[type],
|
2013-07-25 13:56:21 +08:00
|
|
|
i, evtName;
|
2013-07-22 11:14:09 +08:00
|
|
|
|
2013-03-24 13:56:22 +08:00
|
|
|
for(i = 0; i < evtListeners.length; i++) {
|
2013-07-25 13:56:21 +08:00
|
|
|
evtName = evtListeners[i].name;
|
|
|
|
// the following two conditions must be true in order to remove a handler:
|
|
|
|
// 1) the current event name cannot be kinetic unless the event name is kinetic
|
|
|
|
// this enables developers to force remove a kinetic specific listener for whatever reason
|
|
|
|
// 2) an event name is not specified, or if one is specified, it matches the current event name
|
|
|
|
if((evtName !== 'kinetic' || name === 'kinetic') && (!name || evtName === name)) {
|
2013-03-24 13:56:22 +08:00
|
|
|
evtListeners.splice(i, 1);
|
|
|
|
if(evtListeners.length === 0) {
|
2012-11-14 15:22:56 +08:00
|
|
|
delete this.eventListeners[type];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_fireBeforeChangeEvent: function(attr, oldVal, newVal) {
|
2013-12-02 16:06:27 +08:00
|
|
|
this._fire([BEFORE, Kinetic.Util._capitalize(attr), CHANGE].join(EMPTY_STRING), {
|
2012-11-14 15:22:56 +08:00
|
|
|
oldVal: oldVal,
|
|
|
|
newVal: newVal
|
2013-05-13 23:56:09 +08:00
|
|
|
});
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
|
|
|
_fireChangeEvent: function(attr, oldVal, newVal) {
|
2013-05-13 23:56:09 +08:00
|
|
|
this._fire(attr + CHANGE, {
|
2012-11-14 15:22:56 +08:00
|
|
|
oldVal: oldVal,
|
|
|
|
newVal: newVal
|
2013-05-13 23:56:09 +08:00
|
|
|
});
|
2012-11-14 15:22:56 +08:00
|
|
|
},
|
2013-01-14 03:10:49 +08:00
|
|
|
/**
|
|
|
|
* set id
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-01-14 03:10:49 +08:00
|
|
|
* @param {String} id
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2013-01-14 03:10:49 +08:00
|
|
|
*/
|
|
|
|
setId: function(id) {
|
2013-09-09 13:02:04 +08:00
|
|
|
var oldId = this.getId();
|
2013-07-22 11:14:09 +08:00
|
|
|
|
2013-09-09 13:02:04 +08:00
|
|
|
Kinetic._removeId(oldId);
|
|
|
|
Kinetic._addId(this, id);
|
2013-05-15 13:37:33 +08:00
|
|
|
this._setAttr(ID, id);
|
2013-06-07 13:45:31 +08:00
|
|
|
return this;
|
2013-01-14 03:10:49 +08:00
|
|
|
},
|
|
|
|
setName: function(name) {
|
2013-09-09 13:02:04 +08:00
|
|
|
var oldName = this.getName();
|
2013-07-22 11:14:09 +08:00
|
|
|
|
2013-09-09 13:02:04 +08:00
|
|
|
Kinetic._removeName(oldName, this._id);
|
|
|
|
Kinetic._addName(this, name);
|
2013-05-15 13:37:33 +08:00
|
|
|
this._setAttr(NAME, name);
|
2013-06-07 13:45:31 +08:00
|
|
|
return this;
|
2013-01-14 03:10:49 +08:00
|
|
|
},
|
2013-12-05 00:56:21 +08:00
|
|
|
/**
|
|
|
|
* set attr
|
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
|
|
|
* @param {String} attr
|
2013-12-10 02:33:31 +08:00
|
|
|
* @param {*} val
|
|
|
|
* @returns {Kinetic.Node}
|
2013-12-05 00:56:21 +08:00
|
|
|
* @example
|
|
|
|
* node.setAttr('x', 5);
|
|
|
|
*/
|
|
|
|
setAttr: function() {
|
|
|
|
var args = Array.prototype.slice.call(arguments),
|
|
|
|
attr = args[0],
|
|
|
|
val = args[1],
|
|
|
|
method = SET + Kinetic.Util._capitalize(attr),
|
|
|
|
func = this[method];
|
|
|
|
|
|
|
|
if(Kinetic.Util._isFunction(func)) {
|
|
|
|
func.call(this, val);
|
|
|
|
}
|
|
|
|
// otherwise set directly
|
|
|
|
else {
|
|
|
|
this._setAttr(attr, val);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
},
|
2013-05-15 13:37:33 +08:00
|
|
|
_setAttr: function(key, val) {
|
2013-03-24 13:56:22 +08:00
|
|
|
var oldVal;
|
2012-11-14 15:22:56 +08:00
|
|
|
if(val !== undefined) {
|
2013-03-24 13:56:22 +08:00
|
|
|
oldVal = this.attrs[key];
|
2012-11-14 15:22:56 +08:00
|
|
|
this.attrs[key] = val;
|
|
|
|
this._fireChangeEvent(key, oldVal, val);
|
|
|
|
}
|
|
|
|
},
|
2013-12-10 02:38:01 +08:00
|
|
|
_setComponentAttr: function(key, component, val) {
|
2013-12-02 15:47:24 +08:00
|
|
|
var oldVal;
|
|
|
|
if(val !== undefined) {
|
|
|
|
oldVal = this.attrs[key];
|
|
|
|
|
|
|
|
if (!oldVal) {
|
2013-12-04 14:54:16 +08:00
|
|
|
// set value to default value using getAttr
|
|
|
|
this.attrs[key] = this.getAttr(key);
|
2013-12-02 15:47:24 +08:00
|
|
|
}
|
|
|
|
|
2013-12-04 14:54:16 +08:00
|
|
|
//this._fireBeforeChangeEvent(key, oldVal, val);
|
2013-12-02 15:47:24 +08:00
|
|
|
this.attrs[key][component] = val;
|
|
|
|
this._fireChangeEvent(key, oldVal, val);
|
|
|
|
}
|
|
|
|
},
|
2013-05-13 23:56:09 +08:00
|
|
|
_fireAndBubble: function(eventType, evt, compareShape) {
|
2013-08-12 11:34:54 +08:00
|
|
|
var okayToRun = true;
|
|
|
|
|
2013-03-24 13:56:22 +08:00
|
|
|
if(evt && this.nodeType === SHAPE) {
|
2013-03-25 01:38:05 +08:00
|
|
|
evt.targetNode = this;
|
2012-11-14 15:22:56 +08:00
|
|
|
}
|
|
|
|
|
2013-03-24 13:56:22 +08:00
|
|
|
if(eventType === MOUSEENTER && compareShape && this._id === compareShape._id) {
|
2012-11-14 15:22:56 +08:00
|
|
|
okayToRun = false;
|
|
|
|
}
|
2013-03-24 13:56:22 +08:00
|
|
|
else if(eventType === MOUSELEAVE && compareShape && this._id === compareShape._id) {
|
2012-11-14 15:22:56 +08:00
|
|
|
okayToRun = false;
|
|
|
|
}
|
2012-06-10 06:31:25 +08:00
|
|
|
|
2013-07-22 11:14:09 +08:00
|
|
|
if(okayToRun) {
|
2013-05-13 23:56:09 +08:00
|
|
|
this._fire(eventType, evt);
|
2012-11-14 15:22:56 +08:00
|
|
|
|
|
|
|
// simulate event bubbling
|
|
|
|
if(evt && !evt.cancelBubble && this.parent) {
|
|
|
|
if(compareShape && compareShape.parent) {
|
2013-05-13 23:56:09 +08:00
|
|
|
this._fireAndBubble.call(this.parent, eventType, evt, compareShape.parent);
|
2012-11-14 15:22:56 +08:00
|
|
|
}
|
|
|
|
else {
|
2013-05-13 23:56:09 +08:00
|
|
|
this._fireAndBubble.call(this.parent, eventType, evt);
|
2012-11-14 15:22:56 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2013-05-13 23:56:09 +08:00
|
|
|
_fire: function(eventType, evt) {
|
2013-03-22 10:43:17 +08:00
|
|
|
var events = this.eventListeners[eventType],
|
2013-10-05 03:43:08 +08:00
|
|
|
i;
|
2013-07-22 11:14:09 +08:00
|
|
|
|
2013-03-22 10:43:17 +08:00
|
|
|
if (events) {
|
2013-10-05 03:03:50 +08:00
|
|
|
for(i = 0; i < events.length; i++) {
|
2013-05-15 13:37:33 +08:00
|
|
|
events[i].handler.call(this, evt);
|
2013-03-22 10:43:17 +08:00
|
|
|
}
|
2012-11-14 15:22:56 +08:00
|
|
|
}
|
2013-03-22 15:46:41 +08:00
|
|
|
},
|
2013-10-14 03:35:29 +08:00
|
|
|
/**
|
2013-12-10 02:33:31 +08:00
|
|
|
* draw both scene and hit graphs. If the node being drawn is the stage, all of the layers will be cleared and redrawn
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2013-03-22 15:46:41 +08:00
|
|
|
*/
|
|
|
|
draw: function() {
|
|
|
|
this.drawScene();
|
|
|
|
this.drawHit();
|
2013-06-07 13:45:31 +08:00
|
|
|
return this;
|
2012-06-10 06:31:25 +08:00
|
|
|
}
|
2013-05-08 14:17:57 +08:00
|
|
|
});
|
2012-06-10 06:31:25 +08:00
|
|
|
|
2012-03-07 13:45:48 +08:00
|
|
|
/**
|
2012-11-14 15:22:56 +08:00
|
|
|
* create node with JSON string. De-serializtion does not generate custom
|
|
|
|
* shape drawing functions, images, or event handlers (this would make the
|
2013-06-02 13:03:02 +08:00
|
|
|
* serialized object huge). If your app uses custom shapes, images, and
|
2012-11-14 15:22:56 +08:00
|
|
|
* event handlers (it probably does), then you need to select the appropriate
|
|
|
|
* shapes after loading the stage and set these properties via on(), setDrawFunc(),
|
2012-11-27 11:12:02 +08:00
|
|
|
* and setImage() methods
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node
|
2012-11-14 15:22:56 +08:00
|
|
|
* @param {String} JSON string
|
2012-11-30 12:15:01 +08:00
|
|
|
* @param {DomElement} [container] optional container dom element used only if you're
|
2012-11-27 11:12:02 +08:00
|
|
|
* creating a stage node
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
2012-11-27 12:42:01 +08:00
|
|
|
Kinetic.Node.create = function(json, container) {
|
2012-11-14 15:22:56 +08:00
|
|
|
return this._createNode(JSON.parse(json), container);
|
|
|
|
};
|
2012-11-27 12:42:01 +08:00
|
|
|
Kinetic.Node._createNode = function(obj, container) {
|
2013-05-20 12:48:48 +08:00
|
|
|
var className = Kinetic.Node.prototype.getClassName.call(obj),
|
|
|
|
children = obj.children,
|
|
|
|
no, len, n;
|
2012-10-04 10:38:12 +08:00
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
// if container was passed in, add it to attrs
|
|
|
|
if(container) {
|
|
|
|
obj.attrs.container = container;
|
|
|
|
}
|
2012-10-04 10:38:12 +08:00
|
|
|
|
2013-05-20 12:48:48 +08:00
|
|
|
no = new Kinetic[className](obj.attrs);
|
|
|
|
if(children) {
|
|
|
|
len = children.length;
|
2013-03-24 13:56:22 +08:00
|
|
|
for(n = 0; n < len; n++) {
|
2013-05-20 12:48:48 +08:00
|
|
|
no.add(this._createNode(children[n]));
|
2012-10-04 10:38:12 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-14 15:22:56 +08:00
|
|
|
return no;
|
|
|
|
};
|
|
|
|
// add getters setters
|
2013-12-14 13:33:40 +08:00
|
|
|
Kinetic.Factory.addOverloadedGetterSetter(Kinetic.Node, 'position');
|
2012-03-07 13:45:48 +08:00
|
|
|
/**
|
2013-12-14 13:33:40 +08:00
|
|
|
* get or set node position relative to parent
|
|
|
|
* @name position
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-14 13:33:40 +08:00
|
|
|
* @param {Object} pos
|
|
|
|
* @param {Number} pos.x
|
|
|
|
* @param {Nubmer} pos.y
|
|
|
|
* @returns {Object}
|
|
|
|
* @example
|
|
|
|
* // get position<br>
|
|
|
|
* var position = node.position();<br><br>
|
|
|
|
*
|
|
|
|
* // set position<br>
|
|
|
|
* node.position({<br>
|
|
|
|
* x: 5<br>
|
|
|
|
* y: 10
|
|
|
|
* });
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
2012-11-14 15:22:56 +08:00
|
|
|
|
2013-12-14 13:33:40 +08:00
|
|
|
Kinetic.Factory.addGetterSetter(Kinetic.Node, 'x', 0);
|
|
|
|
|
2012-06-02 15:21:49 +08:00
|
|
|
/**
|
2013-12-14 13:33:40 +08:00
|
|
|
* get or set x position
|
|
|
|
* @name x
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-14 13:33:40 +08:00
|
|
|
* @param {Number} x
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Object}
|
2013-12-14 13:33:40 +08:00
|
|
|
* @example
|
|
|
|
* // get x<br>
|
|
|
|
* var x = node.x();<br><br>
|
|
|
|
*
|
|
|
|
* // set x<br>
|
|
|
|
* node.x(5);
|
2012-06-02 15:21:49 +08:00
|
|
|
*/
|
2012-11-14 15:22:56 +08:00
|
|
|
|
2013-12-05 00:15:04 +08:00
|
|
|
Kinetic.Factory.addGetterSetter(Kinetic.Node, 'y', 0);
|
2013-05-02 01:56:01 +08:00
|
|
|
|
2012-03-24 14:39:54 +08:00
|
|
|
/**
|
2013-12-14 13:33:40 +08:00
|
|
|
* get or set y position
|
|
|
|
* @name y
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-05-02 01:56:01 +08:00
|
|
|
* @param {Number} y
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Integer}
|
2013-12-14 13:33:40 +08:00
|
|
|
* @example
|
|
|
|
* // get y<br>
|
|
|
|
* var y = node.y();<br><br>
|
|
|
|
*
|
|
|
|
* // set y<br>
|
|
|
|
* node.y(5);
|
2012-11-27 11:12:02 +08:00
|
|
|
*/
|
2012-11-30 12:15:01 +08:00
|
|
|
|
2013-12-05 00:15:04 +08:00
|
|
|
Kinetic.Factory.addGetterSetter(Kinetic.Node, 'opacity', 1);
|
2013-05-02 01:56:01 +08:00
|
|
|
|
2012-11-27 11:12:02 +08:00
|
|
|
/**
|
2013-12-14 13:33:40 +08:00
|
|
|
* get or set opacity. Opacity values range from 0 to 1.
|
2013-05-02 01:56:01 +08:00
|
|
|
* A node with an opacity of 0 is fully transparent, and a node
|
|
|
|
* with an opacity of 1 is fully opaque
|
2013-12-14 13:33:40 +08:00
|
|
|
* @name opacity
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-05-02 01:56:01 +08:00
|
|
|
* @param {Object} opacity
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Number}
|
2013-12-14 13:33:40 +08:00
|
|
|
* @example
|
|
|
|
* // get opacity<br>
|
|
|
|
* var opacity = node.opacity();<br><br>
|
|
|
|
*
|
|
|
|
* // set opacity<br>
|
|
|
|
* node.opacity(0.5);
|
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
|
|
|
|
2013-08-11 12:11:34 +08:00
|
|
|
Kinetic.Factory.addGetter(Kinetic.Node, 'name');
|
2013-12-14 03:02:07 +08:00
|
|
|
Kinetic.Factory.addOverloadedGetterSetter(Kinetic.Node, 'name');
|
2013-01-14 03:10:49 +08:00
|
|
|
|
2013-12-14 13:33:40 +08:00
|
|
|
/**
|
|
|
|
* set name
|
|
|
|
* @name name
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-14 13:33:40 +08:00
|
|
|
* @param {String} name
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {String}
|
2013-12-14 13:33:40 +08:00
|
|
|
* @example
|
|
|
|
* // get name<br>
|
|
|
|
* var name = node.name();<br><br>
|
|
|
|
*
|
|
|
|
* // set name<br>
|
|
|
|
* node.name('foo');
|
2012-07-15 14:41:16 +08:00
|
|
|
*/
|
2012-11-14 15:22:56 +08:00
|
|
|
|
2013-08-11 12:11:34 +08:00
|
|
|
Kinetic.Factory.addGetter(Kinetic.Node, 'id');
|
2013-12-14 03:02:07 +08:00
|
|
|
Kinetic.Factory.addOverloadedGetterSetter(Kinetic.Node, 'id');
|
2013-05-02 01:56:01 +08:00
|
|
|
|
2012-09-25 11:34:23 +08:00
|
|
|
/**
|
2013-12-14 13:33:40 +08:00
|
|
|
* set id
|
|
|
|
* @name id
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-14 13:33:40 +08:00
|
|
|
* @param {String} id
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {String}
|
2013-12-14 13:33:40 +08:00
|
|
|
* @example
|
|
|
|
* // get id<br>
|
|
|
|
* var name = node.id();<br><br>
|
|
|
|
*
|
|
|
|
* // set id<br>
|
|
|
|
* node.id('foo');
|
2012-09-26 04:38:36 +08:00
|
|
|
*/
|
2012-11-14 15:22:56 +08:00
|
|
|
|
2013-08-11 12:11:34 +08:00
|
|
|
Kinetic.Factory.addRotationGetterSetter(Kinetic.Node, 'rotation', 0);
|
2013-01-03 13:35:51 +08:00
|
|
|
|
2012-09-25 11:34:23 +08:00
|
|
|
/**
|
2013-12-14 13:33:40 +08:00
|
|
|
* get or set rotation in radians
|
|
|
|
* @name rotation
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-01-03 13:35:51 +08:00
|
|
|
* @param {Number} theta
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Number}
|
2013-12-14 13:33:40 +08:00
|
|
|
* @example
|
|
|
|
* // get rotation in radians<br>
|
|
|
|
* var rotation = node.rotation();<br><br>
|
|
|
|
*
|
|
|
|
* // set rotation in radians<br>
|
|
|
|
* node.rotation(Math.PI / 2);
|
2012-10-11 09:48:08 +08:00
|
|
|
*/
|
2012-11-14 15:22:56 +08:00
|
|
|
|
2012-10-11 09:48:08 +08:00
|
|
|
/**
|
2013-12-14 13:33:40 +08:00
|
|
|
* get or set rotation in degrees
|
|
|
|
* @name rotationDeg
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-14 13:33:40 +08:00
|
|
|
* @param {Number} deg
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Number}
|
2013-12-14 13:33:40 +08:00
|
|
|
* @example
|
|
|
|
* // get rotation in degrees<br>
|
|
|
|
* var rotationDeg = node.rotationDeg();<br><br>
|
|
|
|
*
|
|
|
|
* // set rotation in degrees<br>
|
|
|
|
* node.rotationDeg(45);
|
2012-10-11 09:48:08 +08:00
|
|
|
*/
|
2012-11-14 15:22:56 +08:00
|
|
|
|
2013-12-05 01:10:24 +08:00
|
|
|
Kinetic.Factory.addPointGetterSetter(Kinetic.Node, 'scale', 1);
|
2013-01-03 13:35:51 +08:00
|
|
|
|
2012-10-11 09:48:08 +08:00
|
|
|
/**
|
2013-12-14 13:33:40 +08:00
|
|
|
* get or set scale
|
|
|
|
* @name scale
|
2013-12-02 15:47:24 +08:00
|
|
|
* @param {Object} scale
|
|
|
|
* @param {Number} scale.x
|
|
|
|
* @param {Number} scale.y
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-14 13:33:40 +08:00
|
|
|
* @returns {Object}
|
2013-05-19 01:40:05 +08:00
|
|
|
* @example
|
2013-12-14 13:33:40 +08:00
|
|
|
* // get scale<br>
|
|
|
|
* var scale = node.scale();<br><br>
|
|
|
|
*
|
|
|
|
* // set scale <br>
|
|
|
|
* shape.scale({<br>
|
|
|
|
* x: 2<br>
|
|
|
|
* y: 3<br>
|
2013-12-02 15:47:24 +08:00
|
|
|
* });
|
2013-01-03 13:35:51 +08:00
|
|
|
*/
|
|
|
|
|
2013-12-02 15:47:24 +08:00
|
|
|
/**
|
2013-12-14 13:33:40 +08:00
|
|
|
* get or set scale x
|
|
|
|
* @name scaleX
|
2013-12-02 15:47:24 +08:00
|
|
|
* @param {Number} x
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Number}
|
2013-12-14 13:33:40 +08:00
|
|
|
* @example
|
|
|
|
* // get scale x<br>
|
|
|
|
* var scaleX = node.scaleX();<br><br>
|
|
|
|
*
|
|
|
|
* // set scale x<br>
|
|
|
|
* node.scaleX(2);
|
2013-05-02 01:56:01 +08:00
|
|
|
*/
|
|
|
|
|
2013-12-02 15:47:24 +08:00
|
|
|
/**
|
2013-12-14 13:33:40 +08:00
|
|
|
* get or set scale y
|
|
|
|
* @name scaleY
|
2013-12-02 15:47:24 +08:00
|
|
|
* @param {Number} y
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-14 13:33:40 +08:00
|
|
|
* @returns {Number}
|
|
|
|
* @example
|
|
|
|
* // get scale y<br>
|
|
|
|
* var scaleY = node.scaleY();<br><br>
|
|
|
|
*
|
|
|
|
* // set scale y<br>
|
|
|
|
* node.scaleY(2);
|
2013-05-08 01:19:54 +08:00
|
|
|
*/
|
|
|
|
|
2013-12-05 01:10:24 +08:00
|
|
|
Kinetic.Factory.addPointGetterSetter(Kinetic.Node, 'skew', 0);
|
2013-05-02 01:56:01 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* set skew
|
|
|
|
* @name setSkew
|
2013-12-04 14:54:16 +08:00
|
|
|
* @param {Object} skew
|
|
|
|
* @param {Number} skew.x
|
|
|
|
* @param {Number} skew.y
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2013-05-19 01:40:05 +08:00
|
|
|
* @example
|
2013-12-04 14:54:16 +08:00
|
|
|
* // set x and y <br>
|
2013-05-19 01:40:05 +08:00
|
|
|
* shape.setSkew({<br>
|
|
|
|
* x: 20<br>
|
2013-12-04 14:54:16 +08:00
|
|
|
* y: 10
|
|
|
|
* });
|
2012-10-11 09:48:08 +08:00
|
|
|
*/
|
2012-07-20 14:30:59 +08:00
|
|
|
|
2013-12-04 14:54:16 +08:00
|
|
|
/**
|
|
|
|
* get skew
|
|
|
|
* @name getSkew
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-04 14:54:16 +08:00
|
|
|
* @returns {Object}
|
2013-05-08 01:19:54 +08:00
|
|
|
*/
|
|
|
|
|
2013-12-04 14:54:16 +08:00
|
|
|
/**
|
|
|
|
* set skew x
|
|
|
|
* @name setSkewX
|
|
|
|
* @param {Number} x
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2013-05-08 01:19:54 +08:00
|
|
|
*/
|
|
|
|
|
2012-03-07 13:45:48 +08:00
|
|
|
/**
|
2013-12-04 14:54:16 +08:00
|
|
|
* get skew x
|
|
|
|
* @name getSkewX
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-04 14:54:16 +08:00
|
|
|
* @returns {Number}
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
2012-10-11 09:48:08 +08:00
|
|
|
|
2013-12-04 14:54:16 +08:00
|
|
|
/**
|
|
|
|
* set skew y
|
|
|
|
* @name setSkewY
|
|
|
|
* @param {Number} y
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2013-05-08 01:19:54 +08:00
|
|
|
*/
|
|
|
|
|
2013-12-04 14:54:16 +08:00
|
|
|
/**
|
2013-05-08 01:19:54 +08:00
|
|
|
* get skew y
|
|
|
|
* @name getSkewY
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-04 14:54:16 +08:00
|
|
|
* @returns {Number}
|
2013-05-08 01:19:54 +08:00
|
|
|
*/
|
|
|
|
|
2013-12-05 01:10:24 +08:00
|
|
|
Kinetic.Factory.addPointGetterSetter(Kinetic.Node, 'offset', 0);
|
2013-05-02 01:56:01 +08:00
|
|
|
|
|
|
|
/**
|
2013-12-29 05:25:15 +08:00
|
|
|
* get/set offset. A node's offset defines the position and rotation point
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-29 05:25:15 +08:00
|
|
|
* @param {Object} offset
|
|
|
|
* @param {Number} offset.x
|
|
|
|
* @param {Number} offset.y
|
|
|
|
* @returns {Object}
|
2013-05-19 01:40:05 +08:00
|
|
|
* @example
|
2013-12-02 15:47:24 +08:00
|
|
|
* // set x and y <br>
|
2013-12-29 05:25:15 +08:00
|
|
|
* shape.offset({<br>
|
2013-05-19 01:40:05 +08:00
|
|
|
* x: 20<br>
|
2013-12-02 15:47:24 +08:00
|
|
|
* y: 10<br>
|
2013-05-19 01:40:05 +08:00
|
|
|
* });<br><br>
|
2013-05-02 01:56:01 +08:00
|
|
|
*/
|
|
|
|
|
2013-12-02 15:47:24 +08:00
|
|
|
/**
|
2013-12-29 05:25:15 +08:00
|
|
|
* get/set offset x
|
|
|
|
* @name offsetX
|
2013-05-16 00:27:22 +08:00
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-02 15:47:24 +08:00
|
|
|
* @param {Number} x
|
2013-12-29 05:25:15 +08:00
|
|
|
* @returns {Integer}
|
2012-11-14 15:22:56 +08:00
|
|
|
*/
|
2013-01-02 15:54:02 +08:00
|
|
|
|
2013-12-02 15:47:24 +08:00
|
|
|
/**
|
2013-12-29 05:25:15 +08:00
|
|
|
* get/set offset y
|
|
|
|
* @name offsetY
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-02 15:47:24 +08:00
|
|
|
* @param {Number} y
|
2013-12-29 05:25:15 +08:00
|
|
|
* @returns {Integer}
|
2013-05-08 01:19:54 +08:00
|
|
|
*/
|
|
|
|
|
2013-12-05 00:15:04 +08:00
|
|
|
Kinetic.Factory.addSetter(Kinetic.Node, 'width', 0);
|
2013-12-14 03:02:07 +08:00
|
|
|
Kinetic.Factory.addOverloadedGetterSetter(Kinetic.Node, 'width');
|
2013-01-03 13:35:51 +08:00
|
|
|
|
2013-01-02 15:54:02 +08:00
|
|
|
/**
|
2013-01-03 13:35:51 +08:00
|
|
|
* set width
|
|
|
|
* @name setWidth
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-01-03 13:35:51 +08:00
|
|
|
* @param {Number} width
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2013-01-02 15:54:02 +08:00
|
|
|
*/
|
|
|
|
|
2013-12-05 00:15:04 +08:00
|
|
|
Kinetic.Factory.addSetter(Kinetic.Node, 'height', 0);
|
2013-12-14 03:02:07 +08:00
|
|
|
Kinetic.Factory.addOverloadedGetterSetter(Kinetic.Node, 'height');
|
2013-05-02 01:56:01 +08:00
|
|
|
|
2013-01-02 15:54:02 +08:00
|
|
|
/**
|
2013-01-03 13:35:51 +08:00
|
|
|
* set height
|
|
|
|
* @name setHeight
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-01-03 13:35:51 +08:00
|
|
|
* @param {Number} height
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2013-01-02 15:54:02 +08:00
|
|
|
*/
|
|
|
|
|
2013-12-10 02:07:08 +08:00
|
|
|
Kinetic.Factory.addGetterSetter(Kinetic.Node, 'listening', 'inherit');
|
2013-05-02 01:56:01 +08:00
|
|
|
|
2013-01-02 15:54:02 +08:00
|
|
|
/**
|
2013-12-11 23:46:49 +08:00
|
|
|
* listen or don't listen to events. Can be "inherit", true, or false. The default is "inherit".
|
2013-01-03 13:35:51 +08:00
|
|
|
* @name setListening
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:07:08 +08:00
|
|
|
* @param {Boolean|String} listening
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2013-01-02 15:54:02 +08:00
|
|
|
*/
|
|
|
|
|
2013-07-22 11:14:09 +08:00
|
|
|
/**
|
2013-12-10 02:07:08 +08:00
|
|
|
* determine if node is listening or not.
|
|
|
|
* @name getListening
|
2013-07-22 11:14:09 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:07:08 +08:00
|
|
|
* @returns {Boolean|String}
|
2013-07-22 11:14:09 +08:00
|
|
|
*/
|
|
|
|
|
2014-01-01 05:04:05 +08:00
|
|
|
|
|
|
|
Kinetic.Factory.addGetterSetter(Kinetic.Node, 'filters');
|
|
|
|
/**
|
|
|
|
* get/set filters
|
|
|
|
* @name filters
|
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
|
|
|
* @param {Array} filters array of filters
|
|
|
|
* @returns {Array}
|
|
|
|
* @example
|
|
|
|
* // set a single filter<br>
|
|
|
|
* node.filters([Kinetic.Filters.Blur]);<br><br>
|
|
|
|
*
|
|
|
|
* // get filters<br>
|
|
|
|
* var filters = node.filters();
|
|
|
|
*/
|
|
|
|
|
2013-12-11 23:46:49 +08:00
|
|
|
Kinetic.Factory.addGetterSetter(Kinetic.Node, 'visible', 'inherit');
|
2013-05-02 01:56:01 +08:00
|
|
|
|
2013-01-02 15:54:02 +08:00
|
|
|
/**
|
2013-12-11 23:46:49 +08:00
|
|
|
* set visible. Can be "inherit", true, or false. The default is "inherit".
|
2013-01-03 13:35:51 +08:00
|
|
|
* @name setVisible
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-01-03 13:35:51 +08:00
|
|
|
* @param {Boolean} visible
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Kinetic.Node}
|
2013-01-02 15:54:02 +08:00
|
|
|
*/
|
2013-01-03 13:35:51 +08:00
|
|
|
|
|
|
|
/**
|
2013-08-11 07:19:33 +08:00
|
|
|
* get visible property for the node. If you need to determine if the node is actually visible,
|
|
|
|
* use the isVisible() method because it takes ancestors into account
|
|
|
|
* @name getVisible
|
2013-05-16 00:27:22 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-10 02:33:31 +08:00
|
|
|
* @returns {Boolean}
|
2013-01-03 13:35:51 +08:00
|
|
|
*/
|
2013-07-22 11:14:09 +08:00
|
|
|
|
2013-12-20 15:29:23 +08:00
|
|
|
Kinetic.Factory.addGetterSetter(Kinetic.Node, 'transformsEnabled', 'all');
|
2013-12-11 15:28:46 +08:00
|
|
|
|
|
|
|
/**
|
2013-12-20 15:29:23 +08:00
|
|
|
* get/set transforms that are enabled. Can be "all", "none", or "position". The default
|
|
|
|
* is "all"
|
|
|
|
* @name transformsEnabled
|
2013-12-11 15:28:46 +08:00
|
|
|
* @method
|
|
|
|
* @memberof Kinetic.Node.prototype
|
2013-12-20 15:29:23 +08:00
|
|
|
* @param {String} enabled
|
|
|
|
* @returns {String}
|
2013-12-11 15:28:46 +08:00
|
|
|
*/
|
|
|
|
|
2013-06-07 13:45:31 +08:00
|
|
|
Kinetic.Collection.mapMethods([
|
2013-07-22 11:14:09 +08:00
|
|
|
'on',
|
|
|
|
'off',
|
|
|
|
'remove',
|
|
|
|
'destroy',
|
|
|
|
'show',
|
|
|
|
'hide',
|
|
|
|
'move',
|
|
|
|
'rotate',
|
|
|
|
'moveToTop',
|
|
|
|
'moveUp',
|
|
|
|
'moveDown',
|
|
|
|
'moveToBottom',
|
|
|
|
'moveTo',
|
|
|
|
'fire',
|
2013-06-07 13:45:31 +08:00
|
|
|
'draw'
|
|
|
|
]);
|
2012-09-26 04:38:36 +08:00
|
|
|
})();
|