mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-01 02:38:43 -05:00
Big refactoring of how curves are kept in sync with segments (direct references rather than indices), along with various tests.
This commit is contained in:
parent
47c88a1252
commit
a0e211c691
4 changed files with 110 additions and 55 deletions
|
@ -93,6 +93,7 @@ if (window.tests) {
|
|||
'test/tests/Path.js',
|
||||
'test/tests/Path_Shapes.js',
|
||||
'test/tests/Path_Drawing_Commands.js',
|
||||
'test/tests/Path_Curves.js',
|
||||
'test/tests/Path_Bounds.js',
|
||||
'test/tests/Path_Length.js',
|
||||
'test/tests/PathStyle.js',
|
||||
|
|
|
@ -40,18 +40,6 @@ var Curve = this.Curve = Base.extend({
|
|||
delete this._length;
|
||||
},
|
||||
|
||||
_updateSegments: function() {
|
||||
if (this._path) {
|
||||
this._index2 = this._index1 + 1;
|
||||
// A closing curve?
|
||||
var segments = this._path._segments;
|
||||
if (this._index2 >= segments.length)
|
||||
this._index2 = 0;
|
||||
this._segment1 = segments[this._index1];
|
||||
this._segment2 = segments[this._index2];
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The first anchor point of the curve.
|
||||
*/
|
||||
|
@ -119,19 +107,18 @@ var Curve = this.Curve = Base.extend({
|
|||
},
|
||||
|
||||
getIndex: function() {
|
||||
return this._index1;
|
||||
return this._segment1._index;
|
||||
},
|
||||
|
||||
getNext: function() {
|
||||
// TODO: No need to call getCurves() here?
|
||||
var curves = this._path && this._path._curves;
|
||||
return curves && (curves[this._index1 + 1]
|
||||
return curves && (curves[this._segment1._index + 1]
|
||||
|| this._path._closed && curves[0]) || null;
|
||||
},
|
||||
|
||||
getPrevious: function() {
|
||||
var curves = this._path && this._path._curves;
|
||||
return curves && (curves[this._index1 - 1]
|
||||
return curves && (curves[this._segment1._index - 1]
|
||||
|| this._path._closed && curves[curves.length - 1]) || null;
|
||||
},
|
||||
|
||||
|
@ -226,11 +213,11 @@ var Curve = this.Curve = Base.extend({
|
|||
},
|
||||
|
||||
statics: {
|
||||
create: function(path, index) {
|
||||
create: function(path, segment1, segment2) {
|
||||
var curve = new Curve(Curve.dont);
|
||||
curve._path = path;
|
||||
curve._index1 = index;
|
||||
curve._updateSegments();
|
||||
curve._segment1 = segment1;
|
||||
curve._segment2 = segment2;
|
||||
return curve;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,13 +69,16 @@ var Path = this.Path = PathItem.extend({
|
|||
*/
|
||||
getCurves: function() {
|
||||
if (!this._curves) {
|
||||
var length = this._segments.length;
|
||||
var segments = this._segments,
|
||||
length = segments.length;
|
||||
// Reduce length by one if it's an open path:
|
||||
if (!this._closed && length > 0)
|
||||
length--;
|
||||
this._curves = new Array(length);
|
||||
for (var i = 0; i < length; i++)
|
||||
this._curves[i] = Curve.create(this, i);
|
||||
this._curves[i] = Curve.create(this, segments[i],
|
||||
// Use first segment for segment2 of closing curve
|
||||
segments[i + 1] || segments[0]);
|
||||
}
|
||||
return this._curves;
|
||||
},
|
||||
|
@ -107,7 +110,8 @@ var Path = this.Path = PathItem.extend({
|
|||
this._curves.length = length;
|
||||
// If we were closing this path, we need to add a new curve now
|
||||
if (closed)
|
||||
this._curves[i = length - 1] = Curve.create(this, i);
|
||||
this._curves[i = length - 1] = Curve.create(this,
|
||||
this._segments[i], this._segments[0]);
|
||||
}
|
||||
this._changed();
|
||||
}
|
||||
|
@ -135,42 +139,37 @@ var Path = this.Path = PathItem.extend({
|
|||
*/
|
||||
// TODO: Add support for adding multiple segments at once
|
||||
_add: function(segment, index) {
|
||||
// Local short-cuts:
|
||||
var segments = this._segments,
|
||||
curves = this._curves;
|
||||
// If this segment belongs to another path already, clone it before
|
||||
// adding.
|
||||
if (segment._path)
|
||||
segment = new Segment(segment);
|
||||
if (index === undefined) {
|
||||
// Insert at the end
|
||||
index = this._segments.push(segment) - 1;
|
||||
index = segments.push(segment) - 1;
|
||||
} else {
|
||||
// Insert somewhere else
|
||||
this._segments.splice(index, 0, segment);
|
||||
segments.splice(index, 0, segment);
|
||||
// Adjust the indices of the segments above.
|
||||
for (var i = index + 1, l = this._segments.length; i < l; i++)
|
||||
this._segments[i]._index = i;
|
||||
for (var i = index + 1, l = segments.length; i < l; i++)
|
||||
segments[i]._index = i;
|
||||
}
|
||||
segment._path = this;
|
||||
segment._index = index;
|
||||
// Keep the curves list in sync all the time in case it as requested
|
||||
// already. We need to step one index down from the inserted segment to
|
||||
// get its curve:
|
||||
if (this._curves && --index >= 0) {
|
||||
if (curves && --index >= 0) {
|
||||
// Insert a new curve as well and update the curves above
|
||||
this._curves.splice(index, 0, Curve.create(this, index));
|
||||
// Adjust indices now for the curves above this one.
|
||||
for (var i = index + 1, l = this._curves.length; i < l; i++) {
|
||||
var curve = this._curves[i];
|
||||
curve._index1 = i;
|
||||
// This is wrong for the last closing curve but it will be
|
||||
// corrected further down.
|
||||
curve._index2 = i + 1;
|
||||
}
|
||||
// The curve that comes right after will has changed beyond a simple
|
||||
// shift in indices, so it needs an update:
|
||||
this._curves[index + 1]._updateSegments();
|
||||
// If this is a closed path, also update the closing curve
|
||||
if (this._closed)
|
||||
this._curves[l - 1]._updateSegments();
|
||||
curves.splice(index, 0, Curve.create(this, segments[index],
|
||||
segments[++index]));
|
||||
// Adjust segment1 now for the curves above the inserted one
|
||||
// (note the ++index in the statement above)/
|
||||
var curve = curves[index];
|
||||
if (curve)
|
||||
curve._segment1 = segments[index];
|
||||
}
|
||||
this._changed();
|
||||
return segment;
|
||||
|
@ -198,21 +197,40 @@ var Path = this.Path = PathItem.extend({
|
|||
removeSegments: function(from, to) {
|
||||
from = from || 0;
|
||||
to = Base.pick(to, this._segments.length - 1);
|
||||
var amount = to - from,
|
||||
segments = this._segments.splice(from, amount);
|
||||
if (segments.length == amount) {
|
||||
// TODO: Keep _curves in sync
|
||||
for (var i = 0; i < amount; i++) {
|
||||
var segment = segments[0];
|
||||
if (segment._selectionState) {
|
||||
this._selectedSegmentCount--;
|
||||
segment._selectionState = 0;
|
||||
}
|
||||
var segments = this._segments,
|
||||
curves = this._curves,
|
||||
last = to >= segments.length,
|
||||
removed = segments.splice(from, to - from),
|
||||
amount = removed.length;
|
||||
if (!amount)
|
||||
return removed;
|
||||
// Update selection state accordingly
|
||||
for (var i = 0; i < amount; i++) {
|
||||
var segment = removed[i];
|
||||
if (segment._selectionState) {
|
||||
this._selectedSegmentCount--;
|
||||
segment._selectionState = 0;
|
||||
}
|
||||
this._changed();
|
||||
return segments;
|
||||
}
|
||||
return null;
|
||||
// Adjust the indices of the segments above.
|
||||
for (var i = from, l = segments.length; i < l; i++)
|
||||
segments[i]._index = i;
|
||||
// Keep curves in sync
|
||||
if (curves) {
|
||||
curves.splice(from, amount);
|
||||
// Adjust segments for the curves before and after the removed ones
|
||||
var curve;
|
||||
if (curve = curves[from - 1])
|
||||
curve._segment2 = segments[from];
|
||||
if (curve = curves[from])
|
||||
curve._segment1 = segments[from];
|
||||
// If the last segment of a closing path was removed, we need to
|
||||
// readjust the last curve of the list now.
|
||||
if (last && this._closed && (curve = curves[curves.length - 1]))
|
||||
curve._segment2 = segments[0];
|
||||
}
|
||||
this._changed();
|
||||
return removed;
|
||||
},
|
||||
|
||||
isSelected: function() {
|
||||
|
|
49
test/tests/Path_Curves.js
Normal file
49
test/tests/Path_Curves.js
Normal file
|
@ -0,0 +1,49 @@
|
|||
module('Path Curves');
|
||||
|
||||
test('path.curves Synchronisation', function() {
|
||||
|
||||
var doc = new Document();
|
||||
var path = new Path();
|
||||
|
||||
path.add(new Point(0, 100));
|
||||
equals(path.curves.toString(), '');
|
||||
|
||||
path.add(new Point(100, 100));
|
||||
equals(path.curves.toString(),
|
||||
'{ point1: { x: 0, y: 100 }, point2: { x: 100, y: 100 } }',
|
||||
'2 x path.add()');
|
||||
|
||||
path.insert(1, { point: [50, 0], handleIn: [-25, 0], handleOut: [25, 0] });
|
||||
equals(path.curves.toString(),
|
||||
'{ point1: { x: 0, y: 100 }, handle2: { x: -25, y: 0 }, point2: { x: 50, y: 0 } },{ point1: { x: 50, y: 0 }, handle1: { x: 25, y: 0 }, point2: { x: 100, y: 100 } }',
|
||||
'path.insert()'
|
||||
);
|
||||
|
||||
path.closed = true;
|
||||
equals(path.curves.toString(),
|
||||
'{ point1: { x: 0, y: 100 }, handle2: { x: -25, y: 0 }, point2: { x: 50, y: 0 } },{ point1: { x: 50, y: 0 }, handle1: { x: 25, y: 0 }, point2: { x: 100, y: 100 } },{ point1: { x: 100, y: 100 }, point2: { x: 0, y: 100 } }',
|
||||
'path.closed = true');
|
||||
|
||||
path.removeSegments(2, 3);
|
||||
equals(path.curves.toString(),
|
||||
'{ point1: { x: 0, y: 100 }, handle2: { x: -25, y: 0 }, point2: { x: 50, y: 0 } },{ point1: { x: 50, y: 0 }, handle1: { x: 25, y: 0 }, point2: { x: 0, y: 100 } }',
|
||||
'path.removeSegments(2, 3)');
|
||||
|
||||
equals(path.segments.toString(),
|
||||
'{ point: { x: 0, y: 100 } },{ point: { x: 50, y: 0 }, handleIn: { x: -25, y: 0 }, handleOut: { x: 25, y: 0 } }',
|
||||
'segments');
|
||||
|
||||
path.add(new Point(100, 100));
|
||||
equals(path.curves.toString(),
|
||||
'{ point1: { x: 0, y: 100 }, handle2: { x: -25, y: 0 }, point2: { x: 50, y: 0 } },{ point1: { x: 50, y: 0 }, handle1: { x: 25, y: 0 }, point2: { x: 100, y: 100 } },{ point1: { x: 100, y: 100 }, point2: { x: 0, y: 100 } }',
|
||||
'path.add()');
|
||||
|
||||
path.removeSegments(1, 2);
|
||||
equals(path.curves.toString(),
|
||||
'{ point1: { x: 0, y: 100 }, point2: { x: 100, y: 100 } },{ point1: { x: 100, y: 100 }, point2: { x: 0, y: 100 } }',
|
||||
'path.removeSegments(1, 2)');
|
||||
|
||||
equals(path.segments.toString(),
|
||||
'{ point: { x: 0, y: 100 } },{ point: { x: 100, y: 100 } }',
|
||||
'segments');
|
||||
});
|
Loading…
Reference in a new issue