comparison flys-artifacts/src/main/java/org/dive4elements/river/exports/TimeseriesChartGenerator.java @ 5831:bd047b71ab37

Repaired internal references
author Sascha L. Teichmann <teichmann@intevation.de>
date Thu, 25 Apr 2013 12:06:39 +0200
parents flys-artifacts/src/main/java/de/intevation/flys/exports/TimeseriesChartGenerator.java@7eebd9e58641
children
comparison
equal deleted inserted replaced
5830:160f53ee0870 5831:bd047b71ab37
1 package org.dive4elements.river.exports;
2
3 import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
4 import org.dive4elements.river.artifacts.resources.Resources;
5 import org.dive4elements.river.jfree.Bounds;
6 import org.dive4elements.river.jfree.CollisionFreeXYTextAnnotation;
7 import org.dive4elements.river.jfree.DoubleBounds;
8 import org.dive4elements.river.jfree.FLYSAnnotation;
9 import org.dive4elements.river.jfree.StyledTimeSeries;
10 import org.dive4elements.river.jfree.TimeBounds;
11
12 import java.awt.Color;
13 import java.awt.Font;
14 import java.text.DateFormat;
15 import java.text.ParseException;
16 import java.util.ArrayList;
17 import java.util.Date;
18 import java.util.HashMap;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.Map;
22
23 import javax.swing.ImageIcon;
24
25 import org.apache.log4j.Logger;
26 import org.jfree.chart.ChartFactory;
27 import org.jfree.chart.JFreeChart;
28 import org.jfree.chart.LegendItem;
29 import org.jfree.chart.LegendItemCollection;
30 import org.jfree.chart.annotations.XYAnnotation;
31 import org.jfree.chart.annotations.XYImageAnnotation;
32 import org.jfree.chart.annotations.XYTextAnnotation;
33 import org.jfree.chart.axis.ValueAxis;
34 import org.jfree.chart.plot.Marker;
35 import org.jfree.chart.plot.XYPlot;
36 import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
37 import org.jfree.data.Range;
38 import org.jfree.data.general.Series;
39 import org.jfree.data.time.Day;
40 import org.jfree.data.time.TimeSeries;
41 import org.jfree.data.time.TimeSeriesCollection;
42 import org.jfree.data.xy.XYDataset;
43 import org.jfree.ui.Layer;
44 import org.json.JSONArray;
45 import org.json.JSONException;
46 import org.w3c.dom.Document;
47
48 /**
49 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
50 */
51 public abstract class TimeseriesChartGenerator extends ChartGenerator {
52
53
54 /**
55 * Inner class TimeseriesAxisDataset stores TimeSeriesCollection.
56 */
57 public class TimeseriesAxisDataset implements AxisDataset {
58
59 protected int axisSymbol;
60
61 protected List<TimeSeriesCollection> datasets;
62
63 protected Range range;
64
65 protected int plotAxisIndex;
66
67 public TimeseriesAxisDataset(int axisSymbol) {
68 this.axisSymbol = axisSymbol;
69 this.datasets = new ArrayList<TimeSeriesCollection>();
70 }
71
72
73 @Override
74 public void addDataset(XYDataset dataset) {
75 if (!(dataset instanceof TimeSeriesCollection)) {
76 logger.warn("Skip non TimeSeriesCollection dataset.");
77 return;
78 }
79
80 TimeSeriesCollection tsc = (TimeSeriesCollection) dataset;
81
82 datasets.add(tsc);
83 mergeRanges(tsc);
84 }
85
86
87 @Override
88 public XYDataset[] getDatasets() {
89 return datasets.toArray(new XYDataset[datasets.size()]);
90 }
91
92
93 @Override
94 public boolean isEmpty() {
95 return datasets.isEmpty();
96 }
97
98
99 @Override
100 public void setRange(Range range) {
101 this.range = range;
102 }
103
104
105 @Override
106 public Range getRange() {
107 return range;
108 }
109
110
111 @Override
112 public void setPlotAxisIndex(int plotAxisIndex) {
113 this.plotAxisIndex = plotAxisIndex;
114 }
115
116
117 @Override
118 public int getPlotAxisIndex() {
119 return plotAxisIndex;
120 }
121
122
123 @Override
124 public boolean isArea(XYDataset dataset) {
125 logger.warn("This AxisDataset doesn't support Areas yet!");
126 return false;
127 }
128
129
130 protected void mergeRanges(TimeSeriesCollection dataset) {
131 logger.debug("Range before merging: " + range);
132 Range subRange = null;
133
134 // Determine min/max of range axis.
135 for (int i = 0; i < dataset.getSeriesCount(); i++) {
136 if (dataset.getSeries(i).getItemCount() == 0) {
137 continue;
138 }
139 double min = Double.MAX_VALUE;
140 double max = -Double.MAX_VALUE;
141 TimeSeries series = dataset.getSeries(i);
142 for (int j = 0; j < series.getItemCount(); j++) {
143 double tmp = series.getValue(j).doubleValue();
144 min = tmp < min ? tmp : min;
145 max = tmp > max ? tmp : max;
146 }
147 if (subRange != null) {
148 subRange = new Range(
149 min < subRange.getLowerBound() ?
150 min : subRange.getLowerBound(),
151 max > subRange.getUpperBound() ?
152 max : subRange.getUpperBound());
153 }
154 else {
155 subRange = new Range(min, max);
156 }
157 }
158
159 // Avoid merging NaNs, as they take min/max place forever.
160 if (subRange == null ||
161 Double.isNaN(subRange.getLowerBound()) ||
162 Double.isNaN(subRange.getUpperBound())) {
163 return;
164 }
165 if (range == null) {
166 range = subRange;
167 return;
168 }
169 range = Range.combine(range, subRange);
170 }
171
172 } // end of TimeseriesAxisDataset class
173
174 protected List<Marker> domainMarker;
175
176 protected List<Marker> valueMarker;
177
178 protected Map<String, String> attributes;
179
180 protected boolean domainZeroLineVisible;
181
182 private static final Logger logger =
183 Logger.getLogger(TimeseriesChartGenerator.class);
184
185 public static final int AXIS_SPACE = 5;
186
187 protected Map<Integer, Bounds> xBounds;
188
189 protected Map<Integer, Bounds> yBounds;
190
191
192 /**
193 * The default constructor that initializes internal datastructures.
194 */
195 public TimeseriesChartGenerator() {
196 super();
197
198 xBounds = new HashMap<Integer, Bounds>();
199 yBounds = new HashMap<Integer, Bounds>();
200 domainMarker = new ArrayList<Marker>();
201 valueMarker = new ArrayList<Marker>();
202 attributes = new HashMap<String, String>();
203 }
204
205
206
207 @Override
208 public JFreeChart generateChart() {
209 logger.info("Generate Timeseries Chart.");
210
211 JFreeChart chart = ChartFactory.createTimeSeriesChart(
212 getChartTitle(),
213 getXAxisLabel(),
214 getYAxisLabel(0),
215 null,
216 isLegendVisible(),
217 false,
218 false);
219
220 XYPlot plot = (XYPlot) chart.getPlot();
221
222 chart.setBackgroundPaint(Color.WHITE);
223 plot.setBackgroundPaint(Color.WHITE);
224
225 addSubtitles(chart);
226 adjustPlot(plot);
227 addDatasets(plot);
228 adjustAxes(plot);
229 addDomainAxisMarker(plot);
230 addValueAxisMarker(plot);
231 adaptZoom(plot);
232
233 applySeriesAttributes(plot);
234
235 addAnnotationsToRenderer(plot);
236 addLogo(plot);
237 aggregateLegendEntries(plot);
238 return chart;
239 }
240
241
242 /**
243 * Return left most data points x value (on first axis).
244 * Shortcut, especially to be overridden in (LS) charts where
245 * axis could be inverted.
246 */
247 protected double getLeftX() {
248 return (Long)getXBounds(0).getLower();
249 }
250
251
252 /**
253 * Return right most data points x value (on first axis).
254 * Shortcut, especially to be overridden in (LS) charts where
255 * axis could be inverted.
256 */
257 protected double getRightX() {
258 return (Long)getXBounds(0).getUpper();
259 }
260
261
262 /**
263 * Add a logo as background annotation to plot.
264 * Copy from XYChartGenerator.
265 */
266 protected void addLogo(XYPlot plot) {
267 String logo = showLogo();
268 if (logo == null) {
269 logger.debug("No logo to show chosen");
270 return;
271 }
272
273 ImageIcon imageIcon = null;
274 if (logo.equals("none")) {
275 return;
276 }
277 /*
278 If you want to add images, remember to change code in these places:
279 flys-artifacts:
280 XYChartGenerator.java
281 Timeseries*Generator.java and
282 in the flys-client projects Chart*Propert*Editor.java.
283 Also, these images have to be put in
284 flys-artifacts/src/main/resources/images/
285 flys-client/src/main/webapp/images/
286 */
287 java.net.URL imageURL;
288 if (logo.equals("Intevation")) {
289 imageURL = XYChartGenerator.class.getResource("/images/intevation.png");
290 }
291 else { // TODO else if ...
292 imageURL = XYChartGenerator.class.getResource("/images/bfg_logo.gif");
293 }
294 imageIcon = new ImageIcon(imageURL);
295 double xPos = 0d, yPos = 0d;
296
297 String placeh = logoHPlace();
298 String placev = logoVPlace();
299
300 if (placev == null || placev.equals("none")) {
301 placev = "top";
302 }
303 if (placev.equals("top")) {
304 yPos = (Double)getYBounds(0).getUpper();
305 }
306 else if (placev.equals("bottom")) {
307 yPos = (Double)getYBounds(0).getLower();
308 }
309 else if (placev.equals("center")) {
310 yPos = ((Double)getYBounds(0).getUpper() + (Double)getYBounds(0).getLower())/2d;
311 }
312 else {
313 logger.debug("Unknown place-v value: " + placev);
314 }
315
316 if (placeh == null || placeh.equals("none")) {
317 placeh = "center";
318 }
319 if (placeh.equals("left")) {
320 xPos = getLeftX();
321 }
322 else if (placeh.equals("right")) {
323 xPos = getRightX();
324 }
325 else if (placeh.equals("center")) {
326 xPos = ((Long)getXBounds(0).getUpper() + (Long)getXBounds(0).getLower())/2d;
327 }
328 else {
329 logger.debug("Unknown place-h value: " + placeh);
330 }
331
332 logger.debug("logo position: " + xPos + "/" + yPos);
333
334 org.jfree.ui.RectangleAnchor anchor
335 = org.jfree.ui.RectangleAnchor.TOP;
336 if (placev.equals("top")) {
337 if (placeh.equals("left")) {
338 anchor = org.jfree.ui.RectangleAnchor.TOP_LEFT;
339 }
340 else if (placeh.equals("right")) {
341 anchor = org.jfree.ui.RectangleAnchor.TOP_RIGHT;
342 }
343 else if (placeh.equals("center")) {
344 anchor = org.jfree.ui.RectangleAnchor.TOP;
345 }
346 }
347 else if (placev.equals("bottom")) {
348 if (placeh.equals("left")) {
349 anchor = org.jfree.ui.RectangleAnchor.BOTTOM_LEFT;
350 }
351 else if (placeh.equals("right")) {
352 anchor = org.jfree.ui.RectangleAnchor.BOTTOM_RIGHT;
353 }
354 else if (placeh.equals("center")) {
355 anchor = org.jfree.ui.RectangleAnchor.BOTTOM;
356 }
357 }
358 else if (placev.equals("center")) {
359 if (placeh.equals("left")) {
360 anchor = org.jfree.ui.RectangleAnchor.LEFT;
361 }
362 else if (placeh.equals("right")) {
363 anchor = org.jfree.ui.RectangleAnchor.RIGHT;
364 }
365 else if (placeh.equals("center")) {
366 anchor = org.jfree.ui.RectangleAnchor.CENTER;
367 }
368 }
369
370 XYAnnotation xyannotation =
371 new XYImageAnnotation(xPos, yPos, imageIcon.getImage(), anchor);
372 plot.getRenderer().addAnnotation(xyannotation, org.jfree.ui.Layer.BACKGROUND);
373 }
374
375
376 @Override
377 protected Series getSeriesOf(XYDataset dataset, int idx) {
378 return ((TimeSeriesCollection) dataset).getSeries(idx);
379 }
380
381
382 /**
383 * This method creates new instances of TimeseriesAxisDataset.
384 *
385 * @param idx The symbol for the new TimeseriesAxisDataset.
386 */
387 @Override
388 protected AxisDataset createAxisDataset(int idx) {
389 logger.debug("Create a new AxisDataset for index: " + idx);
390 return new TimeseriesAxisDataset(idx);
391 }
392
393
394 @Override
395 protected void combineXBounds(Bounds bounds, int index) {
396 if (bounds != null) {
397 Bounds old = getXBounds(index);
398
399 if (old != null) {
400 bounds = bounds.combine(old);
401 }
402
403 setXBounds(index, bounds);
404 }
405 }
406
407
408 @Override
409 protected void combineYBounds(Bounds bounds, int index) {
410 if (bounds != null) {
411 Bounds old = getYBounds(index);
412
413 if (old != null) {
414 bounds = bounds.combine(old);
415 }
416
417 setYBounds(index, bounds);
418 }
419 }
420
421
422 // TODO REPLACE THIS METHOD WITH getBoundsForAxis(index)
423 @Override
424 public Range[] getRangesForAxis(int index) {
425 // TODO
426 Bounds[] bounds = getBoundsForAxis(index);
427
428 return new Range[] {
429 new Range(
430 bounds[0].getLower().doubleValue(),
431 bounds[0].getUpper().doubleValue()),
432 new Range(
433 bounds[1].getLower().doubleValue(),
434 bounds[1].getUpper().doubleValue())
435 };
436 }
437
438
439 @Override
440 public Bounds getXBounds(int axis) {
441 return xBounds.get(axis);
442 }
443
444
445 @Override
446 protected void setXBounds(int axis, Bounds bounds) {
447 xBounds.put(axis, bounds);
448 }
449
450
451 @Override
452 public Bounds getYBounds(int axis) {
453 return yBounds.get(axis);
454 }
455
456
457 @Override
458 protected void setYBounds(int axis, Bounds bounds) {
459 if (bounds != null) {
460 yBounds.put(axis, bounds);
461 }
462 }
463
464
465 public Bounds[] getBoundsForAxis(int index) {
466 logger.debug("Return x and y bounds for axis at: " + index);
467
468 Bounds rx = getXBounds(Integer.valueOf(index));
469 Bounds ry = getYBounds(Integer.valueOf(index));
470
471 if (rx == null) {
472 logger.warn("Range for x axis not set." +
473 " Using default values: 0 - 1.");
474 rx = new TimeBounds(0l, 1l);
475 }
476
477 if (ry == null) {
478 logger.warn("Range for y axis not set." +
479 " Using default values: 0 - 1.");
480 ry = new DoubleBounds(0l, 1l);
481 }
482
483 logger.debug("X Bounds at index " + index + " is: " + rx);
484 logger.debug("Y Bounds at index " + index + " is: " + ry);
485
486 return new Bounds[] {rx, ry};
487 }
488
489
490 /** Get (zoom)values from request. */
491 public Bounds getDomainAxisRange() {
492 String[] ranges = getDomainAxisRangeFromRequest();
493
494 if (ranges == null || ranges.length < 2) {
495 logger.debug("No zoom range for domain axis specified.");
496 return null;
497 }
498
499 if (ranges[0] == null || ranges[1] == null) {
500 logger.warn("Invalid ranges for domain axis specified!");
501 return null;
502 }
503
504 try {
505 double lower = Double.parseDouble(ranges[0]);
506 double upper = Double.parseDouble(ranges[1]);
507
508 return new DoubleBounds(lower, upper);
509 }
510 catch (NumberFormatException nfe) {
511 logger.warn("Invalid ranges for domain axis specified: " + nfe);
512 }
513
514 return null;
515 }
516
517
518 public Bounds getValueAxisRange() {
519 String[] ranges = getValueAxisRangeFromRequest();
520
521 if (ranges == null || ranges.length < 2) {
522 logger.debug("No zoom range for domain axis specified.");
523 return null;
524 }
525
526 if (ranges[0] == null || ranges[1] == null) {
527 logger.warn("Invalid ranges for domain axis specified!");
528 return null;
529 }
530
531 try {
532 double lower = Double.parseDouble(ranges[0]);
533 double upper = Double.parseDouble(ranges[1]);
534
535 return new DoubleBounds(lower, upper);
536 }
537 catch (NumberFormatException nfe) {
538 logger.warn("Invalid ranges for domain axis specified: " + nfe);
539 }
540
541 return null;
542 }
543
544
545 protected void adaptZoom(XYPlot plot) {
546 logger.debug("Adapt zoom of Timeseries chart.");
547
548 zoomX(plot, plot.getDomainAxis(), getXBounds(0), getDomainAxisRange());
549
550 Bounds valueAxisBounds = getValueAxisRange();
551
552 for (int j = 0, n = plot.getRangeAxisCount(); j < n; j++) {
553 zoomY(
554 plot,
555 plot.getRangeAxis(j),
556 getYBounds(j),
557 valueAxisBounds);
558 }
559 }
560
561
562 /**
563 * @param plot the plot.
564 * @param axis the value (x, time) axis of which to set bounds.
565 * @param total the current bounds (?).
566 */
567 protected void zoomX(
568 XYPlot plot,
569 ValueAxis axis,
570 Bounds total,//we could equally nicely getXBounds(0)
571 Bounds user
572 ) {
573 if (logger.isDebugEnabled()) {
574 logger.debug("== Zoom X axis ==");
575 logger.debug(" Total axis range : " + total);
576 logger.debug(" User defined range: " + user);
577 }
578
579 if (user != null) {
580 long min = total.getLower().longValue();
581 long max = total.getUpper().longValue();
582 long diff = max > min ? max - min : min - max;
583
584 long newMin = Math.round(min + user.getLower().doubleValue() * diff);
585 long newMax = Math.round(min + user.getUpper().doubleValue() * diff);
586
587 TimeBounds newBounds = new TimeBounds(newMin, newMax);
588
589 logger.debug(" Zoom axis to: " + newBounds);
590
591 newBounds.applyBounds(axis, AXIS_SPACE);
592 }
593 else {
594 logger.debug("No user specified zoom values found!");
595 if (total != null && axis != null) {
596 total.applyBounds(axis, AXIS_SPACE);
597 }
598 }
599 }
600
601
602 /**
603 * @param user zoom values in percent.
604 */
605 protected void zoomY(
606 XYPlot plot,
607 ValueAxis axis,
608 Bounds total,
609 Bounds user
610 ) {
611 if (logger.isDebugEnabled()) {
612 logger.debug("== Zoom Y axis ==");
613 logger.debug(" Total axis range : " + total);
614 logger.debug(" User defined range: " + user);
615 }
616
617 if (user != null) {
618 double min = total.getLower().doubleValue();
619 double max = total.getUpper().doubleValue();
620 double diff = max > min ? max - min : min - max;
621
622 double newMin = min + user.getLower().doubleValue() * diff;
623 double newMax = min + user.getUpper().doubleValue() * diff;
624
625 DoubleBounds newBounds = new DoubleBounds(newMin, newMax);
626
627 logger.debug(" Zoom axis to: " + newBounds);
628
629 newBounds.applyBounds(axis, AXIS_SPACE);
630 }
631 else {
632 logger.debug("No user specified zoom values found!");
633 if (total != null && axis != null) {
634 total.applyBounds(axis, AXIS_SPACE);
635 }
636 }
637 }
638
639
640 /**
641 * Adjusts the axes of a plot. This method sets the <i>labelFont</i> of the
642 * X axis.
643 *
644 * (Duplicate in XYChartGenerator).
645 *
646 * @param plot The XYPlot of the chart.
647 */
648 protected void adjustAxes(XYPlot plot) {
649 ValueAxis xaxis = plot.getDomainAxis();
650
651 ChartSettings chartSettings = getChartSettings();
652 if (chartSettings == null) {
653 return;
654 }
655
656 Font labelFont = new Font(
657 DEFAULT_FONT_NAME,
658 Font.BOLD,
659 getXAxisLabelFontSize());
660
661 xaxis.setLabelFont(labelFont);
662 xaxis.setTickLabelFont(labelFont);
663 }
664
665
666 protected Date decodeXAxisValue(JSONArray array) throws JSONException, ParseException {
667 try {
668 double x = array.getDouble(0);
669 long l = (new Double(x)).longValue();
670 return new Date(l);
671 }
672 catch(JSONException ex) {
673 String str = array.getString(0);
674 DateFormat df = DateFormat.getDateInstance(
675 DateFormat.MEDIUM, Resources.getLocale(context.getMeta()));
676 return df.parse(str);
677 }
678 }
679
680 /**
681 * Do Points out.
682 */
683 protected void doPoints(
684 Object o,
685 ArtifactAndFacet aandf,
686 Document theme,
687 boolean visible,
688 int axisIndex
689 ) {
690 String seriesName = aandf.getFacetDescription();
691 TimeSeries series = new StyledTimeSeries(seriesName, theme);
692
693 // Add text annotations for single points.
694 List<XYTextAnnotation> xy = new ArrayList<XYTextAnnotation>();
695 HashMap<Day, String> names = new HashMap<Day, String>();
696
697 try {
698 JSONArray points = new JSONArray((String) o);
699 for (int i = 0, P = points.length(); i < P; i++) {
700 JSONArray array = points.getJSONArray(i);
701
702 double y = array.getDouble(1);
703 String name = array.getString(2);
704 boolean act = array.getBoolean(3);
705 if (!act) {
706 continue;
707 }
708
709 Date date = decodeXAxisValue(array);
710
711 Day day = new Day(date);
712 series.add(day, y, false);
713 names.put(day, name);
714 }
715 }
716 catch(JSONException ex) {
717 logger.error("Could not decode json");
718 }
719 catch(ParseException ex) {
720 logger.error("Could not parse date string");
721 }
722
723 TimeSeriesCollection tsc = new TimeSeriesCollection();
724 tsc.addSeries(series);
725 // Add Annotations.
726 for (int i = 0, S = series.getItemCount(); i < S; i++) {
727 double x = tsc.getXValue(0, i);
728 double y = tsc.getYValue(0, i);
729 xy.add(new CollisionFreeXYTextAnnotation(
730 names.get(series.getTimePeriod(i)), x, y));
731 logger.debug("doPoints(): x=" + x + " y=" + y);
732 }
733 FLYSAnnotation annotations =
734 new FLYSAnnotation(null, null, null, theme);
735 annotations.setTextAnnotations(xy);
736
737 // Do not generate second legend entry. (null was passed for the aand before).
738 doAnnotations(annotations, null, theme, visible);
739
740 addAxisDataset(tsc, axisIndex, visible);
741 }
742
743 public void addDomainAxisMarker(XYPlot plot) {
744 logger.debug("domainmarkers: " + domainMarker.size());
745 for (Marker marker: domainMarker) {
746 logger.debug("adding domain marker");
747 plot.addDomainMarker(marker, Layer.BACKGROUND);
748 }
749 domainMarker.clear();
750 }
751
752 public void addValueAxisMarker(XYPlot plot) {
753 for (Marker marker: valueMarker) {
754 logger.debug("adding value marker..");
755 plot.addRangeMarker(marker, Layer.BACKGROUND);
756 }
757 valueMarker.clear();
758 }
759
760 public void addAttribute(String seriesKey, String name) {
761 attributes.put(seriesKey, name);
762 }
763
764 private LegendItem getLegendItemFor(XYPlot plot, String interSeriesKey) {
765 LegendItemCollection litems = plot.getLegendItems();
766 Iterator<LegendItem> iter = litems.iterator();
767 while(iter.hasNext()) {
768 LegendItem item = iter.next();
769 if(interSeriesKey.startsWith(item.getSeriesKey().toString())) {
770 return item;
771 }
772 }
773 return null;
774 }
775
776 protected void applySeriesAttributes(XYPlot plot) {
777 int count = plot.getDatasetCount();
778 for (int i = 0; i < count; i++) {
779 XYDataset data = plot.getDataset(i);
780 if (data == null) {
781 continue;
782 }
783
784 int seriesCount = data.getSeriesCount();
785 for (int j = 0; j < seriesCount; j++) {
786 StyledTimeSeries series =
787 (StyledTimeSeries)getSeriesOf(data, j);
788 String key = series.getKey().toString();
789
790 if (attributes.containsKey(key)) {
791 // Interpolated points are drawn unfilled
792 if (attributes.get(key).equals("interpolate")) {
793 XYLineAndShapeRenderer renderer =
794 series.getStyle().getRenderer();
795 renderer.setSeriesPaint(
796 j,
797 renderer.getSeriesFillPaint(j));
798 renderer.setSeriesShapesFilled(j, false);
799
800 LegendItem legendItem = getLegendItemFor(plot, key);
801 if(legendItem != null) {
802 LegendItem interLegend = new LegendItem(
803 legendItem.getLabel(),
804 legendItem.getDescription(),
805 legendItem.getToolTipText(),
806 legendItem.getURLText(),
807 legendItem.isShapeVisible(),
808 legendItem.getShape(),
809 false, // shapeFilled?
810 legendItem.getFillPaint(),
811 true, // shapeOutlineVisible?
812 renderer.getSeriesFillPaint(j),
813 legendItem.getOutlineStroke(),
814 legendItem.isLineVisible(),
815 legendItem.getLine(),
816 legendItem.getLineStroke(),
817 legendItem.getLinePaint()
818 );
819 interLegend.setSeriesKey(series.getKey());
820 logger.debug("applySeriesAttributes: draw unfilled legend item");
821 plot.getLegendItems().add(interLegend);
822 }
823 }
824 }
825
826 if (attributes.containsKey(key)) {
827 if(attributes.get(key).equals("outline")) {
828 XYLineAndShapeRenderer renderer =
829 series.getStyle().getRenderer();
830 renderer.setSeriesPaint(
831 j,
832 renderer.getSeriesFillPaint(j));
833 renderer.setDrawOutlines(true);
834 }
835 }
836 }
837 }
838 }
839
840 /** Two Ranges that span a rectangular area. */
841 public static class Area {
842 protected Range xRange;
843 protected Range yRange;
844
845 public Area(Range rangeX, Range rangeY) {
846 this.xRange = rangeX;
847 this.yRange = rangeY;
848 }
849
850 public Area(ValueAxis axisX, ValueAxis axisY) {
851 this.xRange = axisX.getRange();
852 this.yRange = axisY.getRange();
853 }
854
855 public double ofLeft(double percent) {
856 return xRange.getLowerBound()
857 + xRange.getLength() * percent;
858 }
859
860 public double ofRight(double percent) {
861 return xRange.getUpperBound()
862 - xRange.getLength() * percent;
863 }
864
865 public double ofGround(double percent) {
866 return yRange.getLowerBound()
867 + yRange.getLength() * percent;
868 }
869
870 public double atTop() {
871 return yRange.getUpperBound();
872 }
873
874 public double atGround() {
875 return yRange.getLowerBound();
876 }
877
878 public double atRight() {
879 return xRange.getUpperBound();
880 }
881
882 public double atLeft() {
883 return xRange.getLowerBound();
884 }
885
886 public double above(double percent, double base) {
887 return base + yRange.getLength() * percent;
888 }
889 }
890
891 }
892 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org