All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.codename1.charts.views.BarChart Maven / Gradle / Ivy

There is a newer version: 7.0.164
Show newest version
/**
 * Copyright (C) 2009 - 2013 SC 4ViewSoft SRL
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.codename1.charts.views;


import java.util.List;
import com.codename1.charts.compat.Canvas;
import com.codename1.charts.compat.GradientDrawable;
import com.codename1.charts.compat.GradientDrawable.Orientation;
import com.codename1.charts.compat.Paint;
import com.codename1.charts.compat.Paint.Style;

import com.codename1.charts.models.XYMultipleSeriesDataset;
import com.codename1.charts.models.XYSeries;
import com.codename1.charts.renderers.SimpleSeriesRenderer;
import com.codename1.charts.renderers.XYMultipleSeriesRenderer;
import com.codename1.charts.renderers.XYSeriesRenderer;
import com.codename1.charts.util.ColorUtil;



/**
 * The bar chart rendering class.
 */
public class BarChart extends XYChart {
  /** The constant to identify this chart type. */
  public static final String TYPE = "Bar";
  /** The legend shape width. */
  private static final int SHAPE_WIDTH = 12;
  /** The chart type. */
  protected Type mType = Type.DEFAULT;
  /** The previous series Y axis point limits to be used for HEAP type bar charts. */
  private List mPreviousSeriesPoints;

  /**
   * The bar chart type enum.
   */
  public enum Type {
    DEFAULT, STACKED, HEAPED;
  }

  BarChart() {
  }

  BarChart(Type type) {
    mType = type;
  }

  /**
   * Builds a new bar chart instance.
   * 
   * @param dataset the multiple series dataset
   * @param renderer the multiple series renderer
   * @param type the bar chart type
   */
  public BarChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, Type type) {
    super(dataset, renderer);
    mType = type;
  }

  @Override
  protected ClickableArea[] clickableAreasForPoints(List points, List values,
      float yAxisValue, int seriesIndex, int startIndex) {
    int seriesNr = mDataset.getSeriesCount();
    int length = points.size();
    ClickableArea[] ret = new ClickableArea[length / 2];
    float halfDiffX = getHalfDiffX(points, length, seriesNr);
    for (int i = 0; i < length; i += 2) {
      float x = points.get(i);
      float y = points.get(i + 1);
      if (mType == Type.STACKED || mType == Type.HEAPED) {
        ret[i / 2] = new ClickableArea(PkgUtils.makeRect(x - halfDiffX, Math.min(y, yAxisValue), x
            + halfDiffX, Math.max(y, yAxisValue)), values.get(i), values.get(i + 1));
      } else {
        float startX = x - seriesNr * halfDiffX + seriesIndex * 2 * halfDiffX;
        ret[i / 2] = new ClickableArea(PkgUtils.makeRect(startX, Math.min(y, yAxisValue), startX + 2
            * halfDiffX, Math.max(y, yAxisValue)), values.get(i), values.get(i + 1));
      }
    }
    return ret;
  }

  private class Point {
      int seriesIndex;
      float yval;
  }
  
  /**
   * The graphical representation of a series.
   * 
   * @param canvas the canvas to paint to
   * @param paint the paint to be used for drawing
   * @param points the array of points to be used for drawing the series
   * @param seriesRenderer the series renderer
   * @param yAxisValue the minimum value of the y axis
   * @param seriesIndex the index of the series currently being drawn
   * @param startIndex the start index of the rendering points
   */
  @Override
  public void drawSeries(Canvas canvas, Paint paint, List points,
      XYSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, int startIndex) {
    int seriesNr = mDataset.getSeriesCount();
    int length = points.size();
    paint.setColor(seriesRenderer.getColor());
    paint.setStyle(Style.FILL);
    float halfDiffX = getHalfDiffX(points, length, seriesNr);
    
    Point[] yvals = new Point[length/2];
    for ( int i=0; i 0) {
        float lastY = mPreviousSeriesPoints.get(i + 1);
        y = y + (lastY - yAxisValue);
        points.set(i + 1, y);
        drawBar(canvas, x, lastY, x, y, halfDiffX, seriesNr, seriesIndex, paint);
      } else {
        drawBar(canvas, x, yAxisValue, x, y, halfDiffX, seriesNr, seriesIndex, paint);
      }
    }
    paint.setColor(seriesRenderer.getColor());
    mPreviousSeriesPoints = points;
  }

  /**
   * Draws a bar.
   * 
   * @param canvas the canvas
   * @param xMin the X axis minimum
   * @param yMin the Y axis minimum
   * @param xMax the X axis maximum
   * @param yMax the Y axis maximum
   * @param halfDiffX half the size of a bar
   * @param seriesNr the total number of series
   * @param seriesIndex the current series index
   * @param paint the paint
   */
  protected void drawBar(Canvas canvas, float xMin, float yMin, float xMax, float yMax,
      float halfDiffX, int seriesNr, int seriesIndex, Paint paint) {
    int scale = mDataset.getSeriesAt(seriesIndex).getScaleNumber();
    if (mType == Type.STACKED || mType == Type.HEAPED) {
      drawBar(canvas, xMin - halfDiffX, yMax, xMax + halfDiffX, yMin, scale, seriesIndex, paint);
    } else {
      float startX = xMin - seriesNr * halfDiffX + seriesIndex * 2 * halfDiffX;
      drawBar(canvas, startX, yMax, startX + 2 * halfDiffX, yMin, scale, seriesIndex, paint);
    }
  }

  /**
   * Draws a bar.
   * 
   * @param canvas the canvas
   * @param xMin the X axis minimum
   * @param yMin the Y axis minimum
   * @param xMax the X axis maximum
   * @param yMax the Y axis maximum
   * @param scale the scale index
   * @param seriesIndex the current series index
   * @param paint the paint
   */
  protected void drawBar(Canvas canvas, float xMin, float yMin, float xMax, float yMax, int scale,
      int seriesIndex, Paint paint) {
    // Fix negative bars issue in Android 4.2
    float temp;
    if (xMin > xMax) {
      temp = xMin;
      xMin = xMax;
      xMax = temp;
    }
    if (yMin > yMax) {
      temp = yMin;
      yMin = yMax;
      yMax = temp;
    }

    SimpleSeriesRenderer renderer = mRenderer.getSeriesRendererAt(seriesIndex);
    if (renderer.isGradientEnabled()) {
      float minY = (float) toScreenPoint(new double[] { 0, renderer.getGradientStopValue() }, scale)[1];
      float maxY = (float) toScreenPoint(new double[] { 0, renderer.getGradientStartValue() },
          scale)[1];
      float gradientMinY = Math.max(minY, Math.min(yMin, yMax));
      float gradientMaxY = Math.min(maxY, Math.max(yMin, yMax));
      int gradientMinColor = renderer.getGradientStopColor();
      int gradientMaxColor = renderer.getGradientStartColor();
      int gradientStartColor = gradientMaxColor;
      int gradientStopColor = gradientMinColor;

      if (yMin < minY) {
        paint.setColor(gradientMinColor);
        canvas.drawRect(Math.round(xMin), Math.round(yMin), Math.round(xMax),
            Math.round(gradientMinY), paint);
      } else {
        gradientStopColor = getGradientPartialColor(gradientMinColor, gradientMaxColor,
            (maxY - gradientMinY) / (maxY - minY));
      }
      if (yMax > maxY) {
        paint.setColor(gradientMaxColor);
        canvas.drawRect(Math.round(xMin), Math.round(gradientMaxY), Math.round(xMax),
            Math.round(yMax), paint);
      } else {
        gradientStartColor = getGradientPartialColor(gradientMaxColor, gradientMinColor,
            (gradientMaxY - minY) / (maxY - minY));
      }
      GradientDrawable gradient = new GradientDrawable(Orientation.BOTTOM_TOP, new int[] {
          gradientStartColor, gradientStopColor });
      gradient.setBounds(Math.round(xMin), Math.round(gradientMinY), Math.round(xMax),
          Math.round(gradientMaxY));
      gradient.draw(canvas);
    } else {
      if (Math.abs(yMin - yMax) < 1) {
        if (yMin < yMax) {
          yMax = yMin + 1;
        } else {
          yMax = yMin - 1;
        }
      }
      canvas
          .drawRect(Math.round(xMin), Math.round(yMin), Math.round(xMax), Math.round(yMax), paint);
    }
  }

  protected int getGradientPartialColor(int minColor, int maxColor, float fraction) {
    int alpha = Math.round(fraction * ColorUtil.alpha(minColor) + (1 - fraction)
        * ColorUtil.alpha(maxColor));
    int r = Math.round(fraction * ColorUtil.red(minColor) + (1 - fraction) * ColorUtil.red(maxColor));
    int g = Math.round(fraction * ColorUtil.green(minColor) + (1 - fraction) * ColorUtil.green(maxColor));
    int b = Math.round(fraction * ColorUtil.blue(minColor) + (1 - fraction) * ColorUtil.blue((maxColor)));
    return ColorUtil.argb(alpha, r, g, b);
  }

  /**
   * The graphical representation of the series values as text.
   * 
   * @param canvas the canvas to paint to
   * @param series the series to be painted
   * @param renderer the series renderer
   * @param paint the paint to be used for drawing
   * @param points the array of points to be used for drawing the series
   * @param seriesIndex the index of the series currently being drawn
   * @param startIndex the start index of the rendering points
   */
  protected void drawChartValuesText(Canvas canvas, XYSeries series, XYSeriesRenderer renderer,
      Paint paint, List points, int seriesIndex, int startIndex) {
    int seriesNr = mDataset.getSeriesCount();
    int length = points.size();
    float halfDiffX = getHalfDiffX(points, length, seriesNr);
    for (int i = 0; i < length; i += 2) {
      int index = startIndex + i / 2;
      double value = series.getY(index);
      if (!isNullValue(value)) {
        float x = points.get(i);
        if (mType == Type.DEFAULT) {
          x += seriesIndex * 2 * halfDiffX - (seriesNr - 1.5f) * halfDiffX;
        }
        if (value >= 0) {
          drawText(canvas, getLabel(renderer.getChartValuesFormat(), value), x, points.get(i + 1)
              - renderer.getChartValuesSpacing(), paint, 0);
        } else {
          drawText(canvas, getLabel(renderer.getChartValuesFormat(), value), x, points.get(i + 1)
              + renderer.getChartValuesTextSize() + renderer.getChartValuesSpacing() - 3, paint, 0);
        }
      }
    }
  }

  /**
   * Returns the legend shape width.
   * 
   * @param seriesIndex the series index
   * @return the legend shape width
   */
  public int getLegendShapeWidth(int seriesIndex) {
    return SHAPE_WIDTH;
  }

  /**
   * The graphical representation of the legend shape.
   * 
   * @param canvas the canvas to paint to
   * @param renderer the series renderer
   * @param x the x value of the point the shape should be drawn at
   * @param y the y value of the point the shape should be drawn at
   * @param seriesIndex the series index
   * @param paint the paint to be used for drawing
   */
  public void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y,
      int seriesIndex, Paint paint) {
    float halfShapeWidth = SHAPE_WIDTH / 2;
    canvas.drawRect(x, y - halfShapeWidth, x + SHAPE_WIDTH, y + halfShapeWidth, paint);
  }

  /**
   * Calculates and returns the half-distance in the graphical representation of
   * 2 consecutive points.
   * 
   * @param points the points
   * @param length the points length
   * @param seriesNr the series number
   * @return the calculated half-distance value
   */
  protected float getHalfDiffX(List points, int length, int seriesNr) {
    float barWidth = mRenderer.getBarWidth();
    if (barWidth > 0) {
      return barWidth / 2;
    }
    int div = length;
    if (length > 2) {
      div = length - 2;
    }
    float halfDiffX = (points.get(length - 2) - points.get(0)) / div;
    if (halfDiffX == 0) {
      halfDiffX = 10;
    }

    if (mType != Type.STACKED && mType != Type.HEAPED) {
      halfDiffX /= seriesNr;
    }
    return (float) (halfDiffX / (getCoeficient() * (1 + mRenderer.getBarSpacing())));
  }

  /**
   * Returns the value of a constant used to calculate the half-distance.
   * 
   * @return the constant value
   */
  protected float getCoeficient() {
    return 1f;
  }

  /**
   * Returns if the chart should display the null values.
   * 
   * @return if null values should be rendered
   */
  protected boolean isRenderNullValues() {
    return true;
  }

  /**
   * Returns the default axis minimum.
   * 
   * @return the default axis minimum
   */
  public double getDefaultMinimum() {
    return 0;
  }

  /**
   * Returns the chart type identifier.
   * 
   * @return the chart type
   */
  public String getChartType() {
    return TYPE;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy