konva/src/Container.js

238 lines
6.4 KiB
JavaScript
Raw Normal View History

///////////////////////////////////////////////////////////////////////
// Container
///////////////////////////////////////////////////////////////////////
/**
* Container constructor.  Containers are used to contain nodes or other containers
* @constructor
* @augments Kinetic.Node
* @param {Object} config
*/
Kinetic.Container = Kinetic.Node.extend({
init: function(config) {
this.children = [];
this._super(config);
},
/**
* get children
* @name getChildren
* @methodOf Kinetic.Container.prototype
*/
getChildren: function() {
return this.children;
},
/**
* remove all children
* @name removeChildren
* @methodOf Kinetic.Container.prototype
*/
removeChildren: function() {
while(this.children.length > 0) {
this.remove(this.children[0]);
}
},
/**
* add node to container
* @name add
* @methodOf Kinetic.Container.prototype
* @param {Node} child
*/
add: function(child) {
child._id = Kinetic.Global.idCounter++;
child.index = this.children.length;
child.parent = this;
this.children.push(child);
var stage = child.getStage();
if(stage === undefined) {
var go = Kinetic.Global;
go.tempNodes.push(child);
}
else {
stage._addId(child);
stage._addName(child);
/*
* pull in other nodes that are now linked
* to a stage
*/
var go = Kinetic.Global;
go._pullNodes(stage);
}
// do extra stuff if needed
if(this._add !== undefined) {
this._add(child);
}
// chainable
return this;
},
/**
* remove child from container
* @name remove
* @methodOf Kinetic.Container.prototype
* @param {Node} child
*/
remove: function(child) {
if(child && child.index !== undefined && this.children[child.index]._id == child._id) {
var stage = this.getStage();
if(stage !== undefined) {
stage._removeId(child.getId());
stage._removeName(child.getName(), child._id);
}
var go = Kinetic.Global;
for(var n = 0; n < go.tempNodes.length; n++) {
var node = go.tempNodes[n];
if(node._id === child._id) {
go.tempNodes.splice(n, 1);
break;
}
}
this.children.splice(child.index, 1);
this._setChildrenIndices();
// remove children
while(child.children && child.children.length > 0) {
child.remove(child.children[0]);
}
// do extra stuff if needed
if(this._remove !== undefined) {
this._remove(child);
}
}
// chainable
return this;
},
/**
2012-04-09 12:37:10 +08:00
* return an array of nodes that match the selector. Use '#' for id selections
* and '.' for name selections
* ex:
* var node = stage.get('#foo'); // selects node with id foo
* var nodes = layer.get('.bar'); // selects nodes with name bar inside layer
* @name get
* @methodOf Kinetic.Container.prototype
* @param {String} selector
*/
get: function(selector) {
var stage = this.getStage();
var arr;
var key = selector.slice(1);
if(selector.charAt(0) === '#') {
arr = stage.ids[key] !== undefined ? [stage.ids[key]] : [];
}
else if(selector.charAt(0) === '.') {
arr = stage.names[key] !== undefined ? stage.names[key] : [];
}
else if(selector === 'Shape' || selector === 'Group' || selector === 'Layer') {
return this._getNodes(selector);
}
else {
return false;
}
var retArr = [];
for(var n = 0; n < arr.length; n++) {
var node = arr[n];
if(this.isAncestorOf(node)) {
retArr.push(node);
}
}
return retArr;
},
/**
* determine if node is an ancestor
* of descendant
* @name isAncestorOf
* @methodOf Kinetic.Container.prototype
* @param {Kinetic.Node} node
*/
isAncestorOf: function(node) {
if(this.nodeType === 'Stage') {
return true;
}
var parent = node.getParent();
while(parent) {
if(parent._id === this._id) {
return true;
}
parent = parent.getParent();
}
return false;
},
/**
* get shapes that intersect a point
* @name getIntersections
* @methodOf Kinetic.Container.prototype
* @param {Object} point
*/
getIntersections: function() {
var pos = Kinetic.Type._getXY(Array.prototype.slice.call(arguments));
var arr = [];
var shapes = this.get('Shape');
for(var n = 0; n < shapes.length; n++) {
var shape = shapes[n];
if(shape.isVisible() && shape.intersects(pos)) {
arr.push(shape);
}
}
return arr;
},
/**
* get all shapes inside container
*/
_getNodes: function(sel) {
var arr = [];
function traverse(cont) {
var children = cont.getChildren();
for(var n = 0; n < children.length; n++) {
var child = children[n];
if(child.nodeType === sel) {
arr.push(child);
}
else if(child.nodeType !== 'Shape') {
traverse(child);
}
}
}
traverse(this);
return arr;
},
/**
* draw children
*/
_drawChildren: function(canvas) {
var stage = this.getStage();
var children = this.children;
for(var n = 0; n < children.length; n++) {
var child = children[n];
if(child.nodeType === 'Shape') {
if(child.isVisible() && stage.isVisible()) {
child._draw(canvas);
}
}
else {
child.draw(canvas);
}
}
},
/**
* set children indices
*/
_setChildrenIndices: function() {
for(var n = 0; n < this.children.length; n++) {
this.children[n].index = n;
}
}
});