From 3ba89d36e7f642dbf733af88ce40f46f336651cf Mon Sep 17 00:00:00 2001 From: Eric Rowell Date: Sat, 31 Aug 2013 21:49:18 -0700 Subject: [PATCH] introduced new Context class. I've bumped up the next release to v4.7.0 because this is a relatively big mind shift in how the framework works, and it's a big enough API change to warrant a minor update. This is the first step towards enabling context tracing for stellar unit testing --- Gruntfile.js | 1 + package.json | 2 +- src/Canvas.js | 399 ++++--------------------------- src/Container.js | 12 +- src/Context.js | 350 +++++++++++++++++++++++++++ src/Layer.js | 55 +++-- src/Node.js | 8 +- src/Shape.js | 43 ++-- src/Stage.js | 8 +- src/plugins/Label.js | 46 ++-- src/plugins/Path.js | 39 +-- src/plugins/RegularPolygon.js | 14 +- src/plugins/Star.js | 17 +- src/plugins/TextPath.js | 43 ++-- src/shapes/Blob.js | 16 +- src/shapes/Circle.js | 12 +- src/shapes/Ellipse.js | 20 +- src/shapes/Image.js | 69 +++--- src/shapes/Line.js | 12 +- src/shapes/Polygon.js | 17 +- src/shapes/Rect.js | 30 +-- src/shapes/Spline.js | 18 +- src/shapes/Sprite.js | 18 +- src/shapes/Text.js | 60 ++--- src/shapes/Wedge.js | 15 +- tests/html/performanceTests.html | 5 + tests/js/Test.js | 4 +- tests/js/functionalTests.js | 30 +-- tests/js/manualTests.js | 12 +- tests/js/unit/layerTests.js | 2 +- tests/js/unit/nodeTests.js | 40 ++-- tests/js/unit/shapeTests.js | 34 +-- tests/js/unit/stageTests.js | 4 +- tests/js/visualTests.js | 103 ++++---- 34 files changed, 813 insertions(+), 745 deletions(-) create mode 100644 src/Context.js diff --git a/Gruntfile.js b/Gruntfile.js index b3038e50..b3d846ee 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -4,6 +4,7 @@ module.exports = function(grunt) { 'src/Global.js', 'src/Util.js', 'src/Canvas.js', + 'src/Context.js', 'src/Factory.js', 'src/Node.js', 'src/Animation.js', diff --git a/package.json b/package.json index 772d3e7b..6b4d0d0e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "KineticJS", - "version": "4.6.1", + "version": "4.7.0", "devDependencies": { "grunt-contrib-jshint": "~0.5.4", "grunt-contrib-nodeunit": "~0.1.2", diff --git a/src/Canvas.js b/src/Canvas.js index 2bb987da..a5f8179e 100644 --- a/src/Canvas.js +++ b/src/Canvas.js @@ -34,25 +34,28 @@ init: function(config) { config = config || {}; - var width = config.width || 0, - height = config.height || 0, - pixelRatio = config.pixelRatio || _pixelRatio, - contextType = config.contextType || '2d'; + var pixelRatio = config.pixelRatio || _pixelRatio; this.pixelRatio = pixelRatio; - this.element = document.createElement('canvas'); + this._canvas = document.createElement('canvas'); // set inline styles - this.element.style.padding = 0; - this.element.style.margin = 0; - this.element.style.border = 0; - this.element.style.background = 'transparent'; - this.element.style.position = 'absolute'; - this.element.style.top = 0; - this.element.style.left = 0; - - this.context = this.element.getContext(contextType); - this.setSize(width, height); + this._canvas.style.padding = 0; + this._canvas.style.margin = 0; + this._canvas.style.border = 0; + this._canvas.style.background = 'transparent'; + this._canvas.style.position = 'absolute'; + this._canvas.style.top = 0; + this._canvas.style.left = 0; + }, + /** + * get canvas context + * @method + * @memberof Kinetic.Canvas.prototype + * @returns {CanvasContext} context + */ + getContext: function() { + return this.context; }, /** * get pixel ratio @@ -79,32 +82,6 @@ this.pixelRatio = pixelRatio; this.setSize(this.getWidth(), this.getHeight()); }, - /** - * reset canvas context transform - * @method - * @memberof Kinetic.Canvas.prototype - */ - reset: function() { - this.getContext().setTransform(1 * this.pixelRatio, 0, 0, 1 * this.pixelRatio, 0, 0); - }, - /** - * get canvas element - * @method - * @memberof Kinetic.Canvas.prototype - * @returns {DomElement} canvas element - */ - getElement: function() { - return this.element; - }, - /** - * get canvas context - * @method - * @memberof Kinetic.Canvas.prototype - * @returns {CanvasContext} context - */ - getContext: function() { - return this.context; - }, /** * set width * @method @@ -113,8 +90,8 @@ */ setWidth: function(width) { // take into account pixel ratio - this.width = this.element.width = width * this.pixelRatio; - this.element.style.width = width + 'px'; + this.width = this._canvas.width = width * this.pixelRatio; + this._canvas.style.width = width + 'px'; }, /** * set height @@ -124,8 +101,8 @@ */ setHeight: function(height) { // take into account pixel ratio - this.height = this.element.height = height * this.pixelRatio; - this.element.style.height = height + 'px'; + this.height = this._canvas.height = height * this.pixelRatio; + this._canvas.style.height = height + 'px'; }, /** * get width @@ -156,24 +133,6 @@ this.setWidth(width); this.setHeight(height); }, - /** - * clear canvas - * @method - * @memberof Kinetic.Canvas.prototype - */ - clear: function(clip) { - var context = this.getContext(), - pos, size; - - if (clip) { - pos = Kinetic.Util._getXY(clip); - size = Kinetic.Util._getSize(clip); - context.clearRect(pos.x || 0, pos.y || 0, size.width, size.height); - } - else { - context.clearRect(0, 0, this.getWidth(), this.getHeight()); - } - }, /** * to data url * @method @@ -186,326 +145,56 @@ 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.element.toDataURL(mimeType, quality); + return this._canvas.toDataURL(mimeType, quality); } catch(e) { try { - return this.element.toDataURL(); + return this._canvas.toDataURL(); } catch(err) { Kinetic.Util.warn('Unable to get data URL. ' + err.message); return ''; } } - }, - /** - * fill shape - * @method - * @memberof Kinetic.Canvas.prototype - * @param {Kinetic.Shape} shape - */ - fill: function(shape) { - if(shape.getFillEnabled()) { - this._fill(shape); - } - }, - /** - * stroke shape - * @method - * @memberof Kinetic.Canvas.prototype - * @param {Kinetic.Shape} shape - */ - stroke: function(shape) { - if(shape.getStrokeEnabled()) { - this._stroke(shape); - } - }, - /** - * fill, stroke, and apply shadows - * will only be applied to either the fill or stroke.  Fill - * is given priority over stroke. - * @method - * @memberof Kinetic.Canvas.prototype - * @param {Kinetic.Shape} shape - */ - fillStroke: function(shape) { - var fillEnabled = shape.getFillEnabled(); - if(fillEnabled) { - this._fill(shape); - } - - if(shape.getStrokeEnabled()) { - this._stroke(shape, shape.hasShadow() && shape.hasFill() && fillEnabled); - } - }, - /** - * apply shadow - * @method - * @memberof Kinetic.Canvas.prototype - * @param {Kinetic.Shape} shape - * @param {Function} drawFunc - */ - applyShadow: function(shape, drawFunc) { - var context = this.context; - context.save(); - this._applyShadow(shape); - drawFunc(); - context.restore(); - drawFunc(); - }, - _applyLineCap: function(shape) { - var lineCap = shape.getLineCap(); - if(lineCap) { - this.context.lineCap = lineCap; - } - }, - _applyOpacity: function(shape) { - var absOpacity = shape.getAbsoluteOpacity(); - if(absOpacity !== 1) { - this.context.globalAlpha = absOpacity; - } - }, - _applyLineJoin: function(shape) { - var lineJoin = shape.getLineJoin(); - if(lineJoin) { - this.context.lineJoin = lineJoin; - } - }, - _applyAncestorTransforms: function(node) { - var m = node.getAbsoluteTransform().getMatrix(); - this.context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); - }, - _clip: function(container) { - var context = this.getContext(), - clipX = container.getClipX() || 0, - clipY = container.getClipY() || 0, - clipWidth = container.getClipWidth(), - clipHeight = container.getClipHeight(); - - context.save(); - this._applyAncestorTransforms(container); - context.beginPath(); - context.rect(clipX, clipY, clipWidth, clipHeight); - context.clip(); - this.reset(); - container._drawChildren(this); - context.restore(); } }; Kinetic.SceneCanvas = function(config) { + config = config || {}; + var width = config.width || 0, + height = config.height || 0; + Kinetic.Canvas.call(this, config); + this.context = new Kinetic.SceneContext(this); + this.setSize(width, height); }; Kinetic.SceneCanvas.prototype = { setWidth: function(width) { - var pixelRatio = this.pixelRatio; + var pixelRatio = this.pixelRatio, + _context = this.getContext()._context; + Kinetic.Canvas.prototype.setWidth.call(this, width); - this.context.scale(pixelRatio, pixelRatio); + _context.scale(pixelRatio, pixelRatio); }, setHeight: function(height) { - var pixelRatio = this.pixelRatio; + var pixelRatio = this.pixelRatio, + _context = this.getContext()._context; + Kinetic.Canvas.prototype.setHeight.call(this, height); - this.context.scale(pixelRatio, pixelRatio); - }, - _fillColor: function(shape) { - var context = this.context, fill = shape.getFill(); - context.fillStyle = fill; - shape._fillFunc(context); - }, - _fillPattern: function(shape) { - var context = this.context, - fillPatternImage = shape.getFillPatternImage(), - fillPatternX = shape.getFillPatternX(), - fillPatternY = shape.getFillPatternY(), - fillPatternScale = shape.getFillPatternScale(), - fillPatternRotation = shape.getFillPatternRotation(), - fillPatternOffset = shape.getFillPatternOffset(), - fillPatternRepeat = shape.getFillPatternRepeat(); - - if(fillPatternX || fillPatternY) { - context.translate(fillPatternX || 0, fillPatternY || 0); - } - if(fillPatternRotation) { - context.rotate(fillPatternRotation); - } - if(fillPatternScale) { - context.scale(fillPatternScale.x, fillPatternScale.y); - } - if(fillPatternOffset) { - context.translate(-1 * fillPatternOffset.x, -1 * fillPatternOffset.y); - } - - context.fillStyle = context.createPattern(fillPatternImage, fillPatternRepeat || 'repeat'); - context.fill(); - }, - _fillLinearGradient: function(shape) { - var context = this.context, - start = shape.getFillLinearGradientStartPoint(), - end = shape.getFillLinearGradientEndPoint(), - colorStops = shape.getFillLinearGradientColorStops(), - grd = context.createLinearGradient(start.x, start.y, end.x, end.y); - - if (colorStops) { - // build color stops - for(var n = 0; n < colorStops.length; n += 2) { - grd.addColorStop(colorStops[n], colorStops[n + 1]); - } - context.fillStyle = grd; - context.fill(); - } - }, - _fillRadialGradient: function(shape) { - var context = this.context, - start = shape.getFillRadialGradientStartPoint(), - end = shape.getFillRadialGradientEndPoint(), - startRadius = shape.getFillRadialGradientStartRadius(), - endRadius = shape.getFillRadialGradientEndRadius(), - colorStops = shape.getFillRadialGradientColorStops(), - grd = context.createRadialGradient(start.x, start.y, startRadius, end.x, end.y, endRadius); - - // build color stops - for(var n = 0; n < colorStops.length; n += 2) { - grd.addColorStop(colorStops[n], colorStops[n + 1]); - } - context.fillStyle = grd; - context.fill(); - }, - _fill: function(shape, skipShadow) { - var context = this.context, - hasColor = shape.getFill(), - hasPattern = shape.getFillPatternImage(), - hasLinearGradient = shape.getFillLinearGradientColorStops(), - hasRadialGradient = shape.getFillRadialGradientColorStops(), - fillPriority = shape.getFillPriority(); - - context.save(); - - if(!skipShadow && shape.hasShadow()) { - this._applyShadow(shape); - } - - // priority fills - if(hasColor && fillPriority === 'color') { - this._fillColor(shape); - } - else if(hasPattern && fillPriority === 'pattern') { - this._fillPattern(shape); - } - else if(hasLinearGradient && fillPriority === 'linear-gradient') { - this._fillLinearGradient(shape); - } - else if(hasRadialGradient && fillPriority === 'radial-gradient') { - this._fillRadialGradient(shape); - } - // now just try and fill with whatever is available - else if(hasColor) { - this._fillColor(shape); - } - else if(hasPattern) { - this._fillPattern(shape); - } - else if(hasLinearGradient) { - this._fillLinearGradient(shape); - } - else if(hasRadialGradient) { - this._fillRadialGradient(shape); - } - context.restore(); - - if(!skipShadow && shape.hasShadow()) { - this._fill(shape, true); - } - }, - _stroke: function(shape, skipShadow) { - var context = this.context, - stroke = shape.getStroke(), - strokeWidth = shape.getStrokeWidth(), - dashArray = shape.getDashArray(); - - if(stroke || strokeWidth) { - context.save(); - if (!shape.getStrokeScaleEnabled()) { - - context.setTransform(1, 0, 0, 1, 0, 0); - } - this._applyLineCap(shape); - if(dashArray && shape.getDashArrayEnabled()) { - if(context.setLineDash) { - context.setLineDash(dashArray); - } - else if('mozDash' in context) { - context.mozDash = dashArray; - } - else if('webkitLineDash' in context) { - context.webkitLineDash = dashArray; - } - } - if(!skipShadow && shape.hasShadow()) { - this._applyShadow(shape); - } - context.lineWidth = strokeWidth || 2; - context.strokeStyle = stroke || 'black'; - shape._strokeFunc(context); - context.restore(); - - if(!skipShadow && shape.hasShadow()) { - this._stroke(shape, true); - } - } - }, - _applyShadow: function(shape) { - var context = this.context, - util, absOpacity, color, blur, offset, shadowOpacity; - - if(shape.hasShadow() && shape.getShadowEnabled()) { - util = Kinetic.Util; - absOpacity = shape.getAbsoluteOpacity(); - color = util.get(shape.getShadowColor(), 'black'); - blur = util.get(shape.getShadowBlur(), 5); - shadowOpacity = util.get(shape.getShadowOpacity(), 0); - offset = util.get(shape.getShadowOffset(), { - x: 0, - y: 0 - }); - - if(shadowOpacity) { - context.globalAlpha = shadowOpacity * absOpacity; - } - - context.shadowColor = color; - context.shadowBlur = blur; - context.shadowOffsetX = offset.x; - context.shadowOffsetY = offset.y; - } + _context.scale(pixelRatio, pixelRatio); } }; Kinetic.Util.extend(Kinetic.SceneCanvas, Kinetic.Canvas); Kinetic.HitCanvas = function(config) { + config = config || {}; + var width = config.width || 0, + height = config.height || 0; + Kinetic.Canvas.call(this, config); - }; - - Kinetic.HitCanvas.prototype = { - _fill: function(shape) { - var context = this.context; - context.save(); - context.fillStyle = shape.colorKey; - shape._fillFuncHit(context); - context.restore(); - }, - _stroke: function(shape) { - var context = this.context, - stroke = shape.getStroke(), - strokeWidth = shape.getStrokeWidth(); - - if(stroke || strokeWidth) { - this._applyLineCap(shape); - context.lineWidth = strokeWidth || 2; - context.strokeStyle = shape.colorKey; - shape._strokeFuncHit(context); - } - } + this.context = new Kinetic.HitContext(this); + this.setSize(width, height); }; Kinetic.Util.extend(Kinetic.HitCanvas, Kinetic.Canvas); diff --git a/src/Container.js b/src/Container.js index 292d0d45..37188c78 100644 --- a/src/Container.js +++ b/src/Container.js @@ -253,7 +253,7 @@ if(this.isVisible()) { if (clip) { - canvas._clip(this); + canvas.getContext()._clip(this); } else { this._drawChildren(canvas); @@ -271,16 +271,16 @@ } }, drawHit: function() { - var clip = this.getClipWidth() && this.getClipHeight() && this.nodeType !== 'Stage', + var hasClip = this.getClipWidth() && this.getClipHeight() && this.nodeType !== 'Stage', n = 0, len = 0, children = [], hitCanvas; if(this.shouldDrawHit()) { - if (clip) { + if (hasClip) { hitCanvas = this.getLayer().hitCanvas; - hitCanvas._clip(this); + hitCanvas.getContext()._clip(this); } children = this.children; @@ -289,8 +289,8 @@ for(n = 0; n < len; n++) { children[n].drawHit(); } - if (clip) { - hitCanvas.getContext().restore(); + if (hasClip) { + hitCanvas.getContext()._context.restore(); } } diff --git a/src/Context.js b/src/Context.js new file mode 100644 index 00000000..ca964648 --- /dev/null +++ b/src/Context.js @@ -0,0 +1,350 @@ +(function() { + /** + * Canvas Context constructor + * @constructor + * @abstract + * @memberof Kinetic + */ + Kinetic.Context = function(canvas) { + this.init(canvas); + }; + + Kinetic.Context.prototype = { + init: function(canvas) { + this.canvas = canvas; + this._context = canvas._canvas.getContext('2d'); + }, + /** + * reset canvas context transform + * @method + * @memberof Kinetic.Context.prototype + */ + reset: function() { + var pixelRatio = this.getCanvas().getPixelRatio(); + this._context.setTransform(1 * pixelRatio, 0, 0, 1 * pixelRatio, 0, 0); + }, + getCanvas: function() { + return this.canvas; + }, + /** + * clear canvas + * @method + * @memberof Kinetic.Context.prototype + */ + clear: function(clip) { + var _context = this._context, + canvas = this.getCanvas(), + pos, size; + + if (clip) { + pos = Kinetic.Util._getXY(clip); + size = Kinetic.Util._getSize(clip); + _context.clearRect(pos.x || 0, pos.y || 0, size.width, size.height); + } + else { + _context.clearRect(0, 0, canvas.getWidth(), canvas.getHeight()); + } + }, + /** + * fill shape + * @method + * @memberof Kinetic.Context.prototype + * @param {Kinetic.Shape} shape + */ + fill: function(shape) { + if(shape.getFillEnabled()) { + this._fill(shape); + } + }, + /** + * stroke shape + * @method + * @memberof Kinetic.Context.prototype + * @param {Kinetic.Shape} shape + */ + stroke: function(shape) { + if(shape.getStrokeEnabled()) { + this._stroke(shape); + } + }, + /** + * fill, stroke, and apply shadows + * will only be applied to either the fill or stroke.  Fill + * is given priority over stroke. + * @method + * @memberof Kinetic.Context.prototype + * @param {Kinetic.Shape} shape + */ + fillStroke: function(shape) { + var fillEnabled = shape.getFillEnabled(); + if(fillEnabled) { + this._fill(shape); + } + + if(shape.getStrokeEnabled()) { + this._stroke(shape, shape.hasShadow() && shape.hasFill() && fillEnabled); + } + }, + /** + * apply shadow + * @method + * @memberof Kinetic.Context.prototype + * @param {Kinetic.Shape} shape + * @param {Function} drawFunc + */ + applyShadow: function(shape, drawFunc) { + var _context = this._context; + _context.save(); + this._applyShadow(shape); + drawFunc(); + _context.restore(); + drawFunc(); + }, + _applyLineCap: function(shape) { + var lineCap = shape.getLineCap(); + if(lineCap) { + this._context.lineCap = lineCap; + } + }, + _applyOpacity: function(shape) { + var absOpacity = shape.getAbsoluteOpacity(); + if(absOpacity !== 1) { + this._context.globalAlpha = absOpacity; + } + }, + _applyLineJoin: function(shape) { + var lineJoin = shape.getLineJoin(); + if(lineJoin) { + this._context.lineJoin = lineJoin; + } + }, + _applyAncestorTransforms: function(shape) { + var m = shape.getAbsoluteTransform().getMatrix(); + this._context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); + }, + _clip: function(container) { + var _context = this._context, + clipX = container.getClipX() || 0, + clipY = container.getClipY() || 0, + clipWidth = container.getClipWidth(), + clipHeight = container.getClipHeight(); + + _context.save(); + this._applyAncestorTransforms(container); + _context.beginPath(); + _context.rect(clipX, clipY, clipWidth, clipHeight); + _context.clip(); + this.reset(); + container._drawChildren(this.getCanvas()); + _context.restore(); + } + }; + + Kinetic.SceneContext = function(canvas) { + Kinetic.Context.call(this, canvas); + }; + + Kinetic.SceneContext.prototype = { + _fillColor: function(shape) { + var _context = this._context, + fill = shape.getFill(); + + _context.fillStyle = fill; + shape._fillFunc(_context); + }, + _fillPattern: function(shape) { + var _context = this._context, + fillPatternImage = shape.getFillPatternImage(), + fillPatternX = shape.getFillPatternX(), + fillPatternY = shape.getFillPatternY(), + fillPatternScale = shape.getFillPatternScale(), + fillPatternRotation = shape.getFillPatternRotation(), + fillPatternOffset = shape.getFillPatternOffset(), + fillPatternRepeat = shape.getFillPatternRepeat(); + + if(fillPatternX || fillPatternY) { + _context.translate(fillPatternX || 0, fillPatternY || 0); + } + if(fillPatternRotation) { + _context.rotate(fillPatternRotation); + } + if(fillPatternScale) { + _context.scale(fillPatternScale.x, fillPatternScale.y); + } + if(fillPatternOffset) { + _context.translate(-1 * fillPatternOffset.x, -1 * fillPatternOffset.y); + } + + _context.fillStyle = _context.createPattern(fillPatternImage, fillPatternRepeat || 'repeat'); + _context.fill(); + }, + _fillLinearGradient: function(shape) { + var _context = this._context, + start = shape.getFillLinearGradientStartPoint(), + end = shape.getFillLinearGradientEndPoint(), + colorStops = shape.getFillLinearGradientColorStops(), + grd = _context.createLinearGradient(start.x, start.y, end.x, end.y); + + if (colorStops) { + // build color stops + for(var n = 0; n < colorStops.length; n += 2) { + grd.addColorStop(colorStops[n], colorStops[n + 1]); + } + _context.fillStyle = grd; + _context.fill(); + } + }, + _fillRadialGradient: function(shape) { + var _context = this._context, + start = shape.getFillRadialGradientStartPoint(), + end = shape.getFillRadialGradientEndPoint(), + startRadius = shape.getFillRadialGradientStartRadius(), + endRadius = shape.getFillRadialGradientEndRadius(), + colorStops = shape.getFillRadialGradientColorStops(), + grd = _context.createRadialGradient(start.x, start.y, startRadius, end.x, end.y, endRadius); + + // build color stops + for(var n = 0; n < colorStops.length; n += 2) { + grd.addColorStop(colorStops[n], colorStops[n + 1]); + } + _context.fillStyle = grd; + _context.fill(); + }, + _fill: function(shape, skipShadow) { + var _context = this._context, + hasColor = shape.getFill(), + hasPattern = shape.getFillPatternImage(), + hasLinearGradient = shape.getFillLinearGradientColorStops(), + hasRadialGradient = shape.getFillRadialGradientColorStops(), + fillPriority = shape.getFillPriority(); + + _context.save(); + + if(!skipShadow && shape.hasShadow()) { + this._applyShadow(shape); + } + + // priority fills + if(hasColor && fillPriority === 'color') { + this._fillColor(shape); + } + else if(hasPattern && fillPriority === 'pattern') { + this._fillPattern(shape); + } + else if(hasLinearGradient && fillPriority === 'linear-gradient') { + this._fillLinearGradient(shape); + } + else if(hasRadialGradient && fillPriority === 'radial-gradient') { + this._fillRadialGradient(shape); + } + // now just try and fill with whatever is available + else if(hasColor) { + this._fillColor(shape); + } + else if(hasPattern) { + this._fillPattern(shape); + } + else if(hasLinearGradient) { + this._fillLinearGradient(shape); + } + else if(hasRadialGradient) { + this._fillRadialGradient(shape); + } + _context.restore(); + + if(!skipShadow && shape.hasShadow()) { + this._fill(shape, true); + } + }, + _stroke: function(shape, skipShadow) { + var _context = this._context, + stroke = shape.getStroke(), + strokeWidth = shape.getStrokeWidth(), + dashArray = shape.getDashArray(); + + if(stroke || strokeWidth) { + _context.save(); + if (!shape.getStrokeScaleEnabled()) { + _context.setTransform(1, 0, 0, 1, 0, 0); + } + this._applyLineCap(shape); + if(dashArray && shape.getDashArrayEnabled()) { + if(_context.setLineDash) { + _context.setLineDash(dashArray); + } + else if('mozDash' in _context) { + _context.mozDash = dashArray; + } + else if('webkitLineDash' in _context) { + _context.webkitLineDash = dashArray; + } + } + if(!skipShadow && shape.hasShadow()) { + this._applyShadow(shape); + } + _context.lineWidth = strokeWidth || 2; + _context.strokeStyle = stroke || 'black'; + shape._strokeFunc(_context); + _context.restore(); + + if(!skipShadow && shape.hasShadow()) { + this._stroke(shape, true); + } + } + }, + _applyShadow: function(shape) { + var _context = this._context, + util, absOpacity, color, blur, offset, shadowOpacity; + + if(shape.hasShadow() && shape.getShadowEnabled()) { + util = Kinetic.Util; + absOpacity = shape.getAbsoluteOpacity(); + color = util.get(shape.getShadowColor(), 'black'); + blur = util.get(shape.getShadowBlur(), 5); + shadowOpacity = util.get(shape.getShadowOpacity(), 0); + offset = util.get(shape.getShadowOffset(), { + x: 0, + y: 0 + }); + + if(shadowOpacity) { + _context.globalAlpha = shadowOpacity * absOpacity; + } + + _context.shadowColor = color; + _context.shadowBlur = blur; + _context.shadowOffsetX = offset.x; + _context.shadowOffsetY = offset.y; + } + } + }; + Kinetic.Util.extend(Kinetic.SceneContext, Kinetic.Context); + + Kinetic.HitContext = function(canvas) { + Kinetic.Context.call(this, canvas); + }; + + Kinetic.HitContext.prototype = { + _fill: function(shape) { + var _context = this._context; + _context.save(); + _context.fillStyle = shape.colorKey; + shape._fillFuncHit(_context); + _context.restore(); + }, + _stroke: function(shape) { + var _context = this._context, + stroke = shape.getStroke(), + strokeWidth = shape.getStrokeWidth(); + + if(stroke || strokeWidth) { + this._applyLineCap(shape); + _context.lineWidth = strokeWidth || 2; + _context.strokeStyle = shape.colorKey; + shape._strokeFuncHit(_context); + } + } + }; + Kinetic.Util.extend(Kinetic.HitContext, Kinetic.Context); + +})(); diff --git a/src/Layer.js b/src/Layer.js index 1e5253e7..bf342502 100644 --- a/src/Layer.js +++ b/src/Layer.js @@ -30,7 +30,7 @@ p, colorKey, shape; if(this.isVisible() && this.isListening()) { - p = this.hitCanvas.context.getImageData(pos.x | 0, pos.y | 0, 1, 1).data; + p = this.hitCanvas.context._context.getImageData(pos.x | 0, pos.y | 0, 1, 1).data; // this indicates that a hit pixel may have been found if(p[3] === 255) { colorKey = Kinetic.Util._rgbToHex(p[0], p[1], p[2]); @@ -51,6 +51,7 @@ return null; }, drawScene: function(canvas) { + debugger; canvas = canvas || this.getCanvas(); this._fire(BEFORE_DRAW, { @@ -58,7 +59,7 @@ }); if(this.getClearBeforeDraw()) { - canvas.clear(); + canvas.getContext().clear(); } Kinetic.Container.prototype.drawScene.call(this, canvas); @@ -73,7 +74,7 @@ var layer = this.getLayer(); if(layer && layer.getClearBeforeDraw()) { - layer.getHitCanvas().clear(); + layer.getHitCanvas().getContext().clear(); } Kinetic.Container.prototype.drawHit.call(this); @@ -115,74 +116,79 @@ this.getCanvas().clear(clip); return this; }, - // extenders + // extend Node.prototype.setVisible setVisible: function(visible) { Kinetic.Node.prototype.setVisible.call(this, visible); if(visible) { - this.getCanvas().element.style.display = 'block'; - this.hitCanvas.element.style.display = 'block'; + this.getCanvas()._canvas.style.display = 'block'; + this.hitCanvas._canvas.style.display = 'block'; } else { - this.getCanvas().element.style.display = 'none'; - this.hitCanvas.element.style.display = 'none'; + this.getCanvas()._canvas.style.display = 'none'; + this.hitCanvas._canvas.style.display = 'none'; } return this; }, + // extend Node.prototype.setZIndex setZIndex: function(index) { Kinetic.Node.prototype.setZIndex.call(this, index); var stage = this.getStage(); if(stage) { - stage.content.removeChild(this.getCanvas().element); + stage.content.removeChild(this.getCanvas()._canvas); if(index < stage.getChildren().length - 1) { - stage.content.insertBefore(this.getCanvas().element, stage.getChildren()[index + 1].getCanvas().element); + stage.content.insertBefore(this.getCanvas()._canvas, stage.getChildren()[index + 1].getCanvas()._canvas); } else { - stage.content.appendChild(this.getCanvas().element); + stage.content.appendChild(this.getCanvas()._canvas); } } return this; }, + // extend Node.prototype.moveToTop moveToTop: function() { Kinetic.Node.prototype.moveToTop.call(this); var stage = this.getStage(); if(stage) { - stage.content.removeChild(this.getCanvas().element); - stage.content.appendChild(this.getCanvas().element); + stage.content.removeChild(this.getCanvas()._canvas); + stage.content.appendChild(this.getCanvas()._canvas); } }, + // extend Node.prototype.moveUp moveUp: function() { if(Kinetic.Node.prototype.moveUp.call(this)) { var stage = this.getStage(); if(stage) { - stage.content.removeChild(this.getCanvas().element); + stage.content.removeChild(this.getCanvas()._canvas); if(this.index < stage.getChildren().length - 1) { - stage.content.insertBefore(this.getCanvas().element, stage.getChildren()[this.index + 1].getCanvas().element); + stage.content.insertBefore(this.getCanvas()._canvas, stage.getChildren()[this.index + 1].getCanvas()._canvas); } else { - stage.content.appendChild(this.getCanvas().element); + stage.content.appendChild(this.getCanvas()._canvas); } } } }, + // extend Node.prototype.moveDown moveDown: function() { if(Kinetic.Node.prototype.moveDown.call(this)) { var stage = this.getStage(); if(stage) { var children = stage.getChildren(); - stage.content.removeChild(this.getCanvas().element); - stage.content.insertBefore(this.getCanvas().element, children[this.index + 1].getCanvas().element); + stage.content.removeChild(this.getCanvas()._canvas); + stage.content.insertBefore(this.getCanvas()._canvas, children[this.index + 1].getCanvas()._canvas); } } }, + // extend Node.prototype.moveToBottom moveToBottom: function() { if(Kinetic.Node.prototype.moveToBottom.call(this)) { var stage = this.getStage(); if(stage) { var children = stage.getChildren(); - stage.content.removeChild(this.getCanvas().element); - stage.content.insertBefore(this.getCanvas().element, children[1].getCanvas().element); + stage.content.removeChild(this.getCanvas()._canvas); + stage.content.insertBefore(this.getCanvas()._canvas, children[1].getCanvas()._canvas); } } }, @@ -190,11 +196,14 @@ return this; }, remove: function() { - var stage = this.getStage(), canvas = this.getCanvas(), element = canvas.element; + var stage = this.getStage(), + canvas = this.getCanvas(), + _canvas = canvas._canvas; + Kinetic.Node.prototype.remove.call(this); - if(stage && canvas && Kinetic.Util._isInDocument(element)) { - stage.content.removeChild(element); + if(stage && _canvas && Kinetic.Util._isInDocument(_canvas)) { + stage.content.removeChild(_canvas); } return this; }, diff --git a/src/Node.js b/src/Node.js index dc6be303..a80720ba 100644 --- a/src/Node.js +++ b/src/Node.js @@ -1009,16 +1009,16 @@ height: config.height || stage.getHeight(), pixelRatio: 1 }), - context = canvas.getContext(); + _context = canvas.getContext()._context; - context.save(); + _context.save(); if(x || y) { - context.translate(-1 * x, -1 * y); + _context.translate(-1 * x, -1 * y); } this.drawScene(canvas); - context.restore(); + _context.restore(); return canvas.toDataURL(mimeType, quality); }, diff --git a/src/Shape.js b/src/Shape.js index c759f6ae..81cd308d 100644 --- a/src/Shape.js +++ b/src/Shape.js @@ -1,17 +1,17 @@ (function() { var HAS_SHADOW = 'hasShadow'; - function _fillFunc(context) { - context.fill(); + function _fillFunc(_context) { + _context.fill(); } - function _strokeFunc(context) { - context.stroke(); + function _strokeFunc(_context) { + _context.stroke(); } - function _fillFuncHit(context) { - context.fill(); + function _fillFuncHit(_context) { + _context.fill(); } - function _strokeFuncHit(context) { - context.stroke(); + function _strokeFuncHit(_context) { + _context.stroke(); } function _clearHasShadowCache() { @@ -107,9 +107,9 @@ var pos = Kinetic.Util._getXY(Array.prototype.slice.call(arguments)); var stage = this.getStage(); var hitCanvas = stage.hitCanvas; - hitCanvas.clear(); + hitCanvas.getContext().clear(); this.drawScene(hitCanvas); - var p = hitCanvas.context.getImageData(pos.x | 0, pos.y | 0, 1, 1).data; + var p = hitCanvas.context._context.getImageData(pos.x | 0, pos.y | 0, 1, 1).data; return p[3] > 0; }, /** @@ -202,6 +202,7 @@ this._setAttr('dashArrayEnabled', false); return this; }, + // extends Node.prototype.destroy destroy: function() { Kinetic.Node.prototype.destroy.call(this); delete Kinetic.Global.shapes[this.colorKey]; @@ -214,12 +215,12 @@ context = canvas.getContext(); if(drawFunc && this.isVisible()) { - context.save(); - canvas._applyOpacity(this); - canvas._applyLineJoin(this); - canvas._applyAncestorTransforms(this); - drawFunc.call(this, canvas); - context.restore(); + context._context.save(); + context._applyOpacity(this); + context._applyLineJoin(this); + context._applyAncestorTransforms(this); + drawFunc.call(this, context); + context._context.restore(); } return this; }, @@ -230,12 +231,12 @@ context = canvas.getContext(); if(drawFunc && this.shouldDrawHit()) { - context.save(); - canvas._applyLineJoin(this); - canvas._applyAncestorTransforms(this); + context._context.save(); + context._applyLineJoin(this); + context._applyAncestorTransforms(this); - drawFunc.call(this, canvas); - context.restore(); + drawFunc.call(this, context); + context._context.restore(); } return this; }, diff --git a/src/Stage.js b/src/Stage.js index cfb3569b..891920cb 100644 --- a/src/Stage.js +++ b/src/Stage.js @@ -196,11 +196,11 @@ height: config.height || this.getHeight(), pixelRatio: 1 }), - context = canvas.getContext(), + _context = canvas.getContext()._context, layers = this.children; if(x || y) { - context.translate(-1 * x, -1 * y); + _context.translate(-1 * x, -1 * y); } function drawLayer(n) { @@ -209,7 +209,7 @@ imageObj = new Image(); imageObj.onload = function() { - context.drawImage(imageObj, 0, 0); + _context.drawImage(imageObj, 0, 0); if(n < layers.length - 1) { drawLayer(n + 1); @@ -308,7 +308,7 @@ // draw layer and append canvas to container layer.draw(); - this.content.appendChild(layer.canvas.element); + this.content.appendChild(layer.canvas._canvas); // chainable return this; diff --git a/src/plugins/Label.js b/src/plugins/Label.js index 562b9026..295723de 100644 --- a/src/plugins/Label.js +++ b/src/plugins/Label.js @@ -86,7 +86,7 @@ getTag: function() { return this.get('Tag')[0]; }, - _addListeners: function(context) { + _addListeners: function(text) { var that = this, n; var func = function(){ @@ -95,7 +95,7 @@ // update text data for certain attr changes for(n = 0; n < attrChangeListLen; n++) { - context.on(ATTR_CHANGE_LIST[n] + CHANGE_KINETIC, func); + text.on(ATTR_CHANGE_LIST[n] + CHANGE_KINETIC, func); } }, getWidth: function() { @@ -175,8 +175,8 @@ Kinetic.Shape.call(this, config); this.className = 'Tag'; }, - drawFunc: function(canvas) { - var context = canvas.getContext(), + drawFunc: function(context) { + var _context = context._context, width = this.getWidth(), height = this.getHeight(), pointerDirection = this.getPointerDirection(), @@ -184,41 +184,41 @@ pointerHeight = this.getPointerHeight(), cornerRadius = this.getCornerRadius(); - context.beginPath(); - context.moveTo(0,0); + _context.beginPath(); + _context.moveTo(0,0); if (pointerDirection === UP) { - context.lineTo((width - pointerWidth)/2, 0); - context.lineTo(width/2, -1 * pointerHeight); - context.lineTo((width + pointerWidth)/2, 0); + _context.lineTo((width - pointerWidth)/2, 0); + _context.lineTo(width/2, -1 * pointerHeight); + _context.lineTo((width + pointerWidth)/2, 0); } - context.lineTo(width, 0); + _context.lineTo(width, 0); if (pointerDirection === RIGHT) { - context.lineTo(width, (height - pointerHeight)/2); - context.lineTo(width + pointerWidth, height/2); - context.lineTo(width, (height + pointerHeight)/2); + _context.lineTo(width, (height - pointerHeight)/2); + _context.lineTo(width + pointerWidth, height/2); + _context.lineTo(width, (height + pointerHeight)/2); } - context.lineTo(width, height); + _context.lineTo(width, height); if (pointerDirection === DOWN) { - context.lineTo((width + pointerWidth)/2, height); - context.lineTo(width/2, height + pointerHeight); - context.lineTo((width - pointerWidth)/2, height); + _context.lineTo((width + pointerWidth)/2, height); + _context.lineTo(width/2, height + pointerHeight); + _context.lineTo((width - pointerWidth)/2, height); } - context.lineTo(0, height); + _context.lineTo(0, height); if (pointerDirection === LEFT) { - context.lineTo(0, (height + pointerHeight)/2); - context.lineTo(-1 * pointerWidth, height/2); - context.lineTo(0, (height - pointerHeight)/2); + _context.lineTo(0, (height + pointerHeight)/2); + _context.lineTo(-1 * pointerWidth, height/2); + _context.lineTo(0, (height - pointerHeight)/2); } - context.closePath(); - canvas.fillStroke(this); + _context.closePath(); + context.fillStroke(this); } }; diff --git a/src/plugins/Path.js b/src/plugins/Path.js index 41205b1e..49c292fb 100644 --- a/src/plugins/Path.js +++ b/src/plugins/Path.js @@ -36,25 +36,27 @@ that.dataArray = Kinetic.Path.parsePathData(this.getData()); }); }, - drawFunc: function (canvas) { - var ca = this.dataArray, context = canvas.getContext(); + drawFunc: function (context) { + var ca = this.dataArray, + _context = context._context; + // context position - context.beginPath(); + _context.beginPath(); for (var n = 0; n < ca.length; n++) { var c = ca[n].command; var p = ca[n].points; switch (c) { case 'L': - context.lineTo(p[0], p[1]); + _context.lineTo(p[0], p[1]); break; case 'M': - context.moveTo(p[0], p[1]); + _context.moveTo(p[0], p[1]); break; case 'C': - context.bezierCurveTo(p[0], p[1], p[2], p[3], p[4], p[5]); + _context.bezierCurveTo(p[0], p[1], p[2], p[3], p[4], p[5]); break; case 'Q': - context.quadraticCurveTo(p[0], p[1], p[2], p[3]); + _context.quadraticCurveTo(p[0], p[1], p[2], p[3]); break; case 'A': var cx = p[0], cy = p[1], rx = p[2], ry = p[3], theta = p[4], dTheta = p[5], psi = p[6], fs = p[7]; @@ -63,24 +65,25 @@ var scaleX = (rx > ry) ? 1 : rx / ry; var scaleY = (rx > ry) ? ry / rx : 1; - context.translate(cx, cy); - context.rotate(psi); - context.scale(scaleX, scaleY); - context.arc(0, 0, r, theta, theta + dTheta, 1 - fs); - context.scale(1 / scaleX, 1 / scaleY); - context.rotate(-psi); - context.translate(-cx, -cy); + _context.translate(cx, cy); + _context.rotate(psi); + _context.scale(scaleX, scaleY); + _context.arc(0, 0, r, theta, theta + dTheta, 1 - fs); + _context.scale(1 / scaleX, 1 / scaleY); + _context.rotate(-psi); + _context.translate(-cx, -cy); break; case 'z': - context.closePath(); + _context.closePath(); break; } } - if (this.getFill() !== undefined) - canvas.fill(this); + if (this.getFill() !== undefined) { + context.fill(this); + } - canvas.stroke(this); + context.stroke(this); } }; Kinetic.Util.extend(Kinetic.Path, Kinetic.Shape); diff --git a/src/plugins/RegularPolygon.js b/src/plugins/RegularPolygon.js index c2ce6be5..cdd60387 100644 --- a/src/plugins/RegularPolygon.js +++ b/src/plugins/RegularPolygon.js @@ -30,22 +30,22 @@ Kinetic.Shape.call(this, config); this.className = 'RegularPolygon'; }, - drawFunc: function(canvas) { - var context = canvas.getContext(), + drawFunc: function(context) { + var _context = context._context, sides = this.attrs.sides, radius = this.attrs.radius, n, x, y; - context.beginPath(); - context.moveTo(0, 0 - radius); + _context.beginPath(); + _context.moveTo(0, 0 - radius); for(n = 1; n < sides; n++) { x = radius * Math.sin(n * 2 * Math.PI / sides); y = -1 * radius * Math.cos(n * 2 * Math.PI / sides); - context.lineTo(x, y); + _context.lineTo(x, y); } - context.closePath(); - canvas.fillStroke(this); + _context.closePath(); + context.fillStroke(this); } }; Kinetic.Util.extend(Kinetic.RegularPolygon, Kinetic.Shape); diff --git a/src/plugins/Star.js b/src/plugins/Star.js index 48c9fbdf..d2c8a18e 100644 --- a/src/plugins/Star.js +++ b/src/plugins/Star.js @@ -32,21 +32,24 @@ Kinetic.Shape.call(this, config); this.className = 'Star'; }, - drawFunc: function(canvas) { - var context = canvas.getContext(), innerRadius = this.attrs.innerRadius, outerRadius = this.attrs.outerRadius, numPoints = this.attrs.numPoints; + drawFunc: function(context) { + var _context = context._context, + innerRadius = this.attrs.innerRadius, + outerRadius = this.attrs.outerRadius, + numPoints = this.attrs.numPoints; - context.beginPath(); - context.moveTo(0, 0 - this.attrs.outerRadius); + _context.beginPath(); + _context.moveTo(0, 0 - this.attrs.outerRadius); for(var n = 1; n < numPoints * 2; n++) { var radius = n % 2 === 0 ? outerRadius : innerRadius; var x = radius * Math.sin(n * Math.PI / numPoints); var y = -1 * radius * Math.cos(n * Math.PI / numPoints); - context.lineTo(x, y); + _context.lineTo(x, y); } - context.closePath(); + _context.closePath(); - canvas.fillStroke(this); + context.fillStroke(this); } }; Kinetic.Util.extend(Kinetic.Star, Kinetic.Shape); diff --git a/src/plugins/TextPath.js b/src/plugins/TextPath.js index 153c49e7..6a7f45e5 100644 --- a/src/plugins/TextPath.js +++ b/src/plugins/TextPath.js @@ -32,11 +32,11 @@ this.___init(config); }; - function _fillFunc(context) { - context.fillText(this.partialText, 0, 0); + function _fillFunc(_context) { + _context.fillText(this.partialText, 0, 0); } - function _strokeFunc(context) { - context.strokeText(this.partialText, 0, 0); + function _strokeFunc(_context) { + _context.strokeText(this.partialText, 0, 0); } Kinetic.TextPath.prototype = { @@ -64,28 +64,29 @@ this.on('textChange.kinetic textStroke.kinetic textStrokeWidth.kinetic', that._setTextData); that._setTextData(); }, - drawFunc: function(canvas) { - var charArr = this.charArr, context = canvas.getContext(); + drawFunc: function(context) { + var charArr = this.charArr, + _context = context._context; - context.font = this._getContextFont(); - context.textBaseline = 'middle'; - context.textAlign = 'left'; - context.save(); + _context.font = this._getContextFont(); + _context.textBaseline = 'middle'; + _context.textAlign = 'left'; + _context.save(); var glyphInfo = this.glyphInfo; for(var i = 0; i < glyphInfo.length; i++) { - context.save(); + _context.save(); var p0 = glyphInfo[i].p0; var p1 = glyphInfo[i].p1; var ht = parseFloat(this.attrs.fontSize); - context.translate(p0.x, p0.y); - context.rotate(glyphInfo[i].rotation); + _context.translate(p0.x, p0.y); + _context.rotate(glyphInfo[i].rotation); this.partialText = glyphInfo[i].text; - canvas.fillStroke(this); - context.restore(); + context.fillStroke(this); + _context.restore(); //// To assist with debugging visually, uncomment following // context.beginPath(); @@ -98,7 +99,7 @@ // context.lineTo(p1.x, p1.y); // context.stroke(); } - context.restore(); + _context.restore(); }, /** * get text width in pixels @@ -127,14 +128,14 @@ }, _getTextSize: function(text) { var dummyCanvas = this.dummyCanvas; - var context = dummyCanvas.getContext('2d'); + var _context = dummyCanvas.getContext('2d'); - context.save(); + _context.save(); - context.font = this._getContextFont(); - var metrics = context.measureText(text); + _context.font = this._getContextFont(); + var metrics = _context.measureText(text); - context.restore(); + _context.restore(); return { width: metrics.width, diff --git a/src/shapes/Blob.js b/src/shapes/Blob.js index 214a8dcb..28bf1881 100644 --- a/src/shapes/Blob.js +++ b/src/shapes/Blob.js @@ -37,15 +37,15 @@ this._setAllPoints(); }, - drawFunc: function(canvas) { + drawFunc: function(context) { var points = this.getPoints(), length = points.length, - context = canvas.getContext(), + _context = context._context, tension = this.getTension(), ap, len, n, point; - context.beginPath(); - context.moveTo(points[0].x, points[0].y); + _context.beginPath(); + _context.moveTo(points[0].x, points[0].y); // tension if(tension !== 0 && length > 2) { @@ -54,19 +54,19 @@ n = 0; while(n < len-1) { - context.bezierCurveTo(ap[n].x, ap[n++].y, ap[n].x, ap[n++].y, ap[n].x, ap[n++].y); + _context.bezierCurveTo(ap[n].x, ap[n++].y, ap[n].x, ap[n++].y, ap[n].x, ap[n++].y); } } // no tension else { for(n = 1; n < length; n++) { point = points[n]; - context.lineTo(point.x, point.y); + _context.lineTo(point.x, point.y); } } - context.closePath(); - canvas.fillStroke(this); + _context.closePath(); + context.fillStroke(this); }, _setAllPoints: function() { var points = this.getPoints(), diff --git a/src/shapes/Circle.js b/src/shapes/Circle.js index 615b6d6d..23628589 100644 --- a/src/shapes/Circle.js +++ b/src/shapes/Circle.js @@ -41,13 +41,13 @@ Kinetic.Shape.call(this, config); this.className = CIRCLE; }, - drawFunc: function(canvas) { - var context = canvas.getContext(); + drawFunc: function(context) { + var _context = context._context; - context.beginPath(); - context.arc(0, 0, this.getRadius(), 0, PIx2, false); - context.closePath(); - canvas.fillStroke(this); + _context.beginPath(); + _context.arc(0, 0, this.getRadius(), 0, PIx2, false); + _context.closePath(); + context.fillStroke(this); }, getWidth: function() { return this.getRadius() * 2; diff --git a/src/shapes/Ellipse.js b/src/shapes/Ellipse.js index ab681bf9..de6032a5 100644 --- a/src/shapes/Ellipse.js +++ b/src/shapes/Ellipse.js @@ -22,17 +22,19 @@ Kinetic.Shape.call(this, config); this.className = ELLIPSE; }, - drawFunc: function(canvas) { - var context = canvas.getContext(), r = this.getRadius(); - context.beginPath(); - context.save(); + drawFunc: function(context) { + var _context = context._context, + r = this.getRadius(); + + _context.beginPath(); + _context.save(); if(r.x !== r.y) { - context.scale(1, r.y / r.x); + _context.scale(1, r.y / r.x); } - context.arc(0, 0, r.x, 0, PIx2, false); - context.restore(); - context.closePath(); - canvas.fillStroke(this); + _context.arc(0, 0, r.x, 0, PIx2, false); + _context.restore(); + _context.closePath(); + context.fillStroke(this); }, getWidth: function() { return this.getRadius().x * 2; diff --git a/src/shapes/Image.js b/src/shapes/Image.js index c5d41869..791c615d 100644 --- a/src/shapes/Image.js +++ b/src/shapes/Image.js @@ -40,12 +40,12 @@ Kinetic.Shape.call(this, config); this.className = IMAGE; }, - drawFunc: function(canvas) { + drawFunc: function(context) { var width = this.getWidth(), height = this.getHeight(), params, that = this, - context = canvas.getContext(), + _context = context._context, cropX = this.getCropX() || 0, cropY = this.getCropY() || 0, cropWidth = this.getCropWidth(), @@ -60,16 +60,16 @@ // NOTE: this.filterCanvas may be set by the above code block if (this.filterCanvas) { - image = this.filterCanvas.getElement(); + image = this.filterCanvas._canvas; } else { image = this.getImage(); } - context.beginPath(); - context.rect(0, 0, width, height); - context.closePath(); - canvas.fillStroke(this); + _context.beginPath(); + _context.rect(0, 0, width, height); + _context.closePath(); + context.fillStroke(this); if(image) { // if cropping @@ -82,33 +82,33 @@ } if(this.hasShadow()) { - canvas.applyShadow(this, function() { - that._drawImage(context, params); + context.applyShadow(this, function() { + that._drawImage(_context, params); }); } else { - this._drawImage(context, params); + this._drawImage(_context, params); } } }, - drawHitFunc: function(canvas) { + drawHitFunc: function(context) { var width = this.getWidth(), height = this.getHeight(), imageHitRegion = this.imageHitRegion, - context = canvas.getContext(); + _context = context._context; if(imageHitRegion) { - context.drawImage(imageHitRegion, 0, 0, width, height); - context.beginPath(); - context.rect(0, 0, width, height); - context.closePath(); - canvas.stroke(this); + _context.drawImage(imageHitRegion, 0, 0, width, height); + _context.beginPath(); + _context.rect(0, 0, width, height); + _context.closePath(); + context.stroke(this); } else { - context.beginPath(); - context.rect(0, 0, width, height); - context.closePath(); - canvas.fillStroke(this); + _context.beginPath(); + _context.rect(0, 0, width, height); + _context.closePath(); + context.fillStroke(this); } }, applyFilter: function() { @@ -117,11 +117,11 @@ width = this.getWidth(), height = this.getHeight(), filter = this.getFilter(), - filterCanvas, context, imageData; + filterCanvas, _context, imageData; if (this.filterCanvas){ filterCanvas = this.filterCanvas; - filterCanvas.clear(); + filterCanvas.getContext().clear(); } else { filterCanvas = this.filterCanvas = new Kinetic.SceneCanvas({ @@ -131,13 +131,13 @@ }); } - context = filterCanvas.getContext(); + _context = filterCanvas.getContext()._context; try { - this._drawImage(context, [image, 0, 0, filterCanvas.getWidth(), filterCanvas.getHeight()]); - imageData = context.getImageData(0, 0, filterCanvas.getWidth(), filterCanvas.getHeight()); + this._drawImage(_context, [image, 0, 0, filterCanvas.getWidth(), filterCanvas.getHeight()]); + imageData = _context.getImageData(0, 0, filterCanvas.getWidth(), filterCanvas.getHeight()); filter.call(this, imageData); - context.putImageData(imageData, 0, 0); + _context.putImageData(imageData, 0, 0); } catch(e) { this.clearFilter(); @@ -165,18 +165,19 @@ var that = this, width = this.getWidth(), height = this.getHeight(), - canvas = new Kinetic.Canvas({ + // TODO: may consider creating a native canvas element here instead + canvas = new Kinetic.SceneCanvas({ width: width, height: height }), - context = canvas.getContext(), + _context = canvas.getContext()._context, image = this.getImage(), imageData, data, rgbColorKey, i, n; - context.drawImage(image, 0, 0); + _context.drawImage(image, 0, 0); try { - imageData = context.getImageData(0, 0, width, height); + imageData = _context.getImageData(0, 0, width, height); data = imageData.data; rgbColorKey = Kinetic.Util._hexToRgb(this.colorKey); @@ -216,12 +217,12 @@ var image = this.getImage(); return this.attrs.height || (image ? image.height : 0); }, - _drawImage: function(context, a) { + _drawImage: function(_context, a) { if(a.length === 5) { - context.drawImage(a[0], a[1], a[2], a[3], a[4]); + _context.drawImage(a[0], a[1], a[2], a[3], a[4]); } else if(a.length === 9) { - context.drawImage(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); + _context.drawImage(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); } } }; diff --git a/src/shapes/Line.js b/src/shapes/Line.js index 89b6ef0f..15038a00 100644 --- a/src/shapes/Line.js +++ b/src/shapes/Line.js @@ -41,21 +41,21 @@ Kinetic.Shape.call(this, config); this.className = 'Line'; }, - drawFunc: function(canvas) { + drawFunc: function(context) { var points = this.getPoints(), length = points.length, - context = canvas.getContext(), + _context = context._context, n, point; - context.beginPath(); - context.moveTo(points[0].x, points[0].y); + _context.beginPath(); + _context.moveTo(points[0].x, points[0].y); for(n = 1; n < length; n++) { point = points[n]; - context.lineTo(point.x, point.y); + _context.lineTo(point.x, point.y); } - canvas.stroke(this); + context.stroke(this); } }; Kinetic.Util.extend(Kinetic.Line, Kinetic.Shape); diff --git a/src/shapes/Polygon.js b/src/shapes/Polygon.js index 5bc69602..bd211145 100644 --- a/src/shapes/Polygon.js +++ b/src/shapes/Polygon.js @@ -27,15 +27,18 @@ Kinetic.Shape.call(this, config); this.className = 'Polygon'; }, - drawFunc: function(canvas) { - var context = canvas.getContext(), points = this.getPoints(), length = points.length; - context.beginPath(); - context.moveTo(points[0].x, points[0].y); + drawFunc: function(context) { + var _context = context._context, + points = this.getPoints(), + length = points.length; + + _context.beginPath(); + _context.moveTo(points[0].x, points[0].y); for(var n = 1; n < length; n++) { - context.lineTo(points[n].x, points[n].y); + _context.lineTo(points[n].x, points[n].y); } - context.closePath(); - canvas.fillStroke(this); + _context.closePath(); + context.fillStroke(this); } }; Kinetic.Util.extend(Kinetic.Polygon, Kinetic.Shape); diff --git a/src/shapes/Rect.js b/src/shapes/Rect.js index b0f2a718..59825bdf 100644 --- a/src/shapes/Rect.js +++ b/src/shapes/Rect.js @@ -26,32 +26,32 @@ Kinetic.Shape.call(this, config); this.className = 'Rect'; }, - drawFunc: function(canvas) { - var context = canvas.getContext(), + drawFunc: function(context) { + var _context = context._context, cornerRadius = this.getCornerRadius(), width = this.getWidth(), height = this.getHeight(); - context.beginPath(); + _context.beginPath(); if(!cornerRadius) { // simple rect - don't bother doing all that complicated maths stuff. - context.rect(0, 0, width, height); + _context.rect(0, 0, width, height); } else { // arcTo would be nicer, but browser support is patchy (Opera) - context.moveTo(cornerRadius, 0); - context.lineTo(width - cornerRadius, 0); - context.arc(width - cornerRadius, cornerRadius, cornerRadius, Math.PI * 3 / 2, 0, false); - context.lineTo(width, height - cornerRadius); - context.arc(width - cornerRadius, height - cornerRadius, cornerRadius, 0, Math.PI / 2, false); - context.lineTo(cornerRadius, height); - context.arc(cornerRadius, height - cornerRadius, cornerRadius, Math.PI / 2, Math.PI, false); - context.lineTo(0, cornerRadius); - context.arc(cornerRadius, cornerRadius, cornerRadius, Math.PI, Math.PI * 3 / 2, false); + _context.moveTo(cornerRadius, 0); + _context.lineTo(width - cornerRadius, 0); + _context.arc(width - cornerRadius, cornerRadius, cornerRadius, Math.PI * 3 / 2, 0, false); + _context.lineTo(width, height - cornerRadius); + _context.arc(width - cornerRadius, height - cornerRadius, cornerRadius, 0, Math.PI / 2, false); + _context.lineTo(cornerRadius, height); + _context.arc(cornerRadius, height - cornerRadius, cornerRadius, Math.PI / 2, Math.PI, false); + _context.lineTo(0, cornerRadius); + _context.arc(cornerRadius, cornerRadius, cornerRadius, Math.PI, Math.PI * 3 / 2, false); } - context.closePath(); - canvas.fillStroke(this); + _context.closePath(); + context.fillStroke(this); } }; diff --git a/src/shapes/Spline.js b/src/shapes/Spline.js index f04ea7ed..69880286 100644 --- a/src/shapes/Spline.js +++ b/src/shapes/Spline.js @@ -37,15 +37,15 @@ this._setAllPoints(); }, - drawFunc: function(canvas) { + drawFunc: function(context) { var points = this.getPoints(), length = points.length, - context = canvas.getContext(), + _context = context._context, tension = this.getTension(), ap, len, n, point; - context.beginPath(); - context.moveTo(points[0].x, points[0].y); + _context.beginPath(); + _context.moveTo(points[0].x, points[0].y); // tension if(tension !== 0 && length > 2) { @@ -53,23 +53,23 @@ len = ap.length; n = 2; - context.quadraticCurveTo(ap[0].x, ap[0].y, ap[1].x, ap[1].y); + _context.quadraticCurveTo(ap[0].x, ap[0].y, ap[1].x, ap[1].y); while(n < len - 1) { - context.bezierCurveTo(ap[n].x, ap[n++].y, ap[n].x, ap[n++].y, ap[n].x, ap[n++].y); + _context.bezierCurveTo(ap[n].x, ap[n++].y, ap[n].x, ap[n++].y, ap[n].x, ap[n++].y); } - context.quadraticCurveTo(ap[len - 1].x, ap[len - 1].y, points[length - 1].x, points[length - 1].y); + _context.quadraticCurveTo(ap[len - 1].x, ap[len - 1].y, points[length - 1].x, points[length - 1].y); } // no tension else { for(n = 1; n < length; n++) { point = points[n]; - context.lineTo(point.x, point.y); + _context.lineTo(point.x, point.y); } } - canvas.stroke(this); + context.stroke(this); }, _setAllPoints: function() { this.allPoints = Kinetic.Util._expandPoints(this.getPoints(), this.getTension()); diff --git a/src/shapes/Sprite.js b/src/shapes/Sprite.js index 21669276..aef7644f 100644 --- a/src/shapes/Sprite.js +++ b/src/shapes/Sprite.js @@ -83,27 +83,27 @@ that.setIndex(0); }); }, - drawFunc: function(canvas) { + drawFunc: function(context) { var anim = this.getAnimation(), index = this.getIndex(), f = this.getAnimations()[anim][index], - context = canvas.getContext(), + _context = context._context, image = this.getImage(); if(image) { - context.drawImage(image, f.x, f.y, f.width, f.height, 0, 0, f.width, f.height); + _context.drawImage(image, f.x, f.y, f.width, f.height, 0, 0, f.width, f.height); } }, - drawHitFunc: function(canvas) { + drawHitFunc: function(context) { var anim = this.getAnimation(), index = this.getIndex(), f = this.getAnimations()[anim][index], - context = canvas.getContext(); + _context = context._context; - context.beginPath(); - context.rect(0, 0, f.width, f.height); - context.closePath(); - canvas.fill(this); + _context.beginPath(); + _context.rect(0, 0, f.width, f.height); + _context.closePath(); + context.fill(this); }, /** * start sprite animation diff --git a/src/shapes/Text.js b/src/shapes/Text.js index 823409a1..dc0f12ab 100644 --- a/src/shapes/Text.js +++ b/src/shapes/Text.js @@ -58,11 +58,11 @@ Kinetic.Text = function(config) { this.___init(config); }; - function _fillFunc(context) { - context.fillText(this.partialText, 0, 0); + function _fillFunc(_context) { + _context.fillText(this.partialText, 0, 0); } - function _strokeFunc(context) { - context.strokeText(this.partialText, 0, 0); + function _strokeFunc(_context) { + _context.strokeText(this.partialText, 0, 0); } Kinetic.Text.prototype = { @@ -90,8 +90,8 @@ this._setTextData(); }, - drawFunc: function(canvas) { - var context = canvas.getContext(), + drawFunc: function(context) { + var _context = context._context, p = this.getPadding(), fontStyle = this.getFontStyle(), fontSize = this.getFontSize(), @@ -102,12 +102,12 @@ textArrLen = textArr.length, totalWidth = this.getWidth(); - context.font = this._getContextFont(); - context.textBaseline = MIDDLE; - context.textAlign = LEFT; - context.save(); - context.translate(p, 0); - context.translate(0, p + textHeight / 2); + _context.font = this._getContextFont(); + _context.textBaseline = MIDDLE; + _context.textAlign = LEFT; + _context.save(); + _context.translate(p, 0); + _context.translate(0, p + textHeight / 2); // draw text lines for(var n = 0; n < textArrLen; n++) { @@ -116,30 +116,30 @@ width = obj.width; // horizontal alignment - context.save(); + _context.save(); if(this.getAlign() === RIGHT) { - context.translate(totalWidth - width - p * 2, 0); + _context.translate(totalWidth - width - p * 2, 0); } else if(this.getAlign() === CENTER) { - context.translate((totalWidth - width - p * 2) / 2, 0); + _context.translate((totalWidth - width - p * 2) / 2, 0); } this.partialText = text; - canvas.fillStroke(this); - context.restore(); - context.translate(0, lineHeightPx); + context.fillStroke(this); + _context.restore(); + _context.translate(0, lineHeightPx); } - context.restore(); + _context.restore(); }, - drawHitFunc: function(canvas) { - var context = canvas.getContext(), + drawHitFunc: function(context) { + var _context = context._context, width = this.getWidth(), height = this.getHeight(); - context.beginPath(); - context.rect(0, 0, width, height); - context.closePath(); - canvas.fillStroke(this); + _context.beginPath(); + _context.rect(0, 0, width, height); + _context.closePath(); + context.fillStroke(this); }, /** * set text @@ -184,15 +184,15 @@ return this.textHeight; }, _getTextSize: function(text) { - var context = dummyContext, + var _context = dummyContext, fontSize = this.getFontSize(), metrics; - context.save(); - context.font = this._getContextFont(); + _context.save(); + _context.font = this._getContextFont(); - metrics = context.measureText(text); - context.restore(); + metrics = _context.measureText(text); + _context.restore(); return { width: metrics.width, height: parseInt(fontSize, 10) diff --git a/src/shapes/Wedge.js b/src/shapes/Wedge.js index 42555cf5..eb311edd 100644 --- a/src/shapes/Wedge.js +++ b/src/shapes/Wedge.js @@ -31,13 +31,14 @@ Kinetic.Shape.call(this, config); this.className = 'Wedge'; }, - drawFunc: function(canvas) { - var context = canvas.getContext(); - context.beginPath(); - context.arc(0, 0, this.getRadius(), 0, this.getAngle(), this.getClockwise()); - context.lineTo(0, 0); - context.closePath(); - canvas.fillStroke(this); + drawFunc: function(context) { + var _context = context._context; + + _context.beginPath(); + _context.arc(0, 0, this.getRadius(), 0, this.getAngle(), this.getClockwise()); + _context.lineTo(0, 0); + _context.closePath(); + context.fillStroke(this); } }; Kinetic.Util.extend(Kinetic.Wedge, Kinetic.Shape); diff --git a/tests/html/performanceTests.html b/tests/html/performanceTests.html index d743d56e..862e3b73 100644 --- a/tests/html/performanceTests.html +++ b/tests/html/performanceTests.html @@ -29,6 +29,11 @@ run(Kinetic); + + +