001 package railo.runtime.tag; 002 003 import java.awt.Color; 004 import java.awt.Font; 005 import java.awt.GradientPaint; 006 import java.awt.Rectangle; 007 import java.awt.image.BufferedImage; 008 import java.io.ByteArrayOutputStream; 009 import java.io.IOException; 010 import java.io.OutputStream; 011 import java.io.Serializable; 012 import java.util.ArrayList; 013 import java.util.Collections; 014 import java.util.Iterator; 015 import java.util.List; 016 import java.util.TimeZone; 017 018 import org.jfree.chart.ChartFactory; 019 import org.jfree.chart.ChartRenderingInfo; 020 import org.jfree.chart.ChartUtilities; 021 import org.jfree.chart.JFreeChart; 022 import org.jfree.chart.axis.Axis; 023 import org.jfree.chart.axis.CategoryAxis; 024 import org.jfree.chart.axis.ValueAxis; 025 import org.jfree.chart.block.ColumnArrangement; 026 import org.jfree.chart.block.LineBorder; 027 import org.jfree.chart.imagemap.ImageMapUtilities; 028 import org.jfree.chart.imagemap.ToolTipTagFragmentGenerator; 029 import org.jfree.chart.imagemap.URLTagFragmentGenerator; 030 import org.jfree.chart.plot.CategoryPlot; 031 import org.jfree.chart.plot.PiePlot; 032 import org.jfree.chart.plot.PiePlot3D; 033 import org.jfree.chart.plot.Plot; 034 import org.jfree.chart.plot.PlotOrientation; 035 import org.jfree.chart.plot.XYPlot; 036 import org.jfree.chart.renderer.category.BarRenderer3D; 037 import org.jfree.chart.renderer.category.CategoryItemRenderer; 038 import org.jfree.chart.renderer.category.LineAndShapeRenderer; 039 import org.jfree.chart.renderer.xy.XYItemRenderer; 040 import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; 041 import org.jfree.chart.title.LegendTitle; 042 import org.jfree.chart.title.TextTitle; 043 import org.jfree.data.Range; 044 import org.jfree.data.category.CategoryDataset; 045 import org.jfree.data.category.DefaultCategoryDataset; 046 import org.jfree.data.general.DefaultPieDataset; 047 import org.jfree.data.time.Second; 048 import org.jfree.data.time.TimeSeries; 049 import org.jfree.data.time.TimeSeriesCollection; 050 import org.jfree.data.xy.XYDataset; 051 import org.jfree.ui.HorizontalAlignment; 052 import org.jfree.ui.RectangleAnchor; 053 import org.jfree.ui.RectangleEdge; 054 import org.jfree.ui.RectangleInsets; 055 import org.jfree.util.ShapeUtilities; 056 057 import railo.commons.color.ColorCaster; 058 import railo.commons.io.IOUtil; 059 import railo.commons.io.res.Resource; 060 import railo.commons.io.res.util.ResourceUtil; 061 import railo.commons.lang.Md5; 062 import railo.commons.lang.StringUtil; 063 import railo.runtime.chart.BarRenderer3DWrap; 064 import railo.runtime.chart.CategoryToolTipGeneratorImpl; 065 import railo.runtime.chart.EmptyURLTagFragmentGenerator; 066 import railo.runtime.chart.LabelFormatUtil; 067 import railo.runtime.chart.PieSectionLabelGeneratorImpl; 068 import railo.runtime.chart.PieSectionLegendLabelGeneratorImpl; 069 import railo.runtime.chart.PieToolTipGeneratorImpl; 070 import railo.runtime.chart.TickUnitsImpl; 071 import railo.runtime.chart.ToolTipTagFragmentGeneratorImpl; 072 import railo.runtime.converter.JavaConverter; 073 import railo.runtime.engine.ThreadLocalPageContext; 074 import railo.runtime.exp.ApplicationException; 075 import railo.runtime.exp.ExpressionException; 076 import railo.runtime.exp.PageException; 077 import railo.runtime.ext.tag.BodyTagImpl; 078 import railo.runtime.functions.dateTime.DateAdd; 079 import railo.runtime.img.Image; 080 import railo.runtime.op.Caster; 081 import railo.runtime.op.date.DateCaster; 082 import railo.runtime.type.dt.DateTime; 083 084 085 public final class Chart extends BodyTagImpl implements Serializable { 086 087 088 089 public static final Color COLOR_999999=new Color(0x99,0x99,0x99); 090 public static final Color COLOR_666666=new Color(0x66,0x66,0x66); 091 public static final Color COLOR_333333=new Color(0x33,0x33,0x33); 092 093 public static final String FONT_ARIAL = "arial"; 094 public static final String FONT_TIMES = "times"; 095 public static final String FONT_COURIER = "courier"; 096 public static final String FONT_ARIAL_UNICODE_MS = "arialunicodems"; 097 098 public static final int FORMAT_GIF = 0; 099 public static final int FORMAT_JPG = 1; 100 public static final int FORMAT_PNG = 2; 101 public static final int FORMAT_FLASH=3; 102 103 104 public static final int PIE_SLICE_STYLE_SOLID = 0; 105 public static final int PIE_SLICE_STYLE_SLICED = 1; 106 107 public static final int SERIES_PLACEMENT_DEFAULT = 0; 108 public static final int SERIES_PLACEMENT_CLUSTER = 1; 109 public static final int SERIES_PLACEMENT_STACKED = 2; 110 public static final int SERIES_PLACEMENT_PERCENT = 3; 111 112 public static final int TIP_STYLE_NONE = 0; 113 public static final int TIP_STYLE_FORMATS = 1; 114 public static final int TIP_STYLE_MOUSEDOWN = 2; 115 public static final int TIP_STYLE_MOUSEOVER = 3; 116 117 private static final int NONE = 0; 118 private static final int YES = 1; 119 private static final int NO = 2; 120 121 122 private static int chartIndex=0; 123 124 private Color backgroundcolor=Color.WHITE; 125 private Color databackgroundcolor=Color.WHITE; 126 private Color foregroundcolor=Color.BLACK; 127 private Color tipbgcolor=Color.WHITE; 128 private String xaxistitle=null; 129 private String yaxistitle=null; 130 131 132 private int chartheight=240; 133 private int chartwidth=320; 134 135 private String font=FONT_ARIAL; 136 private int fontstyle=0; 137 private int fontsize=11; 138 139 private int format=FORMAT_PNG; 140 private int gridlines=10; 141 142 private int labelFormat=LabelFormatUtil.LABEL_FORMAT_NUMBER; 143 private int markersize=-1; 144 145 private String name=null; 146 147 private int pieslicestyle=PIE_SLICE_STYLE_SLICED; 148 149 private double scalefrom=Double.NaN; 150 private double scaleto=Double.NaN; 151 private boolean legendMultiLine=false; 152 153 private int seriesplacement=SERIES_PLACEMENT_DEFAULT; 154 155 private boolean show3d=false; 156 private boolean showtooltip=true; 157 private boolean showborder=false; 158 private boolean showlegend=true; 159 private boolean showmarkers=true; 160 private int showxgridlines=NONE; 161 private boolean showygridlines=false; 162 private boolean sortxaxis=false; 163 164 private String style=null; 165 private String title=""; 166 167 private int tipstyle=TIP_STYLE_MOUSEOVER; 168 private List<ChartSeriesBean> _series=new ArrayList<ChartSeriesBean>(); 169 170 private String url; 171 private double xoffset=0.1; 172 private double yoffset=0.1; 173 private String xaxistype="category"; 174 private String yaxistype="category"; 175 private double smallest; 176 private double biggest; 177 private boolean showXLabel=true; 178 private String source; 179 180 public void release() { 181 _series.clear(); 182 183 url=null; 184 xoffset=0.1; 185 yoffset=0.1; 186 xaxistype="category"; 187 yaxistype="category"; 188 189 190 191 xaxistitle=""; 192 yaxistitle=""; 193 legendMultiLine=false; 194 // TODO super.release(); 195 backgroundcolor=Color.WHITE; 196 databackgroundcolor=Color.WHITE; 197 foregroundcolor=Color.BLACK; 198 tipbgcolor=Color.WHITE; 199 200 chartheight=240; 201 chartwidth=320; 202 203 font=FONT_ARIAL; 204 fontstyle=0; 205 fontsize=11; 206 207 format=FORMAT_PNG; 208 gridlines=10; 209 210 labelFormat=LabelFormatUtil.LABEL_FORMAT_NUMBER; 211 markersize=-1; 212 name=null; 213 214 pieslicestyle=PIE_SLICE_STYLE_SLICED; 215 216 scalefrom=Double.NaN; 217 scaleto=Double.NaN; 218 seriesplacement=SERIES_PLACEMENT_DEFAULT; 219 220 show3d=false; 221 showborder=false; 222 showlegend=true; 223 showmarkers=true; 224 showxgridlines=NONE; 225 showygridlines=false; 226 sortxaxis=false; 227 showXLabel=true; 228 showtooltip=true; 229 style=null; 230 title=""; 231 source=null; 232 tipstyle=TIP_STYLE_MOUSEOVER; 233 } 234 235 236 237 public void setShowxlabel(boolean showXLabel) { 238 this.showXLabel = showXLabel; 239 } 240 public void setSource(String source) { 241 this.source = source; 242 } 243 public void setShowtooltip(boolean showtooltip) { 244 this.showtooltip = showtooltip; 245 } 246 public void setBackgroundcolor(String strBackgroundColor) throws ExpressionException { 247 this.backgroundcolor = ColorCaster.toColor(strBackgroundColor); 248 } 249 250 public void setDatabackgroundcolor(String strDatabackgroundcolor) throws ExpressionException { 251 this.databackgroundcolor = ColorCaster.toColor(strDatabackgroundcolor); 252 } 253 254 public void setForegroundcolor(String strForegroundcolor) throws ExpressionException { 255 this.foregroundcolor = ColorCaster.toColor(strForegroundcolor); 256 } 257 258 public void setTipbgcolor(String strTipbgcolor) throws ExpressionException { 259 this.tipbgcolor = ColorCaster.toColor(strTipbgcolor); 260 } 261 262 public void setChartheight(double chartheight) { 263 this.chartheight = (int) chartheight; 264 } 265 266 public void setChartwidth(double chartwidth) { 267 this.chartwidth = (int) chartwidth; 268 } 269 270 public void setFont(String strFont) { 271 strFont=strFont.trim().toLowerCase(); 272 if("arial".equals(strFont))font=FONT_ARIAL; 273 else if("times".equals(strFont))font=FONT_TIMES; 274 else if("courier".equals(strFont))font=FONT_COURIER; 275 else if("arialunicodems".equals(strFont))font=FONT_ARIAL_UNICODE_MS; 276 else font=strFont; 277 //else throw new ExpressionException("invalid value ["+strFont+"] for attribute font, for this attribute only the following values are supported [arial,times,courier,arialunicodeMS]"); 278 } 279 280 public void setFontbold(boolean fontbold) { 281 if(fontbold)fontstyle+=Font.BOLD; 282 } 283 284 public void setFontitalic(boolean fontitalic) { 285 if(fontitalic)fontstyle+=Font.ITALIC; 286 } 287 288 public void setFontsize(double fontsize) { 289 this.fontsize = (int) fontsize; 290 } 291 292 public void setFormat(String strFormat) throws ExpressionException { 293 strFormat=strFormat.trim().toLowerCase(); 294 if("gif".equals(strFormat)) format=FORMAT_GIF; 295 else if("jpg".equals(strFormat)) format=FORMAT_JPG; 296 else if("jpeg".equals(strFormat)) format=FORMAT_JPG; 297 else if("jpe".equals(strFormat)) format=FORMAT_JPG; 298 else if("png".equals(strFormat)) format=FORMAT_PNG; 299 //else if("flash".equals(strFormat)) format=FORMAT_FLASH; 300 //else if("swf".equals(strFormat)) format=FORMAT_FLASH; 301 302 else throw new ExpressionException("invalid value ["+strFormat+"] for attribute format, for this attribute only the following values are supported [gif,jpg,png]"); 303 } 304 305 public void setGridlines(double gridlines) { 306 this.gridlines = (int) gridlines; 307 } 308 309 public void setLabelformat(String strLabelFormat) throws ExpressionException { 310 strLabelFormat=strLabelFormat.trim().toLowerCase(); 311 if("number".equals(strLabelFormat)) labelFormat=LabelFormatUtil.LABEL_FORMAT_NUMBER; 312 else if("numeric".equals(strLabelFormat)) labelFormat=LabelFormatUtil.LABEL_FORMAT_NUMBER; 313 else if("currency".equals(strLabelFormat)) labelFormat=LabelFormatUtil.LABEL_FORMAT_CURRENCY; 314 else if("date".equals(strLabelFormat)) labelFormat=LabelFormatUtil.LABEL_FORMAT_DATE; 315 else if("percent".equals(strLabelFormat)) labelFormat=LabelFormatUtil.LABEL_FORMAT_PERCENT; 316 //else if("integer".equals(strLabelFormat)) labelFormat=LabelFormatUtil.LABEL_FORMAT_INTEGER; 317 318 else throw new ExpressionException("invalid value ["+strLabelFormat+"] for attribute labelFormat, for this attribute only the following values are supported [date,percent,currency,number]"); 319 } 320 321 public void setMarkersize(double markersize) throws ExpressionException { 322 if(markersize<1) throw new ExpressionException("invalid value ["+markersize+"] for attribute markersize, value must be a positive integer greater than 0"); 323 this.markersize=(int) markersize; 324 } 325 326 public void setName(String name) { 327 this.name = name; 328 } 329 330 public void setPieslicestyle(String strPieslicestyle) throws ExpressionException { 331 strPieslicestyle=strPieslicestyle.trim().toLowerCase(); 332 if("sliced".equals(strPieslicestyle)) pieslicestyle=PIE_SLICE_STYLE_SLICED; 333 else if("slice".equals(strPieslicestyle)) pieslicestyle=PIE_SLICE_STYLE_SLICED; 334 else if("solid".equals(strPieslicestyle)) pieslicestyle=PIE_SLICE_STYLE_SOLID; 335 336 else throw new ExpressionException("invalid value ["+strPieslicestyle+"] for attribute pieSliceStyle, for this attribute only the following values are supported [sliced,solid]"); 337 } 338 339 public void setScaleto(double scaleto) { 340 //if(scaleto<0) throw new ExpressionException("invalid value ["+scaleto+"] for attribute scaleto, value must be a positive integer greater or equal than 0"); 341 this.scaleto = scaleto; 342 } 343 344 public void setScalefrom(double scaletrom) { 345 //if(scaletrom<0) throw new ExpressionException("invalid value ["+scaletrom+"] for attribute scaletrom, value must be a positive integer greater or equal than 0"); 346 this.scalefrom = scaletrom; 347 } 348 349 public void setSeriesplacement(String strSeriesplacement) throws ExpressionException { 350 strSeriesplacement=strSeriesplacement.trim().toLowerCase(); 351 if("default".equals(strSeriesplacement)) seriesplacement=SERIES_PLACEMENT_DEFAULT; 352 else if("cluster".equals(strSeriesplacement))seriesplacement=SERIES_PLACEMENT_CLUSTER; 353 else if("stacked".equals(strSeriesplacement))seriesplacement=SERIES_PLACEMENT_STACKED; 354 else if("percent".equals(strSeriesplacement))seriesplacement=SERIES_PLACEMENT_PERCENT; 355 356 else throw new ExpressionException("invalid value ["+strSeriesplacement+"] for attribute seriesplacement, for this attribute only the following values are supported [default,cluster,percent,stacked]"); 357 } 358 359 public void setShow3d(boolean show3d) { 360 this.show3d = show3d; 361 } 362 363 public void setShowborder(boolean showborder) { 364 this.showborder = showborder; 365 } 366 367 public void setShowlegend(boolean showlegend) { 368 this.showlegend = showlegend; 369 } 370 371 public void setShowmarkers(boolean showmarkers) { 372 this.showmarkers = showmarkers; 373 } 374 375 public void setShowxgridlines(boolean showxgridlines) { 376 this.showxgridlines = showxgridlines?YES:NO; 377 } 378 379 public void setShowygridlines(boolean showygridlines) { 380 this.showygridlines = showygridlines; 381 } 382 383 public void setSortxaxis(boolean sortxaxis) { 384 this.sortxaxis = sortxaxis; 385 } 386 387 public void setStyle(String style) { 388 this.style = style; 389 } 390 391 public void setTitle(String title) { 392 this.title = title; 393 } 394 395 public void setTipstyle(String strTipstyle) throws ExpressionException { 396 strTipstyle=strTipstyle.trim().toLowerCase(); 397 if("mousedown".equals(strTipstyle)) tipstyle=TIP_STYLE_MOUSEDOWN; 398 else if("mouseover".equals(strTipstyle))tipstyle=TIP_STYLE_MOUSEOVER; 399 else if("none".equals(strTipstyle)) tipstyle=TIP_STYLE_NONE; 400 else if("formats".equals(strTipstyle)) tipstyle=TIP_STYLE_FORMATS; 401 402 else throw new ExpressionException("invalid value ["+strTipstyle+"] for attribute Tipstyle, for this attribute only the following values are supported [mouseover,mousedown,one,formats]"); 403 } 404 405 406 407 /** 408 * @param xaxistitle the xaxistitle to set 409 */ 410 public void setXaxistitle(String xaxistitle) { 411 this.xaxistitle = xaxistitle; 412 } 413 414 /** 415 * @param yaxistitle the yaxistitle to set 416 */ 417 public void setYaxistitle(String yaxistitle) { 418 this.yaxistitle = yaxistitle; 419 } 420 421 public void addChartSeries(ChartSeriesBean series) { 422 _series.add(series); 423 } 424 425 426 public int doStartTag() { 427 return EVAL_BODY_INCLUDE; 428 } 429 430 /** 431 * 432 * @see railo.runtime.ext.tag.TagImpl#doEndTag() 433 */ 434 public int doEndTag() throws PageException { 435 if(_series.size()==0) throw new ApplicationException("at least one cfchartseries tag required inside cfchart"); 436 //if(_series.size()>1) throw new ApplicationException("only one cfchartseries tag allowed inside cfchart"); 437 //doSingleSeries((ChartSeriesBean) _series.get(0)); 438 ChartSeriesBean first= _series.get(0); 439 440 try { 441 442 if(first.getType()==ChartSeriesBean.TYPE_BAR) 443 //throw new ApplicationException("type bar is not supported"); 444 chartBar(); 445 else if(first.getType()==ChartSeriesBean.TYPE_TIME) 446 chartTimeLine(); 447 else if(first.getType()==ChartSeriesBean.TYPE_AREA) 448 chartArea(); 449 else if(first.getType()==ChartSeriesBean.TYPE_CONE) 450 throw new ApplicationException("type cone is not supported"); 451 else if(first.getType()==ChartSeriesBean.TYPE_CURVE) 452 chartLine(); 453 //throw new ApplicationException("type curve is not supported"); 454 else if(first.getType()==ChartSeriesBean.TYPE_CYLINDER) 455 throw new ApplicationException("type cylinder is not supported"); 456 else if(first.getType()==ChartSeriesBean.TYPE_HORIZONTALBAR) 457 throw new ApplicationException("type horizontalbar is not supported"); 458 else if(first.getType()==ChartSeriesBean.TYPE_LINE) 459 chartLine(); 460 //throw new ApplicationException("type line is not supported"); 461 else if(first.getType()==ChartSeriesBean.TYPE_PIE) 462 chartPie(); 463 else if(first.getType()==ChartSeriesBean.TYPE_PYRAMID) 464 throw new ApplicationException("type pyramid is not supported"); 465 else if(first.getType()==ChartSeriesBean.TYPE_SCATTER) 466 throw new ApplicationException("type scatter is not supported"); 467 else if(first.getType()==ChartSeriesBean.TYPE_STEP) 468 throw new ApplicationException("type step is not supported"); 469 } 470 catch(IOException ioe) { 471 throw Caster.toPageException(ioe); 472 } 473 474 return EVAL_PAGE; 475 } 476 477 private void chartPie() throws PageException, IOException { 478 // do dataset 479 DefaultPieDataset dataset = new DefaultPieDataset(); 480 ChartSeriesBean csb = _series.get(0); 481 482 ChartDataBean cdb; 483 484 List datas=csb.getDatas(); 485 if(sortxaxis)Collections.sort(datas); 486 Iterator itt = datas.iterator(); 487 while(itt.hasNext()) { 488 cdb=(ChartDataBean) itt.next(); 489 dataset.setValue(cdb.getItemAsString(), cdb.getValue()); 490 } 491 492 493 JFreeChart chart = show3d? 494 ChartFactory.createPieChart3D (title, dataset, false, true, true): 495 ChartFactory.createPieChart (title, dataset, false, true, true); 496 497 Plot p = chart.getPlot(); 498 PiePlot pp = (PiePlot)p; 499 500 Font _font = getFont(); 501 pp.setLegendLabelGenerator(new PieSectionLegendLabelGeneratorImpl(_font,chartwidth)); 502 pp.setBaseSectionOutlinePaint(Color.GRAY); // rand der st゚cke 503 pp.setLegendItemShape(new Rectangle(7,7)); 504 pp.setLabelFont(new Font(font,0,11)); 505 pp.setLabelLinkPaint(COLOR_333333); 506 pp.setLabelLinkMargin(-0.05); 507 pp.setInteriorGap(0.123); 508 pp.setLabelGenerator(new PieSectionLabelGeneratorImpl(labelFormat)); 509 510 511 512 513 databackgroundcolor=backgroundcolor; 514 515 setBackground(chart,p); 516 setBorder(chart,p); 517 setLegend(chart,p,_font); 518 set3d(p); 519 setFont(chart, _font); 520 setTooltip(chart); 521 setScale(chart); 522 523 // Slice Type and colors 524 boolean doSclice=pieslicestyle==PIE_SLICE_STYLE_SLICED; 525 Color[] colors = csb.getColorlist(); 526 Iterator it = csb.getDatas().iterator(); 527 int count=0; 528 while(it.hasNext()) { 529 cdb=(ChartDataBean) it.next(); 530 if(doSclice)pp.setExplodePercent(cdb.getItemAsString(), 0.13); 531 532 if(count<colors.length){ 533 pp.setSectionPaint(cdb.getItemAsString(), colors[count]); 534 } 535 count++; 536 } 537 538 writeOut(chart); 539 } 540 541 542 private void set3d(Plot plot) { 543 if(!show3d) return; 544 545 plot.setForegroundAlpha(0.6f); 546 547 if(plot instanceof CategoryPlot) { 548 plot.setForegroundAlpha(0.8f); 549 CategoryPlot cp=(CategoryPlot) plot; 550 CategoryItemRenderer renderer = cp.getRenderer(); 551 if(renderer instanceof BarRenderer3D) { 552 BarRenderer3D br3d=(BarRenderer3D) renderer; 553 cp.setRenderer(new BarRenderer3DWrap(br3d,xoffset,yoffset)); 554 } 555 556 } 557 else if(plot instanceof PiePlot3D) { 558 PiePlot3D pp3d=(PiePlot3D) plot; 559 pp3d.setDepthFactor(0.10); 560 } 561 562 563 564 //CategoryItemRenderer renderer = plot.getRenderer(); 565 566 } 567 568 private void setFont(JFreeChart chart, Font font) { 569 // title 570 TextTitle title=chart.getTitle(); 571 if(title!=null) { 572 title.setFont(font); 573 title.setPaint(foregroundcolor); 574 chart.setTitle(title); 575 } 576 577 // axis fonts 578 Plot plot = chart.getPlot(); 579 if(plot instanceof CategoryPlot) { 580 CategoryPlot cp = (CategoryPlot)plot; 581 setAxis(cp.getRangeAxis(),font); 582 setAxis(cp.getDomainAxis(),font); 583 } 584 if(plot instanceof XYPlot) { 585 XYPlot cp = (XYPlot)plot; 586 setAxis(cp.getRangeAxis(),font); 587 setAxis(cp.getDomainAxis(),font); 588 } 589 590 591 } 592 593 594 private void setAxis(Axis axis, Font font) { 595 if(axis!=null) { 596 axis.setLabelFont(font); 597 axis.setLabelPaint(foregroundcolor); 598 599 axis.setTickLabelFont(font); 600 axis.setTickLabelPaint(foregroundcolor); 601 axis.setTickLabelsVisible(true); 602 } 603 } 604 605 606 607 private void setLegend(JFreeChart chart, Plot plot, Font font) { 608 if(!showlegend) return; 609 610 611 Color bg = backgroundcolor==null?databackgroundcolor:backgroundcolor; 612 if(font==null)font=getFont(); 613 614 615 616 LegendTitle legend = legendMultiLine? 617 new LegendTitle(plot,new ColumnArrangement(), new ColumnArrangement()): 618 new LegendTitle(plot); 619 legend.setBackgroundPaint(bg); 620 legend.setMargin(new RectangleInsets(1.0, 1.0, 1.0, 1.0)); 621 legend.setFrame(new LineBorder()); 622 legend.setPosition(RectangleEdge.BOTTOM); 623 legend.setHorizontalAlignment(HorizontalAlignment.LEFT); 624 625 legend.setWidth(chartwidth-20);// geht nicht 626 legend.setItemFont(font); 627 legend.setItemPaint(foregroundcolor); 628 629 //RectangleInsets labelPadding; 630 legend.setItemLabelPadding(new RectangleInsets(2,2,2,2)); 631 legend.setBorder(0,0,0,0); 632 legend.setLegendItemGraphicLocation(RectangleAnchor.TOP_LEFT); 633 legend.setLegendItemGraphicPadding(new RectangleInsets(8,10,0,0)); 634 chart.addLegend(legend); 635 636 } 637 638 639 640 private void setBorder(JFreeChart chart, Plot plot) { 641 chart.setBorderVisible(false); 642 chart.setBorderPaint(foregroundcolor); 643 plot.setOutlinePaint(foregroundcolor); 644 } 645 646 647 648 private void setBackground(JFreeChart chart, Plot plot) { 649 //Color bg = backgroundcolor==null?databackgroundcolor:backgroundcolor; 650 651 chart.setBackgroundPaint(backgroundcolor); 652 plot.setBackgroundPaint(databackgroundcolor); 653 chart.setBorderPaint(databackgroundcolor); 654 655 656 plot.setOutlineVisible(false); 657 658 // Pie 659 if(plot instanceof PiePlot) { 660 PiePlot pp=(PiePlot) plot; 661 pp.setLabelOutlinePaint(backgroundcolor); 662 pp.setLabelBackgroundPaint(backgroundcolor); 663 pp.setLabelShadowPaint(backgroundcolor); 664 pp.setShadowPaint(backgroundcolor); 665 } 666 // Bar 667 /*if(plot instanceof CategoryPlot) { 668 CategoryPlot cp=(CategoryPlot) plot; 669 670 }*/ 671 } 672 673 674 675 676 677 private Font getFont() { 678 return new Font(font,fontstyle,fontsize); 679 } 680 681 private void writeOut(JFreeChart jfc) throws PageException, IOException { 682 final ChartRenderingInfo info=new ChartRenderingInfo(); 683 684 // map name 685 chartIndex++; 686 if(chartIndex<0)chartIndex=0; 687 String mapName="chart_"+(chartIndex++); 688 689 // write out to variable 690 if(!StringUtil.isEmpty(name)){ 691 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 692 copy(baos, jfc,info); 693 pageContext.setVariable(name, baos.toByteArray()); 694 return; 695 } 696 697 // write out as link 698 String id=Md5.getDigestAsString(JavaConverter.serialize(this)); 699 Resource graph = pageContext.getConfig().getTempDirectory().getRealResource("graph"); 700 Resource res = graph.getRealResource(id); 701 if(!res.exists()) { 702 clean(graph); 703 copy(res.getOutputStream(),jfc,info); 704 } 705 706 String src="/railo-context/graph.cfm?img="+id+"&type="+formatToString(format); 707 if(!StringUtil.isEmpty(source)) { 708 pageContext.setVariable(source, src); 709 return; 710 } 711 try { 712 // Tooltip 713 if(showtooltip) { 714 ToolTipTagFragmentGenerator tttfg = new ToolTipTagFragmentGeneratorImpl(url); 715 URLTagFragmentGenerator utfg=new EmptyURLTagFragmentGenerator(); 716 717 String map=ImageMapUtilities.getImageMap(mapName, info,tttfg,utfg).trim(); 718 pageContext.write(map); 719 } 720 pageContext.write("<img border=\"0\" usemap=\"#"+mapName+"\" src=\""+src+"\">"); 721 } 722 catch (IOException e) { 723 throw Caster.toPageException(e); 724 } 725 } 726 727 private void copy(OutputStream os, JFreeChart jfc, ChartRenderingInfo info) throws ApplicationException, IOException, ExpressionException { 728 //OutputStream os = null; 729 try { 730 //os = res.getOutputStream(); 731 BufferedImage bi = jfc.createBufferedImage(chartwidth,chartheight,info); 732 Image img; 733 734 // add border 735 if(showborder) { 736 try { 737 img = new Image(bi); 738 img.addBorder(1,Color.BLACK,Image.BORDER_TYPE_CONSTANT); 739 bi=img.getBufferedImage(); 740 } 741 catch (PageException e) {} 742 } 743 if(format==FORMAT_PNG) ChartUtilities.writeBufferedImageAsPNG(os, bi); 744 else if(format==FORMAT_JPG) ChartUtilities.writeBufferedImageAsJPEG(os, bi); 745 else if(format==FORMAT_GIF) { 746 img = new railo.runtime.img.Image(bi); 747 img.writeOut(os, "gif",1,true); 748 749 //throw new ApplicationException("format gif not supported"); 750 } 751 else if(format==FORMAT_FLASH)throw new ApplicationException("format flash not supported"); 752 } 753 finally { 754 IOUtil.flushEL(os); 755 IOUtil.closeEL(os); 756 } 757 } 758 759 private String formatToString(int format) { 760 if(format==FORMAT_GIF) return "gif"; 761 if(format==FORMAT_JPG) return "jpeg"; 762 if(format==FORMAT_PNG) return "png"; 763 return "swf"; 764 } 765 766 private void clean(Resource graph) throws IOException { 767 if(!graph.exists())graph.createDirectory(true); 768 else if(graph.isDirectory() && ResourceUtil.getRealSize(graph)>(1024*1024)) { 769 770 Resource[] children = graph.listResources(); 771 long maxAge=System.currentTimeMillis()-(1000*60); 772 for(int i=0;i<children.length;i++) { 773 if(children[i].lastModified()<maxAge) 774 children[i].delete(); 775 } 776 } 777 } 778 779 private void chartBar() throws PageException, IOException { 780 // create the chart... 781 final JFreeChart chart = show3d? 782 ChartFactory.createBarChart3D(title,xaxistitle,yaxistitle,createDatasetCategory(),PlotOrientation.VERTICAL,false,true,false): 783 ChartFactory.createBarChart (title,xaxistitle,yaxistitle,createDatasetCategory(),PlotOrientation.VERTICAL,false,true,false); 784 Plot p = chart.getPlot(); 785 Font _font = getFont(); 786 // settings 787 788 789 setBackground(chart,p); 790 setBorder(chart,p); 791 set3d(p); 792 setFont(chart,_font); 793 setLabelFormat(chart); 794 setLegend(chart, p, _font); 795 setTooltip(chart); 796 setScale(chart); 797 setAxis(chart); 798 setColor(chart); 799 800 writeOut(chart); 801 } 802 803 804 805 806 807 private void chartLine() throws PageException, IOException { 808 // create the chart... 809 final JFreeChart chart = show3d? 810 ChartFactory.createLineChart3D(title,xaxistitle,yaxistitle,createDatasetCategory(),PlotOrientation.VERTICAL,false,true,false): 811 ChartFactory.createLineChart(title,xaxistitle,yaxistitle,createDatasetCategory(),PlotOrientation.VERTICAL,false,true,false); 812 Plot p = chart.getPlot(); 813 Font _font = getFont(); 814 815 // settings 816 setMarker(chart,p); 817 setBackground(chart,p); 818 setBorder(chart,p); 819 set3d(p); 820 setFont(chart,_font); 821 setLabelFormat(chart); 822 setLegend(chart, p, _font); 823 setTooltip(chart); 824 setScale(chart); 825 setAxis(chart); 826 setColor(chart); 827 828 writeOut(chart); 829 } 830 831 private void chartArea() throws PageException, IOException { 832 // create the chart... 833 final JFreeChart chart = ChartFactory.createAreaChart(title,xaxistitle,yaxistitle,createDatasetCategory(),PlotOrientation.VERTICAL,false,true,false); 834 Plot p = chart.getPlot(); 835 Font _font = getFont(); 836 837 // settings 838 setMarker(chart,p); 839 setBackground(chart,p); 840 setBorder(chart,p); 841 set3d(p); 842 setFont(chart,_font); 843 setLabelFormat(chart); 844 setLegend(chart, p, _font); 845 setTooltip(chart); 846 setScale(chart); 847 setAxis(chart); 848 setColor(chart); 849 850 writeOut(chart); 851 } 852 853 private void chartTimeLine() throws PageException, IOException { 854 // create the chart... 855 final JFreeChart chart = ChartFactory.createTimeSeriesChart(title,xaxistitle,yaxistitle,createTimeSeriesCollection(),false,true,false); 856 Plot p = chart.getPlot(); 857 Font _font = getFont(); 858 859 // settings 860 setMarker(chart,p); 861 setBackground(chart,p); 862 setBorder(chart,p); 863 set3d(p); 864 setFont(chart,_font); 865 setLabelFormat(chart); 866 setLegend(chart, p, _font); 867 setTooltip(chart); 868 setScale(chart); 869 setAxis(chart); 870 setColor(chart); 871 872 writeOut(chart); 873 } 874 875 876 877 private void setMarker(JFreeChart chart, Plot p) { 878 if(!showmarkers) return; 879 880 if(markersize<1 || markersize>100) markersize=4; 881 882 883 884 if(p instanceof XYPlot) { 885 XYPlot xyp=(XYPlot) p; 886 XYItemRenderer r = xyp.getRenderer(); 887 if (r instanceof XYLineAndShapeRenderer) { 888 XYLineAndShapeRenderer xyr = (XYLineAndShapeRenderer) r; 889 xyr.setBaseShapesVisible(true); 890 xyr.setBaseShapesFilled(true); 891 892 int seriesCount=_series.size(); 893 for(int i=0;i<seriesCount;i++){ 894 xyr.setSeriesShapesVisible(i, true); 895 xyr.setSeriesItemLabelsVisible(i, true); 896 xyr.setSeriesShape(i, ShapeUtilities.createDiamond(markersize)); 897 xyr.setUseFillPaint(true); 898 xyr.setBaseFillPaint(databackgroundcolor); 899 } 900 } 901 } 902 else if(p instanceof CategoryPlot) { 903 CategoryPlot cp=(CategoryPlot) p; 904 CategoryItemRenderer r = cp.getRenderer(); 905 if (r instanceof LineAndShapeRenderer) { 906 LineAndShapeRenderer lsr = (LineAndShapeRenderer)r; 907 908 int seriesCount=_series.size(); 909 for(int i=0;i<seriesCount;i++){ 910 lsr.setSeriesShapesVisible(i, true); 911 lsr.setSeriesItemLabelsVisible(i, true); 912 lsr.setSeriesShape(i, ShapeUtilities.createDiamond(markersize)); 913 lsr.setUseFillPaint(true); 914 lsr.setBaseFillPaint(databackgroundcolor); 915 } 916 } 917 } 918 } 919 920 921 922 private void setAxis(JFreeChart chart) { 923 Plot plot = chart.getPlot(); 924 if(plot instanceof CategoryPlot) { 925 CategoryPlot cp=(CategoryPlot)plot; 926 927 // Y 928 cp.setDomainGridlinesVisible(showygridlines); 929 if(showygridlines) cp.setDomainGridlinePaint(foregroundcolor); 930 931 cp.setRangeGridlinesVisible(showxgridlines!=NO); 932 if(showxgridlines==NONE)cp.setRangeGridlinePaint(Color.GRAY); 933 else if(showxgridlines==YES)cp.setRangeGridlinePaint(foregroundcolor); 934 } 935 else if(plot instanceof XYPlot) { 936 XYPlot cp=(XYPlot)plot; 937 938 // Y 939 cp.setDomainGridlinesVisible(showygridlines); 940 if(showygridlines) cp.setDomainGridlinePaint(foregroundcolor); 941 942 cp.setRangeGridlinesVisible(showxgridlines!=NO); 943 if(showxgridlines==NONE)cp.setRangeGridlinePaint(Color.GRAY); 944 else if(showxgridlines==YES)cp.setRangeGridlinePaint(foregroundcolor); 945 } 946 } 947 948 949 950 private void setTooltip(JFreeChart chart) { 951 Plot plot = chart.getPlot(); 952 if(plot instanceof PiePlot) { 953 PiePlot pp = (PiePlot)plot; 954 955 pp.setToolTipGenerator(new PieToolTipGeneratorImpl(labelFormat)); 956 957 } 958 else if(plot instanceof CategoryPlot) { 959 CategoryPlot cp=(CategoryPlot) plot; 960 CategoryItemRenderer renderer = cp.getRenderer(); 961 renderer.setBaseToolTipGenerator(new CategoryToolTipGeneratorImpl(labelFormat)); 962 } 963 /*else if(plot instanceof XYPlot) { 964 XYPlot cp=(XYPlot) plot; 965 XYItemRenderer renderer = cp.getRenderer(); 966 renderer.setBaseToolTipGenerator(new XYToolTipGeneratorImpl(labelFormat)); 967 }*/ 968 969 } 970 971 972 973 private void setScale(JFreeChart chart) { 974 Plot plot = chart.getPlot(); 975 if(plot instanceof CategoryPlot) { 976 CategoryPlot cp=(CategoryPlot) plot; 977 ValueAxis rangeAxis = cp.getRangeAxis(); 978 Range r=rangeAxis.getRange(); 979 double lower=r.getLowerBound(); 980 double upper=r.getUpperBound(); 981 982 if(labelFormat==LabelFormatUtil.LABEL_FORMAT_DATE && rangeAxis.getRange().getLowerBound()==0) { 983 lower = smallest; 984 upper=biggest; 985 try { 986 DateTime d = Caster.toDate(Caster.toDouble(lower),true,null,null); 987 lower = DateAdd.call(pageContext,"yyyy", -1, d).castToDoubleValue(lower); 988 } 989 catch (PageException e) {} 990 } 991 if(!Double.isNaN(scalefrom))lower=scalefrom; 992 if(!Double.isNaN(scaleto))upper=scaleto; 993 rangeAxis.setRange(new Range(lower,upper),true,true); 994 } 995 else if(plot instanceof XYPlot) { 996 XYPlot cp=(XYPlot) plot; 997 ValueAxis rangeAxis = cp.getRangeAxis(); 998 Range r=rangeAxis.getRange(); 999 double lower=r.getLowerBound(); 1000 double upper=r.getUpperBound(); 1001 1002 if(labelFormat==LabelFormatUtil.LABEL_FORMAT_DATE && rangeAxis.getRange().getLowerBound()==0) { 1003 lower = smallest; 1004 upper=biggest; 1005 try { 1006 DateTime d = Caster.toDate(Caster.toDouble(lower),true,null,null); 1007 lower = DateAdd.call(pageContext,"yyyy", -1, d).castToDoubleValue(lower); 1008 } 1009 catch (PageException e) {} 1010 } 1011 if(!Double.isNaN(scalefrom))lower=scalefrom; 1012 if(!Double.isNaN(scaleto))upper=scaleto; 1013 rangeAxis.setRange(new Range(lower,upper),true,true); 1014 } 1015 } 1016 1017 private void setLabelFormat(JFreeChart chart) { 1018 Plot plot = chart.getPlot(); 1019 if(plot instanceof CategoryPlot) { 1020 CategoryPlot cp=(CategoryPlot) plot; 1021 ValueAxis rangeAxis = cp.getRangeAxis(); 1022 rangeAxis.setAutoTickUnitSelection(true); 1023 rangeAxis.setStandardTickUnits(new TickUnitsImpl(rangeAxis.getStandardTickUnits(),labelFormat)); 1024 CategoryItemRenderer r = cp.getRenderer(); 1025 r.setBaseItemLabelsVisible(false); 1026 1027 CategoryAxis da = cp.getDomainAxis(); 1028 if(!showXLabel)da.setTickLabelsVisible(false); 1029 //da.setVisible(false); 1030 } 1031 if(plot instanceof XYPlot) { 1032 XYPlot cp=(XYPlot) plot; 1033 ValueAxis rangeAxis = cp.getRangeAxis(); 1034 rangeAxis.setAutoTickUnitSelection(true); 1035 rangeAxis.setStandardTickUnits(new TickUnitsImpl(rangeAxis.getStandardTickUnits(),labelFormat)); 1036 XYItemRenderer r = cp.getRenderer(); 1037 r.setBaseItemLabelsVisible(false); 1038 1039 ValueAxis da = cp.getDomainAxis(); 1040 if(!showXLabel)da.setTickLabelsVisible(false); 1041 //da.setVisible(false); 1042 } 1043 } 1044 1045 1046 1047 // set individual colors for series 1048 private void setColor(JFreeChart chart) { 1049 Plot p = chart.getPlot(); 1050 if(p instanceof CategoryPlot) { 1051 CategoryPlot cp=(CategoryPlot) p; 1052 1053 CategoryItemRenderer renderer = cp.getRenderer(); 1054 1055 1056 1057 Iterator<ChartSeriesBean> cs = _series.iterator(); 1058 //int seriesCount=_series.size(); 1059 ChartSeriesBean csb; 1060 GradientPaint gp; 1061 Color c=null; 1062 Color[] ac; 1063 1064 int index=0; 1065 while(cs.hasNext()) { 1066 csb= cs.next(); 1067 // more than 1 series 1068 //if(seriesCount>1) { 1069 c=csb.getSeriesColor(); 1070 if(c==null) { 1071 ac=csb.getColorlist(); 1072 if(ac!=null && ac.length>0)c=ac[0]; 1073 } 1074 1075 //} 1076 if(c==null) continue; 1077 gp = new GradientPaint(0.0f, 0.0f, c, 0.0f, 0.0f,c); 1078 renderer.setSeriesPaint(index++, gp); 1079 } 1080 } 1081 else if(p instanceof XYPlot) { 1082 XYPlot cp=(XYPlot) p; 1083 1084 XYItemRenderer renderer = cp.getRenderer(); 1085 1086 1087 1088 Iterator<ChartSeriesBean> cs = _series.iterator(); 1089 //int seriesCount=_series.size(); 1090 ChartSeriesBean csb; 1091 GradientPaint gp; 1092 Color c=null; 1093 Color[] ac; 1094 1095 int index=0; 1096 while(cs.hasNext()) { 1097 csb= cs.next(); 1098 // more than 1 series 1099 //if(seriesCount>1) { 1100 c=csb.getSeriesColor(); 1101 if(c==null) { 1102 ac=csb.getColorlist(); 1103 if(ac!=null && ac.length>0)c=ac[0]; 1104 } 1105 1106 //} 1107 if(c==null) continue; 1108 gp = new GradientPaint(0.0f, 0.0f, c, 0.0f, 0.0f,c); 1109 renderer.setSeriesPaint(index++, gp); 1110 } 1111 } 1112 } 1113 1114 1115 1116 private DefaultPieDataset createDatasetPie() { 1117 DefaultPieDataset dataset = new DefaultPieDataset(); 1118 ChartSeriesBean csb = _series.get(0); 1119 1120 ChartDataBean cdb; 1121 // write data set 1122 Iterator itt = csb.getDatas().iterator(); 1123 while(itt.hasNext()) { 1124 cdb=(ChartDataBean) itt.next(); 1125 dataset.setValue(cdb.getItemAsString(), cdb.getValue()); 1126 } 1127 return dataset; 1128 } 1129 1130 1131 1132 1133 1134 private CategoryDataset createDatasetCategory() { 1135 final DefaultCategoryDataset dataset = new DefaultCategoryDataset(); 1136 Iterator<ChartSeriesBean> it = _series.iterator(); 1137 //int seriesCount=_series.size(); 1138 Iterator itt; 1139 List datas; 1140 ChartSeriesBean csb; 1141 ChartDataBean cdb; 1142 int count=0; 1143 smallest=Double.MAX_VALUE; 1144 biggest = Double.MIN_VALUE; 1145 String label; 1146 boolean hasLabels=false; 1147 while(it.hasNext()) { 1148 count++; 1149 csb= it.next(); 1150 label=csb.getSeriesLabel(); 1151 if(StringUtil.isEmpty(label))label=""+count; 1152 else hasLabels=true; 1153 datas = csb.getDatas(); 1154 if(sortxaxis)Collections.sort(datas); 1155 itt=datas.iterator(); 1156 while(itt.hasNext()) { 1157 cdb=(ChartDataBean) itt.next(); 1158 if(smallest>cdb.getValue())smallest=cdb.getValue(); 1159 if(biggest<cdb.getValue())biggest=cdb.getValue(); 1160 //if(seriesCount>1) 1161 1162 dataset.addValue(cdb.getValue(), label,cdb.getItemAsString()); 1163 1164 //else dataset.addValue(cdb.getValue(), cdb.getItem(),""); 1165 1166 1167 } 1168 } 1169 if(!hasLabels)showlegend=false; 1170 return dataset; 1171 } 1172 private XYDataset createTimeSeriesCollection() { 1173 TimeZone tz = ThreadLocalPageContext.getTimeZone(); 1174 final TimeSeriesCollection coll=new TimeSeriesCollection(tz); 1175 1176 //final DefaultCategoryDataset dataset = new DefaultCategoryDataset(); 1177 Iterator<ChartSeriesBean> it = _series.iterator(); 1178 //int seriesCount=_series.size(); 1179 Iterator itt; 1180 List datas; 1181 ChartSeriesBean csb; 1182 ChartDataBean cdb; 1183 int count=0; 1184 smallest=Double.MAX_VALUE; 1185 biggest = Double.MIN_VALUE; 1186 String label; 1187 boolean hasLabels=false; 1188 while(it.hasNext()) { 1189 count++; 1190 csb=it.next(); 1191 label=csb.getSeriesLabel(); 1192 if(StringUtil.isEmpty(label))label=""+count; 1193 else hasLabels=true; 1194 datas = csb.getDatas(); 1195 if(sortxaxis)Collections.sort(datas); 1196 itt=datas.iterator(); 1197 TimeSeries ts=new TimeSeries(label,Second.class); 1198 while(itt.hasNext()) { 1199 cdb=(ChartDataBean) itt.next(); 1200 if(smallest>cdb.getValue())smallest=cdb.getValue(); 1201 if(biggest<cdb.getValue())biggest=cdb.getValue(); 1202 //if(seriesCount>1) 1203 ts.addOrUpdate(new Second(DateCaster.toDateSimple(cdb.getItem(),false, tz,null)), cdb.getValue()); 1204 1205 //else dataset.addValue(cdb.getValue(), cdb.getItem(),""); 1206 1207 1208 } 1209 coll.addSeries(ts); 1210 } 1211 if(!hasLabels)showlegend=false; 1212 return coll; 1213 } 1214 1215 /** 1216 * @param url the url to set 1217 */ 1218 public void setUrl(String url) { 1219 this.url = url; 1220 } 1221 1222 /** 1223 * @param xoffset the xoffset to set 1224 */ 1225 public void setXoffset(double xoffset) { 1226 this.xoffset = xoffset; 1227 } 1228 1229 /** 1230 * @param yoffset the yoffset to set 1231 */ 1232 public void setYoffset(double yoffset) { 1233 this.yoffset = yoffset; 1234 } 1235 1236 /** 1237 * @param yaxistype the yaxistype to set 1238 */ 1239 public void setYaxistype(String yaxistype) { 1240 this.yaxistype = yaxistype; 1241 } 1242 /** 1243 * @param yaxistype the yaxistype to set 1244 */ 1245 public void setXaxistype(String xaxistype) { 1246 this.xaxistype = xaxistype; 1247 } 1248 1249 }