Remove path to shape guess-work from SVGExport.

This commit is contained in:
Jürg Lehni 2013-10-16 23:21:29 +02:00
parent c4c7a37993
commit 772f8175e4

View file

@ -37,10 +37,6 @@ new function() {
document.createElementNS('http://www.w3.org/2000/svg', tag), attrs);
}
function getDistance(segments, index1, index2) {
return segments[index1]._point.getDistance(segments[index2]._point);
}
function getTransform(item, coordinates, center) {
var matrix = item._matrix,
trans = matrix.getTranslation(),
@ -80,97 +76,6 @@ new function() {
return attrs;
}
function determineAngle(path, segments, type, center) {
// If the object is a circle, ellipse, rectangle, or rounded rectangle,
// see if it is placed at an angle, by figuring out its topCenter point
// and measuring the angle to its center.
var topCenter = type === 'rect'
? segments[1]._point.add(segments[2]._point).divide(2)
: type === 'roundrect'
? segments[3]._point.add(segments[4]._point).divide(2)
: type === 'circle' || type === 'ellipse'
? segments[1]._point
: null;
var angle = topCenter && topCenter.subtract(center).getAngle() + 90;
return Numerical.isZero(angle || 0) ? 0 : angle;
}
function determineType(path, segments) {
// Returns true if the the two segment indices are the beggining of two
// lines and if the wto lines are parallel.
function isColinear(i, j) {
var seg1 = segments[i],
seg2 = seg1.getNext(),
seg3 = segments[j],
seg4 = seg3.getNext();
return seg1._handleOut.isZero() && seg2._handleIn.isZero()
&& seg3._handleOut.isZero() && seg4._handleIn.isZero()
&& seg2._point.subtract(seg1._point).isColinear(
seg4._point.subtract(seg3._point));
}
function isOrthogonal(i) {
var seg2 = segments[i],
seg1 = seg2.getPrevious(),
seg3 = seg2.getNext();
return seg2._point.subtract(seg1._point).isOrthogonal(
seg3._point.subtract(seg2._point));
}
// Returns true if the segment at the given index is the beginning of
// a orthogonal arc segment. The code is looking at the length of the
// handles and their relation to the distance to the imaginary corner
// point. If the relation is kappa, then it's an arc.
function isArc(i) {
var segment = segments[i],
next = segment.getNext(),
handle1 = segment._handleOut,
handle2 = next._handleIn,
kappa = Numerical.KAPPA;
if (handle1.isOrthogonal(handle2)) {
var from = segment._point,
to = next._point,
// Find the corner point by intersecting the lines described
// by both handles:
corner = new Line(from, handle1, true).intersect(
new Line(to, handle2, true), true);
return corner && Numerical.isZero(handle1.getLength() /
corner.subtract(from).getLength() - kappa)
&& Numerical.isZero(handle2.getLength() /
corner.subtract(to).getLength() - kappa);
}
}
// See if actually have any curves in the path. Differentiate
// between straight objects (line, polyline, rect, and polygon) and
// objects with curves(circle, ellipse, roundedRectangle).
if (path.isPolygon()) {
return segments.length === 4 && path._closed
&& isColinear(0, 2) && isColinear(1, 3) && isOrthogonal(1)
? 'rect'
: segments.length === 0
? 'empty'
: segments.length >= 3
? path._closed ? 'polygon' : 'polyline'
: 'line';
} else if (path._closed) {
if (segments.length === 8
&& isArc(0) && isArc(2) && isArc(4) && isArc(6)
&& isColinear(1, 5) && isColinear(3, 7)) {
return 'roundrect';
} else if (segments.length === 4
&& isArc(0) && isArc(1) && isArc(2) && isArc(3)) {
// If the distance between (point0 and point2) and (point1
// and point3) are equal, then it is a circle
return Numerical.isZero(getDistance(segments, 0, 2)
- getDistance(segments, 1, 3))
? 'circle'
: 'ellipse';
}
}
return 'path';
}
function exportGroup(item) {
var attrs = getTransform(item),
children = item._children;
@ -208,98 +113,34 @@ new function() {
function exportPath(item) {
var segments = item._segments,
center = item.getPosition(true),
type = determineType(item, segments),
angle = determineAngle(item, segments, type, center),
type,
attrs;
switch (type) {
case 'empty':
if (segments.length === 0)
return null;
case 'path':
if (item.isPolygon()) {
if (segments.length >= 3) {
type = item._closed ? 'polygon' : 'polyline';
var parts = [];
for(i = 0, l = segments.length; i < l; i++)
parts.push(formatter.point(segments[i]._point));
attrs = {
points: parts.join(' ')
};
} else {
type = 'line';
var first = segments[0]._point,
last = segments[segments.length - 1]._point;
attrs = {
x1: first.x,
y1: first.y,
x2: last.x,
y2: last.y
};
}
} else {
type = 'path';
var data = item.getPathData();
attrs = data && { d: data };
break;
case 'polyline':
case 'polygon':
var parts = [];
for(i = 0, l = segments.length; i < l; i++)
parts.push(formatter.point(segments[i]._point));
attrs = {
points: parts.join(' ')
};
break;
case 'rect':
var width = getDistance(segments, 0, 3),
height = getDistance(segments, 0, 1),
// Counter-compensate the determined rotation angle
point = segments[1]._point.rotate(-angle, center);
attrs = {
x: point.x,
y: point.y,
width: width,
height: height
};
break;
case 'roundrect':
type = 'rect';
// d-variables and point are used to determine the rounded corners
// for the rounded rectangle
var width = getDistance(segments, 1, 6),
height = getDistance(segments, 0, 3),
// Subtract side lengths from total width and divide by 2 to get
// corner radius size
rx = (width - getDistance(segments, 0, 7)) / 2,
ry = (height - getDistance(segments, 1, 2)) / 2,
// Calculate topLeft corner point, by using sides vectors and
// subtracting normalized rx vector to calculate arc corner.
left = segments[3]._point, // top-left side point
right = segments[4]._point, // top-right side point
point = left.subtract(right.subtract(left).normalize(rx))
// Counter-compensate the determined rotation angle
.rotate(-angle, center);
attrs = {
x: point.x,
y: point.y,
width: width,
height: height,
rx: rx,
ry: ry
};
break;
case'line':
var first = segments[0]._point,
last = segments[segments.length - 1]._point;
attrs = {
x1: first.x,
y1: first.y,
x2: last.x,
y2: last.y
};
break;
case 'circle':
var radius = getDistance(segments, 0, 2) / 2;
attrs = {
cx: center.x,
cy: center.y,
r: radius
};
break;
case 'ellipse':
var rx = getDistance(segments, 2, 0) / 2,
ry = getDistance(segments, 3, 1) / 2;
attrs = {
cx: center.x,
cy: center.y,
rx: rx,
ry: ry
};
break;
}
if (angle) {
attrs.transform = 'rotate(' + formatter.number(angle) + ','
+ formatter.point(center) + ')';
// Tell applyStyle() that to transform the gradient the other way
item._gradientMatrix = new Matrix().rotate(-angle, center);
}
return createElement(type, attrs);
}