Mercurial > dive4elements > gnv-client
comparison gnv-artifacts/src/main/java/de/intevation/gnv/jfreechart/PolygonPlot.java @ 1119:7c4f81f74c47
merged gnv-artifacts
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:14:00 +0200 |
parents | f953c9a559d8 |
children |
comparison
equal
deleted
inserted
replaced
1027:fca4b5eb8d2f | 1119:7c4f81f74c47 |
---|---|
1 /* | |
2 * Copyright (c) 2010 by Intevation GmbH | |
3 * | |
4 * This program is free software under the LGPL (>=v2.1) | |
5 * Read the file LGPL.txt coming with the software for details | |
6 * or visit http://www.gnu.org/licenses/ if it does not exist. | |
7 */ | |
8 | |
9 package de.intevation.gnv.jfreechart; | |
10 | |
11 import java.awt.AlphaComposite; | |
12 import java.awt.Composite; | |
13 import java.awt.Graphics2D; | |
14 import java.awt.Shape; | |
15 | |
16 import java.awt.geom.Point2D; | |
17 import java.awt.geom.Rectangle2D; | |
18 | |
19 import java.util.HashMap; | |
20 import java.util.Iterator; | |
21 import java.util.Map; | |
22 | |
23 import org.jfree.chart.axis.Axis; | |
24 import org.jfree.chart.axis.AxisCollection; | |
25 import org.jfree.chart.axis.AxisLocation; | |
26 import org.jfree.chart.axis.AxisSpace; | |
27 import org.jfree.chart.axis.AxisState; | |
28 import org.jfree.chart.axis.ValueAxis; | |
29 | |
30 import org.jfree.chart.plot.Plot; | |
31 import org.jfree.chart.plot.PlotOrientation; | |
32 import org.jfree.chart.plot.PlotRenderingInfo; | |
33 import org.jfree.chart.plot.PlotState; | |
34 | |
35 import org.jfree.data.Range; | |
36 | |
37 import org.jfree.ui.RectangleEdge; | |
38 import org.jfree.ui.RectangleInsets; | |
39 | |
40 import org.jfree.util.ObjectList; | |
41 | |
42 /** | |
43 * A class for plotting polygons into a 2D chart. This plot makes use of <code> | |
44 * PolygonRenderer</code>. | |
45 * | |
46 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> | |
47 */ | |
48 // TODO implement cloneable | |
49 public class PolygonPlot | |
50 extends Plot | |
51 { | |
52 public static final String PLOT_TYPE = "PolygonPlot"; | |
53 | |
54 public static final PlotOrientation DEFAULT_PLOT_ORIENTATION = | |
55 PlotOrientation.VERTICAL; | |
56 | |
57 private PolygonDataset dataset; | |
58 private transient PolygonRenderer renderer; | |
59 | |
60 private PlotOrientation orientation; | |
61 | |
62 private RectangleInsets axisOffset; | |
63 | |
64 private ObjectList domainAxisLocation; | |
65 private ObjectList rangeAxisLocation; | |
66 private ObjectList domainAxes; | |
67 private ObjectList rangeAxes; | |
68 | |
69 | |
70 /** | |
71 * Constructs a new PolygonPlot with a dataset and a renderer. | |
72 * | |
73 * @param dataset Dataset containing polygons. | |
74 * @param renderer The renderer used to draw polygons. | |
75 */ | |
76 public PolygonPlot(PolygonDataset dataset, PolygonRenderer renderer) { | |
77 this(dataset, renderer, null, null, PlotOrientation.HORIZONTAL); | |
78 } | |
79 | |
80 | |
81 /** | |
82 * @param dataset Dataset containing polygons. | |
83 * @param renderer The renderer used to draw polygons. | |
84 * @param orientation The orientation used for this plot. | |
85 */ | |
86 public PolygonPlot( | |
87 PolygonDataset dataset, | |
88 PolygonRenderer renderer, | |
89 PlotOrientation orientation | |
90 ) { | |
91 this(dataset, renderer, null, null, orientation); | |
92 } | |
93 | |
94 | |
95 /** | |
96 * @param dataset Dataset containing polygons. | |
97 * @param renderer The renderer used to draw polygons. | |
98 * @param domainAxis The x axis. | |
99 * @param rangeAxis The y axis. | |
100 * @param orientation The orientation used for this plot. | |
101 */ | |
102 public PolygonPlot( | |
103 PolygonDataset dataset, | |
104 PolygonRenderer renderer, | |
105 ValueAxis domainAxis, | |
106 ValueAxis rangeAxis, | |
107 PlotOrientation orientation | |
108 ) { | |
109 super(); | |
110 | |
111 this.dataset = dataset; | |
112 this.renderer = renderer; | |
113 this.domainAxes = new ObjectList(); | |
114 this.rangeAxes = new ObjectList(); | |
115 this.domainAxisLocation = new ObjectList(); | |
116 this.rangeAxisLocation = new ObjectList(); | |
117 this.axisOffset = RectangleInsets.ZERO_INSETS; | |
118 | |
119 if (orientation != null) | |
120 this.orientation = orientation; | |
121 else | |
122 this.orientation = DEFAULT_PLOT_ORIENTATION; | |
123 | |
124 if (domainAxis != null) { | |
125 this.domainAxes.set(0, domainAxis); | |
126 domainAxis.setPlot(this); | |
127 } | |
128 domainAxisLocation.set(0, AxisLocation.BOTTOM_OR_LEFT); | |
129 | |
130 if (rangeAxis != null) { | |
131 this.rangeAxes.set(0, rangeAxis); | |
132 rangeAxis.setPlot(this); | |
133 } | |
134 rangeAxisLocation.set(0, AxisLocation.BOTTOM_OR_LEFT); | |
135 | |
136 configureDomainAxis(); | |
137 configureRangeAxis(); | |
138 } | |
139 | |
140 | |
141 public void configureDomainAxis() { | |
142 // we just have 1 dataset | |
143 Range domainAxisRange = getDataset().getDomainBounds(); | |
144 | |
145 for (int i = 0; i < domainAxes.size(); i++) { | |
146 ValueAxis axis = (ValueAxis) domainAxes.get(i); | |
147 | |
148 if (axis != null) { | |
149 axis.configure(); | |
150 axis.setRange(domainAxisRange); | |
151 } | |
152 } | |
153 } | |
154 | |
155 public ValueAxis getDomainAxis() { | |
156 return getDomainAxis(0); | |
157 } | |
158 | |
159 public void setDomainAxis(ValueAxis axis) { | |
160 domainAxes.set(0, axis); | |
161 } | |
162 | |
163 public ValueAxis getDomainAxis(int index) { | |
164 return index < domainAxes.size() | |
165 ? (ValueAxis)domainAxes.get(index) | |
166 : null; | |
167 } | |
168 | |
169 public ValueAxis getRangeAxis() { | |
170 return getRangeAxis(0); | |
171 } | |
172 | |
173 public void setRangeAxis(ValueAxis axis) { | |
174 rangeAxes.set(0, axis); | |
175 } | |
176 | |
177 public ValueAxis getRangeAxis(int index) { | |
178 return index < rangeAxes.size() | |
179 ? (ValueAxis)rangeAxes.get(index) | |
180 : null; | |
181 } | |
182 | |
183 public void configureRangeAxis() { | |
184 // we just have 1 dataset | |
185 Range rangeAxisRange = getDataset().getRangeBounds(); | |
186 | |
187 for (int i = 0; i < rangeAxes.size(); i++) { | |
188 ValueAxis axis = (ValueAxis) rangeAxes.get(i); | |
189 | |
190 if (axis != null) { | |
191 axis.configure(); | |
192 axis.setRange(rangeAxisRange); | |
193 } | |
194 } | |
195 } | |
196 | |
197 public PolygonDataset getDataset(){ | |
198 return this.dataset; | |
199 } | |
200 | |
201 public String getPlotType() { | |
202 return PLOT_TYPE; | |
203 } | |
204 | |
205 public void setDataset(PolygonDataset dataset) { | |
206 this.dataset = dataset; | |
207 } | |
208 | |
209 | |
210 /** | |
211 * This is the major method to draw the into a given Graphic2D object. | |
212 * | |
213 * @param g2 Graphics object where the plot is drawn into. | |
214 * @param area The bounds for drawing this plot. | |
215 * @param anchor An anchor point. | |
216 * @param parentState The plot state. | |
217 * @param info | |
218 */ | |
219 public void draw( | |
220 Graphics2D g2, | |
221 Rectangle2D area, | |
222 Point2D anchor, | |
223 PlotState parentState, | |
224 PlotRenderingInfo info | |
225 ) { | |
226 Graphics2D savedG2 = g2; | |
227 Rectangle2D savedDataArea = area; | |
228 | |
229 if (info != null) { | |
230 info.setPlotArea(area); | |
231 info.setDataArea(area); | |
232 } | |
233 | |
234 AxisSpace space = calculateAxisSpace(g2, area); | |
235 Rectangle2D dataArea = space.shrink(area, null); | |
236 | |
237 // draw background and outline | |
238 drawBackground(g2, area); | |
239 drawOutline(g2, area); | |
240 | |
241 Shape savedClip = g2.getClip(); | |
242 g2.clip(area); | |
243 | |
244 Composite originalComposite = g2.getComposite(); | |
245 g2.setComposite(AlphaComposite.getInstance( | |
246 AlphaComposite.SRC_OVER, | |
247 getForegroundAlpha() | |
248 )); | |
249 | |
250 // draw axis | |
251 drawAxes(g2, area, dataArea, info); | |
252 | |
253 if (!isEmptyOrNull(dataset)) { | |
254 // draw data | |
255 drawPolygons(savedG2, dataArea, info); | |
256 drawLabels(savedG2, dataArea, info); | |
257 } | |
258 | |
259 g2.setClip(savedClip); | |
260 g2.setComposite(originalComposite); | |
261 } | |
262 | |
263 | |
264 /** | |
265 * Method to draw the axis for this plot. | |
266 * | |
267 * @param g2 | |
268 * @param plotArea | |
269 * @param dataArea | |
270 * @param plotState | |
271 */ | |
272 private void drawAxes( | |
273 Graphics2D g2, | |
274 Rectangle2D plotArea, | |
275 Rectangle2D dataArea, | |
276 PlotRenderingInfo plotState | |
277 ) { | |
278 AxisCollection axisCollection = new AxisCollection(); | |
279 | |
280 for (int i = 0; i < domainAxes.size(); i++) { | |
281 ValueAxis axis = (ValueAxis) domainAxes.get(i); | |
282 if (axis != null) | |
283 axisCollection.add(axis, getDomainAxisEdge(i)); | |
284 } | |
285 | |
286 for (int i = 0; i < rangeAxes.size(); i++) { | |
287 ValueAxis axis = (ValueAxis) rangeAxes.get(i); | |
288 if (axis != null) | |
289 axisCollection.add(axis, getRangeAxisEdge(i)); | |
290 } | |
291 | |
292 Map axisStateMap = new HashMap(); | |
293 | |
294 // draw the top axes | |
295 double cursor = dataArea.getMinY() - this.axisOffset.calculateTopOutset( | |
296 dataArea.getHeight()); | |
297 Iterator iterator = axisCollection.getAxesAtTop().iterator(); | |
298 while (iterator.hasNext()) { | |
299 ValueAxis axis = (ValueAxis) iterator.next(); | |
300 AxisState info = axis.draw(g2, cursor, plotArea, dataArea, | |
301 RectangleEdge.TOP, plotState); | |
302 cursor = info.getCursor(); | |
303 axisStateMap.put(axis, info); | |
304 } | |
305 | |
306 // draw the bottom axes | |
307 cursor = dataArea.getMaxY() | |
308 + this.axisOffset.calculateBottomOutset(dataArea.getHeight()); | |
309 iterator = axisCollection.getAxesAtBottom().iterator(); | |
310 while (iterator.hasNext()) { | |
311 ValueAxis axis = (ValueAxis) iterator.next(); | |
312 AxisState info = axis.draw(g2, cursor, plotArea, dataArea, | |
313 RectangleEdge.BOTTOM, plotState); | |
314 cursor = info.getCursor(); | |
315 axisStateMap.put(axis, info); | |
316 } | |
317 | |
318 // draw the left axes | |
319 cursor = dataArea.getMinX() | |
320 - this.axisOffset.calculateLeftOutset(dataArea.getWidth()); | |
321 iterator = axisCollection.getAxesAtLeft().iterator(); | |
322 while (iterator.hasNext()) { | |
323 ValueAxis axis = (ValueAxis) iterator.next(); | |
324 AxisState info = axis.draw(g2, cursor, plotArea, dataArea, | |
325 RectangleEdge.LEFT, plotState); | |
326 cursor = info.getCursor(); | |
327 axisStateMap.put(axis, info); | |
328 } | |
329 | |
330 // draw the right axes | |
331 cursor = dataArea.getMaxX() | |
332 + this.axisOffset.calculateRightOutset(dataArea.getWidth()); | |
333 iterator = axisCollection.getAxesAtRight().iterator(); | |
334 while (iterator.hasNext()) { | |
335 ValueAxis axis = (ValueAxis) iterator.next(); | |
336 AxisState info = axis.draw(g2, cursor, plotArea, dataArea, | |
337 RectangleEdge.RIGHT, plotState); | |
338 cursor = info.getCursor(); | |
339 axisStateMap.put(axis, info); | |
340 } | |
341 } | |
342 | |
343 | |
344 /** | |
345 * Put some labels at data items into the plot. Uses PolygonRenderer to do | |
346 * this job. | |
347 * | |
348 * @param g2 | |
349 * @param area | |
350 * @param info | |
351 */ | |
352 private void drawLabels( | |
353 Graphics2D g2, | |
354 Rectangle2D area, | |
355 PlotRenderingInfo info | |
356 ) { | |
357 renderer.drawLabels(g2, this, area, dataset); | |
358 } | |
359 | |
360 | |
361 /** | |
362 * Plot the polygons. Uses PolygonRenderer to do this job. | |
363 * | |
364 * @param g2 | |
365 * @param area | |
366 * @param info | |
367 */ | |
368 private void drawPolygons( | |
369 Graphics2D g2, | |
370 Rectangle2D area, | |
371 PlotRenderingInfo info | |
372 ) { | |
373 renderer.drawPolygons(g2, this, area, dataset); | |
374 } | |
375 | |
376 | |
377 private AxisSpace calculateAxisSpace(Graphics2D g2, Rectangle2D plotArea) { | |
378 AxisSpace space = new AxisSpace(); | |
379 space = calculateRangeAxisSpace(g2, plotArea, space); | |
380 Rectangle2D tmpPlotArea = space.shrink(plotArea, null); | |
381 space = calculateDomainAxisSpace(g2, plotArea, space); | |
382 | |
383 return space; | |
384 } | |
385 | |
386 | |
387 private AxisSpace calculateDomainAxisSpace( | |
388 Graphics2D g2, | |
389 Rectangle2D plotArea, | |
390 AxisSpace space | |
391 ) { | |
392 if (space == null) | |
393 space = new AxisSpace(); | |
394 | |
395 for (int i = 0; i < domainAxes.size(); i++) { | |
396 Axis axis = (Axis) domainAxes.get(i); | |
397 | |
398 if (axis != null) { | |
399 RectangleEdge edge = getDomainAxisEdge(i); | |
400 space = axis.reserveSpace(g2, this, plotArea, edge, space); | |
401 } | |
402 } | |
403 | |
404 return space; | |
405 } | |
406 | |
407 | |
408 private AxisSpace calculateRangeAxisSpace( | |
409 Graphics2D g2, | |
410 Rectangle2D plotArea, | |
411 AxisSpace space | |
412 ) { | |
413 if (space == null) | |
414 space = new AxisSpace(); | |
415 | |
416 for (int i = 0; i < rangeAxes.size(); i++) { | |
417 Axis axis = (Axis) rangeAxes.get(i); | |
418 | |
419 if (axis != null) { | |
420 RectangleEdge edge = getRangeAxisEdge(i); | |
421 space = axis.reserveSpace(g2, this, plotArea, edge, space); | |
422 } | |
423 } | |
424 | |
425 return space; | |
426 } | |
427 | |
428 | |
429 public RectangleEdge getDomainAxisEdge() { | |
430 return Plot.resolveDomainAxisLocation( | |
431 getDomainAxisLocation(), orientation | |
432 ); | |
433 } | |
434 | |
435 | |
436 public RectangleEdge getDomainAxisEdge(int idx) { | |
437 AxisLocation location = getDomainAxisLocation(idx); | |
438 RectangleEdge result = Plot.resolveDomainAxisLocation( | |
439 location, orientation | |
440 ); | |
441 | |
442 if (result == null) | |
443 result = RectangleEdge.opposite(getDomainAxisEdge()); | |
444 | |
445 return result; | |
446 } | |
447 | |
448 | |
449 public RectangleEdge getRangeAxisEdge() { | |
450 return Plot.resolveRangeAxisLocation( | |
451 getRangeAxisLocation(), orientation | |
452 ); | |
453 } | |
454 | |
455 | |
456 public RectangleEdge getRangeAxisEdge(int idx) { | |
457 AxisLocation location = getRangeAxisLocation(idx); | |
458 RectangleEdge result = Plot.resolveRangeAxisLocation( | |
459 location, | |
460 orientation | |
461 ); | |
462 | |
463 if (result == null) | |
464 result = RectangleEdge.opposite(getRangeAxisEdge()); | |
465 | |
466 return result; | |
467 } | |
468 | |
469 | |
470 public AxisLocation getDomainAxisLocation() { | |
471 return (AxisLocation) domainAxisLocation.get(0); | |
472 } | |
473 | |
474 | |
475 public AxisLocation getDomainAxisLocation(int idx) { | |
476 if (idx < domainAxisLocation.size()) | |
477 return (AxisLocation) domainAxisLocation.get(idx); | |
478 | |
479 return null; | |
480 } | |
481 | |
482 | |
483 public AxisLocation getRangeAxisLocation() { | |
484 return (AxisLocation) rangeAxisLocation.get(0); | |
485 } | |
486 | |
487 | |
488 public AxisLocation getRangeAxisLocation(int idx) { | |
489 if (idx < rangeAxisLocation.size()) | |
490 return (AxisLocation) rangeAxisLocation.get(idx); | |
491 | |
492 return null; | |
493 } | |
494 | |
495 | |
496 /** | |
497 * @return true, if dataset is null or if it does not contain any | |
498 * PolygonSeries, otherwise false. | |
499 */ | |
500 private boolean isEmptyOrNull(PolygonDataset dataset) { | |
501 if (dataset != null) { | |
502 int seriesCount = dataset.getSeriesCount(); | |
503 for (int s = 0; s < seriesCount; s++) { | |
504 PolygonSeries series = dataset.getSeries(s); | |
505 if (series.getItemCount() > 0) { | |
506 return false; | |
507 } | |
508 } | |
509 } | |
510 return true; | |
511 } | |
512 } | |
513 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 : |