Files
konva/src/Layer.js

292 lines
9.3 KiB
JavaScript

(function() {
// constants
var HASH = '#',
BEFORE_DRAW ='beforeDraw',
DRAW = 'draw',
/*
* 2 - 3 - 4
* | |
* 1 - 0 5
* |
* 8 - 7 - 6
*/
INTERSECTION_OFFSETS = [
{x: 0, y: 0}, // 0
{x: -1, y: 0}, // 1
{x: -1, y: -1}, // 2
{x: 0, y: -1}, // 3
{x: 1, y: -1}, // 4
{x: 1, y: 0}, // 5
{x: 1, y: 1}, // 6
{x: 0, y: 1}, // 7
{x: -1, y: 1} // 8
],
INTERSECTION_OFFSETS_LEN = INTERSECTION_OFFSETS.length;
Kinetic.Util.addMethods(Kinetic.Layer, {
___init: function(config) {
this.nodeType = 'Layer';
this.canvas = new Kinetic.SceneCanvas();
this.hitCanvas = new Kinetic.HitCanvas();
// call super constructor
Kinetic.Container.call(this, config);
},
_validateAdd: function(child) {
var type = child.getType();
if (type !== 'Group' && type !== 'Shape') {
Kinetic.Util.error('You may only add groups and shapes to a layer.');
}
},
/**
* get visible intersection shape. This is the preferred
* method for determining if a point intersects a shape or not
* @method
* @memberof Kinetic.Layer.prototype
* @param {Object} pos
* @param {Number} pos.x
* @param {Number} pos.y
* @returns {Kinetic.Shape}
*/
getIntersection: function(pos) {
var obj, i, intersectionOffset, shape;
if(this.isVisible()) {
for (i=0; i<INTERSECTION_OFFSETS_LEN; i++) {
intersectionOffset = INTERSECTION_OFFSETS[i];
obj = this._getIntersection({
x: pos.x + intersectionOffset.x,
y: pos.y + intersectionOffset.y
});
shape = obj.shape;
if (shape) {
return shape;
}
else if (!obj.antialiased) {
return null;
}
}
}
else {
return null;
}
},
_getIntersection: function(pos) {
var p = this.hitCanvas.context._context.getImageData(pos.x, pos.y, 1, 1).data,
p3 = p[3],
colorKey, shape;
// fully opaque pixel
if(p3 === 255) {
colorKey = Kinetic.Util._rgbToHex(p[0], p[1], p[2]);
shape = Kinetic.shapes[HASH + colorKey];
return {
shape: shape
};
}
// antialiased pixel
else if(p3 > 0) {
return {
antialiased: true
};
}
// empty pixel
else {
return {};
}
},
drawScene: function(canvas) {
canvas = canvas || this.getCanvas();
this._fire(BEFORE_DRAW, {
node: this
});
if(this.getClearBeforeDraw()) {
canvas.getContext().clear();
}
Kinetic.Container.prototype.drawScene.call(this, canvas);
this._fire(DRAW, {
node: this
});
return this;
},
drawHit: function() {
var layer = this.getLayer();
if(layer && layer.getClearBeforeDraw()) {
layer.getHitCanvas().getContext().clear();
}
Kinetic.Container.prototype.drawHit.call(this);
return this;
},
/**
* get layer canvas
* @method
* @memberof Kinetic.Node.prototype
*/
getCanvas: function() {
return this.canvas;
},
/**
* get layer hit canvas
* @method
* @memberof Kinetic.Node.prototype
*/
getHitCanvas: function() {
return this.hitCanvas;
},
/**
* get layer canvas context
* @method
* @memberof Kinetic.Node.prototype
*/
getContext: function() {
return this.getCanvas().getContext();
},
/**
* clear scene and hit canvas contexts tied to the layer
* @method
* @memberof Kinetic.Node.prototype
* @param {Object} [bounds]
* @param {Number} [bounds.x]
* @param {Number} [bounds.y]
* @param {Number} [bounds.width]
* @param {Number} [bounds.height]
* @example
* layer.clear();<br>
* layer.clear(0, 0, 100, 100);
*/
clear: function(bounds) {
var context = this.getContext(),
hitContext = this.getHitCanvas().getContext();
context.clear(bounds);
hitContext.clear(bounds);
return this;
},
// extend Node.prototype.setVisible
setVisible: function(visible) {
Kinetic.Node.prototype.setVisible.call(this, visible);
if(visible) {
this.getCanvas()._canvas.style.display = 'block';
this.hitCanvas._canvas.style.display = 'block';
}
else {
this.getCanvas()._canvas.style.display = 'none';
this.hitCanvas._canvas.style.display = 'none';
}
return this;
},
// extend Node.prototype.setZIndex
setZIndex: function(index) {
Kinetic.Node.prototype.setZIndex.call(this, index);
var stage = this.getStage();
if(stage) {
stage.content.removeChild(this.getCanvas()._canvas);
if(index < stage.getChildren().length - 1) {
stage.content.insertBefore(this.getCanvas()._canvas, stage.getChildren()[index + 1].getCanvas()._canvas);
}
else {
stage.content.appendChild(this.getCanvas()._canvas);
}
}
return this;
},
// extend Node.prototype.moveToTop
moveToTop: function() {
Kinetic.Node.prototype.moveToTop.call(this);
var stage = this.getStage();
if(stage) {
stage.content.removeChild(this.getCanvas()._canvas);
stage.content.appendChild(this.getCanvas()._canvas);
}
},
// extend Node.prototype.moveUp
moveUp: function() {
if(Kinetic.Node.prototype.moveUp.call(this)) {
var stage = this.getStage();
if(stage) {
stage.content.removeChild(this.getCanvas()._canvas);
if(this.index < stage.getChildren().length - 1) {
stage.content.insertBefore(this.getCanvas()._canvas, stage.getChildren()[this.index + 1].getCanvas()._canvas);
}
else {
stage.content.appendChild(this.getCanvas()._canvas);
}
}
}
},
// extend Node.prototype.moveDown
moveDown: function() {
if(Kinetic.Node.prototype.moveDown.call(this)) {
var stage = this.getStage();
if(stage) {
var children = stage.getChildren();
stage.content.removeChild(this.getCanvas()._canvas);
stage.content.insertBefore(this.getCanvas()._canvas, children[this.index + 1].getCanvas()._canvas);
}
}
},
// extend Node.prototype.moveToBottom
moveToBottom: function() {
if(Kinetic.Node.prototype.moveToBottom.call(this)) {
var stage = this.getStage();
if(stage) {
var children = stage.getChildren();
stage.content.removeChild(this.getCanvas()._canvas);
stage.content.insertBefore(this.getCanvas()._canvas, children[1].getCanvas()._canvas);
}
}
},
getLayer: function() {
return this;
},
remove: function() {
var stage = this.getStage(),
canvas = this.getCanvas(),
_canvas = canvas._canvas;
Kinetic.Node.prototype.remove.call(this);
if(stage && _canvas && Kinetic.Util._isInDocument(_canvas)) {
stage.content.removeChild(_canvas);
}
return this;
},
getStage: function() {
return this.parent;
}
});
Kinetic.Util.extend(Kinetic.Layer, Kinetic.Container);
// add getters and setters
Kinetic.Factory.addGetterSetter(Kinetic.Layer, 'clearBeforeDraw', function() {
return true;
});
/**
* set flag which determines if the layer is cleared or not
* before drawing
* @name setClearBeforeDraw
* @method
* @memberof Kinetic.Node.prototype
* @param {Boolean} clearBeforeDraw
*/
/**
* get flag which determines if the layer is cleared or not
* before drawing
* @name getClearBeforeDraw
* @method
* @memberof Kinetic.Node.prototype
*/
})();