1 19 package jcckit.renderer; 20 21 import jcckit.graphic.Anchor; 22 import jcckit.graphic.BasicGraphicalElement; 23 import jcckit.graphic.ClippingShape; 24 import jcckit.graphic.FillAttributes; 25 import jcckit.graphic.FontStyle; 26 import jcckit.graphic.GraphicalComposite; 27 import jcckit.graphic.GraphicalCompositeRenderer; 28 import jcckit.graphic.GraphicAttributes; 29 import jcckit.graphic.LineAttributes; 30 import jcckit.graphic.Oval; 31 import jcckit.graphic.OvalRenderer; 32 import jcckit.graphic.Polygon; 33 import jcckit.graphic.PolygonRenderer; 34 import jcckit.graphic.Rectangle; 35 import jcckit.graphic.RectangleRenderer; 36 import jcckit.graphic.Text; 37 import jcckit.graphic.TextAttributes; 38 import jcckit.graphic.TextRenderer; 39 import jcckit.util.Format; 40 41 import java.awt.Color ; 42 import java.util.Hashtable ; 43 44 71 public class SVGRenderer implements GraphicalCompositeRenderer, 72 PolygonRenderer, OvalRenderer, 73 TextRenderer, RectangleRenderer { 74 private static final Format POLYGON_FORMAT = new Format("%9.7g,%9.7g"); 75 private static final Format RECT_FORMAT 76 = new Format("<rect x='%9.7g' y='%9.7g' width='%9.7g' height='%9.7g'"); 77 private static final Format OVAL_FORMAT 78 = new Format("<ellipse cx='%9.7g' cy='%9.7g' rx='%9.7g' ry='%9.7g'"); 79 private static final Format TEXT_FORMAT 80 = new Format("<text x='%9.7g' y='%9.7g'"); 81 private static final Format ORIENTATION_FORMAT 82 = new Format(" transform='rotate(%9.7g,%9.7g,%9.7g)'"); 83 private static final Format FONT_FORMAT 84 = new Format(" font-size='%9.7g' text-anchor='"); 85 private static final Format COLOR_FORMAT = new Format("='#%06x'"); 86 private static final Format STROKE_WIDTH_FORMAT 87 = new Format(" stroke-width='%9.7g'"); 88 private static final String DEFAULT_FONT_NAME = "SansSerif"; 89 private static final Color DEFAULT_COLOR = Color.black; 90 private static final double DEFAULT_FONT_SIZE = 0.01; 91 private static final int BASELINE_SHIFT_OFFSET = 41; 92 private static final int BASELINE_SHIFT_FACTOR = 64; 93 private static final Hashtable FONT_MAP = new Hashtable (); 94 95 private StringBuffer _document; 96 private double _defaultFontSize; 97 private int _level; 98 private int _id; 99 100 static { 101 FONT_MAP.put("SansSerif", "sans-serif"); 102 FONT_MAP.put("Serif", "serif"); 103 FONT_MAP.put("Monospaced", "monospace"); 104 } 105 106 115 public SVGRenderer init(StringBuffer buffer, int initialIndentLevel, 116 double paperSize) { 117 _document = buffer; 118 _level = initialIndentLevel; 119 _defaultFontSize = paperSize * DEFAULT_FONT_SIZE; 120 return this; 121 } 122 123 127 private void indentAndAdd(String text) { 128 for (int i = 2 * _level; i > 0; i--) { 129 _document.append(' '); 130 } 131 _document.append(text); 132 } 133 134 146 public void startRendering(GraphicalComposite composite) { 147 indentAndAdd("<g"); 148 ClippingShape shape = composite.getClippingShape(); 149 if (shape == null) { 150 _document.append(">\n"); 151 } else { 152 _document.append(" clip-path='url(#path").append(_id).append(")'>\n"); 153 } 154 _level++; 155 if (shape != null) { 156 indentAndAdd("<clipPath id='path"); 157 _document.append(_id++).append("'>\n"); 158 _level++; 159 shape.getBoundingBox().getGraphicalElement().renderWith(this); 160 _level--; 161 indentAndAdd("</clipPath>\n"); 162 } 163 } 164 165 169 public void finishRendering(GraphicalComposite composite) { 170 _level--; 171 indentAndAdd("</g>\n"); 172 } 173 174 178 public void render(Polygon polygon) { 179 indentAndAdd(polygon.isClosed() ? "<polygon" : "<polyline"); 180 int n = polygon.getNumberOfPoints(); 181 if (n > 0) { 182 _document.append(" points='"); 183 for (int i = 0; i < n; i++) { 184 _document.append(POLYGON_FORMAT.form( 185 new double[] {polygon.getPoint(i).getX(), 186 -polygon.getPoint(i).getY()})) 187 .append(i < n - 1 ? ' ' : '\''); 188 } 189 } 190 addShapeAttributes(polygon); 191 } 192 193 194 public void render(Rectangle rectangle) { 195 double width = rectangle.getWidth(); 196 double height = rectangle.getHeight(); 197 indentAndAdd(RECT_FORMAT.form(new double[] { 198 rectangle.getCenter().getX() - width / 2, 199 -rectangle.getCenter().getY() - height / 2, width, height})); 200 addShapeAttributes(rectangle); 201 } 202 203 204 public void render(Oval oval) { 205 indentAndAdd(OVAL_FORMAT.form(new double[] {oval.getCenter().getX(), 206 -oval.getCenter().getY(), oval.getWidth() / 2, oval.getHeight() / 2})); 207 addShapeAttributes(oval); 208 } 209 210 211 public void render(Text text) { 212 double x = text.getPosition().getX(); 213 double y = -text.getPosition().getY(); 214 indentAndAdd(TEXT_FORMAT.form(new double[] {x, y})); 215 TextAttributes ta = (TextAttributes) text.getGraphicAttributes(); 216 addTextAttributes(ta); 217 if (ta != null && ta.getOrientationAngle() != 0) { 218 _document.append(ORIENTATION_FORMAT.form( 219 new double[] {-ta.getOrientationAngle(), x, y})); 220 } 221 _document.append('>'); 222 String str = text.getText(); 223 for (int i = 0, n = str.length(); i < n; i++) { 224 char c = str.charAt(i); 225 switch (c) { 226 case '&': _document.append("&"); break; 227 case '<': _document.append("<"); break; 228 case '>': _document.append(">"); break; 229 case '"': _document.append("""); break; 230 default: _document.append(c); 231 } 232 } 233 _document.append("</text>\n"); 234 } 235 236 private void addShapeAttributes(BasicGraphicalElement element) { 237 GraphicAttributes ga = element.getGraphicAttributes(); 238 Color fillColor = null; 239 if (ga instanceof FillAttributes) { 240 fillColor = ((FillAttributes) ga).getFillColor(); 241 addColor(" fill", fillColor); 242 } 243 if (ga instanceof LineAttributes) { 244 addLineAttributes((LineAttributes) ga, 245 fillColor == null ? DEFAULT_COLOR : null); 246 } 247 _document.append("/>\n"); 248 } 249 250 private void addLineAttributes(LineAttributes attributes, 251 Color defaultColor) { 252 Color color = attributes.getLineColor(); 253 if (color == null) { 254 color = defaultColor; 255 } 256 if (color != null) { 257 addColor(" stroke", color); 258 _document.append(STROKE_WIDTH_FORMAT.form( 259 Math.max(1e-6, attributes.getLineThickness()))); 260 double[] linePattern = attributes.getLinePattern(); 261 if (linePattern != null && linePattern.length > 0) { 262 _document.append(" stroke-dasharray='"); 263 for (int i = 0; i < linePattern.length; i++) { 264 _document.append(linePattern[i]) 265 .append(i < linePattern.length - 1 ? ',' : '\''); 266 } 267 } 268 } 269 } 270 271 private void addTextAttributes(TextAttributes ta) { 272 if (ta != null) { 273 addColor(" fill", ta.getTextColor() == null ? DEFAULT_COLOR 274 : ta.getTextColor()); 275 String fontName = ta.getFontName(); 276 if (fontName == null) { 277 fontName = DEFAULT_FONT_NAME; 278 } 279 String fontFamily = (String ) FONT_MAP.get(fontName); 280 if (fontFamily == null) { 281 fontFamily = fontName; 282 } 283 FontStyle fontStyle = ta.getFontStyle(); 284 if (fontStyle == FontStyle.BOLD || fontStyle == FontStyle.BOLD_ITALIC) { 285 _document.append(" font-weight='bold'"); 286 } 287 if (fontStyle == FontStyle.ITALIC 288 || fontStyle == FontStyle.BOLD_ITALIC) { 289 _document.append(" font-style='italic'"); 290 } 291 _document.append(FONT_FORMAT.form( 292 ta.getFontSize() == 0 ? _defaultFontSize 293 : ta.getFontSize())) 294 .append(ta.getHorizontalAnchor() == Anchor.CENTER ? "middle'" 295 : (ta.getHorizontalAnchor() == Anchor.RIGHT_TOP ? 296 "end'" : "start'")) 297 .append(" font-family='").append(fontFamily) 298 .append("' baseline-shift='") 299 .append(BASELINE_SHIFT_OFFSET 300 - (ta.getVerticalAnchor() == null ? 301 1 : ta.getVerticalAnchor().getFactor()) 302 * BASELINE_SHIFT_FACTOR) 303 .append("%'"); 304 } 305 } 306 307 private void addColor(String name, Color color) { 308 _document.append(name); 309 if (color == null) { 310 _document.append("='none'"); 311 } else { 312 _document.append(COLOR_FORMAT.form(color.getRGB() & 0xffffff)); 313 } 314 } 315 } 316 | Popular Tags |