combined Line, Spline, Blob, and Polygon into a single shape for more flexibility. converted allPoints property into cacheable getTensionPoints method

This commit is contained in:
Eric Rowell 2013-11-30 00:24:47 -08:00
parent 4fafde7451
commit 4b62ecea7c
10 changed files with 154 additions and 364 deletions

View File

@ -22,11 +22,8 @@ module.exports = function(grunt) {
'src/shapes/Ellipse.js', 'src/shapes/Ellipse.js',
'src/shapes/Wedge.js', 'src/shapes/Wedge.js',
'src/shapes/Image.js', 'src/shapes/Image.js',
'src/shapes/Polygon.js',
'src/shapes/Text.js', 'src/shapes/Text.js',
'src/shapes/Line.js', 'src/shapes/Line.js',
'src/shapes/Spline.js',
'src/shapes/Blob.js',
'src/shapes/Sprite.js', 'src/shapes/Sprite.js',
// plugins // plugins

View File

@ -1,128 +0,0 @@
(function() {
/**
* Blob constructor. Blobs are defined by an array of points and
* a tension
* @constructor
* @memberof Kinetic
* @augments Kinetic.Shape
* @param {Object} config
* @param {Array} config.points can be a flattened array of points, an array of point arrays, or an array of point objects.
* e.g. [0,1,2,3], [[0,1],[2,3]] and [{x:0,y:1},{x:2,y:3}] are equivalent
* @param {Number} [config.tension] default value is 1. Higher values will result in a more curvy line. A value of 0 will result in no interpolation.
* @@shapeParams
* @@nodeParams
* @example
* var blob = new Kinetic.Blob({<br>
* points: [73, 140, 340, 23, 500, 109, 300, 170],<br>
* tension: 0.8,<br>
* fill: 'red',<br>
* stroke: 'black'<br>
* strokeWidth: 5<br>
* });
*/
Kinetic.Blob = function(config) {
this.___init(config);
};
Kinetic.Blob.prototype = {
___init: function(config) {
var that = this;
// call super constructor
Kinetic.Shape.call(this, config);
this.className = 'Blob';
this.on('pointsChange.kinetic tensionChange.kinetic', function() {
that._setAllPoints();
});
this._setAllPoints();
},
drawFunc: function(context) {
var points = this.getPoints(),
length = points.length,
tension = this.getTension(),
ap, len, n, point;
context.beginPath();
context.moveTo(points[0].x, points[0].y);
// tension
if(tension !== 0 && length > 2) {
ap = this.allPoints;
len = ap.length;
n = 0;
while(n < len-1) {
context.bezierCurveTo(ap[n].x, ap[n++].y, ap[n].x, ap[n++].y, ap[n].x, ap[n++].y);
}
}
// no tension
else {
for(n = 1; n < length; n++) {
point = points[n];
context.lineTo(point.x, point.y);
}
}
context.closePath();
context.fillStrokeShape(this);
},
_setAllPoints: function() {
var points = this.getPoints(),
length = points.length,
tension = this.getTension(),
util = Kinetic.Util,
firstControlPoints = util._getControlPoints(points[length - 1], points[0], points[1], tension),
lastControlPoints = util._getControlPoints(points[length - 2], points[length - 1], points[0], tension);
this.allPoints = Kinetic.Util._expandPoints(this.getPoints(), this.getTension());
// prepend control point
this.allPoints.unshift(firstControlPoints[1]);
// append cp, point, cp, cp, first point
this.allPoints.push(lastControlPoints[0]);
this.allPoints.push(points[length - 1]);
this.allPoints.push(lastControlPoints[1]);
this.allPoints.push(firstControlPoints[0]);
this.allPoints.push(points[0]);
}
};
Kinetic.Util.extend(Kinetic.Blob, Kinetic.Shape);
Kinetic.Factory.addGetterSetter(Kinetic.Blob, 'tension', 1);
/**
* get tension
* @name getTension
* @method
* @memberof Kinetic.Blob.prototype
* @returns {Number}
*/
/**
* set tension
* @name setTension
* @method
* @memberof Kinetic.Blob.prototype
* @param {Number} tension
*/
Kinetic.Factory.addPointsGetterSetter(Kinetic.Blob, 'points');
/**
* get points array
* @name getPoints
* @method
* @memberof Kinetic.Blob.prototype
* @returns {Array}
*/
/**
* set points array
* @name setPoints
* @method
* @memberof Kinetic.Blob.prototype
* @param {Array} can be an array of point objects or an array
* of Numbers. e.g. [{x:1,y:2},{x:3,y:4}] or [1,2,3,4]
*/
})();

View File

@ -1,34 +1,23 @@
(function() { (function() {
/** /**
* Line constructor.&nbsp; Lines are defined by an array of points * Line constructor.&nbsp; Lines are defined by an array of points and
* a tension
* @constructor * @constructor
* @memberof Kinetic * @memberof Kinetic
* @augments Kinetic.Shape * @augments Kinetic.Shape
* @param {Object} config * @param {Object} config
* @param {Array} config.points can be a flattened array of points, an array of point arrays, or an array of point objects. * @param {Array} config.points can be a flattened array of points, an array of point arrays, or an array of point objects.
* e.g. [0,1,2,3], [[0,1],[2,3]] and [{x:0,y:1},{x:2,y:3}] are equivalent * e.g. [0,1,2,3], [[0,1],[2,3]] and [{x:0,y:1},{x:2,y:3}] are equivalent
* @param {Number} [config.tension] default value is 1. Higher values will result in a more curvy line. A value of 0 will result in no interpolation.
* @@shapeParams * @@shapeParams
* @@nodeParams * @@nodeParams
* @example * @example
* // simple line
* var line = new Kinetic.Line({<br>
* x: 100,<br>
* y: 50,<br>
* points: [73, 70, 340, 23, 450, 60, 500, 20],<br>
* stroke: 'red'<br>
* });<br><br>
*
* // dashed line with shadow<br>
* var line = new Kinetic.Line({<br> * var line = new Kinetic.Line({<br>
* x: 100,<br> * x: 100,<br>
* y: 50,<br> * y: 50,<br>
* points: [73, 70, 340, 23, 450, 60, 500, 20],<br> * points: [73, 70, 340, 23, 450, 60, 500, 20],<br>
* stroke: 'red',<br> * stroke: 'red',<br>
* dashArray: [33, 10],<br> * tension: 1<br>
* shadowColor: 'black',<br>
* shadowBlur: 10,<br>
* shadowOffset: 10,<br>
* shadowOpacity: 0.5<br>
* }); * });
*/ */
Kinetic.Line = function(config) { Kinetic.Line = function(config) {
@ -37,29 +26,142 @@
Kinetic.Line.prototype = { Kinetic.Line.prototype = {
___init: function(config) { ___init: function(config) {
var that = this;
// call super constructor // call super constructor
Kinetic.Shape.call(this, config); Kinetic.Shape.call(this, config);
this.className = 'Line'; this.className = 'Line';
this.on('pointsChange.kinetic tensionChange.kinetic closedChange.kinetic', function() {
this._clearCache('tensionPoints');
});
}, },
drawFunc: function(context) { drawFunc: function(context) {
var points = this.getPoints(), var points = this.getPoints(),
length = points.length, length = points.length,
n, point; tension = this.getTension(),
closed = this.getClosed(),
tp, len, n, point;
context.beginPath(); context.beginPath();
context.moveTo(points[0].x, points[0].y); context.moveTo(points[0].x, points[0].y);
for(n = 1; n < length; n++) { // tension
point = points[n]; if(tension !== 0 && length > 2) {
context.lineTo(point.x, point.y); tp = this.getTensionPoints();
len = tp.length;
n = closed ? 0 : 2;
if (!closed) {
context.quadraticCurveTo(tp[0].x, tp[0].y, tp[1].x, tp[1].y);
}
while(n < len - 1) {
context.bezierCurveTo(tp[n].x, tp[n++].y, tp[n].x, tp[n++].y, tp[n].x, tp[n++].y);
}
if (!closed) {
context.quadraticCurveTo(tp[len - 1].x, tp[len - 1].y, points[length - 1].x, points[length - 1].y);
}
}
// no tension
else {
for(n = 1; n < length; n++) {
point = points[n];
context.lineTo(point.x, point.y);
}
} }
context.strokeShape(this); // closed e.g. polygons and blobs
if (closed) {
context.closePath();
context.fillStrokeShape(this);
}
// open e.g. lines and splines
else {
context.strokeShape(this);
};
},
getTensionPoints: function() {
return this._getCache('tensionPoints', this._getTensionPoints);
},
_getTensionPoints: function() {
if (this.getClosed()) {
return this._getTensionPointsClosed();
}
else {
return Kinetic.Util._expandPoints(this.getPoints(), this.getTension());
}
},
_getTensionPointsClosed: function() {
var points = this.getPoints(),
length = points.length,
tension = this.getTension(),
util = Kinetic.Util,
firstControlPoints = util._getControlPoints(points[length - 1], points[0], points[1], tension),
lastControlPoints = util._getControlPoints(points[length - 2], points[length - 1], points[0], tension),
tensionPoints = Kinetic.Util._expandPoints(points, tension);
// prepend control point
tensionPoints.unshift(firstControlPoints[1]);
// append cp, point, cp, cp, first point
tensionPoints.push(lastControlPoints[0]);
tensionPoints.push(points[length - 1]);
tensionPoints.push(lastControlPoints[1]);
tensionPoints.push(firstControlPoints[0]);
tensionPoints.push(points[0]);
return tensionPoints;
} }
}; };
Kinetic.Util.extend(Kinetic.Line, Kinetic.Shape); Kinetic.Util.extend(Kinetic.Line, Kinetic.Shape);
// add getters setters
Kinetic.Factory.addGetterSetter(Kinetic.Line, 'closed', false);
/**
* get closed
* @name getClosed
* @method
* @memberof Kinetic.Line.prototype
* @returns {Boolean}
*/
/**
* set closed
* @name setClosed
* @method
* @memberof Kinetic.Line.prototype
* @param {Boolean} closed
*/
Kinetic.Factory.addGetterSetter(Kinetic.Line, 'tension', 0);
/**
* get tension
* @name getTension
* @method
* @memberof Kinetic.Line.prototype
* @returns {Number}
*/
/**
* set tension
* @name setTension
* @method
* @memberof Kinetic.Line.prototype
* @param {Number} tension
*/
Kinetic.Factory.addPointsGetterSetter(Kinetic.Line, 'points'); Kinetic.Factory.addPointsGetterSetter(Kinetic.Line, 'points');
/**
* get points array
* @name getPoints
* @method
* @memberof Kinetic.Line.prototype
* @returns {Array}
*/
/** /**
* set points array * set points array
* @name setPoints * @name setPoints
@ -68,12 +170,4 @@
* @param {Array} can be an array of point objects or an array * @param {Array} can be an array of point objects or an array
* of Numbers. e.g. [{x:1,y:2},{x:3,y:4}] or [1,2,3,4] * of Numbers. e.g. [{x:1,y:2},{x:3,y:4}] or [1,2,3,4]
*/ */
/**
* get points array
* @name getPoints
* @method
* @memberof Kinetic.Line.prototype
* @returns {Array}
*/
})(); })();

View File

@ -1,62 +0,0 @@
(function() {
/**
* Polygon constructor.&nbsp; Polygons are defined by an array of points
* @constructor
* @memberof Kinetic
* @augments Kinetic.Shape
* @param {Object} config
* @param {Array} config.points can be a flattened array of points, an array of point arrays, or an array of point objects.
* e.g. [0,1,2,3], [[0,1],[2,3]] and [{x:0,y:1},{x:2,y:3}] are equivalent
* @@shapeParams
* @@nodeParams
* @example
* var polygon = new Kinetic.Polygon({<br>
* points: [73, 192, 73, 160, 340, 23, 500, 109, 499, 139, 342, 93],<br>
* fill: '#00D2FF',<br>
* stroke: 'black',<br>
* strokeWidth: 5<br>
* });
*/
Kinetic.Polygon = function(config) {
this.___init(config);
};
Kinetic.Polygon.prototype = {
___init: function(config) {
// call super constructor
Kinetic.Shape.call(this, config);
this.className = 'Polygon';
},
drawFunc: function(context) {
var points = this.getPoints(),
length = points.length;
context.beginPath();
context.moveTo(points[0].x, points[0].y);
for(var n = 1; n < length; n++) {
context.lineTo(points[n].x, points[n].y);
}
context.closePath();
context.fillStrokeShape(this);
}
};
Kinetic.Util.extend(Kinetic.Polygon, Kinetic.Shape);
Kinetic.Factory.addPointsGetterSetter(Kinetic.Polygon, 'points');
/**
* set points array
* @name setPoints
* @method
* @memberof Kinetic.Polygon.prototype
* @param {Array} can be an array of point objects or an array
* of Numbers. e.g. [{x:1,y:2},{x:3,y:4}] or [1,2,3,4]
*/
/**
* get points array
* @name getPoints
* @method
* @memberof Kinetic.Polygon.prototype
* @returns {Array}
*/
})();

View File

@ -1,115 +0,0 @@
(function() {
/**
* Spline constructor.&nbsp; Splines are defined by an array of points and
* a tension
* @constructor
* @memberof Kinetic
* @augments Kinetic.Shape
* @param {Object} config
* @param {Array} config.points can be a flattened array of points, an array of point arrays, or an array of point objects.
* e.g. [0,1,2,3], [[0,1],[2,3]] and [{x:0,y:1},{x:2,y:3}] are equivalent
* @param {Number} [config.tension] default value is 1. Higher values will result in a more curvy line. A value of 0 will result in no interpolation.
* @@shapeParams
* @@nodeParams
* @example
* var spline = new Kinetic.Spline({<br>
* x: 100,<br>
* y: 50,<br>
* points: [73, 70, 340, 23, 450, 60, 500, 20],<br>
* stroke: 'red',<br>
* tension: 1<br>
* });
*/
Kinetic.Spline = function(config) {
this.___init(config);
};
Kinetic.Spline.prototype = {
___init: function(config) {
var that = this;
// call super constructor
Kinetic.Shape.call(this, config);
this.className = 'Spline';
this.on('pointsChange.kinetic tensionChange.kinetic', function() {
that._setAllPoints();
});
this._setAllPoints();
},
drawFunc: function(context) {
var points = this.getPoints(),
length = points.length,
tension = this.getTension(),
ap, len, n, point;
context.beginPath();
context.moveTo(points[0].x, points[0].y);
// tension
if(tension !== 0 && length > 2) {
ap = this.allPoints;
len = ap.length;
n = 2;
context.quadraticCurveTo(ap[0].x, ap[0].y, ap[1].x, ap[1].y);
while(n < len - 1) {
context.bezierCurveTo(ap[n].x, ap[n++].y, ap[n].x, ap[n++].y, ap[n].x, ap[n++].y);
}
context.quadraticCurveTo(ap[len - 1].x, ap[len - 1].y, points[length - 1].x, points[length - 1].y);
}
// no tension
else {
for(n = 1; n < length; n++) {
point = points[n];
context.lineTo(point.x, point.y);
}
}
context.strokeShape(this);
},
_setAllPoints: function() {
this.allPoints = Kinetic.Util._expandPoints(this.getPoints(), this.getTension());
}
};
Kinetic.Util.extend(Kinetic.Spline, Kinetic.Shape);
// add getters setters
Kinetic.Factory.addGetterSetter(Kinetic.Spline, 'tension', 1);
/**
* get tension
* @name getTension
* @method
* @memberof Kinetic.Spline.prototype
* @returns {Number}
*/
/**
* set tension
* @name setTension
* @method
* @memberof Kinetic.Spline.prototype
* @param {Number} tension
*/
Kinetic.Factory.addPointsGetterSetter(Kinetic.Spline, 'points');
/**
* get points array
* @name getPoints
* @method
* @memberof Kinetic.Spline.prototype
* @returns {Array}
*/
/**
* set points array
* @name setPoints
* @method
* @memberof Kinetic.Spline.prototype
* @param {Array} can be an array of point objects or an array
* of Numbers. e.g. [{x:1,y:2},{x:3,y:4}] or [1,2,3,4]
*/
})();

View File

@ -912,12 +912,13 @@ suite('Node', function() {
y: 93 y: 93
}]; }];
var poly = new Kinetic.Polygon({ var poly = new Kinetic.Line({
points: points, points: points,
fill: 'green', fill: 'green',
stroke: 'blue', stroke: 'blue',
strokeWidth: 5, strokeWidth: 5,
draggable: true draggable: true,
closed: true
}); });
group.add(poly); group.add(poly);

View File

@ -4,7 +4,7 @@ suite('Blob', function(){
var stage = addStage(); var stage = addStage();
var layer = new Kinetic.Layer(); var layer = new Kinetic.Layer();
var blob = new Kinetic.Blob({ var blob = new Kinetic.Line({
points: [{ points: [{
x: 73, x: 73,
y: 140 y: 140
@ -22,7 +22,8 @@ suite('Blob', function(){
strokeWidth: 10, strokeWidth: 10,
draggable: true, draggable: true,
fill: '#aaf', fill: '#aaf',
tension: 0.8 tension: 0.8,
closed: true
}); });
layer.add(blob); layer.add(blob);
@ -30,7 +31,7 @@ suite('Blob', function(){
assert.equal(blob.getTension(), 0.8); assert.equal(blob.getTension(), 0.8);
assert.equal(blob.getClassName(), 'Blob'); assert.equal(blob.getClassName(), 'Line');
//console.log(blob1.getPoints()) //console.log(blob1.getPoints())
@ -48,7 +49,7 @@ suite('Blob', function(){
var layer = new Kinetic.Layer(); var layer = new Kinetic.Layer();
var blob = new Kinetic.Blob({ var blob = new Kinetic.Line({
tension: 0.8, tension: 0.8,
points: [{ points: [{
x: 73, x: 73,
@ -66,14 +67,15 @@ suite('Blob', function(){
stroke: 'blue', stroke: 'blue',
strokeWidth: 10, strokeWidth: 10,
draggable: true, draggable: true,
fill: '#aaf' fill: '#aaf',
closed: true
}); });
layer.add(blob); layer.add(blob);
stage.add(layer); stage.add(layer);
assert.equal(stage.find('Blob')[0].getPoints().length, 4); assert.equal(stage.find('Line')[0].getPoints().length, 4);
}); });
@ -82,7 +84,7 @@ suite('Blob', function(){
var stage = addStage(); var stage = addStage();
var layer = new Kinetic.Layer(); var layer = new Kinetic.Layer();
var blob = new Kinetic.Blob({ var blob = new Kinetic.Line({
points: [{ points: [{
x: 73, x: 73,
y: 140 y: 140
@ -100,7 +102,8 @@ suite('Blob', function(){
strokeWidth: 10, strokeWidth: 10,
draggable: true, draggable: true,
fill: '#aaf', fill: '#aaf',
tension: 0.8 tension: 0.8,
closed: true
}); });
layer.add(blob); layer.add(blob);

View File

@ -18,7 +18,8 @@ suite('Line', function() {
strokeWidth: 20, strokeWidth: 20,
lineCap: 'round', lineCap: 'round',
lineJoin: 'round', lineJoin: 'round',
draggable: true draggable: true,
tension: 0
}); });
layer.add(line); layer.add(line);

View File

@ -24,16 +24,17 @@ suite('Polygon', function() {
y: 93 y: 93
}]; }];
var poly = new Kinetic.Polygon({ var poly = new Kinetic.Line({
points: points, points: points,
fill: 'green', fill: 'green',
stroke: 'blue', stroke: 'blue',
strokeWidth: 5 strokeWidth: 5,
closed: true
}); });
layer.add(poly); layer.add(poly);
stage.add(layer); stage.add(layer);
assert.equal(poly.getClassName(), 'Polygon'); assert.equal(poly.getClassName(), 'Line');
}); });
}); });

View File

@ -1,10 +1,10 @@
suite('Spline', function() { suite('Spline', function() {
// ====================================================== // ======================================================
test('add spline', function() { test('add splines', function() {
var stage = addStage(); var stage = addStage();
var layer = new Kinetic.Layer(); var layer = new Kinetic.Layer();
var line1 = new Kinetic.Spline({ var line1 = new Kinetic.Line({
points: [{ points: [{
x: 73, x: 73,
y: 160 y: 160
@ -26,7 +26,7 @@ suite('Spline', function() {
tension: 1 tension: 1
}); });
var line2 = new Kinetic.Spline({ var line2 = new Kinetic.Line({
points: [{ points: [{
x: 73, x: 73,
y: 160 y: 160
@ -45,7 +45,7 @@ suite('Spline', function() {
tension: 1 tension: 1
}); });
var line3 = new Kinetic.Spline({ var line3 = new Kinetic.Line({
points: [{ points: [{
x: 73, x: 73,
y: 160 y: 160
@ -66,14 +66,12 @@ suite('Spline', function() {
layer.add(line3); layer.add(line3);
stage.add(layer); stage.add(layer);
assert.equal(line1.getClassName(), 'Spline'); assert.equal(line1.getClassName(), 'Line');
var trace = layer.getContext().getTrace(); var trace = layer.getContext().getTrace();
//console.log(trace); //console.log(trace);
assert.equal(trace, 'clearRect(0,0,578,200);save();lineJoin=round;transform(1,0,0,1,0,0);beginPath();moveTo(73,160);quadraticCurveTo(74.006,54.77,340,23);bezierCurveTo(501.006,3.77,519.038,68.068,500,109);quadraticCurveTo(479.038,154.068,300,109);lineCap=round;lineWidth=10;strokeStyle=blue;stroke();restore();save();lineJoin=round;transform(1,0,0,1,0,0);beginPath();moveTo(73,160);quadraticCurveTo(74.006,54.77,340,23);quadraticCurveTo(501.006,3.77,500,109);lineCap=round;lineWidth=10;strokeStyle=red;stroke();restore();save();lineJoin=round;transform(1,0,0,1,0,0);beginPath();moveTo(73,160);lineTo(340,23);lineCap=round;lineWidth=10;strokeStyle=green;stroke();restore();'); assert.equal(trace, 'clearRect(0,0,578,200);save();lineJoin=round;transform(1,0,0,1,0,0);beginPath();moveTo(73,160);quadraticCurveTo(74.006,54.77,340,23);bezierCurveTo(501.006,3.77,519.038,68.068,500,109);quadraticCurveTo(479.038,154.068,300,109);lineCap=round;lineWidth=10;strokeStyle=blue;stroke();restore();save();lineJoin=round;transform(1,0,0,1,0,0);beginPath();moveTo(73,160);quadraticCurveTo(74.006,54.77,340,23);quadraticCurveTo(501.006,3.77,500,109);lineCap=round;lineWidth=10;strokeStyle=red;stroke();restore();save();lineJoin=round;transform(1,0,0,1,0,0);beginPath();moveTo(73,160);lineTo(340,23);lineCap=round;lineWidth=10;strokeStyle=green;stroke();restore();');
}); });
// ====================================================== // ======================================================
@ -81,7 +79,7 @@ suite('Spline', function() {
var stage = addStage(); var stage = addStage();
var layer = new Kinetic.Layer(); var layer = new Kinetic.Layer();
var spline = new Kinetic.Spline({ var spline = new Kinetic.Line({
points: [{ points: [{
x: 73, x: 73,
y: 160 y: 160
@ -107,7 +105,7 @@ suite('Spline', function() {
layer.add(spline); layer.add(spline);
stage.add(layer); stage.add(layer);
assert.equal(spline.allPoints.length, 6); assert.equal(spline.getTensionPoints().length, 6);
spline.setPoints([{ spline.setPoints([{
x: 73, x: 73,
@ -120,7 +118,7 @@ suite('Spline', function() {
y: 109 y: 109
}]); }]);
assert.equal(spline.allPoints.length, 3); assert.equal(spline.getTensionPoints().length, 3);
layer.draw(); layer.draw();
@ -132,7 +130,7 @@ suite('Spline', function() {
var stage = addStage(); var stage = addStage();
var layer = new Kinetic.Layer(); var layer = new Kinetic.Layer();
var spline = new Kinetic.Spline({ var spline = new Kinetic.Line({
points: [{ points: [{
x: 73, x: 73,
y: 160 y: 160
@ -175,7 +173,7 @@ suite('Spline', function() {
var stage = addStage(); var stage = addStage();
var layer = new Kinetic.Layer(); var layer = new Kinetic.Layer();
var line = new Kinetic.Spline({ var line = new Kinetic.Line({
points: [ points: [
73, 160, 73, 160,
340, 23, 340, 23,
@ -201,7 +199,7 @@ suite('Spline', function() {
var stage = addStage(); var stage = addStage();
var layer = new Kinetic.Layer(); var layer = new Kinetic.Layer();
var line = new Kinetic.Spline({ var line = new Kinetic.Line({
points: [{ points: [{
x: 73, x: 73,
y: 160 y: 160
@ -234,7 +232,7 @@ suite('Spline', function() {
var stage = addStage(); var stage = addStage();
var layer = new Kinetic.Layer(); var layer = new Kinetic.Layer();
var line = new Kinetic.Spline({ var line = new Kinetic.Line({
points: [ points: [
[73, 160], [73, 160],
[340, 23], [340, 23],