moved drawFunc definition out of the shape initializers as a method to improve space performance

This commit is contained in:
Eric Rowell
2012-07-28 10:46:16 -07:00
parent a67c1e70b1
commit c4a359cd48
12 changed files with 670 additions and 698 deletions

306
dist/kinetic-core.js vendored
View File

@@ -4555,20 +4555,8 @@ Kinetic.Ellipse = Kinetic.Shape.extend({
}); });
this.shapeType = "Ellipse"; 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 // call super constructor
this._super(config); this._super(config);
@@ -4579,6 +4567,19 @@ Kinetic.Ellipse = Kinetic.Shape.extend({
that._convertRadius(); 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 * converts numeric radius into an object
*/ */
@@ -4638,34 +4639,35 @@ Kinetic.Node.addGettersSetters(Kinetic.Ellipse, ['radius']);
Kinetic.Image = Kinetic.Shape.extend({ Kinetic.Image = Kinetic.Shape.extend({
init: function(config) { init: function(config) {
this.shapeType = "Image"; this.shapeType = "Image";
config.drawFunc = function(context) { config.drawFunc = this.drawFunc;
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);
}
}
};
// call super constructor // call super constructor
this._super(config); 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 * set width and height
* @name setSize * @name setSize
@@ -4817,18 +4819,19 @@ Kinetic.Polygon = Kinetic.Shape.extend({
}); });
this.shapeType = "Polygon"; this.shapeType = "Polygon";
config.drawFunc = function(context) { config.drawFunc = this.drawFunc;
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);
};
// call super constructor // call super constructor
this._super(config); 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.dummyCanvas = document.createElement('canvas');
this.shapeType = "Text"; this.shapeType = "Text";
config.drawFunc = function(context) { config.drawFunc = this.drawFunc;
/*
* 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();
};
// call super constructor // call super constructor
this._super(config); this._super(config);
@@ -4953,6 +4894,67 @@ Kinetic.Text = Kinetic.Shape.extend({
that._setTextData(); 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 * get box width
* @name getBoxWidth * @name getBoxWidth
@@ -5255,36 +5257,37 @@ Kinetic.Line = Kinetic.Shape.extend({
}); });
this.shapeType = "Line"; this.shapeType = "Line";
config.drawFunc = function(context) { config.drawFunc = this.drawFunc;
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);
};
// call super constructor // call super constructor
this._super(config); 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 * draw dashed line. Written by Phrogz
*/ */
@@ -5397,19 +5400,7 @@ Kinetic.Sprite = Kinetic.Shape.extend({
frameRate: 17 frameRate: 17
}); });
config.drawFunc = function(context) { config.drawFunc = this.drawFunc;
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);
}
};
// call super constructor // call super constructor
this._super(config); this._super(config);
@@ -5419,6 +5410,19 @@ Kinetic.Sprite = Kinetic.Shape.extend({
that.setIndex(0); 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 * start sprite animation
* @name start * @name start

File diff suppressed because one or more lines are too long

View File

@@ -9,73 +9,67 @@
* @param {Object} config * @param {Object} config
*/ */
Kinetic.Plugins.Path = Kinetic.Shape.extend({ Kinetic.Plugins.Path = Kinetic.Shape.extend({
init : function (config) { init: function(config) {
this.shapeType = "Path"; this.shapeType = "Path";
this.dataArray = []; this.dataArray = [];
var that = this; var that = this;
config.drawFunc = function (context) { config.drawFunc = this.drawFunc;
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; // call super constructor
var scaleX = (rx > ry) ? 1 : rx / ry; this._super(config);
var scaleY = (rx > ry) ? ry / rx : 1;
context.translate(cx, cy); this.dataArray = Kinetic.Plugins.PathHelper.parsePathData(this.attrs.data);
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; this.on('dataChange', function() {
case 'z': that.dataArray = Kinetic.Plugins.PathHelper.parsePathData(that.attrs.data);
context.closePath(); });
break; },
} drawFunc: function(context) {
} var ca = this.dataArray;
this.fill(context); // context position
this.stroke(context); 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];
// call super constructor var r = (rx > ry) ? rx : ry;
this._super(config); var scaleX = (rx > ry) ? 1 : rx / ry;
var scaleY = (rx > ry) ? ry / rx : 1;
this.dataArray = Kinetic.Plugins.PathHelper.parsePathData(this.attrs.data); 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);
this.on('dataChange', function () { break;
that.dataArray = Kinetic.Plugins.PathHelper.parsePathData(that.attrs.data); case 'z':
}); context.closePath();
break;
}
} }
}); this.fill(context);
this.stroke(context);
}
});
// add getters setters // add getters setters
Kinetic.Node.addGettersSetters(Kinetic.Plugins.Path, ['data']); Kinetic.Node.addGettersSetters(Kinetic.Plugins.Path, ['data']);
@@ -94,4 +88,4 @@ Kinetic.Node.addGettersSetters(Kinetic.Plugins.Path, ['data']);
* get SVG path data string * get SVG path data string
* @name getData * @name getData
* @methodOf Kinetic.Plugins.Path.prototype * @methodOf Kinetic.Plugins.Path.prototype
*/ */

View File

@@ -15,21 +15,22 @@ Kinetic.Plugins.RegularPolygon = Kinetic.Shape.extend({
}); });
this.shapeType = "RegularPolygon"; this.shapeType = "RegularPolygon";
config.drawFunc = function(context) { config.drawFunc = this.drawFunc;
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);
};
// call super constructor // call super constructor
this._super(config); 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);
} }
}); });

View File

@@ -16,23 +16,24 @@ Kinetic.Plugins.Star = Kinetic.Shape.extend({
}); });
this.shapeType = "Star"; this.shapeType = "Star";
config.drawFunc = function(context) { config.drawFunc = this.drawFunc;
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);
};
// call super constructor // call super constructor
this._super(config); 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);
} }
}); });

View File

@@ -9,285 +9,282 @@
* @param {Object} config * @param {Object} config
*/ */
Kinetic.Plugins.TextPath = Kinetic.Shape.extend({ Kinetic.Plugins.TextPath = Kinetic.Shape.extend({
init : function (config) { init: function(config) {
this.setDefaultAttrs({ this.setDefaultAttrs({
fontFamily : 'Calibri', fontFamily: 'Calibri',
fontSize : 12, fontSize: 12,
fontStyle : 'normal', fontStyle: 'normal',
detectionType : 'path', detectionType: 'path',
text : '' text: ''
}); });
this.dummyCanvas = document.createElement('canvas'); this.dummyCanvas = document.createElement('canvas');
this.shapeType = "TextPath"; this.shapeType = "TextPath";
this.dataArray = []; this.dataArray = [];
var that = this; var that = this;
config.drawFunc = function (context) { config.drawFunc = this.drawFunc;
var charArr = this.charArr;
context.font = this.attrs.fontStyle + ' ' + this.attrs.fontSize + 'pt ' + this.attrs.fontFamily; // call super constructor
context.textBaseline = 'middle'; this._super(config);
context.textAlign = 'left';
context.save();
var glyphInfo = this.glyphInfo; this.dataArray = Kinetic.Plugins.PathHelper.parsePathData(this.attrs.data);
for (var i = 0; i < glyphInfo.length; i++) { this.on('dataChange', function() {
context.save(); 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);
}
var p0 = glyphInfo[i].p0; that._setTextData();
var p1 = glyphInfo[i].p1; },
var ht = parseFloat(this.attrs.fontSize); drawFunc: function(context) {
var charArr = this.charArr;
context.translate(p0.x, p0.y); context.font = this.attrs.fontStyle + ' ' + this.attrs.fontSize + 'pt ' + this.attrs.fontFamily;
context.textBaseline = 'middle';
context.textAlign = 'left';
context.save();
context.rotate(glyphInfo[i].rotation); var glyphInfo = this.glyphInfo;
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');
for(var i = 0; i < glyphInfo.length; i++) {
context.save(); context.save();
context.font = this.attrs.fontStyle + ' ' + this.attrs.fontSize + 'pt ' + this.attrs.fontFamily; var p0 = glyphInfo[i].p0;
var metrics = context.measureText(text); 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(); context.restore();
return { //// To assist with debugging visually, uncomment following
width : metrics.width, // context.beginPath();
height : parseInt(this.attrs.fontSize, 10) // if (i % 2)
}; // context.strokeStyle = 'cyan';
}, // else
/** // context.strokeStyle = 'green';
* set text data.
*/
_setTextData : function () {
var that = this; // context.moveTo(p0.x, p0.y);
var size = this._getTextSize(this.attrs.text); // context.lineTo(p1.x, p1.y);
this.textWidth = size.width; // context.stroke();
this.textHeight = size.height; }
this.glyphInfo = []; 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');
var charArr = this.attrs.text.split(''); context.save();
var p0, context.font = this.attrs.fontStyle + ' ' + this.attrs.fontSize + 'pt ' + this.attrs.fontFamily;
p1, var metrics = context.measureText(text);
pathCmd;
var pIndex = -1; context.restore();
var currentT = 0;
var getNextPathSegment = function () { return {
currentT = 0; width: metrics.width,
var pathData = that.dataArray; height: parseInt(this.attrs.fontSize, 10)
};
},
/**
* set text data.
*/
_setTextData: function() {
for (var i = pIndex + 1; i < pathData.length; i++) { var that = this;
if (pathData[i].pathLength > 0) { var size = this._getTextSize(this.attrs.text);
pIndex = i; this.textWidth = size.width;
this.textHeight = size.height;
return pathData[i]; this.glyphInfo = [];
} else if (pathData[i].command == 'M') {
p0 = { var charArr = this.attrs.text.split('');
x : pathData[i].points[0],
y : pathData[i].points[1] 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]
};
}
}
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;
} }
} }
return {}; if(pathCmd === {} || p0 === undefined)
}; return undefined;
var findSegmentToFitCharacter = function (c, before) { var needNewSegment = false;
var glyphWidth = that._getTextSize(c).width; switch (pathCmd.command) {
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': case 'L':
if (Kinetic.Plugins.PathHelper.getLineLength(p0.x, p0.y, pathCmd.points[0], pathCmd.points[1]) > glyphWidth) { 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); p1 = Kinetic.Plugins.PathHelper.getPointOnLine(glyphWidth, p0.x, p0.y, pathCmd.points[0], pathCmd.points[1], p0.x, p0.y);
} else }
else
pathCmd = undefined; pathCmd = undefined;
break; break;
case 'A': case 'A':
var start = pathCmd.points[4]; // 4 = theta var start = pathCmd.points[4];
var dTheta = pathCmd.points[5]; // 5 = dTheta // 4 = theta
var dTheta = pathCmd.points[5];
// 5 = dTheta
var end = pathCmd.points[4] + dTheta; var end = pathCmd.points[4] + dTheta;
if (currentT === 0) if(currentT === 0)
currentT = start + 0.00000001; // Just in case start is 0 currentT = start + 0.00000001;
else if (glyphWidth > currLen) // Just in case start is 0
else if(glyphWidth > currLen)
currentT += (Math.PI / 180.0) * dTheta / Math.abs(dTheta); currentT += (Math.PI / 180.0) * dTheta / Math.abs(dTheta);
else else
currentT -= Math.PI / 360.0 * dTheta / Math.abs(dTheta); currentT -= Math.PI / 360.0 * dTheta / Math.abs(dTheta);
if (Math.abs(currentT) > Math.abs(end)) { if(Math.abs(currentT) > Math.abs(end)) {
currentT = end; currentT = end;
needNewSegment = true; needNewSegment = true;
} }
p1 = Kinetic.Plugins.PathHelper.getPointOnEllipticalArc(pathCmd.points[0], pathCmd.points[1], pathCmd.points[2], pathCmd.points[3], currentT, pathCmd.points[6]); p1 = Kinetic.Plugins.PathHelper.getPointOnEllipticalArc(pathCmd.points[0], pathCmd.points[1], pathCmd.points[2], pathCmd.points[3], currentT, pathCmd.points[6]);
break; break;
case 'C': case 'C':
if (currentT === 0) { if(currentT === 0) {
if (glyphWidth > pathCmd.pathLength) if(glyphWidth > pathCmd.pathLength)
currentT = 0.00000001; currentT = 0.00000001;
else else
currentT = glyphWidth / pathCmd.pathLength; currentT = glyphWidth / pathCmd.pathLength;
} else if (glyphWidth > currLen) }
else if(glyphWidth > currLen)
currentT += (glyphWidth - currLen) / pathCmd.pathLength; currentT += (glyphWidth - currLen) / pathCmd.pathLength;
else else
currentT -= (currLen - glyphWidth) / pathCmd.pathLength; currentT -= (currLen - glyphWidth) / pathCmd.pathLength;
if (currentT > 1.0) { if(currentT > 1.0) {
currentT = 1.0; currentT = 1.0;
needNewSegment = true; 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]); 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; break;
case 'Q': case 'Q':
if (currentT === 0) if(currentT === 0)
currentT = glyphWidth / pathCmd.pathLength; currentT = glyphWidth / pathCmd.pathLength;
else if (glyphWidth > currLen) else if(glyphWidth > currLen)
currentT += (glyphWidth - currLen) / pathCmd.pathLength; currentT += (glyphWidth - currLen) / pathCmd.pathLength;
else else
currentT -= (currLen - glyphWidth) / pathCmd.pathLength; currentT -= (currLen - glyphWidth) / pathCmd.pathLength;
if (currentT > 1.0) { if(currentT > 1.0) {
currentT = 1.0; currentT = 1.0;
needNewSegment = true; 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]); 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; 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++) { if(p1 !== undefined) {
currLen = Kinetic.Plugins.PathHelper.getLineLength(p0.x, p0.y, p1.x, p1.y);
}
// Find p1 such that line segment between p0 and p1 is approx. width of glyph if(needNewSegment) {
findSegmentToFitCharacter(charArr[i]); needNewSegment = false;
pathCmd = undefined;
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;
} }
};
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 // add setters and getters
Kinetic.Node.addGettersSetters(Kinetic.Plugins.TextPath, ['fontFamily', 'fontSize', 'fontStyle', 'textFill', 'textStroke', 'textStrokeWidth', 'text']); Kinetic.Node.addGettersSetters(Kinetic.Plugins.TextPath, ['fontFamily', 'fontSize', 'fontStyle', 'textFill', 'textStroke', 'textStrokeWidth', 'text']);

View File

@@ -17,20 +17,8 @@ Kinetic.Ellipse = Kinetic.Shape.extend({
}); });
this.shapeType = "Ellipse"; 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 // call super constructor
this._super(config); this._super(config);
@@ -41,6 +29,19 @@ Kinetic.Ellipse = Kinetic.Shape.extend({
that._convertRadius(); 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 * converts numeric radius into an object
*/ */

View File

@@ -14,34 +14,35 @@
Kinetic.Image = Kinetic.Shape.extend({ Kinetic.Image = Kinetic.Shape.extend({
init: function(config) { init: function(config) {
this.shapeType = "Image"; this.shapeType = "Image";
config.drawFunc = function(context) { config.drawFunc = this.drawFunc;
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);
}
}
};
// call super constructor // call super constructor
this._super(config); 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 * set width and height
* @name setSize * @name setSize

View File

@@ -17,36 +17,37 @@ Kinetic.Line = Kinetic.Shape.extend({
}); });
this.shapeType = "Line"; this.shapeType = "Line";
config.drawFunc = function(context) { config.drawFunc = this.drawFunc;
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);
};
// call super constructor // call super constructor
this._super(config); 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 * draw dashed line. Written by Phrogz
*/ */

View File

@@ -14,18 +14,19 @@ Kinetic.Polygon = Kinetic.Shape.extend({
}); });
this.shapeType = "Polygon"; this.shapeType = "Polygon";
config.drawFunc = function(context) { config.drawFunc = this.drawFunc;
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);
};
// call super constructor // call super constructor
this._super(config); 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);
} }
}); });

View File

@@ -14,19 +14,7 @@ Kinetic.Sprite = Kinetic.Shape.extend({
frameRate: 17 frameRate: 17
}); });
config.drawFunc = function(context) { config.drawFunc = this.drawFunc;
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);
}
};
// call super constructor // call super constructor
this._super(config); this._super(config);
@@ -36,6 +24,19 @@ Kinetic.Sprite = Kinetic.Shape.extend({
that.setIndex(0); 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 * start sprite animation
* @name start * @name start

View File

@@ -27,69 +27,7 @@ Kinetic.Text = Kinetic.Shape.extend({
this.dummyCanvas = document.createElement('canvas'); this.dummyCanvas = document.createElement('canvas');
this.shapeType = "Text"; this.shapeType = "Text";
config.drawFunc = function(context) { config.drawFunc = this.drawFunc;
/*
* 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();
};
// call super constructor // call super constructor
this._super(config); this._super(config);
@@ -103,6 +41,67 @@ Kinetic.Text = Kinetic.Shape.extend({
that._setTextData(); 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 * get box width
* @name getBoxWidth * @name getBoxWidth