From 176e805e58b15a6bb09cff6d038178dd9ef8bc51 Mon Sep 17 00:00:00 2001 From: Eric Rowell Date: Mon, 31 Dec 2012 20:30:00 -0800 Subject: [PATCH] decided to make an actual Spline shape. Will create a Blob shape soon, which will be an enclosed spline --- Thorfile | 3 +- src/shapes/Line.js | 74 ++--------------- src/shapes/Spline.js | 118 ++++++++++++++++++++++++++++ tests/js/unit/shapes/lineTests.js | 81 ------------------- tests/js/unit/shapes/splineTests.js | 83 +++++++++++++++++++ 5 files changed, 210 insertions(+), 149 deletions(-) create mode 100644 src/shapes/Spline.js create mode 100644 tests/js/unit/shapes/splineTests.js diff --git a/Thorfile b/Thorfile index 6abc38c3..6871c886 100644 --- a/Thorfile +++ b/Thorfile @@ -7,7 +7,7 @@ class Build < Thor "src/Global.js", "src/util/Type.js", "src/Canvas.js", "src/util/Tween.js", "src/util/Transform.js", "src/util/Collection.js", "src/filters/Grayscale.js", "src/filters/Brighten.js", "src/filters/Invert.js", "src/Animation.js", "src/Node.js", "src/DragAndDrop.js", "src/Transition.js", "src/Container.js", "src/Stage.js", "src/Layer.js", "src/Group.js", "src/Shape.js", - "src/shapes/Rect.js", "src/shapes/Circle.js", "src/shapes/Wedge.js", "src/shapes/Ellipse.js", "src/shapes/Image.js", "src/shapes/Polygon.js", "src/shapes/Text.js", "src/shapes/Line.js", "src/shapes/Sprite.js", "src/shapes/Star.js", "src/shapes/RegularPolygon.js", "src/shapes/Path.js", "src/shapes/TextPath.js" + "src/shapes/Rect.js", "src/shapes/Circle.js", "src/shapes/Wedge.js", "src/shapes/Ellipse.js", "src/shapes/Image.js", "src/shapes/Polygon.js", "src/shapes/Text.js", "src/shapes/Line.js", "src/shapes/Spline.js", "src/shapes/Sprite.js", "src/shapes/Star.js", "src/shapes/RegularPolygon.js", "src/shapes/Path.js", "src/shapes/TextPath.js" ] UNIT_TESTS = [ @@ -27,6 +27,7 @@ class Build < Thor "tests/js/unit/shapes/imageTests.js", "tests/js/unit/shapes/polygonTests.js", "tests/js/unit/shapes/lineTests.js", + "tests/js/unit/shapes/splineTests.js", "tests/js/unit/shapes/regularPolygonTests.js", "tests/js/unit/shapes/starTests.js", "tests/js/unit/shapes/textTests.js", diff --git a/src/shapes/Line.js b/src/shapes/Line.js index 083984c2..2478567d 100644 --- a/src/shapes/Line.js +++ b/src/shapes/Line.js @@ -10,59 +10,28 @@ Kinetic.Line = function(config) { this._initLine(config); }; - // function written by Rob Spencer - function getControlPoints(x0, y0, x1, y1, x2, y2, t) { - var d01 = Math.sqrt(Math.pow(x1 - x0, 2) + Math.pow(y1 - y0, 2)); - var d12 = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); - var fa = t * d01 / (d01 + d12); - var fb = t * d12 / (d01 + d12); - var p1x = x1 - fa * (x2 - x0); - var p1y = y1 - fa * (y2 - y0); - var p2x = x1 + fb * (x2 - x0); - var p2y = y1 + fb * (y2 - y0); - return [p1x, p1y, p2x, p2y]; - } Kinetic.Line.prototype = { _initLine: function(config) { this.setDefaultAttrs({ points: [], - lineCap: 'butt', - dashArray: [], - detectionType: 'pixel', - spline: 0 + lineCap: 'butt' }); - this.shapeType = "Line"; + this.shapeType = 'Line'; // call super constructor Kinetic.Shape.call(this, config); this._setDrawFuncs(); }, drawFunc: function(canvas) { - var points = this.getPoints(), length = points.length, dashArray = this.getDashArray(), dashLength = dashArray.length, context = canvas.getContext(), spline = this.getSpline(); + var points = this.getPoints(), length = points.length, context = canvas.getContext(); context.beginPath(); context.moveTo(points[0].x, points[0].y); - // spline - if(spline !== 0 && length > 2) { - var ap = this.allPoints, len = ap.length; - context.quadraticCurveTo(ap[0].x, ap[0].y, ap[1].x, ap[1].y); - - var n = 2; - 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 spline - else { - for(var n = 1; n < length; n++) { - var point = points[n]; - context.lineTo(point.x, point.y); - } + for(var n = 1; n < length; n++) { + var point = points[n]; + context.lineTo(point.x, point.y); } canvas.stroke(this); @@ -76,41 +45,12 @@ */ setPoints: function(val) { this.setAttr('points', Kinetic.Type._getPoints(val)); - this._setAllPoints(); - }, - /** - * set spline - * @name setSpline - * @methodOf Kinetic.Line.prototype - * @param {Number} spline - */ - setSpline: function(spline) { - this.setAttr('spline', spline); - this._setAllPoints(); - }, - _setAllPoints: function() { - var points = this.getPoints(), length = points.length, spline = this.getSpline(), allPoints = []; - - for(var n = 1; n < length - 1; n++) { - var p0 = points[n - 1], p1 = points[n], p2 = points[n + 1], cp = getControlPoints(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, spline); - allPoints.push({ - x: cp[0], - y: cp[1] - }); - allPoints.push(p1); - allPoints.push({ - x: cp[2], - y: cp[3] - }); - } - - this.allPoints = allPoints; } }; Kinetic.Global.extend(Kinetic.Line, Kinetic.Shape); // add getters setters - Kinetic.Node.addGetters(Kinetic.Line, ['points', 'spline']); + Kinetic.Node.addGetters(Kinetic.Line, ['points']); /** * get points array diff --git a/src/shapes/Spline.js b/src/shapes/Spline.js new file mode 100644 index 00000000..fa4063c7 --- /dev/null +++ b/src/shapes/Spline.js @@ -0,0 +1,118 @@ +(function() { + /** + * Spline constructor.  Splines are defined by an array of points + * @constructor + * @augments Kinetic.Shape + * @param {Object} config + * @param {Array} config.points can be a flattened array of points, or an array of point objects. + * e.g. [0,1,2,3] and [{x:1,y:2},{x:3,y:4}] are equivalent + */ + Kinetic.Spline = function(config) { + this._initSpline(config); + }; + // function written by Rob Spencer + function getControlPoints(x0, y0, x1, y1, x2, y2, t) { + var d01 = Math.sqrt(Math.pow(x1 - x0, 2) + Math.pow(y1 - y0, 2)); + var d12 = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); + var fa = t * d01 / (d01 + d12); + var fb = t * d12 / (d01 + d12); + var p1x = x1 - fa * (x2 - x0); + var p1y = y1 - fa * (y2 - y0); + var p2x = x1 + fb * (x2 - x0); + var p2y = y1 + fb * (y2 - y0); + return [p1x, p1y, p2x, p2y]; + } + + Kinetic.Spline.prototype = { + _initSpline: function(config) { + this.setDefaultAttrs({ + points: [], + lineCap: 'butt', + tension: 0 + }); + + this.shapeType = 'Spline'; + + // call super constructor + Kinetic.Shape.call(this, config); + this._setDrawFuncs(); + }, + drawFunc: function(canvas) { + var points = this.getPoints(), length = points.length, context = canvas.getContext(), tension = this.getTension(); + context.beginPath(); + context.moveTo(points[0].x, points[0].y); + + // tension + if(tension !== 0 && length > 2) { + var ap = this.allPoints, len = ap.length; + context.quadraticCurveTo(ap[0].x, ap[0].y, ap[1].x, ap[1].y); + + var n = 2; + 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(var n = 1; n < length; n++) { + var point = points[n]; + context.lineTo(point.x, point.y); + } + } + + canvas.stroke(this); + }, + /** + * set points array + * @name setPoints + * @methodOf 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] + */ + setPoints: function(val) { + this.setAttr('points', Kinetic.Type._getPoints(val)); + this._setAllPoints(); + }, + /** + * set tension + * @name setTension + * @methodOf Kinetic.Spline.prototype + * @param {Number} tension + */ + setTension: function(tension) { + this.setAttr('tension', tension); + this._setAllPoints(); + }, + _setAllPoints: function() { + var points = this.getPoints(), length = points.length, tension = this.getTension(), allPoints = []; + + for(var n = 1; n < length - 1; n++) { + var p0 = points[n - 1], p1 = points[n], p2 = points[n + 1], cp = getControlPoints(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, tension); + allPoints.push({ + x: cp[0], + y: cp[1] + }); + allPoints.push(p1); + allPoints.push({ + x: cp[2], + y: cp[3] + }); + } + + this.allPoints = allPoints; + } + }; + Kinetic.Global.extend(Kinetic.Spline, Kinetic.Shape); + + // add getters setters + Kinetic.Node.addGetters(Kinetic.Spline, ['points', 'tension']); + + /** + * get points array + * @name getPoints + * @methodOf Kinetic.Spline.prototype + */ +})(); diff --git a/tests/js/unit/shapes/lineTests.js b/tests/js/unit/shapes/lineTests.js index 9d7fa771..aecfb47b 100644 --- a/tests/js/unit/shapes/lineTests.js +++ b/tests/js/unit/shapes/lineTests.js @@ -47,87 +47,6 @@ Test.Modules.LINE = { line.setPoints([73, 160, 340, 23]); test(line.getPoints()[0].x === 73, 'first point x should be 73'); }, - 'add curvy lines': function(containerId) { - var stage = new Kinetic.Stage({ - container: containerId, - width: 578, - height: 200 - }); - var layer = new Kinetic.Layer(); - - var line1 = new Kinetic.Line({ - points: [{ - x: 73, - y: 160 - }, { - x: 340, - y: 23 - }, { - x: 500, - y: 109 - }, { - x: 300, - y: 109 - }], - stroke: 'blue', - strokeWidth: 10, - lineCap: 'round', - lineJoin: 'round', - draggable: true, - spline: 1 - }); - - var line2 = new Kinetic.Line({ - points: [{ - x: 73, - y: 160 - }, { - x: 340, - y: 23 - }, { - x: 500, - y: 109 - }], - stroke: 'red', - strokeWidth: 10, - lineCap: 'round', - lineJoin: 'round', - draggable: true, - spline: 1 - }); - - var line3 = new Kinetic.Line({ - points: [{ - x: 73, - y: 160 - }, { - x: 340, - y: 23 - }], - stroke: 'green', - strokeWidth: 10, - lineCap: 'round', - lineJoin: 'round', - draggable: true, - spline: 1 - }); - - layer.add(line1); - layer.add(line2); - layer.add(line3); - stage.add(layer); - - /* - line.transitionTo({ - spline: 3, - duration: 3 - }); - */ - - //console.log(layer.toDataURL()); - warn(layer.toDataURL() === dataUrls['curvy lines'], 'problem with curvy lines'); - - }, 'add dashed line': function(containerId) { var stage = new Kinetic.Stage({ container: containerId, diff --git a/tests/js/unit/shapes/splineTests.js b/tests/js/unit/shapes/splineTests.js new file mode 100644 index 00000000..e24a0f78 --- /dev/null +++ b/tests/js/unit/shapes/splineTests.js @@ -0,0 +1,83 @@ +Test.Modules.SPLINE = { + 'add splines': function(containerId) { + var stage = new Kinetic.Stage({ + container: containerId, + width: 578, + height: 200 + }); + var layer = new Kinetic.Layer(); + + var line1 = new Kinetic.Spline({ + points: [{ + x: 73, + y: 160 + }, { + x: 340, + y: 23 + }, { + x: 500, + y: 109 + }, { + x: 300, + y: 109 + }], + stroke: 'blue', + strokeWidth: 10, + lineCap: 'round', + lineJoin: 'round', + draggable: true, + tension: 1 + }); + + var line2 = new Kinetic.Spline({ + points: [{ + x: 73, + y: 160 + }, { + x: 340, + y: 23 + }, { + x: 500, + y: 109 + }], + stroke: 'red', + strokeWidth: 10, + lineCap: 'round', + lineJoin: 'round', + draggable: true, + tension: 1 + }); + + var line3 = new Kinetic.Spline({ + points: [{ + x: 73, + y: 160 + }, { + x: 340, + y: 23 + }], + stroke: 'green', + strokeWidth: 10, + lineCap: 'round', + lineJoin: 'round', + draggable: true, + tension: 1 + }); + + layer.add(line1); + layer.add(line2); + layer.add(line3); + stage.add(layer); + + /* + line.transitionTo({ + spline: 3, + duration: 3 + }); + */ + + //console.log(layer.toDataURL()); + warn(layer.toDataURL() === dataUrls['curvy lines'], 'problem with curvy lines'); + + } +};