1:
48:
49: package ;
50:
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56:
57: import ;
58: import ;
59: import ;
60: import ;
61: import ;
62: import ;
63: import ;
64: import ;
65: import ;
66: import ;
67: import ;
68: import ;
69: import ;
70: import ;
71: import ;
72:
73:
77: public class GroupedStackedBarRenderer extends StackedBarRenderer
78: implements Cloneable, PublicCloneable,
79: Serializable {
80:
81:
82: private static final long serialVersionUID = -2725921399005922939L;
83:
84:
85: private KeyToGroupMap seriesToGroupMap;
86:
87:
90: public GroupedStackedBarRenderer() {
91: super();
92: this.seriesToGroupMap = new KeyToGroupMap();
93: }
94:
95:
100: public void setSeriesToGroupMap(KeyToGroupMap map) {
101: if (map == null) {
102: throw new IllegalArgumentException("Null 'map' argument.");
103: }
104: this.seriesToGroupMap = map;
105: notifyListeners(new RendererChangeEvent(this));
106: }
107:
108:
117: public Range findRangeBounds(CategoryDataset dataset) {
118: Range r = DatasetUtilities.findStackedRangeBounds(
119: dataset, this.seriesToGroupMap
120: );
121: return r;
122: }
123:
124:
134: protected void calculateBarWidth(CategoryPlot plot,
135: Rectangle2D dataArea,
136: int rendererIndex,
137: CategoryItemRendererState state) {
138:
139:
140: CategoryAxis xAxis = plot.getDomainAxisForDataset(rendererIndex);
141: CategoryDataset data = plot.getDataset(rendererIndex);
142: if (data != null) {
143: PlotOrientation orientation = plot.getOrientation();
144: double space = 0.0;
145: if (orientation == PlotOrientation.HORIZONTAL) {
146: space = dataArea.getHeight();
147: }
148: else if (orientation == PlotOrientation.VERTICAL) {
149: space = dataArea.getWidth();
150: }
151: double maxWidth = space * getMaximumBarWidth();
152: int groups = this.seriesToGroupMap.getGroupCount();
153: int categories = data.getColumnCount();
154: int columns = groups * categories;
155: double categoryMargin = 0.0;
156: double itemMargin = 0.0;
157: if (categories > 1) {
158: categoryMargin = xAxis.getCategoryMargin();
159: }
160: if (groups > 1) {
161: itemMargin = getItemMargin();
162: }
163:
164: double used = space * (1 - xAxis.getLowerMargin()
165: - xAxis.getUpperMargin()
166: - categoryMargin - itemMargin);
167: if (columns > 0) {
168: state.setBarWidth(Math.min(used / columns, maxWidth));
169: }
170: else {
171: state.setBarWidth(Math.min(used, maxWidth));
172: }
173: }
174:
175: }
176:
177:
192: protected double calculateBarW0(CategoryPlot plot,
193: PlotOrientation orientation,
194: Rectangle2D dataArea,
195: CategoryAxis domainAxis,
196: CategoryItemRendererState state,
197: int row,
198: int column) {
199:
200: double space = 0.0;
201: if (orientation == PlotOrientation.HORIZONTAL) {
202: space = dataArea.getHeight();
203: }
204: else {
205: space = dataArea.getWidth();
206: }
207: double barW0 = domainAxis.getCategoryStart(
208: column, getColumnCount(), dataArea, plot.getDomainAxisEdge()
209: );
210: int groupCount = this.seriesToGroupMap.getGroupCount();
211: int groupIndex = this.seriesToGroupMap.getGroupIndex(
212: this.seriesToGroupMap.getGroup(plot.getDataset().getRowKey(row))
213: );
214: int categoryCount = getColumnCount();
215: if (groupCount > 1) {
216: double groupGap = space * getItemMargin()
217: / (categoryCount * (groupCount - 1));
218: double groupW = calculateSeriesWidth(
219: space, domainAxis, categoryCount, groupCount
220: );
221: barW0 = barW0 + groupIndex * (groupW + groupGap)
222: + (groupW / 2.0) - (state.getBarWidth() / 2.0);
223: }
224: else {
225: barW0 = domainAxis.getCategoryMiddle(
226: column, getColumnCount(), dataArea, plot.getDomainAxisEdge()
227: ) - state.getBarWidth() / 2.0;
228: }
229: return barW0;
230: }
231:
232:
246: public void drawItem(Graphics2D g2,
247: CategoryItemRendererState state,
248: Rectangle2D dataArea,
249: CategoryPlot plot,
250: CategoryAxis domainAxis,
251: ValueAxis rangeAxis,
252: CategoryDataset dataset,
253: int row,
254: int column,
255: int pass) {
256:
257:
258: Number dataValue = dataset.getValue(row, column);
259: if (dataValue == null) {
260: return;
261: }
262:
263: double value = dataValue.doubleValue();
264: Comparable group
265: = this.seriesToGroupMap.getGroup(dataset.getRowKey(row));
266: PlotOrientation orientation = plot.getOrientation();
267: double barW0 = calculateBarW0(
268: plot, orientation, dataArea, domainAxis,
269: state, row, column
270: );
271:
272: double positiveBase = 0.0;
273: double negativeBase = 0.0;
274:
275: for (int i = 0; i < row; i++) {
276: if (group.equals(
277: this.seriesToGroupMap.getGroup(dataset.getRowKey(i))
278: )) {
279: Number v = dataset.getValue(i, column);
280: if (v != null) {
281: double d = v.doubleValue();
282: if (d > 0) {
283: positiveBase = positiveBase + d;
284: }
285: else {
286: negativeBase = negativeBase + d;
287: }
288: }
289: }
290: }
291:
292: double translatedBase;
293: double translatedValue;
294: RectangleEdge location = plot.getRangeAxisEdge();
295: if (value > 0.0) {
296: translatedBase
297: = rangeAxis.valueToJava2D(positiveBase, dataArea, location);
298: translatedValue = rangeAxis.valueToJava2D(
299: positiveBase + value, dataArea, location
300: );
301: }
302: else {
303: translatedBase = rangeAxis.valueToJava2D(
304: negativeBase, dataArea, location
305: );
306: translatedValue = rangeAxis.valueToJava2D(
307: negativeBase + value, dataArea, location
308: );
309: }
310: double barL0 = Math.min(translatedBase, translatedValue);
311: double barLength = Math.max(
312: Math.abs(translatedValue - translatedBase), getMinimumBarLength()
313: );
314:
315: Rectangle2D bar = null;
316: if (orientation == PlotOrientation.HORIZONTAL) {
317: bar = new Rectangle2D.Double(
318: barL0, barW0, barLength, state.getBarWidth()
319: );
320: }
321: else {
322: bar = new Rectangle2D.Double(
323: barW0, barL0, state.getBarWidth(), barLength
324: );
325: }
326: Paint itemPaint = getItemPaint(row, column);
327: if (getGradientPaintTransformer() != null
328: && itemPaint instanceof GradientPaint) {
329: GradientPaint gp = (GradientPaint) itemPaint;
330: itemPaint = getGradientPaintTransformer().transform(gp, bar);
331: }
332: g2.setPaint(itemPaint);
333: g2.fill(bar);
334: if (isDrawBarOutline()
335: && state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD) {
336: g2.setStroke(getItemStroke(row, column));
337: g2.setPaint(getItemOutlinePaint(row, column));
338: g2.draw(bar);
339: }
340:
341: CategoryItemLabelGenerator generator
342: = getItemLabelGenerator(row, column);
343: if (generator != null && isItemLabelVisible(row, column)) {
344: drawItemLabel(
345: g2, dataset, row, column, plot, generator, bar,
346: (value < 0.0)
347: );
348: }
349:
350:
351: if (state.getInfo() != null) {
352: EntityCollection entities = state.getEntityCollection();
353: if (entities != null) {
354: String tip = null;
355: CategoryToolTipGenerator tipster
356: = getToolTipGenerator(row, column);
357: if (tipster != null) {
358: tip = tipster.generateToolTip(dataset, row, column);
359: }
360: String url = null;
361: if (getItemURLGenerator(row, column) != null) {
362: url = getItemURLGenerator(row, column).generateURL(
363: dataset, row, column
364: );
365: }
366: CategoryItemEntity entity = new CategoryItemEntity(
367: bar, tip, url, dataset, row,
368: dataset.getColumnKey(column), column
369: );
370: entities.add(entity);
371: }
372: }
373:
374: }
375:
376:
383: public boolean equals(Object obj) {
384: if (obj == this) {
385: return true;
386: }
387: if (obj instanceof GroupedStackedBarRenderer && super.equals(obj)) {
388: GroupedStackedBarRenderer r = (GroupedStackedBarRenderer) obj;
389: if (!r.seriesToGroupMap.equals(this.seriesToGroupMap)) {
390: return false;
391: }
392: return true;
393: }
394: return false;
395: }
396:
397: }