001 
002 /*
003  *  JScripter Standard 1.0 - To Script In Java
004  *  Copyright (C) 2008-2011  J.J.Liu<jianjunliu@126.com> <http://www.jscripter.org>
005  *  
006  *  This program is free software: you can redistribute it and/or modify
007  *  it under the terms of the GNU Affero General Public License as published by
008  *  the Free Software Foundation, either version 3 of the License, or
009  *  (at your option) any later version.
010  *  
011  *  This program is distributed in the hope that it will be useful,
012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014  *  GNU Affero General Public License for more details.
015  *  
016  *  You should have received a copy of the GNU Affero General Public License
017  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
018  */
019 
020 package jsx.graphic;
021 
022 import js.ArrayLike;
023 import js.Disposable;
024 import js.Js;
025 import js.Vars;
026 import jsx.core.ArrayLikes;
027 import jsx.ui.Component;
028 
029 /**
030  * <p>A utility class providing static methods to create basic SVG components.</p>
031  * <p>A SVG component wraps an HTML <tt>&lt;svg:svg&gt;</tt> element, a SVG path element 
032  * or a SVG shape element.</p>
033  * 
034  * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
035  */
036 public final class SVG extends Disposable
037 {
038     private SVG() {}
039 
040     /**
041      * <p>Creates a SVG component that wraps an HTML <tt>&lt;svg:svg&gt;</tt> element.</p>
042      * @return The newly created SVG component.
043      * @since 1.0
044      */
045     public static final Component svg() {
046         return Component.createElementNS(SVG_NS, SVG);
047     }
048 
049     /**
050      * <p>Sets view box attributes to a SVG component.</p>
051      * @param v The current SVG component.
052      * @param x The X coordinate of the base point.
053      * @param y The Y coordinate of the base point.
054      * @param w The X dimension.
055      * @param h The Y dimension.
056      * @since 1.0
057      */
058     public static final void viewBox(Component v, double x, double y, double w, double h) {
059         Component.setAttribute(v, VIEWBOX, ArrayLikes.join(
060                 new Vars<Object>().add(x).add(y).add(w).add(h).var(),
061                 SPACE
062         ));
063     }
064 
065     /**
066      * <p>Sets view box attributes to a SVG component.</p>
067      * @param v The current SVG component.
068      * @param s A string of the attribute value to set.
069      * @since 1.0
070      */
071     public static final void viewBox(Component v, String s) {
072         Component.setAttribute(v, VIEWBOX, s);
073     }
074 
075     /**
076      * <p>Defines the XLink name space that SVG uses.</p>
077      * @param v The current SVG component.
078      * @since 1.0
079      */
080     public static final void xlink(Component v) {
081         Component.setAttributeNS(v, XML_NS, "xmlns:xlink", XLINKNS);
082     }
083 
084     /**
085      * <p>A constant string of a space.</p>
086      * @since 1.0
087      */
088     public final static String SPACE = " ";
089 
090     /**
091      * <p>The name of a SVG element.</p>
092      * @since 1.0
093      */
094     public final static String RECT     = "rect";
095     /**
096      * <p>The name of a SVG element.</p>
097      * @since 1.0
098      */
099     public final static String CIRCLE   = "circle";
100     /**
101      * <p>The name of a SVG element.</p>
102      * @since 1.0
103      */
104     public final static String ELLIPSE  = "ellipse";
105     /**
106      * <p>The name of a SVG element.</p>
107      * @since 1.0
108      */
109     public final static String LINE     = "line";
110     /**
111      * <p>The name of a SVG element.</p>
112      * @since 1.0
113      */
114     public final static String PATH     = "path";
115     /**
116      * <p>The name of a SVG element.</p>
117      * @since 1.0
118      */
119     public final static String POLYLINE = "polyline";
120     /**
121      * <p>The name of a SVG element.</p>
122      * @since 1.0
123      */
124     public final static String POLYGON  = "polygon";
125 
126     /**
127      * <p>The XML name space.</p>
128      * @since 1.0
129      */
130     public final static String XML_NS  = "http://www.w3.org/2000/xmlns";
131     /**
132      * <p>The SVG name space.</p>
133      * @since 1.0
134      */
135     public final static String SVG_NS  = "http://www.w3.org/2000/svg";
136     /**
137      * <p>The XLink name space.</p>
138      * @since 1.0
139      */
140     public final static String XLINKNS = "http://www.w3.org/1999/xlink";
141 
142     /**
143      * <p>The HTML tag name for a root SVG element.</p>
144      * @since 1.0
145      */
146     public final static String SVG = "svg:svg";
147     /**
148      * <p>The name of an attribute for a path element to define itself.</p>
149      * @since 1.0
150      */
151     public final static String DEF = "d";
152 
153     /**
154      * <p>The name of a <tt>width</tt> attribute.</p>
155      * @since 1.0
156      */
157     public final static String WIDTH   = "width";
158     /**
159      * <p>The name of a <tt>height</tt> attribute.</p>
160      * @since 1.0
161      */
162     public final static String HEIGHT  = "height";
163     /**
164      * <p>The name of a <tt>viewBox</tt> attribute.</p>
165      * @since 1.0
166      */
167     public final static String VIEWBOX = "viewBox";
168 
169     /**
170      * <p>Represents the specified coordinates in a string.</p>
171      * @param x The X coordinate.
172      * @param y The Y coordinate.
173      * @return A string representation for the coordinates.
174      * @since 1.0
175      */
176     public static final String coord(double x, double y) {
177         return ArrayLikes.join(
178                 new Vars<Object>().add(x).add(y).var()
179         );
180     }
181 
182     /**
183      * <p>Creates SVG component that wraps a "rect" element.</p>
184      * @return A SVG component wrapping a basic shape element.
185      * @since 1.0
186      * @see #rectFrom(Component, double, double)
187      * @see #rectSize(Component, double, double)
188      * @see #rectRound(Component, double, double)
189      */
190     public static final Component rect() {
191         return Component.createElementNS(SVG_NS, RECT);
192     }
193 
194     /**
195      * <p>Defines the base point of a rectangle by setting attributes to the SVG 
196      * element wrapped by the specified component.</p>
197      * @param v The current SVG component.
198      * @param x The X coordinate of the base point.
199      * @param y The Y coordinate of the base point.
200      * @since 1.0
201      * @see #rect()
202      * @see #rectSize(Component, double, double)
203      * @see #rectRound(Component, double, double)
204      */
205     public static final void rectFrom(Component v, double x, double y) {
206         Component.setAttribute(v, "x", x);
207         Component.setAttribute(v, "y", y);
208     }
209 
210     /**
211      * <p>Defines the size of a rectangle by setting attributes to the SVG 
212      * element wrapped by the specified component.</p>
213      * @param v The current SVG component.
214      * @param w The X dimension.
215      * @param h The Y dimension.
216      * @since 1.0
217      * @see #rect()
218      * @see #rectFrom(Component, double, double)
219      * @see #rectRound(Component, double, double)
220      */
221     public static final void rectSize(Component v, double w, double h) {
222         Component.setAttribute(v, WIDTH , w);
223         Component.setAttribute(v, HEIGHT, h);
224     }
225 
226     /**
227      * <p>Rounds off the corners of a rectangle by setting attributes to the SVG 
228      * element wrapped by the specified component.</p>
229      * @param v The current SVG component.
230      * @param rx The X-axis radius of the ellipse used to round off the corners of 
231      * the rectangle.
232      * @param ry The Y-axis radius of the ellipse used to round off the corners of 
233      * the rectangle.
234      * @since 1.0
235      * @see #rect()
236      * @see #rectFrom(Component, double, double)
237      * @see #rectSize(Component, double, double)
238      */
239     public static final void rectRound(Component v, double rx, double ry) {
240         Component.setAttribute(v, "rx", rx);
241         Component.setAttribute(v, "ry", ry);
242     }
243 
244     /**
245      * <p>Creates SVG component that wraps a "rect" element.</p>
246      * @param x The X coordinate of the base point.
247      * @param y The Y coordinate of the base point.
248      * @param w The X dimension.
249      * @param h The Y dimension.
250      * @return A SVG component wrapping a basic shape element.
251      * @since 1.0
252      * @see #rect()
253      * @see #rect(double, double, double, double, double, double)
254      */
255     public static final Component rect(double x, double y, double w, double h) {
256         Component v = rect();
257         rectFrom(v, x, y);
258         rectSize(v, w, h);
259         return v;
260     }
261 
262     /**
263      * <p>Creates SVG component that wraps a "rect" element.</p>
264      * @param x The X coordinate of the base point.
265      * @param y The Y coordinate of the base point.
266      * @param w The X dimension.
267      * @param h The Y dimension.
268      * @param rx The X-axis radius of the ellipse used to round off the corners of 
269      * the rectangle.
270      * @param ry The Y-axis radius of the ellipse used to round off the corners of 
271      * the rectangle.
272      * @return A SVG component wrapping a basic shape element.
273      * @since 1.0
274      * @see #rect()
275      * @see #rect(double, double, double, double)
276      */
277     public static final Component rect(double x, double y, double w, double h, double rx, double ry) {
278         Component v = rect(x, y, w, h);
279         rectRound(v, rx, ry);
280         return v;
281     }
282 
283     /**
284      * <p>Creates SVG component that wraps a "circle" element.</p>
285      * @return A SVG component wrapping a basic shape element.
286      * @since 1.0
287      * @see #circle(double, double, double)
288      * @see #circleCenter(Component, double, double)
289      * @see #circleRadius(Component, double)
290      */
291     public static final Component circle() {
292         return Component.createElementNS(SVG_NS, CIRCLE);
293     }
294 
295     /**
296      * <p>Defines the center of a circle by setting attributes to the SVG 
297      * element wrapped by the specified component.</p>
298      * @param v The current SVG component.
299      * @param cx The X coordinate of the center of the circle.
300      * @param cy The Y coordinate of the center of the circle.
301      * @since 1.0
302      * @see #circle()
303      * @see #circleRadius(Component, double)
304      */
305     public static final void circleCenter(Component v, double cx, double cy) {
306         Component.setAttribute(v, "cx", cx);
307         Component.setAttribute(v, "cy", cy);
308     }
309 
310     /**
311      * <p>Defines the radius of a circle by setting attributes to the SVG 
312      * element wrapped by the specified component.</p>
313      * @param v The current SVG component.
314      * @param r The radius of the circle.
315      * @since 1.0
316      * @see #circle()
317      * @see #circleCenter(Component, double, double)
318      */
319     public static final void circleRadius(Component v, double r) {
320         Component.setAttribute(v, "r", r);
321     }
322 
323     /**
324      * <p>Creates SVG component that wraps a "circle" element.</p>
325      * @param cx The X coordinate of the center of the circle.
326      * @param cy The Y coordinate of the center of the circle.
327      * @param r The radius of the circle.
328      * @return A SVG component wrapping a basic shape element.
329      * @since 1.0
330      * @see #circle()
331      */
332     public static final Component circle(double cx, double cy, double r) {
333         Component v = circle();
334         circleCenter(v, cx, cy);
335         circleRadius(v, r);
336         return v;
337     }
338 
339     /**
340      * <p>Creates SVG component that wraps an "ellipse" element.</p>
341      * @return A SVG component wrapping a basic shape element.
342      * @since 1.0
343      */
344     public static final Component ellipse() {
345         return Component.createElementNS(SVG_NS, ELLIPSE);
346     }
347 
348     /**
349      * <p>Defines the center of an ellipse by setting attributes to the SVG 
350      * element wrapped by the specified component.</p>
351      * @param v The current SVG component.
352      * @param cx The X coordinate of the center of the ellipse.
353      * @param cy The Y coordinate of the center of the ellipse.
354      * @since 1.0
355      * @see #ellipse()
356      * @see #ellipseRadius(Component, double, double)
357      */
358     public static final void ellipseCenter(Component v, double cx, double cy) {
359         Component.setAttribute(v, "cx", cx);
360         Component.setAttribute(v, "cy", cy);
361     }
362 
363     /**
364      * <p>Defines the radiuses of an ellipse by setting attributes to the SVG 
365      * element wrapped by the specified component.</p>
366      * @param v The current SVG component.
367      * @param rx The X-axis radius of the ellipse.
368      * @param ry The Y-axis radius of the ellipse.
369      * @since 1.0
370      * @see #ellipse()
371      * @see #ellipseCenter(Component, double, double)
372      */
373     public static final void ellipseRadius(Component v, double rx, double ry) {
374         Component.setAttribute(v, "rx", rx);
375         Component.setAttribute(v, "ry", ry);
376     }
377 
378     /**
379      * <p>Creates SVG component that wraps an "ellipse" element.</p>
380      * @param cx The X coordinate of the center of the ellipse.
381      * @param cy The Y coordinate of the center of the ellipse.
382      * @param rx The X-axis radius of the ellipse.
383      * @param ry The Y-axis radius of the ellipse.
384      * @return A SVG component wrapping a basic shape element.
385      * @since 1.0
386      * @see #ellipse()
387      */
388     public static final Component ellipse(double cx, double cy, double rx, double ry) {
389         Component v = ellipse();
390         ellipseCenter(v, cx, cy);
391         ellipseRadius(v, rx, ry);
392         return v;
393     }
394 
395     /**
396      * <p>Creates SVG component that wraps a "line" element.</p>
397      * @return A SVG component wrapping a basic shape element.
398      * @since 1.0
399      * @see #lineFrom(Component, double, double)
400      * @see #lineTo(Component, double, double)
401      * @see #line(double, double, double, double)
402      */
403     public static final Component line() {
404         return Component.createElementNS(SVG_NS, LINE);
405     }
406 
407     /**
408      * <p>Defines the starting point of a line by setting attributes to the SVG 
409      * element wrapped by the specified component.</p>
410      * @param v The current SVG component.
411      * @param x The X coordinate of the start point of the line.
412      * @param y The Y coordinate of the start point of the line.
413      * @since 1.0
414      * @see #line()
415      * @see #lineTo(Component, double, double)
416      */
417     public static final void lineFrom(Component v, double x, double y) {
418         Component.setAttribute(v, "x1", x);
419         Component.setAttribute(v, "y1", y);
420     }
421 
422     /**
423      * <p>Defines the ending point of a line by setting attributes to the SVG 
424      * element wrapped by the specified component.</p>
425      * @param v The current SVG component.
426      * @param x The X coordinate of the end point of the line.
427      * @param y The Y coordinate of the end point of the line.
428      * @since 1.0
429      * @see #line()
430      * @see #lineFrom(Component, double, double)
431      */
432     public static final void lineTo(Component v, double x, double y) {
433         Component.setAttribute(v, "x2", x);
434         Component.setAttribute(v, "y2", y);
435     }
436 
437     /**
438      * <p>Creates SVG component that wraps a "line" element.</p>
439      * @param x1 The X coordinate of the start point of the line.
440      * @param y1 The Y coordinate of the start point of the line.
441      * @param x2 The X coordinate of the end point of the line.
442      * @param y2 The Y coordinate of the end point of the line.
443      * @return A SVG component wrapping a basic shape element.
444      * @since 1.0
445      * @see #line()
446      */
447     public static final Component line(double x1, double y1, double x2, double y2) {
448         Component v = line();
449         lineFrom(v, x1, y1);
450         lineTo(v, x2, y2);
451         return v;
452     }
453 
454     /**
455      * <p>Creates SVG component that wraps a "polyline" element.</p>
456      * @return A SVG component wrapping a basic shape element.
457      * @since 1.0
458      */
459     public static final Component polyline() {
460         return Component.createElementNS(SVG_NS, POLYLINE);
461     }
462 
463     /**
464      * <p>Defines the points of a polyline by setting attributes to the SVG 
465      * element wrapped by the specified component.</p>
466      * @param v The current SVG component.
467      * @param points The points that make up the polyline.
468      * @since 1.0
469      * @see #polyline()
470      */
471     public static final void polyline(Component v, ArrayLike<String> points) {
472         Component.setAttribute(v, "points", ArrayLikes.join(points, SPACE));
473     }
474 
475     /**
476      * <p>Creates SVG component that wraps a "polyline" element.</p>
477      * @param points The points that make up the polyline.
478      * @return A SVG component wrapping a basic shape element.
479      * @since 1.0
480      * @see #polyline()
481      */
482     public static final Component polyline(ArrayLike<String> points) {
483         Component v = polyline();
484         polyline(v, points);
485         return v;
486     }
487 
488     /**
489      * <p>Creates SVG component that wraps a "polygon" element.</p>
490      * @return A SVG component wrapping a basic shape element.
491      * @since 1.0
492      */
493     public static final Component polygon() {
494         return Component.createElementNS(SVG_NS, POLYGON);
495     }
496 
497     /**
498      * <p>Defines the points of a polygon by setting attributes to the SVG 
499      * element wrapped by the specified component.</p>
500      * @param v The current SVG component.
501      * @param points The points that make up the polygon.
502      * @since 1.0
503      * @see #polygon()
504      */
505     public static final void polygon(Component v, ArrayLike<String> points) {
506         Component.setAttribute(v, "points", ArrayLikes.join(points, SPACE));
507     }
508 
509     /**
510      * <p>Creates SVG component that wraps a "polygon" element.</p>
511      * @param points The points that make up the polygon.
512      * @return A SVG component wrapping a basic shape element.
513      * @since 1.0
514      * @see #polygon()
515      */
516     public static final Component polygon(ArrayLike<String> points) {
517         Component v = polygon();
518         polygon(v, points);
519         return v;
520     }
521 
522     /**
523      * <p>Defines the outline data of a path by setting attributes to the SVG 
524      * element wrapped by the specified component.</p>
525      * @param v The current SVG component.
526      * @param commands An array of path commands.
527      * @since 1.0
528      * @see #path()
529      */
530     public static final void path(Component v, ArrayLike<String> commands) {
531         Component.setAttribute(v, DEF, ArrayLikes.join(commands, SPACE));
532     }
533 
534     /**
535      * <p>Creates SVG component that wraps a "path" element.</p>
536      * @return A SVG component wrapping a basic shape element.
537      * @since 1.0
538      */
539     public static final Component path() {
540         return Component.createElementNS(SVG_NS, PATH);
541     }
542 
543     /**
544      * <p>Creates SVG component that wraps a "path" element.</p>
545      * @param commands An array of path commands used to define the outline shape of 
546      * the specified path.
547      * @return A SVG component wrapping a basic shape element.
548      * @since 1.0
549      */
550     public static final Component path(ArrayLike<String> commands) {
551         Component v = path();
552         path(v, commands);
553         return v;
554     }
555 
556     /**
557      * <p>Creates an absolute move-to path command.</p>
558      * @param x The X coordinate of the point to move to.
559      * @param y The Y coordinate of the point to move to.
560      * @return A string value of the newly created path command.
561      * @since 1.0
562      */
563     public static final String moveTo(double x, double y) {
564         return Js.add("M ", coord(x, y));
565     }
566 
567     /**
568      * <p>Creates an absolute line-to path command.</p>
569      * @param x The X coordinate of the point to line to.
570      * @param y The Y coordinate of the point to line to.
571      * @return A string value of the newly created path command.
572      * @since 1.0
573      */
574     public static final String lineTo(double x, double y) {
575         return Js.add("L ", coord(x, y));
576     }
577 
578     /**
579      * <p>Creates a close-path command.</p>
580      * @return A string value of the newly created path command.
581      * @since 1.0
582      */
583     public static final String closePath() {
584         return "Z";
585     }
586 
587     /**
588      * <p>Creates a relative move-to path command.</p>
589      * @param x The relative X coordinate of the point to move to.
590      * @param y The relative Y coordinate of the point to move to.
591      * @return A string value of the newly created path command.
592      * @since 1.0
593      */
594     public static final String moveto(double x, double y) {
595         return Js.add("m", coord(x, y));
596     }
597 
598     /**
599      * <p>Creates a relative line-to path command.</p>
600      * @param x The relative X coordinate of the point to line to.
601      * @param y The relative Y coordinate of the point to line to.
602      * @return A string value of the newly created path command.
603      * @since 1.0
604      */
605     public static final String lineto(double x, double y) {
606         return Js.add("l", coord(x, y));
607     }
608 
609     /**
610      * <p>Fills with a CSS color by setting attributes to the SVG element wrapped by 
611      * the specified component.</p>
612      * @param v The current SVG component.
613      * @param color A string of CSS color value.
614      * @since 1.0
615      * @see #stroke(Component, String)
616      * @see #strokeWidth(Component, Object)
617      */
618     public static final void fill(Component v, String color) {
619         Component.setAttribute(v, "fill", color);
620     }
621 
622     /**
623      * <p>Defines a stroke color by setting attributes to the SVG element wrapped by 
624      * the specified component.</p>
625      * @param v The current SVG component.
626      * @param color A string of CSS color value.
627      * @since 1.0
628      * @see #fill(Component, String)
629      * @see #strokeWidth(Component, Object)
630      */
631     public static final void stroke(Component v, String color) {
632         Component.setAttribute(v, "stroke", color);
633     }
634 
635     /**
636      * <p>Defines stroke width by setting attributes to the SVG element wrapped by 
637      * the specified component.</p>
638      * @param v The current SVG component.
639      * @param w A number or string value of stroke width.
640      * @since 1.0
641      * @see #fill(Component, String)
642      * @see #stroke(Component, String)
643      */
644     public static final void strokeWidth(Component v, Object w) {
645         Component.setAttribute(v, "stroke-width", w);
646     }
647 }