mirror of
https://github.com/konvajs/konva.git
synced 2025-11-18 09:07:30 +08:00
decided to make an actual Spline shape. Will create a Blob shape soon, which will be an enclosed spline
This commit is contained in:
3
Thorfile
3
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/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/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/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 = [
|
UNIT_TESTS = [
|
||||||
@@ -27,6 +27,7 @@ class Build < Thor
|
|||||||
"tests/js/unit/shapes/imageTests.js",
|
"tests/js/unit/shapes/imageTests.js",
|
||||||
"tests/js/unit/shapes/polygonTests.js",
|
"tests/js/unit/shapes/polygonTests.js",
|
||||||
"tests/js/unit/shapes/lineTests.js",
|
"tests/js/unit/shapes/lineTests.js",
|
||||||
|
"tests/js/unit/shapes/splineTests.js",
|
||||||
"tests/js/unit/shapes/regularPolygonTests.js",
|
"tests/js/unit/shapes/regularPolygonTests.js",
|
||||||
"tests/js/unit/shapes/starTests.js",
|
"tests/js/unit/shapes/starTests.js",
|
||||||
"tests/js/unit/shapes/textTests.js",
|
"tests/js/unit/shapes/textTests.js",
|
||||||
|
|||||||
@@ -10,59 +10,28 @@
|
|||||||
Kinetic.Line = function(config) {
|
Kinetic.Line = function(config) {
|
||||||
this._initLine(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 = {
|
Kinetic.Line.prototype = {
|
||||||
_initLine: function(config) {
|
_initLine: function(config) {
|
||||||
this.setDefaultAttrs({
|
this.setDefaultAttrs({
|
||||||
points: [],
|
points: [],
|
||||||
lineCap: 'butt',
|
lineCap: 'butt'
|
||||||
dashArray: [],
|
|
||||||
detectionType: 'pixel',
|
|
||||||
spline: 0
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.shapeType = "Line";
|
this.shapeType = 'Line';
|
||||||
|
|
||||||
// call super constructor
|
// call super constructor
|
||||||
Kinetic.Shape.call(this, config);
|
Kinetic.Shape.call(this, config);
|
||||||
this._setDrawFuncs();
|
this._setDrawFuncs();
|
||||||
},
|
},
|
||||||
drawFunc: function(canvas) {
|
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.beginPath();
|
||||||
context.moveTo(points[0].x, points[0].y);
|
context.moveTo(points[0].x, points[0].y);
|
||||||
|
|
||||||
// spline
|
for(var n = 1; n < length; n++) {
|
||||||
if(spline !== 0 && length > 2) {
|
var point = points[n];
|
||||||
var ap = this.allPoints, len = ap.length;
|
context.lineTo(point.x, point.y);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas.stroke(this);
|
canvas.stroke(this);
|
||||||
@@ -76,41 +45,12 @@
|
|||||||
*/
|
*/
|
||||||
setPoints: function(val) {
|
setPoints: function(val) {
|
||||||
this.setAttr('points', Kinetic.Type._getPoints(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);
|
Kinetic.Global.extend(Kinetic.Line, Kinetic.Shape);
|
||||||
|
|
||||||
// add getters setters
|
// add getters setters
|
||||||
Kinetic.Node.addGetters(Kinetic.Line, ['points', 'spline']);
|
Kinetic.Node.addGetters(Kinetic.Line, ['points']);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get points array
|
* get points array
|
||||||
|
|||||||
118
src/shapes/Spline.js
Normal file
118
src/shapes/Spline.js
Normal file
@@ -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
|
||||||
|
*/
|
||||||
|
})();
|
||||||
@@ -47,87 +47,6 @@ Test.Modules.LINE = {
|
|||||||
line.setPoints([73, 160, 340, 23]);
|
line.setPoints([73, 160, 340, 23]);
|
||||||
test(line.getPoints()[0].x === 73, 'first point x should be 73');
|
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) {
|
'add dashed line': function(containerId) {
|
||||||
var stage = new Kinetic.Stage({
|
var stage = new Kinetic.Stage({
|
||||||
container: containerId,
|
container: containerId,
|
||||||
|
|||||||
83
tests/js/unit/shapes/splineTests.js
Normal file
83
tests/js/unit/shapes/splineTests.js
Normal file
@@ -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');
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user