From d9bfc2fa356526c5ff651ae2657dbefb823c5f03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Tue, 6 Nov 2012 10:02:40 -0800 Subject: [PATCH] Implement Matrix support in SvgExporter. --- src/basic/Matrix.js | 1 + src/svg/SvgExporter.js | 78 ++++++++++++++++++++++++++---------------- 2 files changed, 50 insertions(+), 29 deletions(-) diff --git a/src/basic/Matrix.js b/src/basic/Matrix.js index 03e14f7d..edf0287f 100644 --- a/src/basic/Matrix.js +++ b/src/basic/Matrix.js @@ -471,6 +471,7 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ }, getScaling: function() { + // http://math.stackexchange.com/questions/13150/ var hor = Math.sqrt(this._a * this._a + this._c * this._c), ver = Math.sqrt(this._b * this._b + this._d * this._d); return Point.create(this._a < 0 ? -hor : hor, this._b < 0 ? -ver : ver); diff --git a/src/svg/SvgExporter.js b/src/svg/SvgExporter.js index 7231d2ff..9c60a79b 100644 --- a/src/svg/SvgExporter.js +++ b/src/svg/SvgExporter.js @@ -51,38 +51,60 @@ var SvgExporter = this.SvgExporter = new function() { return segments[index1]._point.getDistance(segments[index2]._point); } + function getTransform(item) { + var matrix = item._matrix.createShiftless(), + trans = matrix._inverseTransform(item._matrix.getTranslation()), + attrs = { + x: trans.x, + y: trans.y + }; + if (matrix.isIdentity()) + return attrs; + // See if we can formulate this matrix as simple scale / rotate commands + // Note: getScaling() returns values also when it's not a simple scale, + // but angle is only != null if it is, so check for that. + var transform = [], + angle = matrix.getRotation(), + scale = matrix.getScaling(); + if (angle != null) { + transform.push(angle + ? 'rotate(' + angle + ',' + formatPoint(center) +')' + : 'scale(' + formatPoint(scale) +')'); + } else { + transform.push('matrix(' + matrix.getValues().join(',') + ')'); + } + attrs.transform = transform.join(' '); + return attrs; + } + function exportGroup(group) { - var svg = createElement('g'), + var attrs = getTransform(group), children = group._children; + // Override default SVG style on groups, then apply style. + attrs.fill = 'none'; + var svg = createElement('g', attrs); for (var i = 0, l = children.length; i < l; i++) svg.appendChild(SvgExporter.exportItem(children[i])); - // Override default SVG style on groups, then apply style. - return setAttributes(svg, { - fill: 'none' - }); + return svg; } function exportText(item) { - var point = item.getPoint(), - style = item._style, - attrs = { - x: point._x, - y: point._y - }; + var attrs = getTransform(item), + style = item._style; if (style._font != null) attrs['font-family'] = style._font; if (style._fontSize != null) attrs['font-size'] = style._fontSize; var svg = createElement('text', attrs); - svg.textContent = item.getContent(); - svg.setAttribute('transform','rotate(' + item.matrix.getRotation() + ',' + item.getPoint()._x + ',' + item.getPoint()._y +')'); + svg.textContent = item._content; return svg; } function exportPath(path) { var segments = path._segments, + center = path.getPosition(true), type = determineType(path, segments), - angle = determineAngle(path, segments, type), + angle = determineAngle(path, segments, type, center), attrs; switch (type) { case 'path': @@ -105,7 +127,7 @@ var SvgExporter = this.SvgExporter = new function() { var width = getDistance(segments, 0, 3), height = getDistance(segments, 0, 1), // Counter-compensate the determined rotation angle - point = segments[1]._point.rotate(-angle, path.getPosition()); + point = segments[1]._point.rotate(-angle, center); attrs = { x: point.x, y: point.y, @@ -129,7 +151,7 @@ var SvgExporter = this.SvgExporter = new function() { right = segments[4]._point, // top-right side point point = left.subtract(right.subtract(left).normalize(rx)) // Counter-compensate the determined rotation angle - .rotate(-angle, path.getPosition()); + .rotate(-angle, center); attrs = { x: point.x, y: point.y, @@ -150,31 +172,29 @@ var SvgExporter = this.SvgExporter = new function() { }; break; case 'circle': - var radius = getDistance(segments, 0, 2) / 2, - center = path.getPosition(); + var radius = getDistance(segments, 0, 2) / 2; attrs = { - cx: center._x, - cy: center._y, + cx: center.x, + cy: center.y, r: radius }; break; case 'ellipse': var rx = getDistance(segments, 2, 0) / 2, - ry = getDistance(segments, 3, 1) / 2, - center = path.getPosition(); + ry = getDistance(segments, 3, 1) / 2; attrs = { - cx: center._x, - cy: center._y, + cx: center.x, + cy: center.y, rx: rx, ry: ry }; break; } - var svg = createElement(type, attrs); if (angle) { - svg.setAttribute('transform', 'rotate(' + formatNumber(angle) + ',' - + formatPoint(path.getPosition()) + ')'); + attrs.transform = 'rotate(' + formatNumber(angle) + ',' + + formatPoint(center) + ')'; } + var svg = createElement(type, attrs); return svg; } @@ -213,7 +233,7 @@ var SvgExporter = this.SvgExporter = new function() { return parts.join(' '); } - function determineAngle(path, segments, type) { + function determineAngle(path, segments, type, center) { // If the object is a circle, ellipse, rectangle, or rounded rectangle, // see if they are placed at an angle. var topCenter = type === 'rect' @@ -224,7 +244,7 @@ var SvgExporter = this.SvgExporter = new function() { ? segments[1]._point : null; if (topCenter) { - var angle = topCenter.subtract(path.getPosition()).getAngle() + 90; + var angle = topCenter.subtract(center).getAngle() + 90; return Numerical.isZero(angle) ? 0 : angle; } return 0;