/* LogMyNight - Android app for logging night activities. Copyright (c) 2010 Michael Greifeneder <mikegr@gmx.net>, Oliver Selinger <oliver.selinger@gmail.com> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package at.madexperts.logmynight.chart; import java.util.ArrayList; import java.util.Collections; import java.util.List; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PathEffect; import android.graphics.Paint.Style; import android.text.StaticLayout; import android.text.TextPaint; import android.util.AttributeSet; import android.util.Log; import android.view.View; public class BarChartView extends View { private static final String TAG = BarChartView.class.getName(); private float STROKE_REDUCE_Y_TOP = 40; private float STROKE_REDUCE_Y_BOTTOM = 100; private float STROKE_REDUCE_X_LEFT = 40; private float STROKE_REDUCE_X_RIGHT = 30; private float STROKE_WIDTH = 1; private float LABEL_WIDTH = 2; private float NAME_LABEL_SPACE_TO_BAR = 2f; private float AMOUNT_LABEL_SPACE_TO_BAR = 5f; private float Y_LABEL_SPACE_TO_LINE = 5f; private Paint strokePaint; private Paint labelPaint; private Paint bar1Paint; private Paint bar2Paint; private Paint bar3Paint; private Paint bar4Paint; private Paint bar5Paint; private Paint bar6Paint; private Paint[] barPaints; private List<BarItem> barItems = new ArrayList<BarItem>(); // =========================================================== // Constructors // =========================================================== public BarChartView(Context context) { super(context); initPaints(); } public BarChartView(Context context, AttributeSet attrs) { super(context, attrs); initPaints(); } private void initPaints() { strokePaint = new Paint(); strokePaint.setStrokeWidth(STROKE_WIDTH); strokePaint.setColor(Color.GRAY); labelPaint = new Paint(); labelPaint.setStrokeWidth(LABEL_WIDTH); labelPaint.setColor(Color.GRAY); labelPaint.setTextAlign(Paint.Align.CENTER); bar1Paint = new Paint(); bar1Paint.setStrokeWidth(STROKE_WIDTH); bar1Paint.setColor(Color.RED); bar2Paint = new Paint(); bar2Paint.setStrokeWidth(STROKE_WIDTH); bar2Paint.setColor(Color.GREEN); bar3Paint = new Paint(); bar3Paint.setStrokeWidth(STROKE_WIDTH); bar3Paint.setColor(Color.BLUE); bar4Paint = new Paint(); bar4Paint.setStrokeWidth(STROKE_WIDTH); bar4Paint.setColor(Color.YELLOW); bar5Paint = new Paint(); bar5Paint.setStrokeWidth(STROKE_WIDTH); bar5Paint.setColor(Color.MAGENTA); bar6Paint = new Paint(); bar6Paint.setStrokeWidth(STROKE_WIDTH); bar6Paint.setColor(Color.CYAN); barPaints = new Paint[] { bar1Paint, bar2Paint, bar3Paint, bar4Paint, bar5Paint, bar6Paint }; } public void setData(List<BarItem> barItems) { this.barItems = barItems; if (barItems != null && barItems.size() > 0) { Collections.sort(barItems); invalidate(); } } private void drawBars(Canvas canvas, float width, float height, float stopX, float stopY, float lineWidth, float lineHeight) { int counter = 0; float spaceForFigureOnFirstBar = 20f; float heightOfOneDrink = 0; float space = lineWidth / 6f; float widthOfBar = space / 2f; float halfWidthOfBar = widthOfBar / 2f; // float leftFirstBar = STROKE_REDUCE_X_LEFT + spaceForFigureOnFirstBar; float heightOfFirstBar = stopY - STROKE_REDUCE_Y_TOP - spaceForFigureOnFirstBar; float pointerInWidth = stopX + space - halfWidthOfBar; for (BarItem barItem : barItems) { float amount = (float) barItem.getAmount(); if (heightOfOneDrink == 0) { heightOfOneDrink = heightOfFirstBar / amount; Log.d(TAG, "heightOfOneDrink: " + heightOfOneDrink); } // float left = leftFirstBar; float heightOfBar = amount * heightOfOneDrink; float left = pointerInWidth - widthOfBar; float top = stopY - heightOfBar; float right = pointerInWidth; float bottom = stopY; final int mainColor = barPaints[counter].getColor(); Log.d(TAG, "amount: " + amount + "left: " + left + " top: " + top + " right: " + right + "bottom: " + bottom); // left <= right and top <= bottom canvas.drawRect(left, top, right, bottom, barPaints[counter]); paint3d(left, top, right, bottom, mainColor, canvas); /* Paint linePaint = new Paint(); linePaint.setColor(Color.WHITE); canvas.drawLine(right, top, right+10, top-10, linePaint); */ // name canvas.save(); float tempX = pointerInWidth - halfWidthOfBar; float tempY = stopY + NAME_LABEL_SPACE_TO_BAR; canvas.translate(tempX, tempY); StaticLayout layout = new StaticLayout(barItem.getName(), new TextPaint(labelPaint), (int)space-2, android.text.Layout.Alignment.ALIGN_NORMAL, 1.0f, 0f, true); layout.draw(canvas); canvas.restore(); // canvas.drawText(barItem.getName(), pointerInWidth - halfWidthOfBar, // stopY + NAME_LABEL_SPACE_TO_BAR, labelPaint); // amount canvas.drawText(String.valueOf(barItem.getAmount()), pointerInWidth - halfWidthOfBar, top - AMOUNT_LABEL_SPACE_TO_BAR, labelPaint); // set pointer one bar up pointerInWidth += space; if (counter == 4) break; counter++; } // draw rest of the drinks float sumAmountOfRest = 0; for (int i = 5; i < barItems.size(); i++) { BarItem barItem = barItems.get(i); sumAmountOfRest += barItem.getAmount(); } if (sumAmountOfRest != 0) { float heightOfBar = sumAmountOfRest * heightOfOneDrink; float left = pointerInWidth - widthOfBar; float top = stopY - heightOfBar; float right = pointerInWidth; float bottom = stopY; canvas.drawRect(left, top, right, bottom, barPaints[5]); paint3d(left, top, right, bottom, barPaints[5].getColor(), canvas); //name canvas.save(); float tempX = pointerInWidth - halfWidthOfBar; float tempY = stopY + NAME_LABEL_SPACE_TO_BAR; canvas.translate(tempX, tempY); StaticLayout layout = new StaticLayout("Others", new TextPaint(labelPaint), (int)space-2, android.text.Layout.Alignment.ALIGN_NORMAL, 1.0f, 0f, true); layout.draw(canvas); canvas.restore(); // canvas.drawText("Others", pointerInWidth - halfWidthOfBar, stopY // + NAME_LABEL_SPACE_TO_BAR, labelPaint); // amount canvas.drawText(String.valueOf((int) sumAmountOfRest), pointerInWidth - halfWidthOfBar, top - AMOUNT_LABEL_SPACE_TO_BAR, labelPaint); } } private void paint3d(float left, float top, float right, float bottom, int mainColor, Canvas canvas) { Path topPath = new Path(); topPath.moveTo(left, top); topPath.lineTo(left+10, top-10); topPath.lineTo(right+10, top-10); topPath.lineTo(right, top); Paint topPaint = new Paint(); topPaint.setStyle(Style.FILL_AND_STROKE); topPaint.setColor(lighten(mainColor, 0.875f)); canvas.drawPath(topPath, topPaint); Path sidePath = new Path(); sidePath.moveTo(right, top); sidePath.lineTo(right+10, top-10); sidePath.lineTo(right+10, bottom-10); sidePath.lineTo(right, bottom); Paint sidePaint = new Paint(); sidePaint.setStyle(Style.FILL_AND_STROKE); sidePaint.setColor(lighten(mainColor, 0.75f)); canvas.drawPath(sidePath, sidePaint); } private int lighten(int color, float newLightValue) { float[] hsv = new float[3]; Color.colorToHSV(color, hsv); hsv[2] = newLightValue; return Color.HSVToColor(hsv); } @Override protected void onDraw(Canvas canvas) { float height = canvas.getHeight(); float width = canvas.getWidth(); Log.d(TAG, "canvas height: " + height); Log.d(TAG, "canvas width: " + width); // draw Y & X line float stopX = STROKE_REDUCE_X_LEFT; float stopY = height - STROKE_REDUCE_Y_BOTTOM; float lineWidth = width - STROKE_REDUCE_X_LEFT - STROKE_REDUCE_X_RIGHT; float lineHeight = height - STROKE_REDUCE_Y_BOTTOM - STROKE_REDUCE_Y_TOP; float startXHorizontal = width - STROKE_REDUCE_X_RIGHT; float startYHorizontal = stopY; Log.d(TAG, "Draw X line: " + startXHorizontal + "/" + startYHorizontal + " - " + stopX + "/" + stopY); canvas.drawLine(startXHorizontal, startYHorizontal, stopX, stopY, strokePaint); float startXVertical = stopX; float startYVertical = STROKE_REDUCE_Y_TOP; Log.d(TAG, "Draw Y line: " + startXVertical + "/" + startYVertical + " - " + stopX + "/" + stopY); canvas.drawLine(startXVertical, startYVertical, stopX, stopY + STROKE_WIDTH / 2f, strokePaint); // draw y label canvas.translate(stopX - Y_LABEL_SPACE_TO_LINE, (stopY - startYVertical) / 2 + startYVertical); canvas.rotate(-90); canvas.drawText("Menge", 0, 0, labelPaint); canvas.restore(); drawBars(canvas, width, height, stopX, stopY, lineWidth, lineHeight); } }