Merge github.com:ericdrowell/KineticJS

This commit is contained in:
Louis Jolibois
2013-03-27 18:55:52 +01:00
46 changed files with 1263 additions and 882 deletions

View File

@@ -135,7 +135,7 @@
})();
Kinetic.Animation.requestAnimFrame = function(callback) {
var raf = Kinetic.DD && Kinetic.DD.moving ? this.fixedRequestAnimFrame : RAF;
var raf = Kinetic.DD && Kinetic.DD.isDragging ? this.fixedRequestAnimFrame : RAF;
raf(callback);
};

View File

@@ -204,11 +204,7 @@
if (!canvas && layer) {
canvas = layer.getCanvas();
}
if(layer && layer.getClearBeforeDraw()) {
canvas.clear();
}
}
if(this.isVisible()) {
if (clip) {
@@ -229,20 +225,21 @@
},
drawHit: function() {
var clip = !!this.getClipFunc() && this.nodeType !== 'Stage',
dd = Kinetic.DD,
hitCanvas;
if (clip) {
hitCanvas = this.getLayer().hitCanvas;
hitCanvas._clip(this);
}
if(this.isVisible() && this.isListening()) {
if(this.shouldDrawHit()) {
if (clip) {
hitCanvas = this.getLayer().hitCanvas;
hitCanvas._clip(this);
}
var children = this.children, len = children.length;
for(var n = 0; n < len; n++) {
children[n].drawHit();
}
}
if (clip) {
hitCanvas.getContext().restore();
if (clip) {
hitCanvas.getContext().restore();
}
}
}
};

View File

@@ -1,127 +1,122 @@
(function() {
Kinetic.DD = {
// properties
anim: new Kinetic.Animation(),
moving: false,
isDragging: false,
offset: {
x: 0,
y: 0
}
};
Kinetic.getNodeDragging = function() {
return Kinetic.DD.node;
};
Kinetic.DD._initDragLayer = function(stage) {
stage.dragLayer = new Kinetic.Layer();
stage.dragLayer.getCanvas().getElement().className = 'kinetic-drag-and-drop-layer';
};
Kinetic.DD._drag = function(evt) {
var dd = Kinetic.DD, node = dd.node;
if(node) {
var pos = node.getStage().getUserPosition();
var dbf = node.attrs.dragBoundFunc;
var newNodePos = {
x: pos.x - dd.offset.x,
y: pos.y - dd.offset.y
};
if(dbf !== undefined) {
newNodePos = dbf.call(node, newNodePos, evt);
}
node.setAbsolutePosition(newNodePos);
if(!dd.moving) {
dd.moving = true;
node.setListening(false);
// execute dragstart events if defined
node._handleEvent('dragstart', evt);
}
// execute ondragmove if defined
node._handleEvent('dragmove', evt);
}
};
Kinetic.DD._endDrag = function(evt) {
var dd = Kinetic.DD, node = dd.node;
if(node) {
var nodeType = node.nodeType, stage = node.getStage();
node.setListening(true);
if(nodeType === 'Stage') {
node.draw();
}
// else if group, shape, or layer
else {
if((nodeType === 'Group' || nodeType === 'Shape') && node.getDragOnTop()) {
node.getStage().dragLayer.remove();
},
node: null,
// methods
_drag: function(evt) {
var dd = Kinetic.DD,
node = dd.node;
if(node) {
var pos = node.getStage().getPointerPosition();
var dbf = node.getDragBoundFunc();
var newNodePos = {
x: pos.x - dd.offset.x,
y: pos.y - dd.offset.y
};
if(dbf !== undefined) {
newNodePos = dbf.call(node, newNodePos, evt);
}
node.moveToTop();
node.getLayer().draw();
node.setAbsolutePosition(newNodePos);
if(!dd.isDragging) {
dd.isDragging = true;
node._handleEvent('dragstart', evt);
}
// execute ondragmove if defined
node._handleEvent('dragmove', evt);
}
delete dd.node;
dd.anim.stop();
// only fire dragend event if the drag and drop
// operation actually started. This can be detected by
// checking dd.moving
if(dd.moving) {
dd.moving = false;
node._handleEvent('dragend', evt);
},
_endDragBefore: function(evt) {
var dd = Kinetic.DD,
evt = evt || {},
node = dd.node,
nodeType, layer;
if(node) {
nodeType = node.nodeType,
layer = node.getLayer();
dd.anim.stop();
// only fire dragend event if the drag and drop
// operation actually started.
if(dd.isDragging) {
dd.isDragging = false;
evt.dragEndNode = node;
}
delete dd.node;
if (layer) {
layer.draw();
}
else {
node.draw();
}
}
},
_endDragAfter: function(evt) {
var evt = evt || {},
dragEndNode = evt.dragEndNode;
if (evt && dragEndNode) {
dragEndNode._handleEvent('dragend', evt);
}
}
};
Kinetic.Node.prototype._startDrag = function(evt) {
// Node extenders
/**
* initiate drag and drop
* @name startDrag
* @methodOf Kinetic.Node.prototype
*/
Kinetic.Node.prototype.startDrag = function() {
var dd = Kinetic.DD,
that = this,
stage = this.getStage(),
layer = this.getLayer(),
pos = stage.getUserPosition();
pos = stage.getPointerPosition(),
m = this.getTransform().getTranslation(),
ap = this.getAbsolutePosition(),
animNode = layer || this;
if(pos) {
var m = this.getTransform().getTranslation(), ap = this.getAbsolutePosition(), nodeType = this.nodeType, container;
if (dd.node) {
dd.node.stopDrag();
}
dd.node = this;
dd.offset.x = pos.x - ap.x;
dd.offset.y = pos.y - ap.y;
dd.anim.node = this;
// Stage and Layer node types
if(nodeType === 'Stage' || nodeType === 'Layer') {
dd.anim.start();
}
// Group or Shape node types
else {
if(this.getDragOnTop()) {
// WARNING: it's important to delay the moveTo operation,
// layer redraws, and anim.start() until after the method execution
// has completed or else there will be a flicker on mobile devices
// due to the time it takes to append the dd canvas to the DOM
//setTimeout(function() {
//if(dd.node) {
// clear shape from layer canvas
that.setVisible(false);
layer.draw();
that.setVisible(true);
stage.add(stage.dragLayer);
dd.anim.start();
//}
//}, 0);
}
else {
dd.anim.start();
}
}
dd.anim.node = animNode;
dd.anim.start();
}
};
/**
* stop drag and drop
* @name stopDrag
* @methodOf Kinetic.Node.prototype
*/
Kinetic.Node.prototype.stopDrag = function() {
var dd = Kinetic.DD;
dd._endDragBefore();
dd._endDragAfter();
};
/**
* set draggable
* @name setDraggable
@@ -140,15 +135,15 @@
*/
Kinetic.Node.prototype.isDragging = function() {
var dd = Kinetic.DD;
return dd.node && dd.node._id === this._id && dd.moving;
return dd.node && dd.node._id === this._id && dd.isDragging;
};
Kinetic.Node.prototype._listenDrag = function() {
this._dragCleanup();
var that = this;
this.on('mousedown.kinetic touchstart.kinetic', function(evt) {
if(!Kinetic.getNodeDragging()) {
that._startDrag(evt);
if(!Kinetic.DD.node) {
that.startDrag(evt);
}
});
};
@@ -169,10 +164,11 @@
var stage = this.getStage();
var dd = Kinetic.DD;
if(stage && dd.node && dd.node._id === this._id) {
dd._endDrag();
dd.node.stopDrag();
}
}
};
Kinetic.Node.prototype._dragCleanup = function() {
this.off('mousedown.kinetic');
this.off('touchstart.kinetic');
@@ -224,11 +220,15 @@
* @methodOf Kinetic.Node.prototype
*/
Kinetic.Node.prototype.isDraggable = Kinetic.Node.prototype.getDraggable;
// listen for capturing phase so that the _endDrag method is
// listen for capturing phase so that the _endDrag* methods are
// called before the stage mouseup event is triggered in order
// to render the hit graph just in time to pick up the event
var html = document.getElementsByTagName('html')[0];
html.addEventListener('mouseup', Kinetic.DD._endDrag, true);
html.addEventListener('touchend', Kinetic.DD._endDrag, true);
html.addEventListener('mouseup', Kinetic.DD._endDragBefore, true);
html.addEventListener('touchend', Kinetic.DD._endDragBefore, true);
html.addEventListener('mouseup', Kinetic.DD._endDragAfter, false);
html.addEventListener('touchend', Kinetic.DD._endDragAfter, false);
})();

View File

@@ -25,16 +25,22 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* @namespace
/**
* @namespace
*/
var Kinetic = {}; (function() {
var Kinetic = {};
(function() {
Kinetic.version = '{{version}}';
/**
* @namespace
/**
* @namespace
*/
Kinetic.Filters = {};
Kinetic.Plugins = {};
Kinetic.DD = {};
/**
* @namespace
*/
Kinetic.Global = {
stages: [],
idCounter: 0,
@@ -42,6 +48,15 @@ var Kinetic = {}; (function() {
names: {},
//shapes hash. rgb keys and shape values
shapes: {},
/**
* @method isDragging returns whether or not drag and drop
* is currently active
* @methodOf Kinetic.Global
*/
isDragging: function() {
var dd = Kinetic.DD;
return (!dd || dd.isDragging);
},
warn: function(str) {
/*
* IE9 on Windows7 64bit will throw a JS error

View File

@@ -27,49 +27,6 @@
// call super constructor
Kinetic.Container.call(this, config);
},
/**
* draw children nodes. this includes any groups
* or shapes
* @name draw
* @methodOf Kinetic.Layer.prototype
*/
draw: function() {
// before draw handler
if(this.beforeDrawFunc !== undefined) {
this.beforeDrawFunc.call(this);
}
Kinetic.Container.prototype.draw.call(this);
// after draw handler
if(this.afterDrawFunc !== undefined) {
this.afterDrawFunc.call(this);
}
},
/**
* draw children nodes on hit. this includes any groups
* or shapes
* @name drawHit
* @methodOf Kinetic.Layer.prototype
*/
drawHit: function() {
this.hitCanvas.clear();
Kinetic.Container.prototype.drawHit.call(this);
},
/**
* draw children nodes on scene. this includes any groups
* or shapes
* @name drawScene
* @methodOf Kinetic.Layer.prototype
* @param {Kinetic.Canvas} [canvas]
*/
drawScene: function(canvas) {
canvas = canvas || this.getCanvas();
if(this.getClearBeforeDraw()) {
canvas.clear();
}
Kinetic.Container.prototype.drawScene.call(this, canvas);
},
toDataURL: function(config) {
config = config || {};
var mimeType = config.mimeType || null,
@@ -114,8 +71,15 @@
* @methodOf Kinetic.Layer.prototype
*/
getCanvas: function() {
var stage = this.getStage();
return (stage && stage._isTempDDLayerActive()) ? stage.dragLayer.canvas : this.canvas;
return this.canvas;
},
/**
* get layer hit canvas
* @name getHitCanvas
* @methodOf Kinetic.Layer.prototype
*/
getHitCanvas: function() {
return this.hitCanvas;
},
/**
* get layer canvas context

View File

@@ -1,4 +1,27 @@
(function() {
// CONSTANTS
var SPACE = ' ',
EMPTY_STRING = '',
DOT = '.',
GET = 'get',
SET = 'set',
SHAPE = 'Shape',
STAGE = 'Stage',
X = 'x',
Y = 'y',
KINETIC = 'kinetic',
BEFORE = 'before',
CHANGE = 'Change',
ID = 'id',
NAME = 'name',
MOUSEENTER = 'mouseenter',
MOUSELEAVE = 'mouseleave',
DEG = 'Deg',
ON = 'on',
OFF = 'off',
BEFORE_DRAW = 'beforeDraw',
DRAW = 'draw';
/**
* Node constructor. Nodes are entities that can be transformed, layered,
* and have bound events. The stage, layers, groups, and shapes all extend Node.
@@ -29,19 +52,21 @@
* @param {Function} handler The handler function is passed an event object
*/
on: function(typesStr, handler) {
var types = typesStr.split(' ');
/*
var types = typesStr.split(SPACE),
len = types.length,
n, type, event, parts, baseEvent, name;
/*
* loop through types and attach event listeners to
* each one. eg. 'click mouseover.namespace mouseout'
* will create three event bindings
*/
var len = types.length;
for(var n = 0; n < len; n++) {
var type = types[n];
var event = type;
var parts = event.split('.');
var baseEvent = parts[0];
var name = parts.length > 1 ? parts[1] : '';
for(n = 0; n < len; n++) {
type = types[n];
event = type;
parts = event.split(DOT);
baseEvent = parts[0];
name = parts.length > 1 ? parts[1] : EMPTY_STRING;
if(!this.eventListeners[baseEvent]) {
this.eventListeners[baseEvent] = [];
@@ -66,13 +91,15 @@
* @param {String} typesStr e.g. 'click', 'mousedown touchstart', '.foobar'
*/
off: function(typesStr) {
var types = typesStr.split(' ');
var len = types.length;
for(var n = 0; n < len; n++) {
var type = types[n];
var event = type;
var parts = event.split('.');
var baseEvent = parts[0];
var types = typesStr.split(SPACE),
len = types.length,
n, type, event, parts, baseEvent;
for(n = 0; n < len; n++) {
type = types[n];
event = type;
parts = event.split(DOT);
baseEvent = parts[0];
if(parts.length > 1) {
if(baseEvent) {
@@ -99,6 +126,7 @@
*/
remove: function() {
var parent = this.getParent();
if(parent && parent.children) {
parent.children.splice(this.index, 1);
parent._setChildrenIndices();
@@ -111,7 +139,10 @@
* @methodOf Kinetic.Node.prototype
*/
destroy: function() {
var parent = this.getParent(), stage = this.getStage(), dd = Kinetic.DD, go = Kinetic.Global;
var parent = this.getParent(),
stage = this.getStage(),
dd = Kinetic.DD,
go = Kinetic.Global;
// destroy children
while(this.children && this.children.length > 0) {
@@ -141,7 +172,7 @@
* @param {String} attr
*/
getAttr: function(attr) {
var method = 'get' + Kinetic.Type._capitalize(attr);
var method = GET + Kinetic.Type._capitalize(attr);
return this[method]();
},
/**
@@ -169,9 +200,11 @@
* @param {Object} config object containing key value pairs
*/
setAttrs: function(config) {
var key, method;
if(config) {
for(var key in config) {
var method = 'set' + Kinetic.Type._capitalize(key);
for(key in config) {
method = SET + Kinetic.Type._capitalize(key);
// use setter if available
if(Kinetic.Type._isFunction(this[method])) {
this[method](config[key]);
@@ -256,18 +289,20 @@
* @methodOf Kinetic.Node.prototype
*/
getAbsoluteZIndex: function() {
var level = this.getLevel();
var stage = this.getStage();
var that = this;
var index = 0;
var level = this.getLevel(),
stage = this.getStage(),
that = this,
index = 0,
nodes, len, n, child;
function addChildren(children) {
var nodes = [];
var len = children.length;
for(var n = 0; n < len; n++) {
var child = children[n];
nodes = [];
len = children.length;
for(n = 0; n < len; n++) {
child = children[n];
index++;
if(child.nodeType !== 'Shape') {
if(child.nodeType !== SHAPE) {
nodes = nodes.concat(child.getChildren());
}
@@ -280,7 +315,7 @@
addChildren(nodes);
}
}
if(that.nodeType !== 'Stage') {
if(that.nodeType !== STAGE) {
addChildren(that.getStage().getChildren());
}
@@ -294,8 +329,9 @@
* @methodOf Kinetic.Node.prototype
*/
getLevel: function() {
var level = 0;
var parent = this.parent;
var level = 0,
parent = this.parent;
while(parent) {
level++;
parent = parent.parent;
@@ -311,8 +347,8 @@
*/
setPosition: function() {
var pos = Kinetic.Type._getXY([].slice.call(arguments));
this.setAttr('x', pos.x);
this.setAttr('y', pos.y);
this.setAttr(X, pos.x);
this.setAttr(Y, pos.y);
},
/**
* get node position relative to parent
@@ -331,8 +367,9 @@
* @methodOf Kinetic.Node.prototype
*/
getAbsolutePosition: function() {
var trans = this.getAbsoluteTransform();
var o = this.getOffset();
var trans = this.getAbsoluteTransform(),
o = this.getOffset();
trans.translate(o.x, o.y);
return trans.getTranslation();
},
@@ -344,8 +381,10 @@
* @param {Number} y
*/
setAbsolutePosition: function() {
var pos = Kinetic.Type._getXY([].slice.call(arguments));
var trans = this._clearTransform();
var pos = Kinetic.Type._getXY([].slice.call(arguments)),
trans = this._clearTransform(),
it;
// don't clear translation
this.attrs.x = trans.x;
this.attrs.y = trans.y;
@@ -353,7 +392,7 @@
delete trans.y;
// unravel transform
var it = this.getAbsoluteTransform();
it = this.getAbsoluteTransform();
it.invert();
it.translate(pos.x, pos.y);
@@ -373,9 +412,9 @@
* @param {Number} y
*/
move: function() {
var pos = Kinetic.Type._getXY([].slice.call(arguments));
var x = this.getX();
var y = this.getY();
var pos = Kinetic.Type._getXY([].slice.call(arguments)),
x = this.getX(),
y = this.getY();
if(pos.x !== undefined) {
x += pos.x;
@@ -388,7 +427,9 @@
this.setPosition(x, y);
},
_eachAncestorReverse: function(func, includeSelf) {
var family = [], parent = this.getParent();
var family = [],
parent = this.getParent(),
len, n;
// build family by traversing ancestors
if(includeSelf) {
@@ -399,8 +440,8 @@
parent = parent.parent;
}
var len = family.length;
for(var n = 0; n < len; n++) {
len = family.length;
for(n = 0; n < len; n++) {
func(family[n]);
}
},
@@ -440,8 +481,8 @@
* @methodOf Kinetic.Node.prototype
*/
moveUp: function() {
var index = this.index;
var len = this.parent.getChildren().length;
var index = this.index,
len = this.parent.getChildren().length;
if(index < len - 1) {
this.parent.children.splice(index, 1);
this.parent.children.splice(index + 1, 0, this);
@@ -517,13 +558,16 @@
* @methodOf Kinetic.Node.prototype
*/
toObject: function() {
var type = Kinetic.Type, obj = {}, attrs = this.attrs;
var type = Kinetic.Type,
obj = {},
attrs = this.getAttrs(),
key, val;
obj.attrs = {};
// serialize only attributes that are not function, image, DOM, or objects with methods
for(var key in attrs) {
var val = attrs[key];
for(key in attrs) {
val = attrs[key];
if(!type._isFunction(val) && !type._isElement(val) && !(type._isObject(val) && type._hasMethods(val))) {
obj.attrs[key] = val;
}
@@ -597,10 +641,11 @@
*/
getAbsoluteTransform: function() {
// absolute transform
var am = new Kinetic.Transform();
var am = new Kinetic.Transform(),
m;
this._eachAncestorReverse(function(node) {
var m = node.getTransform();
m = node.getTransform();
am.multiply(m);
}, true);
return am;
@@ -645,20 +690,21 @@
*/
clone: function(obj) {
// instantiate new node
var classType = this.shapeType || this.nodeType;
var node = new Kinetic[classType](this.attrs);
var classType = this.shapeType || this.nodeType,
node = new Kinetic[classType](this.attrs),
key, allListeners, len, n, listener;
// copy over user listeners
for(var key in this.eventListeners) {
var allListeners = this.eventListeners[key];
var len = allListeners.length;
for(var n = 0; n < len; n++) {
var listener = allListeners[n];
// copy over listeners
for(key in this.eventListeners) {
allListeners = this.eventListeners[key];
len = allListeners.length;
for(n = 0; n < len; n++) {
listener = allListeners[n];
/*
* don't include kinetic namespaced listeners because
* these are generated by the constructors
*/
if(listener.name.indexOf('kinetic') < 0) {
if(listener.name.indexOf(KINETIC) < 0) {
// if listeners array doesn't exist, then create it
if(!node.eventListeners[key]) {
node.eventListeners[key] = [];
@@ -691,8 +737,12 @@
* is very high quality
*/
toDataURL: function(config) {
config = config || {};
var mimeType = config.mimeType || null, quality = config.quality || null, canvas, context, x = config.x || 0, y = config.y || 0;
var config = config || {},
mimeType = config.mimeType || null,
quality = config.quality || null,
x = config.x || 0,
y = config.y || 0,
canvas, context;
//if width and height are defined, create new canvas to draw on, else reuse stage buffer canvas
if(config.width && config.height) {
@@ -784,10 +834,13 @@
return this.nodeType === selector ? [this] : [];
},
_off: function(type, name) {
for(var i = 0; i < this.eventListeners[type].length; i++) {
if(this.eventListeners[type][i].name === name) {
this.eventListeners[type].splice(i, 1);
if(this.eventListeners[type].length === 0) {
var evtListeners = this.eventListeners[type],
i;
for(i = 0; i < evtListeners.length; i++) {
if(evtListeners[i].name === name) {
evtListeners.splice(i, 1);
if(evtListeners.length === 0) {
delete this.eventListeners[type];
break;
}
@@ -827,18 +880,20 @@
return trans;
},
_setTransform: function(trans) {
for(var key in trans) {
var key;
for(key in trans) {
this.attrs[key] = trans[key];
}
},
_fireBeforeChangeEvent: function(attr, oldVal, newVal) {
this._handleEvent('before' + Kinetic.Type._capitalize(attr) + 'Change', {
this._handleEvent(BEFORE + Kinetic.Type._capitalize(attr) + CHANGE, {
oldVal: oldVal,
newVal: newVal
});
},
_fireChangeEvent: function(attr, oldVal, newVal) {
this._handleEvent(attr + 'Change', {
this._handleEvent(attr + CHANGE, {
oldVal: oldVal,
newVal: newVal
});
@@ -850,10 +905,13 @@
* @param {String} id
*/
setId: function(id) {
var oldId = this.getId(), stage = this.getStage(), go = Kinetic.Global;
var oldId = this.getId(),
stage = this.getStage(),
go = Kinetic.Global;
go._removeId(oldId);
go._addId(this, id);
this.setAttr('id', id);
this.setAttr(ID, id);
},
/**
* set name
@@ -862,31 +920,43 @@
* @param {String} name
*/
setName: function(name) {
var oldName = this.getName(), stage = this.getStage(), go = Kinetic.Global;
var oldName = this.getName(),
stage = this.getStage(),
go = Kinetic.Global;
go._removeName(oldName, this._id);
go._addName(this, name);
this.setAttr('name', name);
this.setAttr(NAME, name);
},
/**
* get node type. Returns 'Stage', 'Layer', 'Group', or 'Shape'
* @name getNodeType
* @methodOf Kinetic.Node.prototype
*/
getNodeType: function() {
return this.nodeType;
},
setAttr: function(key, val) {
var oldVal;
if(val !== undefined) {
var oldVal = this.attrs[key];
oldVal = this.attrs[key];
this._fireBeforeChangeEvent(key, oldVal, val);
this.attrs[key] = val;
this._fireChangeEvent(key, oldVal, val);
}
},
_handleEvent: function(eventType, evt, compareShape) {
if(evt && this.nodeType === 'Shape') {
evt.shape = this;
if(evt && this.nodeType === SHAPE) {
evt.targetNode = this;
}
var stage = this.getStage();
var el = this.eventListeners;
var okayToRun = true;
if(eventType === 'mouseenter' && compareShape && this._id === compareShape._id) {
if(eventType === MOUSEENTER && compareShape && this._id === compareShape._id) {
okayToRun = false;
}
else if(eventType === 'mouseleave' && compareShape && this._id === compareShape._id) {
else if(eventType === MOUSELEAVE && compareShape && this._id === compareShape._id) {
okayToRun = false;
}
@@ -916,20 +986,29 @@
}
},
/*
* draw both scene and hit graphs.
* draw both scene and hit graphs. If the node being drawn is the stage, all of the layers will be cleared and redra
* @name draw
* @methodOf Kinetic.Node.prototype
* the scene renderer
*/
draw: function() {
var layer = this.getLayer();
var layer = this.getLayer(),
evt = {
node: this
};
if(layer && layer.getClearBeforeDraw()) {
layer.getCanvas().clear();
layer.getHitCanvas().clear();
}
this.fire(BEFORE_DRAW, evt);
this.drawScene();
this.drawHit();
this.fire(DRAW, evt);
},
shouldDrawHit: function() {
return this.isVisible() && this.isListening() && !Kinetic.Global.isDragging();
}
};
@@ -948,15 +1027,17 @@
this.addRotationSetter(constructor, arr);
};
Kinetic.Node.addSetter = function(constructor, attr) {
var that = this;
var method = 'set' + Kinetic.Type._capitalize(attr);
var that = this,
method = SET + Kinetic.Type._capitalize(attr);
constructor.prototype[method] = function(val) {
this.setAttr(attr, val);
};
};
Kinetic.Node.addPointSetter = function(constructor, attr) {
var that = this;
var method = 'set' + Kinetic.Type._capitalize(attr);
var that = this,
method = SET + Kinetic.Type._capitalize(attr);
constructor.prototype[method] = function() {
var pos = Kinetic.Type._getXY([].slice.call(arguments));
@@ -975,20 +1056,22 @@
};
};
Kinetic.Node.addRotationSetter = function(constructor, attr) {
var that = this;
var method = 'set' + Kinetic.Type._capitalize(attr);
var that = this,
method = SET + Kinetic.Type._capitalize(attr);
// radians
constructor.prototype[method] = function(val) {
this.setAttr(attr, val);
};
// degrees
constructor.prototype[method + 'Deg'] = function(deg) {
constructor.prototype[method + DEG] = function(deg) {
this.setAttr(attr, Kinetic.Type._degToRad(deg));
};
};
Kinetic.Node.addGetter = function(constructor, attr, def) {
var that = this;
var method = 'get' + Kinetic.Type._capitalize(attr);
var that = this,
method = GET + Kinetic.Type._capitalize(attr);
constructor.prototype[method] = function(arg) {
var val = this.attrs[attr];
if (val === undefined) {
@@ -998,8 +1081,9 @@
};
};
Kinetic.Node.addRotationGetter = function(constructor, attr, def) {
var that = this;
var method = 'get' + Kinetic.Type._capitalize(attr);
var that = this,
method = GET + Kinetic.Type._capitalize(attr);
// radians
constructor.prototype[method] = function() {
var val = this.attrs[attr];
@@ -1009,7 +1093,7 @@
return val;
};
// degrees
constructor.prototype[method + 'Deg'] = function() {
constructor.prototype[method + DEG] = function() {
var val = this.attrs[attr];
if (val === undefined) {
val = def;
@@ -1034,13 +1118,13 @@
return this._createNode(JSON.parse(json), container);
};
Kinetic.Node._createNode = function(obj, container) {
var type;
var type, no, len, n;
// determine type
if(obj.nodeType === 'Shape') {
if(obj.nodeType === SHAPE) {
// add custom shape
if(obj.shapeType === undefined) {
type = 'Shape';
type = SHAPE;
}
// add standard shape
else {
@@ -1056,10 +1140,10 @@
obj.attrs.container = container;
}
var no = new Kinetic[type](obj.attrs);
no = new Kinetic[type](obj.attrs);
if(obj.children) {
var len = obj.children.length;
for(var n = 0; n < len; n++) {
len = obj.children.length;
for(n = 0; n < len; n++) {
no.add(this._createNode(obj.children[n]));
}
}
@@ -1232,18 +1316,6 @@
* @methodOf Kinetic.Node.prototype
*/
Kinetic.Node.prototype.isVisible = Kinetic.Node.prototype.getVisible;
// collection mappings
var collectionMappings = ['on', 'off'];
for(var n = 0; n < 2; n++) {
// induce scope
(function(i) {
var method = collectionMappings[i];
Kinetic.Collection.prototype[method] = function() {
var args = [].slice.call(arguments);
args.unshift(method);
this.apply.apply(this, args);
};
})(n);
}
Kinetic.Collection.mapMethods(['on', 'off']);
})();

View File

@@ -163,6 +163,14 @@
disableDashArray: function() {
this.setAttr('dashArrayEnabled', false);
},
/**
* get shape type. Ex. 'Circle', 'Rect', 'Text', etc.
* @name getShapeType
* @methodOf Kinetic.Shape.prototype
*/
getShapeType: function() {
return this.shapeType;
},
remove: function() {
Kinetic.Node.prototype.remove.call(this);
delete Kinetic.Global.shapes[this.colorKey];
@@ -188,7 +196,7 @@
canvas = this.getLayer().hitCanvas,
context = canvas.getContext();
if(drawFunc && this.isVisible() && this.isListening()) {
if(drawFunc && this.shouldDrawHit()) {
context.save();
canvas._applyLineJoin(this);
canvas._applyAncestorTransforms(this);

View File

@@ -1,7 +1,31 @@
(function() {
// CONSTANTS
var EVENTS = ['mousedown', 'mousemove', 'mouseup', 'mouseout', 'touchstart', 'touchmove', 'touchend'],
var STAGE = 'Stage',
STRING = 'string',
PX = 'px',
MOUSEOUT = 'mouseout',
MOUSELEAVE = 'mouseleave',
MOUSEOUT = 'mouseout',
MOUSEOVER = 'mouseover',
MOUSEENTER = 'mouseenter',
MOUSEMOVE = 'mousemove',
MOUSEDOWN = 'mousedown',
MOUSEUP = 'mouseup',
CLICK = 'click',
DBL_CLICK = 'dblclick',
TOUCHSTART = 'touchstart'
TOUCHEND = 'touchend'
TAP = 'tap',
DBL_TAP = 'dbltap',
TOUCHMOVE = 'touchmove',
DIV = 'div',
RELATIVE = 'relative',
INLINE_BLOCK = 'inline-block',
KINETICJS_CONTENT = 'kineticjs-content',
SPACE = ' ',
CONTAINER = 'container',
EVENTS = [MOUSEDOWN, MOUSEMOVE, MOUSEUP, MOUSEOUT, TOUCHSTART, TOUCHMOVE, TOUCHEND],
// cached variables
eventsLength = EVENTS.length;
@@ -20,20 +44,15 @@
Kinetic.Stage.prototype = {
_initStage: function(config) {
var dd = Kinetic.DD;
this.createAttrs();
// call super constructor
Kinetic.Container.call(this, config);
this._setStageDefaultProperties();
this.nodeType = STAGE;
this.dblClickWindow = 400;
this._id = Kinetic.Global.idCounter++;
this._buildDOM();
this._bindContentEvents();
Kinetic.Global.stages.push(this);
if(dd) {
dd._initDragLayer(this);
}
},
/**
* set container dom element which contains the stage wrapper div element
@@ -42,14 +61,26 @@
* @param {DomElement} container can pass in a dom element or id string
*/
setContainer: function(container) {
/*
* if container is a string, assume it's an id for
* a DOM element
*/
if( typeof container === 'string') {
if( typeof container === STRING) {
container = document.getElementById(container);
}
this.setAttr('container', container);
this.setAttr(CONTAINER, container);
},
draw: function() {
// clear children layers
var children = this.getChildren(),
len = children.length,
n, layer;
for(n = 0; n < len; n++) {
layer = children[n];
if (layer.getClearBeforeDraw()) {
layer.getCanvas().clear();
layer.getHitCanvas().clear();
}
}
Kinetic.Node.prototype.draw.call(this);
},
/**
* draw layer scene graphs
@@ -89,8 +120,11 @@
* @methodOf Kinetic.Stage.prototype
*/
clear: function() {
var layers = this.children;
for(var n = 0; n < layers.length; n++) {
var layers = this.children,
len = length,
n;
for(n = 0; n < len; n++) {
layers[n].clear();
}
},
@@ -102,7 +136,7 @@
Kinetic.Node.prototype.remove.call(this);
if(content && Kinetic.Type._isInDocument(content)) {
this.attrs.container.removeChild(content);
this.getContainer().removeChild(content);
}
},
/**
@@ -122,11 +156,11 @@
return this.touchPos;
},
/**
* get user position which can be a touc position or mouse position
* @name getUserPosition
* get pointer position which can be a touc position or mouse position
* @name getPointerPosition
* @methodOf Kinetic.Stage.prototype
*/
getUserPosition: function() {
getPointerPosition: function() {
return this.getTouchPosition() || this.getMousePosition();
},
getStage: function() {
@@ -158,8 +192,8 @@
* is very high quality
*/
toDataURL: function(config) {
config = config || {};
var mimeType = config.mimeType || null,
var config = config || {},
mimeType = config.mimeType || null,
quality = config.quality || null,
x = config.x || 0,
y = config.y || 0,
@@ -175,9 +209,10 @@
}
function drawLayer(n) {
var layer = layers[n];
var layerUrl = layer.toDataURL();
var imageObj = new Image();
var layer = layers[n],
layerUrl = layer.toDataURL(),
imageObj = new Image();
imageObj.onload = function() {
context.drawImage(imageObj, 0, 0);
@@ -225,20 +260,22 @@
* @param {Object} pos point object
*/
getIntersection: function(pos) {
var shape;
var layers = this.getChildren();
var layers = this.getChildren(),
len = layers.length,
end = len - 1,
n, layer, p, colorKey, shape;
/*
* 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];
for(n = end; n >= 0; n--) {
layer = layers[n];
if(layer.isVisible() && layer.isListening()) {
var p = layer.hitCanvas.context.getImageData(Math.round(pos.x), Math.round(pos.y), 1, 1).data;
p = layer.hitCanvas.context.getImageData(Math.round(pos.x), Math.round(pos.y), 1, 1).data;
// this indicates that a hit pixel may have been found
if(p[3] === 255) {
var colorKey = Kinetic.Type._rgbToHex(p[0], p[1], p[2]);
colorKey = Kinetic.Type._rgbToHex(p[0], p[1], p[2]);
shape = Kinetic.Global.shapes[colorKey];
return {
shape: shape,
@@ -258,19 +295,22 @@
},
_resizeDOM: function() {
if(this.content) {
var width = this.attrs.width;
var height = this.attrs.height;
var width = this.getWidth(),
height = this.getHeight(),
layers = this.getChildren(),
len = layers.length,
n;
// set content dimensions
this.content.style.width = width + 'px';
this.content.style.height = height + 'px';
this.content.style.width = width + PX;
this.content.style.height = height + PX;
this.bufferCanvas.setSize(width, height, 1);
this.hitCanvas.setSize(width, height);
// set user defined layer dimensions
var layers = this.children;
for(var n = 0; n < layers.length; n++) {
var layer = layers[n];
// set pointer defined layer dimensions
for(n = 0; n < len; n++) {
layer = layers[n];
layer.getCanvas().setSize(width, height);
layer.hitCanvas.setSize(width, height);
layer.draw();
@@ -293,23 +333,13 @@
// chainable
return this;
},
/**
* get drag and drop layer
*/
getDragLayer: function() {
return this.dragLayer;
},
getParent: function() {
return null;
},
getLayer: function() {
return null;
},
_isTempDDLayerActive: function() {
var dragLayer = this.dragLayer;
return dragLayer && dragLayer.getStage();
},
_setUserPosition: function(evt) {
_setPointerPosition: function(evt) {
if(!evt) {
evt = window.event;
}
@@ -324,43 +354,45 @@
var that = this,
n, pubEvent, f;
for (var n = 0; n < eventsLength; n++) {
for (n = 0; n < eventsLength; n++) {
pubEvent = EVENTS[n];
f = that['_' + pubEvent];
that.content.addEventListener(pubEvent, f.bind(that), false);
}
},
_mouseout: function(evt) {
this._setUserPosition(evt);
var dd = Kinetic.DD;
// if there's a current target shape, run mouseout handlers
var targetShape = this.targetShape;
if(targetShape && (!dd || !dd.moving)) {
targetShape._handleEvent('mouseout', evt);
targetShape._handleEvent('mouseleave', evt);
this._setPointerPosition(evt);
var go = Kinetic.Global,
targetShape = this.targetShape;
if(targetShape && !go.isDragging()) {
targetShape._handleEvent(MOUSEOUT, evt);
targetShape._handleEvent(MOUSELEAVE, evt);
this.targetShape = null;
}
this.mousePos = undefined;
},
_mousemove: function(evt) {
this._setUserPosition(evt);
var dd = Kinetic.DD;
var obj = this.getIntersection(this.getUserPosition());
this._setPointerPosition(evt);
var go = Kinetic.Global,
dd = Kinetic.DD,
obj = this.getIntersection(this.getPointerPosition()),
shape;
if(obj) {
var shape = obj.shape;
shape = obj.shape;
if(shape) {
if((!dd || !dd.moving) && obj.pixel[3] === 255 && (!this.targetShape || this.targetShape._id !== shape._id)) {
if(!go.isDragging() && obj.pixel[3] === 255 && (!this.targetShape || this.targetShape._id !== shape._id)) {
if(this.targetShape) {
this.targetShape._handleEvent('mouseout', evt, shape);
this.targetShape._handleEvent('mouseleave', evt, shape);
this.targetShape._handleEvent(MOUSEOUT, evt, shape);
this.targetShape._handleEvent(MOUSELEAVE, evt, shape);
}
shape._handleEvent('mouseover', evt, this.targetShape);
shape._handleEvent('mouseenter', evt, this.targetShape);
shape._handleEvent(MOUSEOVER, evt, this.targetShape);
shape._handleEvent(MOUSEENTER, evt, this.targetShape);
this.targetShape = shape;
}
else {
shape._handleEvent('mousemove', evt);
shape._handleEvent(MOUSEMOVE, evt);
}
}
}
@@ -368,51 +400,57 @@
* if no shape was detected, clear target shape and try
* to run mouseout from previous target shape
*/
else if(this.targetShape && (!dd || !dd.moving)) {
this.targetShape._handleEvent('mouseout', evt);
this.targetShape._handleEvent('mouseleave', evt);
else if(this.targetShape && !go.isDragging()) {
this.targetShape._handleEvent(MOUSEOUT, evt);
this.targetShape._handleEvent(MOUSELEAVE, evt);
this.targetShape = null;
}
// start drag and drop
if(dd) {
dd._drag(evt);
}
},
_mousedown: function(evt) {
var obj, dd = Kinetic.DD;
this._setUserPosition(evt);
obj = this.getIntersection(this.getUserPosition());
this._setPointerPosition(evt);
var dd = Kinetic.DD,
go = Kinetic.Global,
obj = this.getIntersection(this.getPointerPosition()),
shape;
if(obj && obj.shape) {
var shape = obj.shape;
shape = obj.shape;
this.clickStart = true;
shape._handleEvent('mousedown', evt);
this.clickStartShape = shape;
shape._handleEvent(MOUSEDOWN, evt);
}
//init stage drag and drop
if(dd && this.attrs.draggable && !dd.node) {
this._startDrag(evt);
if(this.isDraggable() && !dd.node) {
this.startDrag(evt);
}
},
_mouseup: function(evt) {
this._setUserPosition(evt);
var that = this, dd = Kinetic.DD, obj = this.getIntersection(this.getUserPosition());
this._setPointerPosition(evt);
var that = this,
go = Kinetic.Global,
obj = this.getIntersection(this.getPointerPosition()),
shape;
if(obj && obj.shape) {
var shape = obj.shape;
shape._handleEvent('mouseup', evt);
shape = obj.shape;
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 dragging and dropping, or if click doesn't map to
* the correct shape, don't fire click or dbl click event
*/
if(!dd || !dd.moving || !dd.node) {
shape._handleEvent('click', evt);
if(!go.isDragging() && shape._id === this.clickStartShape._id) {
shape._handleEvent(CLICK, evt);
if(this.inDoubleClickWindow) {
shape._handleEvent('dblclick', evt);
shape._handleEvent(DBL_CLICK, evt);
}
this.inDoubleClickWindow = true;
setTimeout(function() {
@@ -424,30 +462,37 @@
this.clickStart = false;
},
_touchstart: function(evt) {
var obj, dd = Kinetic.DD;
this._setPointerPosition(evt);
var dd = Kinetic.DD,
go = Kinetic.Global,
obj = this.getIntersection(this.getPointerPosition()),
shape;
this._setUserPosition(evt);
evt.preventDefault();
obj = this.getIntersection(this.getUserPosition());
if(obj && obj.shape) {
var shape = obj.shape;
shape = obj.shape;
this.tapStart = true;
shape._handleEvent('touchstart', evt);
this.tapStartShape = shape;
shape._handleEvent(TOUCHSTART, evt);
}
// init stage drag and drop
if(dd && this.attrs.draggable && !dd.node) {
this._startDrag(evt);
if(dd && !go.isDragging() && this.isDraggable()) {
this.startDrag(evt);
}
},
_touchend: function(evt) {
this._setUserPosition(evt);
var that = this, dd = Kinetic.DD, obj = this.getIntersection(this.getUserPosition());
this._setPointerPosition(evt);
var that = this,
go = Kinetic.Global,
obj = this.getIntersection(this.getPointerPosition()),
shape;
if(obj && obj.shape) {
var shape = obj.shape;
shape._handleEvent('touchend', evt);
shape = obj.shape;
shape._handleEvent(TOUCHEND, evt);
// detect if tap or double tap occurred
if(this.tapStart) {
@@ -455,11 +500,11 @@
* if dragging and dropping, don't fire tap or dbltap
* event
*/
if(!dd || !dd.moving || !dd.node) {
shape._handleEvent('tap', evt);
if(!go.isDragging() && shape._id === this.tapStartShape._id) {
shape._handleEvent(TAP, evt);
if(this.inDoubleClickWindow) {
shape._handleEvent('dbltap', evt);
shape._handleEvent(DBL_TAP, evt);
}
this.inDoubleClickWindow = true;
setTimeout(function() {
@@ -472,13 +517,16 @@
this.tapStart = false;
},
_touchmove: function(evt) {
this._setUserPosition(evt);
var dd = Kinetic.DD;
this._setPointerPosition(evt);
var dd = Kinetic.DD,
obj = this.getIntersection(this.getPointerPosition()),
shape;
evt.preventDefault();
var obj = this.getIntersection(this.getUserPosition());
if(obj && obj.shape) {
var shape = obj.shape;
shape._handleEvent('touchmove', evt);
shape = obj.shape;
shape._handleEvent(TOUCHMOVE, evt);
}
// start drag and drop
@@ -491,8 +539,9 @@
* @param {Event} evt
*/
_setMousePosition: function(evt) {
var mouseX = evt.clientX - this._getContentPosition().left;
var mouseY = evt.clientY - this._getContentPosition().top;
var mouseX = evt.clientX - this._getContentPosition().left,
mouseY = evt.clientY - this._getContentPosition().top;
this.mousePos = {
x: mouseX,
y: mouseY
@@ -503,12 +552,15 @@
* @param {Event} evt
*/
_setTouchPosition: function(evt) {
var touch, touchX, touchY;
if(evt.touches !== undefined && evt.touches.length === 1) {
// one finger
var touch = evt.touches[0];
// Get the information for finger #1
var touchX = touch.clientX - this._getContentPosition().left;
var touchY = touch.clientY - this._getContentPosition().top;
touch = evt.touches[0];
// get the information for finger #1
touchX = touch.clientX - this._getContentPosition().left;
touchY = touch.clientY - this._getContentPosition().top;
this.touchPos = {
x: touchX,
@@ -531,10 +583,10 @@
*/
_buildDOM: function() {
// content
this.content = document.createElement('div');
this.content.style.position = 'relative';
this.content.style.display = 'inline-block';
this.content.className = 'kineticjs-content';
this.content = document.createElement(DIV);
this.content.style.position = RELATIVE;
this.content.style.display = INLINE_BLOCK;
this.content.className = KINETICJS_CONTENT;
this.attrs.container.appendChild(this.content);
this.bufferCanvas = new Kinetic.SceneCanvas();
@@ -548,23 +600,14 @@
* @param {function} handler
*/
_onContent: function(typesStr, handler) {
var types = typesStr.split(' ');
for(var n = 0; n < types.length; n++) {
var baseEvent = types[n];
var types = typesStr.split(SPACE),
len = types.length,
n, baseEvent;
for(n = 0; n < len; n++) {
baseEvent = types[n];
this.content.addEventListener(baseEvent, handler, false);
}
},
/**
* set defaults
*/
_setStageDefaultProperties: function() {
this.nodeType = 'Stage';
this.dblClickWindow = 400;
this.targetShape = null;
this.mousePos = undefined;
this.clickStart = false;
this.touchPos = undefined;
this.tapStart = false;
}
};
Kinetic.Global.extend(Kinetic.Stage, Kinetic.Container);

View File

@@ -31,11 +31,11 @@
* @param {Number} [config.text.lineHeight] default is 1
* {{NodeParams}}
*/
Kinetic.Plugins.Label = function(config) {
Kinetic.Label = function(config) {
this._initLabel(config);
};
Kinetic.Plugins.Label.prototype = {
Kinetic.Label.prototype = {
_initLabel: function(config) {
var that = this,
text = null;
@@ -45,7 +45,7 @@
Kinetic.Group.call(this, config);
text = new Kinetic.Text(config.text);
this.setText(text);
this.setRect(new Kinetic.Plugins.LabelRect(config.rect));
this.setRect(new Kinetic.LabelRect(config.rect));
this.innerGroup.add(this.getRect());
this.innerGroup.add(text);
this.add(this.innerGroup);
@@ -102,15 +102,15 @@
}
};
Kinetic.Global.extend(Kinetic.Plugins.Label, Kinetic.Group);
Kinetic.Node.addGetterSetter(Kinetic.Plugins.Label, 'text');
Kinetic.Node.addGetterSetter(Kinetic.Plugins.Label, 'rect');
Kinetic.Global.extend(Kinetic.Label, Kinetic.Group);
Kinetic.Node.addGetterSetter(Kinetic.Label, 'text');
Kinetic.Node.addGetterSetter(Kinetic.Label, 'rect');
Kinetic.Plugins.LabelRect = function(config) {
Kinetic.LabelRect = function(config) {
this._initLabelRect(config);
};
Kinetic.Plugins.LabelRect.prototype = {
Kinetic.LabelRect.prototype = {
_initLabelRect: function(config) {
this.createAttrs();
Kinetic.Shape.call(this, config);
@@ -165,9 +165,9 @@
}
};
Kinetic.Global.extend(Kinetic.Plugins.LabelRect, Kinetic.Shape);
Kinetic.Node.addGetterSetter(Kinetic.Plugins.LabelRect, 'pointerDirection', NONE);
Kinetic.Node.addGetterSetter(Kinetic.Plugins.LabelRect, 'pointerWidth', 0);
Kinetic.Node.addGetterSetter(Kinetic.Plugins.LabelRect, 'pointerHeight', 0);
Kinetic.Node.addGetterSetter(Kinetic.Plugins.LabelRect, 'cornerRadius', 0);
Kinetic.Global.extend(Kinetic.LabelRect, Kinetic.Shape);
Kinetic.Node.addGetterSetter(Kinetic.LabelRect, 'pointerDirection', NONE);
Kinetic.Node.addGetterSetter(Kinetic.LabelRect, 'pointerWidth', 0);
Kinetic.Node.addGetterSetter(Kinetic.LabelRect, 'pointerHeight', 0);
Kinetic.Node.addGetterSetter(Kinetic.LabelRect, 'cornerRadius', 0);
})();

View File

@@ -9,11 +9,11 @@
* {{ShapeParams}}
* {{NodeParams}}
*/
Kinetic.Plugins.Path = function(config) {
Kinetic.Path = function(config) {
this._initPath(config);
};
Kinetic.Plugins.Path.prototype = {
Kinetic.Path.prototype = {
_initPath: function(config) {
this.dataArray = [];
var that = this;
@@ -23,9 +23,9 @@
this.shapeType = 'Path';
this._setDrawFuncs();
this.dataArray = Kinetic.Plugins.Path.parsePathData(this.attrs.data);
this.dataArray = Kinetic.Path.parsePathData(this.attrs.data);
this.on('dataChange', function() {
that.dataArray = Kinetic.Plugins.Path.parsePathData(that.attrs.data);
that.dataArray = Kinetic.Path.parsePathData(that.attrs.data);
});
},
drawFunc: function(canvas) {
@@ -72,16 +72,16 @@
canvas.fillStroke(this);
}
};
Kinetic.Global.extend(Kinetic.Plugins.Path, Kinetic.Shape);
Kinetic.Global.extend(Kinetic.Path, Kinetic.Shape);
/*
* Utility methods written by jfollas to
* handle length and point measurements
*/
Kinetic.Plugins.Path.getLineLength = function(x1, y1, x2, y2) {
Kinetic.Path.getLineLength = function(x1, y1, x2, y2) {
return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
};
Kinetic.Plugins.Path.getPointOnLine = function(dist, P1x, P1y, P2x, P2y, fromX, fromY) {
Kinetic.Path.getPointOnLine = function(dist, P1x, P1y, P2x, P2y, fromX, fromY) {
if(fromX === undefined) {
fromX = P1x;
}
@@ -129,7 +129,7 @@
return pt;
};
Kinetic.Plugins.Path.getPointOnCubicBezier = function(pct, P1x, P1y, P2x, P2y, P3x, P3y, P4x, P4y) {
Kinetic.Path.getPointOnCubicBezier = function(pct, P1x, P1y, P2x, P2y, P3x, P3y, P4x, P4y) {
function CB1(t) {
return t * t * t;
}
@@ -150,7 +150,7 @@
y: y
};
};
Kinetic.Plugins.Path.getPointOnQuadraticBezier = function(pct, P1x, P1y, P2x, P2y, P3x, P3y) {
Kinetic.Path.getPointOnQuadraticBezier = function(pct, P1x, P1y, P2x, P2y, P3x, P3y) {
function QB1(t) {
return t * t;
}
@@ -168,7 +168,7 @@
y: y
};
};
Kinetic.Plugins.Path.getPointOnEllipticalArc = function(cx, cy, rx, ry, theta, psi) {
Kinetic.Path.getPointOnEllipticalArc = function(cx, cy, rx, ry, theta, psi) {
var cosPsi = Math.cos(psi), sinPsi = Math.sin(psi);
var pt = {
x: rx * Math.cos(theta),
@@ -185,7 +185,7 @@
* L data for the purpose of high performance Path
* rendering
*/
Kinetic.Plugins.Path.parsePathData = function(data) {
Kinetic.Path.parsePathData = function(data) {
// Path Data Segment must begin with a moveTo
//m (x y)+ Relative moveTo (subsequent points are treated as lineTo)
//M (x y)+ Absolute moveTo (subsequent points are treated as lineTo)
@@ -422,9 +422,9 @@
return ca;
};
Kinetic.Plugins.Path.calcLength = function(x, y, cmd, points) {
Kinetic.Path.calcLength = function(x, y, cmd, points) {
var len, p1, p2;
var path = Kinetic.Plugins.Path;
var path = Kinetic.Path;
switch (cmd) {
case 'L':
@@ -486,7 +486,7 @@
return 0;
};
Kinetic.Plugins.Path.convertEndpointToCenterParameterization = function(x1, y1, x2, y2, fa, fs, rx, ry, psiDeg) {
Kinetic.Path.convertEndpointToCenterParameterization = function(x1, y1, x2, y2, fa, fs, rx, ry, psiDeg) {
// Derived from: http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
var psi = psiDeg * (Math.PI / 180.0);
var xp = Math.cos(psi) * (x1 - x2) / 2.0 + Math.sin(psi) * (y1 - y2) / 2.0;
@@ -543,7 +543,7 @@
return [cx, cy, rx, ry, theta, dTheta, psi, fs];
};
// add getters setters
Kinetic.Node.addGetterSetter(Kinetic.Plugins.Path, 'data');
Kinetic.Node.addGetterSetter(Kinetic.Path, 'data');
/**
* set SVG path data string. This method
@@ -551,13 +551,13 @@
* into a data array. Currently supported SVG data:
* M, m, L, l, H, h, V, v, Q, q, T, t, C, c, S, s, A, a, Z, z
* @name setData
* @methodOf Kinetic.Plugins.Path.prototype
* @methodOf Kinetic.Path.prototype
* @param {String} SVG path command string
*/
/**
* get SVG path data string
* @name getData
* @methodOf Kinetic.Plugins.Path.prototype
* @methodOf Kinetic.Path.prototype
*/
})();

View File

@@ -9,11 +9,11 @@
* {{ShapeParams}}
* {{NodeParams}}
*/
Kinetic.Plugins.RegularPolygon = function(config) {
Kinetic.RegularPolygon = function(config) {
this._initRegularPolygon(config);
};
Kinetic.Plugins.RegularPolygon.prototype = {
Kinetic.RegularPolygon.prototype = {
_initRegularPolygon: function(config) {
this.createAttrs();
@@ -36,35 +36,35 @@
canvas.fillStroke(this);
}
};
Kinetic.Global.extend(Kinetic.Plugins.RegularPolygon, Kinetic.Shape);
Kinetic.Global.extend(Kinetic.RegularPolygon, Kinetic.Shape);
// add getters setters
Kinetic.Node.addGetterSetter(Kinetic.Plugins.RegularPolygon, 'radius', 0);
Kinetic.Node.addGetterSetter(Kinetic.Plugins.RegularPolygon, 'sides', 0);
Kinetic.Node.addGetterSetter(Kinetic.RegularPolygon, 'radius', 0);
Kinetic.Node.addGetterSetter(Kinetic.RegularPolygon, 'sides', 0);
/**
* set radius
* @name setRadius
* @methodOf Kinetic.Plugins.RegularPolygon.prototype
* @methodOf Kinetic.RegularPolygon.prototype
* @param {Number} radius
*/
/**
* set number of sides
* @name setSides
* @methodOf Kinetic.Plugins.RegularPolygon.prototype
* @methodOf Kinetic.RegularPolygon.prototype
* @param {int} sides
*/
/**
* get radius
* @name getRadius
* @methodOf Kinetic.Plugins.RegularPolygon.prototype
* @methodOf Kinetic.RegularPolygon.prototype
*/
/**
* get number of sides
* @name getSides
* @methodOf Kinetic.Plugins.RegularPolygon.prototype
* @methodOf Kinetic.RegularPolygon.prototype
*/
})();

View File

@@ -10,11 +10,11 @@
* {{ShapeParams}}
* {{NodeParams}}
*/
Kinetic.Plugins.Star = function(config) {
Kinetic.Star = function(config) {
this._initStar(config);
};
Kinetic.Plugins.Star.prototype = {
Kinetic.Star.prototype = {
_initStar: function(config) {
this.createAttrs();
@@ -40,49 +40,49 @@
canvas.fillStroke(this);
}
};
Kinetic.Global.extend(Kinetic.Plugins.Star, Kinetic.Shape);
Kinetic.Global.extend(Kinetic.Star, Kinetic.Shape);
// add getters setters
Kinetic.Node.addGetterSetter(Kinetic.Plugins.Star, 'numPoints', 0);
Kinetic.Node.addGetterSetter(Kinetic.Plugins.Star, 'innerRadius', 0);
Kinetic.Node.addGetterSetter(Kinetic.Plugins.Star, 'outerRadius', 0);
Kinetic.Node.addGetterSetter(Kinetic.Star, 'numPoints', 0);
Kinetic.Node.addGetterSetter(Kinetic.Star, 'innerRadius', 0);
Kinetic.Node.addGetterSetter(Kinetic.Star, 'outerRadius', 0);
/**
* set number of points
* @name setNumPoints
* @methodOf Kinetic.Plugins.Star.prototype
* @methodOf Kinetic.Star.prototype
* @param {Integer} points
*/
/**
* set outer radius
* @name setOuterRadius
* @methodOf Kinetic.Plugins.Star.prototype
* @methodOf Kinetic.Star.prototype
* @param {Number} radius
*/
/**
* set inner radius
* @name setInnerRadius
* @methodOf Kinetic.Plugins.Star.prototype
* @methodOf Kinetic.Star.prototype
* @param {Number} radius
*/
/**
* get number of points
* @name getNumPoints
* @methodOf Kinetic.Plugins.Star.prototype
* @methodOf Kinetic.Star.prototype
*/
/**
* get outer radius
* @name getOuterRadius
* @methodOf Kinetic.Plugins.Star.prototype
* @methodOf Kinetic.Star.prototype
*/
/**
* get inner radius
* @name getInnerRadius
* @methodOf Kinetic.Plugins.Star.prototype
* @methodOf Kinetic.Star.prototype
*/
})();

View File

@@ -16,7 +16,7 @@
* {{ShapeParams}}
* {{NodeParams}}
*/
Kinetic.Plugins.TextPath = function(config) {
Kinetic.TextPath = function(config) {
this._initTextPath(config);
};
@@ -27,7 +27,7 @@
context.strokeText(this.partialText, 0, 0);
}
Kinetic.Plugins.TextPath.prototype = {
Kinetic.TextPath.prototype = {
_initTextPath: function(config) {
var that = this;
@@ -46,9 +46,9 @@
this.shapeType = 'TextPath';
this._setDrawFuncs();
this.dataArray = Kinetic.Plugins.Path.parsePathData(this.attrs.data);
this.dataArray = Kinetic.Path.parsePathData(this.attrs.data);
this.on('dataChange', function() {
that.dataArray = Kinetic.Plugins.Path.parsePathData(this.attrs.data);
that.dataArray = Kinetic.Path.parsePathData(this.attrs.data);
});
// update text data for certain attr changes
var attrs = ['text', 'textStroke', 'textStrokeWidth'];
@@ -97,7 +97,7 @@
/**
* get text width in pixels
* @name getTextWidth
* @methodOf Kinetic.Plugins.TextPath.prototype
* @methodOf Kinetic.TextPath.prototype
*/
getTextWidth: function() {
return this.textWidth;
@@ -105,7 +105,7 @@
/**
* get text height in pixels
* @name getTextHeight
* @methodOf Kinetic.Plugins.TextPath.prototype
* @methodOf Kinetic.TextPath.prototype
*/
getTextHeight: function() {
return this.textHeight;
@@ -113,7 +113,7 @@
/**
* set text
* @name setText
* @methodOf Kinetic.Plugins.TextPath.prototype
* @methodOf Kinetic.TextPath.prototype
* @param {String} text
*/
setText: function(text) {
@@ -201,8 +201,8 @@
switch (pathCmd.command) {
case 'L':
if(Kinetic.Plugins.Path.getLineLength(p0.x, p0.y, pathCmd.points[0], pathCmd.points[1]) > glyphWidth) {
p1 = Kinetic.Plugins.Path.getPointOnLine(glyphWidth, p0.x, p0.y, pathCmd.points[0], pathCmd.points[1], p0.x, p0.y);
if(Kinetic.Path.getLineLength(p0.x, p0.y, pathCmd.points[0], pathCmd.points[1]) > glyphWidth) {
p1 = Kinetic.Path.getPointOnLine(glyphWidth, p0.x, p0.y, pathCmd.points[0], pathCmd.points[1], p0.x, p0.y);
}
else
pathCmd = undefined;
@@ -227,7 +227,7 @@
currentT = end;
needNewSegment = true;
}
p1 = Kinetic.Plugins.Path.getPointOnEllipticalArc(pathCmd.points[0], pathCmd.points[1], pathCmd.points[2], pathCmd.points[3], currentT, pathCmd.points[6]);
p1 = Kinetic.Path.getPointOnEllipticalArc(pathCmd.points[0], pathCmd.points[1], pathCmd.points[2], pathCmd.points[3], currentT, pathCmd.points[6]);
break;
case 'C':
if(currentT === 0) {
@@ -245,7 +245,7 @@
currentT = 1.0;
needNewSegment = true;
}
p1 = Kinetic.Plugins.Path.getPointOnCubicBezier(currentT, pathCmd.start.x, pathCmd.start.y, pathCmd.points[0], pathCmd.points[1], pathCmd.points[2], pathCmd.points[3], pathCmd.points[4], pathCmd.points[5]);
p1 = Kinetic.Path.getPointOnCubicBezier(currentT, pathCmd.start.x, pathCmd.start.y, pathCmd.points[0], pathCmd.points[1], pathCmd.points[2], pathCmd.points[3], pathCmd.points[4], pathCmd.points[5]);
break;
case 'Q':
if(currentT === 0)
@@ -259,13 +259,13 @@
currentT = 1.0;
needNewSegment = true;
}
p1 = Kinetic.Plugins.Path.getPointOnQuadraticBezier(currentT, pathCmd.start.x, pathCmd.start.y, pathCmd.points[0], pathCmd.points[1], pathCmd.points[2], pathCmd.points[3]);
p1 = Kinetic.Path.getPointOnQuadraticBezier(currentT, pathCmd.start.x, pathCmd.start.y, pathCmd.points[0], pathCmd.points[1], pathCmd.points[2], pathCmd.points[3]);
break;
}
if(p1 !== undefined) {
currLen = Kinetic.Plugins.Path.getLineLength(p0.x, p0.y, p1.x, p1.y);
currLen = Kinetic.Path.getLineLength(p0.x, p0.y, p1.x, p1.y);
}
if(needNewSegment) {
@@ -282,7 +282,7 @@
if(p0 === undefined || p1 === undefined)
break;
var width = Kinetic.Plugins.Path.getLineLength(p0.x, p0.y, p1.x, p1.y);
var width = Kinetic.Path.getLineLength(p0.x, p0.y, p1.x, p1.y);
// Note: Since glyphs are rendered one at a time, any kerning pair data built into the font will not be used.
// Can foresee having a rough pair table built in that the developer can override as needed.
@@ -290,7 +290,7 @@
var kern = 0;
// placeholder for future implementation
var midpoint = Kinetic.Plugins.Path.getPointOnLine(kern + width / 2.0, p0.x, p0.y, p1.x, p1.y);
var midpoint = Kinetic.Path.getPointOnLine(kern + width / 2.0, p0.x, p0.y, p1.x, p1.y);
var rotation = Math.atan2((p1.y - p0.y), (p1.x - p0.x));
this.glyphInfo.push({
@@ -307,59 +307,59 @@
};
// map TextPath methods to Text
Kinetic.Plugins.TextPath.prototype._getContextFont = Kinetic.Text.prototype._getContextFont;
Kinetic.TextPath.prototype._getContextFont = Kinetic.Text.prototype._getContextFont;
Kinetic.Global.extend(Kinetic.Plugins.TextPath, Kinetic.Shape);
Kinetic.Global.extend(Kinetic.TextPath, Kinetic.Shape);
// add setters and getters
Kinetic.Node.addGetterSetter(Kinetic.Plugins.TextPath, 'fontFamily', CALIBRI);
Kinetic.Node.addGetterSetter(Kinetic.Plugins.TextPath, 'fontSize', 12);
Kinetic.Node.addGetterSetter(Kinetic.Plugins.TextPath, 'fontStyle', NORMAL);
Kinetic.Node.addGetterSetter(Kinetic.TextPath, 'fontFamily', CALIBRI);
Kinetic.Node.addGetterSetter(Kinetic.TextPath, 'fontSize', 12);
Kinetic.Node.addGetterSetter(Kinetic.TextPath, 'fontStyle', NORMAL);
Kinetic.Node.addGetter(Kinetic.Plugins.TextPath, 'text', EMPTY_STRING);
Kinetic.Node.addGetter(Kinetic.TextPath, 'text', EMPTY_STRING);
/**
* set font family
* @name setFontFamily
* @methodOf Kinetic.Plugins.TextPath.prototype
* @methodOf Kinetic.TextPath.prototype
* @param {String} fontFamily
*/
/**
* set font size
* @name setFontSize
* @methodOf Kinetic.Plugins.TextPath.prototype
* @methodOf Kinetic.TextPath.prototype
* @param {int} fontSize
*/
/**
* set font style. Can be 'normal', 'italic', or 'bold'. 'normal' is the default.
* @name setFontStyle
* @methodOf Kinetic.Plugins.TextPath.prototype
* @methodOf Kinetic.TextPath.prototype
* @param {String} fontStyle
*/
/**
* get font family
* @name getFontFamily
* @methodOf Kinetic.Plugins.TextPath.prototype
* @methodOf Kinetic.TextPath.prototype
*/
/**
* get font size
* @name getFontSize
* @methodOf Kinetic.Plugins.TextPath.prototype
* @methodOf Kinetic.TextPath.prototype
*/
/**
* get font style
* @name getFontStyle
* @methodOf Kinetic.Plugins.TextPath.prototype
* @methodOf Kinetic.TextPath.prototype
*/
/**
* get text
* @name getText
* @methodOf Kinetic.Plugins.TextPath.prototype
* @methodOf Kinetic.TextPath.prototype
*/
})();

View File

@@ -1,4 +1,8 @@
(function() {
// CONSTANTS
var IMAGE = 'Image',
CROP = 'crop';
/**
* Image constructor
* @constructor
@@ -15,38 +19,40 @@
Kinetic.Image.prototype = {
_initImage: function(config) {
var that = this;
// call super constructor
Kinetic.Shape.call(this, config);
this.shapeType = 'Image';
this.shapeType = IMAGE;
this._setDrawFuncs();
var that = this;
this.on('imageChange', function(evt) {
that._syncSize();
});
this._syncSize();
},
drawFunc: function(canvas) {
var width = this.getWidth(), height = this.getHeight(), params, that = this, context = canvas.getContext();
var width = this.getWidth(),
height = this.getHeight(),
params,
that = this,
context = canvas.getContext(),
image = this.getImage(),
crop = this.getCrop(),
cropX, cropY, cropWidth, cropHeight;
context.beginPath();
context.rect(0, 0, width, height);
context.closePath();
canvas.fillStroke(this);
if(this.attrs.image) {
if(image) {
// if cropping
if(this.attrs.crop && this.attrs.crop.width && this.attrs.crop.height) {
var cropX = this.attrs.crop.x || 0;
var cropY = this.attrs.crop.y || 0;
var cropWidth = this.attrs.crop.width;
var cropHeight = this.attrs.crop.height;
params = [this.attrs.image, cropX, cropY, cropWidth, cropHeight, 0, 0, width, height];
if(crop) {
cropX = crop.x || 0;
cropY = crop.y || 0;
cropWidth = crop.width || 0;
cropHeight = crop.height || 0;
params = [image, cropX, cropY, cropWidth, cropHeight, 0, 0, width, height];
}
// no cropping
else {
params = [this.attrs.image, 0, 0, width, height];
params = [image, 0, 0, width, height];
}
if(this.hasShadow()) {
@@ -57,12 +63,13 @@
else {
this._drawImage(context, params);
}
}
},
drawHitFunc: function(canvas) {
var width = this.getWidth(), height = this.getHeight(), imageHitRegion = this.imageHitRegion, appliedShadow = false, context = canvas.getContext();
var width = this.getWidth(),
height = this.getHeight(),
imageHitRegion = this.imageHitRegion,
context = canvas.getContext();
if(imageHitRegion) {
context.drawImage(imageHitRegion, 0, 0, width, height);
@@ -89,16 +96,20 @@
* filter has been applied
*/
applyFilter: function(filter, config, callback) {
var canvas = new Kinetic.Canvas(this.attrs.image.width, this.attrs.image.height);
var context = canvas.getContext();
context.drawImage(this.attrs.image, 0, 0);
var image = this.getImage(),
canvas = new Kinetic.Canvas({
width: image.width,
height: image.height
}),
context = canvas.getContext(),
that = this;
context.drawImage(image, 0, 0);
try {
var imageData = context.getImageData(0, 0, canvas.getWidth(), canvas.getHeight());
filter(imageData, config);
var that = this;
Kinetic.Type._getImage(imageData, function(imageObj) {
that.setImage(imageObj);
if(callback) {
callback();
}
@@ -119,11 +130,12 @@
* @param {Number} config.height
*/
setCrop: function() {
var config = [].slice.call(arguments);
var pos = Kinetic.Type._getXY(config);
var size = Kinetic.Type._getSize(config);
var both = Kinetic.Type._merge(pos, size);
this.setAttr('crop', Kinetic.Type._merge(both, this.getCrop()));
var config = [].slice.call(arguments),
pos = Kinetic.Type._getXY(config),
size = Kinetic.Type._getSize(config),
both = Kinetic.Type._merge(pos, size);
this.setAttr(CROP, Kinetic.Type._merge(both, this.getCrop()));
},
/**
* create image hit region which enables more accurate hit detection mapping of the image
@@ -134,22 +146,33 @@
* the image hit region has been created
*/
createImageHitRegion: function(callback) {
var canvas = new Kinetic.Canvas(this.attrs.width, this.attrs.height);
var context = canvas.getContext();
context.drawImage(this.attrs.image, 0, 0);
var that = this,
width = this.getWidth(),
height = this.getHeight(),
canvas = new Kinetic.Canvas({
width: width,
height: height
}),
context = canvas.getContext(),
image = this.getImage(),
imageData, data, rgbColorKey, i, n;
context.drawImage(image, 0, 0);
try {
var imageData = context.getImageData(0, 0, canvas.getWidth(), canvas.getHeight());
var data = imageData.data;
var rgbColorKey = Kinetic.Type._hexToRgb(this.colorKey);
imageData = context.getImageData(0, 0, width, height);
data = imageData.data;
rgbColorKey = Kinetic.Type._hexToRgb(this.colorKey);
// replace non transparent pixels with color key
for(var i = 0, n = data.length; i < n; i += 4) {
data[i] = rgbColorKey.r;
data[i + 1] = rgbColorKey.g;
data[i + 2] = rgbColorKey.b;
// i+3 is alpha (the fourth element)
for(i = 0, n = data.length; i < n; i += 4) {
if (data[i + 3] > 0) {
data[i] = rgbColorKey.r;
data[i + 1] = rgbColorKey.g;
data[i + 2] = rgbColorKey.b;
}
}
var that = this;
Kinetic.Type._getImage(imageData, function(imageObj) {
that.imageHitRegion = imageObj;
if(callback) {
@@ -169,15 +192,13 @@
clearImageHitRegion: function() {
delete this.imageHitRegion;
},
_syncSize: function() {
if(this.attrs.image) {
if(!this.attrs.width) {
this.setWidth(this.attrs.image.width);
}
if(!this.attrs.height) {
this.setHeight(this.attrs.image.height);
}
}
getWidth: function() {
var image = this.getImage();
return this.attrs.width || (image ? image.width : 0);
},
getHeight: function() {
var image = this.getImage();
return this.attrs.height || (image ? image.height : 0);
},
_drawImage: function(context, a) {
if(a.length === 5) {

View File

@@ -318,7 +318,7 @@
Kinetic.Node.addGetterSetter(Kinetic.Text, 'padding', 0);
Kinetic.Node.addGetterSetter(Kinetic.Text, 'align', LEFT);
Kinetic.Node.addGetterSetter(Kinetic.Text, 'lineHeight', 1);
Kinetic.Node.addGetterSetter(Kinetic.Text, 'wrap', NONE);
Kinetic.Node.addGetterSetter(Kinetic.Text, 'wrap', WORD);
Kinetic.Node.addGetter(Kinetic.Text, TEXT, EMPTY_STRING);

View File

@@ -32,20 +32,9 @@
context.closePath();
canvas.fillStroke(this);
},
/**
* set angle in degrees
* @name setAngleDeg
* @methodOf Kinetic.Wedge.prototype
* @param {Number} deg
*/
setAngleDeg: function(deg) {
this.setAngle(Kinetic.Type._degToRad(deg));
},
/**
* set angle in degrees
* @name getAngleDeg
* @methodOf Kinetic.Wedge.prototype
*/
getAngleDeg: function() {
return Kinetic.Type._radToDeg(this.getAngle());
}

View File

@@ -14,22 +14,6 @@
return this;
}
Kinetic.Collection.prototype = new Array();
/**
* apply a method to all nodes in the array
* @name apply
* @methodOf Kinetic.Collection.prototype
* @param {String} method
* @param val
*/
Kinetic.Collection.prototype.apply = function(method) {
args = [].slice.call(arguments);
args.shift();
for(var n = 0; n < this.length; n++) {
if(Kinetic.Type._isFunction(this[n][method])) {
this[n][method].apply(this[n], args);
}
}
};
/**
* iterate through node array
* @name each
@@ -38,7 +22,28 @@
*/
Kinetic.Collection.prototype.each = function(func) {
for(var n = 0; n < this.length; n++) {
func.call(this[n], n, this[n]);
func(this[n], n);
}
};
Kinetic.Collection.mapMethods = function(arr) {
var leng = arr.length,
n;
for(n = 0; n < leng; n++) {
// induce scope
(function(i) {
var method = arr[i];
Kinetic.Collection.prototype[method] = function() {
var len = this.length,
i;
args = [].slice.call(arguments);
for(i = 0; i < len; i++) {
this[i][method].apply(this[i], args);
}
};
})(n);
}
};
})();

View File

@@ -1,4 +1,13 @@
(function() {
// CONSTANTS
var CANVAS = 'canvas',
CONTEXT_2D = '2d',
OBJECT_ARRAY = '[object Array]',
OBJECT_NUMBER = '[object Number]',
OBJECT_STRING = '[object String]',
PI_OVER_DEG180 = Math.PI / 180,
DEG180_OVER_PI = 180 / Math.PI;
/*
* utilities that handle data type detection, conversion, and manipulation
*/
@@ -16,27 +25,30 @@
return (!!obj && obj.constructor == Object);
},
_isArray: function(obj) {
return Object.prototype.toString.call(obj) == '[object Array]';
return Object.prototype.toString.call(obj) == OBJECT_ARRAY;
},
_isNumber: function(obj) {
return Object.prototype.toString.call(obj) == '[object Number]';
return Object.prototype.toString.call(obj) == OBJECT_NUMBER;
},
_isString: function(obj) {
return Object.prototype.toString.call(obj) == '[object String]';
return Object.prototype.toString.call(obj) == OBJECT_STRING;
},
/*
* other utils
*/
_hasMethods: function(obj) {
var names = [];
for(var key in obj) {
if(this._isFunction(obj[key]))
var names = [],
key;
for(key in obj) {
if(this._isFunction(obj[key])) {
names.push(key);
}
}
return names.length > 0;
},
_isInDocument: function(el) {
while( el = el.parentNode) {
while(el = el.parentNode) {
if(el == document) {
return true;
}
@@ -229,6 +241,8 @@
* arg can be an image object or image data
*/
_getImage: function(arg, callback) {
var imageObj, canvas, context, dataUrl;
// if arg is null or undefined
if(!arg) {
callback(null);
@@ -241,8 +255,7 @@
// if arg is a string, then it's a data url
else if(this._isString(arg)) {
var imageObj = new Image();
/** @ignore */
imageObj = new Image();
imageObj.onload = function() {
callback(imageObj);
}
@@ -251,14 +264,13 @@
//if arg is an object that contains the data property, it's an image object
else if(arg.data) {
var canvas = document.createElement('canvas');
canvas = document.createElement(CANVAS);
canvas.width = arg.width;
canvas.height = arg.height;
var context = canvas.getContext('2d');
context = canvas.getContext(CONTEXT_2D);
context.putImageData(arg, 0, 0);
var dataUrl = canvas.toDataURL();
var imageObj = new Image();
/** @ignore */
dataUrl = canvas.toDataURL();
imageObj = new Image();
imageObj.onload = function() {
callback(imageObj);
}
@@ -280,9 +292,10 @@
};
},
_getRandomColorKey: function() {
var r = (Math.random() * 255) | 0;
var g = (Math.random() * 255) | 0;
var b = (Math.random() * 255) | 0;
var r = (Math.random() * 255) | 0,
g = (Math.random() * 255) | 0,
b = (Math.random() * 255) | 0;
return this._rgbToHex(r, g, b);
},
// o1 takes precedence over o2
@@ -312,10 +325,10 @@
return retObj;
},
_degToRad: function(deg) {
return deg * Math.PI / 180;
return deg * PI_OVER_DEG180;
},
_radToDeg: function(rad) {
return rad * 180 / Math.PI;
return rad * DEG180_OVER_PI;
},
_capitalize: function(str) {
return str.charAt(0).toUpperCase() + str.slice(1);