00001
00002
00003
00004
00005
00006
00007 package org.swtchart.internal.series;
00008
00009 import org.eclipse.swt.SWT;
00010 import org.eclipse.swt.graphics.Color;
00011 import org.eclipse.swt.graphics.GC;
00012 import org.eclipse.swt.graphics.Point;
00013 import org.eclipse.swt.graphics.Rectangle;
00014 import org.eclipse.swt.widgets.Display;
00015 import org.swtchart.Chart;
00016 import org.swtchart.IAxis.Direction;
00017 import org.swtchart.IBarSeries;
00018 import org.swtchart.Range;
00019 import org.swtchart.internal.axis.Axis;
00020 import org.swtchart.internal.compress.CompressBarSeries;
00021 import org.swtchart.internal.compress.CompressScatterSeries;
00022
00026 public class BarSeries extends Series implements IBarSeries {
00027
00029 private int riserIndex;
00030
00032 private Color barColor;
00033
00035 private int barWidth;
00036
00038 private int padding;
00039
00041 private BarWidthStyle barWidthStyle;
00042
00044 public static final int INITIAL_BAR_WIDTH = 20;
00045
00047 public static final int INITIAL_PADDING = 20;
00048
00050 private static final int ALPHA = 0xD0;
00051
00053 private static final int MARGIN_AT_MIN_MAX_PLOT = 6;
00054
00056 private static final int DEFAULT_BAR_COLOR = SWT.COLOR_CYAN;
00057
00066 protected BarSeries(Chart chart, String id) {
00067 super(chart, id);
00068
00069 barColor = Display.getDefault().getSystemColor(DEFAULT_BAR_COLOR);
00070 barWidthStyle = BarWidthStyle.STRETCHED;
00071 barWidth = INITIAL_PADDING;
00072 padding = INITIAL_PADDING;
00073 type = SeriesType.BAR;
00074
00075 compressor = new CompressBarSeries();
00076 }
00077
00078
00079
00080
00081 public BarWidthStyle getBarWidthStyle(BarWidthStyle style) {
00082 return barWidthStyle;
00083 }
00084
00085
00086
00087
00088 public void setBarWidthStyle(BarWidthStyle style) {
00089 this.barWidthStyle = style;
00090 }
00091
00092
00093
00094
00095 public int getBarWidth() {
00096 return barWidth;
00097 }
00098
00099
00100
00101
00102 public void setBarWidth(int width) {
00103 if (padding <= 0) {
00104 SWT.error(SWT.ERROR_INVALID_ARGUMENT);
00105 }
00106 this.barWidth = width;
00107 }
00108
00109
00110
00111
00112 public int getBarPadding() {
00113 return padding;
00114 }
00115
00116
00117
00118
00119 public void setBarPadding(int padding) {
00120 if (padding < 0 || padding > 100) {
00121 SWT.error(SWT.ERROR_INVALID_ARGUMENT);
00122 }
00123 this.padding = padding;
00124 }
00125
00126
00127
00128
00129 public Color getBarColor() {
00130 if (barColor.isDisposed()) {
00131 barColor = Display.getDefault().getSystemColor(DEFAULT_BAR_COLOR);
00132 }
00133 return barColor;
00134 }
00135
00136
00137
00138
00139 public void setBarColor(Color color) {
00140 if (color != null && color.isDisposed()) {
00141 SWT.error(SWT.ERROR_INVALID_ARGUMENT);
00142 }
00143
00144 if (color == null) {
00145 this.barColor = Display.getDefault().getSystemColor(
00146 DEFAULT_BAR_COLOR);
00147 } else {
00148 this.barColor = color;
00149 }
00150 }
00151
00152
00153
00154
00155 public Rectangle[] getBounds() {
00156 Rectangle[] compressedBounds = getBoundsForCompressedSeries();
00157 if (((Axis) chart.getAxisSet().getXAxis(xAxisId)).isValidCategoryAxis()) {
00158 return compressedBounds;
00159 }
00160
00161 Rectangle[] rs = new Rectangle[xSeries.length];
00162 double[] comporessedXSeries = compressor.getCompressedXSeries();
00163 int cnt = 0;
00164 for (int i = 0; i < xSeries.length; i++) {
00165 if (cnt < comporessedXSeries.length
00166 && comporessedXSeries[cnt] == xSeries[i]
00167 && compressedBounds[cnt].width != 0
00168 && compressedBounds[cnt].height != 0) {
00169 rs[i] = compressedBounds[cnt++];
00170 }
00171 }
00172 return rs;
00173 }
00174
00180 private Rectangle[] getBoundsForCompressedSeries() {
00181 Axis xAxis = (Axis) chart.getAxisSet().getXAxis(xAxisId);
00182 Axis yAxis = (Axis) chart.getAxisSet().getYAxis(yAxisId);
00183
00184
00185 double[] xseries = compressor.getCompressedXSeries();
00186 double[] yseries = compressor.getCompressedYSeries();
00187 int[] indexes = compressor.getCompressedIndexes();
00188 if (xAxis.isValidCategoryAxis()) {
00189 for (int i = 0; i < xseries.length; i++) {
00190 xseries[i] = indexes[i];
00191 }
00192 }
00193
00194 Rectangle[] rectangles = new Rectangle[xseries.length];
00195 Range xRange = xAxis.getRange();
00196 Range yRange = yAxis.getRange();
00197 for (int i = 0; i < xseries.length; i++) {
00198 int x = xAxis.getPixelCoordinate(xseries[i]);
00199 int y = yAxis
00200 .getPixelCoordinate(isValidStackSeries() ? stackSeries[indexes[i]]
00201 : yseries[i]);
00202 double baseYCoordinate = yAxis.getRange().lower > 0 ? yAxis
00203 .getRange().lower : 0;
00204 double riserwidth = getRiserWidth(xseries, i, xAxis, xRange.lower,
00205 xRange.upper);
00206 double riserHeight = Math.abs(yAxis.getPixelCoordinate(yseries[i],
00207 yRange.lower, yRange.upper)
00208 - yAxis.getPixelCoordinate(
00209 yAxis.isLogScaleEnabled() ? yRange.lower
00210 : baseYCoordinate, yRange.lower,
00211 yRange.upper));
00212
00213
00214 int riserCnt = xAxis.getNumRisers();
00215 if (riserCnt > 1) {
00216 if (xAxis.isHorizontalAxis()) {
00217 x = (int) (x - riserwidth / 2d + riserwidth / riserCnt
00218 * (riserIndex + 0.5));
00219 } else {
00220 x = (int) (x - riserwidth / 2d + riserwidth / riserCnt
00221 * (riserCnt - riserIndex - 0.5));
00222 }
00223 riserwidth /= riserCnt;
00224 }
00225
00226 if (xAxis.isHorizontalAxis()) {
00227
00228
00229 if (y > yAxis.getPixelCoordinate(0)) {
00230 y = yAxis.getPixelCoordinate(0);
00231 }
00232
00233 int width = (int) Math.ceil(riserwidth);
00234 width = (width == 0) ? 1 : width;
00235
00236 rectangles[i] = getVisibleRectangle((int) Math.floor(x
00237 - riserwidth / 2d), y, width, (int) riserHeight);
00238 } else {
00239
00240
00241 if (y < yAxis.getPixelCoordinate(0)) {
00242 y = yAxis.getPixelCoordinate(0);
00243 }
00244
00245 int height = (int) Math.ceil(riserwidth);
00246 height = (height == 0) ? 1 : height;
00247
00248 rectangles[i] = getVisibleRectangle((int) (y - riserHeight),
00249 (int) Math.floor(x - riserwidth / 2d),
00250 (int) riserHeight, height);
00251 }
00252 }
00253
00254 return rectangles;
00255 }
00256
00270 private Rectangle getVisibleRectangle(int x, int y, int width, int height) {
00271
00272 final int offset = 5;
00273 int newX = x;
00274 int newY = y;
00275 int newWidth = width;
00276 int newHeight = height;
00277
00278 if (x < 0) {
00279 newX = -offset;
00280 newWidth += x + offset;
00281 }
00282 if (y < 0) {
00283 newY = -offset;
00284 newHeight += y + offset;
00285 }
00286
00287 Point size = chart.getPlotArea().getSize();
00288 if (x + width > size.x) {
00289 newWidth -= x + width - size.x + offset;
00290 if (newWidth < 0) {
00291 newWidth = 0;
00292 }
00293 }
00294 if (y + height > size.y) {
00295 newHeight -= y + height - size.y + offset;
00296 if (newHeight < 0) {
00297 newHeight = 0;
00298 }
00299 }
00300
00301 return new Rectangle(newX, newY, newWidth, newHeight);
00302 }
00303
00310 protected void setRiserIndex(int riserIndex) {
00311 this.riserIndex = riserIndex;
00312 }
00313
00314
00315
00316
00317 @Override
00318 protected void setCompressor() {
00319 if (isXMonotoneIncreasing) {
00320 compressor = new CompressBarSeries();
00321 } else {
00322 compressor = new CompressScatterSeries();
00323 }
00324 }
00325
00326
00327
00328
00329 @Override
00330 public Range getAdjustedRange(Axis axis, int length) {
00331
00332
00333 Range range;
00334 int lowerPlotMargin;
00335 int upperPlotMargin;
00336 if (axis.getDirection() == Direction.X) {
00337 double lowerRiserWidth = getRiserWidth(xSeries, 0, axis, minX, maxX);
00338 double upperRiserWidth = getRiserWidth(xSeries, xSeries.length - 1,
00339 axis, minX, maxX);
00340 lowerPlotMargin = (int) (lowerRiserWidth / 2d + MARGIN_AT_MIN_MAX_PLOT);
00341 upperPlotMargin = (int) (upperRiserWidth / 2d + MARGIN_AT_MIN_MAX_PLOT);
00342 range = getXRange();
00343 } else {
00344 range = getYRange();
00345 if (range.upper < 0) {
00346 range.upper = 0;
00347 }
00348 if (range.lower > 0) {
00349 range.lower = axis.isLogScaleEnabled() ? minY : 0;
00350 }
00351 lowerPlotMargin = (range.lower == 0) ? 0 : MARGIN_AT_MIN_MAX_PLOT;
00352 upperPlotMargin = (range.upper == 0) ? 0 : MARGIN_AT_MIN_MAX_PLOT;
00353 }
00354
00355 return getRangeWithMargin(lowerPlotMargin, upperPlotMargin, length,
00356 axis, range);
00357 }
00358
00374 private int getRiserWidth(double[] series, int index, Axis xAxis,
00375 double min, double max) {
00376
00377
00378 double upper;
00379 double lower;
00380 if (series.length == 1) {
00381 upper = series[0] + 0.5;
00382 lower = series[0] - 0.5;
00383 } else if (index != series.length - 1
00384 && (index == 0 || series[index + 1] - series[index] < series[index]
00385 - series[index - 1])) {
00386 upper = series[index + 1];
00387 lower = series[index];
00388 } else {
00389 upper = series[index];
00390 lower = series[index - 1];
00391 }
00392
00393 if (barWidthStyle == BarWidthStyle.STRETCHED) {
00394
00395
00396 int width = Math.abs(xAxis.getPixelCoordinate(upper, min, max)
00397 - xAxis.getPixelCoordinate(lower, min, max));
00398
00399
00400 width *= (100 - padding) / 100d;
00401
00402
00403 if (width == 0) {
00404 width = 1;
00405 }
00406
00407 return width;
00408 } else if (barWidthStyle == BarWidthStyle.FIXED) {
00409 return barWidth;
00410 }
00411
00412 throw new IllegalStateException("unknown bar width style");
00413 }
00414
00423 private static Color getFrameColor(Color color) {
00424 int red = color.getRed();
00425 int green = color.getGreen();
00426 int blue = color.getBlue();
00427
00428 red *= (red > 128) ? 0.8 : 1.2;
00429 green *= (green > 128) ? 0.8 : 1.2;
00430 blue *= (blue > 128) ? 0.8 : 1.2;
00431
00432 return new Color(color.getDevice(), red, green, blue);
00433 }
00434
00435
00436
00437
00438 @Override
00439 protected void draw(GC gc, int width, int height, Axis xAxis, Axis yAxis) {
00440
00441
00442 Rectangle[] rs = getBoundsForCompressedSeries();
00443 for (int i = 0; i < rs.length; i++) {
00444 drawRiser(gc, rs[i].x, rs[i].y, rs[i].width, rs[i].height);
00445 }
00446
00447
00448 if (seriesLabel.isVisible() || xErrorBar.isVisible()
00449 || yErrorBar.isVisible()) {
00450 double[] yseries = compressor.getCompressedYSeries();
00451 int[] indexes = compressor.getCompressedIndexes();
00452
00453 for (int i = 0; i < rs.length; i++) {
00454 seriesLabel.draw(gc, rs[i].x + rs[i].width / 2, rs[i].y
00455 + rs[i].height / 2, yseries[i], indexes[i], SWT.CENTER);
00456
00457 int h, v;
00458 if (xAxis.isHorizontalAxis()) {
00459 h = xAxis.getPixelCoordinate(xSeries[indexes[i]]);
00460 v = yAxis.getPixelCoordinate(ySeries[indexes[i]]);
00461 } else {
00462 v = xAxis.getPixelCoordinate(xSeries[indexes[i]]);
00463 h = yAxis.getPixelCoordinate(ySeries[indexes[i]]);
00464 }
00465 xErrorBar.draw(gc, h, v, xAxis, indexes[i]);
00466 yErrorBar.draw(gc, h, v, yAxis, indexes[i]);
00467 }
00468 }
00469 }
00470
00485 private void drawRiser(GC gc, int h, int v, int width, int height) {
00486 int alpha = gc.getAlpha();
00487 gc.setAlpha(ALPHA);
00488
00489 Color oldBackground = gc.getBackground();
00490 gc.setBackground(getBarColor());
00491
00492 gc.fillRectangle(h, v, width, height);
00493
00494 gc.setLineStyle(SWT.LINE_SOLID);
00495 Color frameColor = getFrameColor(getBarColor());
00496 Color oldForeground = gc.getForeground();
00497 gc.setForeground(frameColor);
00498
00499 gc.drawRectangle(h, v, width, height);
00500 frameColor.dispose();
00501
00502 gc.setAlpha(alpha);
00503 gc.setBackground(oldBackground);
00504 gc.setForeground(oldForeground);
00505 }
00506 }