1:
47:
48: package ;
49:
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55:
56: import ;
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:
70:
74: public class GroupedStackedBarRenderer extends StackedBarRenderer
75: implements Cloneable, PublicCloneable, Serializable {
76:
77:
78: private static final long serialVersionUID = -2725921399005922939L;
79:
80:
81: private KeyToGroupMap seriesToGroupMap;
82:
83:
86: public GroupedStackedBarRenderer() {
87: super();
88: this.seriesToGroupMap = new KeyToGroupMap();
89: }
90:
91:
97: public void setSeriesToGroupMap(KeyToGroupMap map) {
98: if (map == null) {
99: throw new IllegalArgumentException("Null 'map' argument.");
100: }
101: this.seriesToGroupMap = map;
102: fireChangeEvent();
103: }
104:
105:
114: public Range findRangeBounds(CategoryDataset dataset) {
115: Range r = DatasetUtilities.findStackedRangeBounds(
116: dataset, this.seriesToGroupMap);
117: return r;
118: }
119:
120:
130: protected void calculateBarWidth(CategoryPlot plot,
131: Rectangle2D dataArea,
132: int rendererIndex,
133: CategoryItemRendererState state) {
134:
135:
136: CategoryAxis xAxis = plot.getDomainAxisForDataset(rendererIndex);
137: CategoryDataset data = plot.getDataset(rendererIndex);
138: if (data != null) {
139: PlotOrientation orientation = plot.getOrientation();
140: double space = 0.0;
141: if (orientation == PlotOrientation.HORIZONTAL) {
142: space = dataArea.getHeight();
143: }
144: else if (orientation == PlotOrientation.VERTICAL) {
145: space = dataArea.getWidth();
146: }
147: double maxWidth = space * getMaximumBarWidth();
148: int groups = this.seriesToGroupMap.getGroupCount();
149: int categories = data.getColumnCount();
150: int columns = groups * categories;
151: double categoryMargin = 0.0;
152: double itemMargin = 0.0;
153: if (categories > 1) {
154: categoryMargin = xAxis.getCategoryMargin();
155: }
156: if (groups > 1) {
157: itemMargin = getItemMargin();
158: }
159:
160: double used = space * (1 - xAxis.getLowerMargin()
161: - xAxis.getUpperMargin()
162: - categoryMargin - itemMargin);
163: if (columns > 0) {
164: state.setBarWidth(Math.min(used / columns, maxWidth));
165: }
166: else {
167: state.setBarWidth(Math.min(used, maxWidth));
168: }
169: }
170:
171: }
172:
173:
188: protected double calculateBarW0(CategoryPlot plot,
189: PlotOrientation orientation,
190: Rectangle2D dataArea,
191: CategoryAxis domainAxis,
192: CategoryItemRendererState state,
193: int row,
194: int column) {
195:
196: double space = 0.0;
197: if (orientation == PlotOrientation.HORIZONTAL) {
198: space = dataArea.getHeight();
199: }
200: else {
201: space = dataArea.getWidth();
202: }
203: double barW0 = domainAxis.getCategoryStart(column, getColumnCount(),
204: dataArea, plot.getDomainAxisEdge());
205: int groupCount = this.seriesToGroupMap.getGroupCount();
206: int groupIndex = this.seriesToGroupMap.getGroupIndex(
207: this.seriesToGroupMap.getGroup(plot.getDataset(
208: plot.getIndexOf(this)).getRowKey(row)));
209: int categoryCount = getColumnCount();
210: if (groupCount > 1) {
211: double groupGap = space * getItemMargin()
212: / (categoryCount * (groupCount - 1));
213: double groupW = calculateSeriesWidth(space, domainAxis,
214: categoryCount, groupCount);
215: barW0 = barW0 + groupIndex * (groupW + groupGap)
216: + (groupW / 2.0) - (state.getBarWidth() / 2.0);
217: }
218: else {
219: barW0 = domainAxis.getCategoryMiddle(column, getColumnCount(),
220: dataArea, plot.getDomainAxisEdge())
221: - state.getBarWidth() / 2.0;
222: }
223: return barW0;
224: }
225:
226:
240: public void drawItem(Graphics2D g2,
241: CategoryItemRendererState state,
242: Rectangle2D dataArea,
243: CategoryPlot plot,
244: CategoryAxis domainAxis,
245: ValueAxis rangeAxis,
246: CategoryDataset dataset,
247: int row,
248: int column,
249: int pass) {
250:
251:
252: Number dataValue = dataset.getValue(row, column);
253: if (dataValue == null) {
254: return;
255: }
256:
257: double value = dataValue.doubleValue();
258: Comparable group = this.seriesToGroupMap.getGroup(
259: dataset.getRowKey(row));
260: PlotOrientation orientation = plot.getOrientation();
261: double barW0 = calculateBarW0(plot, orientation, dataArea, domainAxis,
262: state, row, column);
263:
264: double positiveBase = 0.0;
265: double negativeBase = 0.0;
266:
267: for (int i = 0; i < row; i++) {
268: if (group.equals(this.seriesToGroupMap.getGroup(
269: dataset.getRowKey(i)))) {
270: Number v = dataset.getValue(i, column);
271: if (v != null) {
272: double d = v.doubleValue();
273: if (d > 0) {
274: positiveBase = positiveBase + d;
275: }
276: else {
277: negativeBase = negativeBase + d;
278: }
279: }
280: }
281: }
282:
283: double translatedBase;
284: double translatedValue;
285: RectangleEdge location = plot.getRangeAxisEdge();
286: if (value > 0.0) {
287: translatedBase = rangeAxis.valueToJava2D(positiveBase, dataArea,
288: location);
289: translatedValue = rangeAxis.valueToJava2D(positiveBase + value,
290: dataArea, location);
291: }
292: else {
293: translatedBase = rangeAxis.valueToJava2D(negativeBase, dataArea,
294: location);
295: translatedValue = rangeAxis.valueToJava2D(negativeBase + value,
296: dataArea, location);
297: }
298: double barL0 = Math.min(translatedBase, translatedValue);
299: double barLength = Math.max(Math.abs(translatedValue - translatedBase),
300: getMinimumBarLength());
301:
302: Rectangle2D bar = null;
303: if (orientation == PlotOrientation.HORIZONTAL) {
304: bar = new Rectangle2D.Double(barL0, barW0, barLength,
305: state.getBarWidth());
306: }
307: else {
308: bar = new Rectangle2D.Double(barW0, barL0, state.getBarWidth(),
309: barLength);
310: }
311: Paint itemPaint = getItemPaint(row, column);
312: if (getGradientPaintTransformer() != null
313: && itemPaint instanceof GradientPaint) {
314: GradientPaint gp = (GradientPaint) itemPaint;
315: itemPaint = getGradientPaintTransformer().transform(gp, bar);
316: }
317: g2.setPaint(itemPaint);
318: g2.fill(bar);
319: if (isDrawBarOutline()
320: && state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD) {
321: g2.setStroke(getItemStroke(row, column));
322: g2.setPaint(getItemOutlinePaint(row, column));
323: g2.draw(bar);
324: }
325:
326: CategoryItemLabelGenerator generator = getItemLabelGenerator(row,
327: column);
328: if (generator != null && isItemLabelVisible(row, column)) {
329: drawItemLabel(g2, dataset, row, column, plot, generator, bar,
330: (value < 0.0));
331: }
332:
333:
334: if (state.getInfo() != null) {
335: EntityCollection entities = state.getEntityCollection();
336: if (entities != null) {
337: addItemEntity(entities, dataset, row, column, bar);
338: }
339: }
340:
341: }
342:
343:
350: public boolean equals(Object obj) {
351: if (obj == this) {
352: return true;
353: }
354: if (!(obj instanceof GroupedStackedBarRenderer)) {
355: return false;
356: }
357: GroupedStackedBarRenderer that = (GroupedStackedBarRenderer) obj;
358: if (!this.seriesToGroupMap.equals(that.seriesToGroupMap)) {
359: return false;
360: }
361: return super.equals(obj);
362: }
363:
364: }