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
|
|
|
/**
|
|
|
|
* Stage constructor. A stage is used to contain multiple layers and handle
|
|
|
|
* animations
|
|
|
|
* @constructor
|
|
|
|
* @augments Kinetic.Container
|
|
|
|
* @param {String|DomElement} cont Container id or DOM element
|
|
|
|
* @param {int} width
|
|
|
|
* @param {int} height
|
|
|
|
*/
|
2012-07-04 03:07:27 +08:00
|
|
|
Kinetic.Stage = Kinetic.Container.extend({
|
|
|
|
init: function(config) {
|
|
|
|
this.setDefaultAttrs({
|
|
|
|
width: 400,
|
|
|
|
height: 200,
|
|
|
|
throttle: 80
|
|
|
|
});
|
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
|
|
|
|
this._super(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-03-07 13:45:48 +08:00
|
|
|
/**
|
|
|
|
* sets onFrameFunc for animation
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name onFrame
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
* @param {function} func
|
|
|
|
*/
|
|
|
|
onFrame: function(func) {
|
2012-04-04 04:44:48 +08:00
|
|
|
this.anim = {
|
2012-04-03 13:54:05 +08:00
|
|
|
func: func
|
2012-04-04 04:44:48 +08:00
|
|
|
};
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* start animation
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name start
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
|
|
|
start: function() {
|
2012-04-29 09:33:05 +08:00
|
|
|
if(!this.animRunning) {
|
2012-07-04 14:00:52 +08:00
|
|
|
var a = Kinetic.Animation;
|
|
|
|
a._addAnimation(this.anim);
|
|
|
|
a._handleAnimation();
|
2012-04-29 09:33:05 +08:00
|
|
|
this.animRunning = true;
|
|
|
|
}
|
2012-03-07 13:45:48 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* stop animation
|
2012-07-09 12:56:52 +08:00
|
|
|
* @name stop
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
|
|
|
stop: function() {
|
2012-07-04 14:00:52 +08:00
|
|
|
Kinetic.Animation._removeAnimation(this.anim);
|
2012-04-29 09:33:05 +08:00
|
|
|
this.animRunning = false;
|
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-07-19 14:28:45 +08:00
|
|
|
draw: function(canvas) {
|
|
|
|
this._draw(canvas);
|
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-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
|
|
|
/**
|
|
|
|
* return 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-04-08 09:50:53 +08:00
|
|
|
* serialize stage and children as a JSON object
|
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
|
|
|
|
* 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
|
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) {
|
|
|
|
var mimeType = config && config.mimeType ? config.mimeType : null;
|
|
|
|
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-07-22 04:29:22 +08:00
|
|
|
var layerUrl = layer.getCanvas().toDataURL(mimeType, quality);
|
toDataURL() is now synchronous, and works with all nodes, including the stage, layers, groups, and shapes. This also sets things up nicely for node caching. You can now cache anything, including the whole stage, layers, groups, or shapes, manifested as Kinetic Images that were instantiated with data urls
2012-07-15 09:10:37 +08:00
|
|
|
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-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-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
|
|
|
// set buffer canvas and path canvas sizes
|
|
|
|
this.bufferCanvas.setSize(width, height);
|
|
|
|
this.pathCanvas.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-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 {
|
|
|
|
this.content.removeChild(layer.canvas);
|
|
|
|
}
|
|
|
|
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-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 09:31:13 +08:00
|
|
|
|
2012-05-27 07:49:58 +08:00
|
|
|
/*
|
|
|
|
* set layer last draw time to zero
|
|
|
|
* so that throttling doesn't take into account
|
|
|
|
* the layer draws associated with adding a node
|
|
|
|
*/
|
|
|
|
layer.lastDrawTime = 0;
|
|
|
|
},
|
2012-03-07 13:45:48 +08:00
|
|
|
/**
|
2012-03-11 08:52:16 +08:00
|
|
|
* detect event
|
|
|
|
* @param {Shape} shape
|
2012-03-07 13:45:48 +08:00
|
|
|
*/
|
2012-03-11 08:52:16 +08:00
|
|
|
_detectEvent: function(shape, evt) {
|
2012-07-04 13:08:59 +08:00
|
|
|
var isDragging = Kinetic.Global.drag.moving;
|
|
|
|
var go = Kinetic.Global;
|
2012-03-11 08:52:16 +08:00
|
|
|
var pos = this.getUserPosition();
|
|
|
|
var el = shape.eventListeners;
|
2012-06-19 08:56:12 +08:00
|
|
|
var that = this;
|
2012-03-07 13:45:48 +08:00
|
|
|
|
2012-04-08 11:32:24 +08:00
|
|
|
if(this.targetShape && shape._id === this.targetShape._id) {
|
2012-03-11 08:52:16 +08:00
|
|
|
this.targetFound = true;
|
|
|
|
}
|
2012-03-07 13:45:48 +08:00
|
|
|
|
2012-06-03 10:12:06 +08:00
|
|
|
if(shape.isVisible() && pos !== undefined && shape.intersects(pos)) {
|
2012-03-11 08:52:16 +08:00
|
|
|
// handle onmousedown
|
|
|
|
if(!isDragging && this.mouseDown) {
|
|
|
|
this.mouseDown = false;
|
|
|
|
this.clickStart = true;
|
2012-06-08 15:42:48 +08:00
|
|
|
shape._handleEvent('mousedown', evt);
|
2012-03-11 08:52:16 +08:00
|
|
|
return true;
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
2012-03-11 08:52:16 +08:00
|
|
|
// handle onmouseup & onclick
|
2012-03-18 05:35:34 +08:00
|
|
|
else if(this.mouseUp) {
|
2012-03-11 08:52:16 +08:00
|
|
|
this.mouseUp = false;
|
2012-06-08 15:42:48 +08:00
|
|
|
shape._handleEvent('mouseup', evt);
|
2012-03-07 13:45:48 +08:00
|
|
|
|
2012-03-11 08:52:16 +08:00
|
|
|
// 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) {
|
2012-06-08 15:42:48 +08:00
|
|
|
shape._handleEvent('click', evt);
|
2012-03-11 08:52:16 +08:00
|
|
|
|
2012-06-19 08:56:12 +08:00
|
|
|
if(this.inDoubleClickWindow) {
|
2012-06-08 15:42:48 +08:00
|
|
|
shape._handleEvent('dblclick', evt);
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
2012-06-19 08:56:12 +08:00
|
|
|
this.inDoubleClickWindow = true;
|
2012-03-11 08:52:16 +08:00
|
|
|
setTimeout(function() {
|
2012-06-19 08:56:12 +08:00
|
|
|
that.inDoubleClickWindow = false;
|
2012-03-11 08:52:16 +08:00
|
|
|
}, this.dblClickWindow);
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
|
|
|
}
|
2012-03-11 08:52:16 +08:00
|
|
|
return true;
|
|
|
|
}
|
2012-03-07 13:45:48 +08:00
|
|
|
|
2012-03-11 08:52:16 +08:00
|
|
|
// handle touchstart
|
2012-06-16 02:47:55 +08:00
|
|
|
else if(!isDragging && this.touchStart && !this.touchMove) {
|
2012-03-11 08:52:16 +08:00
|
|
|
this.touchStart = false;
|
2012-06-01 15:44:38 +08:00
|
|
|
this.tapStart = true;
|
2012-06-08 15:42:48 +08:00
|
|
|
shape._handleEvent('touchstart', evt);
|
2012-03-11 08:52:16 +08:00
|
|
|
return true;
|
|
|
|
}
|
2012-06-01 15:44:38 +08:00
|
|
|
// handle touchend & tap
|
2012-03-18 05:35:34 +08:00
|
|
|
else if(this.touchEnd) {
|
2012-03-11 08:52:16 +08:00
|
|
|
this.touchEnd = false;
|
2012-06-08 15:42:48 +08:00
|
|
|
shape._handleEvent('touchend', evt);
|
2012-06-01 15:44:38 +08:00
|
|
|
|
|
|
|
// 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) {
|
2012-06-08 15:42:48 +08:00
|
|
|
shape._handleEvent('tap', evt);
|
2012-06-01 15:44:38 +08:00
|
|
|
|
2012-06-19 08:56:12 +08:00
|
|
|
if(this.inDoubleClickWindow) {
|
2012-06-08 15:42:48 +08:00
|
|
|
shape._handleEvent('dbltap', evt);
|
2012-06-01 15:44:38 +08:00
|
|
|
}
|
2012-06-19 08:56:12 +08:00
|
|
|
this.inDoubleClickWindow = true;
|
2012-06-01 15:44:38 +08:00
|
|
|
setTimeout(function() {
|
2012-06-19 08:56:12 +08:00
|
|
|
that.inDoubleClickWindow = false;
|
2012-06-01 15:44:38 +08:00
|
|
|
}, this.dblClickWindow);
|
|
|
|
}
|
|
|
|
}
|
2012-03-11 08:52:16 +08:00
|
|
|
return true;
|
|
|
|
}
|
2012-06-19 08:56:12 +08:00
|
|
|
else if(!isDragging && this.touchMove) {
|
|
|
|
shape._handleEvent('touchmove', evt);
|
|
|
|
return true;
|
|
|
|
}
|
2012-03-18 10:48:54 +08:00
|
|
|
/*
|
2012-03-19 02:24:57 +08:00
|
|
|
* NOTE: these event handlers require target shape
|
|
|
|
* handling
|
|
|
|
*/
|
|
|
|
// handle onmouseover
|
2012-03-18 10:48:54 +08:00
|
|
|
else if(!isDragging && this._isNewTarget(shape, evt)) {
|
2012-03-19 02:24:57 +08:00
|
|
|
/*
|
|
|
|
* check to see if there are stored mouseout events first.
|
|
|
|
* if there are, run those before running the onmouseover
|
|
|
|
* events
|
|
|
|
*/
|
|
|
|
if(this.mouseoutShape) {
|
|
|
|
this.mouseoverShape = shape;
|
2012-06-08 15:42:48 +08:00
|
|
|
this.mouseoutShape._handleEvent('mouseout', evt);
|
2012-03-19 02:24:57 +08:00
|
|
|
this.mouseoverShape = undefined;
|
|
|
|
}
|
|
|
|
|
2012-06-08 15:42:48 +08:00
|
|
|
shape._handleEvent('mouseover', evt);
|
2012-03-19 02:24:57 +08:00
|
|
|
this._setTarget(shape);
|
2012-03-07 13:45:48 +08:00
|
|
|
return true;
|
|
|
|
}
|
2012-03-18 10:48:54 +08:00
|
|
|
// handle mousemove and touchmove
|
2012-07-02 11:58:13 +08:00
|
|
|
else {
|
|
|
|
if(!isDragging && this.mouseMove) {
|
|
|
|
shape._handleEvent('mousemove', evt);
|
|
|
|
return true;
|
|
|
|
}
|
2012-06-01 15:44:38 +08:00
|
|
|
}
|
|
|
|
|
2012-03-11 08:52:16 +08:00
|
|
|
}
|
|
|
|
// handle mouseout condition
|
2012-04-08 11:32:24 +08:00
|
|
|
else if(!isDragging && this.targetShape && this.targetShape._id === shape._id) {
|
2012-03-19 02:24:57 +08:00
|
|
|
this._setTarget(undefined);
|
|
|
|
this.mouseoutShape = shape;
|
2012-03-11 08:52:16 +08:00
|
|
|
return true;
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
|
|
|
|
2012-03-11 08:52:16 +08:00
|
|
|
return false;
|
|
|
|
},
|
2012-03-19 02:24:57 +08:00
|
|
|
/**
|
|
|
|
* set new target
|
|
|
|
*/
|
|
|
|
_setTarget: function(shape) {
|
|
|
|
this.targetShape = shape;
|
|
|
|
this.targetFound = true;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* check if shape should be a new target
|
|
|
|
*/
|
2012-03-18 10:48:54 +08:00
|
|
|
_isNewTarget: function(shape, evt) {
|
2012-04-08 11:32:24 +08:00
|
|
|
if(!this.targetShape || (!this.targetFound && shape._id !== this.targetShape._id)) {
|
2012-03-18 10:48:54 +08:00
|
|
|
/*
|
|
|
|
* check if old target has an onmouseout event listener
|
|
|
|
*/
|
|
|
|
if(this.targetShape) {
|
|
|
|
var oldEl = this.targetShape.eventListeners;
|
|
|
|
if(oldEl) {
|
2012-03-19 02:24:57 +08:00
|
|
|
this.mouseoutShape = this.targetShape;
|
2012-03-18 10:48:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
},
|
2012-03-11 08:52:16 +08:00
|
|
|
/**
|
|
|
|
* traverse container children
|
|
|
|
* @param {Container} obj
|
|
|
|
*/
|
|
|
|
_traverseChildren: function(obj, evt) {
|
|
|
|
var children = obj.children;
|
|
|
|
// propapgate backwards through children
|
|
|
|
for(var i = children.length - 1; i >= 0; i--) {
|
|
|
|
var child = children[i];
|
2012-06-19 14:12:56 +08:00
|
|
|
if(child.getListening()) {
|
2012-04-05 13:57:36 +08:00
|
|
|
if(child.nodeType === 'Shape') {
|
2012-03-22 21:15:31 +08:00
|
|
|
var exit = this._detectEvent(child, evt);
|
|
|
|
if(exit) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
var exit = this._traverseChildren(child, evt);
|
|
|
|
if(exit) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-03-11 08:52:16 +08:00
|
|
|
}
|
2012-03-07 13:45:48 +08:00
|
|
|
|
2012-03-11 08:52:16 +08:00
|
|
|
return false;
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* handle incoming event
|
|
|
|
* @param {Event} evt
|
|
|
|
*/
|
2012-05-29 03:12:26 +08:00
|
|
|
_handleStageEvent: function(evt) {
|
2012-05-28 14:41:05 +08:00
|
|
|
var date = new Date();
|
|
|
|
var time = date.getTime();
|
|
|
|
this.lastEventTime = time;
|
|
|
|
|
2012-07-04 13:08:59 +08:00
|
|
|
var go = Kinetic.Global;
|
2012-03-11 08:52:16 +08:00
|
|
|
if(!evt) {
|
|
|
|
evt = window.event;
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
|
|
|
|
2012-03-11 08:52:16 +08:00
|
|
|
this._setMousePosition(evt);
|
|
|
|
this._setTouchPosition(evt);
|
2012-07-19 14:28:45 +08:00
|
|
|
this.pathCanvas.clear();
|
2012-03-11 08:52:16 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* loop through layers. If at any point an event
|
2012-06-08 15:42:48 +08:00
|
|
|
* is triggered, break out
|
2012-03-11 08:52:16 +08:00
|
|
|
*/
|
|
|
|
this.targetFound = false;
|
2012-03-19 02:24:57 +08:00
|
|
|
var shapeDetected = false;
|
2012-03-11 08:52:16 +08:00
|
|
|
for(var n = this.children.length - 1; n >= 0; n--) {
|
|
|
|
var layer = this.children[n];
|
2012-06-19 14:12:56 +08:00
|
|
|
if(layer.isVisible() && n >= 0 && layer.getListening()) {
|
2012-03-11 08:52:16 +08:00
|
|
|
if(this._traverseChildren(layer, evt)) {
|
2012-03-19 02:24:57 +08:00
|
|
|
shapeDetected = true;
|
2012-06-08 15:42:48 +08:00
|
|
|
break;
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-03-19 02:24:57 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* if no shape was detected and a mouseout shape has been stored,
|
|
|
|
* then run the onmouseout event handlers
|
|
|
|
*/
|
|
|
|
if(!shapeDetected && this.mouseoutShape) {
|
2012-06-08 15:42:48 +08:00
|
|
|
this.mouseoutShape._handleEvent('mouseout', evt);
|
2012-03-19 02:24:57 +08:00
|
|
|
this.mouseoutShape = undefined;
|
|
|
|
}
|
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-06-15 14:46:52 +08:00
|
|
|
var events = ['mousedown', 'mousemove', 'mouseup', 'mouseover', 'mouseout', 'touchstart', 'touchmove', 'touchend'];
|
|
|
|
|
|
|
|
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
|
|
|
_mouseover: function(evt) {
|
2012-06-15 14:46:52 +08:00
|
|
|
this._handleStageEvent(evt);
|
|
|
|
},
|
2012-06-16 02:47:55 +08:00
|
|
|
_mouseout: function(evt) {
|
2012-06-15 14:46:52 +08:00
|
|
|
// if there's a current target shape, run mouseout handlers
|
|
|
|
var targetShape = this.targetShape;
|
|
|
|
if(targetShape) {
|
|
|
|
targetShape._handleEvent('mouseout', evt);
|
|
|
|
this.targetShape = undefined;
|
|
|
|
}
|
|
|
|
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-06-15 14:46:52 +08:00
|
|
|
//throttle mousemove
|
|
|
|
var throttle = this.attrs.throttle;
|
|
|
|
var date = new Date();
|
|
|
|
var time = date.getTime();
|
|
|
|
var timeDiff = time - this.lastEventTime;
|
|
|
|
var tt = 1000 / throttle;
|
|
|
|
|
2012-06-19 08:56:12 +08:00
|
|
|
if(timeDiff >= tt || throttle > 200) {
|
2012-06-15 14:46:52 +08:00
|
|
|
this.mouseDown = false;
|
|
|
|
this.mouseUp = false;
|
2012-06-19 08:56:12 +08:00
|
|
|
this.mouseMove = true;
|
2012-06-15 14:46:52 +08:00
|
|
|
this._handleStageEvent(evt);
|
|
|
|
}
|
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-06-15 14:46:52 +08:00
|
|
|
this.mouseDown = true;
|
|
|
|
this.mouseUp = false;
|
|
|
|
this.mouseMove = false;
|
|
|
|
this._handleStageEvent(evt);
|
|
|
|
|
|
|
|
//init stage drag and drop
|
|
|
|
if(this.attrs.draggable) {
|
|
|
|
this._initDrag();
|
|
|
|
}
|
|
|
|
},
|
2012-06-16 02:47:55 +08:00
|
|
|
_mouseup: function(evt) {
|
2012-06-15 14:46:52 +08:00
|
|
|
this.mouseDown = false;
|
|
|
|
this.mouseUp = true;
|
|
|
|
this.mouseMove = false;
|
|
|
|
this._handleStageEvent(evt);
|
|
|
|
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-06-15 14:46:52 +08:00
|
|
|
evt.preventDefault();
|
|
|
|
this.touchStart = true;
|
|
|
|
this.touchEnd = false;
|
|
|
|
this.touchMove = false;
|
|
|
|
this._handleStageEvent(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-06-15 14:46:52 +08:00
|
|
|
this.touchStart = false;
|
|
|
|
this.touchEnd = true;
|
|
|
|
this.touchMove = false;
|
|
|
|
this._handleStageEvent(evt);
|
|
|
|
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-06-15 14:46:52 +08:00
|
|
|
//throttle touchmove
|
|
|
|
var that = this;
|
|
|
|
var throttle = this.attrs.throttle;
|
|
|
|
var date = new Date();
|
|
|
|
var time = date.getTime();
|
|
|
|
var timeDiff = time - this.lastEventTime;
|
|
|
|
var tt = 1000 / throttle;
|
|
|
|
|
2012-06-19 08:56:12 +08:00
|
|
|
if(timeDiff >= tt || throttle > 200) {
|
|
|
|
evt.preventDefault();
|
|
|
|
that.touchEnd = false;
|
|
|
|
that.touchMove = true;
|
|
|
|
that._handleStageEvent(evt);
|
2012-06-15 14:46:52 +08:00
|
|
|
}
|
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-03-07 13:45:48 +08:00
|
|
|
if(go.drag.node) {
|
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-06-08 15:42:48 +08:00
|
|
|
go.drag.node._handleEvent('dragend', evt);
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
go.drag.node = undefined;
|
|
|
|
},
|
|
|
|
/**
|
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) {
|
|
|
|
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-03-07 13:45:48 +08:00
|
|
|
|
2012-06-16 02:47:55 +08:00
|
|
|
// default
|
|
|
|
var newNodePos = {
|
|
|
|
x: pos.x - go.drag.offset.x,
|
|
|
|
y: pos.y - go.drag.offset.y
|
|
|
|
};
|
2012-04-13 12:33:40 +08:00
|
|
|
|
2012-06-16 02:47:55 +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-04-15 07:27:00 +08:00
|
|
|
|
2012-06-16 02:47:55 +08:00
|
|
|
node.setAbsolutePosition(newNodePos);
|
2012-03-25 11:52:17 +08:00
|
|
|
|
2012-06-16 02:47:55 +08:00
|
|
|
// constraint overrides
|
|
|
|
if(dc === 'horizontal') {
|
|
|
|
node.attrs.y = lastNodePos.y;
|
|
|
|
}
|
|
|
|
else if(dc === 'vertical') {
|
|
|
|
node.attrs.x = lastNodePos.x;
|
|
|
|
}
|
2012-03-07 13:45:48 +08:00
|
|
|
|
2012-06-16 02:47:55 +08:00
|
|
|
/*
|
|
|
|
* if dragging and dropping the stage,
|
|
|
|
* draw all of the layers
|
|
|
|
*/
|
|
|
|
if(go.drag.node.nodeType === 'Stage') {
|
|
|
|
go.drag.node.draw();
|
|
|
|
}
|
2012-03-26 03:45:46 +08:00
|
|
|
|
2012-06-16 02:47:55 +08:00
|
|
|
else {
|
|
|
|
go.drag.node.getLayer().draw();
|
|
|
|
}
|
2012-05-27 15:07:36 +08:00
|
|
|
|
2012-06-16 02:47:55 +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-06-16 02:47:55 +08:00
|
|
|
// execute user defined ondragmove if defined
|
|
|
|
go.drag.node._handleEvent('dragmove', evt);
|
|
|
|
}
|
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-07-19 14:28:45 +08:00
|
|
|
this.pathCanvas = new Kinetic.Canvas({
|
|
|
|
width: this.attrs.width,
|
|
|
|
height: this.attrs.height
|
2012-04-02 10:38:30 +08:00
|
|
|
});
|
2012-07-19 14:28:45 +08:00
|
|
|
this.pathCanvas.strip();
|
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.lastEventTime = 0;
|
|
|
|
this.dblClickWindow = 400;
|
2012-04-29 04:46:54 +08:00
|
|
|
this.targetShape = undefined;
|
|
|
|
this.targetFound = false;
|
|
|
|
this.mouseoverShape = undefined;
|
|
|
|
this.mouseoutShape = undefined;
|
|
|
|
|
|
|
|
// desktop flags
|
|
|
|
this.mousePos = undefined;
|
|
|
|
this.mouseDown = false;
|
|
|
|
this.mouseUp = false;
|
2012-06-01 15:44:38 +08:00
|
|
|
this.mouseMove = false;
|
|
|
|
this.clickStart = false;
|
2012-04-29 04:46:54 +08:00
|
|
|
|
|
|
|
// mobile flags
|
|
|
|
this.touchPos = undefined;
|
|
|
|
this.touchStart = false;
|
|
|
|
this.touchEnd = false;
|
2012-06-01 15:44:38 +08:00
|
|
|
this.touchMove = false;
|
|
|
|
this.tapStart = false;
|
2012-04-29 04:46:54 +08:00
|
|
|
|
|
|
|
this.ids = {};
|
|
|
|
this.names = {};
|
|
|
|
this.anim = undefined;
|
2012-04-29 09:33:05 +08:00
|
|
|
this.animRunning = false;
|
2012-07-15 07:25:56 +08:00
|
|
|
},
|
2012-07-19 14:28:45 +08:00
|
|
|
_draw: function(canvas) {
|
|
|
|
this._drawChildren(canvas);
|
2012-03-07 13:45:48 +08:00
|
|
|
}
|
2012-07-04 03:07:27 +08:00
|
|
|
});
|
2012-06-11 04:07:09 +08:00
|
|
|
|
2012-07-04 03:07:27 +08:00
|
|
|
// add getters and setters
|
|
|
|
Kinetic.Node.addGettersSetters(Kinetic.Stage, ['width', 'height', 'throttle']);
|
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
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* get throttle
|
2012-06-14 17:19:51 +08:00
|
|
|
* @name getThrottle
|
|
|
|
* @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
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* set throttle. Increasing the throttle will increase
|
|
|
|
* the number of mousemove and touchmove event detections,
|
|
|
|
* and decreasing the throttle will decrease the number
|
|
|
|
* of mousemove and touchmove events which improves performance
|
2012-06-14 17:19:51 +08:00
|
|
|
* @name setThrottle
|
|
|
|
* @methodOf Kinetic.Stage.prototype
|
2012-06-11 04:07:09 +08:00
|
|
|
* @param {Number} throttle
|
|
|
|
*/
|