1 /**********************************************
2 * Copyright (C) 2010 Lukas Laag
3 * This file is part of lib-gwt-svg.
4 *
5 * libgwtsvg is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * libgwtsvg is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with libgwtsvg. If not, see http://www.gnu.org/licenses/
17 **********************************************/
18 /*
19 * Copyright (c) 2004 World Wide Web Consortium,
20 *
21 * (Massachusetts Institute of Technology, European Research Consortium for
22 * Informatics and Mathematics, Keio University). All Rights Reserved. This
23 * work is distributed under the W3C(r) Software License [1] in the hope that
24 * it will be useful, but WITHOUT ANY WARRANTY; without even the implied
25 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
26 *
27 * [1] http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
28 */
29
30 package org.vectomatic.dom.svg;
31
32 import org.vectomatic.dom.svg.utils.SVGConstants;
33
34 import com.google.gwt.core.client.JavaScriptException;
35 import com.google.gwt.core.client.JavaScriptObject;
36
37 /**
38 * {@link org.vectomatic.dom.svg.OMSVGTransform} is the interface for one
39 * of the component transformations within an {@link org.vectomatic.dom.svg.OMSVGTransformList};
40 * thus, an {@link org.vectomatic.dom.svg.OMSVGTransform} object corresponds
41 * to a single component (e.g., <span class='attr-value'>'scale(…)'</span>
42 * or <span class='attr-value'>'matrix(…)'</span>) within a <code>transform</code>
43 * attribute specification.
44 */
45 public class OMSVGTransform extends JavaScriptObject {
46 /**
47 * The unit type is not one of predefined types. It is invalid to attempt
48 * to define a new value of this type or to attempt to switch an existing
49 * value to this type.
50 */
51 public static final short SVG_TRANSFORM_UNKNOWN = 0;
52 /**
53 * A <span class='attr-value'>'matrix(…)'</span> transformation.
54 */
55 public static final short SVG_TRANSFORM_MATRIX = 1;
56 /**
57 * A <span class='attr-value'>'translate(…)'</span> transformation.
58 */
59 public static final short SVG_TRANSFORM_TRANSLATE = 2;
60 /**
61 * A <span class='attr-value'>'scale(…)'</span> transformation.
62 */
63 public static final short SVG_TRANSFORM_SCALE = 3;
64 /**
65 * A <span class='attr-value'>'rotate(…)'</span> transformation.
66 */
67 public static final short SVG_TRANSFORM_ROTATE = 4;
68 /**
69 * A <span class='attr-value'>'skewX(…)'</span> transformation.
70 */
71 public static final short SVG_TRANSFORM_SKEWX = 5;
72 /**
73 * A <span class='attr-value'>'skewY(…)'</span> transformation.
74 */
75 public static final short SVG_TRANSFORM_SKEWY = 6;
76 protected OMSVGTransform() {
77 }
78
79 // Implementation of the svg::SVGTransform W3C IDL interface
80 /**
81 * The type of the value as specified by one of the SVG_TRANSFORM_ constants
82 * defined on this interface.
83 */
84 public final native short getType() /*-{
85 return this.type;
86 }-*/;
87 /**
88 * <p>The matrix that represents this transformation. The matrix object is
89 * live, meaning that any changes made to the SVGTransform object are immediately
90 * reflected in the matrix object and vice versa. In case the matrix object
91 * is changed directly (i.e., without using the methods on the SVGTransform
92 * interface itself) then the type of the SVGTransform changes to SVG_TRANSFORM_MATRIX.
93 * </p> <ul> <li>For SVG_TRANSFORM_MATRIX, the matrix contains the {@link
94 * org.vectomatic.dom.svg.OMSVGMatrix#getA()}, {@link org.vectomatic.dom.svg.OMSVGMatrix#getB()},
95 * {@link org.vectomatic.dom.svg.OMSVGMatrix#getC()}, {@link org.vectomatic.dom.svg.OMSVGMatrix#getD()},
96 * {@link org.vectomatic.dom.svg.OMSVGMatrix#getE()}, {@link org.vectomatic.dom.svg.OMSVGMatrix#getF()}
97 * values supplied by the user.</li> <li>For SVG_TRANSFORM_TRANSLATE, {@link
98 * org.vectomatic.dom.svg.OMSVGMatrix#getE()} and {@link org.vectomatic.dom.svg.OMSVGMatrix#getF()}
99 * represent the translation amounts ({@link org.vectomatic.dom.svg.OMSVGMatrix#getA()}=1,
100 * {@link org.vectomatic.dom.svg.OMSVGMatrix#getB()}=0, {@link org.vectomatic.dom.svg.OMSVGMatrix#getC()}=0
101 * and {@link org.vectomatic.dom.svg.OMSVGMatrix#getD()}=1).</li> <li>For
102 * SVG_TRANSFORM_SCALE, {@link org.vectomatic.dom.svg.OMSVGMatrix#getA()}
103 * and {@link org.vectomatic.dom.svg.OMSVGMatrix#getD()} represent the translation
104 * amounts ({@link org.vectomatic.dom.svg.OMSVGMatrix#getB()}=0, {@link org.vectomatic.dom.svg.OMSVGMatrix#getC()}=0,
105 * {@link org.vectomatic.dom.svg.OMSVGMatrix#getE()}=0 and {@link org.vectomatic.dom.svg.OMSVGMatrix#getF()}=0).</li>
106 * <li>For SVG_TRANSFORM_ROTATE, SVG_TRANSFORM_SKEWX and SVG_TRANSFORM_SKEWY,
107 * {@link org.vectomatic.dom.svg.OMSVGMatrix#getA()}, {@link org.vectomatic.dom.svg.OMSVGMatrix#getB()},
108 * {@link org.vectomatic.dom.svg.OMSVGMatrix#getC()} and {@link org.vectomatic.dom.svg.OMSVGMatrix#getD()}
109 * represent the matrix which will result in the given transformation ({@link
110 * org.vectomatic.dom.svg.OMSVGMatrix#getE()}=0 and {@link org.vectomatic.dom.svg.OMSVGMatrix#getF()}=0).</li>
111 * </ul>
112 */
113 public final native OMSVGMatrix getMatrix() /*-{
114 return this.matrix;
115 }-*/;
116 /**
117 * <p>A convenience attribute for SVG_TRANSFORM_ROTATE, SVG_TRANSFORM_SKEWX
118 * and SVG_TRANSFORM_SKEWY. It holds the angle that was specified.</p> <p>For
119 * SVG_TRANSFORM_MATRIX, SVG_TRANSFORM_TRANSLATE and SVG_TRANSFORM_SCALE,
120 * {@link org.vectomatic.dom.svg.OMSVGTransform#getAngle()} will be zero.</p>
121 */
122 public final native float getAngle() /*-{
123 return this.angle;
124 }-*/;
125 /**
126 * <p xmlns:edit="http://xmlns.grorg.org/SVGT12NG/"> Sets the transform type
127 * to SVG_TRANSFORM_MATRIX, with parameter <var>matrix</var> defining the
128 * new transformation. The values from the parameter <var>matrix</var> are
129 * copied, the <var>matrix</var> parameter does not replace <a edit:format="expanded">SVGTransform::matrix</a>.
130 * </p>
131 * @param matrix The new matrix for the transformation.
132 * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) Raised on an attempt
133 * to change the value of a <a href="svgdom.html#ReadOnlyNodes">read only
134 * attribute</a>.
135 */
136 public final native void setMatrix(OMSVGMatrix matrix) throws JavaScriptException /*-{
137 this.setMatrix(matrix);
138 }-*/;
139 /**
140 * Sets the transform type to SVG_TRANSFORM_TRANSLATE, with parameters <var>tx</var>
141 * and <var>ty</var> defining the translation amounts.
142 * @param tx The translation amount in X.
143 * @param ty The translation amount in Y.
144 * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) Raised on an attempt
145 * to change the value of a <a href="svgdom.html#ReadOnlyNodes">read only
146 * attribute</a>.
147 */
148 public final native void setTranslate(float tx, float ty) throws JavaScriptException /*-{
149 this.setTranslate(tx, ty);
150 }-*/;
151 /**
152 * Sets the transform type to SVG_TRANSFORM_SCALE, with parameters <var>sx</var>
153 * and <var>sy</var> defining the scale amounts.
154 * @param sx The scale amount in X.
155 * @param sy The scale amount in Y.
156 * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) Raised on an attempt
157 * to change the value of a <a href="svgdom.html#ReadOnlyNodes">read only
158 * attribute</a>.
159 */
160 public final native void setScale(float sx, float sy) throws JavaScriptException /*-{
161 this.setScale(sx, sy);
162 }-*/;
163 /**
164 * Sets the transform type to SVG_TRANSFORM_ROTATE, with parameter <var>angle</var>
165 * defining the rotation angle and parameters <var>cx</var> and <var>cy</var>
166 * defining the optional center of rotation.
167 * @param angle The rotation angle.
168 * @param cx The x coordinate of center of rotation.
169 * @param cy The y coordinate of center of rotation.
170 * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) Raised on an attempt
171 * to change the value of a <a href="svgdom.html#ReadOnlyNodes">read only
172 * attribute</a>.
173 */
174 public final native void setRotate(float angle, float cx, float cy) throws JavaScriptException /*-{
175 this.setRotate(angle, cx, cy);
176 }-*/;
177 /**
178 * Sets the transform type to SVG_TRANSFORM_SKEWX, with parameter <var>angle</var>
179 * defining the amount of skew.
180 * @param angle The skew angle.
181 * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) Raised on an attempt
182 * to change the value of a <a href="svgdom.html#ReadOnlyNodes">read only
183 * attribute</a>.
184 */
185 public final native void setSkewX(float angle) throws JavaScriptException /*-{
186 this.setSkewX(angle);
187 }-*/;
188 /**
189 * Sets the transform type to SVG_TRANSFORM_SKEWY, with parameter <var>angle</var>
190 * defining the amount of skew.
191 * @param angle The skew angle.
192 * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) Raised on an attempt
193 * to change the value of a <a href="svgdom.html#ReadOnlyNodes">read only
194 * attribute</a>.
195 */
196 public final native void setSkewY(float angle) throws JavaScriptException /*-{
197 this.setSkewY(angle);
198 }-*/;
199
200 // Helper methods
201 /**
202 * Returns a textual description of the transform for debugging purposes.
203 * @return a textual description of the transform.
204 */
205 public final String getDescription() {
206 StringBuilder builder = new StringBuilder();
207 switch(getType()) {
208 case SVG_TRANSFORM_MATRIX:
209 builder.append(SVGConstants.TRANSFORM_MATRIX + "(");
210 builder.append(getMatrix().getDescription());
211 builder.append(")");
212 break;
213 case SVG_TRANSFORM_TRANSLATE:
214 builder.append(SVGConstants.TRANSFORM_TRANSLATE + "(");
215 builder.append(getMatrix().getE());
216 builder.append(",");
217 builder.append(getMatrix().getF());
218 builder.append(")");
219 break;
220 case SVG_TRANSFORM_SCALE:
221 builder.append(SVGConstants.TRANSFORM_SCALE + "(");
222 builder.append(getMatrix().getA());
223 builder.append(",");
224 builder.append(getMatrix().getD());
225 builder.append(")");
226 break;
227 case SVG_TRANSFORM_ROTATE:
228 builder.append(SVGConstants.TRANSFORM_ROTATE + "(");
229 builder.append(getAngle());
230 if (getMatrix().getE() != 0f || getMatrix().getF() != 0f) {
231 if (getAngle() == 0f) {
232 builder.append(",");
233 builder.append(getMatrix().getE());
234 builder.append(",");
235 builder.append(getMatrix().getF());
236 } else {
237 float a = (float)(1 - Math.cos(getAngle() * 2 * Math.PI / 360));
238 float b = (float)Math.sin(getAngle() * 2 * Math.PI / 360);
239 float c = -b;
240 float d = a;
241 float det = a * d - b * c;
242 float x = (getMatrix().getE() * d - b * getMatrix().getF()) / det;
243 float y = (a * getMatrix().getF() - getMatrix().getE() * c) / det;
244 builder.append(",");
245 builder.append(x);
246 builder.append(",");
247 builder.append(y);
248 }
249 }
250 builder.append(")");
251 break;
252 case SVG_TRANSFORM_SKEWX:
253 builder.append(SVGConstants.TRANSFORM_SKEWX + "(");
254 builder.append(getAngle());
255 builder.append(")");
256 break;
257 case SVG_TRANSFORM_SKEWY:
258 builder.append(SVGConstants.TRANSFORM_SKEWY + "(");
259 builder.append(getAngle());
260 builder.append(")");
261 break;
262 case SVG_TRANSFORM_UNKNOWN:
263 default:
264 builder.append(toString());
265 break;
266 }
267 return builder.toString();
268 }
269 /**
270 * Specifies a scaling transform around a center point.
271 * The resulting transform type is set to SVG_TRANSFORM_MATRIX.
272 * @param sx The scale amount in X.
273 * @param sy The scale amount in Y.
274 * @param tx The X coordinate of the scaling center.
275 * @param ty The Y coordinate of the scaling center.
276 * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) Raised on an attempt
277 * to change the value of a <a href="svgdom.html#ReadOnlyNodes">read only
278 * attribute</a>.
279 */
280 public final void setScale(float sx, float sy, float tx, float ty) throws JavaScriptException {
281 OMSVGMatrix m = getMatrix();
282 m.setA(sx);
283 m.setB(0);
284 m.setC(0);
285 m.setD(sy);
286 m.setE(tx * ( 1 - sx ));
287 m.setF(ty * ( 1 - sy ));
288 }
289 }