diff --git a/Thorfile b/Thorfile index 7c6b3385..af3924b8 100644 --- a/Thorfile +++ b/Thorfile @@ -3,7 +3,7 @@ require 'json/pure' class Build < Thor # This is the list of files to concatenate. The first file will appear at the top of the final file. All files are relative to the lib directory. FILES = [ - "license.js", "src/Global.js", "src/util/Type.js", "src/util/Class.js", "src/Animation.js", "src/Node.js", "src/Container.js", "src/Stage.js", + "license.js", "src/Global.js", "src/util/Type.js", "src/util/Canvas.js", "src/util/Class.js", "src/Animation.js", "src/Node.js", "src/Container.js", "src/Stage.js", "src/Layer.js", "src/Group.js", "src/Shape.js", "src/shapes/Rect.js", "src/shapes/Ellipse.js", "src/shapes/Image.js", "src/shapes/Sprite.js", "src/shapes/Polygon.js", "src/shapes/RegularPolygon.js", "src/shapes/Star.js", "src/shapes/Text.js", "src/shapes/Line.js", "src/shapes/Path.js", "src/util/Transform.js", "src/Transition.js", "src/util/Tween.js", "src/filters/Grayscale.js" diff --git a/dist/kinetic-core.js b/dist/kinetic-core.js index 552b01f0..c4607608 100644 --- a/dist/kinetic-core.js +++ b/dist/kinetic-core.js @@ -3,7 +3,7 @@ * http://www.kineticjs.com/ * Copyright 2012, Eric Rowell * Licensed under the MIT or GPL Version 2 licenses. - * Date: Jul 17 2012 + * Date: Jul 18 2012 * * Copyright (C) 2011 - 2012 by Eric Rowell * @@ -323,6 +323,103 @@ Kinetic.Type = { } }; +/////////////////////////////////////////////////////////////////////// +// Canvas +/////////////////////////////////////////////////////////////////////// +/** + * Canvas wrapper constructor + * @constructor + * @param {Number} width + * @param {Number} height + */ +Kinetic.Canvas = function(width, height) { + this.element = document.createElement('canvas'); + this.context = this.element.getContext('2d'); + + // set dimensions + this.element.width = width; + this.element.height = height; +}; + +Kinetic.Canvas.prototype = { + /** + * clear canvas + * @name clear + * @methodOf Kinetic.Canvas.prototype + */ + clear: function() { + var context = this.getContext(); + var el = this.getElement(); + context.clearRect(0, 0, el.width, el.height); + }, + /** + * get element + * @name getElement + * @methodOf Kinetic.Canvas.prototype + */ + getElement: function() { + return this.element; + }, + /** + * get context + * @name getContext + * @methodOf Kinetic.Canvas.prototype + */ + getContext: function() { + return this.context; + }, + /** + * set width + * @name setWidth + * @methodOf Kinetic.Canvas.prototype + */ + setWidth: function(width) { + this.element.width = width; + }, + /** + * set height + * @name setHeight + * @methodOf Kinetic.Canvas.prototype + */ + setHeight: function(height) { + this.element.height = height; + }, + /** + * set size + * @name setSize + * @methodOf Kinetic.Canvas.prototype + */ + setSize: function(width, height) { + this.setWidth(width); + this.setHeight(height); + }, + /** + * strip away all functions that draw pixels onto the bitmap + * @name strip + * @methodOf Kinetic.Canvas.prototype + * @param {CanvasContext} context + */ + strip: function() { + var context = this.context; + context.stroke = function() { + }; + context.fill = function() { + }; + context.fillRect = function(x, y, width, height) { + context.rect(x, y, width, height); + }; + context.strokeRect = function(x, y, width, height) { + context.rect(x, y, width, height); + }; + context.drawImage = function() { + }; + context.fillText = function() { + }; + context.strokeText = function() { + }; + } +}; + /////////////////////////////////////////////////////////////////////// // Class /////////////////////////////////////////////////////////////////////// @@ -867,7 +964,10 @@ Kinetic.Node = Kinetic.Class.extend({ * @methodOf Kinetic.Node.prototype */ getAbsolutePosition: function() { - return this.getAbsoluteTransform().getTranslation(); + var trans = this.getAbsoluteTransform(); + var o = this.getOffset(); + trans.translate(o.x, o.y); + return trans.getTranslation(); }, /** * set absolute position relative to stage @@ -897,9 +997,16 @@ Kinetic.Node = Kinetic.Class.extend({ x: 1, y: 1 }; + this.attrs.offset = { + x: 0, + y: 0 + }; + + var o = this.getOffset(); // unravel transform var it = this.getAbsoluteTransform(); + it.invert(); it.translate(pos.x, pos.y); pos = { @@ -915,6 +1022,10 @@ Kinetic.Node = Kinetic.Class.extend({ x: scale.x, y: scale.y }; + this.attrs.offset = { + x: offset.x, + y: offset.y + }; }, /** * move node by an amount @@ -1208,7 +1319,6 @@ Kinetic.Node = Kinetic.Class.extend({ for(var n = 0; n < family.length; n++) { var node = family[n]; var m = node.getTransform(); - am.multiply(m); } @@ -1284,14 +1394,14 @@ Kinetic.Node = Kinetic.Class.extend({ saveImageData: function() { try { var stage = this.getStage(); - var bufferLayer = stage.bufferLayer; - var bufferLayerContext = bufferLayer.getContext(); + var bufferCanvas = stage.bufferCanvas; + var bufferContext = bufferCanvas.getContext(); var width = stage.getWidth(); var height = stage.getHeight(); - bufferLayer.clear(); - this._draw(bufferLayer); - var imageData = bufferLayerContext.getImageData(0, 0, width, height); + bufferCanvas.clear(); + this._draw(bufferCanvas); + var imageData = bufferContext.getImageData(0, 0, width, height); this.imageData = imageData; } catch(e) { @@ -1319,24 +1429,23 @@ Kinetic.Node = Kinetic.Class.extend({ * specified, then "image/png" will result. For "image/jpeg", specify a quality * level as quality (range 0.0 - 1.0) * @name toDataURL - * @methodOf Kinetic.Stage.prototype + * @methodOf Kinetic.Node.prototype * @param {String} [mimeType] * @param {Number} [quality] */ toDataURL: function(mimeType, quality) { - var bufferLayer = this.getStage().bufferLayer; - var bufferCanvas = bufferLayer.getCanvas(); - var bufferContext = bufferLayer.getContext(); - bufferLayer.clear(); - this._draw(bufferLayer); + var bufferCanvas = this.getStage().bufferCanvas; + var bufferContext = bufferCanvas.getContext(); + bufferCanvas.clear(); + this._draw(bufferCanvas); try { // If this call fails (due to browser bug, like in Firefox 3.6), // then revert to previous no-parameter image/png behavior - return bufferLayer.getCanvas().toDataURL(mimeType, quality); + return bufferCanvas.element.toDataURL(mimeType, quality); } catch(e) { - return bufferLayer.getCanvas().toDataURL(); + return bufferCanvas.element.toDataURL(); } }, /** @@ -1391,9 +1500,10 @@ Kinetic.Node = Kinetic.Class.extend({ if(pos) { var m = this.getTransform().getTranslation(); var am = this.getAbsoluteTransform().getTranslation(); + var ap = this.getAbsolutePosition(); go.drag.node = this; - go.drag.offset.x = pos.x - this.getAbsoluteTransform().getTranslation().x; - go.drag.offset.y = pos.y - this.getAbsoluteTransform().getTranslation().y; + go.drag.offset.x = pos.x - ap.x; + go.drag.offset.y = pos.y - ap.y; } }, _onDraggableChange: function() { @@ -1895,18 +2005,18 @@ Kinetic.Container = Kinetic.Node.extend({ /** * draw children */ - _drawChildren: function(layer) { + _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( layer ? layer : child.getLayer()); + child._draw(canvas); } } else { - child.draw(layer); + child.draw(canvas); } } }, @@ -1914,27 +2024,8 @@ Kinetic.Container = Kinetic.Node.extend({ * set children indices */ _setChildrenIndices: function() { - /* - * if reordering Layers, remove all canvas elements - * from the container except the buffer and backstage canvases - * and then readd all the layers - */ - if(this.nodeType === 'Stage') { - var canvases = this.content.children; - var bufferCanvas = canvases[0]; - var backstageCanvas = canvases[1]; - - this.content.innerHTML = ''; - this.content.appendChild(bufferCanvas); - this.content.appendChild(backstageCanvas); - } - for(var n = 0; n < this.children.length; n++) { this.children[n].index = n; - - if(this.nodeType === 'Stage') { - this.content.appendChild(this.children[n].canvas); - } } } }); @@ -2026,8 +2117,8 @@ Kinetic.Stage = Kinetic.Container.extend({ * @name draw * @methodOf Kinetic.Stage.prototype */ - draw: function(layer) { - this._draw(layer); + draw: function(canvas) { + this._draw(canvas); }, /** * set stage size @@ -2229,37 +2320,25 @@ Kinetic.Stage = Kinetic.Container.extend({ * @param {Number} [quality] */ toDataURL: function(callback, mimeType, quality) { - /* - * we need to create a temp layer rather than using - * the bufferLayer because the stage toDataURL method - * is asynchronous, which means that other parts of the - * code base could be updating or clearing the bufferLayer - * while the stage toDataURL method is processing - */ - var tempLayer = new Kinetic.Layer(); - tempLayer.getCanvas().width = this.attrs.width; - tempLayer.getCanvas().height = this.attrs.height; - tempLayer.parent = this; - var tempCanvas = tempLayer.getCanvas(); - var tempContext = tempLayer.getContext(); - + var canvas = new Kinetic.Canvas(this.attrs.width, this.attrs.height); + var context = canvas.getContext(); var layers = this.children; function drawLayer(n) { var layer = layers[n]; - var layerUrl; + var canvasUrl; try { // If this call fails (due to browser bug, like in Firefox 3.6), // then revert to previous no-parameter image/png behavior - layerUrl = layer.getCanvas().toDataURL(mimeType, quality); + canvasUrl = canvas.getElement().toDataURL(mimeType, quality); } catch(e) { - layerUrl = layer.getCanvas().toDataURL(); + canvasUrl = canvas.getElement().toDataURL(); } var imageObj = new Image(); imageObj.onload = function() { - tempContext.drawImage(imageObj, 0, 0); + context.drawImage(imageObj, 0, 0); if(n < layers.length - 1) { drawLayer(n + 1); @@ -2268,14 +2347,14 @@ Kinetic.Stage = Kinetic.Container.extend({ try { // If this call fails (due to browser bug, like in Firefox 3.6), // then revert to previous no-parameter image/png behavior - callback(tempLayer.getCanvas().toDataURL(mimeType, quality)); + callback(canvas.getElement().toDataURL(mimeType, quality)); } catch(e) { - callback(tempLayer.getCanvas().toDataURL()); + callback(canvas.getElement().toDataURL()); } } }; - imageObj.src = layerUrl; + imageObj.src = canvasUrl; } drawLayer(0); }, @@ -2301,18 +2380,15 @@ Kinetic.Stage = Kinetic.Container.extend({ this.content.style.width = width + 'px'; this.content.style.height = height + 'px'; - // set buffer layer and path layer sizes - this.bufferLayer.getCanvas().width = width; - this.bufferLayer.getCanvas().height = height; - this.pathLayer.getCanvas().width = width; - this.pathLayer.getCanvas().height = height; + // set buffer canvas and path canvas sizes + this.bufferCanvas.setSize(width, height); + this.pathCanvas.setSize(width, height); // set user defined layer dimensions var layers = this.children; for(var n = 0; n < layers.length; n++) { var layer = layers[n]; - layer.getCanvas().width = width; - layer.getCanvas().height = height; + layer.getCanvas().setSize(width, height); layer.draw(); } }, @@ -2336,12 +2412,11 @@ Kinetic.Stage = Kinetic.Container.extend({ * @param {Layer} layer */ _add: function(layer) { - layer.canvas.width = this.attrs.width; - layer.canvas.height = this.attrs.height; + layer.canvas.setSize(this.attrs.width, this.attrs.height); // draw layer and append canvas to container layer.draw(); - this.content.appendChild(layer.canvas); + this.content.appendChild(layer.canvas.element); /* * set layer last draw time to zero @@ -2544,7 +2619,7 @@ Kinetic.Stage = Kinetic.Container.extend({ this._setMousePosition(evt); this._setTouchPosition(evt); - this.pathLayer.clear(); + this.pathCanvas.clear(); /* * loop through layers. If at any point an event @@ -2735,28 +2810,6 @@ Kinetic.Stage = Kinetic.Container.extend({ left: left }; }, - /** - * modify path context - * @param {CanvasContext} context - */ - _modifyPathContext: function(context) { - context.stroke = function() { - }; - context.fill = function() { - }; - context.fillRect = function(x, y, width, height) { - context.rect(x, y, width, height); - }; - context.strokeRect = function(x, y, width, height) { - context.rect(x, y, width, height); - }; - context.drawImage = function() { - }; - context.fillText = function() { - }; - context.strokeText = function() { - }; - }, /** * end drag and drop */ @@ -2851,34 +2904,15 @@ Kinetic.Stage = Kinetic.Container.extend({ this.content.className = 'kineticjs-content'; this.attrs.container.appendChild(this.content); - // default layers - this.bufferLayer = new Kinetic.Layer({ - name: 'bufferLayer' + this.bufferCanvas = new Kinetic.Canvas({ + width: this.attrs.width, + height: this.attrs.height }); - this.pathLayer = new Kinetic.Layer({ - name: 'pathLayer' + this.pathCanvas = new Kinetic.Canvas({ + width: this.attrs.width, + height: this.attrs.height }); - - // set parents - this.bufferLayer.parent = this; - this.pathLayer.parent = this; - - // customize back stage context - this._modifyPathContext(this.pathLayer.context); - - // hide canvases - this.bufferLayer.getCanvas().style.display = 'none'; - this.pathLayer.getCanvas().style.display = 'none'; - - // add buffer layer - this.bufferLayer.canvas.className = 'kineticjs-buffer-layer'; - this.content.appendChild(this.bufferLayer.canvas); - - // add path layer - this.pathLayer.canvas.className = 'kineticjs-path-layer'; - this.content.appendChild(this.pathLayer.canvas); - - this.setSize(this.attrs.width, this.attrs.height); + this.pathCanvas.strip(); this._resizeDOM(); }, _addId: function(node) { @@ -2959,8 +2993,8 @@ Kinetic.Stage = Kinetic.Container.extend({ this.anim = undefined; this.animRunning = false; }, - _draw: function(layer) { - this._drawChildren(layer); + _draw: function(canvas) { + this._drawChildren(canvas); } }); @@ -3030,9 +3064,8 @@ Kinetic.Layer = Kinetic.Container.extend({ this.beforeDrawFunc = undefined; this.afterDrawFunc = undefined; - this.canvas = document.createElement('canvas'); - this.context = this.canvas.getContext('2d'); - this.canvas.style.position = 'absolute'; + this.canvas = new Kinetic.Canvas(); + this.canvas.getElement().style.position = 'absolute'; // call super constructor this._super(config); @@ -3043,7 +3076,7 @@ Kinetic.Layer = Kinetic.Container.extend({ * @name draw * @methodOf Kinetic.Layer.prototype */ - draw: function(layer) { + draw: function(canvas) { var throttle = this.attrs.throttle; var date = new Date(); var time = date.getTime(); @@ -3051,7 +3084,7 @@ Kinetic.Layer = Kinetic.Container.extend({ var tt = 1000 / throttle; if(timeDiff >= tt || throttle > 200) { - this._draw(layer); + this._draw(canvas); if(this.drawTimeout !== undefined) { clearTimeout(this.drawTimeout); @@ -3068,7 +3101,7 @@ Kinetic.Layer = Kinetic.Container.extend({ * wait 17ms before trying again (60fps) */ this.drawTimeout = setTimeout(function() { - that.draw(layer); + that.draw(canvas); }, 17); } }, @@ -3088,19 +3121,6 @@ Kinetic.Layer = Kinetic.Container.extend({ afterDraw: function(func) { this.afterDrawFunc = func; }, - /** - * clears the canvas context tied to the layer. Clearing - * a layer does not remove its children. The nodes within - * the layer will be redrawn whenever the .draw() method - * is used again. - * @name clear - * @methodOf Kinetic.Layer.prototype - */ - clear: function() { - var context = this.getContext(); - var canvas = this.getCanvas(); - context.clearRect(0, 0, canvas.width, canvas.height); - }, /** * get layer canvas * @name getCanvas @@ -3110,12 +3130,12 @@ Kinetic.Layer = Kinetic.Container.extend({ return this.canvas; }, /** - * get layer context + * get layer canvas context * @name getContext * @methodOf Kinetic.Layer.prototype */ getContext: function() { - return this.context; + return this.canvas.context; }, /** * Creates a composite data URL. If MIME type is not @@ -3125,7 +3145,7 @@ Kinetic.Layer = Kinetic.Container.extend({ * based on what's draw on the layer, rather than drawing * the current state of each child node * @name toDataURL - * @methodOf Kinetic.Stage.prototype + * @methodOf Kinetic.Layer.prototype * @param {String} [mimeType] * @param {Number} [quality] */ @@ -3133,16 +3153,24 @@ Kinetic.Layer = Kinetic.Container.extend({ try { // If this call fails (due to browser bug, like in Firefox 3.6), // then revert to previous no-parameter image/png behavior - return this.getCanvas().toDataURL(mimeType, quality); + return this.getCanvas().element.toDataURL(mimeType, quality); } catch(e) { - return this.getCanvas().toDataURL(); + return this.getCanvas().element.toDataURL(); } }, /** * private draw children */ - _draw: function(layer) { + _draw: function(canvas) { + /* + * if canvas is not defined, then use the canvas + * tied to the layer + */ + if(!canvas) { + canvas = this.getCanvas(); + } + var date = new Date(); var time = date.getTime(); this.lastDrawTime = time; @@ -3153,8 +3181,7 @@ Kinetic.Layer = Kinetic.Container.extend({ } if(this.attrs.clearBeforeDraw) { - var clearLayer = layer ? layer : this; - clearLayer.clear(); + canvas.clear(); } if(this.isVisible()) { @@ -3164,7 +3191,7 @@ Kinetic.Layer = Kinetic.Container.extend({ } // draw children - this._drawChildren(layer); + this._drawChildren(canvas); } // after draw handler @@ -3220,12 +3247,12 @@ Kinetic.Group = Kinetic.Container.extend({ // call super constructor this._super(config); }, - draw: function(layer) { - this._draw(layer); + draw: function(canvas) { + this._draw(canvas); }, - _draw: function(layer) { + _draw: function(canvas) { if(this.attrs.visible) { - this._drawChildren(layer); + this._drawChildren(canvas); } } }); @@ -3262,24 +3289,20 @@ Kinetic.Shape = Kinetic.Node.extend({ this._super(config); }, /** - * get layer context where the shape is being drawn. When - * the shape is being rendered, .getContext() returns the context of the - * user created layer that contains the shape. When the event detection - * engine is determining whether or not an event has occured on that shape, - * .getContext() returns the context of the invisible path layer. + * get canvas context tied to the layer * @name getContext * @methodOf Kinetic.Shape.prototype */ getContext: function() { - return this.tempLayer.getContext(); + return this.getLayer().getContext(); }, /** - * get shape temp layer canvas + * get canvas tied to the layer * @name getCanvas * @methodOf Kinetic.Shape.prototype */ getCanvas: function() { - return this.tempLayer.getCanvas(); + return this.getLayer().getCanvas(); }, /** * helper method to stroke the shape and apply @@ -3287,15 +3310,14 @@ Kinetic.Shape = Kinetic.Node.extend({ * @name stroke * @methodOf Kinetic.Shape.prototype */ - stroke: function() { + stroke: function(context) { var go = Kinetic.Global; var appliedShadow = false; - var context = this.getContext(); if(this.attrs.stroke || this.attrs.strokeWidth) { context.save(); if(this.attrs.shadow && !this.appliedShadow) { - appliedShadow = this._applyShadow(); + appliedShadow = this._applyShadow(context); } var stroke = this.attrs.stroke ? this.attrs.stroke : 'black'; @@ -3303,12 +3325,12 @@ Kinetic.Shape = Kinetic.Node.extend({ context.lineWidth = strokeWidth; context.strokeStyle = stroke; - context.stroke(); + context.stroke(context); context.restore(); } if(appliedShadow) { - this.stroke(); + this.stroke(context); } }, /** @@ -3317,16 +3339,15 @@ Kinetic.Shape = Kinetic.Node.extend({ * @name fill * @methodOf Kinetic.Shape.prototype * */ - fill: function() { + fill: function(context) { var appliedShadow = false; - var context = this.getContext(); context.save(); var fill = this.attrs.fill; if(fill) { if(this.attrs.shadow && !this.appliedShadow) { - appliedShadow = this._applyShadow(); + appliedShadow = this._applyShadow(context); } var s = fill.start; @@ -3337,7 +3358,7 @@ Kinetic.Shape = Kinetic.Node.extend({ if( typeof fill == 'string') { f = this.attrs.fill; context.fillStyle = f; - context.fill(); + context.fill(context); } // pattern else if(fill.image) { @@ -3354,12 +3375,11 @@ Kinetic.Shape = Kinetic.Node.extend({ } context.fillStyle = f; - context.fill(); + context.fill(context); context.restore(); } // linear gradient else if(!s.radius && !e.radius) { - var context = this.getContext(); var grd = context.createLinearGradient(s.x, s.y, e.x, e.y); var colorStops = fill.colorStops; @@ -3369,11 +3389,10 @@ Kinetic.Shape = Kinetic.Node.extend({ } f = grd; context.fillStyle = f; - context.fill(); + context.fill(context); } // radial gradient else if((s.radius || s.radius === 0) && (e.radius || e.radius === 0)) { - var context = this.getContext(); var grd = context.createRadialGradient(s.x, s.y, s.radius, e.x, e.y, e.radius); var colorStops = fill.colorStops; @@ -3383,18 +3402,18 @@ Kinetic.Shape = Kinetic.Node.extend({ } f = grd; context.fillStyle = f; - context.fill(); + context.fill(context); } else { f = 'black'; context.fillStyle = f; - context.fill(); + context.fill(context); } } context.restore(); if(appliedShadow) { - this.fill(); + this.fill(context); } }, /** @@ -3403,13 +3422,12 @@ Kinetic.Shape = Kinetic.Node.extend({ * @name fillText * @methodOf Kinetic.Shape.prototype */ - fillText: function(text) { + fillText: function(context, text) { var appliedShadow = false; - var context = this.getContext(); context.save(); if(this.attrs.textFill) { if(this.attrs.shadow && !this.appliedShadow) { - appliedShadow = this._applyShadow(); + appliedShadow = this._applyShadow(context); } context.fillStyle = this.attrs.textFill; context.fillText(text, 0, 0); @@ -3417,7 +3435,7 @@ Kinetic.Shape = Kinetic.Node.extend({ context.restore(); if(appliedShadow) { - this.fillText(text, 0, 0); + this.fillText(context, text, 0, 0); } }, /** @@ -3427,13 +3445,12 @@ Kinetic.Shape = Kinetic.Node.extend({ * @methodOf Kinetic.Shape.prototype * @param {String} text */ - strokeText: function(text) { + strokeText: function(context, text) { var appliedShadow = false; - var context = this.getContext(); context.save(); if(this.attrs.textStroke || this.attrs.textStrokeWidth) { if(this.attrs.shadow && !this.appliedShadow) { - appliedShadow = this._applyShadow(); + appliedShadow = this._applyShadow(context); } // defaults @@ -3445,12 +3462,12 @@ Kinetic.Shape = Kinetic.Node.extend({ } context.lineWidth = this.attrs.textStrokeWidth; context.strokeStyle = this.attrs.textStroke; - context.strokeText(text, 0, 0); + context.strokeText(context, text, 0, 0); } context.restore(); if(appliedShadow) { - this.strokeText(text, 0, 0); + this.strokeText(context, text, 0, 0); } }, /** @@ -3461,21 +3478,20 @@ Kinetic.Shape = Kinetic.Node.extend({ */ drawImage: function() { var appliedShadow = false; - var context = this.getContext(); + var context = arguments[0]; context.save(); var a = Array.prototype.slice.call(arguments); - if(a.length === 5 || a.length === 9) { + if(a.length === 6 || a.length === 10) { if(this.attrs.shadow && !this.appliedShadow) { - appliedShadow = this._applyShadow(); + appliedShadow = this._applyShadow(context); } - switch(a.length) { - case 5: - context.drawImage(a[0], a[1], a[2], a[3], a[4]); - break; - case 9: - context.drawImage(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); - break; + + if(a.length === 6) { + context.drawImage(a[1], a[2], a[3], a[4], a[5]); + } + else { + context.drawImage(a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]); } } @@ -3491,8 +3507,7 @@ Kinetic.Shape = Kinetic.Node.extend({ * @name applyLineJoin * @methodOf Kinetic.Shape.prototype */ - applyLineJoin: function() { - var context = this.getContext(); + applyLineJoin: function(context) { if(this.attrs.lineJoin) { context.lineJoin = this.attrs.lineJoin; } @@ -3501,8 +3516,7 @@ Kinetic.Shape = Kinetic.Node.extend({ * apply shadow. return true if shadow was applied * and false if it was not */ - _applyShadow: function() { - var context = this.getContext(); + _applyShadow: function(context) { var s = this.attrs.shadow; if(s) { var aa = this.getAbsoluteAlpha(); @@ -3540,12 +3554,12 @@ Kinetic.Shape = Kinetic.Node.extend({ // path detection if(this.attrs.detectionType === 'path') { - var pathLayer = stage.pathLayer; - var pathLayerContext = pathLayer.getContext(); + var pathCanvas = stage.pathCanvas; + var pathCanvasContext = pathCanvas.getContext(); - this._draw(pathLayer); + this._draw(pathCanvas); - return pathLayerContext.isPointInPath(pos.x, pos.y); + return pathCanvasContext.isPointInPath(pos.x, pos.y); } // pixel detection @@ -3558,10 +3572,10 @@ Kinetic.Shape = Kinetic.Node.extend({ // default return false; }, - _draw: function(layer) { - if(layer && this.attrs.drawFunc) { - var stage = layer.getStage(); - var context = layer.getContext(); + _draw: function(canvas) { + if(this.attrs.drawFunc) { + var stage = this.getStage(); + var context = canvas.getContext(); var family = []; var parent = this.parent; @@ -3580,8 +3594,6 @@ Kinetic.Shape = Kinetic.Node.extend({ context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); } - this.tempLayer = layer; - /* * pre styles include alpha, linejoin */ @@ -3589,11 +3601,11 @@ Kinetic.Shape = Kinetic.Node.extend({ if(absAlpha !== 1) { context.globalAlpha = absAlpha; } - this.applyLineJoin(); + this.applyLineJoin(context); // draw the shape this.appliedShadow = false; - this.attrs.drawFunc.call(this); + this.attrs.drawFunc.call(this, canvas.getContext()); context.restore(); } } @@ -3700,8 +3712,7 @@ Kinetic.Rect = Kinetic.Shape.extend({ this.shapeType = "Rect"; - config.drawFunc = function() { - var context = this.getContext(); + config.drawFunc = function(context) { context.beginPath(); if(this.attrs.cornerRadius === 0) { // simple rect - don't bother doing all that complicated maths stuff. @@ -3721,8 +3732,8 @@ Kinetic.Rect = Kinetic.Shape.extend({ } context.closePath(); - this.fill(); - this.stroke(); + this.fill(context); + this.stroke(context); }; // call super constructor this._super(config); @@ -3810,9 +3821,7 @@ Kinetic.Ellipse = Kinetic.Shape.extend({ this.shapeType = "Ellipse"; - config.drawFunc = function() { - var canvas = this.getCanvas(); - var context = this.getContext(); + config.drawFunc = function(context) { var r = this.getRadius(); context.beginPath(); context.save(); @@ -3822,8 +3831,8 @@ Kinetic.Ellipse = Kinetic.Shape.extend({ context.arc(0, 0, r.x, 0, Math.PI * 2, true); context.restore(); context.closePath(); - this.fill(); - this.stroke(); + this.fill(context); + this.stroke(context); }; // call super constructor this._super(config); @@ -3894,18 +3903,16 @@ Kinetic.Node.addGettersSetters(Kinetic.Ellipse, ['radius']); Kinetic.Image = Kinetic.Shape.extend({ init: function(config) { this.shapeType = "Image"; - config.drawFunc = function() { + config.drawFunc = function(context) { if(!!this.attrs.image) { var width = this.getWidth(); var height = this.getHeight(); - var canvas = this.getCanvas(); - var context = this.getContext(); context.beginPath(); context.rect(0, 0, width, height); context.closePath(); - this.fill(); - this.stroke(); + this.fill(context); + this.stroke(context); // if cropping if(this.attrs.crop && this.attrs.crop.width && this.attrs.crop.height) { @@ -3913,11 +3920,11 @@ Kinetic.Image = Kinetic.Shape.extend({ var cropY = this.attrs.crop.y ? this.attrs.crop.y : 0; var cropWidth = this.attrs.crop.width; var cropHeight = this.attrs.crop.height; - this.drawImage(this.attrs.image, cropX, cropY, cropWidth, cropHeight, 0, 0, width, height); + this.drawImage(context, this.attrs.image, cropX, cropY, cropWidth, cropHeight, 0, 0, width, height); } // no cropping else { - this.drawImage(this.attrs.image, 0, 0, width, height); + this.drawImage(context, this.attrs.image, 0, 0, width, height); } } }; @@ -4105,9 +4112,8 @@ Kinetic.Sprite = Kinetic.Shape.extend({ frameRate: 17 }); - config.drawFunc = function() { + config.drawFunc = function(context) { if(!!this.attrs.image) { - var context = this.getContext(); var anim = this.attrs.animation; var index = this.attrs.index; var f = this.attrs.animations[anim][index]; @@ -4116,7 +4122,7 @@ Kinetic.Sprite = Kinetic.Shape.extend({ context.rect(0, 0, f.width, f.height); context.closePath(); - this.drawImage(this.attrs.image, f.x, f.y, f.width, f.height, 0, 0, f.width, f.height); + this.drawImage(context, this.attrs.image, f.x, f.y, f.width, f.height, 0, 0, f.width, f.height); } }; // call super constructor @@ -4263,16 +4269,15 @@ Kinetic.Polygon = Kinetic.Shape.extend({ }); this.shapeType = "Polygon"; - config.drawFunc = function() { - var context = this.getContext(); + config.drawFunc = function(context) { context.beginPath(); context.moveTo(this.attrs.points[0].x, this.attrs.points[0].y); for(var n = 1; n < this.attrs.points.length; n++) { context.lineTo(this.attrs.points[n].x, this.attrs.points[n].y); } context.closePath(); - this.fill(); - this.stroke(); + this.fill(context); + this.stroke(context); }; // call super constructor this._super(config); @@ -4312,8 +4317,7 @@ Kinetic.RegularPolygon = Kinetic.Shape.extend({ }); this.shapeType = "RegularPolygon"; - config.drawFunc = function() { - var context = this.getContext(); + config.drawFunc = function(context) { context.beginPath(); context.moveTo(0, 0 - this.attrs.radius); @@ -4323,8 +4327,8 @@ Kinetic.RegularPolygon = Kinetic.Shape.extend({ context.lineTo(x, y); } context.closePath(); - this.fill(); - this.stroke(); + this.fill(context); + this.stroke(context); }; // call super constructor this._super(config); @@ -4376,8 +4380,7 @@ Kinetic.Star = Kinetic.Shape.extend({ }); this.shapeType = "Star"; - config.drawFunc = function() { - var context = this.getContext(); + config.drawFunc = function(context) { context.beginPath(); context.moveTo(0, 0 - this.attrs.outerRadius); @@ -4389,8 +4392,8 @@ Kinetic.Star = Kinetic.Shape.extend({ } context.closePath(); - this.fill(); - this.stroke(); + this.fill(context); + this.stroke(context); }; // call super constructor this._super(config); @@ -4467,8 +4470,7 @@ Kinetic.Text = Kinetic.Shape.extend({ this.dummyCanvas = document.createElement('canvas'); this.shapeType = "Text"; - config.drawFunc = function() { - var context = this.getContext(); + config.drawFunc = function(context) { /* * draw rect */ @@ -4494,8 +4496,8 @@ Kinetic.Text = Kinetic.Shape.extend({ } context.closePath(); - this.fill(); - this.stroke(); + this.fill(context); + this.stroke(context); /* * draw text */ @@ -4523,8 +4525,8 @@ Kinetic.Text = Kinetic.Shape.extend({ context.translate((this.getBoxWidth() - this._getTextSize(text).width - p * 2) / 2, 0); } - this.fillText(text); - this.strokeText(text); + this.fillText(context, text); + this.strokeText(context, text); context.restore(); context.translate(0, lineHeightPx); @@ -4846,8 +4848,7 @@ Kinetic.Line = Kinetic.Shape.extend({ }); this.shapeType = "Line"; - config.drawFunc = function() { - var context = this.getContext(); + config.drawFunc = function(context) { var lastPos = {}; context.beginPath(); @@ -4860,7 +4861,7 @@ Kinetic.Line = Kinetic.Shape.extend({ // draw dashed line var lastX = this.attrs.points[n - 1].x; var lastY = this.attrs.points[n - 1].y; - this._dashedLine(lastX, lastY, x, y, this.attrs.dashArray); + this._dashedLine(context, lastX, lastY, x, y, this.attrs.dashArray); } else { // draw normal line @@ -4872,7 +4873,7 @@ Kinetic.Line = Kinetic.Shape.extend({ context.lineCap = this.attrs.lineCap; } - this.stroke(); + this.stroke(context); }; // call super constructor this._super(config); @@ -4880,8 +4881,7 @@ Kinetic.Line = Kinetic.Shape.extend({ /** * draw dashed line. Written by Phrogz */ - _dashedLine: function(x, y, x2, y2, dashArray) { - var context = this.getContext(); + _dashedLine: function(context, x, y, x2, y2, dashArray) { var dashCount = dashArray.length; var dx = (x2 - x), dy = (y2 - y); @@ -4990,8 +4990,7 @@ Kinetic.Path = Kinetic.Shape.extend({ this.dataArray = []; var that = this; - config.drawFunc = function() { - var context = this.getContext(); + config.drawFunc = function(context) { var ca = this.dataArray; // context position context.beginPath(); @@ -5032,8 +5031,8 @@ Kinetic.Path = Kinetic.Shape.extend({ break; } } - this.fill(); - this.stroke(); + this.fill(context); + this.stroke(context); }; // call super constructor this._super(config); diff --git a/dist/kinetic-core.min.js b/dist/kinetic-core.min.js index cb2ae5fe..f024f692 100644 --- a/dist/kinetic-core.min.js +++ b/dist/kinetic-core.min.js @@ -3,7 +3,7 @@ * http://www.kineticjs.com/ * Copyright 2012, Eric Rowell * Licensed under the MIT or GPL Version 2 licenses. - * Date: Jul 17 2012 + * Date: Jul 18 2012 * * Copyright (C) 2011 - 2012 by Eric Rowell * @@ -25,5 +25,5 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -var Kinetic={};Kinetic.Filters={},Kinetic.Global={BUBBLE_WHITELIST:["mousedown","mousemove","mouseup","mouseover","mouseout","click","dblclick","touchstart","touchmove","touchend","tap","dbltap","dragstart","dragmove","dragend"],stages:[],idCounter:0,tempNodes:[],maxDragTimeInterval:20,drag:{moving:!1,offset:{x:0,y:0},lastDrawTime:0},warn:function(a){console&&console.warn&&console.warn("Kinetic warning: "+a)},_pullNodes:function(a){var b=this.tempNodes;for(var c=0;c0},_getXY:function(a){if(this._isNumber(a))return{x:a,y:a};if(this._isArray(a)){if(a.length===1){var b=a[0];if(this._isNumber(b))return{x:b,y:b};if(this._isArray(b))return{x:b[0],y:b[1]};if(this._isObject(b))return b}else if(a.length>=2)return{x:a[0],y:a[1]}}else if(this._isObject(a))return a;return{x:0,y:0}},_getSize:function(a){if(this._isNumber(a))return{width:a,height:a};if(this._isArray(a))if(a.length===1){var b=a[0];if(this._isNumber(b))return{width:b,height:b};if(this._isArray(b)){if(b.length>=4)return{width:b[2],height:b[3]};if(b.length>=2)return{width:b[0],height:b[1]}}else if(this._isObject(b))return b}else{if(a.length>=4)return{width:a[2],height:a[3]};if(a.length>=2)return{width:a[0],height:a[1]}}else if(this._isObject(a))return a;return{width:0,height:0}},_getPoints:function(a){if(a===undefined)return[];if(this._isObject(a[0]))return a;var b=[];for(var c=0;c0){this._updateFrameObject(),this._runFrames();var a=this;requestAnimFrame(function(){a._animationLoop()})}else this.animRunning=!1,this.frame.lastTime=0},_handleAnimation:function(){var a=this;this.animRunning?this.frame.lastTime=0:(this.animRunning=!0,a._animationLoop())}},requestAnimFrame=function(a){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){window.setTimeout(a,1e3/60)}}(),Kinetic.Node=Kinetic.Class.extend({init:function(a){this.defaultNodeAttrs={visible:!0,listening:!0,name:undefined,alpha:1,x:0,y:0,scale:{x:1,y:1},rotation:0,offset:{x:0,y:0},dragConstraint:"none",dragBounds:{},draggable:!1},this.setDefaultAttrs(this.defaultNodeAttrs),this.eventListeners={},this.setAttrs(a),this.on("draggableChange.kinetic",function(){this._onDraggableChange()});var b=this;this.on("idChange.kinetic",function(a){var c=b.getStage();c&&(c._removeId(a.oldVal),c._addId(b))}),this.on("nameChange.kinetic",function(a){var c=b.getStage();c&&(c._removeName(a.oldVal,b._id),c._addName(b))}),this._onDraggableChange()},on:function(a,b){var c=a.split(" ");for(var d=0;d1?g[1]:"";this.eventListeners[h]||(this.eventListeners[h]=[]),this.eventListeners[h].push({name:i,handler:b})}},off:function(a){var b=a.split(" ");for(var c=0;c1){var h=f[1];for(var i=0;i0&&f[0].getLevel()<=a&&e(f)}var a=this.getLevel(),b=this.getStage(),c=this,d=0;return c.nodeType!=="Stage"&&e(c.getStage().getChildren()),d},getLevel:function(){var a=0,b=this.parent;while(b)a++,b=b.parent;return a},setPosition:function(){var a=Kinetic.Type._getXY(Array.prototype.slice.call(arguments));this.setAttrs(a)},getPosition:function(){return{x:this.attrs.x,y:this.attrs.y}},getAbsolutePosition:function(){return this.getAbsoluteTransform().getTranslation()},setAbsolutePosition:function(){var a=Kinetic.Type._getXY(Array.prototype.slice.call(arguments)),b=this.attrs.rotation,c={x:this.attrs.scale.x,y:this.attrs.scale.y},d={x:this.attrs.offset.x,y:this.attrs.offset.y};this.attrs.rotation=0,this.attrs.scale={x:1,y:1};var e=this.getAbsoluteTransform();e.invert(),e.translate(a.x,a.y),a={x:this.attrs.x+e.getTranslation().x,y:this.attrs.y+e.getTranslation().y},this.setPosition(a.x,a.y),this.rotate(b),this.attrs.scale={x:c.x,y:c.y}},move:function(){var a=Kinetic.Type._getXY(Array.prototype.slice.call(arguments)),b=this.getX(),c=this.getY();a.x!==undefined&&(b+=a.x),a.y!==undefined&&(c+=a.y),this.setAttrs({x:b,y:c})},getRotationDeg:function(){return this.attrs.rotation*180/Math.PI},rotate:function(a){this.setAttrs({rotation:this.getRotation()+a})},rotateDeg:function(a){this.setAttrs({rotation:this.getRotation()+a*Math.PI/180})},moveToTop:function(){var a=this.index;this.parent.children.splice(a,1),this.parent.children.push(this),this.parent._setChildrenIndices()},moveUp:function(){var a=this.index;this.parent.children.splice(a,1),this.parent.children.splice(a+1,0,this),this.parent._setChildrenIndices()},moveDown:function(){var a=this.index;a>0&&(this.parent.children.splice(a,1),this.parent.children.splice(a-1,0,this),this.parent._setChildrenIndices())},moveToBottom:function(){var a=this.index;this.parent.children.splice(a,1),this.parent.children.unshift(this),this.parent._setChildrenIndices()},setZIndex:function(a){var b=this.index;this.parent.children.splice(b,1),this.parent.children.splice(a,0,this),this.parent._setChildrenIndices()},getAbsoluteAlpha:function(){var a=1,b=this;while(b.nodeType!=="Stage")a*=b.attrs.alpha,b=b.parent;return a},isDragging:function(){var a=Kinetic.Global;return a.drag.node!==undefined&&a.drag.node._id===this._id&&a.drag.moving},moveTo:function(a){var b=this.parent;b.children.splice(this.index,1),b._setChildrenIndices(),a.children.push(this),this.index=a.children.length-1,this.parent=a,a._setChildrenIndices()},getParent:function(){return this.parent},getLayer:function(){return this.nodeType==="Layer"?this:this.getParent().getLayer()},getStage:function(){return this.nodeType!=="Stage"&&this.getParent()?this.getParent().getStage():this.nodeType==="Stage"?this:undefined},simulate:function(a){this._handleEvent(a,{})},transitionTo:function(a){var b=Kinetic.Animation;this.transAnim&&(b._removeAnimation(this.transAnim),this.transAnim=null);var c=this.nodeType==="Stage"?this:this.getLayer(),d=this,e=new Kinetic.Transition(this,a),f={func:function(){e._onEnterFrame()},node:c};return this.transAnim=f,b._addAnimation(f),e.onFinished=function(){b._removeAnimation(f),d.transAnim=null,a.callback!==undefined&&a.callback(),f.node.draw()},e.start(),b._handleAnimation(),e},getAbsoluteTransform:function(){var a=new Kinetic.Transform,b=[],c=this.parent;b.unshift(this);while(c)b.unshift(c),c=c.parent;for(var d=0;d=0&&!b.cancelBubble&&this.parent&&this._handleEvent.call(this.parent,a,b)}}}),Kinetic.Node.addSetters=function(constructor,a){for(var b=0;b0)this.remove(this.children[0])},add:function(a){a._id=Kinetic.Global.idCounter++,a.index=this.children.length,a.parent=this,this.children.push(a);var b=a.getStage();if(b===undefined){var c=Kinetic.Global;c.tempNodes.push(a)}else{b._addId(a),b._addName(a);var c=Kinetic.Global;c._pullNodes(b)}return this._add!==undefined&&this._add(a),this},remove:function(a){if(a&&a.index!==undefined&&this.children[a.index]._id==a._id){var b=this.getStage();b!==undefined&&(b._removeId(a.getId()),b._removeName(a.getName(),a._id));var c=Kinetic.Global;for(var d=0;d0)a.remove(a.children[0]);this._remove!==undefined&&this._remove(a)}return this},get:function(a){var b=this.getStage(),c,d=a.slice(1);if(a.charAt(0)==="#")c=b.ids[d]!==undefined?[b.ids[d]]:[];else{if(a.charAt(0)!==".")return a==="Shape"||a==="Group"||a==="Layer"?this._getNodes(a):!1;c=b.names[d]!==undefined?b.names[d]:[]}var e=[];for(var f=0;f=0;d--){var e=c[d];if(e.getListening())if(e.nodeType==="Shape"){var f=this._detectEvent(e,b);if(f)return!0}else{var f=this._traverseChildren(e,b);if(f)return!0}}return!1},_handleStageEvent:function(a){var b=new Date,c=b.getTime();this.lastEventTime=c;var d=Kinetic.Global;a||(a=window.event),this._setMousePosition(a),this._setTouchPosition(a),this.pathLayer.clear(),this.targetFound=!1;var e=!1;for(var f=this.children.length-1;f>=0;f--){var g=this.children[f];if(g.isVisible()&&f>=0&&g.getListening()&&this._traverseChildren(g,a)){e=!0;break}}!e&&this.mouseoutShape&&(this.mouseoutShape._handleEvent("mouseout",a),this.mouseoutShape=undefined)},_bindContentEvents:function(){var a=Kinetic.Global,b=this,c=["mousedown","mousemove","mouseup","mouseover","mouseout","touchstart","touchmove","touchend"];for(var d=0;d=f||b>200)this.mouseDown=!1,this.mouseUp=!1,this.mouseMove=!0,this._handleStageEvent(a);this._startDrag(a)},_mousedown:function(a){this.mouseDown=!0,this.mouseUp=!1,this.mouseMove=!1,this._handleStageEvent(a),this.attrs.draggable&&this._initDrag()},_mouseup:function(a){this.mouseDown=!1,this.mouseUp=!0,this.mouseMove=!1,this._handleStageEvent(a),this.clickStart=!1,this._endDrag(a)},_touchstart:function(a){a.preventDefault(),this.touchStart=!0,this.touchEnd=!1,this.touchMove=!1,this._handleStageEvent(a),this.attrs.draggable&&this._initDrag()},_touchend:function(a){this.touchStart=!1,this.touchEnd=!0,this.touchMove=!1,this._handleStageEvent(a),this.tapStart=!1,this._endDrag(a)},_touchmove:function(a){var b=this,c=this.attrs.throttle,d=new Date,e=d.getTime(),f=e-this.lastEventTime,g=1e3/c;if(f>=g||c>200)a.preventDefault(),b.touchEnd=!1,b.touchMove=!0,b._handleStageEvent(a);this._startDrag(a)},_setMousePosition:function(a){var b=a.offsetX||a.clientX-this._getContentPosition().left+window.pageXOffset,c=a.offsetY||a.clientY-this._getContentPosition().top+window.pageYOffset;this.mousePos={x:b,y:c}},_setTouchPosition:function(a){if(a.touches!==undefined&&a.touches.length===1){var b=a.touches[0],c=b.clientX-this._getContentPosition().left+window.pageXOffset,d=b.clientY-this._getContentPosition().top+window.pageYOffset;this.touchPos={x:c,y:d}}},_getContentPosition:function(){var a=this.content,b=0,c=0;while(a&&a.tagName!=="BODY")b+=a.offsetTop-a.scrollTop,c+=a.offsetLeft-a.scrollLeft,a=a.offsetParent;return{top:b,left:c}},_modifyPathContext:function(a){a.stroke=function(){},a.fill=function(){},a.fillRect=function(b,c,d,e){a.rect(b,c,d,e)},a.strokeRect=function(b,c,d,e){a.rect(b,c,d,e)},a.drawImage=function(){},a.fillText=function(){},a.strokeText=function(){}},_endDrag:function(a){var b=Kinetic.Global;b.drag.node&&b.drag.moving&&(b.drag.moving=!1,b.drag.node._handleEvent("dragend",a)),b.drag.node=undefined},_startDrag:function(a){var b=this,c=Kinetic.Global,d=c.drag.node;if(d){var e=b.getUserPosition(),f=d.attrs.dragConstraint,g=d.attrs.dragBounds,h={x:d.attrs.x,y:d.attrs.y},i={x:e.x-c.drag.offset.x,y:e.y-c.drag.offset.y};g.left!==undefined&&i.xg.right&&(i.x=g.right),g.top!==undefined&&i.yg.bottom&&(i.y=g.bottom),d.setAbsolutePosition(i),f==="horizontal"?d.attrs.y=h.y:f==="vertical"&&(d.attrs.x=h.x),c.drag.node.nodeType==="Stage"?c.drag.node.draw():c.drag.node.getLayer().draw(),c.drag.moving||(c.drag.moving=!0,c.drag.node._handleEvent("dragstart",a)),c.drag.node._handleEvent("dragmove",a)}},_buildDOM:function(){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.bufferLayer=new Kinetic.Layer({name:"bufferLayer"}),this.pathLayer=new Kinetic.Layer({name:"pathLayer"}),this.bufferLayer.parent=this,this.pathLayer.parent=this,this._modifyPathContext(this.pathLayer.context),this.bufferLayer.getCanvas().style.display="none",this.pathLayer.getCanvas().style.display="none",this.bufferLayer.canvas.className="kineticjs-buffer-layer",this.content.appendChild(this.bufferLayer.canvas),this.pathLayer.canvas.className="kineticjs-path-layer",this.content.appendChild(this.pathLayer.canvas),this.setSize(this.attrs.width,this.attrs.height),this._resizeDOM()},_addId:function(a){a.attrs.id!==undefined&&(this.ids[a.attrs.id]=a)},_removeId:function(a){a!==undefined&&delete this.ids[a]},_addName:function(a){var b=a.attrs.name;b!==undefined&&(this.names[b]===undefined&&(this.names[b]=[]),this.names[b].push(a))},_removeName:function(a,b){if(a!==undefined){var c=this.names[a];if(c!==undefined){for(var d=0;d=f||b>200)this._draw(a),this.drawTimeout!==undefined&&(clearTimeout(this.drawTimeout),this.drawTimeout=undefined);else if(this.drawTimeout===undefined){var g=this;this.drawTimeout=setTimeout(function(){g.draw(a)},17)}},beforeDraw:function(a){this.beforeDrawFunc=a},afterDraw:function(a){this.afterDrawFunc=a},clear:function(){var a=this.getContext(),b=this.getCanvas();a.clearRect(0,0,b.width,b.height)},getCanvas:function(){return this.canvas},getContext:function(){return this.context},toDataURL:function(a,b){try{return this.getCanvas().toDataURL(a,b)}catch(c){return this.getCanvas().toDataURL()}},_draw:function(a){var b=new Date,c=b.getTime();this.lastDrawTime=c,this.beforeDrawFunc!==undefined&&this.beforeDrawFunc.call(this);if(this.attrs.clearBeforeDraw){var d=a?a:this;d.clear()}this.isVisible()&&(this.attrs.drawFunc!==undefined&&this.attrs.drawFunc.call(this),this._drawChildren(a)),this.afterDrawFunc!==undefined&&this.afterDrawFunc.call(this)}}),Kinetic.Node.addGettersSetters(Kinetic.Layer,["clearBeforeDraw","throttle"]),Kinetic.Group=Kinetic.Container.extend({init:function(a){this.nodeType="Group",this._super(a)},draw:function(a){this._draw(a)},_draw:function(a){this.attrs.visible&&this._drawChildren(a)}}),Kinetic.Shape=Kinetic.Node.extend({init:function(a){this.setDefaultAttrs({detectionType:"path"}),this.nodeType="Shape",this.appliedShadow=!1,this._super(a)},getContext:function(){return this.tempLayer.getContext()},getCanvas:function(){return this.tempLayer.getCanvas()},stroke:function(){var a=Kinetic.Global,b=!1,c=this.getContext();if(this.attrs.stroke||this.attrs.strokeWidth){c.save(),this.attrs.shadow&&!this.appliedShadow&&(b=this._applyShadow());var d=this.attrs.stroke?this.attrs.stroke:"black",e=this.attrs.strokeWidth?this.attrs.strokeWidth:2;c.lineWidth=e,c.strokeStyle=d,c.stroke(),c.restore()}b&&this.stroke()},fill:function(){var a=!1,b=this.getContext();b.save();var c=this.attrs.fill;if(c){this.attrs.shadow&&!this.appliedShadow&&(a=this._applyShadow());var d=c.start,e=c.end,f=null;if(typeof c=="string")f=this.attrs.fill,b.fillStyle=f,b.fill();else if(c.image){var g=c.repeat?c.repeat:"repeat";f=b.createPattern(c.image,g),b.save(),c.scale&&b.scale(c.scale.x,c.scale.y),c.offset&&b.translate(c.offset.x,c.offset.y),b.fillStyle=f,b.fill(),b.restore()}else if(!d.radius&&!e.radius){var b=this.getContext(),h=b.createLinearGradient(d.x,d.y,e.x,e.y),i=c.colorStops;for(var j=0;j0&&d&&(this.attrs.height==="auto"||e*(c+1)this.attrs.width-this.attrs.padding*2){if(f==0)break;var i=h.lastIndexOf(" "),j=h.lastIndexOf("-"),k=Math.max(i,j);if(k>=0){g=a.splice(0,1+k).join("");break}g=a.splice(0,f).join("");break}f++,f===a.length&&(g=a.splice(0,f).join(""))}this.textWidth=Math.max(this.textWidth,this._getTextSize(g).width),g!==undefined&&(b.push(g),d=!0),c++}this.textArr=b}}),Kinetic.Node.addGettersSetters(Kinetic.Text,["fontFamily","fontSize","fontStyle","textFill","textStroke","textStrokeWidth","padding","align","lineHeight","text","width","height","cornerRadius","fill","stroke","strokeWidth","shadow"]),Kinetic.Line=Kinetic.Shape.extend({init:function(a){this.setDefaultAttrs({points:[],lineCap:"butt",dashArray:[],detectionType:"pixel"}),this.shapeType="Line",a.drawFunc=function(){var a=this.getContext(),b={};a.beginPath(),a.moveTo(this.attrs.points[0].x,this.attrs.points[0].y);for(var c=1;c0){var f=this.attrs.points[c-1].x,g=this.attrs.points[c-1].y;this._dashedLine(f,g,d,e,this.attrs.dashArray)}else a.lineTo(d,e)}!this.attrs.lineCap||(a.lineCap=this.attrs.lineCap),this.stroke()},this._super(a)},_dashedLine:function(a,b,c,d,e){var f=this.getContext(),g=e.length,h=c-a,i=d-b,j=h>i,k=j?i/h:h/i;k>9999?k=9999:k<-9999&&(k=-9999);var l=Math.sqrt(h*h+i*i),m=0,n=!0;while(l>=.1&&m<1e4){var o=e[m++%g];o===0&&(o=.001),o>l&&(o=l);var p=Math.sqrt(o*o/(1+k*k));j?(a+=h<0&&i<0?p*-1:p,b+=h<0&&i<0?k*p*-1:k*p):(a+=h<0&&i<0?k*p*-1:k*p,b+=h<0&&i<0?p*-1:p),f[n?"lineTo":"moveTo"](a,b),l-=o,n=!n}f.moveTo(c,d)}}),Kinetic.Node.addGettersSetters(Kinetic.Line,["dashArray","lineCap","points"]),Kinetic.Path=Kinetic.Shape.extend({init:function(a){this.shapeType="Path",this.dataArray=[];var b=this;a.drawFunc=function(){var a=this.getContext(),b=this.dataArray;a.beginPath();for(var c=0;ci?h:i,o=h>i?1:h/i,p=h>i?i/h:1;a.translate(f,g),a.rotate(l),a.scale(o,p),a.arc(0,0,n,j,j+k,1-m),a.scale(1/o,1/p),a.rotate(-l),a.translate(-f,-g);break;case"z":a.closePath()}}this.fill(),this.stroke()},this._super(a),this.dataArray=this._getDataArray(),this.on("dataChange",function(){b.dataArray=b._getDataArray()})},_getDataArray:function(){var a=this.attrs.data;if(!this.attrs.data)return[];var b=["m","M","l","L","v","V","h","H","z","Z","c","C","q","Q","t","T","s","S","a","A"];a=a.replace(new RegExp(" ","g"),",");for(var c=0;c0&&j[0]===""&&j.shift();for(var k=0;k0){if(isNaN(j[0]))break;var l=undefined,m=[];switch(i){case"l":f+=j.shift(),g+=j.shift(),l="L",m.push(f,g);break;case"L":f=j.shift(),g=j.shift(),m.push(f,g);break;case"m":f+=j.shift(),g+=j.shift(),l="M",m.push(f,g),i="l";break;case"M":f=j.shift(),g=j.shift(),l="M",m.push(f,g),i="L";break;case"h":f+=j.shift(),l="L",m.push(f,g);break;case"H":f=j.shift(),l="L",m.push(f,g);break;case"v":g+=j.shift(),l="L",m.push(f,g);break;case"V":g=j.shift(),l="L",m.push(f,g);break;case"C":m.push(j.shift(),j.shift(),j.shift(),j.shift()),f=j.shift(),g=j.shift(),m.push(f,g);break;case"c":m.push(f+j.shift(),g+j.shift(),f+j.shift(),g+j.shift()),f+=j.shift(),g+=j.shift(),l="C",m.push(f,g);break;case"S":var n=f,o=g,p=e[e.length-1];p.command==="C"&&(n=f+(f-p.points[2]),o=g+(g-p.points[3])),m.push(n,o,j.shift(),j.shift()),f=j.shift(),g=j.shift(),l="C",m.push(f,g);break;case"s":var n=f,o=g,p=e[e.length-1];p.command==="C"&&(n=f+(f-p.points[2]),o=g+(g-p.points[3])),m.push(n,o,f+j.shift(),g+j.shift()),f+=j.shift(),g+=j.shift(),l="C",m.push(f,g);break;case"Q":m.push(j.shift(),j.shift()),f=j.shift(),g=j.shift(),m.push(f,g);break;case"q":m.push(f+j.shift(),g+j.shift()),f+=j.shift(),g+=j.shift(),l="Q",m.push(f,g);break;case"T":var n=f,o=g,p=e[e.length-1];p.command==="Q"&&(n=f+(f-p.points[0]),o=g+(g-p.points[1])),f=j.shift(),g=j.shift(),l="Q",m.push(n,o,f,g);break;case"t":var n=f,o=g,p=e[e.length-1];p.command==="Q"&&(n=f+(f-p.points[0]),o=g+(g-p.points[1])),f+=j.shift(),g+=j.shift(),l="Q",m.push(n,o,f,g);break;case"A":var q=j.shift(),r=j.shift(),s=j.shift(),t=j.shift(),u=j.shift(),v=f,w=g;f=j.shift(),g=j.shift(),l="A",m=this._convertEndpointToCenterParameterization(v,w,f,g,t,u,q,r,s);break;case"a":var q=j.shift(),r=j.shift(),s=j.shift(),t=j.shift(),u=j.shift(),v=f,w=g;f+=j.shift(),g+=j.shift(),l="A",m=this._convertEndpointToCenterParameterization(v,w,f,g,t,u,q,r,s)}e.push({command:l||i,points:m})}(i==="z"||i==="Z")&&e.push({command:"z",points:[]})}return e},_convertEndpointToCenterParameterization:function(a,b,c,d,e,f,g,h,i){var j=i*(Math.PI/180),k=Math.cos(j)*(a-c)/2+Math.sin(j)*(b-d)/2,l=-1*Math.sin(j)*(a-c)/2+Math.cos(j)*(b-d)/2,m=k*k/(g*g)+l*l/(h*h);m>1&&(g*=Math.sqrt(m),h*=Math.sqrt(m));var n=Math.sqrt((g*g*h*h-g*g*l*l-h*h*k*k)/(g*g*l*l+h*h*k*k));e==f&&(n*=-1),isNaN(n)&&(n=0);var o=n*g*l/h,p=n*-h*k/g,q=(a+c)/2+Math.cos(j)*o-Math.sin(j)*p,r=(b+d)/2+Math.sin(j)*o+Math.cos(j)*p,s=function(a){return Math.sqrt(a[0]*a[0]+a[1]*a[1])},t=function(a,b){return(a[0]*b[0]+a[1]*b[1])/(s(a)*s(b))},u=function(a,b){return(a[0]*b[1]=1&&(y=0),f==0&&y>0&&(y-=2*Math.PI),f==1&&y<0&&(y+=2*Math.PI),[q,r,g,h,v,y,j,f]}}),Kinetic.Node.addGettersSetters(Kinetic.Path,["data"]),Kinetic.Transform=function(){this.m=[1,0,0,1,0,0]},Kinetic.Transform.prototype={translate:function(a,b){this.m[4]+=this.m[0]*a+this.m[2]*b,this.m[5]+=this.m[1]*a+this.m[3]*b},scale:function(a,b){this.m[0]*=a,this.m[1]*=a,this.m[2]*=b,this.m[3]*=b},rotate:function(a){var b=Math.cos(a),c=Math.sin(a),d=this.m[0]*b+this.m[2]*c,e=this.m[1]*b+this.m[3]*c,f=this.m[0]*-c+this.m[2]*b,g=this.m[1]*-c+this.m[3]*b;this.m[0]=d,this.m[1]=e,this.m[2]=f,this.m[3]=g},getTranslation:function(){return{x:this.m[4],y:this.m[5]}},multiply:function(a){var b=this.m[0]*a.m[0]+this.m[2]*a.m[1],c=this.m[1]*a.m[0]+this.m[3]*a.m[1],d=this.m[0]*a.m[2]+this.m[2]*a.m[3],e=this.m[1]*a.m[2]+this.m[3]*a.m[3],f=this.m[0]*a.m[4]+this.m[2]*a.m[5]+this.m[4],g=this.m[1]*a.m[4]+this.m[3]*a.m[5]+this.m[5];this.m[0]=b,this.m[1]=c,this.m[2]=d,this.m[3]=e,this.m[4]=f,this.m[5]=g},invert:function(){var a=1/(this.m[0]*this.m[3]-this.m[1]*this.m[2]),b=this.m[3]*a,c=-this.m[1]*a,d=-this.m[2]*a,e=this.m[0]*a,f=a*(this.m[2]*this.m[5]-this.m[3]*this.m[4]),g=a*(this.m[1]*this.m[4]-this.m[0]*this.m[5]);this.m[0]=b,this.m[1]=c,this.m[2]=d,this.m[3]=e,this.m[4]=f,this.m[5]=g},getMatrix:function(){return this.m}},Kinetic.Transition=function(a,b){function d(a,b,e,f){for(var g in a)g!=="duration"&&g!=="easing"&&g!=="callback"&&(Kinetic.Type._isObject(a[g])?(e[g]={},d(a[g],b[g],e[g],f)):c._add(c._getTween(b,g,a[g],e,f)))}this.node=a,this.config=b,this.tweens=[];var c=this,e={};d(b,a.attrs,e,e);var f=0;for(var g=0;g=c.tweens.length&&c.onFinished()}}},Kinetic.Transition.prototype={start:function(){for(var a=0;athis.getDuration()?this.looping?(this.rewind(a-this._duration),this.update(),this.broadcastMessage("onLooped",{target:this,type:"onLooped"})):(this._time=this._duration,this.update(),this.stop(),this.broadcastMessage("onFinished",{target:this,type:"onFinished"})):a<0?(this.rewind(),this.update()):(this._time=a,this.update())},getTime:function(){return this._time},setDuration:function(a){this._duration=a===null||a<=0?1e5:a},getDuration:function(){return this._duration},setPosition:function(a){this.prevPos=this._pos,this.propFunc(a),this._pos=a,this.broadcastMessage("onChanged",{target:this,type:"onChanged"})},getPosition:function(a){return a===undefined&&(a=this._time),this.func(a,this.begin,this._change,this._duration)},setFinish:function(a){this._change=a-this.begin},getFinish:function(){return this.begin+this._change},start:function(){this.rewind(),this.startEnterFrame(),this.broadcastMessage("onStarted",{target:this,type:"onStarted"})},rewind:function(a){this.stop(),this._time=a===undefined?0:a,this.fixTime(),this.update()},fforward:function(){this._time=this._duration,this.fixTime(),this.update()},update:function(){this.setPosition(this.getPosition(this._time))},startEnterFrame:function(){this.stopEnterFrame(),this.isPlaying=!0,this.onEnterFrame()},onEnterFrame:function(){this.isPlaying&&this.nextFrame()},nextFrame:function(){this.setTime((this.getTimer()-this._startTime)/1e3)},stop:function(){this.stopEnterFrame(),this.broadcastMessage("onStopped",{target:this,type:"onStopped"})},stopEnterFrame:function(){this.isPlaying=!1},continueTo:function(a,b){this.begin=this._pos,this.setFinish(a),this._duration!==undefined&&this.setDuration(b),this.start()},resume:function(){this.fixTime(),this.startEnterFrame(),this.broadcastMessage("onResumed",{target:this,type:"onResumed"})},yoyo:function(){this.continueTo(this.begin,this._time)},addListener:function(a){return this.removeListener(a),this._listeners.push(a)},removeListener:function(a){var b=this._listeners,c=b.length;while(c--)if(b[c]==a)return b.splice(c,1),!0;return!1},broadcastMessage:function(){var a=[];for(var b=0;b0},_getXY:function(a){if(this._isNumber(a))return{x:a,y:a};if(this._isArray(a)){if(a.length===1){var b=a[0];if(this._isNumber(b))return{x:b,y:b};if(this._isArray(b))return{x:b[0],y:b[1]};if(this._isObject(b))return b}else if(a.length>=2)return{x:a[0],y:a[1]}}else if(this._isObject(a))return a;return{x:0,y:0}},_getSize:function(a){if(this._isNumber(a))return{width:a,height:a};if(this._isArray(a))if(a.length===1){var b=a[0];if(this._isNumber(b))return{width:b,height:b};if(this._isArray(b)){if(b.length>=4)return{width:b[2],height:b[3]};if(b.length>=2)return{width:b[0],height:b[1]}}else if(this._isObject(b))return b}else{if(a.length>=4)return{width:a[2],height:a[3]};if(a.length>=2)return{width:a[0],height:a[1]}}else if(this._isObject(a))return a;return{width:0,height:0}},_getPoints:function(a){if(a===undefined)return[];if(this._isObject(a[0]))return a;var b=[];for(var c=0;c0){this._updateFrameObject(),this._runFrames();var a=this;requestAnimFrame(function(){a._animationLoop()})}else this.animRunning=!1,this.frame.lastTime=0},_handleAnimation:function(){var a=this;this.animRunning?this.frame.lastTime=0:(this.animRunning=!0,a._animationLoop())}},requestAnimFrame=function(a){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){window.setTimeout(a,1e3/60)}}(),Kinetic.Node=Kinetic.Class.extend({init:function(a){this.defaultNodeAttrs={visible:!0,listening:!0,name:undefined,alpha:1,x:0,y:0,scale:{x:1,y:1},rotation:0,offset:{x:0,y:0},dragConstraint:"none",dragBounds:{},draggable:!1},this.setDefaultAttrs(this.defaultNodeAttrs),this.eventListeners={},this.setAttrs(a),this.on("draggableChange.kinetic",function(){this._onDraggableChange()});var b=this;this.on("idChange.kinetic",function(a){var c=b.getStage();c&&(c._removeId(a.oldVal),c._addId(b))}),this.on("nameChange.kinetic",function(a){var c=b.getStage();c&&(c._removeName(a.oldVal,b._id),c._addName(b))}),this._onDraggableChange()},on:function(a,b){var c=a.split(" ");for(var d=0;d1?g[1]:"";this.eventListeners[h]||(this.eventListeners[h]=[]),this.eventListeners[h].push({name:i,handler:b})}},off:function(a){var b=a.split(" ");for(var c=0;c1){var h=f[1];for(var i=0;i0&&f[0].getLevel()<=a&&e(f)}var a=this.getLevel(),b=this.getStage(),c=this,d=0;return c.nodeType!=="Stage"&&e(c.getStage().getChildren()),d},getLevel:function(){var a=0,b=this.parent;while(b)a++,b=b.parent;return a},setPosition:function(){var a=Kinetic.Type._getXY(Array.prototype.slice.call(arguments));this.setAttrs(a)},getPosition:function(){return{x:this.attrs.x,y:this.attrs.y}},getAbsolutePosition:function(){var a=this.getAbsoluteTransform(),b=this.getOffset();return a.translate(b.x,b.y),a.getTranslation()},setAbsolutePosition:function(){var a=Kinetic.Type._getXY(Array.prototype.slice.call(arguments)),b=this.attrs.rotation,c={x:this.attrs.scale.x,y:this.attrs.scale.y},d={x:this.attrs.offset.x,y:this.attrs.offset.y};this.attrs.rotation=0,this.attrs.scale={x:1,y:1},this.attrs.offset={x:0,y:0};var e=this.getOffset(),f=this.getAbsoluteTransform();f.invert(),f.translate(a.x,a.y),a={x:this.attrs.x+f.getTranslation().x,y:this.attrs.y+f.getTranslation().y},this.setPosition(a.x,a.y),this.rotate(b),this.attrs.scale={x:c.x,y:c.y},this.attrs.offset={x:d.x,y:d.y}},move:function(){var a=Kinetic.Type._getXY(Array.prototype.slice.call(arguments)),b=this.getX(),c=this.getY();a.x!==undefined&&(b+=a.x),a.y!==undefined&&(c+=a.y),this.setAttrs({x:b,y:c})},getRotationDeg:function(){return this.attrs.rotation*180/Math.PI},rotate:function(a){this.setAttrs({rotation:this.getRotation()+a})},rotateDeg:function(a){this.setAttrs({rotation:this.getRotation()+a*Math.PI/180})},moveToTop:function(){var a=this.index;this.parent.children.splice(a,1),this.parent.children.push(this),this.parent._setChildrenIndices()},moveUp:function(){var a=this.index;this.parent.children.splice(a,1),this.parent.children.splice(a+1,0,this),this.parent._setChildrenIndices()},moveDown:function(){var a=this.index;a>0&&(this.parent.children.splice(a,1),this.parent.children.splice(a-1,0,this),this.parent._setChildrenIndices())},moveToBottom:function(){var a=this.index;this.parent.children.splice(a,1),this.parent.children.unshift(this),this.parent._setChildrenIndices()},setZIndex:function(a){var b=this.index;this.parent.children.splice(b,1),this.parent.children.splice(a,0,this),this.parent._setChildrenIndices()},getAbsoluteAlpha:function(){var a=1,b=this;while(b.nodeType!=="Stage")a*=b.attrs.alpha,b=b.parent;return a},isDragging:function(){var a=Kinetic.Global;return a.drag.node!==undefined&&a.drag.node._id===this._id&&a.drag.moving},moveTo:function(a){var b=this.parent;b.children.splice(this.index,1),b._setChildrenIndices(),a.children.push(this),this.index=a.children.length-1,this.parent=a,a._setChildrenIndices()},getParent:function(){return this.parent},getLayer:function(){return this.nodeType==="Layer"?this:this.getParent().getLayer()},getStage:function(){return this.nodeType!=="Stage"&&this.getParent()?this.getParent().getStage():this.nodeType==="Stage"?this:undefined},simulate:function(a){this._handleEvent(a,{})},transitionTo:function(a){var b=Kinetic.Animation;this.transAnim&&(b._removeAnimation(this.transAnim),this.transAnim=null);var c=this.nodeType==="Stage"?this:this.getLayer(),d=this,e=new Kinetic.Transition(this,a),f={func:function(){e._onEnterFrame()},node:c};return this.transAnim=f,b._addAnimation(f),e.onFinished=function(){b._removeAnimation(f),d.transAnim=null,a.callback!==undefined&&a.callback(),f.node.draw()},e.start(),b._handleAnimation(),e},getAbsoluteTransform:function(){var a=new Kinetic.Transform,b=[],c=this.parent;b.unshift(this);while(c)b.unshift(c),c=c.parent;for(var d=0;d=0&&!b.cancelBubble&&this.parent&&this._handleEvent.call(this.parent,a,b)}}}),Kinetic.Node.addSetters=function(constructor,a){for(var b=0;b0)this.remove(this.children[0])},add:function(a){a._id=Kinetic.Global.idCounter++,a.index=this.children.length,a.parent=this,this.children.push(a);var b=a.getStage();if(b===undefined){var c=Kinetic.Global;c.tempNodes.push(a)}else{b._addId(a),b._addName(a);var c=Kinetic.Global;c._pullNodes(b)}return this._add!==undefined&&this._add(a),this},remove:function(a){if(a&&a.index!==undefined&&this.children[a.index]._id==a._id){var b=this.getStage();b!==undefined&&(b._removeId(a.getId()),b._removeName(a.getName(),a._id));var c=Kinetic.Global;for(var d=0;d0)a.remove(a.children[0]);this._remove!==undefined&&this._remove(a)}return this},get:function(a){var b=this.getStage(),c,d=a.slice(1);if(a.charAt(0)==="#")c=b.ids[d]!==undefined?[b.ids[d]]:[];else{if(a.charAt(0)!==".")return a==="Shape"||a==="Group"||a==="Layer"?this._getNodes(a):!1;c=b.names[d]!==undefined?b.names[d]:[]}var e=[];for(var f=0;f=0;d--){var e=c[d];if(e.getListening())if(e.nodeType==="Shape"){var f=this._detectEvent(e,b);if(f)return!0}else{var f=this._traverseChildren(e,b);if(f)return!0}}return!1},_handleStageEvent:function(a){var b=new Date,c=b.getTime();this.lastEventTime=c;var d=Kinetic.Global;a||(a=window.event),this._setMousePosition(a),this._setTouchPosition(a),this.pathCanvas.clear(),this.targetFound=!1;var e=!1;for(var f=this.children.length-1;f>=0;f--){var g=this.children[f];if(g.isVisible()&&f>=0&&g.getListening()&&this._traverseChildren(g,a)){e=!0;break}}!e&&this.mouseoutShape&&(this.mouseoutShape._handleEvent("mouseout",a),this.mouseoutShape=undefined)},_bindContentEvents:function(){var a=Kinetic.Global,b=this,c=["mousedown","mousemove","mouseup","mouseover","mouseout","touchstart","touchmove","touchend"];for(var d=0;d=f||b>200)this.mouseDown=!1,this.mouseUp=!1,this.mouseMove=!0,this._handleStageEvent(a);this._startDrag(a)},_mousedown:function(a){this.mouseDown=!0,this.mouseUp=!1,this.mouseMove=!1,this._handleStageEvent(a),this.attrs.draggable&&this._initDrag()},_mouseup:function(a){this.mouseDown=!1,this.mouseUp=!0,this.mouseMove=!1,this._handleStageEvent(a),this.clickStart=!1,this._endDrag(a)},_touchstart:function(a){a.preventDefault(),this.touchStart=!0,this.touchEnd=!1,this.touchMove=!1,this._handleStageEvent(a),this.attrs.draggable&&this._initDrag()},_touchend:function(a){this.touchStart=!1,this.touchEnd=!0,this.touchMove=!1,this._handleStageEvent(a),this.tapStart=!1,this._endDrag(a)},_touchmove:function(a){var b=this,c=this.attrs.throttle,d=new Date,e=d.getTime(),f=e-this.lastEventTime,g=1e3/c;if(f>=g||c>200)a.preventDefault(),b.touchEnd=!1,b.touchMove=!0,b._handleStageEvent(a);this._startDrag(a)},_setMousePosition:function(a){var b=a.offsetX||a.clientX-this._getContentPosition().left+window.pageXOffset,c=a.offsetY||a.clientY-this._getContentPosition().top+window.pageYOffset;this.mousePos={x:b,y:c}},_setTouchPosition:function(a){if(a.touches!==undefined&&a.touches.length===1){var b=a.touches[0],c=b.clientX-this._getContentPosition().left+window.pageXOffset,d=b.clientY-this._getContentPosition().top+window.pageYOffset;this.touchPos={x:c,y:d}}},_getContentPosition:function(){var a=this.content,b=0,c=0;while(a&&a.tagName!=="BODY")b+=a.offsetTop-a.scrollTop,c+=a.offsetLeft-a.scrollLeft,a=a.offsetParent;return{top:b,left:c}},_endDrag:function(a){var b=Kinetic.Global;b.drag.node&&b.drag.moving&&(b.drag.moving=!1,b.drag.node._handleEvent("dragend",a)),b.drag.node=undefined},_startDrag:function(a){var b=this,c=Kinetic.Global,d=c.drag.node;if(d){var e=b.getUserPosition(),f=d.attrs.dragConstraint,g=d.attrs.dragBounds,h={x:d.attrs.x,y:d.attrs.y},i={x:e.x-c.drag.offset.x,y:e.y-c.drag.offset.y};g.left!==undefined&&i.xg.right&&(i.x=g.right),g.top!==undefined&&i.yg.bottom&&(i.y=g.bottom),d.setAbsolutePosition(i),f==="horizontal"?d.attrs.y=h.y:f==="vertical"&&(d.attrs.x=h.x),c.drag.node.nodeType==="Stage"?c.drag.node.draw():c.drag.node.getLayer().draw(),c.drag.moving||(c.drag.moving=!0,c.drag.node._handleEvent("dragstart",a)),c.drag.node._handleEvent("dragmove",a)}},_buildDOM:function(){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.Canvas({width:this.attrs.width,height:this.attrs.height}),this.pathCanvas=new Kinetic.Canvas({width:this.attrs.width,height:this.attrs.height}),this.pathCanvas.strip(),this._resizeDOM()},_addId:function(a){a.attrs.id!==undefined&&(this.ids[a.attrs.id]=a)},_removeId:function(a){a!==undefined&&delete this.ids[a]},_addName:function(a){var b=a.attrs.name;b!==undefined&&(this.names[b]===undefined&&(this.names[b]=[]),this.names[b].push(a))},_removeName:function(a,b){if(a!==undefined){var c=this.names[a];if(c!==undefined){for(var d=0;d=f||b>200)this._draw(a),this.drawTimeout!==undefined&&(clearTimeout(this.drawTimeout),this.drawTimeout=undefined);else if(this.drawTimeout===undefined){var g=this;this.drawTimeout=setTimeout(function(){g.draw(a)},17)}},beforeDraw:function(a){this.beforeDrawFunc=a},afterDraw:function(a){this.afterDrawFunc=a},getCanvas:function(){return this.canvas},getContext:function(){return this.canvas.context},toDataURL:function(a,b){try{return this.getCanvas().element.toDataURL(a,b)}catch(c){return this.getCanvas().element.toDataURL()}},_draw:function(a){a||(a=this.getCanvas());var b=new Date,c=b.getTime();this.lastDrawTime=c,this.beforeDrawFunc!==undefined&&this.beforeDrawFunc.call(this),this.attrs.clearBeforeDraw&&a.clear(),this.isVisible()&&(this.attrs.drawFunc!==undefined&&this.attrs.drawFunc.call(this),this._drawChildren(a)),this.afterDrawFunc!==undefined&&this.afterDrawFunc.call(this)}}),Kinetic.Node.addGettersSetters(Kinetic.Layer,["clearBeforeDraw","throttle"]),Kinetic.Group=Kinetic.Container.extend({init:function(a){this.nodeType="Group",this._super(a)},draw:function(a){this._draw(a)},_draw:function(a){this.attrs.visible&&this._drawChildren(a)}}),Kinetic.Shape=Kinetic.Node.extend({init:function(a){this.setDefaultAttrs({detectionType:"path"}),this.nodeType="Shape",this.appliedShadow=!1,this._super(a)},getContext:function(){return this.getLayer().getContext()},getCanvas:function(){return this.getLayer().getCanvas()},stroke:function(a){var b=Kinetic.Global,c=!1;if(this.attrs.stroke||this.attrs.strokeWidth){a.save(),this.attrs.shadow&&!this.appliedShadow&&(c=this._applyShadow(a));var d=this.attrs.stroke?this.attrs.stroke:"black",e=this.attrs.strokeWidth?this.attrs.strokeWidth:2;a.lineWidth=e,a.strokeStyle=d,a.stroke(a),a.restore()}c&&this.stroke(a)},fill:function(a){var b=!1;a.save();var c=this.attrs.fill;if(c){this.attrs.shadow&&!this.appliedShadow&&(b=this._applyShadow(a));var d=c.start,e=c.end,f=null;if(typeof c=="string")f=this.attrs.fill,a.fillStyle=f,a.fill(a);else if(c.image){var g=c.repeat?c.repeat:"repeat";f=a.createPattern(c.image,g),a.save(),c.scale&&a.scale(c.scale.x,c.scale.y),c.offset&&a.translate(c.offset.x,c.offset.y),a.fillStyle=f,a.fill(a),a.restore()}else if(!d.radius&&!e.radius){var h=a.createLinearGradient(d.x,d.y,e.x,e.y),i=c.colorStops;for(var j=0;j0&&d&&(this.attrs.height==="auto"||e*(c+1)this.attrs.width-this.attrs.padding*2){if(f==0)break;var i=h.lastIndexOf(" "),j=h.lastIndexOf("-"),k=Math.max(i,j);if(k>=0){g=a.splice(0,1+k).join("");break}g=a.splice(0,f).join("");break}f++,f===a.length&&(g=a.splice(0,f).join(""))}this.textWidth=Math.max(this.textWidth,this._getTextSize(g).width),g!==undefined&&(b.push(g),d=!0),c++}this.textArr=b}}),Kinetic.Node.addGettersSetters(Kinetic.Text,["fontFamily","fontSize","fontStyle","textFill","textStroke","textStrokeWidth","padding","align","lineHeight","text","width","height","cornerRadius","fill","stroke","strokeWidth","shadow"]),Kinetic.Line=Kinetic.Shape.extend({init:function(a){this.setDefaultAttrs({points:[],lineCap:"butt",dashArray:[],detectionType:"pixel"}),this.shapeType="Line",a.drawFunc=function(a){var b={};a.beginPath(),a.moveTo(this.attrs.points[0].x,this.attrs.points[0].y);for(var c=1;c0){var f=this.attrs.points[c-1].x,g=this.attrs.points[c-1].y;this._dashedLine(a,f,g,d,e,this.attrs.dashArray)}else a.lineTo(d,e)}!this.attrs.lineCap||(a.lineCap=this.attrs.lineCap),this.stroke(a)},this._super(a)},_dashedLine:function(a,b,c,d,e,f){var g=f.length,h=d-b,i=e-c,j=h>i,k=j?i/h:h/i;k>9999?k=9999:k<-9999&&(k=-9999);var l=Math.sqrt(h*h+i*i),m=0,n=!0;while(l>=.1&&m<1e4){var o=f[m++%g];o===0&&(o=.001),o>l&&(o=l);var p=Math.sqrt(o*o/(1+k*k));j?(b+=h<0&&i<0?p*-1:p,c+=h<0&&i<0?k*p*-1:k*p):(b+=h<0&&i<0?k*p*-1:k*p,c+=h<0&&i<0?p*-1:p),a[n?"lineTo":"moveTo"](b,c),l-=o,n=!n}a.moveTo(d,e)}}),Kinetic.Node.addGettersSetters(Kinetic.Line,["dashArray","lineCap","points"]),Kinetic.Path=Kinetic.Shape.extend({init:function(a){this.shapeType="Path",this.dataArray=[];var b=this;a.drawFunc=function(a){var b=this.dataArray;a.beginPath();for(var c=0;ci?h:i,o=h>i?1:h/i,p=h>i?i/h:1;a.translate(f,g),a.rotate(l),a.scale(o,p),a.arc(0,0,n,j,j+k,1-m),a.scale(1/o,1/p),a.rotate(-l),a.translate(-f,-g);break;case"z":a.closePath()}}this.fill(a),this.stroke(a)},this._super(a),this.dataArray=this._getDataArray(),this.on("dataChange",function(){b.dataArray=b._getDataArray()})},_getDataArray:function(){var a=this.attrs.data;if(!this.attrs.data)return[];var b=["m","M","l","L","v","V","h","H","z","Z","c","C","q","Q","t","T","s","S","a","A"];a=a.replace(new RegExp(" ","g"),",");for(var c=0;c0&&j[0]===""&&j.shift();for(var k=0;k0){if(isNaN(j[0]))break;var l=undefined,m=[];switch(i){case"l":f+=j.shift(),g+=j.shift(),l="L",m.push(f,g);break;case"L":f=j.shift(),g=j.shift(),m.push(f,g);break;case"m":f+=j.shift(),g+=j.shift(),l="M",m.push(f,g),i="l";break;case"M":f=j.shift(),g=j.shift(),l="M",m.push(f,g),i="L";break;case"h":f+=j.shift(),l="L",m.push(f,g);break;case"H":f=j.shift(),l="L",m.push(f,g);break;case"v":g+=j.shift(),l="L",m.push(f,g);break;case"V":g=j.shift(),l="L",m.push(f,g);break;case"C":m.push(j.shift(),j.shift(),j.shift(),j.shift()),f=j.shift(),g=j.shift(),m.push(f,g);break;case"c":m.push(f+j.shift(),g+j.shift(),f+j.shift(),g+j.shift()),f+=j.shift(),g+=j.shift(),l="C",m.push(f,g);break;case"S":var n=f,o=g,p=e[e.length-1];p.command==="C"&&(n=f+(f-p.points[2]),o=g+(g-p.points[3])),m.push(n,o,j.shift(),j.shift()),f=j.shift(),g=j.shift(),l="C",m.push(f,g);break;case"s":var n=f,o=g,p=e[e.length-1];p.command==="C"&&(n=f+(f-p.points[2]),o=g+(g-p.points[3])),m.push(n,o,f+j.shift(),g+j.shift()),f+=j.shift(),g+=j.shift(),l="C",m.push(f,g);break;case"Q":m.push(j.shift(),j.shift()),f=j.shift(),g=j.shift(),m.push(f,g);break;case"q":m.push(f+j.shift(),g+j.shift()),f+=j.shift(),g+=j.shift(),l="Q",m.push(f,g);break;case"T":var n=f,o=g,p=e[e.length-1];p.command==="Q"&&(n=f+(f-p.points[0]),o=g+(g-p.points[1])),f=j.shift(),g=j.shift(),l="Q",m.push(n,o,f,g);break;case"t":var n=f,o=g,p=e[e.length-1];p.command==="Q"&&(n=f+(f-p.points[0]),o=g+(g-p.points[1])),f+=j.shift(),g+=j.shift(),l="Q",m.push(n,o,f,g);break;case"A":var q=j.shift(),r=j.shift(),s=j.shift(),t=j.shift(),u=j.shift(),v=f,w=g;f=j.shift(),g=j.shift(),l="A",m=this._convertEndpointToCenterParameterization(v,w,f,g,t,u,q,r,s);break;case"a":var q=j.shift(),r=j.shift(),s=j.shift(),t=j.shift(),u=j.shift(),v=f,w=g;f+=j.shift(),g+=j.shift(),l="A",m=this._convertEndpointToCenterParameterization(v,w,f,g,t,u,q,r,s)}e.push({command:l||i,points:m})}(i==="z"||i==="Z")&&e.push({command:"z",points:[]})}return e},_convertEndpointToCenterParameterization:function(a,b,c,d,e,f,g,h,i){var j=i*(Math.PI/180),k=Math.cos(j)*(a-c)/2+Math.sin(j)*(b-d)/2,l=-1*Math.sin(j)*(a-c)/2+Math.cos(j)*(b-d)/2,m=k*k/(g*g)+l*l/(h*h);m>1&&(g*=Math.sqrt(m),h*=Math.sqrt(m));var n=Math.sqrt((g*g*h*h-g*g*l*l-h*h*k*k)/(g*g*l*l+h*h*k*k));e==f&&(n*=-1),isNaN(n)&&(n=0);var o=n*g*l/h,p=n*-h*k/g,q=(a+c)/2+Math.cos(j)*o-Math.sin(j)*p,r=(b+d)/2+Math.sin(j)*o+Math.cos(j)*p,s=function(a){return Math.sqrt(a[0]*a[0]+a[1]*a[1])},t=function(a,b){return(a[0]*b[0]+a[1]*b[1])/(s(a)*s(b))},u=function(a,b){return(a[0]*b[1]=1&&(y=0),f==0&&y>0&&(y-=2*Math.PI),f==1&&y<0&&(y+=2*Math.PI),[q,r,g,h,v,y,j,f]}}),Kinetic.Node.addGettersSetters(Kinetic.Path,["data"]),Kinetic.Transform=function(){this.m=[1,0,0,1,0,0]},Kinetic.Transform.prototype={translate:function(a,b){this.m[4]+=this.m[0]*a+this.m[2]*b,this.m[5]+=this.m[1]*a+this.m[3]*b},scale:function(a,b){this.m[0]*=a,this.m[1]*=a,this.m[2]*=b,this.m[3]*=b},rotate:function(a){var b=Math.cos(a),c=Math.sin(a),d=this.m[0]*b+this.m[2]*c,e=this.m[1]*b+this.m[3]*c,f=this.m[0]*-c+this.m[2]*b,g=this.m[1]*-c+this.m[3]*b;this.m[0]=d,this.m[1]=e,this.m[2]=f,this.m[3]=g},getTranslation:function(){return{x:this.m[4],y:this.m[5]}},multiply:function(a){var b=this.m[0]*a.m[0]+this.m[2]*a.m[1],c=this.m[1]*a.m[0]+this.m[3]*a.m[1],d=this.m[0]*a.m[2]+this.m[2]*a.m[3],e=this.m[1]*a.m[2]+this.m[3]*a.m[3],f=this.m[0]*a.m[4]+this.m[2]*a.m[5]+this.m[4],g=this.m[1]*a.m[4]+this.m[3]*a.m[5]+this.m[5];this.m[0]=b,this.m[1]=c,this.m[2]=d,this.m[3]=e,this.m[4]=f,this.m[5]=g},invert:function(){var a=1/(this.m[0]*this.m[3]-this.m[1]*this.m[2]),b=this.m[3]*a,c=-this.m[1]*a,d=-this.m[2]*a,e=this.m[0]*a,f=a*(this.m[2]*this.m[5]-this.m[3]*this.m[4]),g=a*(this.m[1]*this.m[4]-this.m[0]*this.m[5]);this.m[0]=b,this.m[1]=c,this.m[2]=d,this.m[3]=e,this.m[4]=f,this.m[5]=g},getMatrix:function(){return this.m}},Kinetic.Transition=function(a,b){function d(a,b,e,f){for(var g in a)g!=="duration"&&g!=="easing"&&g!=="callback"&&(Kinetic.Type._isObject(a[g])?(e[g]={},d(a[g],b[g],e[g],f)):c._add(c._getTween(b,g,a[g],e,f)))}this.node=a,this.config=b,this.tweens=[];var c=this,e={};d(b,a.attrs,e,e);var f=0;for(var g=0;g=c.tweens.length&&c.onFinished()}}},Kinetic.Transition.prototype={start:function(){for(var a=0;athis.getDuration()?this.looping?(this.rewind(a-this._duration),this.update(),this.broadcastMessage("onLooped",{target:this,type:"onLooped"})):(this._time=this._duration,this.update(),this.stop(),this.broadcastMessage("onFinished",{target:this,type:"onFinished"})):a<0?(this.rewind(),this.update()):(this._time=a,this.update())},getTime:function(){return this._time},setDuration:function(a){this._duration=a===null||a<=0?1e5:a},getDuration:function(){return this._duration},setPosition:function(a){this.prevPos=this._pos,this.propFunc(a),this._pos=a,this.broadcastMessage("onChanged",{target:this,type:"onChanged"})},getPosition:function(a){return a===undefined&&(a=this._time),this.func(a,this.begin,this._change,this._duration)},setFinish:function(a){this._change=a-this.begin},getFinish:function(){return this.begin+this._change},start:function(){this.rewind(),this.startEnterFrame(),this.broadcastMessage("onStarted",{target:this,type:"onStarted"})},rewind:function(a){this.stop(),this._time=a===undefined?0:a,this.fixTime(),this.update()},fforward:function(){this._time=this._duration,this.fixTime(),this.update()},update:function(){this.setPosition(this.getPosition(this._time))},startEnterFrame:function(){this.stopEnterFrame(),this.isPlaying=!0,this.onEnterFrame()},onEnterFrame:function(){this.isPlaying&&this.nextFrame()},nextFrame:function(){this.setTime((this.getTimer()-this._startTime)/1e3)},stop:function(){this.stopEnterFrame(),this.broadcastMessage("onStopped",{target:this,type:"onStopped"})},stopEnterFrame:function(){this.isPlaying=!1},continueTo:function(a,b){this.begin=this._pos,this.setFinish(a),this._duration!==undefined&&this.setDuration(b),this.start()},resume:function(){this.fixTime(),this.startEnterFrame(),this.broadcastMessage("onResumed",{target:this,type:"onResumed"})},yoyo:function(){this.continueTo(this.begin,this._time)},addListener:function(a){return this.removeListener(a),this._listeners.push(a)},removeListener:function(a){var b=this._listeners,c=b.length;while(c--)if(b[c]==a)return b.splice(c,1),!0;return!1},broadcastMessage:function(){var a=[];for(var b=0;b= tt || throttle > 200) { - this._draw(layer); + this._draw(canvas); if(this.drawTimeout !== undefined) { clearTimeout(this.drawTimeout); @@ -58,7 +57,7 @@ Kinetic.Layer = Kinetic.Container.extend({ * wait 17ms before trying again (60fps) */ this.drawTimeout = setTimeout(function() { - that.draw(layer); + that.draw(canvas); }, 17); } }, @@ -78,19 +77,6 @@ Kinetic.Layer = Kinetic.Container.extend({ afterDraw: function(func) { this.afterDrawFunc = func; }, - /** - * clears the canvas context tied to the layer. Clearing - * a layer does not remove its children. The nodes within - * the layer will be redrawn whenever the .draw() method - * is used again. - * @name clear - * @methodOf Kinetic.Layer.prototype - */ - clear: function() { - var context = this.getContext(); - var canvas = this.getCanvas(); - context.clearRect(0, 0, canvas.width, canvas.height); - }, /** * get layer canvas * @name getCanvas @@ -100,12 +86,12 @@ Kinetic.Layer = Kinetic.Container.extend({ return this.canvas; }, /** - * get layer context + * get layer canvas context * @name getContext * @methodOf Kinetic.Layer.prototype */ getContext: function() { - return this.context; + return this.canvas.context; }, /** * Creates a composite data URL. If MIME type is not @@ -115,7 +101,7 @@ Kinetic.Layer = Kinetic.Container.extend({ * based on what's draw on the layer, rather than drawing * the current state of each child node * @name toDataURL - * @methodOf Kinetic.Stage.prototype + * @methodOf Kinetic.Layer.prototype * @param {String} [mimeType] * @param {Number} [quality] */ @@ -123,16 +109,24 @@ Kinetic.Layer = Kinetic.Container.extend({ try { // If this call fails (due to browser bug, like in Firefox 3.6), // then revert to previous no-parameter image/png behavior - return this.getCanvas().toDataURL(mimeType, quality); + return this.getCanvas().element.toDataURL(mimeType, quality); } catch(e) { - return this.getCanvas().toDataURL(); + return this.getCanvas().element.toDataURL(); } }, /** * private draw children */ - _draw: function(layer) { + _draw: function(canvas) { + /* + * if canvas is not defined, then use the canvas + * tied to the layer + */ + if(!canvas) { + canvas = this.getCanvas(); + } + var date = new Date(); var time = date.getTime(); this.lastDrawTime = time; @@ -143,8 +137,7 @@ Kinetic.Layer = Kinetic.Container.extend({ } if(this.attrs.clearBeforeDraw) { - var clearLayer = layer ? layer : this; - clearLayer.clear(); + canvas.clear(); } if(this.isVisible()) { @@ -154,7 +147,7 @@ Kinetic.Layer = Kinetic.Container.extend({ } // draw children - this._drawChildren(layer); + this._drawChildren(canvas); } // after draw handler diff --git a/src/Node.js b/src/Node.js index 574a7b20..00354fd7 100644 --- a/src/Node.js +++ b/src/Node.js @@ -386,7 +386,10 @@ Kinetic.Node = Kinetic.Class.extend({ * @methodOf Kinetic.Node.prototype */ getAbsolutePosition: function() { - return this.getAbsoluteTransform().getTranslation(); + var trans = this.getAbsoluteTransform(); + var o = this.getOffset(); + trans.translate(o.x, o.y); + return trans.getTranslation(); }, /** * set absolute position relative to stage @@ -416,9 +419,16 @@ Kinetic.Node = Kinetic.Class.extend({ x: 1, y: 1 }; + this.attrs.offset = { + x: 0, + y: 0 + }; + + var o = this.getOffset(); // unravel transform var it = this.getAbsoluteTransform(); + it.invert(); it.translate(pos.x, pos.y); pos = { @@ -434,6 +444,10 @@ Kinetic.Node = Kinetic.Class.extend({ x: scale.x, y: scale.y }; + this.attrs.offset = { + x: offset.x, + y: offset.y + }; }, /** * move node by an amount @@ -727,7 +741,6 @@ Kinetic.Node = Kinetic.Class.extend({ for(var n = 0; n < family.length; n++) { var node = family[n]; var m = node.getTransform(); - am.multiply(m); } @@ -803,14 +816,14 @@ Kinetic.Node = Kinetic.Class.extend({ saveImageData: function() { try { var stage = this.getStage(); - var bufferLayer = stage.bufferLayer; - var bufferLayerContext = bufferLayer.getContext(); + var bufferCanvas = stage.bufferCanvas; + var bufferContext = bufferCanvas.getContext(); var width = stage.getWidth(); var height = stage.getHeight(); - bufferLayer.clear(); - this._draw(bufferLayer); - var imageData = bufferLayerContext.getImageData(0, 0, width, height); + bufferCanvas.clear(); + this._draw(bufferCanvas); + var imageData = bufferContext.getImageData(0, 0, width, height); this.imageData = imageData; } catch(e) { @@ -838,24 +851,23 @@ Kinetic.Node = Kinetic.Class.extend({ * specified, then "image/png" will result. For "image/jpeg", specify a quality * level as quality (range 0.0 - 1.0) * @name toDataURL - * @methodOf Kinetic.Stage.prototype + * @methodOf Kinetic.Node.prototype * @param {String} [mimeType] * @param {Number} [quality] */ toDataURL: function(mimeType, quality) { - var bufferLayer = this.getStage().bufferLayer; - var bufferCanvas = bufferLayer.getCanvas(); - var bufferContext = bufferLayer.getContext(); - bufferLayer.clear(); - this._draw(bufferLayer); + var bufferCanvas = this.getStage().bufferCanvas; + var bufferContext = bufferCanvas.getContext(); + bufferCanvas.clear(); + this._draw(bufferCanvas); try { // If this call fails (due to browser bug, like in Firefox 3.6), // then revert to previous no-parameter image/png behavior - return bufferLayer.getCanvas().toDataURL(mimeType, quality); + return bufferCanvas.element.toDataURL(mimeType, quality); } catch(e) { - return bufferLayer.getCanvas().toDataURL(); + return bufferCanvas.element.toDataURL(); } }, /** @@ -910,9 +922,10 @@ Kinetic.Node = Kinetic.Class.extend({ if(pos) { var m = this.getTransform().getTranslation(); var am = this.getAbsoluteTransform().getTranslation(); + var ap = this.getAbsolutePosition(); go.drag.node = this; - go.drag.offset.x = pos.x - this.getAbsoluteTransform().getTranslation().x; - go.drag.offset.y = pos.y - this.getAbsoluteTransform().getTranslation().y; + go.drag.offset.x = pos.x - ap.x; + go.drag.offset.y = pos.y - ap.y; } }, _onDraggableChange: function() { diff --git a/src/Shape.js b/src/Shape.js index 357d36f5..c8133ee7 100644 --- a/src/Shape.js +++ b/src/Shape.js @@ -30,24 +30,20 @@ Kinetic.Shape = Kinetic.Node.extend({ this._super(config); }, /** - * get layer context where the shape is being drawn. When - * the shape is being rendered, .getContext() returns the context of the - * user created layer that contains the shape. When the event detection - * engine is determining whether or not an event has occured on that shape, - * .getContext() returns the context of the invisible path layer. + * get canvas context tied to the layer * @name getContext * @methodOf Kinetic.Shape.prototype */ getContext: function() { - return this.tempLayer.getContext(); + return this.getLayer().getContext(); }, /** - * get shape temp layer canvas + * get canvas tied to the layer * @name getCanvas * @methodOf Kinetic.Shape.prototype */ getCanvas: function() { - return this.tempLayer.getCanvas(); + return this.getLayer().getCanvas(); }, /** * helper method to stroke the shape and apply @@ -55,15 +51,14 @@ Kinetic.Shape = Kinetic.Node.extend({ * @name stroke * @methodOf Kinetic.Shape.prototype */ - stroke: function() { + stroke: function(context) { var go = Kinetic.Global; var appliedShadow = false; - var context = this.getContext(); if(this.attrs.stroke || this.attrs.strokeWidth) { context.save(); if(this.attrs.shadow && !this.appliedShadow) { - appliedShadow = this._applyShadow(); + appliedShadow = this._applyShadow(context); } var stroke = this.attrs.stroke ? this.attrs.stroke : 'black'; @@ -71,12 +66,12 @@ Kinetic.Shape = Kinetic.Node.extend({ context.lineWidth = strokeWidth; context.strokeStyle = stroke; - context.stroke(); + context.stroke(context); context.restore(); } if(appliedShadow) { - this.stroke(); + this.stroke(context); } }, /** @@ -85,16 +80,15 @@ Kinetic.Shape = Kinetic.Node.extend({ * @name fill * @methodOf Kinetic.Shape.prototype * */ - fill: function() { + fill: function(context) { var appliedShadow = false; - var context = this.getContext(); context.save(); var fill = this.attrs.fill; if(fill) { if(this.attrs.shadow && !this.appliedShadow) { - appliedShadow = this._applyShadow(); + appliedShadow = this._applyShadow(context); } var s = fill.start; @@ -105,7 +99,7 @@ Kinetic.Shape = Kinetic.Node.extend({ if( typeof fill == 'string') { f = this.attrs.fill; context.fillStyle = f; - context.fill(); + context.fill(context); } // pattern else if(fill.image) { @@ -122,12 +116,11 @@ Kinetic.Shape = Kinetic.Node.extend({ } context.fillStyle = f; - context.fill(); + context.fill(context); context.restore(); } // linear gradient else if(!s.radius && !e.radius) { - var context = this.getContext(); var grd = context.createLinearGradient(s.x, s.y, e.x, e.y); var colorStops = fill.colorStops; @@ -137,11 +130,10 @@ Kinetic.Shape = Kinetic.Node.extend({ } f = grd; context.fillStyle = f; - context.fill(); + context.fill(context); } // radial gradient else if((s.radius || s.radius === 0) && (e.radius || e.radius === 0)) { - var context = this.getContext(); var grd = context.createRadialGradient(s.x, s.y, s.radius, e.x, e.y, e.radius); var colorStops = fill.colorStops; @@ -151,18 +143,18 @@ Kinetic.Shape = Kinetic.Node.extend({ } f = grd; context.fillStyle = f; - context.fill(); + context.fill(context); } else { f = 'black'; context.fillStyle = f; - context.fill(); + context.fill(context); } } context.restore(); if(appliedShadow) { - this.fill(); + this.fill(context); } }, /** @@ -171,13 +163,12 @@ Kinetic.Shape = Kinetic.Node.extend({ * @name fillText * @methodOf Kinetic.Shape.prototype */ - fillText: function(text) { + fillText: function(context, text) { var appliedShadow = false; - var context = this.getContext(); context.save(); if(this.attrs.textFill) { if(this.attrs.shadow && !this.appliedShadow) { - appliedShadow = this._applyShadow(); + appliedShadow = this._applyShadow(context); } context.fillStyle = this.attrs.textFill; context.fillText(text, 0, 0); @@ -185,7 +176,7 @@ Kinetic.Shape = Kinetic.Node.extend({ context.restore(); if(appliedShadow) { - this.fillText(text, 0, 0); + this.fillText(context, text, 0, 0); } }, /** @@ -195,13 +186,12 @@ Kinetic.Shape = Kinetic.Node.extend({ * @methodOf Kinetic.Shape.prototype * @param {String} text */ - strokeText: function(text) { + strokeText: function(context, text) { var appliedShadow = false; - var context = this.getContext(); context.save(); if(this.attrs.textStroke || this.attrs.textStrokeWidth) { if(this.attrs.shadow && !this.appliedShadow) { - appliedShadow = this._applyShadow(); + appliedShadow = this._applyShadow(context); } // defaults @@ -213,12 +203,12 @@ Kinetic.Shape = Kinetic.Node.extend({ } context.lineWidth = this.attrs.textStrokeWidth; context.strokeStyle = this.attrs.textStroke; - context.strokeText(text, 0, 0); + context.strokeText(context, text, 0, 0); } context.restore(); if(appliedShadow) { - this.strokeText(text, 0, 0); + this.strokeText(context, text, 0, 0); } }, /** @@ -229,21 +219,20 @@ Kinetic.Shape = Kinetic.Node.extend({ */ drawImage: function() { var appliedShadow = false; - var context = this.getContext(); + var context = arguments[0]; context.save(); var a = Array.prototype.slice.call(arguments); - if(a.length === 5 || a.length === 9) { + if(a.length === 6 || a.length === 10) { if(this.attrs.shadow && !this.appliedShadow) { - appliedShadow = this._applyShadow(); + appliedShadow = this._applyShadow(context); } - switch(a.length) { - case 5: - context.drawImage(a[0], a[1], a[2], a[3], a[4]); - break; - case 9: - context.drawImage(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); - break; + + if(a.length === 6) { + context.drawImage(a[1], a[2], a[3], a[4], a[5]); + } + else { + context.drawImage(a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]); } } @@ -259,8 +248,7 @@ Kinetic.Shape = Kinetic.Node.extend({ * @name applyLineJoin * @methodOf Kinetic.Shape.prototype */ - applyLineJoin: function() { - var context = this.getContext(); + applyLineJoin: function(context) { if(this.attrs.lineJoin) { context.lineJoin = this.attrs.lineJoin; } @@ -269,8 +257,7 @@ Kinetic.Shape = Kinetic.Node.extend({ * apply shadow. return true if shadow was applied * and false if it was not */ - _applyShadow: function() { - var context = this.getContext(); + _applyShadow: function(context) { var s = this.attrs.shadow; if(s) { var aa = this.getAbsoluteAlpha(); @@ -308,12 +295,12 @@ Kinetic.Shape = Kinetic.Node.extend({ // path detection if(this.attrs.detectionType === 'path') { - var pathLayer = stage.pathLayer; - var pathLayerContext = pathLayer.getContext(); + var pathCanvas = stage.pathCanvas; + var pathCanvasContext = pathCanvas.getContext(); - this._draw(pathLayer); + this._draw(pathCanvas); - return pathLayerContext.isPointInPath(pos.x, pos.y); + return pathCanvasContext.isPointInPath(pos.x, pos.y); } // pixel detection @@ -326,10 +313,10 @@ Kinetic.Shape = Kinetic.Node.extend({ // default return false; }, - _draw: function(layer) { - if(layer && this.attrs.drawFunc) { - var stage = layer.getStage(); - var context = layer.getContext(); + _draw: function(canvas) { + if(this.attrs.drawFunc) { + var stage = this.getStage(); + var context = canvas.getContext(); var family = []; var parent = this.parent; @@ -348,8 +335,6 @@ Kinetic.Shape = Kinetic.Node.extend({ context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); } - this.tempLayer = layer; - /* * pre styles include alpha, linejoin */ @@ -357,11 +342,11 @@ Kinetic.Shape = Kinetic.Node.extend({ if(absAlpha !== 1) { context.globalAlpha = absAlpha; } - this.applyLineJoin(); + this.applyLineJoin(context); // draw the shape this.appliedShadow = false; - this.attrs.drawFunc.call(this); + this.attrs.drawFunc.call(this, canvas.getContext()); context.restore(); } } diff --git a/src/Stage.js b/src/Stage.js index 90879530..588cac4a 100644 --- a/src/Stage.js +++ b/src/Stage.js @@ -85,8 +85,8 @@ Kinetic.Stage = Kinetic.Container.extend({ * @name draw * @methodOf Kinetic.Stage.prototype */ - draw: function(layer) { - this._draw(layer); + draw: function(canvas) { + this._draw(canvas); }, /** * set stage size @@ -288,37 +288,25 @@ Kinetic.Stage = Kinetic.Container.extend({ * @param {Number} [quality] */ toDataURL: function(callback, mimeType, quality) { - /* - * we need to create a temp layer rather than using - * the bufferLayer because the stage toDataURL method - * is asynchronous, which means that other parts of the - * code base could be updating or clearing the bufferLayer - * while the stage toDataURL method is processing - */ - var tempLayer = new Kinetic.Layer(); - tempLayer.getCanvas().width = this.attrs.width; - tempLayer.getCanvas().height = this.attrs.height; - tempLayer.parent = this; - var tempCanvas = tempLayer.getCanvas(); - var tempContext = tempLayer.getContext(); - + var canvas = new Kinetic.Canvas(this.attrs.width, this.attrs.height); + var context = canvas.getContext(); var layers = this.children; function drawLayer(n) { var layer = layers[n]; - var layerUrl; + var canvasUrl; try { // If this call fails (due to browser bug, like in Firefox 3.6), // then revert to previous no-parameter image/png behavior - layerUrl = layer.getCanvas().toDataURL(mimeType, quality); + canvasUrl = canvas.getElement().toDataURL(mimeType, quality); } catch(e) { - layerUrl = layer.getCanvas().toDataURL(); + canvasUrl = canvas.getElement().toDataURL(); } var imageObj = new Image(); imageObj.onload = function() { - tempContext.drawImage(imageObj, 0, 0); + context.drawImage(imageObj, 0, 0); if(n < layers.length - 1) { drawLayer(n + 1); @@ -327,14 +315,14 @@ Kinetic.Stage = Kinetic.Container.extend({ try { // If this call fails (due to browser bug, like in Firefox 3.6), // then revert to previous no-parameter image/png behavior - callback(tempLayer.getCanvas().toDataURL(mimeType, quality)); + callback(canvas.getElement().toDataURL(mimeType, quality)); } catch(e) { - callback(tempLayer.getCanvas().toDataURL()); + callback(canvas.getElement().toDataURL()); } } }; - imageObj.src = layerUrl; + imageObj.src = canvasUrl; } drawLayer(0); }, @@ -360,18 +348,15 @@ Kinetic.Stage = Kinetic.Container.extend({ this.content.style.width = width + 'px'; this.content.style.height = height + 'px'; - // set buffer layer and path layer sizes - this.bufferLayer.getCanvas().width = width; - this.bufferLayer.getCanvas().height = height; - this.pathLayer.getCanvas().width = width; - this.pathLayer.getCanvas().height = height; + // set buffer canvas and path canvas sizes + this.bufferCanvas.setSize(width, height); + this.pathCanvas.setSize(width, height); // set user defined layer dimensions var layers = this.children; for(var n = 0; n < layers.length; n++) { var layer = layers[n]; - layer.getCanvas().width = width; - layer.getCanvas().height = height; + layer.getCanvas().setSize(width, height); layer.draw(); } }, @@ -395,12 +380,11 @@ Kinetic.Stage = Kinetic.Container.extend({ * @param {Layer} layer */ _add: function(layer) { - layer.canvas.width = this.attrs.width; - layer.canvas.height = this.attrs.height; + layer.canvas.setSize(this.attrs.width, this.attrs.height); // draw layer and append canvas to container layer.draw(); - this.content.appendChild(layer.canvas); + this.content.appendChild(layer.canvas.element); /* * set layer last draw time to zero @@ -603,7 +587,7 @@ Kinetic.Stage = Kinetic.Container.extend({ this._setMousePosition(evt); this._setTouchPosition(evt); - this.pathLayer.clear(); + this.pathCanvas.clear(); /* * loop through layers. If at any point an event @@ -794,28 +778,6 @@ Kinetic.Stage = Kinetic.Container.extend({ left: left }; }, - /** - * modify path context - * @param {CanvasContext} context - */ - _modifyPathContext: function(context) { - context.stroke = function() { - }; - context.fill = function() { - }; - context.fillRect = function(x, y, width, height) { - context.rect(x, y, width, height); - }; - context.strokeRect = function(x, y, width, height) { - context.rect(x, y, width, height); - }; - context.drawImage = function() { - }; - context.fillText = function() { - }; - context.strokeText = function() { - }; - }, /** * end drag and drop */ @@ -910,34 +872,15 @@ Kinetic.Stage = Kinetic.Container.extend({ this.content.className = 'kineticjs-content'; this.attrs.container.appendChild(this.content); - // default layers - this.bufferLayer = new Kinetic.Layer({ - name: 'bufferLayer' + this.bufferCanvas = new Kinetic.Canvas({ + width: this.attrs.width, + height: this.attrs.height }); - this.pathLayer = new Kinetic.Layer({ - name: 'pathLayer' + this.pathCanvas = new Kinetic.Canvas({ + width: this.attrs.width, + height: this.attrs.height }); - - // set parents - this.bufferLayer.parent = this; - this.pathLayer.parent = this; - - // customize back stage context - this._modifyPathContext(this.pathLayer.context); - - // hide canvases - this.bufferLayer.getCanvas().style.display = 'none'; - this.pathLayer.getCanvas().style.display = 'none'; - - // add buffer layer - this.bufferLayer.canvas.className = 'kineticjs-buffer-layer'; - this.content.appendChild(this.bufferLayer.canvas); - - // add path layer - this.pathLayer.canvas.className = 'kineticjs-path-layer'; - this.content.appendChild(this.pathLayer.canvas); - - this.setSize(this.attrs.width, this.attrs.height); + this.pathCanvas.strip(); this._resizeDOM(); }, _addId: function(node) { @@ -1018,8 +961,8 @@ Kinetic.Stage = Kinetic.Container.extend({ this.anim = undefined; this.animRunning = false; }, - _draw: function(layer) { - this._drawChildren(layer); + _draw: function(canvas) { + this._drawChildren(canvas); } }); diff --git a/src/shapes/Ellipse.js b/src/shapes/Ellipse.js index 1dc385b9..9dd1f02e 100644 --- a/src/shapes/Ellipse.js +++ b/src/shapes/Ellipse.js @@ -18,9 +18,7 @@ Kinetic.Ellipse = Kinetic.Shape.extend({ this.shapeType = "Ellipse"; - config.drawFunc = function() { - var canvas = this.getCanvas(); - var context = this.getContext(); + config.drawFunc = function(context) { var r = this.getRadius(); context.beginPath(); context.save(); @@ -30,8 +28,8 @@ Kinetic.Ellipse = Kinetic.Shape.extend({ context.arc(0, 0, r.x, 0, Math.PI * 2, true); context.restore(); context.closePath(); - this.fill(); - this.stroke(); + this.fill(context); + this.stroke(context); }; // call super constructor this._super(config); diff --git a/src/shapes/Image.js b/src/shapes/Image.js index 42302f7d..0488c492 100644 --- a/src/shapes/Image.js +++ b/src/shapes/Image.js @@ -14,18 +14,16 @@ Kinetic.Image = Kinetic.Shape.extend({ init: function(config) { this.shapeType = "Image"; - config.drawFunc = function() { + config.drawFunc = function(context) { if(!!this.attrs.image) { var width = this.getWidth(); var height = this.getHeight(); - var canvas = this.getCanvas(); - var context = this.getContext(); context.beginPath(); context.rect(0, 0, width, height); context.closePath(); - this.fill(); - this.stroke(); + this.fill(context); + this.stroke(context); // if cropping if(this.attrs.crop && this.attrs.crop.width && this.attrs.crop.height) { @@ -33,11 +31,11 @@ Kinetic.Image = Kinetic.Shape.extend({ var cropY = this.attrs.crop.y ? this.attrs.crop.y : 0; var cropWidth = this.attrs.crop.width; var cropHeight = this.attrs.crop.height; - this.drawImage(this.attrs.image, cropX, cropY, cropWidth, cropHeight, 0, 0, width, height); + this.drawImage(context, this.attrs.image, cropX, cropY, cropWidth, cropHeight, 0, 0, width, height); } // no cropping else { - this.drawImage(this.attrs.image, 0, 0, width, height); + this.drawImage(context, this.attrs.image, 0, 0, width, height); } } }; diff --git a/src/shapes/Line.js b/src/shapes/Line.js index a01ffc57..ccea9171 100644 --- a/src/shapes/Line.js +++ b/src/shapes/Line.js @@ -17,8 +17,7 @@ Kinetic.Line = Kinetic.Shape.extend({ }); this.shapeType = "Line"; - config.drawFunc = function() { - var context = this.getContext(); + config.drawFunc = function(context) { var lastPos = {}; context.beginPath(); @@ -31,7 +30,7 @@ Kinetic.Line = Kinetic.Shape.extend({ // draw dashed line var lastX = this.attrs.points[n - 1].x; var lastY = this.attrs.points[n - 1].y; - this._dashedLine(lastX, lastY, x, y, this.attrs.dashArray); + this._dashedLine(context, lastX, lastY, x, y, this.attrs.dashArray); } else { // draw normal line @@ -43,7 +42,7 @@ Kinetic.Line = Kinetic.Shape.extend({ context.lineCap = this.attrs.lineCap; } - this.stroke(); + this.stroke(context); }; // call super constructor this._super(config); @@ -51,8 +50,7 @@ Kinetic.Line = Kinetic.Shape.extend({ /** * draw dashed line. Written by Phrogz */ - _dashedLine: function(x, y, x2, y2, dashArray) { - var context = this.getContext(); + _dashedLine: function(context, x, y, x2, y2, dashArray) { var dashCount = dashArray.length; var dx = (x2 - x), dy = (y2 - y); diff --git a/src/shapes/Path.js b/src/shapes/Path.js index 4fcf9c89..2f156d64 100644 --- a/src/shapes/Path.js +++ b/src/shapes/Path.js @@ -14,8 +14,7 @@ Kinetic.Path = Kinetic.Shape.extend({ this.dataArray = []; var that = this; - config.drawFunc = function() { - var context = this.getContext(); + config.drawFunc = function(context) { var ca = this.dataArray; // context position context.beginPath(); @@ -56,8 +55,8 @@ Kinetic.Path = Kinetic.Shape.extend({ break; } } - this.fill(); - this.stroke(); + this.fill(context); + this.stroke(context); }; // call super constructor this._super(config); diff --git a/src/shapes/Polygon.js b/src/shapes/Polygon.js index f6cd3436..2de679e1 100644 --- a/src/shapes/Polygon.js +++ b/src/shapes/Polygon.js @@ -14,16 +14,15 @@ Kinetic.Polygon = Kinetic.Shape.extend({ }); this.shapeType = "Polygon"; - config.drawFunc = function() { - var context = this.getContext(); + config.drawFunc = function(context) { context.beginPath(); context.moveTo(this.attrs.points[0].x, this.attrs.points[0].y); for(var n = 1; n < this.attrs.points.length; n++) { context.lineTo(this.attrs.points[n].x, this.attrs.points[n].y); } context.closePath(); - this.fill(); - this.stroke(); + this.fill(context); + this.stroke(context); }; // call super constructor this._super(config); diff --git a/src/shapes/Rect.js b/src/shapes/Rect.js index dbcb4a5f..4a819caf 100644 --- a/src/shapes/Rect.js +++ b/src/shapes/Rect.js @@ -17,8 +17,7 @@ Kinetic.Rect = Kinetic.Shape.extend({ this.shapeType = "Rect"; - config.drawFunc = function() { - var context = this.getContext(); + config.drawFunc = function(context) { context.beginPath(); if(this.attrs.cornerRadius === 0) { // simple rect - don't bother doing all that complicated maths stuff. @@ -38,8 +37,8 @@ Kinetic.Rect = Kinetic.Shape.extend({ } context.closePath(); - this.fill(); - this.stroke(); + this.fill(context); + this.stroke(context); }; // call super constructor this._super(config); diff --git a/src/shapes/RegularPolygon.js b/src/shapes/RegularPolygon.js index d9083a62..3769da87 100644 --- a/src/shapes/RegularPolygon.js +++ b/src/shapes/RegularPolygon.js @@ -15,8 +15,7 @@ Kinetic.RegularPolygon = Kinetic.Shape.extend({ }); this.shapeType = "RegularPolygon"; - config.drawFunc = function() { - var context = this.getContext(); + config.drawFunc = function(context) { context.beginPath(); context.moveTo(0, 0 - this.attrs.radius); @@ -26,8 +25,8 @@ Kinetic.RegularPolygon = Kinetic.Shape.extend({ context.lineTo(x, y); } context.closePath(); - this.fill(); - this.stroke(); + this.fill(context); + this.stroke(context); }; // call super constructor this._super(config); diff --git a/src/shapes/Sprite.js b/src/shapes/Sprite.js index b17e3f55..e52c588b 100644 --- a/src/shapes/Sprite.js +++ b/src/shapes/Sprite.js @@ -14,9 +14,8 @@ Kinetic.Sprite = Kinetic.Shape.extend({ frameRate: 17 }); - config.drawFunc = function() { + config.drawFunc = function(context) { if(!!this.attrs.image) { - var context = this.getContext(); var anim = this.attrs.animation; var index = this.attrs.index; var f = this.attrs.animations[anim][index]; @@ -25,7 +24,7 @@ Kinetic.Sprite = Kinetic.Shape.extend({ context.rect(0, 0, f.width, f.height); context.closePath(); - this.drawImage(this.attrs.image, f.x, f.y, f.width, f.height, 0, 0, f.width, f.height); + this.drawImage(context, this.attrs.image, f.x, f.y, f.width, f.height, 0, 0, f.width, f.height); } }; // call super constructor diff --git a/src/shapes/Star.js b/src/shapes/Star.js index a32c6129..0f6281b8 100644 --- a/src/shapes/Star.js +++ b/src/shapes/Star.js @@ -16,8 +16,7 @@ Kinetic.Star = Kinetic.Shape.extend({ }); this.shapeType = "Star"; - config.drawFunc = function() { - var context = this.getContext(); + config.drawFunc = function(context) { context.beginPath(); context.moveTo(0, 0 - this.attrs.outerRadius); @@ -29,8 +28,8 @@ Kinetic.Star = Kinetic.Shape.extend({ } context.closePath(); - this.fill(); - this.stroke(); + this.fill(context); + this.stroke(context); }; // call super constructor this._super(config); diff --git a/src/shapes/Text.js b/src/shapes/Text.js index 0be98b80..addda99e 100644 --- a/src/shapes/Text.js +++ b/src/shapes/Text.js @@ -27,8 +27,7 @@ Kinetic.Text = Kinetic.Shape.extend({ this.dummyCanvas = document.createElement('canvas'); this.shapeType = "Text"; - config.drawFunc = function() { - var context = this.getContext(); + config.drawFunc = function(context) { /* * draw rect */ @@ -54,8 +53,8 @@ Kinetic.Text = Kinetic.Shape.extend({ } context.closePath(); - this.fill(); - this.stroke(); + this.fill(context); + this.stroke(context); /* * draw text */ @@ -83,8 +82,8 @@ Kinetic.Text = Kinetic.Shape.extend({ context.translate((this.getBoxWidth() - this._getTextSize(text).width - p * 2) / 2, 0); } - this.fillText(text); - this.strokeText(text); + this.fillText(context, text); + this.strokeText(context, text); context.restore(); context.translate(0, lineHeightPx); diff --git a/src/util/Canvas.js b/src/util/Canvas.js new file mode 100644 index 00000000..5f17d66f --- /dev/null +++ b/src/util/Canvas.js @@ -0,0 +1,96 @@ +/////////////////////////////////////////////////////////////////////// +// Canvas +/////////////////////////////////////////////////////////////////////// +/** + * Canvas wrapper constructor + * @constructor + * @param {Number} width + * @param {Number} height + */ +Kinetic.Canvas = function(width, height) { + this.element = document.createElement('canvas'); + this.context = this.element.getContext('2d'); + + // set dimensions + this.element.width = width; + this.element.height = height; +}; + +Kinetic.Canvas.prototype = { + /** + * clear canvas + * @name clear + * @methodOf Kinetic.Canvas.prototype + */ + clear: function() { + var context = this.getContext(); + var el = this.getElement(); + context.clearRect(0, 0, el.width, el.height); + }, + /** + * get element + * @name getElement + * @methodOf Kinetic.Canvas.prototype + */ + getElement: function() { + return this.element; + }, + /** + * get context + * @name getContext + * @methodOf Kinetic.Canvas.prototype + */ + getContext: function() { + return this.context; + }, + /** + * set width + * @name setWidth + * @methodOf Kinetic.Canvas.prototype + */ + setWidth: function(width) { + this.element.width = width; + }, + /** + * set height + * @name setHeight + * @methodOf Kinetic.Canvas.prototype + */ + setHeight: function(height) { + this.element.height = height; + }, + /** + * set size + * @name setSize + * @methodOf Kinetic.Canvas.prototype + */ + setSize: function(width, height) { + this.setWidth(width); + this.setHeight(height); + }, + /** + * strip away all functions that draw pixels onto the bitmap + * @name strip + * @methodOf Kinetic.Canvas.prototype + * @param {CanvasContext} context + */ + strip: function() { + var context = this.context; + context.stroke = function() { + }; + context.fill = function() { + }; + context.fillRect = function(x, y, width, height) { + context.rect(x, y, width, height); + }; + context.strokeRect = function(x, y, width, height) { + context.rect(x, y, width, height); + }; + context.drawImage = function() { + }; + context.fillText = function() { + }; + context.strokeText = function() { + }; + } +}; diff --git a/tests/js/functionalTests.js b/tests/js/functionalTests.js index 4c52baff..fc88c0e7 100644 --- a/tests/js/functionalTests.js +++ b/tests/js/functionalTests.js @@ -152,7 +152,7 @@ Test.prototype.tests = { context.quadraticCurveTo(300, 100, 260, 170); context.closePath(); context.fillStyle = 'blue'; - context.fill(); + context.fill(context); }, draggable: true }); diff --git a/tests/js/manualTests.js b/tests/js/manualTests.js index e23b632c..0926a557 100644 --- a/tests/js/manualTests.js +++ b/tests/js/manualTests.js @@ -1349,8 +1349,7 @@ Test.prototype.tests = { rect.rotate(0.01); layer.draw(); }); - //stage.start(); - + stage.start(); }, 'STAGE - hide stage': function(containerId) { var stage = new Kinetic.Stage({ diff --git a/tests/js/performanceTests.js b/tests/js/performanceTests.js index 5fa89448..cc05bce4 100644 --- a/tests/js/performanceTests.js +++ b/tests/js/performanceTests.js @@ -25,7 +25,7 @@ Test.prototype.tests = { var imageData = context.getImageData(7, 7, 106, 106); endTimer('create image data'); - layer.clear(); + layer.canvas.clear(); startTimer(); for(var n = 0; n < 10000; n++) { @@ -62,7 +62,7 @@ Test.prototype.tests = { var imageObj = new Image(); imageObj.onload = function() { - layer.clear(); + layer.canvas.clear(); startTimer(); for(var n = 0; n < 10000; n++) { diff --git a/tests/js/unitTests.js b/tests/js/unitTests.js index 92aa3383..9aafb825 100644 --- a/tests/js/unitTests.js +++ b/tests/js/unitTests.js @@ -68,8 +68,8 @@ Test.prototype.tests = { test(stage.getSize().height === 155, 'stage height should be 155'); test(stage.getDOM().style.width === '333px', 'content width should be 333'); test(stage.getDOM().style.height === '155px', 'content height should be 155px'); - test(layer.getCanvas().width === 333, 'layer canvas width should be 333'); - test(layer.getCanvas().height === 155, 'layer canvas width should be 155'); + test(layer.getCanvas().element.width === 333, 'layer canvas element width should be 333'); + test(layer.getCanvas().element.height === 155, 'layer canvas element width should be 155'); }, 'STAGE - add shape then stage then layer': function(containerId) { var stage = new Kinetic.Stage({ @@ -340,15 +340,14 @@ Test.prototype.tests = { var layer = new Kinetic.Layer(); var group = new Kinetic.Group(); - var drawTriangle = function() { - var context = this.getContext(); + var drawTriangle = function(context) { context.beginPath(); context.moveTo(200, 50); context.lineTo(420, 80); context.quadraticCurveTo(300, 100, 260, 170); context.closePath(); - this.fill(); - this.stroke(); + this.fill(context); + this.stroke(context); }; var triangle = new Kinetic.Shape({ drawFunc: drawTriangle, @@ -388,15 +387,14 @@ Test.prototype.tests = { height: 200 }); - var drawTriangle = function() { - var context = this.getContext(); + var drawTriangle = function(context) { context.beginPath(); context.moveTo(200, 50); context.lineTo(420, 80); context.quadraticCurveTo(300, 100, 260, 170); context.closePath(); - this.fill(); - this.stroke(); + this.fill(context); + this.stroke(context); }; var json = '{"attrs":{"width":578,"height":200,"visible":true,"listen":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"offset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Stage","children":[{"attrs":{"throttle":80,"clearBeforeDraw":true,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"offset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false,"listen":true},"nodeType":"Layer","children":[{"attrs":{"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"offset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false,"listen":true},"nodeType":"Group","children":[{"attrs":{"detectionType":"path","visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"offset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false,"fill":"#00D2FF","stroke":"black","strokeWidth":4,"shadow":{"blur":10,"alpha":1,"offset":{"x":0,"y":0}},"listen":true,"id":"myTriangle"},"nodeType":"Shape"}]}]}]}'; stage.load(json); @@ -2167,7 +2165,7 @@ Test.prototype.tests = { setTimeout(function() { sprite.setAnimation('kicking'); - sprite.afterFrame(0, function() { + sprite.afterFrame(5, function() { sprite.setAnimation('standing'); }); }, 2000); @@ -2720,15 +2718,14 @@ Test.prototype.tests = { }); var layer = new Kinetic.Layer(); var shape = new Kinetic.Shape({ - drawFunc: function() { - var context = this.getContext(); + drawFunc: function(context) { context.beginPath(); context.moveTo(0, 0); context.lineTo(100, 0); context.lineTo(100, 100); context.closePath(); - this.fill(); - this.stroke(); + this.fill(context); + this.stroke(context); }, x: 200, y: 100, @@ -2748,15 +2745,14 @@ Test.prototype.tests = { }); var layer = new Kinetic.Layer(); var shape = new Kinetic.Shape({ - drawFunc: function() { - var context = this.getContext(); + drawFunc: function(context) { context.beginPath(); context.moveTo(0, 0); context.lineTo(100, 0); context.lineTo(100, 100); context.closePath(); - this.fill(); - this.stroke(); + this.fill(context); + this.stroke(context); }, x: 200, y: 100, @@ -2765,15 +2761,14 @@ Test.prototype.tests = { strokeWidth: 5 }); - shape.setDrawFunc(function() { - var context = this.getContext(); + shape.setDrawFunc(function(context) { context.beginPath(); context.moveTo(0, 0); context.lineTo(200, 0); context.lineTo(200, 100); context.closePath(); - this.fill(); - this.stroke(); + this.fill(context); + this.stroke(context); }); layer.add(shape); @@ -4024,6 +4019,8 @@ Test.prototype.tests = { test(stage.get('.layerName')[0].attrs.id === 'layerId', 'problem with layer name selector'); test(stage.get('#layerId')[0].attrs.id === 'layerId', 'problem with layer id selector'); + + layer.draw(); }, 'NODE - test drag and drop properties and methods': function(containerId) { var stage = new Kinetic.Stage({