/* * This source is part of the * _____ ___ ____ * __ / / _ \/ _ | / __/___ _______ _ * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/ * \___/_/|_/_/ |_/_/ (_)___/_/ \_, / * /___/ * repository. * * Copyright (C) 2013 Benoit 'BoD' Lubek (BoD@JRAF.org) * * 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 org.jraf.android.util.ui.graph; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.Style; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.util.AttributeSet; import android.util.SparseArray; import android.view.View; import org.jraf.android.util.math.MathUtil; /** * A very simple view showing a graph from an array of floats.<br/> * The graph is automatically scaled to fit the view. */ public class GraphView extends View { private static final int DOT_WIDTH = 8; private static String KEY_VALUES = "KEY_VALUES"; private static String KEY_COLOR = "KEY_COLOR"; private static String KEY_TYPE = "KEY_TYPE"; public static enum Type { LINES, POINTS, } private static class SavedState extends BaseSavedState { private SparseArray<Object> mValues; public SavedState(Parcel source) { super(source); mValues = source.readSparseArray(getClass().getClassLoader()); } public SavedState(Parcelable superState) { super(superState); } @Override public void writeToParcel(Parcel out, int flags) { super.writeToParcel(out, flags); out.writeSparseArray(mValues); } @SuppressWarnings({ "unused", "hiding" }) public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() { @Override public SavedState createFromParcel(Parcel in) { return new SavedState(in); } @Override public SavedState[] newArray(int size) { return new SavedState[size]; } }; public void setValues(SparseArray<?> values) { mValues = (SparseArray<Object>) values; } public SparseArray<?> getValues() { return mValues; } } private SparseArray<Bundle> mValues = new SparseArray<Bundle>(); private Paint mPaint; public GraphView(Context context) { super(context); init(); } public GraphView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public GraphView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { mPaint = new Paint(); mPaint.setStyle(Style.FILL); mPaint.setAntiAlias(true); mPaint.setStrokeWidth(1 * getResources().getDisplayMetrics().density); } @Override protected Parcelable onSaveInstanceState() { Parcelable superState = super.onSaveInstanceState(); SavedState ss = new SavedState(superState); ss.setValues(mValues); return ss; } @Override protected void onRestoreInstanceState(Parcelable state) { if (!(state instanceof SavedState)) { super.onRestoreInstanceState(state); return; } SavedState ss = (SavedState) state; super.onRestoreInstanceState(ss.getSuperState()); mValues = (SparseArray<Bundle>) ((SavedState) state).getValues(); } private Bundle getBundle(int index) { Bundle res = mValues.get(index); if (res == null) { res = new Bundle(); mValues.put(index, res); } return res; } public void setValues(int index, float[] values) { Bundle bundle = getBundle(index); bundle.putFloatArray(KEY_VALUES, values); invalidate(); } public void setType(int index, Type type) { Bundle bundle = getBundle(index); bundle.putInt(KEY_TYPE, type.ordinal()); invalidate(); } public void setColor(int index, int color) { Bundle bundle = getBundle(index); bundle.putInt(KEY_COLOR, color); invalidate(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int total = mValues.size(); float lineWidth = getResources().getDisplayMetrics().density; for (int i = 0; i < total; i++) { Bundle bundle = mValues.valueAt(i); float[] values = bundle.getFloatArray(KEY_VALUES); if (values == null) continue; Type type = Type.values()[bundle.getInt(KEY_TYPE, 0)]; int color = bundle.getInt(KEY_COLOR, 0xFF000000); mPaint.setColor(color); float[] minMax = MathUtil.getMinMax(values); float minVal = minMax[0]; float maxVal = minMax[1]; int width = 0; int height = 0; switch (type) { case POINTS: width = canvas.getWidth() - DOT_WIDTH; height = canvas.getHeight() - DOT_WIDTH; break; case LINES: width = (int) (canvas.getWidth() - lineWidth * 2); height = (int) (canvas.getHeight() - lineWidth * 2); break; } int len = values.length; float xRatio = width / (float) (len - 1); float yRatio = height / total / (maxVal - minVal); int prevX = 0; int prevY = 0; for (int j = 0; j < len; j++) { float curVal = values[j]; int x = (int) (j * xRatio); int y = (int) ((maxVal - curVal) * yRatio); y += height / total * i; switch (type) { case POINTS: canvas.drawRect(x, y, x + DOT_WIDTH, y + DOT_WIDTH, mPaint); break; case LINES: if (j > 0) { canvas.drawLine(prevX + lineWidth, prevY + lineWidth, x + lineWidth, y + lineWidth, mPaint); } break; } prevX = x; prevY = y; } } } }