2012-04-28 15:07:44 +08:00
|
|
|
///////////////////////////////////////////////////////////////////////
|
2012-03-07 13:45:48 +08:00
|
|
|
// Stage
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
2012-07-09 12:56:52 +08:00
|
|
|
/**
|
2012-08-04 15:23:56 +08:00
|
|
|
* Stage constructor. A stage is used to contain multiple layers
|
2012-07-09 12:56:52 +08:00
|
|
|
* @constructor
|
|
|
|
* @augments Kinetic.Container
|
2012-07-24 13:39:55 +08:00
|
|
|
* @param {Object} config
|
|
|
|
* @param {String|DomElement} config.container Container id or DOM element
|
|
|
|
* @param {Number} config.width
|
|
|
|
* @param {Number} config.height
|
|
|
|
* @param {Number} [config.x]
|
|
|
|
* @param {Number} [config.y]
|
|
|
|
* @param {Boolean} [config.visible]
|
|
|
|
* @param {Boolean} [config.listening] whether or not the node is listening for events
|
|
|
|
* @param {String} [config.id] unique id
|
|
|
|
* @param {String} [config.name] non-unique name
|
2012-08-14 14:06:29 +08:00
|
|
|
* @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1
|
2012-07-24 13:39:55 +08:00
|
|
|
* @param {Object} [config.scale]
|
|
|
|
* @param {Number} [config.scale.x]
|
|
|
|
* @param {Number} [config.scale.y]
|
|
|
|
* @param {Number} [config.rotation] rotation in radians
|
|
|
|
* @param {Number} [config.rotationDeg] rotation in degrees
|
|
|
|
* @param {Object} [config.offset] offsets default position point and rotation point
|
|
|
|
* @param {Number} [config.offset.x]
|
|
|
|
* @param {Number} [config.offset.y]
|
|
|
|
* @param {Boolean} [config.draggable]
|
|
|
|
* @param {String} [config.dragConstraint] can be vertical, horizontal, or none. The default
|
|
|
|
* is none
|
|
|
|
* @param {Object} [config.dragBounds]
|
|
|
|
* @param {Number} [config.dragBounds.top]
|
|
|
|
* @param {Number} [config.dragBounds.right]
|
|
|
|
* @param {Number} [config.dragBounds.bottom]
|
|
|
|
* @param {Number} [config.dragBounds.left]
|
2012-07-09 12:56:52 +08:00
|
|
|
*/
|
2012-08-23 14:13:09 +08:00
|
|
|
Kinetic.Stage = function(config) {
|
2012-08-23 14:35:21 +08:00
|
|
|
this._initStage(config);
|
2012-08-23 14:13:09 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
Kinetic.Stage.prototype = {
|
2012-08-23 14:35:21 +08:00
|
|
|
_initStage: function(config) {
|
2012-07-04 03:07:27 +08:00
|
|
|
this.setDefaultAttrs({
|
|
|
|
width: 400,
|
2012-07-27 14:26:58 +08:00
|
|
|
height: 200
|
2012-07-04 03:07:27 +08:00
|
|
|
});
|
2012-03-23 14:17:52 +08:00
|
|
|
|
2012-07-04 03:07:27 +08:00
|
|
|
/*
|
|
|
|
* if container is a string, assume it's an id for
|
|
|
|
* a DOM element
|
|
|
|
*/
|
|
|
|
if( typeof config.container === 'string') {
|
|
|
|
config.container = document.getElementById(config.container);
|
|
|
|
}
|
2012-04-08 05:39:31 +08:00
|
|
|
|
2012-07-04 03:07:27 +08:00
|
|
|
// call super constructor
|
2012-08-23 14:13:09 +08:00
|
|
|
Kinetic.Container.call(this, config);
|
2012-03-07 13:45:48 +08:00
|
|
|
|
2012-07-04 03:07:27 +08:00
|
|
|
this._setStageDefaultProperties();
|
2012-07-04 13:08:59 +08:00
|
|
|
this._id = Kinetic.Global.idCounter++;
|
2012-07-04 03:07:27 +08:00
|
|
|
this._buildDOM();
|
|
|
|
this._bindContentEvents();
|
2012-06-10 07:13:25 +08:00
|
|
|
|
2012-07-04 03:07:27 +08:00
|
|
|
//change events
|
|
|
|
this.on('widthChange.kinetic', function() {
|
|
|
|
this._resizeDOM();
|
|
|
|
});
|
|
|
|
|
|
|
|
this.on('heightChange.kinetic', function() {
|
|
|
|
this._resizeDOM();
|
|
|
|
});
|
2012-07-04 13:08:59 +08:00
|
|
|
var go = Kinetic.Global;
|
2012-07-04 03:07:27 +08:00
|
|
|
go.stages.push(this);
|
|
|
|
this._addId(this);
|
|
|
|
this._addName(this);
|
2012-08-01 14:23:00 +08:00
|
|
|
|
2012-07-04 03:07:27 +08:00
|
|
|
},
|
2012-03-07 13:45:48 +08:00
|
|
|
/**
|
|
|
|
* draw children
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name draw
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
2012-08-19 13:02:16 +08:00
|
|
|
draw: function() {
|
|
|
|
this._draw();
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* set stage size
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name setSize
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
2012-07-23 14:30:56 +08:00
|
|
|
* @param {Number} width
|
|
|
|
* @param {Number} height
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
2012-06-03 12:27:26 +08:00
|
|
|
setSize: function() {
|
2012-03-07 13:45:48 +08:00
|
|
|
// set stage dimensions
|
2012-07-04 13:08:59 +08:00
|
|
|
var size = Kinetic.Type._getSize(Array.prototype.slice.call(arguments));
|
2012-06-03 12:27:26 +08:00
|
|
|
this.setAttrs(size);
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
2012-03-31 15:08:50 +08:00
|
|
|
/**
|
2012-07-23 14:30:56 +08:00
|
|
|
* get stage size
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name getSize
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
2012-03-31 15:08:50 +08:00
|
|
|
*/
|
|
|
|
getSize: function() {
|
|
|
|
return {
|
2012-04-06 14:48:58 +08:00
|
|
|
width: this.attrs.width,
|
|
|
|
height: this.attrs.height
|
2012-03-31 15:08:50 +08:00
|
|
|
};
|
|
|
|
},
|
2012-03-07 13:45:48 +08:00
|
|
|
/**
|
|
|
|
* clear all layers
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name clear
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
|
|
|
clear: function() {
|
|
|
|
var layers = this.children;
|
|
|
|
for(var n = 0; n < layers.length; n++) {
|
|
|
|
layers[n].clear();
|
|
|
|
}
|
|
|
|
},
|
2012-04-05 13:57:36 +08:00
|
|
|
/**
|
2012-07-23 14:30:56 +08:00
|
|
|
* serialize stage and children as a JSON object and return
|
|
|
|
* the result as a json string
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name toJSON
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
2012-04-05 13:57:36 +08:00
|
|
|
*/
|
|
|
|
toJSON: function() {
|
2012-07-04 13:08:59 +08:00
|
|
|
var type = Kinetic.Type;
|
2012-04-05 15:06:00 +08:00
|
|
|
|
2012-04-05 13:57:36 +08:00
|
|
|
function addNode(node) {
|
|
|
|
var obj = {};
|
2012-05-27 09:31:13 +08:00
|
|
|
|
2012-06-20 10:13:07 +08:00
|
|
|
obj.attrs = {};
|
2012-05-27 09:31:13 +08:00
|
|
|
|
2012-06-20 10:13:07 +08:00
|
|
|
// serialize only attributes that are not function, image, DOM, or objects with methods
|
|
|
|
for(var key in node.attrs) {
|
|
|
|
var val = node.attrs[key];
|
2012-07-04 13:08:59 +08:00
|
|
|
if(!type._isFunction(val) && !type._isElement(val) && !type._hasMethods(val)) {
|
2012-06-20 10:13:07 +08:00
|
|
|
obj.attrs[key] = val;
|
2012-05-27 09:31:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-08 05:39:31 +08:00
|
|
|
obj.nodeType = node.nodeType;
|
|
|
|
obj.shapeType = node.shapeType;
|
2012-04-05 13:57:36 +08:00
|
|
|
|
2012-04-05 15:06:00 +08:00
|
|
|
if(node.nodeType !== 'Shape') {
|
2012-04-06 11:38:12 +08:00
|
|
|
obj.children = [];
|
|
|
|
|
2012-04-05 13:57:36 +08:00
|
|
|
var children = node.getChildren();
|
|
|
|
for(var n = 0; n < children.length; n++) {
|
|
|
|
var child = children[n];
|
2012-04-06 11:38:12 +08:00
|
|
|
obj.children.push(addNode(child));
|
2012-04-05 13:57:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
}
|
2012-04-05 15:06:00 +08:00
|
|
|
return JSON.stringify(addNode(this));
|
|
|
|
},
|
2012-04-29 04:46:54 +08:00
|
|
|
/**
|
|
|
|
* reset stage to default state
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name reset
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
2012-04-29 04:46:54 +08:00
|
|
|
*/
|
|
|
|
reset: function() {
|
|
|
|
// remove children
|
|
|
|
this.removeChildren();
|
|
|
|
|
2012-05-27 09:40:43 +08:00
|
|
|
// defaults
|
|
|
|
this._setStageDefaultProperties();
|
2012-05-27 15:07:36 +08:00
|
|
|
this.setAttrs(this.defaultNodeAttrs);
|
2012-04-29 04:46:54 +08:00
|
|
|
},
|
2012-04-05 15:06:00 +08:00
|
|
|
/**
|
2012-04-08 09:50:53 +08:00
|
|
|
* load stage with JSON string. De-serializtion does not generate custom
|
|
|
|
* shape drawing functions, images, or event handlers (this would make the
|
|
|
|
* serialized object huge). If your app uses custom shapes, images, and
|
|
|
|
* event handlers (it probably does), then you need to select the appropriate
|
|
|
|
* shapes after loading the stage and set these properties via on(), setDrawFunc(),
|
|
|
|
* and setImage()
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name load
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
2012-04-08 09:50:53 +08:00
|
|
|
* @param {String} JSON string
|
2012-04-05 15:06:00 +08:00
|
|
|
*/
|
2012-04-08 09:40:44 +08:00
|
|
|
load: function(json) {
|
2012-04-29 04:57:43 +08:00
|
|
|
this.reset();
|
|
|
|
|
2012-04-05 15:06:00 +08:00
|
|
|
function loadNode(node, obj) {
|
2012-04-06 11:38:12 +08:00
|
|
|
var children = obj.children;
|
2012-04-05 15:06:00 +08:00
|
|
|
if(children !== undefined) {
|
|
|
|
for(var n = 0; n < children.length; n++) {
|
|
|
|
var child = children[n];
|
|
|
|
var type;
|
|
|
|
|
|
|
|
// determine type
|
2012-04-08 05:39:31 +08:00
|
|
|
if(child.nodeType === 'Shape') {
|
2012-04-05 15:06:00 +08:00
|
|
|
// add custom shape
|
2012-04-08 05:39:31 +08:00
|
|
|
if(child.shapeType === undefined) {
|
2012-04-05 15:06:00 +08:00
|
|
|
type = 'Shape';
|
|
|
|
}
|
|
|
|
// add standard shape
|
|
|
|
else {
|
2012-04-08 05:39:31 +08:00
|
|
|
type = child.shapeType;
|
2012-04-05 15:06:00 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2012-04-08 05:39:31 +08:00
|
|
|
type = child.nodeType;
|
2012-04-05 15:06:00 +08:00
|
|
|
}
|
|
|
|
|
2012-04-06 11:38:12 +08:00
|
|
|
var no = new Kinetic[type](child.attrs);
|
2012-04-05 15:06:00 +08:00
|
|
|
node.add(no);
|
|
|
|
loadNode(no, child);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-04-06 11:38:12 +08:00
|
|
|
var obj = JSON.parse(json);
|
|
|
|
|
|
|
|
// copy over stage properties
|
2012-04-08 05:39:31 +08:00
|
|
|
this.attrs = obj.attrs;
|
2012-04-06 11:38:12 +08:00
|
|
|
|
|
|
|
loadNode(this, obj);
|
2012-04-05 15:06:00 +08:00
|
|
|
this.draw();
|
2012-04-05 13:57:36 +08:00
|
|
|
},
|
2012-03-07 13:45:48 +08:00
|
|
|
/**
|
|
|
|
* get mouse position for desktop apps
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name getMousePosition
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
* @param {Event} evt
|
|
|
|
*/
|
|
|
|
getMousePosition: function(evt) {
|
|
|
|
return this.mousePos;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get touch position for mobile apps
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name getTouchPosition
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
* @param {Event} evt
|
|
|
|
*/
|
|
|
|
getTouchPosition: function(evt) {
|
|
|
|
return this.touchPos;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get user position (mouse position or touch position)
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name getUserPosition
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
* @param {Event} evt
|
|
|
|
*/
|
|
|
|
getUserPosition: function(evt) {
|
|
|
|
return this.getTouchPosition() || this.getMousePosition();
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get container DOM element
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name getContainer
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
|
|
|
getContainer: function() {
|
2012-05-20 12:14:04 +08:00
|
|
|
return this.attrs.container;
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get stage
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name getStage
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
|
|
|
getStage: function() {
|
|
|
|
return this;
|
|
|
|
},
|
2012-04-28 15:07:44 +08:00
|
|
|
/**
|
|
|
|
* get stage DOM node, which is a div element
|
2012-07-23 14:30:56 +08:00
|
|
|
* with the class name "kineticjs-content"
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name getDOM
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
2012-04-28 15:07:44 +08:00
|
|
|
*/
|
|
|
|
getDOM: function() {
|
|
|
|
return this.content;
|
|
|
|
},
|
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-16 11:12:18 +08:00
|
|
|
* Creates a composite data URL and requires a callback because the stage
|
|
|
|
* toDataURL method is asynchronous. 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). Note that this method works
|
|
|
|
* differently from toDataURL() for other nodes because it generates an absolute dataURL
|
|
|
|
* based on what's draw onto the canvases for each layer, rather than drawing
|
|
|
|
* the current state of each node
|
toDataURL() is now synchronous, and works with all nodes, including the stage, layers, groups, and shapes. This also sets things up nicely for node caching. You can now cache anything, including the whole stage, layers, groups, or shapes, manifested as Kinetic Images that were instantiated with data urls
2012-07-15 09:10:37 +08:00
|
|
|
* @name toDataURL
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
2012-07-22 06:38:25 +08:00
|
|
|
* @param {Object} config
|
2012-07-23 15:00:22 +08:00
|
|
|
* @param {Function} config.callback since the stage toDataURL() method is asynchronous,
|
2012-07-23 14:30:56 +08:00
|
|
|
* the data url string will be passed into the callback
|
|
|
|
* @param {String} [config.mimeType] mime type. can be "image/png" or "image/jpeg".
|
|
|
|
* "image/png" is the default
|
|
|
|
* @param {Number} [config.width] data url image width
|
|
|
|
* @param {Number} [config.height] data url image height
|
|
|
|
* @param {Number} [config.quality] jpeg quality. If using an "image/jpeg" mimeType,
|
|
|
|
* you can specify the quality from 0 to 1, where 0 is very poor quality and 1
|
|
|
|
* is very high quality
|
toDataURL() is now synchronous, and works with all nodes, including the stage, layers, groups, and shapes. This also sets things up nicely for node caching. You can now cache anything, including the whole stage, layers, groups, or shapes, manifested as Kinetic Images that were instantiated with data urls
2012-07-15 09:10:37 +08:00
|
|
|
*/
|
2012-07-22 06:38:25 +08:00
|
|
|
toDataURL: function(config) {
|
2012-07-23 14:30:56 +08:00
|
|
|
var mimeType = config && config.mimeType ? config.mimeType : null;
|
2012-07-22 06:38:25 +08:00
|
|
|
var quality = config && config.quality ? config.quality : null;
|
2012-07-22 04:29:22 +08:00
|
|
|
/*
|
|
|
|
* need to create a canvas element rather than using the buffer canvas
|
|
|
|
* because this method is asynchonous which means that other parts of the
|
|
|
|
* code could modify the buffer canvas before it's finished
|
|
|
|
*/
|
2012-07-22 06:38:25 +08:00
|
|
|
var width = config && config.width ? config.width : this.attrs.width;
|
|
|
|
var height = config && config.height ? config.height : this.attrs.height;
|
|
|
|
var canvas = new Kinetic.Canvas(width, height);
|
2012-07-19 14:28:45 +08:00
|
|
|
var context = canvas.getContext();
|
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
|
|
|
var layers = this.children;
|
2012-07-16 11:12:18 +08:00
|
|
|
|
|
|
|
function drawLayer(n) {
|
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
|
|
|
var layer = layers[n];
|
2012-08-10 10:39:34 +08:00
|
|
|
var layerUrl = layer.getCanvas().toDataURL();
|
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
|
|
|
var imageObj = new Image();
|
2012-07-16 11:12:18 +08:00
|
|
|
imageObj.onload = function() {
|
2012-07-19 14:28:45 +08:00
|
|
|
context.drawImage(imageObj, 0, 0);
|
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-16 11:12:18 +08:00
|
|
|
if(n < layers.length - 1) {
|
|
|
|
drawLayer(n + 1);
|
|
|
|
}
|
|
|
|
else {
|
2012-07-22 06:38:25 +08:00
|
|
|
config.callback(canvas.toDataURL(mimeType, quality));
|
2012-07-16 11:12:18 +08:00
|
|
|
}
|
|
|
|
};
|
2012-07-22 04:29:22 +08:00
|
|
|
imageObj.src = layerUrl;
|
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-16 11:12:18 +08:00
|
|
|
drawLayer(0);
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* converts stage into an image. Since the stage toImage() method
|
|
|
|
* is asynchronous, a callback function is required
|
|
|
|
* @name toImage
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
2012-07-22 06:38:25 +08:00
|
|
|
* @param {Object} config
|
2012-07-23 14:30:56 +08:00
|
|
|
* @param {Function} callback since the toImage() method is asynchonrous, the
|
|
|
|
* resulting image object is passed into the callback function
|
|
|
|
* @param {String} [config.mimeType] mime type. can be "image/png" or "image/jpeg".
|
|
|
|
* "image/png" is the default
|
|
|
|
* @param {Number} [config.width] data url image width
|
|
|
|
* @param {Number} [config.height] data url image height
|
|
|
|
* @param {Number} [config.quality] jpeg quality. If using an "image/jpeg" mimeType,
|
|
|
|
* you can specify the quality from 0 to 1, where 0 is very poor quality and 1
|
|
|
|
* is very high quality
|
2012-07-16 11:12:18 +08:00
|
|
|
*/
|
2012-07-22 06:38:25 +08:00
|
|
|
toImage: function(config) {
|
|
|
|
this.toDataURL({
|
|
|
|
callback: function(dataUrl) {
|
|
|
|
Kinetic.Type._getImage(dataUrl, function(img) {
|
|
|
|
config.callback(img);
|
|
|
|
});
|
|
|
|
}
|
2012-07-16 11:12:18 +08:00
|
|
|
});
|
toDataURL() is now synchronous, and works with all nodes, including the stage, layers, groups, and shapes. This also sets things up nicely for node caching. You can now cache anything, including the whole stage, layers, groups, or shapes, manifested as Kinetic Images that were instantiated with data urls
2012-07-15 09:10:37 +08:00
|
|
|
},
|
2012-08-17 14:03:28 +08:00
|
|
|
/**
|
|
|
|
* get intersection object that contains shape and pixel data
|
|
|
|
* @name getIntersection
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
|
|
|
* @param {Object} pos point object
|
|
|
|
*/
|
|
|
|
getIntersection: function(pos) {
|
|
|
|
var shape;
|
|
|
|
var layers = this.getChildren();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* traverse through layers from top to bottom and look
|
|
|
|
* for hit detection
|
|
|
|
*/
|
|
|
|
for(var n = layers.length - 1; n >= 0; n--) {
|
|
|
|
var layer = layers[n];
|
|
|
|
var p = layer.bufferCanvas.context.getImageData(pos.x, pos.y, 1, 1).data;
|
|
|
|
// this indicates that a buffer pixel may have been found
|
|
|
|
if(p[3] === 255) {
|
|
|
|
var colorKey = Kinetic.Type._rgbToHex(p[0], p[1], p[2]);
|
|
|
|
shape = Kinetic.Global.shapes[colorKey];
|
|
|
|
return {
|
|
|
|
shape: shape,
|
2012-08-19 13:42:37 +08:00
|
|
|
pixel: p
|
2012-08-17 14:03:28 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
// if no shape mapped to that pixel, return pixel array
|
|
|
|
else if(p[0] > 0 || p[1] > 0 || p[2] > 0 || p[3] > 0) {
|
|
|
|
return {
|
2012-08-19 13:42:37 +08:00
|
|
|
pixel: p
|
2012-08-17 14:03:28 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
},
|
2012-06-09 12:56:33 +08:00
|
|
|
_resizeDOM: function() {
|
|
|
|
var width = this.attrs.width;
|
|
|
|
var height = this.attrs.height;
|
|
|
|
|
|
|
|
// set content dimensions
|
|
|
|
this.content.style.width = width + 'px';
|
|
|
|
this.content.style.height = height + 'px';
|
|
|
|
|
2012-07-19 14:28:45 +08:00
|
|
|
this.bufferCanvas.setSize(width, height);
|
2012-06-09 12:56:33 +08:00
|
|
|
// set user defined layer dimensions
|
|
|
|
var layers = this.children;
|
|
|
|
for(var n = 0; n < layers.length; n++) {
|
|
|
|
var layer = layers[n];
|
2012-07-19 14:28:45 +08:00
|
|
|
layer.getCanvas().setSize(width, height);
|
2012-08-12 07:22:01 +08:00
|
|
|
layer.bufferCanvas.setSize(width, height);
|
2012-06-09 12:56:33 +08:00
|
|
|
layer.draw();
|
|
|
|
}
|
|
|
|
},
|
2012-05-27 07:49:58 +08:00
|
|
|
/**
|
|
|
|
* remove layer from stage
|
|
|
|
* @param {Layer} layer
|
|
|
|
*/
|
|
|
|
_remove: function(layer) {
|
|
|
|
/*
|
|
|
|
* remove canvas DOM from the document if
|
|
|
|
* it exists
|
|
|
|
*/
|
|
|
|
try {
|
2012-07-29 13:16:29 +08:00
|
|
|
this.content.removeChild(layer.canvas.element);
|
2012-05-27 07:49:58 +08:00
|
|
|
}
|
|
|
|
catch(e) {
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* add layer to stage
|
|
|
|
* @param {Layer} layer
|
|
|
|
*/
|
|
|
|
_add: function(layer) {
|
2012-07-19 14:28:45 +08:00
|
|
|
layer.canvas.setSize(this.attrs.width, this.attrs.height);
|
2012-08-12 07:22:01 +08:00
|
|
|
layer.bufferCanvas.setSize(this.attrs.width, this.attrs.height);
|
2012-05-27 07:49:58 +08:00
|
|
|
|
|
|
|
// draw layer and append canvas to container
|
|
|
|
layer.draw();
|
2012-07-19 14:28:45 +08:00
|
|
|
this.content.appendChild(layer.canvas.element);
|
2012-05-27 07:49:58 +08:00
|
|
|
},
|
2012-08-12 14:14:49 +08:00
|
|
|
_setUserPosition: function(evt) {
|
|
|
|
if(!evt) {
|
|
|
|
evt = window.event;
|
2012-03-19 02:24:57 +08:00
|
|
|
}
|
2012-08-12 14:14:49 +08:00
|
|
|
this._setMousePosition(evt);
|
|
|
|
this._setTouchPosition(evt);
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* begin listening for events by adding event handlers
|
|
|
|
* to the container
|
|
|
|
*/
|
2012-06-10 07:13:25 +08:00
|
|
|
_bindContentEvents: function() {
|
2012-07-04 13:08:59 +08:00
|
|
|
var go = Kinetic.Global;
|
2012-03-07 13:45:48 +08:00
|
|
|
var that = this;
|
2012-08-12 14:14:49 +08:00
|
|
|
var events = ['mousedown', 'mousemove', 'mouseup', 'mouseout', 'touchstart', 'touchmove', 'touchend'];
|
2012-06-15 14:46:52 +08:00
|
|
|
|
|
|
|
for(var n = 0; n < events.length; n++) {
|
|
|
|
var pubEvent = events[n];
|
|
|
|
// induce scope
|
|
|
|
( function() {
|
2012-06-16 02:47:55 +08:00
|
|
|
var event = pubEvent;
|
2012-06-15 14:46:52 +08:00
|
|
|
that.content.addEventListener(event, function(evt) {
|
2012-06-16 02:47:55 +08:00
|
|
|
that['_' + event](evt);
|
2012-06-15 14:46:52 +08:00
|
|
|
}, false);
|
|
|
|
}());
|
|
|
|
}
|
|
|
|
},
|
2012-06-16 02:47:55 +08:00
|
|
|
_mouseout: function(evt) {
|
2012-08-17 13:03:39 +08:00
|
|
|
this._setUserPosition(evt);
|
2012-08-20 14:46:06 +08:00
|
|
|
var go = Kinetic.Global;
|
2012-06-15 14:46:52 +08:00
|
|
|
// if there's a current target shape, run mouseout handlers
|
|
|
|
var targetShape = this.targetShape;
|
2012-08-20 14:46:06 +08:00
|
|
|
if(targetShape && !go.drag.moving) {
|
2012-06-15 14:46:52 +08:00
|
|
|
targetShape._handleEvent('mouseout', evt);
|
2012-08-12 14:14:49 +08:00
|
|
|
this.targetShape = null;
|
2012-06-15 14:46:52 +08:00
|
|
|
}
|
|
|
|
this.mousePos = undefined;
|
2012-06-19 08:56:12 +08:00
|
|
|
|
2012-06-16 02:47:55 +08:00
|
|
|
// end drag and drop
|
|
|
|
this._endDrag(evt);
|
2012-06-15 14:46:52 +08:00
|
|
|
},
|
2012-06-16 02:47:55 +08:00
|
|
|
_mousemove: function(evt) {
|
2012-08-17 14:03:28 +08:00
|
|
|
this._setUserPosition(evt);
|
2012-08-12 14:14:49 +08:00
|
|
|
var go = Kinetic.Global;
|
2012-08-17 14:03:28 +08:00
|
|
|
var obj = this.getIntersection(this.getUserPosition());
|
|
|
|
|
|
|
|
if(obj) {
|
|
|
|
var shape = obj.shape;
|
|
|
|
if(shape) {
|
2012-08-19 13:42:37 +08:00
|
|
|
if(!go.drag.moving && obj.pixel[3] === 255 && (!this.targetShape || this.targetShape._id !== shape._id)) {
|
2012-08-17 14:03:28 +08:00
|
|
|
if(this.targetShape) {
|
|
|
|
this.targetShape._handleEvent('mouseout', evt, shape);
|
|
|
|
}
|
|
|
|
shape._handleEvent('mouseover', evt, this.targetShape);
|
|
|
|
this.targetShape = shape;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
shape._handleEvent('mousemove', evt);
|
2012-08-12 14:14:49 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* if no shape was detected, clear target shape and try
|
|
|
|
* to run mouseout from previous target shape
|
|
|
|
*/
|
2012-08-20 14:46:06 +08:00
|
|
|
else if(this.targetShape && !go.drag.moving) {
|
2012-08-12 14:14:49 +08:00
|
|
|
this.targetShape._handleEvent('mouseout', evt);
|
|
|
|
this.targetShape = null;
|
|
|
|
}
|
2012-06-16 02:47:55 +08:00
|
|
|
|
|
|
|
// start drag and drop
|
|
|
|
this._startDrag(evt);
|
2012-06-15 14:46:52 +08:00
|
|
|
},
|
2012-06-16 02:47:55 +08:00
|
|
|
_mousedown: function(evt) {
|
2012-08-17 14:03:28 +08:00
|
|
|
this._setUserPosition(evt);
|
|
|
|
var obj = this.getIntersection(this.getUserPosition());
|
|
|
|
if(obj && obj.shape) {
|
|
|
|
var shape = obj.shape;
|
2012-08-12 14:14:49 +08:00
|
|
|
this.clickStart = true;
|
|
|
|
shape._handleEvent('mousedown', evt);
|
|
|
|
}
|
2012-06-15 14:46:52 +08:00
|
|
|
|
|
|
|
//init stage drag and drop
|
|
|
|
if(this.attrs.draggable) {
|
|
|
|
this._initDrag();
|
|
|
|
}
|
|
|
|
},
|
2012-06-16 02:47:55 +08:00
|
|
|
_mouseup: function(evt) {
|
2012-08-17 14:03:28 +08:00
|
|
|
this._setUserPosition(evt);
|
2012-08-12 14:14:49 +08:00
|
|
|
var go = Kinetic.Global;
|
2012-08-17 14:03:28 +08:00
|
|
|
var obj = this.getIntersection(this.getUserPosition());
|
2012-08-12 14:14:49 +08:00
|
|
|
var that = this;
|
2012-08-17 14:03:28 +08:00
|
|
|
if(obj && obj.shape) {
|
|
|
|
var shape = obj.shape;
|
2012-08-12 14:14:49 +08:00
|
|
|
shape._handleEvent('mouseup', evt);
|
|
|
|
|
|
|
|
// detect if click or double click occurred
|
|
|
|
if(this.clickStart) {
|
|
|
|
/*
|
|
|
|
* if dragging and dropping, don't fire click or dbl click
|
|
|
|
* event
|
|
|
|
*/
|
|
|
|
if((!go.drag.moving) || !go.drag.node) {
|
|
|
|
shape._handleEvent('click', evt);
|
|
|
|
|
|
|
|
if(this.inDoubleClickWindow) {
|
|
|
|
shape._handleEvent('dblclick', evt);
|
|
|
|
}
|
|
|
|
this.inDoubleClickWindow = true;
|
|
|
|
setTimeout(function() {
|
|
|
|
that.inDoubleClickWindow = false;
|
|
|
|
}, this.dblClickWindow);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-06-15 14:46:52 +08:00
|
|
|
this.clickStart = false;
|
2012-06-19 08:56:12 +08:00
|
|
|
|
2012-06-16 02:47:55 +08:00
|
|
|
// end drag and drop
|
|
|
|
this._endDrag(evt);
|
2012-06-15 14:46:52 +08:00
|
|
|
},
|
2012-06-16 02:47:55 +08:00
|
|
|
_touchstart: function(evt) {
|
2012-08-17 14:03:28 +08:00
|
|
|
this._setUserPosition(evt);
|
2012-06-15 14:46:52 +08:00
|
|
|
evt.preventDefault();
|
2012-08-17 14:03:28 +08:00
|
|
|
var obj = this.getIntersection(this.getUserPosition());
|
|
|
|
|
|
|
|
if(obj && obj.shape) {
|
|
|
|
var shape = obj.shape;
|
2012-08-12 14:14:49 +08:00
|
|
|
this.tapStart = true;
|
|
|
|
shape._handleEvent('touchstart', evt);
|
|
|
|
}
|
|
|
|
|
2012-06-10 02:24:35 +08:00
|
|
|
/*
|
2012-06-15 14:46:52 +08:00
|
|
|
* init stage drag and drop
|
2012-06-10 02:24:35 +08:00
|
|
|
*/
|
2012-06-15 14:46:52 +08:00
|
|
|
if(this.attrs.draggable) {
|
|
|
|
this._initDrag();
|
|
|
|
}
|
|
|
|
},
|
2012-06-16 02:47:55 +08:00
|
|
|
_touchend: function(evt) {
|
2012-08-17 14:03:28 +08:00
|
|
|
this._setUserPosition(evt);
|
2012-08-12 14:14:49 +08:00
|
|
|
var go = Kinetic.Global;
|
2012-08-17 14:03:28 +08:00
|
|
|
var obj = this.getIntersection(this.getUserPosition());
|
2012-08-12 14:14:49 +08:00
|
|
|
var that = this;
|
2012-08-17 14:03:28 +08:00
|
|
|
if(obj && obj.shape) {
|
|
|
|
var shape = obj.shape;
|
2012-08-12 14:14:49 +08:00
|
|
|
shape._handleEvent('touchend', evt);
|
|
|
|
|
|
|
|
// detect if tap or double tap occurred
|
|
|
|
if(this.tapStart) {
|
|
|
|
/*
|
|
|
|
* if dragging and dropping, don't fire tap or dbltap
|
|
|
|
* event
|
|
|
|
*/
|
|
|
|
if((!go.drag.moving) || !go.drag.node) {
|
|
|
|
shape._handleEvent('tap', evt);
|
|
|
|
|
|
|
|
if(this.inDoubleClickWindow) {
|
|
|
|
shape._handleEvent('dbltap', evt);
|
|
|
|
}
|
|
|
|
this.inDoubleClickWindow = true;
|
|
|
|
setTimeout(function() {
|
|
|
|
that.inDoubleClickWindow = false;
|
|
|
|
}, this.dblClickWindow);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-15 14:46:52 +08:00
|
|
|
this.tapStart = false;
|
2012-06-19 08:56:12 +08:00
|
|
|
|
2012-06-16 02:47:55 +08:00
|
|
|
// end drag and drop
|
|
|
|
this._endDrag(evt);
|
2012-06-15 14:46:52 +08:00
|
|
|
},
|
2012-06-16 02:47:55 +08:00
|
|
|
_touchmove: function(evt) {
|
2012-08-17 14:03:28 +08:00
|
|
|
this._setUserPosition(evt);
|
2012-07-27 14:26:58 +08:00
|
|
|
evt.preventDefault();
|
2012-08-17 14:03:28 +08:00
|
|
|
var obj = this.getIntersection(this.getUserPosition());
|
|
|
|
if(obj && obj.shape) {
|
|
|
|
var shape = obj.shape;
|
2012-08-12 14:14:49 +08:00
|
|
|
shape._handleEvent('touchmove', evt);
|
|
|
|
}
|
2012-06-16 02:47:55 +08:00
|
|
|
|
|
|
|
// start drag and drop
|
|
|
|
this._startDrag(evt);
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* set mouse positon for desktop apps
|
|
|
|
* @param {Event} evt
|
|
|
|
*/
|
|
|
|
_setMousePosition: function(evt) {
|
2012-04-02 10:38:30 +08:00
|
|
|
var mouseX = evt.offsetX || (evt.clientX - this._getContentPosition().left + window.pageXOffset);
|
|
|
|
var mouseY = evt.offsetY || (evt.clientY - this._getContentPosition().top + window.pageYOffset);
|
2012-03-07 13:45:48 +08:00
|
|
|
this.mousePos = {
|
|
|
|
x: mouseX,
|
|
|
|
y: mouseY
|
|
|
|
};
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* set touch position for mobile apps
|
|
|
|
* @param {Event} evt
|
|
|
|
*/
|
|
|
|
_setTouchPosition: function(evt) {
|
|
|
|
if(evt.touches !== undefined && evt.touches.length === 1) {// Only deal with
|
|
|
|
// one finger
|
|
|
|
var touch = evt.touches[0];
|
|
|
|
// Get the information for finger #1
|
2012-04-02 10:38:30 +08:00
|
|
|
var touchX = touch.clientX - this._getContentPosition().left + window.pageXOffset;
|
|
|
|
var touchY = touch.clientY - this._getContentPosition().top + window.pageYOffset;
|
2012-03-07 13:45:48 +08:00
|
|
|
|
|
|
|
this.touchPos = {
|
|
|
|
x: touchX,
|
|
|
|
y: touchY
|
|
|
|
};
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* get container position
|
|
|
|
*/
|
2012-04-02 10:38:30 +08:00
|
|
|
_getContentPosition: function() {
|
2012-07-19 14:53:28 +08:00
|
|
|
var rect = this.content.getBoundingClientRect(), root = document.documentElement;
|
2012-03-07 13:45:48 +08:00
|
|
|
return {
|
2012-07-17 18:14:49 +08:00
|
|
|
top: rect.top + root.scrollTop,
|
|
|
|
left: rect.left + root.scrollLeft
|
2012-03-07 13:45:48 +08:00
|
|
|
};
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* end drag and drop
|
|
|
|
*/
|
|
|
|
_endDrag: function(evt) {
|
2012-07-04 13:08:59 +08:00
|
|
|
var go = Kinetic.Global;
|
2012-08-09 15:01:21 +08:00
|
|
|
var node = go.drag.node;
|
|
|
|
if(node) {
|
2012-08-11 13:33:22 +08:00
|
|
|
if(node.nodeType === 'Stage') {
|
|
|
|
node.draw();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
node.getLayer().draw();
|
|
|
|
}
|
|
|
|
|
2012-06-20 08:06:31 +08:00
|
|
|
// handle dragend
|
2012-03-07 13:45:48 +08:00
|
|
|
if(go.drag.moving) {
|
|
|
|
go.drag.moving = false;
|
2012-08-09 15:01:21 +08:00
|
|
|
node._handleEvent('dragend', evt);
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
|
|
|
}
|
2012-08-09 15:01:21 +08:00
|
|
|
go.drag.node = null;
|
|
|
|
this.dragAnim.stop();
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
|
|
|
/**
|
2012-06-16 02:47:55 +08:00
|
|
|
* start drag and drop
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
2012-06-16 02:47:55 +08:00
|
|
|
_startDrag: function(evt) {
|
2012-03-07 13:45:48 +08:00
|
|
|
var that = this;
|
2012-07-04 13:08:59 +08:00
|
|
|
var go = Kinetic.Global;
|
2012-06-16 02:47:55 +08:00
|
|
|
var node = go.drag.node;
|
|
|
|
|
|
|
|
if(node) {
|
2012-08-09 15:01:21 +08:00
|
|
|
var pos = that.getUserPosition();
|
|
|
|
var dc = node.attrs.dragConstraint;
|
|
|
|
var db = node.attrs.dragBounds;
|
|
|
|
var lastNodePos = {
|
|
|
|
x: node.attrs.x,
|
|
|
|
y: node.attrs.y
|
|
|
|
};
|
2012-04-15 07:27:00 +08:00
|
|
|
|
2012-08-09 15:01:21 +08:00
|
|
|
// default
|
|
|
|
var newNodePos = {
|
|
|
|
x: pos.x - go.drag.offset.x,
|
|
|
|
y: pos.y - go.drag.offset.y
|
|
|
|
};
|
2012-03-25 11:52:17 +08:00
|
|
|
|
2012-08-09 15:01:21 +08:00
|
|
|
// bounds overrides
|
|
|
|
if(db.left !== undefined && newNodePos.x < db.left) {
|
|
|
|
newNodePos.x = db.left;
|
|
|
|
}
|
|
|
|
if(db.right !== undefined && newNodePos.x > db.right) {
|
|
|
|
newNodePos.x = db.right;
|
|
|
|
}
|
|
|
|
if(db.top !== undefined && newNodePos.y < db.top) {
|
|
|
|
newNodePos.y = db.top;
|
|
|
|
}
|
|
|
|
if(db.bottom !== undefined && newNodePos.y > db.bottom) {
|
|
|
|
newNodePos.y = db.bottom;
|
|
|
|
}
|
2012-03-07 13:45:48 +08:00
|
|
|
|
2012-08-09 15:01:21 +08:00
|
|
|
node.setAbsolutePosition(newNodePos);
|
2012-03-26 03:45:46 +08:00
|
|
|
|
2012-08-09 15:01:21 +08:00
|
|
|
// constraint overrides
|
|
|
|
if(dc === 'horizontal') {
|
|
|
|
node.attrs.y = lastNodePos.y;
|
|
|
|
}
|
|
|
|
else if(dc === 'vertical') {
|
|
|
|
node.attrs.x = lastNodePos.x;
|
|
|
|
}
|
2012-05-27 15:07:36 +08:00
|
|
|
|
2012-08-09 15:01:21 +08:00
|
|
|
if(!go.drag.moving) {
|
|
|
|
go.drag.moving = true;
|
|
|
|
// execute dragstart events if defined
|
|
|
|
go.drag.node._handleEvent('dragstart', evt);
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
2012-08-09 15:01:21 +08:00
|
|
|
|
|
|
|
// execute user defined ondragmove if defined
|
|
|
|
go.drag.node._handleEvent('dragmove', evt);
|
2012-06-16 02:47:55 +08:00
|
|
|
}
|
2012-03-18 01:48:25 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* build dom
|
|
|
|
*/
|
|
|
|
_buildDOM: function() {
|
|
|
|
// content
|
2012-06-10 02:24:35 +08:00
|
|
|
this.content = document.createElement('div');
|
2012-03-18 01:48:25 +08:00
|
|
|
this.content.style.position = 'relative';
|
|
|
|
this.content.style.display = 'inline-block';
|
|
|
|
this.content.className = 'kineticjs-content';
|
2012-05-20 12:14:04 +08:00
|
|
|
this.attrs.container.appendChild(this.content);
|
2012-03-18 01:48:25 +08:00
|
|
|
|
2012-07-19 14:28:45 +08:00
|
|
|
this.bufferCanvas = new Kinetic.Canvas({
|
|
|
|
width: this.attrs.width,
|
|
|
|
height: this.attrs.height
|
2012-04-02 10:38:30 +08:00
|
|
|
});
|
2012-08-12 07:22:01 +08:00
|
|
|
|
2012-06-10 07:13:25 +08:00
|
|
|
this._resizeDOM();
|
2012-04-09 02:01:31 +08:00
|
|
|
},
|
|
|
|
_addId: function(node) {
|
|
|
|
if(node.attrs.id !== undefined) {
|
|
|
|
this.ids[node.attrs.id] = node;
|
|
|
|
}
|
|
|
|
},
|
2012-07-14 12:24:38 +08:00
|
|
|
_removeId: function(id) {
|
|
|
|
if(id !== undefined) {
|
|
|
|
delete this.ids[id];
|
2012-04-09 08:37:49 +08:00
|
|
|
}
|
2012-04-09 02:01:31 +08:00
|
|
|
},
|
|
|
|
_addName: function(node) {
|
|
|
|
var name = node.attrs.name;
|
|
|
|
if(name !== undefined) {
|
|
|
|
if(this.names[name] === undefined) {
|
|
|
|
this.names[name] = [];
|
|
|
|
}
|
|
|
|
this.names[name].push(node);
|
|
|
|
}
|
|
|
|
},
|
2012-07-14 12:24:38 +08:00
|
|
|
_removeName: function(name, _id) {
|
|
|
|
if(name !== undefined) {
|
|
|
|
var nodes = this.names[name];
|
2012-04-09 08:37:49 +08:00
|
|
|
if(nodes !== undefined) {
|
|
|
|
for(var n = 0; n < nodes.length; n++) {
|
|
|
|
var no = nodes[n];
|
2012-07-14 12:24:38 +08:00
|
|
|
if(no._id === _id) {
|
2012-04-09 08:37:49 +08:00
|
|
|
nodes.splice(n, 1);
|
|
|
|
}
|
|
|
|
}
|
2012-06-02 15:39:17 +08:00
|
|
|
if(nodes.length === 0) {
|
2012-07-14 12:24:38 +08:00
|
|
|
delete this.names[name];
|
2012-06-02 15:39:17 +08:00
|
|
|
}
|
2012-04-09 08:37:49 +08:00
|
|
|
}
|
|
|
|
}
|
2012-04-28 15:07:44 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* bind event listener to container DOM element
|
|
|
|
* @param {String} typesStr
|
|
|
|
* @param {function} handler
|
|
|
|
*/
|
|
|
|
_onContent: function(typesStr, handler) {
|
|
|
|
var types = typesStr.split(' ');
|
|
|
|
for(var n = 0; n < types.length; n++) {
|
|
|
|
var baseEvent = types[n];
|
|
|
|
this.content.addEventListener(baseEvent, handler, false);
|
|
|
|
}
|
2012-04-29 04:46:54 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* set defaults
|
|
|
|
*/
|
2012-05-27 09:40:43 +08:00
|
|
|
_setStageDefaultProperties: function() {
|
2012-06-10 02:24:35 +08:00
|
|
|
this.nodeType = 'Stage';
|
|
|
|
this.dblClickWindow = 400;
|
2012-08-12 14:14:49 +08:00
|
|
|
this.targetShape = null;
|
2012-04-29 04:46:54 +08:00
|
|
|
this.mousePos = undefined;
|
2012-06-01 15:44:38 +08:00
|
|
|
this.clickStart = false;
|
2012-04-29 04:46:54 +08:00
|
|
|
this.touchPos = undefined;
|
2012-06-01 15:44:38 +08:00
|
|
|
this.tapStart = false;
|
2012-04-29 04:46:54 +08:00
|
|
|
|
|
|
|
this.ids = {};
|
|
|
|
this.names = {};
|
2012-08-11 13:33:22 +08:00
|
|
|
this.dragAnim = new Kinetic.Animation();
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
2012-08-23 14:13:09 +08:00
|
|
|
};
|
|
|
|
Kinetic.Global.extend(Kinetic.Stage, Kinetic.Container);
|
2012-06-11 04:07:09 +08:00
|
|
|
|
2012-07-04 03:07:27 +08:00
|
|
|
// add getters and setters
|
2012-07-27 14:26:58 +08:00
|
|
|
Kinetic.Node.addGettersSetters(Kinetic.Stage, ['width', 'height']);
|
2012-06-11 04:07:09 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* get width
|
2012-06-14 17:19:51 +08:00
|
|
|
* @name getWidth
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
2012-06-11 04:07:09 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* get height
|
2012-06-14 17:19:51 +08:00
|
|
|
* @name getHeight
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
2012-06-11 04:07:09 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* set width
|
2012-06-14 17:19:51 +08:00
|
|
|
* @name setWidth
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
2012-06-11 04:07:09 +08:00
|
|
|
* @param {Number} width
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* set height
|
2012-06-14 17:19:51 +08:00
|
|
|
* @name setHeight
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
2012-06-11 04:07:09 +08:00
|
|
|
* @param {Number} height
|
|
|
|
*/
|