Merge remote branch 'origin/master'

This commit is contained in:
Jonathan Puckey 2011-05-15 19:12:38 +02:00
commit a90aa09bd7
3 changed files with 74 additions and 61 deletions

View file

@ -15,19 +15,19 @@
*/ */
var CompoundPath = this.CompoundPath = PathItem.extend({ var CompoundPath = this.CompoundPath = PathItem.extend({
// PORT: port the reversing of segments and keepDirection flag initialize: function(paths) {
initialize: function(items, keepDirection) {
this.base(); this.base();
this._children = []; this._children = [];
if (items) { if (paths) {
for (var i = 0, l = items.length; i < l; i++) { for (var i = 0, l = paths.length; i < l; i++) {
var item = items[i]; var path = paths[i];
// All paths except for the first one are reversed when // All paths except for the top one (last one in list) are
// creating a compound path, so that they draw holes. // set to clockwise orientation when creating a compound path,
// When keepDirection is set to true, child paths aren't reversed. // so that they appear as holes, but only if their orientation
if (!keepDirection && i != l - 1) // was not already specified before (= _clockwise is defined).
item.reverse(); if (path._clockwise === undefined)
this.appendTop(items[i]); path.setClockwise(i < l - 1);
this.appendTop(path);
} }
} }
}, },

View file

@ -34,6 +34,8 @@ var Path = this.Path = PathItem.extend({
delete this._bounds; delete this._bounds;
delete this._position; delete this._position;
delete this._strokeBounds; delete this._strokeBounds;
// Clockwise state becomes undefined as soon as geometry changes.
delete this._clockwise;
} else if (flags & ChangeFlags.STROKE) { } else if (flags & ChangeFlags.STROKE) {
delete this._strokeBounds; delete this._strokeBounds;
} }
@ -302,20 +304,66 @@ var Path = this.Path = PathItem.extend({
// TODO: curvesToPoints([maxPointDistance[, flatness]]) // TODO: curvesToPoints([maxPointDistance[, flatness]])
// TODO: reduceSegments([flatness]) // TODO: reduceSegments([flatness])
// TODO: split(offset) / split(location) / split(index[, parameter]) // TODO: split(offset) / split(location) / split(index[, parameter])
/**
* Returns true if the path is oriented clock-wise, false otherwise.
*/
isClockwise: function() {
if (this._clockwise !== undefined)
return this._clockwise;
var sum = 0,
xPre, yPre;
function edge(x, y) {
if (xPre !== undefined)
sum += (xPre - x) * (y + yPre);
xPre = x;
yPre = y;
}
// Method derived from:
// http://stackoverflow.com/questions/1165647
// We treat the curve points and handles as the outline of a polygon of
// which we determine the orientation using the method of calculating
// the sum over the edges. This will work even with non-convex polygons,
// telling you whether it's mostly clockwise
for (var i = 0, l = this._segments.length; i < l; i++) {
var seg1 = this._segments[i],
seg2 = this._segments[i + 1 < l ? i + 1 : 0],
point1 = seg1._point,
handle1 = seg1._handleOut,
handle2 = seg2._handleIn,
point2 = seg2._point;
edge(point1._x, point1._y);
edge(point1._x + handle1._x, point1._y + handle1._y);
edge(point2._x + handle2._x, point2._y + handle2._y);
edge(point2._x, point2._y);
}
return this._clockwise = sum > 0;
},
setClockwise: function(clockwise) {
// On-the-fly conversion to boolean:
if (this.isClockwise() != (clockwise = !!clockwise)) {
// Only revers the path if its clockwise orientation is not the same
// as what it is now demanded to be.
this.reverse();
}
},
/** /**
* Reverses the segments of the path. * Reverses the segments of the path.
*/ */
reverse: function() { reverse: function() {
var segments = this._segments; this._segments.reverse();
segments.reverse();
// Reverse the handles: // Reverse the handles:
for (var i = 0, l = segments.length; i < l; i++) { for (var i = 0, l = this._segments.length; i < l; i++) {
var segment = segments[i]; var segment = this._segments[i];
var handleIn = segment._handleIn; var handleIn = segment._handleIn;
segment._handleIn = segment._handleOut; segment._handleIn = segment._handleOut;
segment._handleOut = handleIn; segment._handleOut = handleIn;
} }
// Flip clockwise state if it's defined
if (this._clockwise !== undefined)
this._clockwise = !this._clockwise;
}, },
join: function(path) { join: function(path) {
@ -356,31 +404,6 @@ var Path = this.Path = PathItem.extend({
return false; return false;
}, },
getOrientation: function() {
var sum = 0;
var xPre, yPre;
function edge(x, y) {
if (xPre !== undefined) {
sum += (xPre - x) * (y + yPre);
}
xPre = x;
yPre = y;
}
for (var i = 0, l = this._segments.length; i < l; i++) {
var seg1 = this._segments[i];
var seg2 = this._segments[i + 1 < l ? i + 1 : 0];
var point1 = seg1._point;
var handle1 = seg1._handleOut;
var handle2 = seg2._handleIn;
var point2 = seg2._point;
edge(point1._x, point1._y);
edge(point1._x + handle1._x, point1._y + handle1._y);
edge(point2._x + handle2._x, point2._y + handle2._y);
edge(point2._x, point2._y);
}
return sum;
},
getLength: function() { getLength: function() {
if (this._length == null) { if (this._length == null) {
var curves = this.getCurves(); var curves = this.getCurves();

View file

@ -25,9 +25,8 @@ var ToolHandler = this.ToolHandler = Base.extend({
this._firstMove = true; this._firstMove = true;
this._count = 0; this._count = 0;
this._downCount = 0; this._downCount = 0;
for (var i in handlers) { for (var i in handlers)
this[i] = handlers[i]; this[i] = handlers[i];
}
}, },
/** /**
@ -59,10 +58,8 @@ var ToolHandler = this.ToolHandler = Base.extend({
}, },
getFixedDistance: function() { getFixedDistance: function() {
if (this._minDistance == this._maxDistance) { return this._minDistance == this._maxDistance
return this._minDistance; ? this._minDistance : null;
}
return null;
}, },
setFixedDistance: function(distance) { setFixedDistance: function(distance) {
@ -77,9 +74,8 @@ var ToolHandler = this.ToolHandler = Base.extend({
var minDist = minDistance != null ? minDistance : 0; var minDist = minDistance != null ? minDistance : 0;
var vector = pt.subtract(this._point); var vector = pt.subtract(this._point);
var distance = vector.getLength(); var distance = vector.getLength();
if (distance < minDist) { if (distance < minDist)
return false; return false;
}
// Produce a new point on the way to pt if pt is further away // Produce a new point on the way to pt if pt is further away
// than maxDistance // than maxDistance
var maxDist = maxDistance != null ? maxDistance : 0; var maxDist = maxDistance != null ? maxDistance : 0;
@ -91,9 +87,8 @@ var ToolHandler = this.ToolHandler = Base.extend({
} }
} }
} }
if (needsChange && pt.equals(this._point)) { if (needsChange && pt.equals(this._point))
return false; return false;
}
} }
this._lastPoint = this._point; this._lastPoint = this._point;
this._point = pt; this._point = pt;
@ -118,9 +113,8 @@ var ToolHandler = this.ToolHandler = Base.extend({
switch (type) { switch (type) {
case 'mousedown': case 'mousedown':
this.updateEvent(type, pt, null, null, true, false, false); this.updateEvent(type, pt, null, null, true, false, false);
if (this.onMouseDown) { if (this.onMouseDown)
this.onMouseDown(new ToolEvent(this, type, event)); this.onMouseDown(new ToolEvent(this, type, event));
}
break; break;
case 'mousedrag': case 'mousedrag':
// In order for idleInterval drag events to work, we need to not // In order for idleInterval drag events to work, we need to not
@ -135,9 +129,8 @@ var ToolHandler = this.ToolHandler = Base.extend({
matchMaxDistance = false; matchMaxDistance = false;
while (this.updateEvent(type, pt, this.minDistance, while (this.updateEvent(type, pt, this.minDistance,
this.maxDistance, false, needsChange, matchMaxDistance)) { this.maxDistance, false, needsChange, matchMaxDistance)) {
if (this.onMouseDrag) { if (this.onMouseDrag)
this.onMouseDrag(new ToolEvent(this, type, event)); this.onMouseDrag(new ToolEvent(this, type, event));
}
needsChange = true; needsChange = true;
matchMaxDistance = true; matchMaxDistance = true;
} }
@ -148,15 +141,13 @@ var ToolHandler = this.ToolHandler = Base.extend({
if ((this._point.x != pt.x || this._point.y != pt.y) if ((this._point.x != pt.x || this._point.y != pt.y)
&& this.updateEvent('mousedrag', pt, this.minDistance, && this.updateEvent('mousedrag', pt, this.minDistance,
this.maxDistance, false, false, false)) { this.maxDistance, false, false, false)) {
if (this.onMouseDrag) { if (this.onMouseDrag)
this.onMouseDrag(new ToolEvent(this, type, event)); this.onMouseDrag(new ToolEvent(this, type, event));
}
} }
this.updateEvent(type, pt, null, this.maxDistance, false, this.updateEvent(type, pt, null, this.maxDistance, false,
false, false); false, false);
if (this.onMouseUp) { if (this.onMouseUp)
this.onMouseUp(new ToolEvent(this, type, event)); this.onMouseUp(new ToolEvent(this, type, event));
}
// Start with new values for 'mousemove' // Start with new values for 'mousemove'
this.updateEvent(type, pt, null, null, true, false, false); this.updateEvent(type, pt, null, null, true, false, false);
this._firstMove = true; this._firstMove = true;
@ -164,9 +155,8 @@ var ToolHandler = this.ToolHandler = Base.extend({
case 'mousemove': case 'mousemove':
while (this.updateEvent(type, pt, this.minDistance, while (this.updateEvent(type, pt, this.minDistance,
this.maxDistance, this._firstMove, true, false)) { this.maxDistance, this._firstMove, true, false)) {
if (this.onMouseMove) { if (this.onMouseMove)
this.onMouseMove(new ToolEvent(this, type, event)); this.onMouseMove(new ToolEvent(this, type, event));
}
this._firstMove = false; this._firstMove = false;
} }
break; break;