diff --git a/dist/kinetic-core.js b/dist/kinetic-core.js index 7878b0d9..d665efe8 100644 --- a/dist/kinetic-core.js +++ b/dist/kinetic-core.js @@ -4555,20 +4555,8 @@ Kinetic.Ellipse = Kinetic.Shape.extend({ }); this.shapeType = "Ellipse"; + config.drawFunc = this.drawFunc; - config.drawFunc = function(context) { - var r = this.getRadius(); - context.beginPath(); - context.save(); - if(r.x !== r.y) { - context.scale(1, r.y / r.x); - } - context.arc(0, 0, r.x, 0, Math.PI * 2, true); - context.restore(); - context.closePath(); - this.fill(context); - this.stroke(context); - }; // call super constructor this._super(config); @@ -4579,6 +4567,19 @@ Kinetic.Ellipse = Kinetic.Shape.extend({ that._convertRadius(); }); }, + drawFunc: function(context) { + var r = this.getRadius(); + context.beginPath(); + context.save(); + if(r.x !== r.y) { + context.scale(1, r.y / r.x); + } + context.arc(0, 0, r.x, 0, Math.PI * 2, true); + context.restore(); + context.closePath(); + this.fill(context); + this.stroke(context); + }, /** * converts numeric radius into an object */ @@ -4638,34 +4639,35 @@ Kinetic.Node.addGettersSetters(Kinetic.Ellipse, ['radius']); Kinetic.Image = Kinetic.Shape.extend({ init: function(config) { this.shapeType = "Image"; - config.drawFunc = function(context) { - if(!!this.attrs.image) { - var width = this.getWidth(); - var height = this.getHeight(); - - context.beginPath(); - context.rect(0, 0, width, height); - context.closePath(); - this.fill(context); - this.stroke(context); - - // if cropping - if(this.attrs.crop && this.attrs.crop.width && this.attrs.crop.height) { - var cropX = this.attrs.crop.x ? this.attrs.crop.x : 0; - 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(context, this.attrs.image, cropX, cropY, cropWidth, cropHeight, 0, 0, width, height); - } - // no cropping - else { - this.drawImage(context, this.attrs.image, 0, 0, width, height); - } - } - }; + config.drawFunc = this.drawFunc; // call super constructor this._super(config); }, + drawFunc: function(context) { + if(this.attrs.image) { + var width = this.getWidth(); + var height = this.getHeight(); + + context.beginPath(); + context.rect(0, 0, width, height); + context.closePath(); + this.fill(context); + this.stroke(context); + + // if cropping + if(this.attrs.crop && this.attrs.crop.width && this.attrs.crop.height) { + var cropX = this.attrs.crop.x ? this.attrs.crop.x : 0; + 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(context, this.attrs.image, cropX, cropY, cropWidth, cropHeight, 0, 0, width, height); + } + // no cropping + else { + this.drawImage(context, this.attrs.image, 0, 0, width, height); + } + } + }, /** * set width and height * @name setSize @@ -4817,18 +4819,19 @@ Kinetic.Polygon = Kinetic.Shape.extend({ }); this.shapeType = "Polygon"; - 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(context); - this.stroke(context); - }; + config.drawFunc = this.drawFunc; // call super constructor this._super(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(context); + this.stroke(context); } }); @@ -4877,69 +4880,7 @@ Kinetic.Text = Kinetic.Shape.extend({ this.dummyCanvas = document.createElement('canvas'); this.shapeType = "Text"; - config.drawFunc = function(context) { - /* - * draw rect - */ - context.beginPath(); - var boxWidth = this.getBoxWidth(); - var boxHeight = this.getBoxHeight(); - - if(this.attrs.cornerRadius === 0) { - // simple rect - don't bother doing all that complicated maths stuff. - context.rect(0, 0, boxWidth, boxHeight); - } - else { - // arcTo would be nicer, but browser support is patchy (Opera) - context.moveTo(this.attrs.cornerRadius, 0); - context.lineTo(boxWidth - this.attrs.cornerRadius, 0); - context.arc(boxWidth - this.attrs.cornerRadius, this.attrs.cornerRadius, this.attrs.cornerRadius, Math.PI * 3 / 2, 0, false); - context.lineTo(boxWidth, boxHeight - this.attrs.cornerRadius); - context.arc(boxWidth - this.attrs.cornerRadius, boxHeight - this.attrs.cornerRadius, this.attrs.cornerRadius, 0, Math.PI / 2, false); - context.lineTo(this.attrs.cornerRadius, boxHeight); - context.arc(this.attrs.cornerRadius, boxHeight - this.attrs.cornerRadius, this.attrs.cornerRadius, Math.PI / 2, Math.PI, false); - context.lineTo(0, this.attrs.cornerRadius); - context.arc(this.attrs.cornerRadius, this.attrs.cornerRadius, this.attrs.cornerRadius, Math.PI, Math.PI * 3 / 2, false); - } - context.closePath(); - - this.fill(context); - this.stroke(context); - /* - * draw text - */ - var p = this.attrs.padding; - var lineHeightPx = this.attrs.lineHeight * this.getTextHeight(); - var textArr = this.textArr; - - context.font = this.attrs.fontStyle + ' ' + this.attrs.fontSize + 'pt ' + this.attrs.fontFamily; - context.textBaseline = 'middle'; - context.textAlign = 'left'; - context.save(); - context.translate(p, 0); - context.translate(0, p + this.getTextHeight() / 2); - - // draw text lines - for(var n = 0; n < textArr.length; n++) { - var text = textArr[n]; - - // horizontal alignment - context.save(); - if(this.attrs.align === 'right') { - context.translate(this.getBoxWidth() - this._getTextSize(text).width - p * 2, 0); - } - else if(this.attrs.align === 'center') { - context.translate((this.getBoxWidth() - this._getTextSize(text).width - p * 2) / 2, 0); - } - - this.fillText(context, text); - this.strokeText(context, text); - context.restore(); - - context.translate(0, lineHeightPx); - } - context.restore(); - }; + config.drawFunc = this.drawFunc; // call super constructor this._super(config); @@ -4953,6 +4894,67 @@ Kinetic.Text = Kinetic.Shape.extend({ that._setTextData(); }, + drawFunc: function(context) { + // draw rect + context.beginPath(); + var boxWidth = this.getBoxWidth(); + var boxHeight = this.getBoxHeight(); + + if(this.attrs.cornerRadius === 0) { + // simple rect - don't bother doing all that complicated maths stuff. + context.rect(0, 0, boxWidth, boxHeight); + } + else { + // arcTo would be nicer, but browser support is patchy (Opera) + context.moveTo(this.attrs.cornerRadius, 0); + context.lineTo(boxWidth - this.attrs.cornerRadius, 0); + context.arc(boxWidth - this.attrs.cornerRadius, this.attrs.cornerRadius, this.attrs.cornerRadius, Math.PI * 3 / 2, 0, false); + context.lineTo(boxWidth, boxHeight - this.attrs.cornerRadius); + context.arc(boxWidth - this.attrs.cornerRadius, boxHeight - this.attrs.cornerRadius, this.attrs.cornerRadius, 0, Math.PI / 2, false); + context.lineTo(this.attrs.cornerRadius, boxHeight); + context.arc(this.attrs.cornerRadius, boxHeight - this.attrs.cornerRadius, this.attrs.cornerRadius, Math.PI / 2, Math.PI, false); + context.lineTo(0, this.attrs.cornerRadius); + context.arc(this.attrs.cornerRadius, this.attrs.cornerRadius, this.attrs.cornerRadius, Math.PI, Math.PI * 3 / 2, false); + } + context.closePath(); + + this.fill(context); + this.stroke(context); + /* + * draw text + */ + var p = this.attrs.padding; + var lineHeightPx = this.attrs.lineHeight * this.getTextHeight(); + var textArr = this.textArr; + + context.font = this.attrs.fontStyle + ' ' + this.attrs.fontSize + 'pt ' + this.attrs.fontFamily; + context.textBaseline = 'middle'; + context.textAlign = 'left'; + context.save(); + context.translate(p, 0); + context.translate(0, p + this.getTextHeight() / 2); + + // draw text lines + for(var n = 0; n < textArr.length; n++) { + var text = textArr[n]; + + // horizontal alignment + context.save(); + if(this.attrs.align === 'right') { + context.translate(this.getBoxWidth() - this._getTextSize(text).width - p * 2, 0); + } + else if(this.attrs.align === 'center') { + context.translate((this.getBoxWidth() - this._getTextSize(text).width - p * 2) / 2, 0); + } + + this.fillText(context, text); + this.strokeText(context, text); + context.restore(); + + context.translate(0, lineHeightPx); + } + context.restore(); + }, /** * get box width * @name getBoxWidth @@ -5255,36 +5257,37 @@ Kinetic.Line = Kinetic.Shape.extend({ }); this.shapeType = "Line"; - config.drawFunc = function(context) { - var lastPos = {}; - context.beginPath(); - - context.moveTo(this.attrs.points[0].x, this.attrs.points[0].y); - - for(var n = 1; n < this.attrs.points.length; n++) { - var x = this.attrs.points[n].x; - var y = this.attrs.points[n].y; - if(this.attrs.dashArray.length > 0) { - // draw dashed line - var lastX = this.attrs.points[n - 1].x; - var lastY = this.attrs.points[n - 1].y; - this._dashedLine(context, lastX, lastY, x, y, this.attrs.dashArray); - } - else { - // draw normal line - context.lineTo(x, y); - } - } - - if(!!this.attrs.lineCap) { - context.lineCap = this.attrs.lineCap; - } - - this.stroke(context); - }; + config.drawFunc = this.drawFunc; // call super constructor this._super(config); }, + drawFunc: function(context) { + var lastPos = {}; + context.beginPath(); + + context.moveTo(this.attrs.points[0].x, this.attrs.points[0].y); + + for(var n = 1; n < this.attrs.points.length; n++) { + var x = this.attrs.points[n].x; + var y = this.attrs.points[n].y; + if(this.attrs.dashArray.length > 0) { + // draw dashed line + var lastX = this.attrs.points[n - 1].x; + var lastY = this.attrs.points[n - 1].y; + this._dashedLine(context, lastX, lastY, x, y, this.attrs.dashArray); + } + else { + // draw normal line + context.lineTo(x, y); + } + } + + if(!!this.attrs.lineCap) { + context.lineCap = this.attrs.lineCap; + } + + this.stroke(context); + }, /** * draw dashed line. Written by Phrogz */ @@ -5397,19 +5400,7 @@ Kinetic.Sprite = Kinetic.Shape.extend({ frameRate: 17 }); - config.drawFunc = function(context) { - if(!!this.attrs.image) { - var anim = this.attrs.animation; - var index = this.attrs.index; - var f = this.attrs.animations[anim][index]; - - context.beginPath(); - context.rect(0, 0, f.width, f.height); - context.closePath(); - - this.drawImage(context, this.attrs.image, f.x, f.y, f.width, f.height, 0, 0, f.width, f.height); - } - }; + config.drawFunc = this.drawFunc; // call super constructor this._super(config); @@ -5419,6 +5410,19 @@ Kinetic.Sprite = Kinetic.Shape.extend({ that.setIndex(0); }); }, + drawFunc: function(context) { + if(this.attrs.image) { + var anim = this.attrs.animation; + var index = this.attrs.index; + var f = this.attrs.animations[anim][index]; + + context.beginPath(); + context.rect(0, 0, f.width, f.height); + context.closePath(); + + this.drawImage(context, this.attrs.image, f.x, f.y, f.width, f.height, 0, 0, f.width, f.height); + } + }, /** * start sprite animation * @name start diff --git a/dist/kinetic-core.min.js b/dist/kinetic-core.min.js index 0402b3d8..e69de29b 100644 --- a/dist/kinetic-core.min.js +++ b/dist/kinetic-core.min.js @@ -1,29 +0,0 @@ -/** - * KineticJS JavaScript Library core - * http://www.kineticjs.com/ - * Copyright 2012, Eric Rowell - * Licensed under the MIT or GPL Version 2 licenses. - * Date: Jul 28 2012 - * - * Copyright (C) 2011 - 2012 by Eric Rowell - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -var Kinetic={};Kinetic.Filters={},Kinetic.Plugins={},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;c=c.tweens.length&&c.onFinished()}}},Kinetic.Transition.prototype={start:function(){for(var a=0;a0},_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;cthis.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){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,dragThrottle:80},this.setDefaultAttrs(this.defaultNodeAttrs),this.eventListeners={},this.lastDragTime=0,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._clearTransform();this.attrs.x=b.x,this.attrs.y=b.y,delete b.x,delete b.y;var c=this.getAbsoluteTransform();c.invert(),c.translate(a.x,a.y),a={x:this.attrs.x+c.getTranslation().x,y:this.attrs.y+c.getTranslation().y},this.setPosition(a.x,a.y),this._setTransform(b)},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){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=Kinetic.Global;a||(a=window.event),this._setMousePosition(a),this._setTouchPosition(a),this.pathCanvas.clear(),this.targetFound=!1;var c=!1;for(var d=this.children.length-1;d>=0;d--){var e=this.children[d];if(e.isVisible()&&d>=0&&e.getListening()&&this._traverseChildren(e,a)){c=!0;break}}!c&&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=h||e>200){var i=b.getUserPosition(),j=d.attrs.dragConstraint,k=d.attrs.dragBounds,l={x:d.attrs.x,y:d.attrs.y},m={x:i.x-c.drag.offset.x,y:i.y-c.drag.offset.y};k.left!==undefined&&m.xk.right&&(m.x=k.right),k.top!==undefined&&m.yk.bottom&&(m.y=k.bottom),d.setAbsolutePosition(m),j==="horizontal"?d.attrs.y=l.y:j==="vertical"&&(d.attrs.x=l.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),d.lastDragTime=(new Date).getTime()}}},_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;d0&&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.Sprite=Kinetic.Shape.extend({init:function(a){this.setDefaultAttrs({index:0,frameRate:17}),a.drawFunc=function(a){if(!!this.attrs.image){var b=this.attrs.animation,c=this.attrs.index,d=this.attrs.animations[b][c];a.beginPath(),a.rect(0,0,d.width,d.height),a.closePath(),this.drawImage(a,this.attrs.image,d.x,d.y,d.width,d.height,0,0,d.width,d.height)}},this._super(a);var b=this;this.on("animationChange.kinetic",function(){b.setIndex(0)})},start:function(){var a=this,b=this.getLayer(),c=Kinetic.Animation;this.anim&&(c._removeAnimation(this.anim),this.anim=null),this.anim={node:b},c._addAnimation(this.anim),this.interval=setInterval(function(){var b=a.attrs.index;a._updateIndex(),a.afterFrameFunc&&b===a.afterFrameIndex&&a.afterFrameFunc()},1e3/this.attrs.frameRate),c._handleAnimation()},stop:function(){var a=Kinetic.Animation;this.anim&&(a._removeAnimation(this.anim),this.anim=null),clearInterval(this.interval)},afterFrame:function(a,b){this.afterFrameIndex=a,this.afterFrameFunc=b},_updateIndex:function(){var a=this.attrs.index,b=this.attrs.animation;a ry) ? rx : ry; - 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); - - break; - case 'z': - context.closePath(); - break; - } - } - this.fill(context); - this.stroke(context); - }; - - // call super constructor - this._super(config); - - this.dataArray = Kinetic.Plugins.PathHelper.parsePathData(this.attrs.data); - - this.on('dataChange', function () { - that.dataArray = Kinetic.Plugins.PathHelper.parsePathData(that.attrs.data); - }); + init: function(config) { + this.shapeType = "Path"; + this.dataArray = []; + var that = this; + + config.drawFunc = this.drawFunc; + + // call super constructor + this._super(config); + + this.dataArray = Kinetic.Plugins.PathHelper.parsePathData(this.attrs.data); + + this.on('dataChange', function() { + that.dataArray = Kinetic.Plugins.PathHelper.parsePathData(that.attrs.data); + }); + }, + drawFunc: function(context) { + var ca = this.dataArray; + // context position + 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]); + break; + case 'M': + context.moveTo(p[0], p[1]); + break; + case 'C': + 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]); + 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]; + + var r = (rx > ry) ? rx : ry; + 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); + + break; + case 'z': + context.closePath(); + break; + } } - }); + this.fill(context); + this.stroke(context); + } +}); // add getters setters Kinetic.Node.addGettersSetters(Kinetic.Plugins.Path, ['data']); @@ -94,4 +88,4 @@ Kinetic.Node.addGettersSetters(Kinetic.Plugins.Path, ['data']); * get SVG path data string * @name getData * @methodOf Kinetic.Plugins.Path.prototype -*/ + */ \ No newline at end of file diff --git a/src/plugins/shapes/RegularPolygon.js b/src/plugins/shapes/RegularPolygon.js index 4e4fcc9b..0a73b935 100644 --- a/src/plugins/shapes/RegularPolygon.js +++ b/src/plugins/shapes/RegularPolygon.js @@ -15,21 +15,22 @@ Kinetic.Plugins.RegularPolygon = Kinetic.Shape.extend({ }); this.shapeType = "RegularPolygon"; - config.drawFunc = function(context) { - context.beginPath(); - context.moveTo(0, 0 - this.attrs.radius); - - for(var n = 1; n < this.attrs.sides; n++) { - var x = this.attrs.radius * Math.sin(n * 2 * Math.PI / this.attrs.sides); - var y = -1 * this.attrs.radius * Math.cos(n * 2 * Math.PI / this.attrs.sides); - context.lineTo(x, y); - } - context.closePath(); - this.fill(context); - this.stroke(context); - }; + config.drawFunc = this.drawFunc; // call super constructor this._super(config); + }, + drawFunc: function(context) { + context.beginPath(); + context.moveTo(0, 0 - this.attrs.radius); + + for(var n = 1; n < this.attrs.sides; n++) { + var x = this.attrs.radius * Math.sin(n * 2 * Math.PI / this.attrs.sides); + var y = -1 * this.attrs.radius * Math.cos(n * 2 * Math.PI / this.attrs.sides); + context.lineTo(x, y); + } + context.closePath(); + this.fill(context); + this.stroke(context); } }); diff --git a/src/plugins/shapes/Star.js b/src/plugins/shapes/Star.js index b1858e98..9c3acd0a 100644 --- a/src/plugins/shapes/Star.js +++ b/src/plugins/shapes/Star.js @@ -16,23 +16,24 @@ Kinetic.Plugins.Star = Kinetic.Shape.extend({ }); this.shapeType = "Star"; - config.drawFunc = function(context) { - context.beginPath(); - context.moveTo(0, 0 - this.attrs.outerRadius); - - for(var n = 1; n < this.attrs.numPoints * 2; n++) { - var radius = n % 2 === 0 ? this.attrs.outerRadius : this.attrs.innerRadius; - var x = radius * Math.sin(n * Math.PI / this.attrs.numPoints); - var y = -1 * radius * Math.cos(n * Math.PI / this.attrs.numPoints); - context.lineTo(x, y); - } - context.closePath(); - - this.fill(context); - this.stroke(context); - }; + config.drawFunc = this.drawFunc; // call super constructor this._super(config); + }, + drawFunc: function(context) { + context.beginPath(); + context.moveTo(0, 0 - this.attrs.outerRadius); + + for(var n = 1; n < this.attrs.numPoints * 2; n++) { + var radius = n % 2 === 0 ? this.attrs.outerRadius : this.attrs.innerRadius; + var x = radius * Math.sin(n * Math.PI / this.attrs.numPoints); + var y = -1 * radius * Math.cos(n * Math.PI / this.attrs.numPoints); + context.lineTo(x, y); + } + context.closePath(); + + this.fill(context); + this.stroke(context); } }); diff --git a/src/plugins/shapes/TextPath.js b/src/plugins/shapes/TextPath.js index 7812c66e..01b32636 100644 --- a/src/plugins/shapes/TextPath.js +++ b/src/plugins/shapes/TextPath.js @@ -9,285 +9,282 @@ * @param {Object} config */ Kinetic.Plugins.TextPath = Kinetic.Shape.extend({ - init : function (config) { - - this.setDefaultAttrs({ - fontFamily : 'Calibri', - fontSize : 12, - fontStyle : 'normal', - detectionType : 'path', - text : '' - }); - - this.dummyCanvas = document.createElement('canvas'); - this.shapeType = "TextPath"; - this.dataArray = []; - var that = this; - - config.drawFunc = function (context) { - var charArr = this.charArr; - - context.font = this.attrs.fontStyle + ' ' + this.attrs.fontSize + 'pt ' + this.attrs.fontFamily; - context.textBaseline = 'middle'; - context.textAlign = 'left'; - context.save(); - - var glyphInfo = this.glyphInfo; - - for (var i = 0; i < glyphInfo.length; i++) { - 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); - - this.fillText(context, glyphInfo[i].text); - this.strokeText(context, glyphInfo[i].text); - - context.restore(); - - //// To assist with debugging visually, uncomment following - // context.beginPath(); - // if (i % 2) - // context.strokeStyle = 'cyan'; - // else - // context.strokeStyle = 'green'; - - // context.moveTo(p0.x, p0.y); - // context.lineTo(p1.x, p1.y); - // context.stroke(); - } - - context.restore(); - }; - - // call super constructor - this._super(config); - - this.dataArray = Kinetic.Plugins.PathHelper.parsePathData(this.attrs.data); - - this.on('dataChange', function () { - that.dataArray = Kinetic.Plugins.PathHelper.parsePathData(that.attrs.data); - }); - - // update text data for certain attr changes - var attrs = ['text', 'textStroke', 'textStrokeWidth']; - for (var n = 0; n < attrs.length; n++) { - var attr = attrs[n]; - this.on(attr + 'Change', that._setTextData); - } - - that._setTextData(); - }, - /** - * get text width in pixels - * @name getTextWidth - * @methodOf Kinetic.Plugins.TextPath.prototype - */ - getTextWidth : function () { - return this.textWidth; - }, - /** - * get text height in pixels - * @name getTextHeight - * @methodOf Kinetic.Plugins.TextPath.prototype - */ - getTextHeight : function () { - return this.textHeight; - }, - _getTextSize : function (text) { - var dummyCanvas = this.dummyCanvas; - var context = dummyCanvas.getContext('2d'); - + init: function(config) { + + this.setDefaultAttrs({ + fontFamily: 'Calibri', + fontSize: 12, + fontStyle: 'normal', + detectionType: 'path', + text: '' + }); + + this.dummyCanvas = document.createElement('canvas'); + this.shapeType = "TextPath"; + this.dataArray = []; + var that = this; + + config.drawFunc = this.drawFunc; + + // call super constructor + this._super(config); + + this.dataArray = Kinetic.Plugins.PathHelper.parsePathData(this.attrs.data); + + this.on('dataChange', function() { + that.dataArray = Kinetic.Plugins.PathHelper.parsePathData(that.attrs.data); + }); + // update text data for certain attr changes + var attrs = ['text', 'textStroke', 'textStrokeWidth']; + for(var n = 0; n < attrs.length; n++) { + var attr = attrs[n]; + this.on(attr + 'Change', that._setTextData); + } + + that._setTextData(); + }, + drawFunc: function(context) { + var charArr = this.charArr; + + context.font = this.attrs.fontStyle + ' ' + this.attrs.fontSize + 'pt ' + this.attrs.fontFamily; + context.textBaseline = 'middle'; + context.textAlign = 'left'; + context.save(); + + var glyphInfo = this.glyphInfo; + + for(var i = 0; i < glyphInfo.length; i++) { context.save(); - - context.font = this.attrs.fontStyle + ' ' + this.attrs.fontSize + 'pt ' + this.attrs.fontFamily; - var metrics = context.measureText(text); - + + 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); + + this.fillText(context, glyphInfo[i].text); + this.strokeText(context, glyphInfo[i].text); + context.restore(); - - return { - width : metrics.width, - height : parseInt(this.attrs.fontSize, 10) - }; - }, - /** - * set text data. - */ - _setTextData : function () { - - var that = this; - var size = this._getTextSize(this.attrs.text); - this.textWidth = size.width; - this.textHeight = size.height; - - this.glyphInfo = []; - - var charArr = this.attrs.text.split(''); - - var p0, - p1, - pathCmd; - - var pIndex = -1; - var currentT = 0; - - var getNextPathSegment = function () { - currentT = 0; - var pathData = that.dataArray; - - for (var i = pIndex + 1; i < pathData.length; i++) { - if (pathData[i].pathLength > 0) { - pIndex = i; - - return pathData[i]; - } else if (pathData[i].command == 'M') { - p0 = { - x : pathData[i].points[0], - y : pathData[i].points[1] - }; - } + + //// To assist with debugging visually, uncomment following + // context.beginPath(); + // if (i % 2) + // context.strokeStyle = 'cyan'; + // else + // context.strokeStyle = 'green'; + + // context.moveTo(p0.x, p0.y); + // context.lineTo(p1.x, p1.y); + // context.stroke(); + } + + context.restore(); + }, + /** + * get text width in pixels + * @name getTextWidth + * @methodOf Kinetic.Plugins.TextPath.prototype + */ + getTextWidth: function() { + return this.textWidth; + }, + /** + * get text height in pixels + * @name getTextHeight + * @methodOf Kinetic.Plugins.TextPath.prototype + */ + getTextHeight: function() { + return this.textHeight; + }, + _getTextSize: function(text) { + var dummyCanvas = this.dummyCanvas; + var context = dummyCanvas.getContext('2d'); + + context.save(); + + context.font = this.attrs.fontStyle + ' ' + this.attrs.fontSize + 'pt ' + this.attrs.fontFamily; + var metrics = context.measureText(text); + + context.restore(); + + return { + width: metrics.width, + height: parseInt(this.attrs.fontSize, 10) + }; + }, + /** + * set text data. + */ + _setTextData: function() { + + var that = this; + var size = this._getTextSize(this.attrs.text); + this.textWidth = size.width; + this.textHeight = size.height; + + this.glyphInfo = []; + + var charArr = this.attrs.text.split(''); + + var p0, p1, pathCmd; + + var pIndex = -1; + var currentT = 0; + + var getNextPathSegment = function() { + currentT = 0; + var pathData = that.dataArray; + + for(var i = pIndex + 1; i < pathData.length; i++) { + if(pathData[i].pathLength > 0) { + pIndex = i; + + return pathData[i]; } - - return {}; - }; - - var findSegmentToFitCharacter = function (c, before) { - - var glyphWidth = that._getTextSize(c).width; - - var currLen = 0; - var attempts = 0; - var needNextSegment = false; - - p1 = undefined; - while (Math.abs(glyphWidth - currLen) / glyphWidth > 0.01 && attempts < 25) { - attempts++; - var cumulativePathLength = currLen; - while (pathCmd === undefined) { - pathCmd = getNextPathSegment(); - - if (pathCmd && cumulativePathLength + pathCmd.pathLength < glyphWidth) { - cumulativePathLength += pathCmd.pathLength; - pathCmd = undefined; - } - } - - if (pathCmd === {} || p0 === undefined) - return undefined; - - var needNewSegment = false; - - switch (pathCmd.command) { - case 'L': - if (Kinetic.Plugins.PathHelper.getLineLength(p0.x, p0.y, pathCmd.points[0], pathCmd.points[1]) > glyphWidth) { - p1 = Kinetic.Plugins.PathHelper.getPointOnLine(glyphWidth, p0.x, p0.y, pathCmd.points[0], pathCmd.points[1], p0.x, p0.y); - } else - pathCmd = undefined; - break; - case 'A': - - var start = pathCmd.points[4]; // 4 = theta - var dTheta = pathCmd.points[5]; // 5 = dTheta - var end = pathCmd.points[4] + dTheta; - - if (currentT === 0) - currentT = start + 0.00000001; // Just in case start is 0 - else if (glyphWidth > currLen) - currentT += (Math.PI / 180.0) * dTheta / Math.abs(dTheta); - else - currentT -= Math.PI / 360.0 * dTheta / Math.abs(dTheta); - - if (Math.abs(currentT) > Math.abs(end)) { - - currentT = end; - needNewSegment = true; - } - - p1 = Kinetic.Plugins.PathHelper.getPointOnEllipticalArc(pathCmd.points[0], pathCmd.points[1], pathCmd.points[2], pathCmd.points[3], currentT, pathCmd.points[6]); - break; - case 'C': - if (currentT === 0) { - if (glyphWidth > pathCmd.pathLength) - currentT = 0.00000001; - else - currentT = glyphWidth / pathCmd.pathLength; - } else if (glyphWidth > currLen) - currentT += (glyphWidth - currLen) / pathCmd.pathLength; - else - currentT -= (currLen - glyphWidth) / pathCmd.pathLength; - - if (currentT > 1.0) { - currentT = 1.0; - needNewSegment = true; - } - - p1 = Kinetic.Plugins.PathHelper.getPointOnCubicBezier(currentT, pathCmd.start.x, pathCmd.start.y, pathCmd.points[0], pathCmd.points[1], pathCmd.points[2], pathCmd.points[3], pathCmd.points[4], pathCmd.points[5]); - break; - case 'Q': - if (currentT === 0) - currentT = glyphWidth / pathCmd.pathLength; - else if (glyphWidth > currLen) - currentT += (glyphWidth - currLen) / pathCmd.pathLength; - else - currentT -= (currLen - glyphWidth) / pathCmd.pathLength; - - if (currentT > 1.0) { - currentT = 1.0; - needNewSegment = true; - } - - p1 = Kinetic.Plugins.PathHelper.getPointOnQuadraticBezier(currentT, pathCmd.start.x, pathCmd.start.y, pathCmd.points[0], pathCmd.points[1], pathCmd.points[2], pathCmd.points[3]); - break; - - } - - if (p1 !== undefined) { - currLen = Kinetic.Plugins.PathHelper.getLineLength(p0.x, p0.y, p1.x, p1.y); - } - - if (needNewSegment) { - needNewSegment = false; + else if(pathData[i].command == 'M') { + p0 = { + x: pathData[i].points[0], + y: pathData[i].points[1] + }; + } + } + + return {}; + }; + var findSegmentToFitCharacter = function(c, before) { + + var glyphWidth = that._getTextSize(c).width; + + var currLen = 0; + var attempts = 0; + var needNextSegment = false; + p1 = undefined; + while(Math.abs(glyphWidth - currLen) / glyphWidth > 0.01 && attempts < 25) { + attempts++; + var cumulativePathLength = currLen; + while(pathCmd === undefined) { + pathCmd = getNextPathSegment(); + + if(pathCmd && cumulativePathLength + pathCmd.pathLength < glyphWidth) { + cumulativePathLength += pathCmd.pathLength; pathCmd = undefined; } } - }; - - for (var i = 0; i < charArr.length; i++) { - - // Find p1 such that line segment between p0 and p1 is approx. width of glyph - findSegmentToFitCharacter(charArr[i]); - - if (p0 === undefined || p1 === undefined) - break; - - var width = Kinetic.Plugins.PathHelper.getLineLength(p0.x, p0.y, p1.x, p1.y); - - // Note: Since glyphs are rendered one at a time, any kerning pair data built into the font will not be used. - // Can foresee having a rough pair table built in that the developer can override as needed. - - var kern = 0; // placeholder for future implementation - - var midpoint = Kinetic.Plugins.PathHelper.getPointOnLine(kern + width / 2.0, p0.x, p0.y, p1.x, p1.y); - - var rotation = Math.atan2((p1.y - p0.y), (p1.x - p0.x)); - this.glyphInfo.push({ - transposeX : midpoint.x, - transposeY : midpoint.y, - text : charArr[i], - rotation : rotation, - p0 : p0, - p1 : p1 - }); - - p0 = p1; + + if(pathCmd === {} || p0 === undefined) + return undefined; + + var needNewSegment = false; + + switch (pathCmd.command) { + case 'L': + if(Kinetic.Plugins.PathHelper.getLineLength(p0.x, p0.y, pathCmd.points[0], pathCmd.points[1]) > glyphWidth) { + p1 = Kinetic.Plugins.PathHelper.getPointOnLine(glyphWidth, p0.x, p0.y, pathCmd.points[0], pathCmd.points[1], p0.x, p0.y); + } + else + pathCmd = undefined; + break; + case 'A': + + var start = pathCmd.points[4]; + // 4 = theta + var dTheta = pathCmd.points[5]; + // 5 = dTheta + var end = pathCmd.points[4] + dTheta; + + if(currentT === 0) + currentT = start + 0.00000001; + // Just in case start is 0 + else if(glyphWidth > currLen) + currentT += (Math.PI / 180.0) * dTheta / Math.abs(dTheta); + else + currentT -= Math.PI / 360.0 * dTheta / Math.abs(dTheta); + + if(Math.abs(currentT) > Math.abs(end)) { + currentT = end; + needNewSegment = true; + } + p1 = Kinetic.Plugins.PathHelper.getPointOnEllipticalArc(pathCmd.points[0], pathCmd.points[1], pathCmd.points[2], pathCmd.points[3], currentT, pathCmd.points[6]); + break; + case 'C': + if(currentT === 0) { + if(glyphWidth > pathCmd.pathLength) + currentT = 0.00000001; + else + currentT = glyphWidth / pathCmd.pathLength; + } + else if(glyphWidth > currLen) + currentT += (glyphWidth - currLen) / pathCmd.pathLength; + else + currentT -= (currLen - glyphWidth) / pathCmd.pathLength; + + if(currentT > 1.0) { + currentT = 1.0; + needNewSegment = true; + } + p1 = Kinetic.Plugins.PathHelper.getPointOnCubicBezier(currentT, pathCmd.start.x, pathCmd.start.y, pathCmd.points[0], pathCmd.points[1], pathCmd.points[2], pathCmd.points[3], pathCmd.points[4], pathCmd.points[5]); + break; + case 'Q': + if(currentT === 0) + currentT = glyphWidth / pathCmd.pathLength; + else if(glyphWidth > currLen) + currentT += (glyphWidth - currLen) / pathCmd.pathLength; + else + currentT -= (currLen - glyphWidth) / pathCmd.pathLength; + + if(currentT > 1.0) { + currentT = 1.0; + needNewSegment = true; + } + p1 = Kinetic.Plugins.PathHelper.getPointOnQuadraticBezier(currentT, pathCmd.start.x, pathCmd.start.y, pathCmd.points[0], pathCmd.points[1], pathCmd.points[2], pathCmd.points[3]); + break; + + } + + if(p1 !== undefined) { + currLen = Kinetic.Plugins.PathHelper.getLineLength(p0.x, p0.y, p1.x, p1.y); + } + + if(needNewSegment) { + needNewSegment = false; + pathCmd = undefined; + } } + }; + for(var i = 0; i < charArr.length; i++) { + + // Find p1 such that line segment between p0 and p1 is approx. width of glyph + findSegmentToFitCharacter(charArr[i]); + + if(p0 === undefined || p1 === undefined) + break; + + var width = Kinetic.Plugins.PathHelper.getLineLength(p0.x, p0.y, p1.x, p1.y); + + // Note: Since glyphs are rendered one at a time, any kerning pair data built into the font will not be used. + // Can foresee having a rough pair table built in that the developer can override as needed. + + var kern = 0; + // placeholder for future implementation + + var midpoint = Kinetic.Plugins.PathHelper.getPointOnLine(kern + width / 2.0, p0.x, p0.y, p1.x, p1.y); + + var rotation = Math.atan2((p1.y - p0.y), (p1.x - p0.x)); + this.glyphInfo.push({ + transposeX: midpoint.x, + transposeY: midpoint.y, + text: charArr[i], + rotation: rotation, + p0: p0, + p1: p1 + }); + p0 = p1; } - }); + } +}); // add setters and getters Kinetic.Node.addGettersSetters(Kinetic.Plugins.TextPath, ['fontFamily', 'fontSize', 'fontStyle', 'textFill', 'textStroke', 'textStrokeWidth', 'text']); @@ -381,4 +378,4 @@ Kinetic.Node.addGettersSetters(Kinetic.Plugins.TextPath, ['fontFamily', 'fontSiz * get text * @name getText * @methodOf Kinetic.Plugins.TextPath.prototype - */ + */ \ No newline at end of file diff --git a/src/shapes/Ellipse.js b/src/shapes/Ellipse.js index 9dd1f02e..93c7b285 100644 --- a/src/shapes/Ellipse.js +++ b/src/shapes/Ellipse.js @@ -17,20 +17,8 @@ Kinetic.Ellipse = Kinetic.Shape.extend({ }); this.shapeType = "Ellipse"; + config.drawFunc = this.drawFunc; - config.drawFunc = function(context) { - var r = this.getRadius(); - context.beginPath(); - context.save(); - if(r.x !== r.y) { - context.scale(1, r.y / r.x); - } - context.arc(0, 0, r.x, 0, Math.PI * 2, true); - context.restore(); - context.closePath(); - this.fill(context); - this.stroke(context); - }; // call super constructor this._super(config); @@ -41,6 +29,19 @@ Kinetic.Ellipse = Kinetic.Shape.extend({ that._convertRadius(); }); }, + drawFunc: function(context) { + var r = this.getRadius(); + context.beginPath(); + context.save(); + if(r.x !== r.y) { + context.scale(1, r.y / r.x); + } + context.arc(0, 0, r.x, 0, Math.PI * 2, true); + context.restore(); + context.closePath(); + this.fill(context); + this.stroke(context); + }, /** * converts numeric radius into an object */ diff --git a/src/shapes/Image.js b/src/shapes/Image.js index 359ea49a..1453b8a6 100644 --- a/src/shapes/Image.js +++ b/src/shapes/Image.js @@ -14,34 +14,35 @@ Kinetic.Image = Kinetic.Shape.extend({ init: function(config) { this.shapeType = "Image"; - config.drawFunc = function(context) { - if(!!this.attrs.image) { - var width = this.getWidth(); - var height = this.getHeight(); - - context.beginPath(); - context.rect(0, 0, width, height); - context.closePath(); - this.fill(context); - this.stroke(context); - - // if cropping - if(this.attrs.crop && this.attrs.crop.width && this.attrs.crop.height) { - var cropX = this.attrs.crop.x ? this.attrs.crop.x : 0; - 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(context, this.attrs.image, cropX, cropY, cropWidth, cropHeight, 0, 0, width, height); - } - // no cropping - else { - this.drawImage(context, this.attrs.image, 0, 0, width, height); - } - } - }; + config.drawFunc = this.drawFunc; // call super constructor this._super(config); }, + drawFunc: function(context) { + if(this.attrs.image) { + var width = this.getWidth(); + var height = this.getHeight(); + + context.beginPath(); + context.rect(0, 0, width, height); + context.closePath(); + this.fill(context); + this.stroke(context); + + // if cropping + if(this.attrs.crop && this.attrs.crop.width && this.attrs.crop.height) { + var cropX = this.attrs.crop.x ? this.attrs.crop.x : 0; + 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(context, this.attrs.image, cropX, cropY, cropWidth, cropHeight, 0, 0, width, height); + } + // no cropping + else { + this.drawImage(context, this.attrs.image, 0, 0, width, height); + } + } + }, /** * set width and height * @name setSize diff --git a/src/shapes/Line.js b/src/shapes/Line.js index ccea9171..2043dfce 100644 --- a/src/shapes/Line.js +++ b/src/shapes/Line.js @@ -17,36 +17,37 @@ Kinetic.Line = Kinetic.Shape.extend({ }); this.shapeType = "Line"; - config.drawFunc = function(context) { - var lastPos = {}; - context.beginPath(); - - context.moveTo(this.attrs.points[0].x, this.attrs.points[0].y); - - for(var n = 1; n < this.attrs.points.length; n++) { - var x = this.attrs.points[n].x; - var y = this.attrs.points[n].y; - if(this.attrs.dashArray.length > 0) { - // draw dashed line - var lastX = this.attrs.points[n - 1].x; - var lastY = this.attrs.points[n - 1].y; - this._dashedLine(context, lastX, lastY, x, y, this.attrs.dashArray); - } - else { - // draw normal line - context.lineTo(x, y); - } - } - - if(!!this.attrs.lineCap) { - context.lineCap = this.attrs.lineCap; - } - - this.stroke(context); - }; + config.drawFunc = this.drawFunc; // call super constructor this._super(config); }, + drawFunc: function(context) { + var lastPos = {}; + context.beginPath(); + + context.moveTo(this.attrs.points[0].x, this.attrs.points[0].y); + + for(var n = 1; n < this.attrs.points.length; n++) { + var x = this.attrs.points[n].x; + var y = this.attrs.points[n].y; + if(this.attrs.dashArray.length > 0) { + // draw dashed line + var lastX = this.attrs.points[n - 1].x; + var lastY = this.attrs.points[n - 1].y; + this._dashedLine(context, lastX, lastY, x, y, this.attrs.dashArray); + } + else { + // draw normal line + context.lineTo(x, y); + } + } + + if(!!this.attrs.lineCap) { + context.lineCap = this.attrs.lineCap; + } + + this.stroke(context); + }, /** * draw dashed line. Written by Phrogz */ diff --git a/src/shapes/Polygon.js b/src/shapes/Polygon.js index 2de679e1..f45c1db0 100644 --- a/src/shapes/Polygon.js +++ b/src/shapes/Polygon.js @@ -14,18 +14,19 @@ Kinetic.Polygon = Kinetic.Shape.extend({ }); this.shapeType = "Polygon"; - 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(context); - this.stroke(context); - }; + config.drawFunc = this.drawFunc; // call super constructor this._super(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(context); + this.stroke(context); } }); diff --git a/src/shapes/Sprite.js b/src/shapes/Sprite.js index e52c588b..9d2494da 100644 --- a/src/shapes/Sprite.js +++ b/src/shapes/Sprite.js @@ -14,19 +14,7 @@ Kinetic.Sprite = Kinetic.Shape.extend({ frameRate: 17 }); - config.drawFunc = function(context) { - if(!!this.attrs.image) { - var anim = this.attrs.animation; - var index = this.attrs.index; - var f = this.attrs.animations[anim][index]; - - context.beginPath(); - context.rect(0, 0, f.width, f.height); - context.closePath(); - - this.drawImage(context, this.attrs.image, f.x, f.y, f.width, f.height, 0, 0, f.width, f.height); - } - }; + config.drawFunc = this.drawFunc; // call super constructor this._super(config); @@ -36,6 +24,19 @@ Kinetic.Sprite = Kinetic.Shape.extend({ that.setIndex(0); }); }, + drawFunc: function(context) { + if(this.attrs.image) { + var anim = this.attrs.animation; + var index = this.attrs.index; + var f = this.attrs.animations[anim][index]; + + context.beginPath(); + context.rect(0, 0, f.width, f.height); + context.closePath(); + + this.drawImage(context, this.attrs.image, f.x, f.y, f.width, f.height, 0, 0, f.width, f.height); + } + }, /** * start sprite animation * @name start diff --git a/src/shapes/Text.js b/src/shapes/Text.js index addda99e..b6f7a723 100644 --- a/src/shapes/Text.js +++ b/src/shapes/Text.js @@ -27,69 +27,7 @@ Kinetic.Text = Kinetic.Shape.extend({ this.dummyCanvas = document.createElement('canvas'); this.shapeType = "Text"; - config.drawFunc = function(context) { - /* - * draw rect - */ - context.beginPath(); - var boxWidth = this.getBoxWidth(); - var boxHeight = this.getBoxHeight(); - - if(this.attrs.cornerRadius === 0) { - // simple rect - don't bother doing all that complicated maths stuff. - context.rect(0, 0, boxWidth, boxHeight); - } - else { - // arcTo would be nicer, but browser support is patchy (Opera) - context.moveTo(this.attrs.cornerRadius, 0); - context.lineTo(boxWidth - this.attrs.cornerRadius, 0); - context.arc(boxWidth - this.attrs.cornerRadius, this.attrs.cornerRadius, this.attrs.cornerRadius, Math.PI * 3 / 2, 0, false); - context.lineTo(boxWidth, boxHeight - this.attrs.cornerRadius); - context.arc(boxWidth - this.attrs.cornerRadius, boxHeight - this.attrs.cornerRadius, this.attrs.cornerRadius, 0, Math.PI / 2, false); - context.lineTo(this.attrs.cornerRadius, boxHeight); - context.arc(this.attrs.cornerRadius, boxHeight - this.attrs.cornerRadius, this.attrs.cornerRadius, Math.PI / 2, Math.PI, false); - context.lineTo(0, this.attrs.cornerRadius); - context.arc(this.attrs.cornerRadius, this.attrs.cornerRadius, this.attrs.cornerRadius, Math.PI, Math.PI * 3 / 2, false); - } - context.closePath(); - - this.fill(context); - this.stroke(context); - /* - * draw text - */ - var p = this.attrs.padding; - var lineHeightPx = this.attrs.lineHeight * this.getTextHeight(); - var textArr = this.textArr; - - context.font = this.attrs.fontStyle + ' ' + this.attrs.fontSize + 'pt ' + this.attrs.fontFamily; - context.textBaseline = 'middle'; - context.textAlign = 'left'; - context.save(); - context.translate(p, 0); - context.translate(0, p + this.getTextHeight() / 2); - - // draw text lines - for(var n = 0; n < textArr.length; n++) { - var text = textArr[n]; - - // horizontal alignment - context.save(); - if(this.attrs.align === 'right') { - context.translate(this.getBoxWidth() - this._getTextSize(text).width - p * 2, 0); - } - else if(this.attrs.align === 'center') { - context.translate((this.getBoxWidth() - this._getTextSize(text).width - p * 2) / 2, 0); - } - - this.fillText(context, text); - this.strokeText(context, text); - context.restore(); - - context.translate(0, lineHeightPx); - } - context.restore(); - }; + config.drawFunc = this.drawFunc; // call super constructor this._super(config); @@ -103,6 +41,67 @@ Kinetic.Text = Kinetic.Shape.extend({ that._setTextData(); }, + drawFunc: function(context) { + // draw rect + context.beginPath(); + var boxWidth = this.getBoxWidth(); + var boxHeight = this.getBoxHeight(); + + if(this.attrs.cornerRadius === 0) { + // simple rect - don't bother doing all that complicated maths stuff. + context.rect(0, 0, boxWidth, boxHeight); + } + else { + // arcTo would be nicer, but browser support is patchy (Opera) + context.moveTo(this.attrs.cornerRadius, 0); + context.lineTo(boxWidth - this.attrs.cornerRadius, 0); + context.arc(boxWidth - this.attrs.cornerRadius, this.attrs.cornerRadius, this.attrs.cornerRadius, Math.PI * 3 / 2, 0, false); + context.lineTo(boxWidth, boxHeight - this.attrs.cornerRadius); + context.arc(boxWidth - this.attrs.cornerRadius, boxHeight - this.attrs.cornerRadius, this.attrs.cornerRadius, 0, Math.PI / 2, false); + context.lineTo(this.attrs.cornerRadius, boxHeight); + context.arc(this.attrs.cornerRadius, boxHeight - this.attrs.cornerRadius, this.attrs.cornerRadius, Math.PI / 2, Math.PI, false); + context.lineTo(0, this.attrs.cornerRadius); + context.arc(this.attrs.cornerRadius, this.attrs.cornerRadius, this.attrs.cornerRadius, Math.PI, Math.PI * 3 / 2, false); + } + context.closePath(); + + this.fill(context); + this.stroke(context); + /* + * draw text + */ + var p = this.attrs.padding; + var lineHeightPx = this.attrs.lineHeight * this.getTextHeight(); + var textArr = this.textArr; + + context.font = this.attrs.fontStyle + ' ' + this.attrs.fontSize + 'pt ' + this.attrs.fontFamily; + context.textBaseline = 'middle'; + context.textAlign = 'left'; + context.save(); + context.translate(p, 0); + context.translate(0, p + this.getTextHeight() / 2); + + // draw text lines + for(var n = 0; n < textArr.length; n++) { + var text = textArr[n]; + + // horizontal alignment + context.save(); + if(this.attrs.align === 'right') { + context.translate(this.getBoxWidth() - this._getTextSize(text).width - p * 2, 0); + } + else if(this.attrs.align === 'center') { + context.translate((this.getBoxWidth() - this._getTextSize(text).width - p * 2) / 2, 0); + } + + this.fillText(context, text); + this.strokeText(context, text); + context.restore(); + + context.translate(0, lineHeightPx); + } + context.restore(); + }, /** * get box width * @name getBoxWidth