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