comparison flys-artifacts/src/main/java/de/intevation/flys/exports/XYChartGenerator.java @ 2161:c68f4f227c09

Somewhat unified Annotation handling, use jfreechart-house-toolkit instead of custom StickyAxisAnnotation. flys-artifacts/trunk@3747 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Felix Wolfsteller <felix.wolfsteller@intevation.de>
date Mon, 23 Jan 2012 10:44:34 +0000
parents 2336927cb096
children 105097966111
comparison
equal deleted inserted replaced
2160:8428de5846e8 2161:c68f4f227c09
29 import org.jfree.chart.ChartFactory; 29 import org.jfree.chart.ChartFactory;
30 import org.jfree.chart.JFreeChart; 30 import org.jfree.chart.JFreeChart;
31 import org.jfree.chart.LegendItem; 31 import org.jfree.chart.LegendItem;
32 import org.jfree.chart.LegendItemCollection; 32 import org.jfree.chart.LegendItemCollection;
33 import org.jfree.chart.annotations.XYBoxAnnotation; 33 import org.jfree.chart.annotations.XYBoxAnnotation;
34 import org.jfree.chart.annotations.XYLineAnnotation;
34 import org.jfree.chart.annotations.XYTextAnnotation; 35 import org.jfree.chart.annotations.XYTextAnnotation;
35 import org.jfree.chart.axis.NumberAxis; 36 import org.jfree.chart.axis.NumberAxis;
36 import org.jfree.chart.axis.ValueAxis; 37 import org.jfree.chart.axis.ValueAxis;
37 import org.jfree.chart.plot.PlotOrientation; 38 import org.jfree.chart.plot.PlotOrientation;
38 import org.jfree.chart.plot.XYPlot; 39 import org.jfree.chart.plot.XYPlot;
39 import org.jfree.chart.renderer.xy.XYItemRenderer;
40 import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; 40 import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
41 import org.jfree.data.Range; 41 import org.jfree.data.Range;
42 import org.jfree.data.xy.XYSeries; 42 import org.jfree.data.xy.XYSeries;
43 import org.jfree.data.xy.XYSeriesCollection; 43 import org.jfree.data.xy.XYSeriesCollection;
44 import org.jfree.data.xy.XYDataset; 44 import org.jfree.data.xy.XYDataset;
45 45
46 import org.jfree.ui.RectangleInsets; 46 import org.jfree.ui.RectangleInsets;
47 import org.jfree.ui.TextAnchor;
47 48
48 import de.intevation.artifacts.CallContext; 49 import de.intevation.artifacts.CallContext;
49 50
50 import de.intevation.artifactdatabase.state.Facet; 51 import de.intevation.artifactdatabase.state.Facet;
51 import de.intevation.artifactdatabase.state.Settings; 52 import de.intevation.artifactdatabase.state.Settings;
54 import de.intevation.flys.exports.ChartExportHelper; 55 import de.intevation.flys.exports.ChartExportHelper;
55 import de.intevation.flys.jfree.EnhancedLineAndShapeRenderer; 56 import de.intevation.flys.jfree.EnhancedLineAndShapeRenderer;
56 import de.intevation.flys.jfree.FLYSAnnotation; 57 import de.intevation.flys.jfree.FLYSAnnotation;
57 import de.intevation.flys.jfree.StableXYDifferenceRenderer; 58 import de.intevation.flys.jfree.StableXYDifferenceRenderer;
58 import de.intevation.flys.jfree.StickyAxisAnnotation; 59 import de.intevation.flys.jfree.StickyAxisAnnotation;
60 import de.intevation.flys.jfree.CollisionFreeXYTextAnnotation;
59 import de.intevation.flys.jfree.StyledAreaSeriesCollection; 61 import de.intevation.flys.jfree.StyledAreaSeriesCollection;
60 import de.intevation.flys.jfree.StyledXYSeries; 62 import de.intevation.flys.jfree.StyledXYSeries;
61 63
62 import de.intevation.flys.utils.ThemeAccess; 64 import de.intevation.flys.utils.ThemeAccess;
63 65
505 //debugDatasets(plot); 507 //debugDatasets(plot);
506 508
507 recoverEmptyPlot(plot); 509 recoverEmptyPlot(plot);
508 preparePointRanges(plot); 510 preparePointRanges(plot);
509 511
510 addAnnotationsToRenderer(plot);
511
512 //debugAxis(plot); 512 //debugAxis(plot);
513 513
514 localizeAxes(plot); 514 localizeAxes(plot);
515 adjustAxes(plot); 515 adjustAxes(plot);
516 autoZoom(plot); 516 autoZoom(plot);
517 517
518 // These have to go after the autozoom. 518 // These have to go after the autozoom.
519 addBoxAnnotations(plot); 519 addAnnotationsToRenderer(plot);
520 520
521 return chart; 521 return chart;
522 } 522 }
523 523
524 524
970 } 970 }
971 971
972 return null; 972 return null;
973 } 973 }
974 974
975 975 public LegendItem createLegendItem(Document theme, String name) {
976 /** 976 // OPTIMIZE Pass font, parsed Theme items.
977 * Add annotations to Renderer. 977 ThemeAccess themeAccess = new ThemeAccess(theme);
978 */ 978 Color color = themeAccess.parseLineColorField();
979 protected void addAnnotationsToRenderer(XYPlot plot) { 979 LegendItem li = new LegendItem(name, color);
980 plot.clearAnnotations(); 980 li.setLabelFont(createLegendLabelFont());
981 981 return li;
982 if (annotations == null) { 982 }
983 logger.debug("No Annotations given."); 983
984 return; 984
985 } 985 /**
986 986 * Get "lowest" X Value for first axis. This value is exactly at the
987 Font labelFont = createLegendLabelFont(); 987 * border of the plot.
988 988 * @return lowest value on first 'x'-axis.
989 LegendItemCollection lic = new LegendItemCollection(); 989 */
990 LegendItemCollection old = plot.getFixedLegendItems(); 990 protected double getLowestXValue(XYPlot plot) {
991 991 ValueAxis axis = plot.getDomainAxis();
992 XYItemRenderer renderer = plot.getRenderer(0); 992 if (axis == null) {
993 993 logger.warn("No X-Axis to find lowest value for.");
994 for (FLYSAnnotation fa: annotations) { 994 }
995 Document theme = fa.getTheme(); 995 return axis.getRange().getLowerBound();
996 996 }
997 ThemeAccess themeAccess = new ThemeAccess(theme); 997
998 998
999 Color color = themeAccess.parseLineColorField(); 999 /**
1000 int lineWidth = themeAccess.parseLineWidth(); 1000 * Get "lowest" X Value for first axis. This value is exactly at the
1001 1001 * border of the plot.
1002 LegendItem li = new LegendItem(fa.getLabel(), color); 1002 * @return highest value on first 'x'-axis.
1003 li.setLabelFont(labelFont); 1003 */
1004 1004 protected double getUppestXValue(XYPlot plot) {
1005 lic.add(li); 1005 ValueAxis axis = plot.getDomainAxis();
1006 1006 if (axis == null) {
1007 for (XYTextAnnotation ta: fa.getTextAnnotations()) { 1007 logger.warn("No first Y-Axis to find uppest value for.");
1008 if(ta instanceof StickyAxisAnnotation) { 1008 }
1009 StickyAxisAnnotation sta = (StickyAxisAnnotation)ta; 1009 return axis.getRange().getUpperBound();
1010 sta.applyTheme(themeAccess);
1011 renderer.addAnnotation(sta);
1012 }
1013 else {
1014 ta.setPaint(color);
1015 ta.setOutlineStroke(new BasicStroke((float) lineWidth));
1016 renderer.addAnnotation(ta);
1017 }
1018 }
1019 }
1020
1021 // (Re-)Add prior legend entries.
1022 if (old != null) {
1023 old.addAll(lic);
1024 }
1025 else {
1026 old = lic;
1027 }
1028
1029 plot.setFixedLegendItems(old);
1030 } 1010 }
1031 1011
1032 1012
1033 /** 1013 /**
1034 * Get "lowest" Y Value for first axis. This value is exactly at the 1014 * Get "lowest" Y Value for first axis. This value is exactly at the
1082 return new Color(255, 0, 0); 1062 return new Color(255, 0, 0);
1083 } 1063 }
1084 } 1064 }
1085 1065
1086 1066
1087 /** Add box annotations (currently, only hyk zones). */ 1067 /**
1088 public void addBoxAnnotations(XYPlot plot) { 1068 * Add a text and a line annotation.
1089 logger.debug("XYChartGenerator.addBoxAnnotations"); 1069 */
1070 public void addStickyAnnotation(
1071 StickyAxisAnnotation annotation,
1072 XYPlot plot,
1073 Area area,
1074 ThemeAccess.LineStyle lineStyle,
1075 ThemeAccess.TextStyle textStyle
1076 ) {
1077 // OPTIMIZE pre-calculate area-related values
1078 final float TEXT_OFF = 0.03f;
1079 final float LINE_OFF = 0.02f;
1080
1081 XYLineAnnotation lineAnnotation = null;
1082 XYTextAnnotation textAnnotation = null;
1083
1084 if (annotation.atX()) {
1085 textAnnotation = new CollisionFreeXYTextAnnotation(
1086 annotation.getText(), annotation.getPos(), area.ofGround(TEXT_OFF));
1087 // OPTIMIZE externalize the calculation involving PI.
1088 textAnnotation.setRotationAngle(270f*Math.PI/180f);
1089 // Style the line.
1090 if (lineStyle != null) {
1091 lineAnnotation = new XYLineAnnotation(annotation.getPos(),
1092 area.atGround(), annotation.getPos(), area.ofGround(LINE_OFF),
1093 new BasicStroke(lineStyle.getWidth()),lineStyle.getColor());
1094 }
1095 else {
1096 lineAnnotation = new XYLineAnnotation(annotation.getPos(),
1097 area.atGround(), annotation.getPos(), area.ofGround(LINE_OFF));
1098 }
1099 }
1100 else {
1101 textAnnotation = new CollisionFreeXYTextAnnotation(
1102 annotation.getText(), area.ofLeft(TEXT_OFF), annotation.getPos());
1103 // Style the line.
1104 if (lineStyle != null) {
1105 lineAnnotation = new XYLineAnnotation(area.atLeft(),
1106 annotation.getPos(), area.ofLeft(LINE_OFF),
1107 annotation.getPos(), new BasicStroke(lineStyle.getWidth()),
1108 lineStyle.getColor());
1109 }
1110 else {
1111 lineAnnotation = new XYLineAnnotation(area.atLeft(),
1112 annotation.getPos(), area.ofLeft(LINE_OFF), annotation.getPos());
1113 }
1114 }
1115
1116 // Style the text.
1117 if (textStyle != null) {
1118 textStyle.apply(textAnnotation);
1119 }
1120
1121 // Add the Annotations to renderer.
1122 textAnnotation.setRotationAnchor(TextAnchor.CENTER_LEFT);
1123 textAnnotation.setTextAnchor(TextAnchor.CENTER_LEFT);
1124
1125 plot.getRenderer().addAnnotation(textAnnotation,
1126 org.jfree.ui.Layer.BACKGROUND);
1127 plot.getRenderer().addAnnotation(lineAnnotation,
1128 org.jfree.ui.Layer.BACKGROUND);
1129 }
1130
1131
1132 /** Add annotations (Sticky, Text and hyk zones). */
1133 public void addAnnotationsToRenderer(XYPlot plot) {
1134 logger.debug("XYChartGenerator.addAnnotationsToRenderer");
1090 1135
1091 if (annotations == null) { 1136 if (annotations == null) {
1092 logger.debug("XYChartGenerator.addBoxAnnotations: no annotations."); 1137 logger.debug("XYChartGenerator.addBoxAnnotations: no annotations.");
1093 return; 1138 return;
1094 } 1139 }
1095 1140
1096 // Paints for the boxes/lines. 1141 // Paints for the boxes/lines.
1097 Stroke basicStroke = new BasicStroke(1.0f); 1142 Stroke basicStroke = new BasicStroke(1.0f);
1098 1143
1099 Paint linePaint = new Color(255,0,0,60); 1144 Paint linePaint = new Color(255, 0,0,60);
1100 Paint fillPaint = new Color(0,255,0,60); 1145 Paint fillPaint = new Color(0, 255,0,60);
1101 Paint tranPaint = new Color(0,0,0,0); 1146 Paint tranPaint = new Color(0, 0,0, 0);
1102 1147
1103 // Pre-calculated positions on y axis. 1148 // OPTMIMIZE: Pre-calculate positions
1104 double fillPercent = 0.03; 1149 Area area = new Area(
1105 double low = getLowestYValue(plot); 1150 plot.getDomainAxis(0).getRange(),
1106 double up = getUppestYValue(plot); 1151 plot.getRangeAxis().getRange());
1107 double upb = low + (up - low) * fillPercent; 1152
1108 double upt = low + (up - low) * fillPercent/2.0d; 1153 // Walk over all Annotation sets.
1109
1110
1111 for (FLYSAnnotation fa: annotations) { 1154 for (FLYSAnnotation fa: annotations) {
1155
1112 // Access text styling, if any. 1156 // Access text styling, if any.
1113 Document theme = fa.getTheme(); 1157 Document theme = fa.getTheme();
1114 ThemeAccess.TextStyle textStyle = null; 1158 ThemeAccess.TextStyle textStyle = null;
1159 ThemeAccess.LineStyle lineStyle = null;
1160
1161 // Get Themeing information and add legend item.
1115 if (theme != null) { 1162 if (theme != null) {
1116 ThemeAccess themeAccess = new ThemeAccess(theme); 1163 ThemeAccess themeAccess = new ThemeAccess(theme);
1117 textStyle = themeAccess.parseTextStyle(); 1164 textStyle = themeAccess.parseTextStyle();
1118 } 1165 lineStyle = themeAccess.parseLineStyle();
1119 1166 LegendItemCollection lic = new LegendItemCollection();
1120 // For each zone, create a box to fill with color, a box to draw 1167 LegendItemCollection old = plot.getFixedLegendItems();
1121 // the lines and a text to display the type. 1168 lic.add(createLegendItem(theme, fa.getLabel()));
1169 // (Re-)Add prior legend entries.
1170 if (old != null) {
1171 old.addAll(lic);
1172 }
1173 else {
1174 old = lic;
1175 }
1176 plot.setFixedLegendItems(old);
1177 }
1178
1179 // The 'Sticky' Annotations (at axis, with line and text).
1180 for (StickyAxisAnnotation sta: fa.getAxisTextAnnotations()) {
1181 addStickyAnnotation(sta, plot, area, lineStyle, textStyle);
1182 }
1183
1184 // The not yet implemented other Text Annotations.
1185 for (XYTextAnnotation ta: fa.getTextAnnotations()) {
1186 // TODO implement, one we have textannotations
1187 }
1188
1189 // Hyks.
1122 for (HYKFactory.Zone zone: fa.getBoxes()) { 1190 for (HYKFactory.Zone zone: fa.getBoxes()) {
1191 // For each zone, create a box to fill with color, a box to draw
1192 // the lines and a text to display the type.
1123 fillPaint = colorForHYKZone(zone.getName()); 1193 fillPaint = colorForHYKZone(zone.getName());
1124 1194
1125 XYBoxAnnotation boxA = new XYBoxAnnotation(zone.getFrom(), low, 1195 XYBoxAnnotation boxA = new XYBoxAnnotation(zone.getFrom(), area.atGround(),
1126 zone.getTo(), upb, basicStroke, tranPaint, fillPaint); 1196 zone.getTo(), area.ofGround(0.03f), basicStroke, tranPaint, fillPaint);
1127 XYBoxAnnotation boxB = new XYBoxAnnotation(zone.getFrom(), low, 1197 XYBoxAnnotation boxB = new XYBoxAnnotation(zone.getFrom(), area.atGround(),
1128 zone.getTo(), up, basicStroke, fillPaint, tranPaint); 1198 zone.getTo(), area.atTop(), basicStroke, fillPaint, tranPaint);
1129 1199
1130 XYTextAnnotation tex = new XYTextAnnotation(zone.getName(), 1200 XYTextAnnotation tex = new XYTextAnnotation(zone.getName(),
1131 zone.getFrom() + (zone.getTo() - zone.getFrom()) / 2.0d, 1201 zone.getFrom() + (zone.getTo() - zone.getFrom()) / 2.0d,
1132 upt); 1202 area.ofGround(0.015f));
1133 if (textStyle != null) { 1203 if (textStyle != null) {
1134 textStyle.apply(tex); 1204 textStyle.apply(tex);
1135 } 1205 }
1136 1206
1137 plot.getRenderer().addAnnotation(boxA); 1207 plot.getRenderer().addAnnotation(boxA, org.jfree.ui.Layer.BACKGROUND);
1138 plot.getRenderer().addAnnotation(boxB); 1208 plot.getRenderer().addAnnotation(boxB, org.jfree.ui.Layer.BACKGROUND);
1139 plot.getRenderer().addAnnotation(tex); 1209 plot.getRenderer().addAnnotation(tex, org.jfree.ui.Layer.BACKGROUND);
1140 } 1210 }
1141 } 1211 }
1142 } 1212 }
1143 1213
1144 1214
1551 axisSections.add(ySection); 1621 axisSections.add(ySection);
1552 } 1622 }
1553 1623
1554 return axisSections; 1624 return axisSections;
1555 } 1625 }
1626
1627
1628 /** Two Ranges that span a rectangular area. */
1629 public static class Area {
1630 protected Range xRange;
1631 protected Range yRange;
1632
1633 public Area(Range rangeX, Range rangeY) {
1634 this.xRange = rangeX;
1635 this.yRange = rangeY;
1636 }
1637
1638 public double ofLeft(double percent) {
1639 return xRange.getLowerBound()
1640 + xRange.getLength() * percent;
1641 }
1642
1643 public double ofGround(double percent) {
1644 return yRange.getLowerBound()
1645 + yRange.getLength() * percent;
1646 }
1647
1648 public double atTop() {
1649 return yRange.getUpperBound();
1650 }
1651
1652 public double atGround() {
1653 return yRange.getLowerBound();
1654 }
1655
1656 public double atLeft() {
1657 return xRange.getLowerBound();
1658 }
1659 }
1556 } 1660 }
1557 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : 1661 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org