/* * Copyright 2014 Diogo Bernardino * * 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.db.chart.view; import java.util.ArrayList; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; import com.db.chart.model.ChartSet; import com.db.williamchart.R; /** * Implements a bar chart extending {@link com.db.chart.view.ChartView} */ public abstract class BaseBarChartView extends ChartView { /** Offset to control bar positions. Added due to multiset charts. */ protected float drawingOffset; /** Style applied to Graph */ protected Style style; /** Bar width */ protected float barWidth; public BaseBarChartView(Context context, AttributeSet attrs) { super(context, attrs); style = new Style(context.getTheme() .obtainStyledAttributes(attrs, R.styleable.ChartAttrs, 0, 0)); } public BaseBarChartView(Context context) { super(context); style = new Style(); } @Override public void onAttachedToWindow(){ super.onAttachedToWindow(); style.init(); } @Override public void onDetachedFromWindow(){ super.onDetachedFromWindow(); style.clean(); } /** * Method responsible to draw bars with the parsed screen points. * * @param canvas The canvas to draw on. * @param data {@link java.util.ArrayList} of {@link com.db.chart.model.ChartSet} * to use while drawing the Chart */ @Override protected void onDrawChart(Canvas canvas, ArrayList<ChartSet> data) {} /** * Draws a bar (a chart bar btw :)). * * @param canvas {@link android.graphics.Canvas} used to draw the background * @param left The X coordinate of the left side of the rectangle * @param top The Y coordinate of the top of the rectangle * @param right The X coordinate of the right side of the rectangle * @param bottom The Y coordinate of the bottom of the rectangle */ protected void drawBar(Canvas canvas, float left, float top, float right, float bottom) { canvas.drawRoundRect(new RectF((int) left, (int) top, (int) right, (int) bottom), style.cornerRadius, style.cornerRadius, style.barPaint); } /** * Draws the background (not the fill) of a bar, the one behind the bar. * * @param canvas {@link android.graphics.Canvas} used to draw the background * @param left The X coordinate of the left side of the rectangle * @param top The Y coordinate of the top of the rectangle * @param right The X coordinate of the right side of the rectangle * @param bottom The Y coordinate of the bottom of the rectangle */ protected void drawBarBackground(Canvas canvas, float left, float top, float right, float bottom) { canvas.drawRoundRect(new RectF(left, top, right, bottom), style.cornerRadius, style.cornerRadius, style.barBackgroundPaint); } /** * Calculates Bar width based on the distance of two horizontal labels. * * @param nSets Number of sets * @param x0 Coordinate(n) * @param x1 Coordinate(n+1) */ protected void calculateBarsWidth(int nSets, float x0, float x1) { barWidth = ((x1 - x0) - style.barSpacing/2 - style.setSpacing * (nSets - 1)) / nSets; } /** * Having calculated previously the barWidth gives the offset to know * where to start drawing the first bar of each group. * * @param size Size of sets */ protected void calculatePositionOffset(int size){ if(size % 2 == 0) drawingOffset = size * barWidth/2 + (size - 1) * (style.setSpacing / 2); else drawingOffset = size * barWidth/2 + ((size - 1) / 2) * style.setSpacing; } /* * -------- * Setters * -------- */ /** * Define the space to use between bars. * * @param spacing Spacing between {@link com.db.chart.model.Bar} */ public void setBarSpacing(float spacing){ style.barSpacing = spacing; } /** * When multiset, it defines the space to use set. * * @param spacing Spacing between {@link com.db.chart.model.BarSet} */ public void setSetSpacing(float spacing){ style.setSpacing = spacing; } /** * Background in bars place. * * @param bool True in case {@link com.db.chart.model.Bar} must display a background */ public void setBarBackground(boolean bool){ style.hasBarBackground = bool; } /** * Color to use in bars background. * * @param color Color of background in case setBarBackground has been set to True */ public void setBarBackgroundColor(int color){ style.mBarBackgroundColor = color; } /** * Round corners of bars. * * @param radius Radius applied to the corners of {@link com.db.chart.model.Bar} */ public void setRoundCorners(float radius){ style.cornerRadius = radius; } /* * ---------- * Style * ---------- */ public class Style{ private static final int DEFAULT_COLOR = -16777216; /** Bars fill variables */ protected Paint barPaint; /** Spacing between bars */ protected float barSpacing; protected float setSpacing; /** Bar background variables */ protected Paint barBackgroundPaint; private int mBarBackgroundColor; protected boolean hasBarBackground; /** Radius to round corners **/ protected float cornerRadius; /** Shadow related variables */ private final float mShadowRadius; private final float mShadowDx; private final float mShadowDy; private final int mShadowColor; /** Shadow color */ private int mAlpha; private int mRed; private int mBlue; private int mGreen; protected Style() { mBarBackgroundColor = DEFAULT_COLOR; hasBarBackground = false; barSpacing = getResources().getDimension(R.dimen.bar_spacing); setSpacing = getResources().getDimension(R.dimen.set_spacing); mShadowRadius = 0; mShadowDx = 0; mShadowDy = 0; mShadowColor = DEFAULT_COLOR; } protected Style(TypedArray attrs) { mBarBackgroundColor = DEFAULT_COLOR; hasBarBackground = false; barSpacing = attrs.getDimension( R.styleable.BarChartAttrs_chart_barSpacing, getResources().getDimension(R.dimen.bar_spacing)); setSpacing = attrs.getDimension( R.styleable.BarChartAttrs_chart_barSpacing, getResources().getDimension(R.dimen.set_spacing)); mShadowRadius = attrs.getDimension( R.styleable.ChartAttrs_chart_shadowRadius, 0); mShadowDx = attrs.getDimension( R.styleable.ChartAttrs_chart_shadowDx, 0); mShadowDy = attrs.getDimension( R.styleable.ChartAttrs_chart_shadowDy, 0); mShadowColor = attrs.getColor( R.styleable.ChartAttrs_chart_shadowColor, 0); } private void init(){ mAlpha = Color.alpha(mShadowColor); mRed = Color.red(mShadowColor); mBlue = Color.blue(mShadowColor); mGreen = Color.green(mShadowColor); barPaint = new Paint(); barPaint.setStyle(Paint.Style.FILL); barPaint.setShadowLayer(mShadowRadius, mShadowDx, mShadowDy, mShadowColor); barBackgroundPaint = new Paint(); barBackgroundPaint.setColor(mBarBackgroundColor); barBackgroundPaint.setStyle(Paint.Style.FILL); } private void clean(){ barPaint = null; barBackgroundPaint = null; } /** * Applies an alpha to the paint object. * * @param paint {@link android.graphics.Paint} object to apply alpha. * @param alpha Alpha value (opacity). */ protected void applyAlpha(Paint paint, float alpha){ paint.setAlpha((int)(alpha * 255)); paint.setShadowLayer( style.mShadowRadius, style.mShadowDx, style.mShadowDy, Color.argb(((int)(alpha * 255) < style.mAlpha) ? (int)(alpha * 255) : style.mAlpha, style.mRed, style.mGreen, style.mBlue)); } } }