From 352af61871dd153783511c34075b5c614d5ea3d2 Mon Sep 17 00:00:00 2001 From: paul Date: Wed, 20 Nov 2013 16:33:49 -0500 Subject: [PATCH 01/44] fixed axis renderer tick marks --- src/com/devsmart/plotter/AxisRenderer.java | 2 +- src/com/devsmart/plotter/DataRenderer.java | 10 ++ src/com/devsmart/plotter/GraphView.java | 79 +++++++------ ...phView.java => LineGraphDataRenderer.java} | 62 ++-------- .../devsmart/plotter/SimpleAxisRenderer.java | 106 +++++++++--------- 5 files changed, 116 insertions(+), 143 deletions(-) create mode 100644 src/com/devsmart/plotter/DataRenderer.java rename src/com/devsmart/plotter/{LineGraphView.java => LineGraphDataRenderer.java} (61%) diff --git a/src/com/devsmart/plotter/AxisRenderer.java b/src/com/devsmart/plotter/AxisRenderer.java index cd1bd45..fa7f723 100644 --- a/src/com/devsmart/plotter/AxisRenderer.java +++ b/src/com/devsmart/plotter/AxisRenderer.java @@ -5,6 +5,6 @@ public interface AxisRenderer { - void drawAxis(Canvas canvas, RectF viewport, GraphView graphview); + void drawAxis(Canvas canvas, int canvasWidth, int canvasHeight, RectF viewport); } diff --git a/src/com/devsmart/plotter/DataRenderer.java b/src/com/devsmart/plotter/DataRenderer.java new file mode 100644 index 0000000..29764e4 --- /dev/null +++ b/src/com/devsmart/plotter/DataRenderer.java @@ -0,0 +1,10 @@ +package com.devsmart.plotter; + +import android.graphics.Canvas; +import android.graphics.RectF; + +public interface DataRenderer { + + public void draw(Canvas canvas, RectF viewPort); + +} diff --git a/src/com/devsmart/plotter/GraphView.java b/src/com/devsmart/plotter/GraphView.java index 3d46cc5..c52b975 100644 --- a/src/com/devsmart/plotter/GraphView.java +++ b/src/com/devsmart/plotter/GraphView.java @@ -1,5 +1,6 @@ package com.devsmart.plotter; +import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.concurrent.ExecutorService; @@ -27,7 +28,7 @@ import com.devsmart.BackgroundTask; -public abstract class GraphView extends View { +public class GraphView extends View { public static enum Axis { X, @@ -40,7 +41,7 @@ public static enum Axis { private ExecutorService mDrawThread = Executors.newSingleThreadExecutor(); private RectF mViewPort = new RectF(); - protected LinkedList mSeries = new LinkedList(); + protected LinkedList mPlotData = new LinkedList(); private Bitmap mFrontBuffer; private Matrix mTransformMatrix = new Matrix(); @@ -61,7 +62,7 @@ public static enum Axis { protected int mXAxisMargin; protected int mYAxisMargin; - protected AxisRenderer mAxisRenderer = new SimpleAxisRenderer(); + protected AxisRenderer mAxisRenderer; private ZoomButtonsController mZoomControls; @@ -76,6 +77,7 @@ public GraphView(Context context, AttributeSet attrs) { } private void init() { + mAxisRenderer = new SimpleAxisRenderer(this); mPanGestureDetector = new GestureDetector(mSimpleGestureListener); mScaleGestureDetector = new XYScaleGestureDetector(getContext(), mSimpleScaleGestureListener); mDrawPaint.setFilterBitmap(true); @@ -143,17 +145,17 @@ protected void onVisibilityChanged(View changedView, int visibility) { } } - public void addSeries(Series series) { - mSeries.add(series); + public void addSeries(DataRenderer series) { + mPlotData.add(series); drawFrame(mViewPort); } - public void removeSeries(Series series) { - mSeries.remove(series); + public void removeSeries(DataRenderer series) { + mPlotData.remove(series); drawFrame(mViewPort); } - public Matrix getViewportToScreenMatrix( + public static Matrix getViewportToScreenMatrix( RectF screen, RectF viewPort){ @@ -220,17 +222,14 @@ protected void onDraw(Canvas canvas) { if(mFrontBuffer != null){ canvas.drawBitmap(mFrontBuffer, mTransformMatrix, mDrawPaint); } - mAxisRenderer.drawAxis(canvas, mViewPort, this); + mAxisRenderer.drawAxis(canvas, getMeasuredWidth(), getMeasuredHeight(), mViewPort); } - protected abstract void drawGraph(Canvas canvas, RectF viewPort); - - private void drawFrame(final RectF viewport) { if(mBackgroundDrawTask != null){ mBackgroundDrawTask.mCanceled = true; } - mBackgroundDrawTask = new BackgroundDrawTask(getMeasuredWidth(), getMeasuredHeight(), new RectF(viewport)); + mBackgroundDrawTask = new BackgroundDrawTask(viewport); BackgroundTask.runBackgroundTask(mBackgroundDrawTask, mDrawThread); } @@ -241,18 +240,23 @@ private class BackgroundDrawTask extends BackgroundTask { private Bitmap mDrawBuffer; private boolean mCanceled = false; private final RectF viewport; + private ArrayList mData; - public BackgroundDrawTask(int width, int height, RectF viewport){ - this.width = width; - this.height = height; - this.viewport = new RectF(viewport); + public BackgroundDrawTask(RectF view){ + this.width = getMeasuredWidth(); + this.height = getMeasuredHeight(); + this.viewport = new RectF(view); + this.mData = new ArrayList(mPlotData); } @Override public void onBackground() { if(!mCanceled){ - mDrawBuffer = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); - drawGraph(new Canvas(mDrawBuffer), viewport); + mDrawBuffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444); + Canvas c = new Canvas(mDrawBuffer); + for(DataRenderer r : mData){ + r.draw(c, viewport); + } } } @@ -263,10 +267,8 @@ public void onAfter() { mViewPort = viewport; mTransformMatrix.reset(); invalidate(); - //mBackgroundDrawTask = null; } else if(mDrawBuffer != null) { mDrawBuffer.recycle(); - mDrawBuffer = null; } } @@ -503,26 +505,28 @@ protected void drawAxis(Canvas canvas, RectF viewPort) { } - - public void autoScaleDomainAndRange() { - - /* - mViewPort.set(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, + + public static RectF getSeriesLimits(Series series) { + RectF retval = new RectF(); + retval.set(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY); - for(Series series : mSeries){ - Iterator it = series.createIterator(); - while(it.hasNext()){ - float[] point = it.next(); - mViewPort.left = Math.min(mViewPort.left, point[0]); - mViewPort.right = Math.max(mViewPort.right, point[0]); - mViewPort.top = Math.min(mViewPort.top, point[1]); - mViewPort.bottom = Math.max(mViewPort.bottom, point[1]); - } + + Iterator it = series.createIterator(); + while(it.hasNext()){ + float[] point = it.next(); + retval.left = Math.min(retval.left, point[0]); + retval.right = Math.max(retval.right, point[0]); + retval.top = Math.min(retval.top, point[1]); + retval.bottom = Math.max(retval.bottom, point[1]); } - drawFrame(mViewPort); - */ + + return retval; + } + + public void autoScaleDomainAndRange() { + /* BackgroundTask.runBackgroundTask(new BackgroundTask() { RectF viewport = new RectF(); @@ -556,6 +560,7 @@ public void onAfter() { } }, mDrawThread); + */ } diff --git a/src/com/devsmart/plotter/LineGraphView.java b/src/com/devsmart/plotter/LineGraphDataRenderer.java similarity index 61% rename from src/com/devsmart/plotter/LineGraphView.java rename to src/com/devsmart/plotter/LineGraphDataRenderer.java index c0b8181..10a7cf9 100644 --- a/src/com/devsmart/plotter/LineGraphView.java +++ b/src/com/devsmart/plotter/LineGraphDataRenderer.java @@ -1,40 +1,28 @@ package com.devsmart.plotter; -import android.content.Context; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.RectF; -import android.util.AttributeSet; import com.devsmart.PeekableIterator; -public class LineGraphView extends GraphView { +public class LineGraphDataRenderer implements DataRenderer { protected Paint mPointPaint = new Paint(); + protected Series mSeries; - public LineGraphView(Context context) { - super(context); - init(); - } - - public LineGraphView(Context context, AttributeSet attrs) { - super(context, attrs); - init(); - } - - protected void init() { - mPointPaint.setColor(Color.GREEN); + public LineGraphDataRenderer(Series series, int color) { + mSeries = series; + mPointPaint.setColor(color); mPointPaint.setStrokeWidth(2.0f); } - protected void drawGraph(Canvas canvas, RectF viewPort){ - //clear the canvas - canvas.drawColor(mBackgroundColor); - Matrix matrix = getViewportToScreenMatrix(new RectF(0,0,canvas.getWidth(), canvas.getHeight()), viewPort); + public void draw(Canvas canvas, RectF viewPort){ + + Matrix matrix = GraphView.getViewportToScreenMatrix(new RectF(0,0,canvas.getWidth(), canvas.getHeight()), viewPort); RectF pixel = new RectF(); @@ -46,8 +34,8 @@ protected void drawGraph(Canvas canvas, RectF viewPort){ pixelBin.top = Float.NEGATIVE_INFINITY; float[] lastpoint = new float[]{Float.NaN, Float.NaN}; - for(Series series : mSeries){ - PeekableIterator it = new PeekableIterator(series.createIterator()); + + PeekableIterator it = new PeekableIterator(mSeries.createIterator()); //findPixelBinLessThan(pixelBin, it); @@ -82,36 +70,8 @@ protected void drawGraph(Canvas canvas, RectF viewPort){ } } - } - - } - - private boolean findPixelBinLessThan(RectF pixelBin, PeekableIterator it) { - boolean retval = false; - float[] point; - while(it.hasNext()){ - - point = it.next(); - pixelBin.bottom = Math.min(pixelBin.bottom, point[1]); - pixelBin.top = Math.max(pixelBin.top, point[1]); - - point = it.peek(); - - if(point[0] >= pixelBin.right){ - break; - } - - if(point[0] >= pixelBin.left && point[0] < pixelBin.right){ - pixelBin.bottom = Float.POSITIVE_INFINITY; - pixelBin.top = Float.NEGATIVE_INFINITY; - } - - - retval = true; - } - - return retval; + } private boolean fillPixelBin(RectF pixelBin, PeekableIterator it) { diff --git a/src/com/devsmart/plotter/SimpleAxisRenderer.java b/src/com/devsmart/plotter/SimpleAxisRenderer.java index 6202b0b..db9eaee 100644 --- a/src/com/devsmart/plotter/SimpleAxisRenderer.java +++ b/src/com/devsmart/plotter/SimpleAxisRenderer.java @@ -23,38 +23,35 @@ public class SimpleAxisRenderer implements AxisRenderer { String mXAxisLabel = "Wavelength"; String mYAxisLabel = "Intensity"; - public SimpleAxisRenderer() { - - } - - protected boolean init = false; - private float[] mYAxis; - private float[] mXAxis; - float[] points = new float[4]; - Rect bounds = new Rect(); + DisplayMetrics mDisplayMetrics; - protected void init(GraphView graphview) { - DisplayMetrics metrics = graphview.getContext().getResources().getDisplayMetrics(); - - final int canvasWidth = graphview.getWidth(); - final int canvasHeight = graphview.getHeight(); + public SimpleAxisRenderer(GraphView graphview) { + mDisplayMetrics = graphview.getContext().getResources().getDisplayMetrics(); mAxisLabelPaint.setColor(Color.BLACK); - mAxisLabelPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 15, metrics)); + mAxisLabelPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 15, mDisplayMetrics)); mAxisLabelPaint.setAntiAlias(true); mAxisTickPaint.setColor(Color.DKGRAY); - mAxisTickPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 10, metrics)); + mAxisTickPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 10, mDisplayMetrics)); mAxisTickPaint.setAntiAlias(true); - + } + + private float[] mYAxis; + private float[] mXAxis; + float[] points = new float[4]; + Rect bounds = new Rect(); + RectF boundsf = new RectF(); + + protected void calcBounds(final int canvasWidth, final int canvasHeight) { mAxisLabelPaint.getTextBounds("1", 0, 1, bounds); float axisLabelHeight = bounds.height(); mAxisTickPaint.getTextBounds("1", 0, 1, bounds); float tickLabelHeight = bounds.height(); - float axisLabelBoundery = axisLabelHeight + tickLabelHeight + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3, metrics); + float axisLabelBoundery = axisLabelHeight + tickLabelHeight + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3, mDisplayMetrics); float height = canvasHeight - axisLabelBoundery - mPlotMargins.height(); @@ -64,28 +61,19 @@ protected void init(GraphView graphview) { mXAxis = new float[]{axisLabelBoundery + mPlotMargins.left, canvasHeight - axisLabelBoundery - mPlotMargins.bottom, canvasWidth - mPlotMargins.right, canvasHeight - axisLabelBoundery - mPlotMargins.bottom}; - - init = true; } - @Override - public void drawAxis(Canvas canvas, RectF viewPort, GraphView graphview) { + public void drawAxis(Canvas canvas, final int canvasWidth, final int canvasHeight, RectF viewPort) { - if(!init){ - init(graphview); - } + calcBounds(canvasWidth, canvasHeight); - DisplayMetrics metrics = graphview.getContext().getResources().getDisplayMetrics(); - - final int canvasWidth = graphview.getWidth(); - final int canvasHeight = graphview.getHeight(); - Paint axisPaint = new Paint(); axisPaint.setColor(mAxisColor); axisPaint.setStrokeWidth(2); - Matrix matrix = graphview.getViewportToScreenMatrix(new RectF(0,0,canvasWidth, canvasHeight), viewPort); + boundsf.set(0,0,canvasWidth, canvasHeight); + Matrix matrix = GraphView.getViewportToScreenMatrix(boundsf, viewPort); if(mDrawXAxis) { @@ -95,7 +83,7 @@ public void drawAxis(Canvas canvas, RectF viewPort, GraphView graphview) { //draw label mAxisLabelPaint.getTextBounds(mXAxisLabel, 0, mXAxisLabel.length(), bounds); - float y = canvasHeight - mPlotMargins.bottom + bounds.bottom + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3, metrics); + float y = canvasHeight - mPlotMargins.bottom + bounds.bottom + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3, mDisplayMetrics); canvas.drawText(mXAxisLabel, (mXAxis[2]-mXAxis[0])/2 - bounds.width()/2 + mXAxis[0], y, mAxisLabelPaint); //draw ticks @@ -108,16 +96,23 @@ public void drawAxis(Canvas canvas, RectF viewPort, GraphView graphview) { points[3] = 0; matrix.mapPoints(points); points[1] = mXAxis[1]; - points[3] = mXAxis[1] - TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, metrics); - canvas.drawLines(points, axisPaint); - - String label = getTickLabel(xPoint); - mAxisTickPaint.getTextBounds(label, 0, label.length(), bounds); + points[3] = mXAxis[1] - TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, mDisplayMetrics); + + if(points[0] >= mXAxis[0]) { + canvas.drawLines(points, axisPaint); + + String label = getTickLabel(xPoint); + mAxisTickPaint.getTextBounds(label, 0, label.length(), bounds); + + + canvas.drawText(label, + points[0]-bounds.width()/2, + points[1] + bounds.height() + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, mDisplayMetrics), + mAxisTickPaint); + } - canvas.drawText(label, - points[0]-bounds.width()/2, - points[1] + bounds.height() + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, metrics), - mAxisTickPaint); + + xPoint += dist; @@ -146,19 +141,22 @@ public void drawAxis(Canvas canvas, RectF viewPort, GraphView graphview) { points[3] = yPoint; matrix.mapPoints(points); points[0] = mYAxis[0]; - points[2] = mYAxis[0] + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, metrics); - canvas.drawLines(points, axisPaint); - - String label = getTickLabel(yPoint); - mAxisTickPaint.getTextBounds(label, 0, label.length(), bounds); - canvas.save(); - points[2] = points[0]-bounds.height()/2-TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, metrics); - points[3] = points[1]+bounds.width()/2; - canvas.rotate(-90, points[2], points[3]); - canvas.drawText(label, - points[2], points[3], - mAxisTickPaint); - canvas.restore(); + points[2] = mYAxis[0] + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, mDisplayMetrics); + + if(points[1] <= mYAxis[3]) { + canvas.drawLines(points, axisPaint); + + String label = getTickLabel(yPoint); + mAxisTickPaint.getTextBounds(label, 0, label.length(), bounds); + canvas.save(); + points[2] = points[0]-bounds.height()/2-TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, mDisplayMetrics); + points[3] = points[1]+bounds.width()/2; + canvas.rotate(-90, points[2], points[3]); + canvas.drawText(label, + points[2], points[3], + mAxisTickPaint); + canvas.restore(); + } yPoint += dist; } From c1778c003514b91472f55bcfe459fc9845d13a0b Mon Sep 17 00:00:00 2001 From: paul Date: Wed, 20 Nov 2013 19:02:52 -0500 Subject: [PATCH 02/44] really unstable but kinda working --- src/com/devsmart/plotter/AxisFunction.java | 21 ++ src/com/devsmart/plotter/AxisRenderer.java | 18 ++ .../devsmart/plotter/CoordinateSystem.java | 82 +++++++ src/com/devsmart/plotter/DataRenderer.java | 2 +- src/com/devsmart/plotter/GraphView.java | 219 +++--------------- .../plotter/LineGraphDataRenderer.java | 24 +- src/com/devsmart/plotter/LinearFunction.java | 42 ++++ .../devsmart/plotter/SimpleAxisRenderer.java | 19 ++ 8 files changed, 228 insertions(+), 199 deletions(-) create mode 100644 src/com/devsmart/plotter/AxisFunction.java create mode 100644 src/com/devsmart/plotter/CoordinateSystem.java create mode 100644 src/com/devsmart/plotter/LinearFunction.java diff --git a/src/com/devsmart/plotter/AxisFunction.java b/src/com/devsmart/plotter/AxisFunction.java new file mode 100644 index 0000000..b6a43ca --- /dev/null +++ b/src/com/devsmart/plotter/AxisFunction.java @@ -0,0 +1,21 @@ +package com.devsmart.plotter; + +public interface AxisFunction { + + void interpolate(float[] x, float[] y); + + AxisFunction copy(); + + /** + * translate screen coord --> graph coord + * @param x + * @return + */ + float value(float x); + + /** + * return the inverse function + * @return + */ + AxisFunction inverse(); +} diff --git a/src/com/devsmart/plotter/AxisRenderer.java b/src/com/devsmart/plotter/AxisRenderer.java index fa7f723..83579d0 100644 --- a/src/com/devsmart/plotter/AxisRenderer.java +++ b/src/com/devsmart/plotter/AxisRenderer.java @@ -1,10 +1,28 @@ package com.devsmart.plotter; import android.graphics.Canvas; +import android.graphics.Rect; import android.graphics.RectF; public interface AxisRenderer { + /** + * Measure the area where the graph data will be drawn. Return a Rect + * in screen coordinates. + * @param screenWidth + * @param screenHeight + * @return + */ + Rect measureGraphArea(int screenWidth, int screenHeight); + + /** + * Draw the axis on the canvas. + * @param canvas + * @param canvasWidth + * @param canvasHeight + * @param viewport + * @return + */ void drawAxis(Canvas canvas, int canvasWidth, int canvasHeight, RectF viewport); } diff --git a/src/com/devsmart/plotter/CoordinateSystem.java b/src/com/devsmart/plotter/CoordinateSystem.java new file mode 100644 index 0000000..00a42d9 --- /dev/null +++ b/src/com/devsmart/plotter/CoordinateSystem.java @@ -0,0 +1,82 @@ +package com.devsmart.plotter; + +import android.graphics.RectF; + +public class CoordinateSystem { + + AxisFunction mXAxisFunction; + AxisFunction mYAxisFunction; + CoordinateSystem mInverse; + + + + public CoordinateSystem copy() { + CoordinateSystem retval = new CoordinateSystem(); + retval.mXAxisFunction = mXAxisFunction.copy(); + retval.mYAxisFunction = mYAxisFunction.copy(); + + return retval; + } + + public float xValue(float x) { + return mXAxisFunction.value(x); + } + + public float yValue(float y) { + return mYAxisFunction.value(y); + } + + public void mapRect(RectF dest, RectF src) { + dest.left = mXAxisFunction.value(src.left); + dest.right = mXAxisFunction.value(src.right); + dest.bottom = mYAxisFunction.value(src.bottom); + dest.top = mYAxisFunction.value(src.top); + } + + public void mapRect(RectF rect) { + rect.left = mXAxisFunction.value(rect.left); + rect.right = mXAxisFunction.value(rect.right); + rect.bottom = mYAxisFunction.value(rect.bottom); + rect.top = mYAxisFunction.value(rect.top); + + } + + public CoordinateSystem getInverse() { + if(mInverse == null){ + mInverse = new CoordinateSystem(); + mInverse.mXAxisFunction = mXAxisFunction.inverse(); + mInverse.mYAxisFunction = mYAxisFunction.inverse(); + } + return mInverse; + } + + void interpolate(RectF from, RectF to){ + mXAxisFunction.interpolate(new float[]{from.left, from.right}, new float[]{to.left, to.right}); + mYAxisFunction.interpolate(new float[]{from.top, from.bottom}, new float[]{to.top, to.bottom}); + } + + public static CoordinateSystem createLinearSystem() { + CoordinateSystem retval = new CoordinateSystem(); + retval.mXAxisFunction = new LinearFunction(); + retval.mYAxisFunction = new LinearFunction(); + + return retval; + } + + /** + * Apply this system to the array of 2D points, and write the transformed points back into the array + * @param pts + */ + public void mapPoints(float[] pts) { + for(int x=0;x mData; + private CoordinateSystem mCoordCopy; public BackgroundDrawTask(RectF view){ - this.width = getMeasuredWidth(); - this.height = getMeasuredHeight(); + this.viewport = new RectF(view); + if(mCoordinateSystem == null){ + mCanceled = true; + return; + } + + this.width = mGraphArea.width(); + this.height = mGraphArea.height(); + this.mCoordCopy = mCoordinateSystem.copy(); + this.mCoordCopy.interpolate(viewport, new RectF(0,0,width,height)); + + this.mData = new ArrayList(mPlotData); } @@ -255,7 +271,7 @@ public void onBackground() { mDrawBuffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444); Canvas c = new Canvas(mDrawBuffer); for(DataRenderer r : mData){ - r.draw(c, viewport); + r.draw(c, viewport, mCoordCopy); } } } @@ -331,179 +347,6 @@ public static double roundToSignificantFigures(double num, int n) { final double magnitude = Math.pow(10, power); final long shifted = Math.round(num*magnitude); return shifted/magnitude; - } - - protected void drawAxis2(Canvas canvas, RectF viewPort) { - Rect bounds = new Rect(); - DisplayMetrics metrics = getContext().getResources().getDisplayMetrics(); - float[] points; - - final int canvasWidth = canvas.getWidth(); - final int canvasHeight = canvas.getHeight(); - - Paint axisPaint = new Paint(); - axisPaint.setColor(mAxisColor); - axisPaint.setStrokeWidth(2); - - Matrix matrix = getViewportToScreenMatrix(new RectF(0,0,canvasWidth, canvasHeight), viewPort); - - if(mDrawXAxis){ - //draw X axis - points = new float[]{ - TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mPlotMargins.left, metrics), canvasHeight - TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mPlotMargins.bottom, metrics), - canvasWidth, canvasHeight - TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mPlotMargins.bottom, metrics) - }; - canvas.drawLines(points, axisPaint); - - float xPoint = (float) (mXAxisDevision * Math.floor(viewPort.left / mXAxisDevision)); - while(xPoint < viewPort.right+mXAxisDevision/2){ - points[0] = xPoint; - points[1] = 0; - points[2] = xPoint; - points[3] = 0; - matrix.mapPoints(points); - points[1] = canvasHeight - TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mPlotMargins.bottom, metrics); - points[3] = canvasHeight - TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mPlotMargins.bottom + 10, metrics); - canvas.drawLines(points, axisPaint); - - String label = String.valueOf(xPoint); - mAxisLabelPaint.getTextBounds(label, 0, label.length(), bounds); - - canvas.drawText(label, - points[0]-bounds.width()/2, - points[1] + bounds.height() + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, metrics), - mAxisLabelPaint); - - xPoint += mXAxisDevision; - - } - - - } - - if(mDrawYAxis){ - //draw Y axis - points = new float[]{ - TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mPlotMargins.left, metrics), 0, - TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mPlotMargins.left, metrics), canvasHeight - }; - canvas.drawLines(points, axisPaint); - - float yPoint = (float) (mYAxisDevision * Math.floor(viewPort.top / mYAxisDevision)); - while(yPoint < viewPort.bottom+mYAxisDevision/2){ - points[0] = 0; - points[1] = yPoint; - points[2] = 0; - points[3] = yPoint; - matrix.mapPoints(points); - points[0] = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mPlotMargins.left, metrics); - points[2] = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mPlotMargins.left + 10, metrics); - canvas.drawLines(points, axisPaint); - - String label = String.valueOf(yPoint); - mAxisLabelPaint.getTextBounds(label, 0, label.length(), bounds); - canvas.drawText(label, - points[0]-bounds.width()-TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, metrics), - points[1]+bounds.height()/2, - mAxisLabelPaint); - - yPoint += mYAxisDevision; - } - - } - - } - - protected void drawAxis(Canvas canvas, RectF viewPort) { - - Rect bounds = new Rect(); - DisplayMetrics metrics = getContext().getResources().getDisplayMetrics(); - float[] points; - - final int canvasWidth = canvas.getWidth(); - final int canvasHeight = canvas.getHeight(); - - Matrix matrix = getViewportToScreenMatrix(new RectF(0,0,canvasWidth, canvasHeight), viewPort); - - Paint axisPaint = new Paint(); - axisPaint.setColor(mAxisColor); - axisPaint.setStrokeWidth(2); - - if(mDrawXAxis){ - //draw X axis - points = new float[]{ - viewPort.left, 0, - viewPort.right, 0 - }; - matrix.mapPoints(points); - canvas.drawLines(points, axisPaint); - - float xPoint = (float) (mXAxisDevision * Math.floor(viewPort.left / mXAxisDevision)); - while(xPoint < viewPort.right+mXAxisDevision/2){ - if(xPoint != 0.0f){ - points[0] = xPoint; - points[1] = 0; - points[2] = xPoint; - points[3] = 0; - matrix.mapPoints(points); - points[1] -= TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, metrics); - points[3] += TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, metrics); - canvas.drawLines(points, axisPaint); - - String label = String.valueOf(xPoint); - mAxisLabelPaint.getTextBounds(label, 0, label.length(), bounds); - - canvas.drawText(label, - points[0]-bounds.width()/2, - points[1] + bounds.height() + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15, metrics), - mAxisLabelPaint); - - } - xPoint += mXAxisDevision; - - } - - - } - - - if(mDrawYAxis){ - //draw Y axis - points = new float[]{ - 0, viewPort.top, - 0, viewPort.bottom - }; - matrix.mapPoints(points); - canvas.drawLines(points, axisPaint); - - float yPoint = (float) (mYAxisDevision * Math.floor(viewPort.top / mYAxisDevision)); - while(yPoint < viewPort.bottom+mYAxisDevision/2){ - if(yPoint != 0.0f){ - points[0] = 0; - points[1] = yPoint; - points[2] = 0; - points[3] = yPoint; - matrix.mapPoints(points); - points[0] -= TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, metrics); - points[2] += TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, metrics); - canvas.drawLines(points, axisPaint); - - String label = String.valueOf(yPoint); - mAxisLabelPaint.getTextBounds(label, 0, label.length(), bounds); - float textWidth = mAxisLabelPaint.measureText(label); - canvas.drawText(label, - points[0]-textWidth-TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, metrics), - points[1]+bounds.height()/2, - mAxisLabelPaint); - } - yPoint += mYAxisDevision; - } - - } - - - - } public static RectF getSeriesLimits(Series series) { diff --git a/src/com/devsmart/plotter/LineGraphDataRenderer.java b/src/com/devsmart/plotter/LineGraphDataRenderer.java index 10a7cf9..d4eda37 100644 --- a/src/com/devsmart/plotter/LineGraphDataRenderer.java +++ b/src/com/devsmart/plotter/LineGraphDataRenderer.java @@ -19,14 +19,16 @@ public LineGraphDataRenderer(Series series, int color) { } + RectF pixel = new RectF(); + RectF pixelBin = new RectF(); + + public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem){ - public void draw(Canvas canvas, RectF viewPort){ - - Matrix matrix = GraphView.getViewportToScreenMatrix(new RectF(0,0,canvas.getWidth(), canvas.getHeight()), viewPort); - - RectF pixel = new RectF(); + try { + canvas.save(); + canvas.scale(1, -1); + canvas.translate(0, -canvas.getHeight()); - RectF pixelBin = new RectF(); final float xBinWidth = viewPort.width()/canvas.getWidth(); pixelBin.left = viewPort.left-xBinWidth; pixelBin.right = viewPort.left; @@ -47,7 +49,8 @@ public void draw(Canvas canvas, RectF viewPort){ break; } } - matrix.mapPoints(lastpoint); + + coordSystem.mapPoints(lastpoint); boolean findOneMore = false; while(it.hasNext()){ @@ -57,7 +60,7 @@ public void draw(Canvas canvas, RectF viewPort){ if(fillPixelBin(pixelBin, it)){ //draw pixel - matrix.mapRect(pixel, pixelBin); + coordSystem.mapRect(pixel, pixelBin); canvas.drawLine(lastpoint[0], lastpoint[1], pixel.left, pixel.top, mPointPaint); lastpoint[0] = pixel.left; lastpoint[1] = pixel.top; @@ -70,8 +73,9 @@ public void draw(Canvas canvas, RectF viewPort){ } } - - + } finally { + canvas.restore(); + } } private boolean fillPixelBin(RectF pixelBin, PeekableIterator it) { diff --git a/src/com/devsmart/plotter/LinearFunction.java b/src/com/devsmart/plotter/LinearFunction.java new file mode 100644 index 0000000..bc3e6ae --- /dev/null +++ b/src/com/devsmart/plotter/LinearFunction.java @@ -0,0 +1,42 @@ +package com.devsmart.plotter; + +public class LinearFunction implements AxisFunction { + + private float a = 1; + private float m = 0; + + public LinearFunction(){ + + } + + public LinearFunction(float a, float m) { + this.a = a; + this.m = m; + } + + @Override + public float value(float x) { + return a * x + m; + } + + @Override + public AxisFunction inverse() { + return new LinearFunction(1/a, -m/a); + } + + @Override + public void interpolate(float[] x, float[] y) { + float top = y[1]-y[0]; + float bottom = x[1]-x[0]; + + this.a = top / bottom; + this.m = -a*x[0]; + + } + + @Override + public AxisFunction copy() { + return new LinearFunction(a, m); + } + +} diff --git a/src/com/devsmart/plotter/SimpleAxisRenderer.java b/src/com/devsmart/plotter/SimpleAxisRenderer.java index db9eaee..c24cf09 100644 --- a/src/com/devsmart/plotter/SimpleAxisRenderer.java +++ b/src/com/devsmart/plotter/SimpleAxisRenderer.java @@ -43,6 +43,7 @@ public SimpleAxisRenderer(GraphView graphview) { float[] points = new float[4]; Rect bounds = new Rect(); RectF boundsf = new RectF(); + Rect graphArea = new Rect(); protected void calcBounds(final int canvasWidth, final int canvasHeight) { mAxisLabelPaint.getTextBounds("1", 0, 1, bounds); @@ -63,6 +64,8 @@ protected void calcBounds(final int canvasWidth, final int canvasHeight) { canvasWidth - mPlotMargins.right, canvasHeight - axisLabelBoundery - mPlotMargins.bottom}; } + + @Override public void drawAxis(Canvas canvas, final int canvasWidth, final int canvasHeight, RectF viewPort) { @@ -120,6 +123,9 @@ public void drawAxis(Canvas canvas, final int canvasWidth, final int canvasHeigh } if(mDrawYAxis){ + + + //draw Y axis canvas.drawLines(mYAxis, axisPaint); @@ -169,6 +175,19 @@ protected String getTickLabel(float value) { return String.valueOf(MathUtils.round(value, 1)); //return String.valueOf(value); } + + + + @Override + public Rect measureGraphArea(int screenWidth, int screenHeight) { + calcBounds(screenWidth, screenHeight); + + graphArea.left = (int) Math.floor(mXAxis[0]); + graphArea.right = (int) Math.ceil(mXAxis[2]); + graphArea.top = (int) Math.floor(mYAxis[1]); + graphArea.bottom = (int) Math.ceil(mYAxis[3]); + return graphArea; + } From 2c3a3c93b4641fa8e81242e6767bdd0b0d01fd76 Mon Sep 17 00:00:00 2001 From: paul Date: Thu, 21 Nov 2013 11:00:44 -0500 Subject: [PATCH 03/44] working good maybe ready for merge --- src/com/devsmart/plotter/AxisRenderer.java | 2 +- src/com/devsmart/plotter/GraphView.java | 31 ++++++++-------- .../devsmart/plotter/SimpleAxisRenderer.java | 35 ++++++++++--------- 3 files changed, 35 insertions(+), 33 deletions(-) diff --git a/src/com/devsmart/plotter/AxisRenderer.java b/src/com/devsmart/plotter/AxisRenderer.java index 83579d0..ff327a1 100644 --- a/src/com/devsmart/plotter/AxisRenderer.java +++ b/src/com/devsmart/plotter/AxisRenderer.java @@ -23,6 +23,6 @@ public interface AxisRenderer { * @param viewport * @return */ - void drawAxis(Canvas canvas, int canvasWidth, int canvasHeight, RectF viewport); + void drawAxis(Canvas canvas, int canvasWidth, int canvasHeight, RectF viewport, CoordinateSystem coordSystem); } diff --git a/src/com/devsmart/plotter/GraphView.java b/src/com/devsmart/plotter/GraphView.java index a0b3cc2..1939184 100644 --- a/src/com/devsmart/plotter/GraphView.java +++ b/src/com/devsmart/plotter/GraphView.java @@ -158,20 +158,7 @@ public void removeSeries(DataRenderer series) { drawFrame(mViewPort); } - public static Matrix getViewportToScreenMatrix( - RectF screen, - RectF viewPort){ - Matrix matrix = new Matrix(); - matrix.setRectToRect(viewPort, - screen, - ScaleToFit.FILL); - - matrix.postScale(1, -1); - matrix.postTranslate(0, screen.height()); - - return matrix; - } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { @@ -206,10 +193,12 @@ protected void updateViewport(){ } public RectF getDisplayViewPort(){ - RectF rect = new RectF(mGraphArea); + RectF rect = new RectF(0,0,mGraphArea.width(), mGraphArea.height()); Matrix m = new Matrix(); mTransformMatrix.invert(m); + m.postScale(1, -1); + m.postTranslate(0, mGraphArea.height()); m.mapRect(rect); mCoordinateSystem.getInverse().mapRect(rect); @@ -217,6 +206,12 @@ public RectF getDisplayViewPort(){ return rect; } + public CoordinateSystem getCoordinateSystem() { + CoordinateSystem retval = mCoordinateSystem.copy(); + retval.interpolate(getDisplayViewPort(), new RectF(0,0,mGraphArea.width(),mGraphArea.height())); + return retval; + } + public void setDisplayViewPort(RectF viewport) { drawFrame(viewport); } @@ -225,9 +220,12 @@ public void setDisplayViewPort(RectF viewport) { protected void onDraw(Canvas canvas) { if(mFrontBuffer != null){ + canvas.save(); + canvas.translate(mGraphArea.left, mGraphArea.top); canvas.drawBitmap(mFrontBuffer, mTransformMatrix, mDrawPaint); + canvas.restore(); } - mAxisRenderer.drawAxis(canvas, getMeasuredWidth(), getMeasuredHeight(), mViewPort); + mAxisRenderer.drawAxis(canvas, getMeasuredWidth(), getMeasuredHeight(), getDisplayViewPort(), getCoordinateSystem()); } private void drawFrame(final RectF viewport) { @@ -251,7 +249,7 @@ private class BackgroundDrawTask extends BackgroundTask { public BackgroundDrawTask(RectF view){ this.viewport = new RectF(view); - if(mCoordinateSystem == null){ + if(mCoordinateSystem == null || mGraphArea == null){ mCanceled = true; return; } @@ -282,6 +280,7 @@ public void onAfter() { mFrontBuffer = mDrawBuffer; mViewPort = viewport; mTransformMatrix.reset(); + mCoordinateSystem = mCoordCopy; invalidate(); } else if(mDrawBuffer != null) { mDrawBuffer.recycle(); diff --git a/src/com/devsmart/plotter/SimpleAxisRenderer.java b/src/com/devsmart/plotter/SimpleAxisRenderer.java index c24cf09..6333c87 100644 --- a/src/com/devsmart/plotter/SimpleAxisRenderer.java +++ b/src/com/devsmart/plotter/SimpleAxisRenderer.java @@ -6,6 +6,7 @@ import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; +import android.graphics.Matrix.ScaleToFit; import android.util.DisplayMetrics; import android.util.TypedValue; @@ -65,24 +66,24 @@ protected void calcBounds(final int canvasWidth, final int canvasHeight) { } + Matrix m = new Matrix(); @Override - public void drawAxis(Canvas canvas, final int canvasWidth, final int canvasHeight, RectF viewPort) { + public void drawAxis(Canvas canvas, final int canvasWidth, final int canvasHeight, RectF viewPort, CoordinateSystem coordSystem) { - calcBounds(canvasWidth, canvasHeight); + measureGraphArea(canvasWidth, canvasHeight); - Paint axisPaint = new Paint(); - axisPaint.setColor(mAxisColor); - axisPaint.setStrokeWidth(2); - - boundsf.set(0,0,canvasWidth, canvasHeight); - Matrix matrix = GraphView.getViewportToScreenMatrix(boundsf, viewPort); + m.setRectToRect(new RectF(0,0,graphArea.width(),graphArea.height()), new RectF(graphArea), ScaleToFit.FILL); + m.postScale(1, -1); + m.postTranslate(0, graphArea.height()); + //Debug axis display + //canvas.drawText(viewPort.toString(), 50, 50, mAxisTickPaint); if(mDrawXAxis) { //draw axis - canvas.drawLines(mXAxis, axisPaint); + canvas.drawLines(mXAxis, mAxisTickPaint); //draw label mAxisLabelPaint.getTextBounds(mXAxisLabel, 0, mXAxisLabel.length(), bounds); @@ -97,12 +98,13 @@ public void drawAxis(Canvas canvas, final int canvasWidth, final int canvasHeigh points[1] = 0; points[2] = xPoint; points[3] = 0; - matrix.mapPoints(points); + coordSystem.mapPoints(points); + m.mapPoints(points); points[1] = mXAxis[1]; points[3] = mXAxis[1] - TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, mDisplayMetrics); if(points[0] >= mXAxis[0]) { - canvas.drawLines(points, axisPaint); + canvas.drawLines(points, mAxisTickPaint); String label = getTickLabel(xPoint); mAxisTickPaint.getTextBounds(label, 0, label.length(), bounds); @@ -127,7 +129,7 @@ public void drawAxis(Canvas canvas, final int canvasWidth, final int canvasHeigh //draw Y axis - canvas.drawLines(mYAxis, axisPaint); + canvas.drawLines(mYAxis, mAxisTickPaint); //draw label mAxisLabelPaint.getTextBounds(mYAxisLabel, 0, mYAxisLabel.length(), bounds); @@ -145,12 +147,13 @@ public void drawAxis(Canvas canvas, final int canvasWidth, final int canvasHeigh points[1] = yPoint; points[2] = 0; points[3] = yPoint; - matrix.mapPoints(points); + coordSystem.mapPoints(points); + m.mapPoints(points); points[0] = mYAxis[0]; points[2] = mYAxis[0] + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, mDisplayMetrics); if(points[1] <= mYAxis[3]) { - canvas.drawLines(points, axisPaint); + canvas.drawLines(points, mAxisTickPaint); String label = getTickLabel(yPoint); mAxisTickPaint.getTextBounds(label, 0, label.length(), bounds); @@ -172,8 +175,8 @@ public void drawAxis(Canvas canvas, final int canvasWidth, final int canvasHeigh } protected String getTickLabel(float value) { - return String.valueOf(MathUtils.round(value, 1)); - //return String.valueOf(value); + return String.format("%3.1f", value); + //return String.valueOf(MathUtils.round(value, 1)); } From 13adf945de9ecae7a0310cfb4e36aaba2224b5ea Mon Sep 17 00:00:00 2001 From: paul Date: Fri, 22 Nov 2013 16:47:37 -0500 Subject: [PATCH 04/44] added continous function plotting --- .../devsmart/plotter/CoordinateSystem.java | 43 +++++++++++------ .../devsmart/plotter/FunctionRenderer.java | 47 +++++++++++++++++++ src/com/devsmart/plotter/GraphView.java | 17 ++++++- .../plotter/LineGraphDataRenderer.java | 8 +--- 4 files changed, 91 insertions(+), 24 deletions(-) create mode 100644 src/com/devsmart/plotter/FunctionRenderer.java diff --git a/src/com/devsmart/plotter/CoordinateSystem.java b/src/com/devsmart/plotter/CoordinateSystem.java index 00a42d9..7d96f87 100644 --- a/src/com/devsmart/plotter/CoordinateSystem.java +++ b/src/com/devsmart/plotter/CoordinateSystem.java @@ -41,6 +41,34 @@ public void mapRect(RectF rect) { } + /** + * Apply this system to the array of 2D points, and write the transformed points back into the array + * @param pts + */ + public void mapPoints(float[] pts) { + mapPoints(pts, pts); + /* + for(int x=0;x it) { From ac3e52feeadd1caceb5f6d43cdf6d3f57cbb8976 Mon Sep 17 00:00:00 2001 From: paul Date: Thu, 5 Dec 2013 12:11:14 -0500 Subject: [PATCH 05/44] fixed some crashing bugs --- src/com/devsmart/plotter/GraphView.java | 1 + src/com/devsmart/plotter/LineGraphDataRenderer.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/com/devsmart/plotter/GraphView.java b/src/com/devsmart/plotter/GraphView.java index afdaa80..b30908e 100644 --- a/src/com/devsmart/plotter/GraphView.java +++ b/src/com/devsmart/plotter/GraphView.java @@ -298,6 +298,7 @@ public void onAfter() { } else if(mDrawBuffer != null) { mDrawBuffer.recycle(); } + mDrawBuffer = null; } diff --git a/src/com/devsmart/plotter/LineGraphDataRenderer.java b/src/com/devsmart/plotter/LineGraphDataRenderer.java index 85a96e9..ccfda41 100644 --- a/src/com/devsmart/plotter/LineGraphDataRenderer.java +++ b/src/com/devsmart/plotter/LineGraphDataRenderer.java @@ -64,7 +64,7 @@ public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem){ break; } } - if(it.peek()[0] > viewPort.right){ + if(it.peek() != null && it.peek()[0] > viewPort.right){ findOneMore = true; } From 30efa3f2b7819e3b319358f7fd3976f1df3e0082 Mon Sep 17 00:00:00 2001 From: paul Date: Wed, 11 Dec 2013 16:55:02 -0500 Subject: [PATCH 06/44] fixing gradle build --- build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 63b01c1..ce1b924 100644 --- a/build.gradle +++ b/build.gradle @@ -16,7 +16,8 @@ repositories { } dependencies { - compile fileTree(dir: 'libs', include: '*.jar') + //compile fileTree(dir: 'libs', include: '*.jar') + compile 'com.android.support:support-v4:19.0.0' compile project(':AndroidEssentials') } From e4d0f678c2d5ea60e232d460530409b8395e6060 Mon Sep 17 00:00:00 2001 From: paul Date: Fri, 20 Dec 2013 13:18:50 -0500 Subject: [PATCH 07/44] added external render capability --- src/com/devsmart/plotter/GraphView.java | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/com/devsmart/plotter/GraphView.java b/src/com/devsmart/plotter/GraphView.java index b30908e..8047688 100644 --- a/src/com/devsmart/plotter/GraphView.java +++ b/src/com/devsmart/plotter/GraphView.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; +import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -239,6 +240,30 @@ private void drawFrame(final RectF viewport) { BackgroundTask.runBackgroundTask(mBackgroundDrawTask, mDrawThread); } + public static Bitmap drawBitmap(int width, int height, List data, + RectF viewport, + CoordinateSystem coordinateSystem) { + + CoordinateSystem mCoordCopy = coordinateSystem.copy(); + mCoordCopy.interpolate(viewport, new RectF(0,0,width,height)); + + Bitmap drawBuffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444); + Canvas c = new Canvas(drawBuffer); + + try { + c.save(); + c.scale(1, -1); + c.translate(0, -c.getHeight()); + + for(DataRenderer r : data){ + r.draw(c, viewport, mCoordCopy); + } + }finally { + c.restore(); + } + return drawBuffer; + } + private class BackgroundDrawTask extends BackgroundTask { private int width; From ebd61d451c7b2f58910ab602181bf047efd6fe9b Mon Sep 17 00:00:00 2001 From: paul Date: Mon, 23 Dec 2013 12:36:47 -0500 Subject: [PATCH 08/44] added auto bounds stuff --- src/com/devsmart/plotter/GraphView.java | 83 ++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 2 deletions(-) diff --git a/src/com/devsmart/plotter/GraphView.java b/src/com/devsmart/plotter/GraphView.java index 8047688..126040c 100644 --- a/src/com/devsmart/plotter/GraphView.java +++ b/src/com/devsmart/plotter/GraphView.java @@ -17,6 +17,8 @@ import android.graphics.Rect; import android.graphics.RectF; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.os.Parcelable; import android.support.v4.view.MotionEventCompat; import android.util.AttributeSet; @@ -25,6 +27,8 @@ import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.Interpolator; import android.widget.ZoomButtonsController; import com.devsmart.BackgroundTask; @@ -69,6 +73,7 @@ public static enum Axis { private ZoomButtonsController mZoomControls; private Rect mGraphArea; + private RectF mViewPortBounds; public GraphView(Context context) { super(context); @@ -174,12 +179,14 @@ protected void onSizeChanged(int w, int h, int oldw, int oldh) { @Override public boolean onTouchEvent(MotionEvent event) { + cancelAnimation(); mZoomControls.setVisible(true); final int action = MotionEventCompat.getActionMasked(event); switch(action){ case MotionEvent.ACTION_UP: - updateViewport(); + doBoundsCheck(); + //updateViewport(); break; } @@ -193,6 +200,68 @@ protected void updateViewport(){ drawFrame(newViewport); } + private Interpolator mAnimationInterpolator = null; + private long mAnimationEndTime = 0; + private static final long mAnimationTime = 1000; + private RectF mAnimationDest; + private void doAnimation() { + if(mAnimationInterpolator != null) { + long now = System.currentTimeMillis(); + if(mAnimationEndTime <= now) { + mAnimationInterpolator = null; + drawFrame(mAnimationDest); + return; + } + float done = 1 - ((float)(mAnimationEndTime - now) / mAnimationTime); + done = mAnimationInterpolator.getInterpolation(done); + RectF newViewport = new RectF(); + RectF currentViewport = getDisplayViewPort(); + newViewport.left = (1-done)*currentViewport.left + done*mAnimationDest.left; + newViewport.right = (1-done)*currentViewport.right + done*mAnimationDest.right; + newViewport.top = (1-done)*currentViewport.top + done*mAnimationDest.top; + newViewport.bottom = (1-done)*currentViewport.bottom + done*mAnimationDest.bottom; + drawFrame(newViewport); + } + } + private void cancelAnimation() { + mAnimationInterpolator = null; + } + + public void setViewportBounds(RectF bounds) { + mViewPortBounds = bounds; + } + + public void doBoundsCheck() { + if(mViewPortBounds != null) { + RectF newViewport = getDisplayViewPort(); + if(newViewport.width() > mViewPortBounds.width()){ + newViewport.left = mViewPortBounds.left; + newViewport.right = mViewPortBounds.right; + } + if(newViewport.height() > mViewPortBounds.height()){ + newViewport.top = mViewPortBounds.top; + newViewport.bottom = mViewPortBounds.bottom; + } + if(newViewport.left < mViewPortBounds.left) { + newViewport.offset(mViewPortBounds.left - newViewport.left, 0); + } + if(newViewport.right > mViewPortBounds.right) { + newViewport.offset(mViewPortBounds.right - newViewport.right, 0); + } + if(newViewport.bottom > mViewPortBounds.bottom) { + newViewport.offset(0, mViewPortBounds.bottom - newViewport.bottom); + } + if(newViewport.top < mViewPortBounds.top) { + newViewport.offset(0, mViewPortBounds.top - newViewport.top); + } + + mAnimationInterpolator = new DecelerateInterpolator(); + mAnimationEndTime = System.currentTimeMillis() + mAnimationTime; + mAnimationDest = newViewport; + invalidate(); + } + } + public RectF getDisplayViewPort(){ RectF rect = new RectF(0,0,mGraphArea.width(), mGraphArea.height()); @@ -222,7 +291,7 @@ public void setDisplayViewPort(RectF viewport) { @Override protected void onDraw(Canvas canvas) { - + doAnimation(); if(mFrontBuffer != null){ canvas.save(); canvas.translate(mGraphArea.left, mGraphArea.top); @@ -446,6 +515,7 @@ public void onAfter() { } public void zoomInCenter() { + cancelAnimation(); float scale = 1.3f; mTransformMatrix.postScale(scale, scale, getMeasuredWidth()/2, getMeasuredHeight()/2); invalidate(); @@ -453,10 +523,19 @@ public void zoomInCenter() { } public void zoomOutCenter() { + cancelAnimation(); float scale = 0.7f; mTransformMatrix.postScale(scale, scale, getMeasuredWidth()/2, getMeasuredHeight()/2); invalidate(); updateViewport(); + new Handler(Looper.getMainLooper()).postDelayed(new Runnable(){ + + @Override + public void run() { + doBoundsCheck(); + } + }, 1000); + } private ZoomButtonsController.OnZoomListener mZoomButtonListener = new ZoomButtonsController.OnZoomListener(){ From 9009b47ba7c6b77e1d04cc6db39f1189314598d9 Mon Sep 17 00:00:00 2001 From: paul Date: Fri, 27 Dec 2013 13:30:33 -0500 Subject: [PATCH 09/44] upgrade gradle android build to 0.7.3 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ce1b924..f1f4f3e 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:0.6.3' + classpath 'com.android.tools.build:gradle:0.7.3' } } From ee593d6b9a3215a3ce997f759fc757703b07f42a Mon Sep 17 00:00:00 2001 From: paul Date: Fri, 27 Dec 2013 16:41:38 -0500 Subject: [PATCH 10/44] removed .iml --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d6201ac..c32f129 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ build/ .project .classpath .settings/ +*.iml From ffaa40c8e74396c667a9aecd58f6cbd8d37a75e3 Mon Sep 17 00:00:00 2001 From: sean Date: Tue, 25 Feb 2014 09:37:49 -0500 Subject: [PATCH 11/44] plotter --- res/values/attrs.xml | 8 ++ src/com/devsmart/plotter/GraphView.java | 84 ++++++++++++------- .../devsmart/plotter/SimpleAxisRenderer.java | 19 ++++- 3 files changed, 76 insertions(+), 35 deletions(-) create mode 100644 res/values/attrs.xml diff --git a/res/values/attrs.xml b/res/values/attrs.xml new file mode 100644 index 0000000..4ed2628 --- /dev/null +++ b/res/values/attrs.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/com/devsmart/plotter/GraphView.java b/src/com/devsmart/plotter/GraphView.java index 126040c..9654571 100644 --- a/src/com/devsmart/plotter/GraphView.java +++ b/src/com/devsmart/plotter/GraphView.java @@ -1,18 +1,11 @@ package com.devsmart.plotter; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - import android.content.Context; +import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; -import android.graphics.Matrix.ScaleToFit; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; @@ -22,8 +15,6 @@ import android.os.Parcelable; import android.support.v4.view.MotionEventCompat; import android.util.AttributeSet; -import android.util.DisplayMetrics; -import android.util.TypedValue; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; @@ -33,6 +24,13 @@ import com.devsmart.BackgroundTask; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + public class GraphView extends View { public static enum Axis { @@ -82,34 +80,58 @@ public GraphView(Context context) { public GraphView(Context context, AttributeSet attrs) { super(context, attrs); - init(); + TypedArray a = context.getTheme().obtainStyledAttributes( + attrs, + R.styleable.GraphView, + 0, 0); + + int axisColor; + int labelColor; + try { + axisColor = a.getInteger(R.styleable.GraphView_axisColor, Color.BLACK); + labelColor = a.getInteger(R.styleable.GraphView_axisColor, Color.DKGRAY); + } finally { + a.recycle(); + } + + init(axisColor,labelColor); } private void init() { mAxisRenderer = new SimpleAxisRenderer(this); - mPanGestureDetector = new GestureDetector(mSimpleGestureListener); - mScaleGestureDetector = new XYScaleGestureDetector(getContext(), mSimpleScaleGestureListener); - mDrawPaint.setFilterBitmap(true); - mViewPort.set(0, 0, 1, 1); - mTransformMatrix.reset(); + setUp(); - //defaults - mDrawXAxis = true; - mXAxisDevision = 1.0f; - mDrawYAxis = true; - mYAxisDevision = 1.0f; - mPlotMargins.set(20, 0, 0, 20); - mAxisColor = Color.DKGRAY; - mAxisLabelPaint.setColor(Color.DKGRAY); - mAxisLabelPaint.setTextSize(15.0f); - mAxisLabelPaint.setAntiAlias(true); - mBackgroundColor = Color.WHITE; - - mZoomControls = new ZoomButtonsController(this); - mZoomControls.setAutoDismissed(true); - mZoomControls.setOnZoomListener(mZoomButtonListener); } + private void init(int axisColor,int labelColor) { + mAxisRenderer = new SimpleAxisRenderer(this,axisColor,labelColor); + setUp(); + + + } + private void setUp(){ + mPanGestureDetector = new GestureDetector(mSimpleGestureListener); + mScaleGestureDetector = new XYScaleGestureDetector(getContext(), mSimpleScaleGestureListener); + mDrawPaint.setFilterBitmap(true); + mViewPort.set(0, 0, 1, 1); + mTransformMatrix.reset(); + + //defaults + mDrawXAxis = true; + mXAxisDevision = 1.0f; + mDrawYAxis = true; + mYAxisDevision = 1.0f; + mPlotMargins.set(20, 0, 0, 20); + mAxisColor = Color.DKGRAY; + mAxisLabelPaint.setColor(Color.DKGRAY); + mAxisLabelPaint.setTextSize(15.0f); + mAxisLabelPaint.setAntiAlias(true); + mBackgroundColor = Color.WHITE; + + mZoomControls = new ZoomButtonsController(this); + mZoomControls.setAutoDismissed(true); + mZoomControls.setOnZoomListener(mZoomButtonListener); + } diff --git a/src/com/devsmart/plotter/SimpleAxisRenderer.java b/src/com/devsmart/plotter/SimpleAxisRenderer.java index 6333c87..4ac69f9 100644 --- a/src/com/devsmart/plotter/SimpleAxisRenderer.java +++ b/src/com/devsmart/plotter/SimpleAxisRenderer.java @@ -3,15 +3,13 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; +import android.graphics.Matrix.ScaleToFit; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; -import android.graphics.Matrix.ScaleToFit; import android.util.DisplayMetrics; import android.util.TypedValue; -import com.devsmart.MathUtils; - public class SimpleAxisRenderer implements AxisRenderer { int numDivisions = 5; @@ -25,7 +23,20 @@ public class SimpleAxisRenderer implements AxisRenderer { String mYAxisLabel = "Intensity"; DisplayMetrics mDisplayMetrics; - + + public SimpleAxisRenderer(GraphView graphview,int axisColor, int lableColor) { + mDisplayMetrics = graphview.getContext().getResources().getDisplayMetrics(); + + mAxisLabelPaint.setColor(axisColor/*Color.BLACK*/); + mAxisLabelPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 15, mDisplayMetrics)); + mAxisLabelPaint.setAntiAlias(true); + + mAxisTickPaint.setColor(lableColor/*Color.DKGRAY*/); + mAxisTickPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 10, mDisplayMetrics)); + mAxisTickPaint.setAntiAlias(true); + + } + public SimpleAxisRenderer(GraphView graphview) { mDisplayMetrics = graphview.getContext().getResources().getDisplayMetrics(); From b4051b39e62f835bdeb9871a0f1e01e022779305 Mon Sep 17 00:00:00 2001 From: sean Date: Tue, 25 Feb 2014 16:04:55 -0500 Subject: [PATCH 12/44] fixing plotter --- src/com/devsmart/plotter/GraphView.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/com/devsmart/plotter/GraphView.java b/src/com/devsmart/plotter/GraphView.java index 9654571..6aa54d1 100644 --- a/src/com/devsmart/plotter/GraphView.java +++ b/src/com/devsmart/plotter/GraphView.java @@ -90,11 +90,14 @@ public GraphView(Context context, AttributeSet attrs) { try { axisColor = a.getInteger(R.styleable.GraphView_axisColor, Color.BLACK); labelColor = a.getInteger(R.styleable.GraphView_axisColor, Color.DKGRAY); - } finally { + init(axisColor,labelColor); + }catch (Exception e){ + init(); + }finally { a.recycle(); } - init(axisColor,labelColor); + } private void init() { From f0c0830674c55c92627cb3868e518ec89ad6b333 Mon Sep 17 00:00:00 2001 From: Brian Bower Date: Thu, 27 Feb 2014 12:36:51 -0500 Subject: [PATCH 13/44] Fixed build.gradle to use verrsion 0.8.+ --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f1f4f3e..89b9474 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:0.7.3' + classpath 'com.android.tools.build:gradle:0.8.+' } } From 6bc5d7f530591a56ee53215a8e29ffcd60d234ad Mon Sep 17 00:00:00 2001 From: paul Date: Sat, 1 Mar 2014 16:25:31 -0500 Subject: [PATCH 14/44] remove zoom controls --- src/com/devsmart/plotter/GraphView.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/com/devsmart/plotter/GraphView.java b/src/com/devsmart/plotter/GraphView.java index 6aa54d1..5799e32 100644 --- a/src/com/devsmart/plotter/GraphView.java +++ b/src/com/devsmart/plotter/GraphView.java @@ -69,7 +69,7 @@ public static enum Axis { protected AxisRenderer mAxisRenderer; - private ZoomButtonsController mZoomControls; + //private ZoomButtonsController mZoomControls; private Rect mGraphArea; private RectF mViewPortBounds; @@ -131,9 +131,9 @@ private void setUp(){ mAxisLabelPaint.setAntiAlias(true); mBackgroundColor = Color.WHITE; - mZoomControls = new ZoomButtonsController(this); - mZoomControls.setAutoDismissed(true); - mZoomControls.setOnZoomListener(mZoomButtonListener); + //mZoomControls = new ZoomButtonsController(this); + //mZoomControls.setAutoDismissed(true); + //mZoomControls.setOnZoomListener(mZoomButtonListener); } @@ -168,14 +168,14 @@ protected void onRestoreInstanceState (Parcelable state) { @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - mZoomControls.setVisible(false); + //mZoomControls.setVisible(false); } @Override protected void onVisibilityChanged(View changedView, int visibility) { super.onVisibilityChanged(changedView, visibility); if(visibility != View.VISIBLE){ - mZoomControls.setVisible(false); + //mZoomControls.setVisible(false); } } @@ -205,7 +205,7 @@ protected void onSizeChanged(int w, int h, int oldw, int oldh) { public boolean onTouchEvent(MotionEvent event) { cancelAnimation(); - mZoomControls.setVisible(true); + //mZoomControls.setVisible(true); final int action = MotionEventCompat.getActionMasked(event); switch(action){ From 4fb1f7e91b04903ca47827fd1a7f4d18195cd955 Mon Sep 17 00:00:00 2001 From: paul Date: Mon, 10 Mar 2014 11:49:39 -0400 Subject: [PATCH 15/44] cruft --- .../devsmart/plotter/FunctionRenderer.java | 82 ++++++++++++++----- 1 file changed, 61 insertions(+), 21 deletions(-) diff --git a/src/com/devsmart/plotter/FunctionRenderer.java b/src/com/devsmart/plotter/FunctionRenderer.java index fe49ed8..7ffbd88 100644 --- a/src/com/devsmart/plotter/FunctionRenderer.java +++ b/src/com/devsmart/plotter/FunctionRenderer.java @@ -2,45 +2,85 @@ import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.RectF; public class FunctionRenderer implements DataRenderer { - - public interface GraphFunction { - float value(float x); + + public interface GraphFunction { + double value(double x); } private GraphFunction mFunction; + private final double mSampleRate; protected Paint mPointPaint = new Paint(); - public FunctionRenderer(GraphFunction f, int color) { + public FunctionRenderer(GraphFunction f, double samplerate, int color) { mFunction = f; + mSampleRate = samplerate; mPointPaint.setColor(color); mPointPaint.setStrokeWidth(2.0f); + mPointPaint.setAntiAlias(true); } float[] points = new float[4]; float[] drawPoints = new float[4]; + double[] yMinMax = new double[2]; @Override public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { - - final float xDiff = viewPort.width() / (float)canvas.getWidth(); - - points[0] = viewPort.left; - points[1] = mFunction.value(viewPort.left); - - for(float x=viewPort.left+xDiff;x<=viewPort.right;x = x + xDiff){ - - points[2] = x; - points[3] = mFunction.value(x); - - coordSystem.mapPoints(drawPoints, points); - canvas.drawLines(drawPoints, mPointPaint); - - points[0] = points[2]; - points[1] = points[3]; - } + + //reset min max + yMinMax[0] = Double.MAX_VALUE; + yMinMax[1] = Double.MIN_VALUE; + + final double pixelWidth = viewPort.width() / (double)canvas.getWidth(); + double startPix = viewPort.left; + Path p = new Path(); + p.moveTo(0, 0); + + points[0] = viewPort.left; + points[1] = (float)mFunction.value(viewPort.left); + coordSystem.mapPoints(points); + p.lineTo(points[0], points[1]); + + for(double x=viewPort.left;x= startPix+pixelWidth){ + + //min + points[0] = (float) startPix; + points[1] = (float) yMinMax[0]; + + //max + points[2] = (float) startPix; + points[3] = (float) yMinMax[1]; + + coordSystem.mapPoints(points); + p.lineTo(points[0], points[1]); + p.lineTo(points[2], points[3]); + + //reset min max + yMinMax[0] = Double.MAX_VALUE; + yMinMax[1] = Double.MIN_VALUE; + + startPix = x; + } + } + + points[0] = viewPort.right; + points[1] = (float)mFunction.value(viewPort.right); + coordSystem.mapPoints(points); + p.lineTo(points[0], points[1]); + + p.lineTo(canvas.getWidth(), 0); + + p.close(); + + canvas.drawPath(p, mPointPaint); } From da7e8b38d98bb91c3b221f9e826a627705629b3b Mon Sep 17 00:00:00 2001 From: paul Date: Tue, 11 Mar 2014 12:08:57 -0400 Subject: [PATCH 16/44] exermental stuff --- .../devsmart/plotter/FunctionRenderer.java | 155 +++++++++++++++++- .../devsmart/plotter/SimpleAxisRenderer.java | 2 + 2 files changed, 148 insertions(+), 9 deletions(-) diff --git a/src/com/devsmart/plotter/FunctionRenderer.java b/src/com/devsmart/plotter/FunctionRenderer.java index 7ffbd88..8f437b0 100644 --- a/src/com/devsmart/plotter/FunctionRenderer.java +++ b/src/com/devsmart/plotter/FunctionRenderer.java @@ -1,6 +1,7 @@ package com.devsmart.plotter; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.RectF; @@ -8,12 +9,21 @@ public class FunctionRenderer implements DataRenderer { public interface GraphFunction { - double value(double x); - } + double value(double x); + } + private double[] mSampleLocations; private GraphFunction mFunction; - private final double mSampleRate; + private double mSampleRate = 2; protected Paint mPointPaint = new Paint(); + + public FunctionRenderer(GraphFunction f, double[] sampleLocations, int color) { + mFunction = f; + mSampleLocations = sampleLocations; + mPointPaint.setColor(color); + mPointPaint.setStrokeWidth(2.0f); + mPointPaint.setAntiAlias(true); + } public FunctionRenderer(GraphFunction f, double samplerate, int color) { mFunction = f; @@ -23,19 +33,20 @@ public FunctionRenderer(GraphFunction f, double samplerate, int color) { mPointPaint.setAntiAlias(true); } - float[] points = new float[4]; + + float[] points = new float[6]; float[] drawPoints = new float[4]; + float[] lastPoint = new float[2]; double[] yMinMax = new double[2]; - - @Override - public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { + private void drawFixedSample(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { //reset min max yMinMax[0] = Double.MAX_VALUE; yMinMax[1] = Double.MIN_VALUE; final double pixelWidth = viewPort.width() / (double)canvas.getWidth(); - double startPix = viewPort.left; + final double stepWidth = Math.min(pixelWidth, 1.0/mSampleRate); + Path p = new Path(); p.moveTo(0, 0); @@ -44,7 +55,8 @@ public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { coordSystem.mapPoints(points); p.lineTo(points[0], points[1]); - for(double x=viewPort.left;x= viewPort.left){ + sampleindex = i; + if(i>0){ + sampleindex = i-1; + } + break; + } + } + + //reset min max + yMinMax[0] = Double.MAX_VALUE; + yMinMax[1] = Double.MIN_VALUE; + MinMax xminmax = new MinMax(); + MinMax yminmax = new MinMax(); + + final double pixelWidth = viewPort.width() / (double)canvas.getWidth(); + + Path p = new Path(); + + points[0] = viewPort.left; + points[1] = (float)mFunction.value(viewPort.left); + xminmax.add(points[0]); + yminmax.add(points[1]); + + coordSystem.mapPoints(points); + p.moveTo(points[0], points[1]); + lastPoint[0] = points[0]; + lastPoint[1] = points[1]; + + double startPix = mSampleLocations[sampleindex]; + double x = 0; + while(true){ + if(sampleindex >= mSampleLocations.length || (x=mSampleLocations[sampleindex++]) > viewPort.right){ + break; + } + final double y = mFunction.value(x); + yMinMax[0] = Math.min(yMinMax[0], y); + yMinMax[1] = Math.max(yMinMax[1], y); + + if(x >= startPix+pixelWidth){ + + //min + points[0] = (float) startPix; + points[1] = (float) yMinMax[0]; + + //max + points[2] = (float) startPix; + points[3] = (float) yMinMax[1]; + + xminmax.add(points[0]); + yminmax.add(points[1]); + xminmax.add(points[2]); + yminmax.add(points[3]); + + coordSystem.mapPoints(points); + + p.quadTo((lastPoint[0]+points[0])/2, coordSystem.yValue((lastPoint[0]+points[0])/2), points[0], points[1]); + lastPoint[0] = points[0]; + lastPoint[1] = points[1]; + + p.quadTo((lastPoint[0]+points[2])/2, coordSystem.yValue((lastPoint[0]+points[2])/2), points[2], points[3]); + lastPoint[0] = points[2]; + lastPoint[1] = points[3]; + + //reset min max + yMinMax[0] = Double.MAX_VALUE; + yMinMax[1] = Double.MIN_VALUE; + + startPix = x; + } + } + + points[0] = viewPort.right; + points[1] = (float)mFunction.value(viewPort.right); + xminmax.add(points[0]); + yminmax.add(points[1]); + coordSystem.mapPoints(points); + p.quadTo((lastPoint[0] + points[0]) / 2, (lastPoint[1] + points[1]) / 2, points[0], points[1]); + + + //p.lineTo(xminmax.max, yminmax.min); + //p.lineTo(xminmax.min, yminmax.min); + + + p.close(); + + canvas.drawPath(p, mPointPaint); + } + + @Override + public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { + if(mSampleLocations == null) { + drawFixedSample(canvas, viewPort, coordSystem); + } else { + drawAtSampleLocations(canvas, viewPort, coordSystem); + } + } + + } diff --git a/src/com/devsmart/plotter/SimpleAxisRenderer.java b/src/com/devsmart/plotter/SimpleAxisRenderer.java index 4ac69f9..478f4ce 100644 --- a/src/com/devsmart/plotter/SimpleAxisRenderer.java +++ b/src/com/devsmart/plotter/SimpleAxisRenderer.java @@ -10,6 +10,8 @@ import android.util.DisplayMetrics; import android.util.TypedValue; +import java.math.BigDecimal; + public class SimpleAxisRenderer implements AxisRenderer { int numDivisions = 5; From 102ddd29248360b675d54509d5c0b7f721080123 Mon Sep 17 00:00:00 2001 From: Paul Soucy Date: Tue, 11 Mar 2014 21:38:03 -0400 Subject: [PATCH 17/44] bargraph+spline+points --- .../devsmart/plotter/FunctionRenderer.java | 87 +++++++++++++++++-- 1 file changed, 80 insertions(+), 7 deletions(-) diff --git a/src/com/devsmart/plotter/FunctionRenderer.java b/src/com/devsmart/plotter/FunctionRenderer.java index 8f437b0..312e94c 100644 --- a/src/com/devsmart/plotter/FunctionRenderer.java +++ b/src/com/devsmart/plotter/FunctionRenderer.java @@ -117,6 +117,9 @@ public void add(float value) { private void drawAtSampleLocations(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { + Paint pointPaint = new Paint(); + pointPaint.setColor(Color.RED); + int sampleindex = 0; for(int i=0;i= viewPort.left){ @@ -137,35 +140,58 @@ private void drawAtSampleLocations(Canvas canvas, RectF viewPort, CoordinateSyst final double pixelWidth = viewPort.width() / (double)canvas.getWidth(); Path p = new Path(); + Path p2 = new Path(); - points[0] = viewPort.left; - points[1] = (float)mFunction.value(viewPort.left); + p.moveTo(0, 0); + + points[0] = (float) mSampleLocations[sampleindex]; + points[1] = (float)mFunction.value(points[0]); xminmax.add(points[0]); yminmax.add(points[1]); coordSystem.mapPoints(points); - p.moveTo(points[0], points[1]); + p.lineTo(points[0], points[1]); + p2.moveTo(points[0], points[1]); lastPoint[0] = points[0]; lastPoint[1] = points[1]; double startPix = mSampleLocations[sampleindex]; double x = 0; while(true){ - if(sampleindex >= mSampleLocations.length || (x=mSampleLocations[sampleindex++]) > viewPort.right){ + if(sampleindex >= mSampleLocations.length-1 || (x=mSampleLocations[sampleindex++ +1]) > viewPort.right){ break; } + final double y = mFunction.value(x); + + + + points[0] = (float) x; + points[1] = (float) y; + coordSystem.mapPoints(points); + + canvas.drawCircle(points[0], points[1], 3.0f, pointPaint); + + p.lineTo((lastPoint[0]+points[0])/2, lastPoint[1]); + p.lineTo((lastPoint[0]+points[0])/2, points[1]); + + //p.lineTo(points[0], lastPoint[1]); + //p.lineTo(points[0], points[1]); + lastPoint[0] = points[0]; + lastPoint[1] = points[1]; + + /* yMinMax[0] = Math.min(yMinMax[0], y); yMinMax[1] = Math.max(yMinMax[1], y); if(x >= startPix+pixelWidth){ //min - points[0] = (float) startPix; + points[0] = (float) x; points[1] = (float) yMinMax[0]; //max - points[2] = (float) startPix; + points[2] = (float) x; points[3] = (float) yMinMax[1]; xminmax.add(points[0]); @@ -189,15 +215,21 @@ private void drawAtSampleLocations(Canvas canvas, RectF viewPort, CoordinateSyst startPix = x; } + */ } + p.lineTo(canvas.getWidth(), lastPoint[1]); + points[0] = viewPort.right; points[1] = (float)mFunction.value(viewPort.right); xminmax.add(points[0]); yminmax.add(points[1]); coordSystem.mapPoints(points); - p.quadTo((lastPoint[0] + points[0]) / 2, (lastPoint[1] + points[1]) / 2, points[0], points[1]); + //p.lineTo(points[0], points[1]); + //p.quadTo((lastPoint[0] + points[0]) / 2, (lastPoint[1] + points[1]) / 2, points[0], points[1]); + + p.lineTo(canvas.getWidth(), 0); //p.lineTo(xminmax.max, yminmax.min); //p.lineTo(xminmax.min, yminmax.min); @@ -206,6 +238,47 @@ private void drawAtSampleLocations(Canvas canvas, RectF viewPort, CoordinateSyst p.close(); canvas.drawPath(p, mPointPaint); + + + //reset min max + yMinMax[0] = Double.MAX_VALUE; + yMinMax[1] = Double.MIN_VALUE; + final double stepWidth = Math.min(pixelWidth, 1.0/mSampleRate); + startPix = viewPort.left; + for(x=startPix;x= startPix+pixelWidth){ + + //min + points[0] = (float) startPix; + points[1] = (float) yMinMax[0]; + + //max + points[2] = (float) startPix; + points[3] = (float) yMinMax[1]; + + coordSystem.mapPoints(points); + + p2.lineTo(points[0], points[1]); + p2.lineTo(points[2], points[3]); + + //reset min max + yMinMax[0] = Double.MAX_VALUE; + yMinMax[1] = Double.MIN_VALUE; + + startPix = x; + } + } + + Paint p2Paint = new Paint(); + p2Paint.setStyle(Paint.Style.STROKE); + p2Paint.setColor(Color.WHITE); + p2Paint.setStrokeWidth(2.0f); + p2Paint.setAntiAlias(true); + canvas.drawPath(p2, p2Paint); } @Override From 3fcf5452ea3e0acccb05c23a13aa8a193cce6a7c Mon Sep 17 00:00:00 2001 From: Stephen Gowen Date: Mon, 17 Mar 2014 07:42:50 -0500 Subject: [PATCH 18/44] dirty --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f1f4f3e..9d73cd0 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:0.7.3' + classpath 'com.android.tools.build:gradle:0.9.+' } } From 4a6ec537a82f29316f969e6ba9a6544c0943b3aa Mon Sep 17 00:00:00 2001 From: paul Date: Tue, 18 Mar 2014 12:59:56 -0400 Subject: [PATCH 19/44] changes for factorymode --- src/com/devsmart/plotter/CoordinateSystem.java | 2 +- src/com/devsmart/plotter/GraphView.java | 8 ++------ src/com/devsmart/plotter/SimpleAxisRenderer.java | 5 +++-- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/com/devsmart/plotter/CoordinateSystem.java b/src/com/devsmart/plotter/CoordinateSystem.java index 7d96f87..fb27a4d 100644 --- a/src/com/devsmart/plotter/CoordinateSystem.java +++ b/src/com/devsmart/plotter/CoordinateSystem.java @@ -78,7 +78,7 @@ public CoordinateSystem getInverse() { return mInverse; } - void interpolate(RectF from, RectF to){ + public void interpolate(RectF from, RectF to){ mXAxisFunction.interpolate(new float[]{from.left, from.right}, new float[]{to.left, to.right}); mYAxisFunction.interpolate(new float[]{from.top, from.bottom}, new float[]{to.top, to.bottom}); } diff --git a/src/com/devsmart/plotter/GraphView.java b/src/com/devsmart/plotter/GraphView.java index 126040c..56c7ec6 100644 --- a/src/com/devsmart/plotter/GraphView.java +++ b/src/com/devsmart/plotter/GraphView.java @@ -86,7 +86,7 @@ public GraphView(Context context, AttributeSet attrs) { } private void init() { - mAxisRenderer = new SimpleAxisRenderer(this); + mAxisRenderer = new SimpleAxisRenderer(getContext()); mPanGestureDetector = new GestureDetector(mSimpleGestureListener); mScaleGestureDetector = new XYScaleGestureDetector(getContext(), mSimpleScaleGestureListener); mDrawPaint.setFilterBitmap(true); @@ -309,16 +309,13 @@ private void drawFrame(final RectF viewport) { BackgroundTask.runBackgroundTask(mBackgroundDrawTask, mDrawThread); } - public static Bitmap drawBitmap(int width, int height, List data, + public static void drawBitmap(Canvas c, int width, int height, List data, RectF viewport, CoordinateSystem coordinateSystem) { CoordinateSystem mCoordCopy = coordinateSystem.copy(); mCoordCopy.interpolate(viewport, new RectF(0,0,width,height)); - Bitmap drawBuffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444); - Canvas c = new Canvas(drawBuffer); - try { c.save(); c.scale(1, -1); @@ -330,7 +327,6 @@ public static Bitmap drawBitmap(int width, int height, List data, }finally { c.restore(); } - return drawBuffer; } private class BackgroundDrawTask extends BackgroundTask { diff --git a/src/com/devsmart/plotter/SimpleAxisRenderer.java b/src/com/devsmart/plotter/SimpleAxisRenderer.java index 6333c87..259265f 100644 --- a/src/com/devsmart/plotter/SimpleAxisRenderer.java +++ b/src/com/devsmart/plotter/SimpleAxisRenderer.java @@ -1,5 +1,6 @@ package com.devsmart.plotter; +import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; @@ -26,8 +27,8 @@ public class SimpleAxisRenderer implements AxisRenderer { DisplayMetrics mDisplayMetrics; - public SimpleAxisRenderer(GraphView graphview) { - mDisplayMetrics = graphview.getContext().getResources().getDisplayMetrics(); + public SimpleAxisRenderer(Context context) { + mDisplayMetrics = context.getResources().getDisplayMetrics(); mAxisLabelPaint.setColor(Color.BLACK); mAxisLabelPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 15, mDisplayMetrics)); From 6a4b82bac94cc772e835ad6c4f44f59a0c204418 Mon Sep 17 00:00:00 2001 From: paul Date: Fri, 28 Mar 2014 10:43:09 -0400 Subject: [PATCH 20/44] set to gradle 0.9.1 --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 9d73cd0..3f6e204 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:0.9.+' + classpath 'com.android.tools.build:gradle:0.9.1' } } @@ -17,7 +17,7 @@ repositories { dependencies { //compile fileTree(dir: 'libs', include: '*.jar') - compile 'com.android.support:support-v4:19.0.0' + compile 'com.android.support:support-v4:19.0.1' compile project(':AndroidEssentials') } From 0779c02c861a9f8ee1aff61d00779d880e973083 Mon Sep 17 00:00:00 2001 From: Paul Soucy Date: Tue, 1 Apr 2014 20:58:30 -0400 Subject: [PATCH 21/44] set buildToolsVersion to 19.0.1 and gradle to 0.9.1 --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 9d73cd0..1ca7e3f 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:0.9.+' + classpath 'com.android.tools.build:gradle:0.9.1' } } @@ -22,7 +22,7 @@ dependencies { } android { - buildToolsVersion "19.0.0" + buildToolsVersion "19.0.1" compileSdkVersion 10 sourceSets { main { From a0d626f5a4bed31c8a4f70adcabdd0f15c997152 Mon Sep 17 00:00:00 2001 From: paul Date: Wed, 7 May 2014 17:13:58 -0400 Subject: [PATCH 22/44] updated FunctionRenderer2 and SimpleAxisRenderer --- src/com/devsmart/plotter/AxisRenderer.java | 3 ++ .../devsmart/plotter/FunctionRenderer2.java | 52 +++++++++++++++++++ src/com/devsmart/plotter/GraphView.java | 8 +-- src/com/devsmart/plotter/PointRenderer.java | 35 +++++++++++++ .../devsmart/plotter/SimpleAxisRenderer.java | 10 ++++ .../plotter/XYScaleGestureDetector.java | 3 ++ 6 files changed, 108 insertions(+), 3 deletions(-) create mode 100644 src/com/devsmart/plotter/FunctionRenderer2.java create mode 100644 src/com/devsmart/plotter/PointRenderer.java diff --git a/src/com/devsmart/plotter/AxisRenderer.java b/src/com/devsmart/plotter/AxisRenderer.java index ff327a1..6761869 100644 --- a/src/com/devsmart/plotter/AxisRenderer.java +++ b/src/com/devsmart/plotter/AxisRenderer.java @@ -25,4 +25,7 @@ public interface AxisRenderer { */ void drawAxis(Canvas canvas, int canvasWidth, int canvasHeight, RectF viewport, CoordinateSystem coordSystem); + void setXAxisLabel(String label); + void setYAxisLabel(String label); + } diff --git a/src/com/devsmart/plotter/FunctionRenderer2.java b/src/com/devsmart/plotter/FunctionRenderer2.java new file mode 100644 index 0000000..c197400 --- /dev/null +++ b/src/com/devsmart/plotter/FunctionRenderer2.java @@ -0,0 +1,52 @@ +package com.devsmart.plotter; + + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.RectF; + +public class FunctionRenderer2 implements DataRenderer { + + public interface GraphFunction { + double value(double x); + } + + private final GraphFunction mFunction; + protected Paint mPaint = new Paint(); + + + public FunctionRenderer2(GraphFunction f, int color){ + mFunction = f; + mPaint.setColor(color); + mPaint.setStrokeWidth(2.0f); + mPaint.setAntiAlias(true); + mPaint.setStyle(Paint.Style.STROKE); + } + + @Override + public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { + + float[] points = new float[2]; + final double pixelWidth = viewPort.width() / (double)canvas.getWidth(); + + Path p = new Path(); + for(double x=viewPort.left;x<=viewPort.right;x+=pixelWidth){ + final double y = mFunction.value(x); + + points[0] = (float)x; + points[1] = (float)y; + + coordSystem.mapPoints(points); + if(x == viewPort.left){ + p.moveTo(points[0], points[1]); + } else { + p.lineTo(points[0], points[1]); + } + } + + //p.close(); + canvas.drawPath(p, mPaint); + + } +} diff --git a/src/com/devsmart/plotter/GraphView.java b/src/com/devsmart/plotter/GraphView.java index 5799e32..0e108c7 100644 --- a/src/com/devsmart/plotter/GraphView.java +++ b/src/com/devsmart/plotter/GraphView.java @@ -109,9 +109,8 @@ private void init() { private void init(int axisColor,int labelColor) { mAxisRenderer = new SimpleAxisRenderer(this,axisColor,labelColor); setUp(); - - } + private void setUp(){ mPanGestureDetector = new GestureDetector(mSimpleGestureListener); mScaleGestureDetector = new XYScaleGestureDetector(getContext(), mSimpleScaleGestureListener); @@ -135,7 +134,10 @@ private void setUp(){ //mZoomControls.setAutoDismissed(true); //mZoomControls.setOnZoomListener(mZoomButtonListener); } - + + public AxisRenderer getAxisRenderer() { + return mAxisRenderer; + } @Override diff --git a/src/com/devsmart/plotter/PointRenderer.java b/src/com/devsmart/plotter/PointRenderer.java new file mode 100644 index 0000000..298821d --- /dev/null +++ b/src/com/devsmart/plotter/PointRenderer.java @@ -0,0 +1,35 @@ +package com.devsmart.plotter; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; + + +public class PointRenderer implements DataRenderer { + + private float[] mPoints; + private Paint mPaint = new Paint(); + + public PointRenderer(float[] points, int color) { + mPoints = points; + mPaint.setColor(color); + mPaint.setStrokeWidth(5.0f); + mPaint.setAntiAlias(true); + mPaint.setStyle(Paint.Style.STROKE); + } + + @Override + public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { + + float[] point = new float[2]; + for(int i=0;i Date: Thu, 8 May 2014 15:11:00 -0400 Subject: [PATCH 23/44] fixed bug in FunctionRenderer2 --- src/com/devsmart/plotter/FunctionRenderer2.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/com/devsmart/plotter/FunctionRenderer2.java b/src/com/devsmart/plotter/FunctionRenderer2.java index c197400..0a57f26 100644 --- a/src/com/devsmart/plotter/FunctionRenderer2.java +++ b/src/com/devsmart/plotter/FunctionRenderer2.java @@ -24,6 +24,10 @@ public FunctionRenderer2(GraphFunction f, int color){ mPaint.setStyle(Paint.Style.STROKE); } + private static boolean isRealNumber(float f) { + return !Float.isNaN(f) && !Float.isInfinite(f); + } + @Override public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { @@ -38,10 +42,12 @@ public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { points[1] = (float)y; coordSystem.mapPoints(points); - if(x == viewPort.left){ - p.moveTo(points[0], points[1]); - } else { - p.lineTo(points[0], points[1]); + if(isRealNumber(points[0]) && isRealNumber(points[1])) { + if (x == viewPort.left) { + p.moveTo(points[0], points[1]); + } else { + p.lineTo(points[0], points[1]); + } } } From db4ab248fa8634c7c870968bbc8ba1ff10101f85 Mon Sep 17 00:00:00 2001 From: paul Date: Thu, 15 May 2014 17:04:13 -0400 Subject: [PATCH 24/44] might work --- .../devsmart/plotter/FunctionRenderer.java | 11 +-- .../devsmart/plotter/FunctionRenderer2.java | 4 +- .../plotter/OversampleFunctionRenderer.java | 93 +++++++++++++++++++ 3 files changed, 97 insertions(+), 11 deletions(-) create mode 100644 src/com/devsmart/plotter/OversampleFunctionRenderer.java diff --git a/src/com/devsmart/plotter/FunctionRenderer.java b/src/com/devsmart/plotter/FunctionRenderer.java index 312e94c..d85584d 100644 --- a/src/com/devsmart/plotter/FunctionRenderer.java +++ b/src/com/devsmart/plotter/FunctionRenderer.java @@ -23,6 +23,7 @@ public FunctionRenderer(GraphFunction f, double[] sampleLocations, int color) { mPointPaint.setColor(color); mPointPaint.setStrokeWidth(2.0f); mPointPaint.setAntiAlias(true); + mPointPaint.setStyle(Paint.Style.STROKE); } public FunctionRenderer(GraphFunction f, double samplerate, int color) { @@ -31,6 +32,7 @@ public FunctionRenderer(GraphFunction f, double samplerate, int color) { mPointPaint.setColor(color); mPointPaint.setStrokeWidth(2.0f); mPointPaint.setAntiAlias(true); + mPointPaint.setStyle(Paint.Style.STROKE); } @@ -48,12 +50,11 @@ private void drawFixedSample(Canvas canvas, RectF viewPort, CoordinateSystem coo final double stepWidth = Math.min(pixelWidth, 1.0/mSampleRate); Path p = new Path(); - p.moveTo(0, 0); points[0] = viewPort.left; points[1] = (float)mFunction.value(viewPort.left); coordSystem.mapPoints(points); - p.lineTo(points[0], points[1]); + p.moveTo(points[0], points[1]); double startPix = viewPort.left; for(double x=startPix;x Date: Fri, 16 May 2014 14:21:01 -0400 Subject: [PATCH 25/44] making OversampleFunctionRenderer work --- src/com/devsmart/plotter/GraphView.java | 7 +- .../plotter/OversampleFunctionRenderer.java | 88 ++++++++++++++----- 2 files changed, 72 insertions(+), 23 deletions(-) diff --git a/src/com/devsmart/plotter/GraphView.java b/src/com/devsmart/plotter/GraphView.java index 0e108c7..f8bf5a0 100644 --- a/src/com/devsmart/plotter/GraphView.java +++ b/src/com/devsmart/plotter/GraphView.java @@ -312,8 +312,11 @@ public CoordinateSystem getCoordinateSystem() { public void setDisplayViewPort(RectF viewport) { mTransformMatrix.reset(); mViewPort = new RectF(viewport); - mCoordinateSystem.interpolate(mViewPort, new RectF(0,0,mGraphArea.width(), mGraphArea.height())); - drawFrame(viewport); + + if(mGraphArea != null) { + mCoordinateSystem.interpolate(mViewPort, new RectF(0, 0, mGraphArea.width(), mGraphArea.height())); + drawFrame(viewport); + } } @Override diff --git a/src/com/devsmart/plotter/OversampleFunctionRenderer.java b/src/com/devsmart/plotter/OversampleFunctionRenderer.java index 921f60f..56ad078 100644 --- a/src/com/devsmart/plotter/OversampleFunctionRenderer.java +++ b/src/com/devsmart/plotter/OversampleFunctionRenderer.java @@ -8,11 +8,33 @@ public class OversampleFunctionRenderer implements DataRenderer { + private static class MinMax { + double min = Double.NaN; + double max = Double.NaN; + + public void addValue(double value){ + if(value < min || Double.isNaN(min)){ + min = value; + } + + if(value > max || Double.isNaN(max)){ + max = value; + } + } + + public void clear() { + min = Double.NaN; + max = Double.NaN; + } + + } private final FunctionRenderer2.GraphFunction mFunction; private double[] mSamplePoints; private double mSampleRate; protected Paint mPaint = new Paint(); + private MinMax mMinMax = new MinMax(); + private float[] mPoints = new float[4]; public OversampleFunctionRenderer(FunctionRenderer2.GraphFunction f, double[] samplePoints, int color) { mFunction = f; @@ -45,46 +67,70 @@ private void drawUsingSamplerate(Canvas canvas, RectF viewPort, CoordinateSystem float[] points = new float[2]; final double pixelWidth = viewPort.width() / (double)canvas.getWidth(); + mMinMax.clear(); + double lastX = viewPort.left-pixelWidth; + Path p = new Path(); - for(double x=viewPort.left;x<=viewPort.right;x+=mSampleRate){ - final double y = mFunction.value(x); + points[0] = viewPort.left; + points[1] = (float) mFunction.value(viewPort.left); + coordSystem.mapPoints(points); + p.moveTo(points[0], points[1]); - points[0] = (float)x; - points[1] = (float)y; + for(double x=viewPort.left;x<=viewPort.right;x+=mSampleRate){ + final double y = mFunction.value(x); + mMinMax.addValue(y); - coordSystem.mapPoints(points); - if(FunctionRenderer2.isRealNumber(points[0]) && FunctionRenderer2.isRealNumber(points[1])) { - if (x == viewPort.left) { - p.moveTo(points[0], points[1]); - } else { - p.lineTo(points[0], points[1]); - } + if(x >= lastX+pixelWidth){ + drawLine(p, (float) x, coordSystem); + lastX = x; + mMinMax.clear(); } } canvas.drawPath(p, mPaint); } + private void drawLine(Path path, float x, CoordinateSystem coordSystem) { + mPoints[0] = x; + mPoints[1] = (float)mMinMax.min; + mPoints[2] = x; + mPoints[3] = (float)mMinMax.max; + + coordSystem.mapPoints(mPoints); + if(FunctionRenderer2.isRealNumber(mPoints[0]) && FunctionRenderer2.isRealNumber(mPoints[1])) { + path.lineTo(mPoints[0], mPoints[1]); + } + if(FunctionRenderer2.isRealNumber(mPoints[2]) && FunctionRenderer2.isRealNumber(mPoints[3])) { + path.lineTo(mPoints[2], mPoints[3]); + } + + path.moveTo(mPoints[0], mPoints[1]); + } + private void drawUsingSamplePoints(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { float[] points = new float[2]; final double pixelWidth = viewPort.width() / (double)canvas.getWidth(); + mMinMax.clear(); + double lastX = viewPort.left-pixelWidth; + Path p = new Path(); + + points[0] = viewPort.left; + points[1] = (float) mFunction.value(viewPort.left); + coordSystem.mapPoints(points); + p.moveTo(points[0], points[1]); + for(int i=0;i= lastX+pixelWidth){ + drawLine(p, (float) x, coordSystem); + lastX = x; + mMinMax.clear(); } } From 63260cdfd58a692833e9616c592c8348a81d9727 Mon Sep 17 00:00:00 2001 From: paul Date: Mon, 30 Jun 2014 10:54:26 -0400 Subject: [PATCH 26/44] set Axis color --- src/com/devsmart/plotter/AxisRenderer.java | 1 + src/com/devsmart/plotter/SimpleAxisRenderer.java | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/com/devsmart/plotter/AxisRenderer.java b/src/com/devsmart/plotter/AxisRenderer.java index 6761869..8479bd1 100644 --- a/src/com/devsmart/plotter/AxisRenderer.java +++ b/src/com/devsmart/plotter/AxisRenderer.java @@ -27,5 +27,6 @@ public interface AxisRenderer { void setXAxisLabel(String label); void setYAxisLabel(String label); + void setAxisColor(int color); } diff --git a/src/com/devsmart/plotter/SimpleAxisRenderer.java b/src/com/devsmart/plotter/SimpleAxisRenderer.java index 4328cab..86f442d 100644 --- a/src/com/devsmart/plotter/SimpleAxisRenderer.java +++ b/src/com/devsmart/plotter/SimpleAxisRenderer.java @@ -52,6 +52,12 @@ public SimpleAxisRenderer(GraphView graphview) { } + @Override + public void setAxisColor(int color) { + mAxisLabelPaint.setColor(color); + mAxisTickPaint.setColor(color); + } + @Override public void setYAxisLabel(String label){ mYAxisLabel = label; From 6b4d05d627b3835479b8c52765cd94a62a695c05 Mon Sep 17 00:00:00 2001 From: Paul Soucy Date: Tue, 8 Jul 2014 00:54:55 -0400 Subject: [PATCH 27/44] update to android studio 0.8 --- build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 1ca7e3f..eb6c9f3 100644 --- a/build.gradle +++ b/build.gradle @@ -4,11 +4,11 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:0.9.1' + classpath 'com.android.tools.build:gradle:0.12.+' } } -apply plugin: 'android-library' +apply plugin: 'com.android.library' apply plugin: 'eclipse' repositories { @@ -22,7 +22,7 @@ dependencies { } android { - buildToolsVersion "19.0.1" + buildToolsVersion "20.0.0" compileSdkVersion 10 sourceSets { main { From b5ee54ddf74263eb787d5ba8600714eff587ba31 Mon Sep 17 00:00:00 2001 From: paul Date: Thu, 17 Jul 2014 16:51:53 -0400 Subject: [PATCH 28/44] update build.gradle --- build.gradle | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6421376..f7b9e72 100644 --- a/build.gradle +++ b/build.gradle @@ -17,13 +17,19 @@ repositories { dependencies { //compile fileTree(dir: 'libs', include: '*.jar') - compile 'com.android.support:support-v4:19.0.1' + compile 'com.android.support:support-v4:19.+' compile project(':AndroidEssentials') } android { buildToolsVersion "20.0.0" compileSdkVersion 10 + + defaultConfig { + minSdkVersion 10 + targetSdkVersion 10 + } + sourceSets { main { manifest.srcFile 'AndroidManifest.xml' From 2c2dbc829342cf74316828f30705783bf04dc665 Mon Sep 17 00:00:00 2001 From: paul Date: Tue, 18 Nov 2014 14:31:38 -0500 Subject: [PATCH 29/44] fix extra line artifact --- src/com/devsmart/plotter/OversampleFunctionRenderer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/devsmart/plotter/OversampleFunctionRenderer.java b/src/com/devsmart/plotter/OversampleFunctionRenderer.java index 56ad078..d8344df 100644 --- a/src/com/devsmart/plotter/OversampleFunctionRenderer.java +++ b/src/com/devsmart/plotter/OversampleFunctionRenderer.java @@ -117,8 +117,8 @@ private void drawUsingSamplePoints(Canvas canvas, RectF viewPort, CoordinateSyst Path p = new Path(); - points[0] = viewPort.left; - points[1] = (float) mFunction.value(viewPort.left); + points[0] = (float) mSamplePoints[0]; + points[1] = (float) mFunction.value(mSamplePoints[0]); coordSystem.mapPoints(points); p.moveTo(points[0], points[1]); From 2d3001e85fd8be5d0f8c7c0fd9494d6cdf86bb48 Mon Sep 17 00:00:00 2001 From: paul Date: Wed, 19 Nov 2014 09:37:29 -0500 Subject: [PATCH 30/44] fix graphing problem --- .../plotter/OversampleFunctionRenderer.java | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/com/devsmart/plotter/OversampleFunctionRenderer.java b/src/com/devsmart/plotter/OversampleFunctionRenderer.java index d8344df..5415d16 100644 --- a/src/com/devsmart/plotter/OversampleFunctionRenderer.java +++ b/src/com/devsmart/plotter/OversampleFunctionRenderer.java @@ -6,6 +6,8 @@ import android.graphics.Path; import android.graphics.RectF; +import java.util.Arrays; + public class OversampleFunctionRenderer implements DataRenderer { private static class MinMax { @@ -38,7 +40,9 @@ public void clear() { public OversampleFunctionRenderer(FunctionRenderer2.GraphFunction f, double[] samplePoints, int color) { mFunction = f; - mSamplePoints = samplePoints; + mSamplePoints = new double[samplePoints.length]; + System.arraycopy(samplePoints, 0, mSamplePoints, 0, mSamplePoints.length); + Arrays.sort(mSamplePoints); mPaint.setColor(color); mPaint.setStrokeWidth(2.0f); mPaint.setAntiAlias(true); @@ -112,17 +116,32 @@ private void drawUsingSamplePoints(Canvas canvas, RectF viewPort, CoordinateSyst float[] points = new float[2]; final double pixelWidth = viewPort.width() / (double)canvas.getWidth(); - mMinMax.clear(); - double lastX = viewPort.left-pixelWidth; + int start = Arrays.binarySearch(mSamplePoints, viewPort.left); + if(start < 0) { + start = -start - 2; + } + if(start < 0){ + start = 0; + } + + int end = Arrays.binarySearch(mSamplePoints, viewPort.right); + if(end < 0) { + end = -end; + } + if(end >= mSamplePoints.length) { + end = mSamplePoints.length; + } Path p = new Path(); + mMinMax.clear(); - points[0] = (float) mSamplePoints[0]; - points[1] = (float) mFunction.value(mSamplePoints[0]); + double lastX = mSamplePoints[start]; + points[0] = (float) lastX; + points[1] = (float) mFunction.value(lastX); coordSystem.mapPoints(points); p.moveTo(points[0], points[1]); - for(int i=0;i Date: Wed, 19 Nov 2014 10:00:24 -0500 Subject: [PATCH 31/44] show more digits on axis --- src/com/devsmart/plotter/SimpleAxisRenderer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/devsmart/plotter/SimpleAxisRenderer.java b/src/com/devsmart/plotter/SimpleAxisRenderer.java index f0d121d..74e755d 100644 --- a/src/com/devsmart/plotter/SimpleAxisRenderer.java +++ b/src/com/devsmart/plotter/SimpleAxisRenderer.java @@ -205,7 +205,7 @@ public void drawAxis(Canvas canvas, final int canvasWidth, final int canvasHeigh } protected String getTickLabel(float value) { - return String.format("%3.1f", value); + return String.format("%g", value); //return String.valueOf(MathUtils.round(value, 1)); } From 5f2a7b6a50a4c998fa85e62198307e62b29d3cdb Mon Sep 17 00:00:00 2001 From: paul Date: Mon, 15 Dec 2014 09:12:28 -0500 Subject: [PATCH 32/44] update for gradle android pluging 1.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f7b9e72..cb4a348 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:0.12.+' + classpath 'com.android.tools.build:gradle:1.0.0' } } From a0521b42d1e0461cd0fd97a5db26fb03f6b1b104 Mon Sep 17 00:00:00 2001 From: paul Date: Mon, 22 Dec 2014 15:36:52 -0500 Subject: [PATCH 33/44] update to work with devsmart-android --- build.gradle | 11 ++++++----- src/com/devsmart/plotter/GraphView.java | 2 +- src/com/devsmart/plotter/LineGraphDataRenderer.java | 1 - 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index cb4a348..817f2cf 100644 --- a/build.gradle +++ b/build.gradle @@ -17,17 +17,18 @@ repositories { dependencies { //compile fileTree(dir: 'libs', include: '*.jar') - compile 'com.android.support:support-v4:19.+' + compile 'com.android.support:support-v4:21.0.3' + compile 'com.dev-smart:devsmart-android:0.1.0' compile project(':AndroidEssentials') } android { - buildToolsVersion "20.0.0" - compileSdkVersion 10 + compileSdkVersion 19 + buildToolsVersion "21.1.2" defaultConfig { - minSdkVersion 10 - targetSdkVersion 10 + minSdkVersion 14 + targetSdkVersion 14 } sourceSets { diff --git a/src/com/devsmart/plotter/GraphView.java b/src/com/devsmart/plotter/GraphView.java index 8c8a04d..f83352c 100644 --- a/src/com/devsmart/plotter/GraphView.java +++ b/src/com/devsmart/plotter/GraphView.java @@ -22,7 +22,7 @@ import android.view.animation.Interpolator; import android.widget.ZoomButtonsController; -import com.devsmart.BackgroundTask; +import com.devsmart.android.BackgroundTask; import java.util.ArrayList; import java.util.Iterator; diff --git a/src/com/devsmart/plotter/LineGraphDataRenderer.java b/src/com/devsmart/plotter/LineGraphDataRenderer.java index ccfda41..77350aa 100644 --- a/src/com/devsmart/plotter/LineGraphDataRenderer.java +++ b/src/com/devsmart/plotter/LineGraphDataRenderer.java @@ -1,7 +1,6 @@ package com.devsmart.plotter; import android.graphics.Canvas; -import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.RectF; From 038f65c32ffcd47608363eb2a5f5a3e8084eef6d Mon Sep 17 00:00:00 2001 From: paul Date: Fri, 2 Jan 2015 13:26:13 -0500 Subject: [PATCH 34/44] devsmart android v0.1.1 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 817f2cf..436c688 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ repositories { dependencies { //compile fileTree(dir: 'libs', include: '*.jar') compile 'com.android.support:support-v4:21.0.3' - compile 'com.dev-smart:devsmart-android:0.1.0' + compile 'com.dev-smart:devsmart-android:0.1.1' compile project(':AndroidEssentials') } From 3a223d49e78d47e8e094427fa85db75d5875280e Mon Sep 17 00:00:00 2001 From: paul Date: Mon, 5 Jan 2015 16:42:06 -0500 Subject: [PATCH 35/44] devsmart core v0.1.2 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 436c688..d0ee0c9 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ repositories { dependencies { //compile fileTree(dir: 'libs', include: '*.jar') compile 'com.android.support:support-v4:21.0.3' - compile 'com.dev-smart:devsmart-android:0.1.1' + compile 'com.dev-smart:devsmart-android:0.1.2' compile project(':AndroidEssentials') } From fdb746b77081d2843c899082c3d3f72cdf241f17 Mon Sep 17 00:00:00 2001 From: paul Date: Wed, 7 Jan 2015 16:44:38 -0500 Subject: [PATCH 36/44] devsmart core v0.1.3 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d0ee0c9..d967ac0 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ repositories { dependencies { //compile fileTree(dir: 'libs', include: '*.jar') compile 'com.android.support:support-v4:21.0.3' - compile 'com.dev-smart:devsmart-android:0.1.2' + compile 'com.dev-smart:devsmart-android:0.1.3' compile project(':AndroidEssentials') } From 09c4d08ac4e803f7fde0976fb370002c522b72a3 Mon Sep 17 00:00:00 2001 From: paul Date: Tue, 17 Feb 2015 17:50:19 -0500 Subject: [PATCH 37/44] upgrade to devsmart core 0.1.4 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d967ac0..b59aed4 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ repositories { dependencies { //compile fileTree(dir: 'libs', include: '*.jar') compile 'com.android.support:support-v4:21.0.3' - compile 'com.dev-smart:devsmart-android:0.1.3' + compile 'com.dev-smart:devsmart-android:0.1.4' compile project(':AndroidEssentials') } From dc84426a68e87fc07e6bd8231e423d11b71d4c42 Mon Sep 17 00:00:00 2001 From: paul Date: Tue, 31 Mar 2015 14:38:43 -0400 Subject: [PATCH 38/44] update devsmart core 1.5 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index b59aed4..f9af734 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ repositories { dependencies { //compile fileTree(dir: 'libs', include: '*.jar') compile 'com.android.support:support-v4:21.0.3' - compile 'com.dev-smart:devsmart-android:0.1.4' + compile 'com.dev-smart:devsmart-android:0.1.5' compile project(':AndroidEssentials') } From 1f346f25a73da19185981cc87d99f06f3fd25c22 Mon Sep 17 00:00:00 2001 From: Stephen Gowen Date: Thu, 9 Apr 2015 15:54:20 -0400 Subject: [PATCH 39/44] Adding the ability to set paint color in the AxisRenderer --- src/com/devsmart/plotter/AxisRenderer.java | 47 +- src/com/devsmart/plotter/DataRenderer.java | 9 +- .../devsmart/plotter/FunctionRenderer.java | 132 +-- .../devsmart/plotter/FunctionRenderer2.java | 8 +- src/com/devsmart/plotter/GraphView.java | 815 ++++++++---------- .../plotter/LineGraphDataRenderer.java | 10 +- .../plotter/OversampleFunctionRenderer.java | 150 ++-- src/com/devsmart/plotter/PointRenderer.java | 8 +- .../devsmart/plotter/SimpleAxisRenderer.java | 380 ++++---- 9 files changed, 744 insertions(+), 815 deletions(-) diff --git a/src/com/devsmart/plotter/AxisRenderer.java b/src/com/devsmart/plotter/AxisRenderer.java index 8479bd1..ffd01d4 100644 --- a/src/com/devsmart/plotter/AxisRenderer.java +++ b/src/com/devsmart/plotter/AxisRenderer.java @@ -4,29 +4,34 @@ import android.graphics.Rect; import android.graphics.RectF; -public interface AxisRenderer { - - /** - * Measure the area where the graph data will be drawn. Return a Rect - * in screen coordinates. - * @param screenWidth - * @param screenHeight - * @return - */ - Rect measureGraphArea(int screenWidth, int screenHeight); - - /** - * Draw the axis on the canvas. - * @param canvas - * @param canvasWidth - * @param canvasHeight - * @param viewport - * @return - */ - void drawAxis(Canvas canvas, int canvasWidth, int canvasHeight, RectF viewport, CoordinateSystem coordSystem); +public interface AxisRenderer +{ + /** + * Measure the area where the graph data will be drawn. Return a Rect + * in screen coordinates. + * + * @param screenWidth + * @param screenHeight + * @return + */ + Rect measureGraphArea(int screenWidth, int screenHeight); + + /** + * Draw the axis on the canvas. + * + * @param canvas + * @param canvasWidth + * @param canvasHeight + * @param viewport + * @return + */ + void drawAxis(Canvas canvas, int canvasWidth, int canvasHeight, RectF viewport, CoordinateSystem coordSystem); void setXAxisLabel(String label); + void setYAxisLabel(String label); + void setAxisColor(int color); -} + void setLabelColor(int color); +} \ No newline at end of file diff --git a/src/com/devsmart/plotter/DataRenderer.java b/src/com/devsmart/plotter/DataRenderer.java index a2d6be0..78d2d00 100644 --- a/src/com/devsmart/plotter/DataRenderer.java +++ b/src/com/devsmart/plotter/DataRenderer.java @@ -3,8 +3,9 @@ import android.graphics.Canvas; import android.graphics.RectF; -public interface DataRenderer { - - public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem); +public interface DataRenderer +{ + void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem); -} + void setPaintColor(int color); +} \ No newline at end of file diff --git a/src/com/devsmart/plotter/FunctionRenderer.java b/src/com/devsmart/plotter/FunctionRenderer.java index d85584d..ce8d2bb 100644 --- a/src/com/devsmart/plotter/FunctionRenderer.java +++ b/src/com/devsmart/plotter/FunctionRenderer.java @@ -6,18 +6,24 @@ import android.graphics.Path; import android.graphics.RectF; -public class FunctionRenderer implements DataRenderer { - - public interface GraphFunction { +public class FunctionRenderer implements DataRenderer +{ + public interface GraphFunction + { double value(double x); } private double[] mSampleLocations; - private GraphFunction mFunction; + private GraphFunction mFunction; private double mSampleRate = 2; - protected Paint mPointPaint = new Paint(); + protected final Paint mPointPaint = new Paint(); + float[] points = new float[6]; + float[] drawPoints = new float[4]; + float[] lastPoint = new float[2]; + double[] yMinMax = new double[2]; - public FunctionRenderer(GraphFunction f, double[] sampleLocations, int color) { + public FunctionRenderer(GraphFunction f, double[] sampleLocations, int color) + { mFunction = f; mSampleLocations = sampleLocations; mPointPaint.setColor(color); @@ -25,44 +31,42 @@ public FunctionRenderer(GraphFunction f, double[] sampleLocations, int color) { mPointPaint.setAntiAlias(true); mPointPaint.setStyle(Paint.Style.STROKE); } - - public FunctionRenderer(GraphFunction f, double samplerate, int color) { - mFunction = f; + + public FunctionRenderer(GraphFunction f, double samplerate, int color) + { + mFunction = f; mSampleRate = samplerate; - mPointPaint.setColor(color); - mPointPaint.setStrokeWidth(2.0f); + mPointPaint.setColor(color); + mPointPaint.setStrokeWidth(2.0f); mPointPaint.setAntiAlias(true); mPointPaint.setStyle(Paint.Style.STROKE); - } - - - float[] points = new float[6]; - float[] drawPoints = new float[4]; - float[] lastPoint = new float[2]; - double[] yMinMax = new double[2]; + } - private void drawFixedSample(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { + private void drawFixedSample(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) + { //reset min max yMinMax[0] = Double.MAX_VALUE; yMinMax[1] = Double.MIN_VALUE; - final double pixelWidth = viewPort.width() / (double)canvas.getWidth(); - final double stepWidth = Math.min(pixelWidth, 1.0/mSampleRate); + final double pixelWidth = viewPort.width() / (double) canvas.getWidth(); + final double stepWidth = Math.min(pixelWidth, 1.0 / mSampleRate); Path p = new Path(); points[0] = viewPort.left; - points[1] = (float)mFunction.value(viewPort.left); + points[1] = (float) mFunction.value(viewPort.left); coordSystem.mapPoints(points); p.moveTo(points[0], points[1]); double startPix = viewPort.left; - for(double x=startPix;x= startPix+pixelWidth){ + if (x >= startPix + pixelWidth) + { //min points[0] = (float) startPix; @@ -86,43 +90,51 @@ private void drawFixedSample(Canvas canvas, RectF viewPort, CoordinateSystem coo } points[0] = viewPort.right; - points[1] = (float)mFunction.value(viewPort.right); + points[1] = (float) mFunction.value(viewPort.right); coordSystem.mapPoints(points); p.lineTo(points[0], points[1]); canvas.drawPath(p, mPointPaint); } - private class MinMax { + private class MinMax + { double min; double max; - public MinMax() { + public MinMax() + { reset(); } - public void reset() { + public void reset() + { min = Double.MAX_VALUE; max = Double.MIN_VALUE; } - public void add(float value) { + public void add(float value) + { min = Math.min(min, value); max = Math.max(max, value); } } - private void drawAtSampleLocations(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { + private void drawAtSampleLocations(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) + { Paint pointPaint = new Paint(); pointPaint.setColor(Color.RED); int sampleindex = 0; - for(int i=0;i= viewPort.left){ + for (int i = 0; i < mSampleLocations.length; i++) + { + if (mSampleLocations[i] >= viewPort.left) + { sampleindex = i; - if(i>0){ - sampleindex = i-1; + if (i > 0) + { + sampleindex = i - 1; } break; } @@ -134,13 +146,13 @@ private void drawAtSampleLocations(Canvas canvas, RectF viewPort, CoordinateSyst MinMax xminmax = new MinMax(); MinMax yminmax = new MinMax(); - final double pixelWidth = viewPort.width() / (double)canvas.getWidth(); + final double pixelWidth = viewPort.width() / (double) canvas.getWidth(); Path p = new Path(); Path p2 = new Path(); points[0] = (float) mSampleLocations[sampleindex]; - points[1] = (float)mFunction.value(points[0]); + points[1] = (float) mFunction.value(points[0]); xminmax.add(points[0]); yminmax.add(points[1]); @@ -152,23 +164,24 @@ private void drawAtSampleLocations(Canvas canvas, RectF viewPort, CoordinateSyst double startPix = mSampleLocations[sampleindex]; double x = 0; - while(true){ - if(sampleindex >= mSampleLocations.length-1 || (x=mSampleLocations[sampleindex++ +1]) > viewPort.right){ + while (true) + { + if (sampleindex >= mSampleLocations.length - 1 || (x = mSampleLocations[sampleindex++ + 1]) > viewPort.right) + { break; } final double y = mFunction.value(x); - points[0] = (float) x; points[1] = (float) y; coordSystem.mapPoints(points); canvas.drawCircle(points[0], points[1], 3.0f, pointPaint); - p.lineTo((lastPoint[0]+points[0])/2, lastPoint[1]); - p.lineTo((lastPoint[0]+points[0])/2, points[1]); + p.lineTo((lastPoint[0] + points[0]) / 2, lastPoint[1]); + p.lineTo((lastPoint[0] + points[0]) / 2, points[1]); //p.lineTo(points[0], lastPoint[1]); //p.lineTo(points[0], points[1]); @@ -216,7 +229,7 @@ private void drawAtSampleLocations(Canvas canvas, RectF viewPort, CoordinateSyst p.lineTo(canvas.getWidth(), lastPoint[1]); points[0] = viewPort.right; - points[1] = (float)mFunction.value(viewPort.right); + points[1] = (float) mFunction.value(viewPort.right); xminmax.add(points[0]); yminmax.add(points[1]); coordSystem.mapPoints(points); @@ -238,14 +251,16 @@ private void drawAtSampleLocations(Canvas canvas, RectF viewPort, CoordinateSyst //reset min max yMinMax[0] = Double.MAX_VALUE; yMinMax[1] = Double.MIN_VALUE; - final double stepWidth = Math.min(pixelWidth, 1.0/mSampleRate); + final double stepWidth = Math.min(pixelWidth, 1.0 / mSampleRate); startPix = viewPort.left; - for(x=startPix;x= startPix+pixelWidth){ + if (x >= startPix + pixelWidth) + { //min points[0] = (float) startPix; @@ -275,18 +290,23 @@ private void drawAtSampleLocations(Canvas canvas, RectF viewPort, CoordinateSyst p2Paint.setAntiAlias(true); canvas.drawPath(p2, p2Paint); } - - @Override - public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { - if(mSampleLocations == null) { + + @Override + public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) + { + if (mSampleLocations == null) + { drawFixedSample(canvas, viewPort, coordSystem); - } else { + } + else + { drawAtSampleLocations(canvas, viewPort, coordSystem); } + } - - } - - - -} + @Override + public void setPaintColor(int color) + { + mPointPaint.setColor(color); + } +} \ No newline at end of file diff --git a/src/com/devsmart/plotter/FunctionRenderer2.java b/src/com/devsmart/plotter/FunctionRenderer2.java index 32d17e1..cd7ef98 100644 --- a/src/com/devsmart/plotter/FunctionRenderer2.java +++ b/src/com/devsmart/plotter/FunctionRenderer2.java @@ -13,7 +13,7 @@ public interface GraphFunction { } private final GraphFunction mFunction; - protected Paint mPaint = new Paint(); + protected final Paint mPaint = new Paint(); public FunctionRenderer2(GraphFunction f, int color){ @@ -53,4 +53,10 @@ public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { canvas.drawPath(p, mPaint); } + + @Override + public void setPaintColor(int color) + { + mPaint.setColor(color); + } } diff --git a/src/com/devsmart/plotter/GraphView.java b/src/com/devsmart/plotter/GraphView.java index f83352c..f978972 100644 --- a/src/com/devsmart/plotter/GraphView.java +++ b/src/com/devsmart/plotter/GraphView.java @@ -10,8 +10,6 @@ import android.graphics.Rect; import android.graphics.RectF; import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; import android.os.Parcelable; import android.support.v4.view.MotionEventCompat; import android.util.AttributeSet; @@ -20,253 +18,251 @@ import android.view.View; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; -import android.widget.ZoomButtonsController; import com.devsmart.android.BackgroundTask; import java.util.ArrayList; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -public class GraphView extends View { - - public static enum Axis { - X, - Y - } - - private static final String KEY_VIEWPORT = "viewport"; - private static final String KEY_SUPERINSTANCE = "superinstance"; - - private CoordinateSystem mCoordinateSystem = CoordinateSystem.createLinearSystem(); - - private ExecutorService mDrawThread = Executors.newSingleThreadExecutor(); - - private RectF mViewPort = new RectF(); - protected LinkedList mPlotData = new LinkedList(); - - private Bitmap mFrontBuffer; - private Matrix mTransformMatrix = new Matrix(); - private Paint mDrawPaint = new Paint(); - private BackgroundDrawTask mBackgroundDrawTask; - private GestureDetector mPanGestureDetector; - private XYScaleGestureDetector mScaleGestureDetector; - - //draw prefs - protected boolean mDrawXAxis; - protected boolean mDrawYAxis; - protected int mAxisColor; - protected Paint mAxisLabelPaint = new Paint(); - protected Rect mPlotMargins = new Rect(); - protected int mBackgroundColor; - public float mXAxisDevision; - public float mYAxisDevision; - protected int mXAxisMargin; - protected int mYAxisMargin; - - protected AxisRenderer mAxisRenderer; - - //private ZoomButtonsController mZoomControls; - private Rect mGraphArea; +public final class GraphView extends View +{ + public static void drawBitmap(Canvas c, int width, int height, List data, RectF viewport, CoordinateSystem coordinateSystem) + { + CoordinateSystem mCoordCopy = coordinateSystem.copy(); + mCoordCopy.interpolate(viewport, new RectF(0, 0, width, height)); + + try + { + c.save(); + c.scale(1, -1); + c.translate(0, -c.getHeight()); + + for (DataRenderer r : data) + { + r.draw(c, viewport, mCoordCopy); + } + } + finally + { + c.restore(); + } + } + + private static final String KEY_VIEWPORT = "viewport"; + private static final String KEY_SUPERINSTANCE = "superinstance"; + private static final long mAnimationTime = 1000; + + private final GestureDetector.SimpleOnGestureListener mSimpleGestureListener = new GestureDetector.SimpleOnGestureListener() + { + @Override + public boolean onDown(MotionEvent e) + { + return true; + } + + @Override + public boolean onDoubleTap(MotionEvent e) + { + mTransformMatrix.postScale(1.3f, 1.3f, e.getX(), e.getY()); + invalidate(); + updateViewport(); + return true; + } + + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) + { + mTransformMatrix.postTranslate(-distanceX, -distanceY); + invalidate(); + updateViewport(); + return true; + } + }; + + private final XYScaleGestureDetector.SimpleOnScaleGestureListener mSimpleScaleGestureListener = new XYScaleGestureDetector.SimpleOnScaleGestureListener() + { + @Override + public boolean onScale(XYScaleGestureDetector detector) + { + mTransformMatrix.postScale(detector.getXScaleFactor(), detector.getYScaleFactor(), detector.getFocusX(), detector.getFocusY()); + invalidate(); + updateViewport(); + return true; + } + }; + + private final ExecutorService mDrawThread = Executors.newSingleThreadExecutor(); + private final LinkedList mPlotData = new LinkedList(); + private final Matrix mTransformMatrix = new Matrix(); + private final Paint mDrawPaint = new Paint(); + private final Paint mAxisLabelPaint = new Paint(); + private final Rect mPlotMargins = new Rect(); + + private CoordinateSystem mCoordinateSystem = CoordinateSystem.createLinearSystem(); + private RectF mViewPort = new RectF(); + private Bitmap mFrontBuffer; + private BackgroundDrawTask mBackgroundDrawTask; + private GestureDetector mPanGestureDetector; + private XYScaleGestureDetector mScaleGestureDetector; + private AxisRenderer mAxisRenderer; + private Rect mGraphArea; private RectF mViewPortBounds; + private Interpolator mAnimationInterpolator = null; + private RectF mAnimationDest; + private long mAnimationEndTime = 0; - public GraphView(Context context) { + public GraphView(Context context) + { super(context); mAxisRenderer = new SimpleAxisRenderer(getContext()); init(); - } + } - public GraphView(Context context, AttributeSet attrs) { - super(context, attrs); + public GraphView(Context context, AttributeSet attrs) + { + super(context, attrs); - TypedArray a = context.getTheme().obtainStyledAttributes( - attrs, - R.styleable.GraphView, - 0, 0); + TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.GraphView, 0, 0); - SimpleAxisRenderer axisRenderer = new SimpleAxisRenderer(getContext()); + mAxisRenderer = new SimpleAxisRenderer(getContext()); - axisRenderer.mAxisTickPaint.setColor(a.getInteger(R.styleable.GraphView_axisColor, Color.BLACK)); - axisRenderer.mAxisLabelPaint.setColor(a.getInteger(R.styleable.GraphView_axisColor, Color.DKGRAY)); + mAxisRenderer.setAxisColor(a.getInteger(R.styleable.GraphView_axisColor, Color.BLACK)); + mAxisRenderer.setLabelColor(a.getInteger(R.styleable.GraphView_axisColor, Color.DKGRAY)); a.recycle(); - mAxisRenderer = axisRenderer; init(); - } + } - private void init(){ + @Override + protected Parcelable onSaveInstanceState() + { + Bundle retval = new Bundle(); + retval.putParcelable(KEY_SUPERINSTANCE, super.onSaveInstanceState()); - mPanGestureDetector = new GestureDetector(mSimpleGestureListener); - mScaleGestureDetector = new XYScaleGestureDetector(getContext(), mSimpleScaleGestureListener); - mDrawPaint.setFilterBitmap(true); - mViewPort.set(0, 0, 1, 1); - mTransformMatrix.reset(); - - //defaults - mDrawXAxis = true; - mXAxisDevision = 1.0f; - mDrawYAxis = true; - mYAxisDevision = 1.0f; - mPlotMargins.set(20, 0, 0, 20); - mAxisColor = Color.DKGRAY; - mAxisLabelPaint.setColor(Color.DKGRAY); - mAxisLabelPaint.setTextSize(15.0f); - mAxisLabelPaint.setAntiAlias(true); - mBackgroundColor = Color.WHITE; + float[] viewportvalues = new float[4]; + viewportvalues[0] = mViewPort.left; + viewportvalues[1] = mViewPort.top; + viewportvalues[2] = mViewPort.right; + viewportvalues[3] = mViewPort.bottom; + retval.putFloatArray(KEY_VIEWPORT, viewportvalues); - //mZoomControls = new ZoomButtonsController(this); - //mZoomControls.setAutoDismissed(true); - //mZoomControls.setOnZoomListener(mZoomButtonListener); + return retval; } - public AxisRenderer getAxisRenderer() { - return mAxisRenderer; + @Override + protected void onRestoreInstanceState(Parcelable state) + { + Bundle bundle = (Bundle) state; + super.onRestoreInstanceState(bundle.getParcelable(KEY_SUPERINSTANCE)); + + float[] viewportvalues = bundle.getFloatArray(KEY_VIEWPORT); + mViewPort.left = viewportvalues[0]; + mViewPort.top = viewportvalues[1]; + mViewPort.right = viewportvalues[2]; + mViewPort.bottom = viewportvalues[3]; + drawFrame(mViewPort); } + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) + { + super.onSizeChanged(w, h, oldw, oldh); + + mGraphArea = mAxisRenderer.measureGraphArea(w, h); + mCoordinateSystem.interpolate(mViewPort, new RectF(0, 0, mGraphArea.width(), mGraphArea.height())); - @Override - protected Parcelable onSaveInstanceState() { - - Bundle retval = new Bundle(); - retval.putParcelable(KEY_SUPERINSTANCE, super.onSaveInstanceState()); - - float[] viewportvalues = new float[4]; - viewportvalues[0] = mViewPort.left; - viewportvalues[1] = mViewPort.top; - viewportvalues[2] = mViewPort.right; - viewportvalues[3] = mViewPort.bottom; - retval.putFloatArray(KEY_VIEWPORT, viewportvalues); - return retval; - } - - protected void onRestoreInstanceState (Parcelable state) { - Bundle bundle = (Bundle) state; - super.onRestoreInstanceState(bundle.getParcelable(KEY_SUPERINSTANCE)); - - float[] viewportvalues = bundle.getFloatArray(KEY_VIEWPORT); - mViewPort.left = viewportvalues[0]; - mViewPort.top = viewportvalues[1]; - mViewPort.right = viewportvalues[2]; - mViewPort.bottom = viewportvalues[3]; - drawFrame(mViewPort); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - //mZoomControls.setVisible(false); - } - - @Override - protected void onVisibilityChanged(View changedView, int visibility) { - super.onVisibilityChanged(changedView, visibility); - if(visibility != View.VISIBLE){ - //mZoomControls.setVisible(false); - } - } - - public void addSeries(DataRenderer series) { - mPlotData.add(series); - drawFrame(mViewPort); - } - - public void removeSeries(DataRenderer series) { - mPlotData.remove(series); - drawFrame(mViewPort); - } - - - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - - mGraphArea = mAxisRenderer.measureGraphArea(w, h); - mCoordinateSystem.interpolate(mViewPort, new RectF(0,0,mGraphArea.width(), mGraphArea.height())); - - drawFrame(mViewPort); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { + drawFrame(mViewPort); + } + @Override + public boolean onTouchEvent(MotionEvent event) + { cancelAnimation(); - //mZoomControls.setVisible(true); - - final int action = MotionEventCompat.getActionMasked(event); - switch(action){ - case MotionEvent.ACTION_UP: - doBoundsCheck(); - //updateViewport(); - break; - } - - boolean retval = mPanGestureDetector.onTouchEvent(event); - retval |= mScaleGestureDetector.onTouchEvent(event); - return retval; - } - - protected void updateViewport(){ - RectF newViewport = getDisplayViewPort(); - drawFrame(newViewport); - } - private Interpolator mAnimationInterpolator = null; - private long mAnimationEndTime = 0; - private static final long mAnimationTime = 1000; - private RectF mAnimationDest; - private void doAnimation() { - if(mAnimationInterpolator != null) { - long now = System.currentTimeMillis(); - if(mAnimationEndTime <= now) { - mAnimationInterpolator = null; - drawFrame(mAnimationDest); - return; - } - float done = 1 - ((float)(mAnimationEndTime - now) / mAnimationTime); - done = mAnimationInterpolator.getInterpolation(done); - RectF newViewport = new RectF(); - RectF currentViewport = getDisplayViewPort(); - newViewport.left = (1-done)*currentViewport.left + done*mAnimationDest.left; - newViewport.right = (1-done)*currentViewport.right + done*mAnimationDest.right; - newViewport.top = (1-done)*currentViewport.top + done*mAnimationDest.top; - newViewport.bottom = (1-done)*currentViewport.bottom + done*mAnimationDest.bottom; - drawFrame(newViewport); + final int action = MotionEventCompat.getActionMasked(event); + switch (action) + { + case MotionEvent.ACTION_UP: + doBoundsCheck(); + break; } + + boolean retval = mPanGestureDetector.onTouchEvent(event); + retval |= mScaleGestureDetector.onTouchEvent(event); + + return retval; } - private void cancelAnimation() { - mAnimationInterpolator = null; + + @Override + protected void onDraw(Canvas canvas) + { + doAnimation(); + if (mFrontBuffer != null) + { + canvas.save(); + canvas.translate(mGraphArea.left, mGraphArea.top); + canvas.drawBitmap(mFrontBuffer, mTransformMatrix, mDrawPaint); + canvas.restore(); + } + + mAxisRenderer.drawAxis(canvas, getMeasuredWidth(), getMeasuredHeight(), getDisplayViewPort(), getCoordinateSystem()); } - public void setViewportBounds(RectF bounds) { + public AxisRenderer getAxisRenderer() + { + return mAxisRenderer; + } + + public void addSeries(DataRenderer series) + { + mPlotData.add(series); + drawFrame(mViewPort); + } + + public void removeSeries(DataRenderer series) + { + mPlotData.remove(series); + drawFrame(mViewPort); + } + + public void setViewportBounds(RectF bounds) + { mViewPortBounds = bounds; } - public void doBoundsCheck() { - if(mViewPortBounds != null) { + public void doBoundsCheck() + { + if (mViewPortBounds != null) + { RectF newViewport = getDisplayViewPort(); - if(newViewport.width() > mViewPortBounds.width()){ + if (newViewport.width() > mViewPortBounds.width()) + { newViewport.left = mViewPortBounds.left; newViewport.right = mViewPortBounds.right; } - if(newViewport.height() > mViewPortBounds.height()){ + if (newViewport.height() > mViewPortBounds.height()) + { newViewport.top = mViewPortBounds.top; newViewport.bottom = mViewPortBounds.bottom; } - if(newViewport.left < mViewPortBounds.left) { + if (newViewport.left < mViewPortBounds.left) + { newViewport.offset(mViewPortBounds.left - newViewport.left, 0); } - if(newViewport.right > mViewPortBounds.right) { + if (newViewport.right > mViewPortBounds.right) + { newViewport.offset(mViewPortBounds.right - newViewport.right, 0); } - if(newViewport.bottom > mViewPortBounds.bottom) { + if (newViewport.bottom > mViewPortBounds.bottom) + { newViewport.offset(0, mViewPortBounds.bottom - newViewport.bottom); } - if(newViewport.top < mViewPortBounds.top) { + if (newViewport.top < mViewPortBounds.top) + { newViewport.offset(0, mViewPortBounds.top - newViewport.top); } @@ -277,298 +273,171 @@ public void doBoundsCheck() { } } - public RectF getDisplayViewPort(){ - RectF rect = new RectF(0,0,mGraphArea.width(), mGraphArea.height()); - - Matrix m = new Matrix(); - mTransformMatrix.invert(m); - m.postScale(1, -1); - m.postTranslate(0, mGraphArea.height()); - m.mapRect(rect); - - mCoordinateSystem.getInverse().mapRect(rect); - - return rect; - } - - public CoordinateSystem getCoordinateSystem() { - CoordinateSystem retval = mCoordinateSystem.copy(); - retval.interpolate(getDisplayViewPort(), new RectF(0,0,mGraphArea.width(),mGraphArea.height())); - return retval; - } - - public void setDisplayViewPort(RectF viewport) { - mTransformMatrix.reset(); - mViewPort = new RectF(viewport); - - if(mGraphArea != null) { + public RectF getDisplayViewPort() + { + RectF rect = new RectF(0, 0, mGraphArea.width(), mGraphArea.height()); + + Matrix m = new Matrix(); + mTransformMatrix.invert(m); + m.postScale(1, -1); + m.postTranslate(0, mGraphArea.height()); + m.mapRect(rect); + + mCoordinateSystem.getInverse().mapRect(rect); + + return rect; + } + + public CoordinateSystem getCoordinateSystem() + { + CoordinateSystem retval = mCoordinateSystem.copy(); + retval.interpolate(getDisplayViewPort(), new RectF(0, 0, mGraphArea.width(), mGraphArea.height())); + + return retval; + } + + public void setDisplayViewPort(RectF viewport) + { + mTransformMatrix.reset(); + mViewPort = new RectF(viewport); + + if (mGraphArea != null) + { mCoordinateSystem.interpolate(mViewPort, new RectF(0, 0, mGraphArea.width(), mGraphArea.height())); drawFrame(viewport); } - } - - @Override - protected void onDraw(Canvas canvas) { - doAnimation(); - if(mFrontBuffer != null){ - canvas.save(); - canvas.translate(mGraphArea.left, mGraphArea.top); - canvas.drawBitmap(mFrontBuffer, mTransformMatrix, mDrawPaint); - canvas.restore(); - } - mAxisRenderer.drawAxis(canvas, getMeasuredWidth(), getMeasuredHeight(), getDisplayViewPort(), getCoordinateSystem()); - } - - private void drawFrame(final RectF viewport) { - if(mBackgroundDrawTask != null){ - mBackgroundDrawTask.mCanceled = true; - } - mBackgroundDrawTask = new BackgroundDrawTask(viewport); - BackgroundTask.runBackgroundTask(mBackgroundDrawTask, mDrawThread); - } - - public static void drawBitmap(Canvas c, int width, int height, List data, - RectF viewport, - CoordinateSystem coordinateSystem) { + } - CoordinateSystem mCoordCopy = coordinateSystem.copy(); - mCoordCopy.interpolate(viewport, new RectF(0,0,width,height)); + public void updateViewport() + { + RectF newViewport = getDisplayViewPort(); + drawFrame(newViewport); + } - try { - c.save(); - c.scale(1, -1); - c.translate(0, -c.getHeight()); + private void init() + { + mPanGestureDetector = new GestureDetector(mSimpleGestureListener); + mScaleGestureDetector = new XYScaleGestureDetector(getContext(), mSimpleScaleGestureListener); + mDrawPaint.setFilterBitmap(true); + mViewPort.set(0, 0, 1, 1); + mTransformMatrix.reset(); - for(DataRenderer r : data){ - r.draw(c, viewport, mCoordCopy); - } - }finally { - c.restore(); - } + //defaults + mPlotMargins.set(20, 0, 0, 20); + mAxisLabelPaint.setColor(Color.DKGRAY); + mAxisLabelPaint.setTextSize(15.0f); + mAxisLabelPaint.setAntiAlias(true); } - private class BackgroundDrawTask extends BackgroundTask { - - private int width; - private int height; - private Bitmap mDrawBuffer; - private boolean mCanceled = false; - private final RectF viewport; - private ArrayList mData; - private CoordinateSystem mCoordCopy; - - public BackgroundDrawTask(RectF view){ - - this.viewport = new RectF(view); - if(mCoordinateSystem == null || mGraphArea == null){ - mCanceled = true; - return; - } - - this.width = mGraphArea.width(); - this.height = mGraphArea.height(); - this.mCoordCopy = mCoordinateSystem.copy(); - this.mCoordCopy.interpolate(viewport, new RectF(0,0,width,height)); - - - this.mData = new ArrayList(mPlotData); - } - - @Override - public void onBackground() { - if(!mCanceled){ - mDrawBuffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444); - Canvas c = new Canvas(mDrawBuffer); - - try { - c.save(); - c.scale(1, -1); - c.translate(0, -c.getHeight()); - - for(DataRenderer r : mData){ - r.draw(c, viewport, mCoordCopy); - } - }finally { - c.restore(); - } - - } - } - - @Override - public void onAfter() { - if(!mCanceled){ - mFrontBuffer = mDrawBuffer; - mViewPort = viewport; - mTransformMatrix.reset(); - mCoordinateSystem = mCoordCopy; - invalidate(); - } else if(mDrawBuffer != null) { - mDrawBuffer.recycle(); - } - mDrawBuffer = null; - } - - - } - - private GestureDetector.SimpleOnGestureListener mSimpleGestureListener = new GestureDetector.SimpleOnGestureListener(){ - - @Override - public boolean onDown(MotionEvent e) { - return true; - } - - - - @Override - public boolean onDoubleTap(MotionEvent e) { - //autoScaleDomainAndRange(); - mTransformMatrix.postScale(1.3f, 1.3f, e.getX(), e.getY()); - invalidate(); - updateViewport(); - return true; - } - - - - @Override - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - mTransformMatrix.postTranslate(-distanceX, -distanceY); - invalidate(); - updateViewport(); - return true; - } - - }; - - private XYScaleGestureDetector.SimpleOnScaleGestureListener mSimpleScaleGestureListener = new XYScaleGestureDetector.SimpleOnScaleGestureListener(){ - - @Override - public boolean onScale(XYScaleGestureDetector detector) { - //float scale = detector.getScaleFactor(); - - mTransformMatrix.postScale(detector.getXScaleFactor(), detector.getYScaleFactor(), detector.getFocusX(), detector.getFocusY()); - invalidate(); - updateViewport(); - return true; - - } - - }; - - public static double roundToSignificantFigures(double num, int n) { - if(num == 0) { - return 0; - } - - final double d = Math.ceil(Math.log10(num < 0 ? -num: num)); - final int power = n - (int) d; - - final double magnitude = Math.pow(10, power); - final long shifted = Math.round(num*magnitude); - return shifted/magnitude; - } - - public static RectF getSeriesLimits(Series series) { - RectF retval = new RectF(); - retval.set(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, - Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY); - - Iterator it = series.createIterator(); - while(it.hasNext()){ - float[] point = it.next(); - retval.left = Math.min(retval.left, point[0]); - retval.right = Math.max(retval.right, point[0]); - retval.top = Math.min(retval.top, point[1]); - retval.bottom = Math.max(retval.bottom, point[1]); - } - - return retval; - } - - public void autoScaleDomainAndRange() { - - - /* - BackgroundTask.runBackgroundTask(new BackgroundTask() { - - RectF viewport = new RectF(); - - @Override - public void onBackground() { - viewport.set(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, - Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY); - for(Series series : mSeries){ - Iterator it = series.createIterator(); - while(it.hasNext()){ - float[] point = it.next(); - viewport.left = Math.min(viewport.left, point[0]); - viewport.right = Math.max(viewport.right, point[0]); - viewport.top = Math.min(viewport.top, point[1]); - viewport.bottom = Math.max(viewport.bottom, point[1]); - } - } - - RectF screen = new RectF(mPlotMargins.left, mPlotMargins.top, getMeasuredWidth(),getMeasuredHeight()-mPlotMargins.height()); - Matrix matrix = new Matrix(); - getViewportToScreenMatrix(screen, viewport).invert(matrix); - matrix.mapRect(viewport, new RectF(0,0,getMeasuredWidth(), getMeasuredHeight())); - - - } - - @Override - public void onAfter() { - drawFrame(viewport); - } - - }, mDrawThread); - */ - - } - - public void zoomInCenter() { - cancelAnimation(); - float scale = 1.3f; - mTransformMatrix.postScale(scale, scale, getMeasuredWidth()/2, getMeasuredHeight()/2); - invalidate(); - updateViewport(); - } - - public void zoomOutCenter() { - cancelAnimation(); - float scale = 0.7f; - mTransformMatrix.postScale(scale, scale, getMeasuredWidth()/2, getMeasuredHeight()/2); - invalidate(); - updateViewport(); - new Handler(Looper.getMainLooper()).postDelayed(new Runnable(){ - - @Override - public void run() { - doBoundsCheck(); + private void doAnimation() + { + if (mAnimationInterpolator != null) + { + long now = System.currentTimeMillis(); + if (mAnimationEndTime <= now) + { + mAnimationInterpolator = null; + drawFrame(mAnimationDest); + return; } - }, 1000); - } + float done = 1 - ((float) (mAnimationEndTime - now) / mAnimationTime); + done = mAnimationInterpolator.getInterpolation(done); + RectF newViewport = new RectF(); + RectF currentViewport = getDisplayViewPort(); + newViewport.left = (1 - done) * currentViewport.left + done * mAnimationDest.left; + newViewport.right = (1 - done) * currentViewport.right + done * mAnimationDest.right; + newViewport.top = (1 - done) * currentViewport.top + done * mAnimationDest.top; + newViewport.bottom = (1 - done) * currentViewport.bottom + done * mAnimationDest.bottom; + drawFrame(newViewport); + } + } - private ZoomButtonsController.OnZoomListener mZoomButtonListener = new ZoomButtonsController.OnZoomListener(){ + private void cancelAnimation() + { + mAnimationInterpolator = null; + } - @Override - public void onVisibilityChanged(boolean visible) {} + private void drawFrame(final RectF viewport) + { + if (mBackgroundDrawTask != null) + { + mBackgroundDrawTask.mCanceled = true; + } - @Override - public void onZoom(boolean zoomIn) { - if(zoomIn) { - zoomInCenter(); - } else { - zoomOutCenter(); - } + mBackgroundDrawTask = new BackgroundDrawTask(viewport); + BackgroundTask.runBackgroundTask(mBackgroundDrawTask, mDrawThread); + } - } + private final class BackgroundDrawTask extends BackgroundTask + { + private int width; + private int height; + private Bitmap mDrawBuffer; + private boolean mCanceled = false; + private final RectF viewport; + private ArrayList mData; + private CoordinateSystem mCoordCopy; + + public BackgroundDrawTask(RectF view) + { + this.viewport = new RectF(view); + if (mCoordinateSystem == null || mGraphArea == null) + { + mCanceled = true; + return; + } - }; + this.width = mGraphArea.width(); + this.height = mGraphArea.height(); + this.mCoordCopy = mCoordinateSystem.copy(); + this.mCoordCopy.interpolate(viewport, new RectF(0, 0, width, height)); + this.mData = new ArrayList(mPlotData); + } + @Override + public void onBackground() + { + if (!mCanceled) + { + mDrawBuffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444); + Canvas c = new Canvas(mDrawBuffer); + + try + { + c.save(); + c.scale(1, -1); + c.translate(0, -c.getHeight()); + + for (DataRenderer r : mData) + { + r.draw(c, viewport, mCoordCopy); + } + } + finally + { + c.restore(); + } + } + } -} + @Override + public void onAfter() + { + if (!mCanceled) + { + mFrontBuffer = mDrawBuffer; + mViewPort = viewport; + mTransformMatrix.reset(); + mCoordinateSystem = mCoordCopy; + invalidate(); + } + else if (mDrawBuffer != null) + { + mDrawBuffer.recycle(); + } + mDrawBuffer = null; + } + } +} \ No newline at end of file diff --git a/src/com/devsmart/plotter/LineGraphDataRenderer.java b/src/com/devsmart/plotter/LineGraphDataRenderer.java index 77350aa..160aea5 100644 --- a/src/com/devsmart/plotter/LineGraphDataRenderer.java +++ b/src/com/devsmart/plotter/LineGraphDataRenderer.java @@ -8,7 +8,7 @@ public class LineGraphDataRenderer implements DataRenderer { - protected Paint mPointPaint = new Paint(); + protected final Paint mPointPaint = new Paint(); protected Series mSeries; public LineGraphDataRenderer(Series series, int color) { @@ -70,7 +70,13 @@ public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem){ } } - + + @Override + public void setPaintColor(int color) + { + mPointPaint.setColor(color); + } + private boolean fillPixelBin(RectF pixelBin, PeekableIterator it) { boolean retval = false; float[] point; diff --git a/src/com/devsmart/plotter/OversampleFunctionRenderer.java b/src/com/devsmart/plotter/OversampleFunctionRenderer.java index 5415d16..06e42d5 100644 --- a/src/com/devsmart/plotter/OversampleFunctionRenderer.java +++ b/src/com/devsmart/plotter/OversampleFunctionRenderer.java @@ -1,6 +1,5 @@ package com.devsmart.plotter; - import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; @@ -8,71 +7,67 @@ import java.util.Arrays; -public class OversampleFunctionRenderer implements DataRenderer { - - private static class MinMax { - double min = Double.NaN; - double max = Double.NaN; - - public void addValue(double value){ - if(value < min || Double.isNaN(min)){ - min = value; - } - - if(value > max || Double.isNaN(max)){ - max = value; - } - } - - public void clear() { - min = Double.NaN; - max = Double.NaN; - } - - } - +public final class OversampleFunctionRenderer implements DataRenderer +{ private final FunctionRenderer2.GraphFunction mFunction; + private final Paint mPaint = new Paint(); + private final MinMax mMinMax = new MinMax(); + private final float[] mPoints = new float[4]; private double[] mSamplePoints; private double mSampleRate; - protected Paint mPaint = new Paint(); - private MinMax mMinMax = new MinMax(); - private float[] mPoints = new float[4]; - public OversampleFunctionRenderer(FunctionRenderer2.GraphFunction f, double[] samplePoints, int color) { + public OversampleFunctionRenderer(FunctionRenderer2.GraphFunction f, double[] samplePoints, int color) + { mFunction = f; mSamplePoints = new double[samplePoints.length]; System.arraycopy(samplePoints, 0, mSamplePoints, 0, mSamplePoints.length); Arrays.sort(mSamplePoints); - mPaint.setColor(color); - mPaint.setStrokeWidth(2.0f); - mPaint.setAntiAlias(true); - mPaint.setStyle(Paint.Style.STROKE); + + initPaint(color); } - public OversampleFunctionRenderer(FunctionRenderer2.GraphFunction f, double sampleRate, int color){ + public OversampleFunctionRenderer(FunctionRenderer2.GraphFunction f, double sampleRate, int color) + { mFunction = f; mSampleRate = sampleRate; - mPaint.setColor(color); - mPaint.setStrokeWidth(2.0f); - mPaint.setAntiAlias(true); - mPaint.setStyle(Paint.Style.STROKE); + + initPaint(color); } @Override - public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { - if(mSamplePoints != null){ + public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) + { + if (mSamplePoints != null) + { drawUsingSamplePoints(canvas, viewPort, coordSystem); - } else { + } + else + { drawUsingSamplerate(canvas, viewPort, coordSystem); } } - private void drawUsingSamplerate(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { + @Override + public void setPaintColor(int color) + { + mPaint.setColor(color); + } + + private void initPaint(int color) + { + mPaint.setColor(color); + mPaint.setStrokeWidth(2.0f); + mPaint.setAntiAlias(true); + mPaint.setStyle(Paint.Style.STROKE); + } + + private void drawUsingSamplerate(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) + { float[] points = new float[2]; - final double pixelWidth = viewPort.width() / (double)canvas.getWidth(); + final double pixelWidth = viewPort.width() / (double) canvas.getWidth(); mMinMax.clear(); - double lastX = viewPort.left-pixelWidth; + double lastX = viewPort.left - pixelWidth; Path p = new Path(); @@ -81,11 +76,13 @@ private void drawUsingSamplerate(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem.mapPoints(points); p.moveTo(points[0], points[1]); - for(double x=viewPort.left;x<=viewPort.right;x+=mSampleRate){ + for (double x = viewPort.left; x <= viewPort.right; x += mSampleRate) + { final double y = mFunction.value(x); mMinMax.addValue(y); - if(x >= lastX+pixelWidth){ + if (x >= lastX + pixelWidth) + { drawLine(p, (float) x, coordSystem); lastX = x; mMinMax.clear(); @@ -95,40 +92,48 @@ private void drawUsingSamplerate(Canvas canvas, RectF viewPort, CoordinateSystem canvas.drawPath(p, mPaint); } - private void drawLine(Path path, float x, CoordinateSystem coordSystem) { + private void drawLine(Path path, float x, CoordinateSystem coordSystem) + { mPoints[0] = x; - mPoints[1] = (float)mMinMax.min; + mPoints[1] = (float) mMinMax.min; mPoints[2] = x; - mPoints[3] = (float)mMinMax.max; + mPoints[3] = (float) mMinMax.max; coordSystem.mapPoints(mPoints); - if(FunctionRenderer2.isRealNumber(mPoints[0]) && FunctionRenderer2.isRealNumber(mPoints[1])) { + if (FunctionRenderer2.isRealNumber(mPoints[0]) && FunctionRenderer2.isRealNumber(mPoints[1])) + { path.lineTo(mPoints[0], mPoints[1]); } - if(FunctionRenderer2.isRealNumber(mPoints[2]) && FunctionRenderer2.isRealNumber(mPoints[3])) { + if (FunctionRenderer2.isRealNumber(mPoints[2]) && FunctionRenderer2.isRealNumber(mPoints[3])) + { path.lineTo(mPoints[2], mPoints[3]); } path.moveTo(mPoints[0], mPoints[1]); } - private void drawUsingSamplePoints(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { + private void drawUsingSamplePoints(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) + { float[] points = new float[2]; - final double pixelWidth = viewPort.width() / (double)canvas.getWidth(); + final double pixelWidth = viewPort.width() / (double) canvas.getWidth(); int start = Arrays.binarySearch(mSamplePoints, viewPort.left); - if(start < 0) { + if (start < 0) + { start = -start - 2; } - if(start < 0){ + if (start < 0) + { start = 0; } int end = Arrays.binarySearch(mSamplePoints, viewPort.right); - if(end < 0) { + if (end < 0) + { end = -end; } - if(end >= mSamplePoints.length) { + if (end >= mSamplePoints.length) + { end = mSamplePoints.length; } @@ -141,12 +146,14 @@ private void drawUsingSamplePoints(Canvas canvas, RectF viewPort, CoordinateSyst coordSystem.mapPoints(points); p.moveTo(points[0], points[1]); - for(int i=start+1;i= lastX+pixelWidth){ + if (x >= lastX + pixelWidth) + { drawLine(p, (float) x, coordSystem); lastX = x; mMinMax.clear(); @@ -155,4 +162,29 @@ private void drawUsingSamplePoints(Canvas canvas, RectF viewPort, CoordinateSyst canvas.drawPath(p, mPaint); } -} + + private static class MinMax + { + double min = Double.NaN; + double max = Double.NaN; + + public void addValue(double value) + { + if (value < min || Double.isNaN(min)) + { + min = value; + } + + if (value > max || Double.isNaN(max)) + { + max = value; + } + } + + public void clear() + { + min = Double.NaN; + max = Double.NaN; + } + } +} \ No newline at end of file diff --git a/src/com/devsmart/plotter/PointRenderer.java b/src/com/devsmart/plotter/PointRenderer.java index 298821d..e652f75 100644 --- a/src/com/devsmart/plotter/PointRenderer.java +++ b/src/com/devsmart/plotter/PointRenderer.java @@ -8,7 +8,7 @@ public class PointRenderer implements DataRenderer { private float[] mPoints; - private Paint mPaint = new Paint(); + private final Paint mPaint = new Paint(); public PointRenderer(float[] points, int color) { mPoints = points; @@ -32,4 +32,10 @@ public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { } } } + + @Override + public void setPaintColor(int color) + { + mPaint.setColor(color); + } } diff --git a/src/com/devsmart/plotter/SimpleAxisRenderer.java b/src/com/devsmart/plotter/SimpleAxisRenderer.java index 74e755d..09bb469 100644 --- a/src/com/devsmart/plotter/SimpleAxisRenderer.java +++ b/src/com/devsmart/plotter/SimpleAxisRenderer.java @@ -11,217 +11,201 @@ import android.util.DisplayMetrics; import android.util.TypedValue; -import java.math.BigDecimal; - -public class SimpleAxisRenderer implements AxisRenderer { - - int numDivisions = 5; - boolean mDrawXAxis = true; - boolean mDrawYAxis = true; - int mAxisColor = Color.BLACK; - Rect mPlotMargins = new Rect(20, 0, 0, 20); - public Paint mAxisLabelPaint = new Paint(); - public Paint mAxisTickPaint = new Paint(); - String mXAxisLabel = "Wavelength"; - String mYAxisLabel = "Intensity"; - - DisplayMetrics mDisplayMetrics; - - public SimpleAxisRenderer(Context context) { - mDisplayMetrics = context.getResources().getDisplayMetrics(); - - mAxisLabelPaint.setColor(Color.BLACK); - mAxisLabelPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 15, mDisplayMetrics)); - mAxisLabelPaint.setAntiAlias(true); +public final class SimpleAxisRenderer implements AxisRenderer +{ + private int numDivisions = 5; + private boolean mDrawXAxis = true; + private boolean mDrawYAxis = true; + private Rect mPlotMargins = new Rect(20, 0, 0, 20); + private final Paint mAxisLabelPaint = new Paint(); + private final Paint mAxisTickPaint = new Paint(); + private String mXAxisLabel = "Wavelength"; + private String mYAxisLabel = "Intensity"; + private final DisplayMetrics mDisplayMetrics; + private float[] mYAxis; + private float[] mXAxis; + private float[] points = new float[4]; + private Rect bounds = new Rect(); + private Rect graphArea = new Rect(); + private Matrix m = new Matrix(); + + public SimpleAxisRenderer(Context context) + { + mDisplayMetrics = context.getResources().getDisplayMetrics(); + + init(); + } - mAxisTickPaint.setColor(Color.DKGRAY); - mAxisTickPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 10, mDisplayMetrics)); - mAxisTickPaint.setAntiAlias(true); + public SimpleAxisRenderer(GraphView graphview) + { + mDisplayMetrics = graphview.getContext().getResources().getDisplayMetrics(); + init(); } - public SimpleAxisRenderer(GraphView graphview) { - mDisplayMetrics = graphview.getContext().getResources().getDisplayMetrics(); - - mAxisLabelPaint.setColor(Color.BLACK); - mAxisLabelPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 15, mDisplayMetrics)); - mAxisLabelPaint.setAntiAlias(true); - - mAxisTickPaint.setColor(Color.DKGRAY); - mAxisTickPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 10, mDisplayMetrics)); - mAxisTickPaint.setAntiAlias(true); - - } + @Override + public void setAxisColor(int color) + { + mAxisTickPaint.setColor(color); + } @Override - public void setAxisColor(int color) { + public void setLabelColor(int color) + { mAxisLabelPaint.setColor(color); - mAxisTickPaint.setColor(color); } @Override - public void setYAxisLabel(String label){ + public void setYAxisLabel(String label) + { mYAxisLabel = label; } @Override - public void setXAxisLabel(String label) { + public void setXAxisLabel(String label) + { mXAxisLabel = label; } - - private float[] mYAxis; - private float[] mXAxis; - float[] points = new float[4]; - Rect bounds = new Rect(); - RectF boundsf = new RectF(); - Rect graphArea = new Rect(); - - protected void calcBounds(final int canvasWidth, final int canvasHeight) { - mAxisLabelPaint.getTextBounds("1", 0, 1, bounds); - float axisLabelHeight = bounds.height(); - - mAxisTickPaint.getTextBounds("1", 0, 1, bounds); - float tickLabelHeight = bounds.height(); - - float axisLabelBoundery = axisLabelHeight + tickLabelHeight + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3, mDisplayMetrics); - - - float height = canvasHeight - axisLabelBoundery - mPlotMargins.height(); - - mYAxis = new float[]{axisLabelBoundery + mPlotMargins.left, mPlotMargins.top, - axisLabelBoundery + mPlotMargins.left, mPlotMargins.top + height}; - - mXAxis = new float[]{axisLabelBoundery + mPlotMargins.left, canvasHeight - axisLabelBoundery - mPlotMargins.bottom, - canvasWidth - mPlotMargins.right, canvasHeight - axisLabelBoundery - mPlotMargins.bottom}; - } - - - Matrix m = new Matrix(); - - @Override - public void drawAxis(Canvas canvas, final int canvasWidth, final int canvasHeight, RectF viewPort, CoordinateSystem coordSystem) { - - measureGraphArea(canvasWidth, canvasHeight); - - m.setRectToRect(new RectF(0,0,graphArea.width(),graphArea.height()), new RectF(graphArea), ScaleToFit.FILL); - m.postScale(1, -1); - m.postTranslate(0, graphArea.height()); - - //Debug axis display - //canvas.drawText(viewPort.toString(), 50, 50, mAxisTickPaint); - - if(mDrawXAxis) { - - //draw axis - canvas.drawLines(mXAxis, mAxisTickPaint); - - //draw label - mAxisLabelPaint.getTextBounds(mXAxisLabel, 0, mXAxisLabel.length(), bounds); - float y = canvasHeight - mPlotMargins.bottom + bounds.bottom + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3, mDisplayMetrics); - canvas.drawText(mXAxisLabel, (mXAxis[2]-mXAxis[0])/2 - bounds.width()/2 + mXAxis[0], y, mAxisLabelPaint); - - //draw ticks - final float dist = viewPort.width() / numDivisions; - float xPoint = (float) (dist * Math.floor(viewPort.left / dist)); - while(xPoint < viewPort.right+dist){ - points[0] = xPoint; - points[1] = 0; - points[2] = xPoint; - points[3] = 0; - coordSystem.mapPoints(points); - m.mapPoints(points); - points[1] = mXAxis[1]; - points[3] = mXAxis[1] - TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, mDisplayMetrics); - - if(points[0] >= mXAxis[0]) { - canvas.drawLines(points, mAxisTickPaint); - - String label = getTickLabel(xPoint); - mAxisTickPaint.getTextBounds(label, 0, label.length(), bounds); - - - canvas.drawText(label, - points[0]-bounds.width()/2, - points[1] + bounds.height() + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, mDisplayMetrics), - mAxisTickPaint); - } - - - - - xPoint += dist; - - } - } - - if(mDrawYAxis){ - - - - //draw Y axis - canvas.drawLines(mYAxis, mAxisTickPaint); - - //draw label - mAxisLabelPaint.getTextBounds(mYAxisLabel, 0, mYAxisLabel.length(), bounds); - canvas.save(); - points[0] = mPlotMargins.left; - points[1] = (mYAxis[3] - mYAxis[1])/2 + bounds.width()/2; - canvas.rotate(-90, points[0], points[1]); - canvas.drawText(mYAxisLabel, points[0], points[1], mAxisLabelPaint); - canvas.restore(); - - final float dist = viewPort.height() / numDivisions; - float yPoint = (float) (dist * Math.floor(viewPort.top / dist)); - while(yPoint < viewPort.bottom+dist){ - points[0] = 0; - points[1] = yPoint; - points[2] = 0; - points[3] = yPoint; - coordSystem.mapPoints(points); - m.mapPoints(points); - points[0] = mYAxis[0]; - points[2] = mYAxis[0] + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, mDisplayMetrics); - - if(points[1] <= mYAxis[3]) { - canvas.drawLines(points, mAxisTickPaint); - - String label = getTickLabel(yPoint); - mAxisTickPaint.getTextBounds(label, 0, label.length(), bounds); - canvas.save(); - points[2] = points[0]-bounds.height()/2-TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, mDisplayMetrics); - points[3] = points[1]+bounds.width()/2; - canvas.rotate(-90, points[2], points[3]); - canvas.drawText(label, - points[2], points[3], - mAxisTickPaint); - canvas.restore(); - } - - yPoint += dist; - } - - } - - } - - protected String getTickLabel(float value) { - return String.format("%g", value); - //return String.valueOf(MathUtils.round(value, 1)); - } - - - - @Override - public Rect measureGraphArea(int screenWidth, int screenHeight) { - calcBounds(screenWidth, screenHeight); - - graphArea.left = (int) Math.floor(mXAxis[0]); - graphArea.right = (int) Math.ceil(mXAxis[2]); - graphArea.top = (int) Math.floor(mYAxis[1]); - graphArea.bottom = (int) Math.ceil(mYAxis[3]); - return graphArea; - } - - - -} + + @Override + public void drawAxis(Canvas canvas, final int canvasWidth, final int canvasHeight, RectF viewPort, CoordinateSystem coordSystem) + { + measureGraphArea(canvasWidth, canvasHeight); + + m.setRectToRect(new RectF(0, 0, graphArea.width(), graphArea.height()), new RectF(graphArea), ScaleToFit.FILL); + m.postScale(1, -1); + m.postTranslate(0, graphArea.height()); + + //Debug axis display + //canvas.drawText(viewPort.toString(), 50, 50, mAxisTickPaint); + + if (mDrawXAxis) + { + //draw axis + canvas.drawLines(mXAxis, mAxisTickPaint); + + //draw label + mAxisLabelPaint.getTextBounds(mXAxisLabel, 0, mXAxisLabel.length(), bounds); + float y = canvasHeight - mPlotMargins.bottom + bounds.bottom + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3, mDisplayMetrics); + canvas.drawText(mXAxisLabel, (mXAxis[2] - mXAxis[0]) / 2 - bounds.width() / 2 + mXAxis[0], y, mAxisLabelPaint); + + //draw ticks + final float dist = viewPort.width() / numDivisions; + float xPoint = (float) (dist * Math.floor(viewPort.left / dist)); + while (xPoint < viewPort.right + dist) + { + points[0] = xPoint; + points[1] = 0; + points[2] = xPoint; + points[3] = 0; + coordSystem.mapPoints(points); + m.mapPoints(points); + points[1] = mXAxis[1]; + points[3] = mXAxis[1] - TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, mDisplayMetrics); + + if (points[0] >= mXAxis[0]) + { + canvas.drawLines(points, mAxisTickPaint); + + String label = getTickLabel(xPoint); + mAxisTickPaint.getTextBounds(label, 0, label.length(), bounds); + + canvas.drawText(label, points[0] - bounds.width() / 2, points[1] + bounds.height() + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, mDisplayMetrics), mAxisTickPaint); + } + + xPoint += dist; + } + } + + if (mDrawYAxis) + { + //draw Y axis + canvas.drawLines(mYAxis, mAxisTickPaint); + + //draw label + mAxisLabelPaint.getTextBounds(mYAxisLabel, 0, mYAxisLabel.length(), bounds); + canvas.save(); + points[0] = mPlotMargins.left; + points[1] = (mYAxis[3] - mYAxis[1]) / 2 + bounds.width() / 2; + canvas.rotate(-90, points[0], points[1]); + canvas.drawText(mYAxisLabel, points[0], points[1], mAxisLabelPaint); + canvas.restore(); + + final float dist = viewPort.height() / numDivisions; + float yPoint = (float) (dist * Math.floor(viewPort.top / dist)); + while (yPoint < viewPort.bottom + dist) + { + points[0] = 0; + points[1] = yPoint; + points[2] = 0; + points[3] = yPoint; + coordSystem.mapPoints(points); + m.mapPoints(points); + points[0] = mYAxis[0]; + points[2] = mYAxis[0] + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, mDisplayMetrics); + + if (points[1] <= mYAxis[3]) + { + canvas.drawLines(points, mAxisTickPaint); + + String label = getTickLabel(yPoint); + mAxisTickPaint.getTextBounds(label, 0, label.length(), bounds); + canvas.save(); + points[2] = points[0] - bounds.height() / 2 - TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, mDisplayMetrics); + points[3] = points[1] + bounds.width() / 2; + canvas.rotate(-90, points[2], points[3]); + canvas.drawText(label, points[2], points[3], mAxisTickPaint); + canvas.restore(); + } + + yPoint += dist; + } + } + } + + @Override + public Rect measureGraphArea(int screenWidth, int screenHeight) + { + calcBounds(screenWidth, screenHeight); + + graphArea.left = (int) Math.floor(mXAxis[0]); + graphArea.right = (int) Math.ceil(mXAxis[2]); + graphArea.top = (int) Math.floor(mYAxis[1]); + graphArea.bottom = (int) Math.ceil(mYAxis[3]); + + return graphArea; + } + + private void init() + { + mAxisLabelPaint.setColor(Color.BLACK); + mAxisLabelPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 15, mDisplayMetrics)); + mAxisLabelPaint.setAntiAlias(true); + + mAxisTickPaint.setColor(Color.DKGRAY); + mAxisTickPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 10, mDisplayMetrics)); + mAxisTickPaint.setAntiAlias(true); + } + + private void calcBounds(final int canvasWidth, final int canvasHeight) + { + mAxisLabelPaint.getTextBounds("1", 0, 1, bounds); + float axisLabelHeight = bounds.height(); + + mAxisTickPaint.getTextBounds("1", 0, 1, bounds); + float tickLabelHeight = bounds.height(); + + float axisLabelBoundery = axisLabelHeight + tickLabelHeight + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3, mDisplayMetrics); + + float height = canvasHeight - axisLabelBoundery - mPlotMargins.height(); + + mYAxis = new float[]{axisLabelBoundery + mPlotMargins.left, mPlotMargins.top, axisLabelBoundery + mPlotMargins.left, mPlotMargins.top + height}; + + mXAxis = new float[]{axisLabelBoundery + mPlotMargins.left, canvasHeight - axisLabelBoundery - mPlotMargins.bottom, canvasWidth - mPlotMargins.right, canvasHeight - axisLabelBoundery - mPlotMargins.bottom}; + } + + private String getTickLabel(float value) + { + return String.format("%g", value); + } +} \ No newline at end of file From dfe3cb61b65c1f3599ac7ca63b57109db9b8426d Mon Sep 17 00:00:00 2001 From: Stephen Gowen Date: Mon, 13 Apr 2015 17:28:48 -0500 Subject: [PATCH 40/44] Undoing my braces --- src/com/devsmart/plotter/AxisRenderer.java | 3 +- src/com/devsmart/plotter/DataRenderer.java | 3 +- .../devsmart/plotter/FunctionRenderer.java | 70 +++---- .../devsmart/plotter/FunctionRenderer2.java | 18 +- src/com/devsmart/plotter/GraphView.java | 168 ++++++----------- .../plotter/LineGraphDataRenderer.java | 172 +++++++++--------- src/com/devsmart/plotter/PointRenderer.java | 12 +- src/com/devsmart/plotter/Series.java | 8 +- .../devsmart/plotter/SimpleAxisRenderer.java | 54 ++---- src/com/devsmart/plotter/SimpleSeries.java | 17 +- 10 files changed, 201 insertions(+), 324 deletions(-) diff --git a/src/com/devsmart/plotter/AxisRenderer.java b/src/com/devsmart/plotter/AxisRenderer.java index ffd01d4..0441c4c 100644 --- a/src/com/devsmart/plotter/AxisRenderer.java +++ b/src/com/devsmart/plotter/AxisRenderer.java @@ -4,8 +4,7 @@ import android.graphics.Rect; import android.graphics.RectF; -public interface AxisRenderer -{ +public interface AxisRenderer { /** * Measure the area where the graph data will be drawn. Return a Rect * in screen coordinates. diff --git a/src/com/devsmart/plotter/DataRenderer.java b/src/com/devsmart/plotter/DataRenderer.java index 78d2d00..dc6eeff 100644 --- a/src/com/devsmart/plotter/DataRenderer.java +++ b/src/com/devsmart/plotter/DataRenderer.java @@ -3,8 +3,7 @@ import android.graphics.Canvas; import android.graphics.RectF; -public interface DataRenderer -{ +public interface DataRenderer { void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem); void setPaintColor(int color); diff --git a/src/com/devsmart/plotter/FunctionRenderer.java b/src/com/devsmart/plotter/FunctionRenderer.java index ce8d2bb..ee034aa 100644 --- a/src/com/devsmart/plotter/FunctionRenderer.java +++ b/src/com/devsmart/plotter/FunctionRenderer.java @@ -6,10 +6,8 @@ import android.graphics.Path; import android.graphics.RectF; -public class FunctionRenderer implements DataRenderer -{ - public interface GraphFunction - { +public class FunctionRenderer implements DataRenderer { + public interface GraphFunction { double value(double x); } @@ -22,8 +20,7 @@ public interface GraphFunction float[] lastPoint = new float[2]; double[] yMinMax = new double[2]; - public FunctionRenderer(GraphFunction f, double[] sampleLocations, int color) - { + public FunctionRenderer(GraphFunction f, double[] sampleLocations, int color) { mFunction = f; mSampleLocations = sampleLocations; mPointPaint.setColor(color); @@ -32,8 +29,7 @@ public FunctionRenderer(GraphFunction f, double[] sampleLocations, int color) mPointPaint.setStyle(Paint.Style.STROKE); } - public FunctionRenderer(GraphFunction f, double samplerate, int color) - { + public FunctionRenderer(GraphFunction f, double samplerate, int color) { mFunction = f; mSampleRate = samplerate; mPointPaint.setColor(color); @@ -42,8 +38,7 @@ public FunctionRenderer(GraphFunction f, double samplerate, int color) mPointPaint.setStyle(Paint.Style.STROKE); } - private void drawFixedSample(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) - { + private void drawFixedSample(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { //reset min max yMinMax[0] = Double.MAX_VALUE; yMinMax[1] = Double.MIN_VALUE; @@ -59,14 +54,12 @@ private void drawFixedSample(Canvas canvas, RectF viewPort, CoordinateSystem coo p.moveTo(points[0], points[1]); double startPix = viewPort.left; - for (double x = startPix; x < viewPort.right; x += stepWidth) - { + for (double x = startPix; x < viewPort.right; x += stepWidth) { final double y = mFunction.value(x); yMinMax[0] = Math.min(yMinMax[0], y); yMinMax[1] = Math.max(yMinMax[1], y); - if (x >= startPix + pixelWidth) - { + if (x >= startPix + pixelWidth) { //min points[0] = (float) startPix; @@ -97,43 +90,35 @@ private void drawFixedSample(Canvas canvas, RectF viewPort, CoordinateSystem coo canvas.drawPath(p, mPointPaint); } - private class MinMax - { + private class MinMax { double min; double max; - public MinMax() - { + public MinMax() { reset(); } - public void reset() - { + public void reset() { min = Double.MAX_VALUE; max = Double.MIN_VALUE; } - public void add(float value) - { + public void add(float value) { min = Math.min(min, value); max = Math.max(max, value); } } - private void drawAtSampleLocations(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) - { + private void drawAtSampleLocations(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { Paint pointPaint = new Paint(); pointPaint.setColor(Color.RED); int sampleindex = 0; - for (int i = 0; i < mSampleLocations.length; i++) - { - if (mSampleLocations[i] >= viewPort.left) - { + for (int i = 0; i < mSampleLocations.length; i++) { + if (mSampleLocations[i] >= viewPort.left) { sampleindex = i; - if (i > 0) - { + if (i > 0) { sampleindex = i - 1; } break; @@ -164,10 +149,8 @@ private void drawAtSampleLocations(Canvas canvas, RectF viewPort, CoordinateSyst double startPix = mSampleLocations[sampleindex]; double x = 0; - while (true) - { - if (sampleindex >= mSampleLocations.length - 1 || (x = mSampleLocations[sampleindex++ + 1]) > viewPort.right) - { + while (true) { + if (sampleindex >= mSampleLocations.length - 1 || (x = mSampleLocations[sampleindex++ + 1]) > viewPort.right) { break; } @@ -253,14 +236,12 @@ private void drawAtSampleLocations(Canvas canvas, RectF viewPort, CoordinateSyst yMinMax[1] = Double.MIN_VALUE; final double stepWidth = Math.min(pixelWidth, 1.0 / mSampleRate); startPix = viewPort.left; - for (x = startPix; x < viewPort.right; x += stepWidth) - { + for (x = startPix; x < viewPort.right; x += stepWidth) { final double y = mFunction.value(x); yMinMax[0] = Math.min(yMinMax[0], y); yMinMax[1] = Math.max(yMinMax[1], y); - if (x >= startPix + pixelWidth) - { + if (x >= startPix + pixelWidth) { //min points[0] = (float) startPix; @@ -292,21 +273,16 @@ private void drawAtSampleLocations(Canvas canvas, RectF viewPort, CoordinateSyst } @Override - public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) - { - if (mSampleLocations == null) - { + public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { + if (mSampleLocations == null) { drawFixedSample(canvas, viewPort, coordSystem); - } - else - { + } else { drawAtSampleLocations(canvas, viewPort, coordSystem); } } @Override - public void setPaintColor(int color) - { + public void setPaintColor(int color) { mPointPaint.setColor(color); } } \ No newline at end of file diff --git a/src/com/devsmart/plotter/FunctionRenderer2.java b/src/com/devsmart/plotter/FunctionRenderer2.java index cd7ef98..bc4e1f5 100644 --- a/src/com/devsmart/plotter/FunctionRenderer2.java +++ b/src/com/devsmart/plotter/FunctionRenderer2.java @@ -1,6 +1,5 @@ package com.devsmart.plotter; - import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; @@ -16,7 +15,7 @@ public interface GraphFunction { protected final Paint mPaint = new Paint(); - public FunctionRenderer2(GraphFunction f, int color){ + public FunctionRenderer2(GraphFunction f, int color) { mFunction = f; mPaint.setColor(color); mPaint.setStrokeWidth(2.0f); @@ -32,17 +31,17 @@ public static boolean isRealNumber(float f) { public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { float[] points = new float[2]; - final double pixelWidth = viewPort.width() / (double)canvas.getWidth(); + final double pixelWidth = viewPort.width() / (double) canvas.getWidth(); Path p = new Path(); - for(double x=viewPort.left;x<=viewPort.right;x+=pixelWidth){ + for (double x = viewPort.left; x <= viewPort.right; x += pixelWidth) { final double y = mFunction.value(x); - points[0] = (float)x; - points[1] = (float)y; + points[0] = (float) x; + points[1] = (float) y; coordSystem.mapPoints(points); - if(isRealNumber(points[0]) && isRealNumber(points[1])) { + if (isRealNumber(points[0]) && isRealNumber(points[1])) { if (x == viewPort.left) { p.moveTo(points[0], points[1]); } else { @@ -55,8 +54,7 @@ public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { } @Override - public void setPaintColor(int color) - { + public void setPaintColor(int color) { mPaint.setColor(color); } -} +} \ No newline at end of file diff --git a/src/com/devsmart/plotter/GraphView.java b/src/com/devsmart/plotter/GraphView.java index f978972..7db3e61 100644 --- a/src/com/devsmart/plotter/GraphView.java +++ b/src/com/devsmart/plotter/GraphView.java @@ -27,26 +27,20 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -public final class GraphView extends View -{ - public static void drawBitmap(Canvas c, int width, int height, List data, RectF viewport, CoordinateSystem coordinateSystem) - { +public final class GraphView extends View { + public static void drawBitmap(Canvas c, int width, int height, List data, RectF viewport, CoordinateSystem coordinateSystem) { CoordinateSystem mCoordCopy = coordinateSystem.copy(); mCoordCopy.interpolate(viewport, new RectF(0, 0, width, height)); - try - { + try { c.save(); c.scale(1, -1); c.translate(0, -c.getHeight()); - for (DataRenderer r : data) - { + for (DataRenderer r : data) { r.draw(c, viewport, mCoordCopy); } - } - finally - { + } finally { c.restore(); } } @@ -55,17 +49,14 @@ public static void drawBitmap(Canvas c, int width, int height, List mViewPortBounds.width()) - { + if (newViewport.width() > mViewPortBounds.width()) { newViewport.left = mViewPortBounds.left; newViewport.right = mViewPortBounds.right; } - if (newViewport.height() > mViewPortBounds.height()) - { + if (newViewport.height() > mViewPortBounds.height()) { newViewport.top = mViewPortBounds.top; newViewport.bottom = mViewPortBounds.bottom; } - if (newViewport.left < mViewPortBounds.left) - { + if (newViewport.left < mViewPortBounds.left) { newViewport.offset(mViewPortBounds.left - newViewport.left, 0); } - if (newViewport.right > mViewPortBounds.right) - { + if (newViewport.right > mViewPortBounds.right) { newViewport.offset(mViewPortBounds.right - newViewport.right, 0); } - if (newViewport.bottom > mViewPortBounds.bottom) - { + if (newViewport.bottom > mViewPortBounds.bottom) { newViewport.offset(0, mViewPortBounds.bottom - newViewport.bottom); } - if (newViewport.top < mViewPortBounds.top) - { + if (newViewport.top < mViewPortBounds.top) { newViewport.offset(0, mViewPortBounds.top - newViewport.top); } @@ -273,8 +240,7 @@ public void doBoundsCheck() } } - public RectF getDisplayViewPort() - { + public RectF getDisplayViewPort() { RectF rect = new RectF(0, 0, mGraphArea.width(), mGraphArea.height()); Matrix m = new Matrix(); @@ -288,34 +254,29 @@ public RectF getDisplayViewPort() return rect; } - public CoordinateSystem getCoordinateSystem() - { + public CoordinateSystem getCoordinateSystem() { CoordinateSystem retval = mCoordinateSystem.copy(); retval.interpolate(getDisplayViewPort(), new RectF(0, 0, mGraphArea.width(), mGraphArea.height())); return retval; } - public void setDisplayViewPort(RectF viewport) - { + public void setDisplayViewPort(RectF viewport) { mTransformMatrix.reset(); mViewPort = new RectF(viewport); - if (mGraphArea != null) - { + if (mGraphArea != null) { mCoordinateSystem.interpolate(mViewPort, new RectF(0, 0, mGraphArea.width(), mGraphArea.height())); drawFrame(viewport); } } - public void updateViewport() - { + public void updateViewport() { RectF newViewport = getDisplayViewPort(); drawFrame(newViewport); } - private void init() - { + private void init() { mPanGestureDetector = new GestureDetector(mSimpleGestureListener); mScaleGestureDetector = new XYScaleGestureDetector(getContext(), mSimpleScaleGestureListener); mDrawPaint.setFilterBitmap(true); @@ -329,13 +290,10 @@ private void init() mAxisLabelPaint.setAntiAlias(true); } - private void doAnimation() - { - if (mAnimationInterpolator != null) - { + private void doAnimation() { + if (mAnimationInterpolator != null) { long now = System.currentTimeMillis(); - if (mAnimationEndTime <= now) - { + if (mAnimationEndTime <= now) { mAnimationInterpolator = null; drawFrame(mAnimationDest); return; @@ -353,15 +311,12 @@ private void doAnimation() } } - private void cancelAnimation() - { + private void cancelAnimation() { mAnimationInterpolator = null; } - private void drawFrame(final RectF viewport) - { - if (mBackgroundDrawTask != null) - { + private void drawFrame(final RectF viewport) { + if (mBackgroundDrawTask != null) { mBackgroundDrawTask.mCanceled = true; } @@ -369,8 +324,7 @@ private void drawFrame(final RectF viewport) BackgroundTask.runBackgroundTask(mBackgroundDrawTask, mDrawThread); } - private final class BackgroundDrawTask extends BackgroundTask - { + private final class BackgroundDrawTask extends BackgroundTask { private int width; private int height; private Bitmap mDrawBuffer; @@ -379,11 +333,9 @@ private final class BackgroundDrawTask extends BackgroundTask private ArrayList mData; private CoordinateSystem mCoordCopy; - public BackgroundDrawTask(RectF view) - { + public BackgroundDrawTask(RectF view) { this.viewport = new RectF(view); - if (mCoordinateSystem == null || mGraphArea == null) - { + if (mCoordinateSystem == null || mGraphArea == null) { mCanceled = true; return; } @@ -397,44 +349,34 @@ public BackgroundDrawTask(RectF view) } @Override - public void onBackground() - { - if (!mCanceled) - { + public void onBackground() { + if (!mCanceled) { mDrawBuffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444); Canvas c = new Canvas(mDrawBuffer); - try - { + try { c.save(); c.scale(1, -1); c.translate(0, -c.getHeight()); - for (DataRenderer r : mData) - { + for (DataRenderer r : mData) { r.draw(c, viewport, mCoordCopy); } - } - finally - { + } finally { c.restore(); } } } @Override - public void onAfter() - { - if (!mCanceled) - { + public void onAfter() { + if (!mCanceled) { mFrontBuffer = mDrawBuffer; mViewPort = viewport; mTransformMatrix.reset(); mCoordinateSystem = mCoordCopy; invalidate(); - } - else if (mDrawBuffer != null) - { + } else if (mDrawBuffer != null) { mDrawBuffer.recycle(); } mDrawBuffer = null; diff --git a/src/com/devsmart/plotter/LineGraphDataRenderer.java b/src/com/devsmart/plotter/LineGraphDataRenderer.java index 160aea5..132b23a 100644 --- a/src/com/devsmart/plotter/LineGraphDataRenderer.java +++ b/src/com/devsmart/plotter/LineGraphDataRenderer.java @@ -8,93 +8,85 @@ public class LineGraphDataRenderer implements DataRenderer { - protected final Paint mPointPaint = new Paint(); - protected Series mSeries; - - public LineGraphDataRenderer(Series series, int color) { - mSeries = series; - mPointPaint.setColor(color); - mPointPaint.setStrokeWidth(2.0f); - } - - - RectF pixel = new RectF(); - RectF pixelBin = new RectF(); - - public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem){ - - - final float xBinWidth = viewPort.width()/canvas.getWidth(); - pixelBin.left = viewPort.left-xBinWidth; - pixelBin.right = viewPort.left; - pixelBin.bottom = Float.POSITIVE_INFINITY; - pixelBin.top = Float.NEGATIVE_INFINITY; - - float[] lastpoint = new float[]{Float.NaN, Float.NaN}; - - PeekableIterator it = new PeekableIterator(mSeries.createIterator()); - - - //findPixelBinLessThan(pixelBin, it); - while(it.hasNext()){ - float[] point = it.next(); - lastpoint[0] = point[0]; - lastpoint[1] = point[1]; - if(it.peek()[0] > viewPort.left){ - break; - } - } - - coordSystem.mapPoints(lastpoint); - - boolean findOneMore = false; - while(it.hasNext()){ - pixelBin.offset(xBinWidth, 0); - pixelBin.bottom = Float.POSITIVE_INFINITY; - pixelBin.top = Float.NEGATIVE_INFINITY; - - if(fillPixelBin(pixelBin, it)){ - //draw pixel - coordSystem.mapRect(pixel, pixelBin); - canvas.drawLine(lastpoint[0], lastpoint[1], pixel.left, pixel.top, mPointPaint); - lastpoint[0] = pixel.left; - lastpoint[1] = pixel.top; - if(findOneMore) { - break; - } - } - if(it.peek() != null && it.peek()[0] > viewPort.right){ - findOneMore = true; - } - - } - - } - - @Override - public void setPaintColor(int color) - { - mPointPaint.setColor(color); - } - - private boolean fillPixelBin(RectF pixelBin, PeekableIterator it) { - boolean retval = false; - float[] point; - while(it.hasNext()){ - point = it.peek(); - if(point[0] > pixelBin.right) { - break; - } - - if(point[0] >= pixelBin.left) { - pixelBin.bottom = Math.min(pixelBin.bottom, point[1]); - pixelBin.top = Math.max(pixelBin.top, point[1]); - retval = true; - } - it.next(); - } - return retval; - } - - -} + protected final Paint mPointPaint = new Paint(); + protected Series mSeries; + + public LineGraphDataRenderer(Series series, int color) { + mSeries = series; + mPointPaint.setColor(color); + mPointPaint.setStrokeWidth(2.0f); + } + + RectF pixel = new RectF(); + RectF pixelBin = new RectF(); + + public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { + final float xBinWidth = viewPort.width() / canvas.getWidth(); + pixelBin.left = viewPort.left - xBinWidth; + pixelBin.right = viewPort.left; + pixelBin.bottom = Float.POSITIVE_INFINITY; + pixelBin.top = Float.NEGATIVE_INFINITY; + + float[] lastpoint = new float[]{Float.NaN, Float.NaN}; + + PeekableIterator it = new PeekableIterator(mSeries.createIterator()); + + + //findPixelBinLessThan(pixelBin, it); + while (it.hasNext()) { + float[] point = it.next(); + lastpoint[0] = point[0]; + lastpoint[1] = point[1]; + if (it.peek()[0] > viewPort.left) { + break; + } + } + + coordSystem.mapPoints(lastpoint); + + boolean findOneMore = false; + while (it.hasNext()) { + pixelBin.offset(xBinWidth, 0); + pixelBin.bottom = Float.POSITIVE_INFINITY; + pixelBin.top = Float.NEGATIVE_INFINITY; + + if (fillPixelBin(pixelBin, it)) { + //draw pixel + coordSystem.mapRect(pixel, pixelBin); + canvas.drawLine(lastpoint[0], lastpoint[1], pixel.left, pixel.top, mPointPaint); + lastpoint[0] = pixel.left; + lastpoint[1] = pixel.top; + if (findOneMore) { + break; + } + } + if (it.peek() != null && it.peek()[0] > viewPort.right) { + findOneMore = true; + } + } + } + + @Override + public void setPaintColor(int color) { + mPointPaint.setColor(color); + } + + private boolean fillPixelBin(RectF pixelBin, PeekableIterator it) { + boolean retval = false; + float[] point; + while (it.hasNext()) { + point = it.peek(); + if (point[0] > pixelBin.right) { + break; + } + + if (point[0] >= pixelBin.left) { + pixelBin.bottom = Math.min(pixelBin.bottom, point[1]); + pixelBin.top = Math.max(pixelBin.top, point[1]); + retval = true; + } + it.next(); + } + return retval; + } +} \ No newline at end of file diff --git a/src/com/devsmart/plotter/PointRenderer.java b/src/com/devsmart/plotter/PointRenderer.java index e652f75..1244008 100644 --- a/src/com/devsmart/plotter/PointRenderer.java +++ b/src/com/devsmart/plotter/PointRenderer.java @@ -4,7 +4,6 @@ import android.graphics.Paint; import android.graphics.RectF; - public class PointRenderer implements DataRenderer { private float[] mPoints; @@ -22,10 +21,10 @@ public PointRenderer(float[] points, int color) { public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { float[] point = new float[2]; - for(int i=0;i createIterator(); -} + Iterator createIterator(); +} \ No newline at end of file diff --git a/src/com/devsmart/plotter/SimpleAxisRenderer.java b/src/com/devsmart/plotter/SimpleAxisRenderer.java index 09bb469..a8e5cea 100644 --- a/src/com/devsmart/plotter/SimpleAxisRenderer.java +++ b/src/com/devsmart/plotter/SimpleAxisRenderer.java @@ -11,8 +11,7 @@ import android.util.DisplayMetrics; import android.util.TypedValue; -public final class SimpleAxisRenderer implements AxisRenderer -{ +public final class SimpleAxisRenderer implements AxisRenderer { private int numDivisions = 5; private boolean mDrawXAxis = true; private boolean mDrawYAxis = true; @@ -29,47 +28,40 @@ public final class SimpleAxisRenderer implements AxisRenderer private Rect graphArea = new Rect(); private Matrix m = new Matrix(); - public SimpleAxisRenderer(Context context) - { + public SimpleAxisRenderer(Context context) { mDisplayMetrics = context.getResources().getDisplayMetrics(); init(); } - public SimpleAxisRenderer(GraphView graphview) - { + public SimpleAxisRenderer(GraphView graphview) { mDisplayMetrics = graphview.getContext().getResources().getDisplayMetrics(); init(); } @Override - public void setAxisColor(int color) - { + public void setAxisColor(int color) { mAxisTickPaint.setColor(color); } @Override - public void setLabelColor(int color) - { + public void setLabelColor(int color) { mAxisLabelPaint.setColor(color); } @Override - public void setYAxisLabel(String label) - { + public void setYAxisLabel(String label) { mYAxisLabel = label; } @Override - public void setXAxisLabel(String label) - { + public void setXAxisLabel(String label) { mXAxisLabel = label; } @Override - public void drawAxis(Canvas canvas, final int canvasWidth, final int canvasHeight, RectF viewPort, CoordinateSystem coordSystem) - { + public void drawAxis(Canvas canvas, final int canvasWidth, final int canvasHeight, RectF viewPort, CoordinateSystem coordSystem) { measureGraphArea(canvasWidth, canvasHeight); m.setRectToRect(new RectF(0, 0, graphArea.width(), graphArea.height()), new RectF(graphArea), ScaleToFit.FILL); @@ -79,8 +71,7 @@ public void drawAxis(Canvas canvas, final int canvasWidth, final int canvasHeigh //Debug axis display //canvas.drawText(viewPort.toString(), 50, 50, mAxisTickPaint); - if (mDrawXAxis) - { + if (mDrawXAxis) { //draw axis canvas.drawLines(mXAxis, mAxisTickPaint); @@ -92,8 +83,7 @@ public void drawAxis(Canvas canvas, final int canvasWidth, final int canvasHeigh //draw ticks final float dist = viewPort.width() / numDivisions; float xPoint = (float) (dist * Math.floor(viewPort.left / dist)); - while (xPoint < viewPort.right + dist) - { + while (xPoint < viewPort.right + dist) { points[0] = xPoint; points[1] = 0; points[2] = xPoint; @@ -103,8 +93,7 @@ public void drawAxis(Canvas canvas, final int canvasWidth, final int canvasHeigh points[1] = mXAxis[1]; points[3] = mXAxis[1] - TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, mDisplayMetrics); - if (points[0] >= mXAxis[0]) - { + if (points[0] >= mXAxis[0]) { canvas.drawLines(points, mAxisTickPaint); String label = getTickLabel(xPoint); @@ -117,8 +106,7 @@ public void drawAxis(Canvas canvas, final int canvasWidth, final int canvasHeigh } } - if (mDrawYAxis) - { + if (mDrawYAxis) { //draw Y axis canvas.drawLines(mYAxis, mAxisTickPaint); @@ -133,8 +121,7 @@ public void drawAxis(Canvas canvas, final int canvasWidth, final int canvasHeigh final float dist = viewPort.height() / numDivisions; float yPoint = (float) (dist * Math.floor(viewPort.top / dist)); - while (yPoint < viewPort.bottom + dist) - { + while (yPoint < viewPort.bottom + dist) { points[0] = 0; points[1] = yPoint; points[2] = 0; @@ -144,8 +131,7 @@ public void drawAxis(Canvas canvas, final int canvasWidth, final int canvasHeigh points[0] = mYAxis[0]; points[2] = mYAxis[0] + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, mDisplayMetrics); - if (points[1] <= mYAxis[3]) - { + if (points[1] <= mYAxis[3]) { canvas.drawLines(points, mAxisTickPaint); String label = getTickLabel(yPoint); @@ -164,8 +150,7 @@ public void drawAxis(Canvas canvas, final int canvasWidth, final int canvasHeigh } @Override - public Rect measureGraphArea(int screenWidth, int screenHeight) - { + public Rect measureGraphArea(int screenWidth, int screenHeight) { calcBounds(screenWidth, screenHeight); graphArea.left = (int) Math.floor(mXAxis[0]); @@ -176,8 +161,7 @@ public Rect measureGraphArea(int screenWidth, int screenHeight) return graphArea; } - private void init() - { + private void init() { mAxisLabelPaint.setColor(Color.BLACK); mAxisLabelPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 15, mDisplayMetrics)); mAxisLabelPaint.setAntiAlias(true); @@ -187,8 +171,7 @@ private void init() mAxisTickPaint.setAntiAlias(true); } - private void calcBounds(final int canvasWidth, final int canvasHeight) - { + private void calcBounds(final int canvasWidth, final int canvasHeight) { mAxisLabelPaint.getTextBounds("1", 0, 1, bounds); float axisLabelHeight = bounds.height(); @@ -204,8 +187,7 @@ private void calcBounds(final int canvasWidth, final int canvasHeight) mXAxis = new float[]{axisLabelBoundery + mPlotMargins.left, canvasHeight - axisLabelBoundery - mPlotMargins.bottom, canvasWidth - mPlotMargins.right, canvasHeight - axisLabelBoundery - mPlotMargins.bottom}; } - private String getTickLabel(float value) - { + private String getTickLabel(float value) { return String.format("%g", value); } } \ No newline at end of file diff --git a/src/com/devsmart/plotter/SimpleSeries.java b/src/com/devsmart/plotter/SimpleSeries.java index b618a11..46c5d5f 100644 --- a/src/com/devsmart/plotter/SimpleSeries.java +++ b/src/com/devsmart/plotter/SimpleSeries.java @@ -3,17 +3,12 @@ import java.util.ArrayList; import java.util.Iterator; -import android.graphics.RectF; - public class SimpleSeries implements Series { - - public ArrayList mData = new ArrayList(); - - @Override - public Iterator createIterator() { - return mData.iterator(); - } - + public ArrayList mData = new ArrayList(); -} + @Override + public Iterator createIterator() { + return mData.iterator(); + } +} \ No newline at end of file From a0ba12322940f67c2f44792be8bb472c5dbcc1c0 Mon Sep 17 00:00:00 2001 From: Stephen Gowen Date: Mon, 13 Apr 2015 21:00:10 -0500 Subject: [PATCH 41/44] Undoing braces and adding LineRenderer --- src/com/devsmart/plotter/LineRenderer.java | 51 ++++++++++++ .../plotter/OversampleFunctionRenderer.java | 79 ++++++------------- 2 files changed, 77 insertions(+), 53 deletions(-) create mode 100644 src/com/devsmart/plotter/LineRenderer.java diff --git a/src/com/devsmart/plotter/LineRenderer.java b/src/com/devsmart/plotter/LineRenderer.java new file mode 100644 index 0000000..d4a7330 --- /dev/null +++ b/src/com/devsmart/plotter/LineRenderer.java @@ -0,0 +1,51 @@ +package com.devsmart.plotter; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; + +import java.util.List; + +/** + * Created by sgowen on 4/13/15. + */ +public final class LineRenderer implements DataRenderer { + public static class XYPair { + public float x; + public float y; + + public XYPair(float x, float y) { + this.x = x; + this.y = y; + } + } + + private final List mLinesFromOriginList; + private final Paint mPaint = new Paint(); + + public LineRenderer(List linesFromOriginList, int color) { + mLinesFromOriginList = linesFromOriginList; + mPaint.setColor(color); + mPaint.setStrokeWidth(2.0f); + mPaint.setAntiAlias(true); + mPaint.setStyle(Paint.Style.STROKE); + } + + @Override + public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { + float[] point = new float[2]; + for (XYPair xyPair : mLinesFromOriginList) { + if (viewPort.contains(xyPair.x, xyPair.y)) { + point[0] = xyPair.x; + point[1] = xyPair.y; + coordSystem.mapPoints(point); + canvas.drawLine(point[0], 0, point[0], point[1], mPaint); + } + } + } + + @Override + public void setPaintColor(int color) { + mPaint.setColor(color); + } +} \ No newline at end of file diff --git a/src/com/devsmart/plotter/OversampleFunctionRenderer.java b/src/com/devsmart/plotter/OversampleFunctionRenderer.java index 06e42d5..16bdc57 100644 --- a/src/com/devsmart/plotter/OversampleFunctionRenderer.java +++ b/src/com/devsmart/plotter/OversampleFunctionRenderer.java @@ -7,8 +7,7 @@ import java.util.Arrays; -public final class OversampleFunctionRenderer implements DataRenderer -{ +public final class OversampleFunctionRenderer implements DataRenderer { private final FunctionRenderer2.GraphFunction mFunction; private final Paint mPaint = new Paint(); private final MinMax mMinMax = new MinMax(); @@ -16,8 +15,7 @@ public final class OversampleFunctionRenderer implements DataRenderer private double[] mSamplePoints; private double mSampleRate; - public OversampleFunctionRenderer(FunctionRenderer2.GraphFunction f, double[] samplePoints, int color) - { + public OversampleFunctionRenderer(FunctionRenderer2.GraphFunction f, double[] samplePoints, int color) { mFunction = f; mSamplePoints = new double[samplePoints.length]; System.arraycopy(samplePoints, 0, mSamplePoints, 0, mSamplePoints.length); @@ -26,8 +24,7 @@ public OversampleFunctionRenderer(FunctionRenderer2.GraphFunction f, double[] sa initPaint(color); } - public OversampleFunctionRenderer(FunctionRenderer2.GraphFunction f, double sampleRate, int color) - { + public OversampleFunctionRenderer(FunctionRenderer2.GraphFunction f, double sampleRate, int color) { mFunction = f; mSampleRate = sampleRate; @@ -35,34 +32,27 @@ public OversampleFunctionRenderer(FunctionRenderer2.GraphFunction f, double samp } @Override - public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) - { - if (mSamplePoints != null) - { + public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { + if (mSamplePoints != null) { drawUsingSamplePoints(canvas, viewPort, coordSystem); - } - else - { + } else { drawUsingSamplerate(canvas, viewPort, coordSystem); } } @Override - public void setPaintColor(int color) - { + public void setPaintColor(int color) { mPaint.setColor(color); } - private void initPaint(int color) - { + private void initPaint(int color) { mPaint.setColor(color); mPaint.setStrokeWidth(2.0f); mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.STROKE); } - private void drawUsingSamplerate(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) - { + private void drawUsingSamplerate(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { float[] points = new float[2]; final double pixelWidth = viewPort.width() / (double) canvas.getWidth(); @@ -76,13 +66,11 @@ private void drawUsingSamplerate(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem.mapPoints(points); p.moveTo(points[0], points[1]); - for (double x = viewPort.left; x <= viewPort.right; x += mSampleRate) - { + for (double x = viewPort.left; x <= viewPort.right; x += mSampleRate) { final double y = mFunction.value(x); mMinMax.addValue(y); - if (x >= lastX + pixelWidth) - { + if (x >= lastX + pixelWidth) { drawLine(p, (float) x, coordSystem); lastX = x; mMinMax.clear(); @@ -92,48 +80,40 @@ private void drawUsingSamplerate(Canvas canvas, RectF viewPort, CoordinateSystem canvas.drawPath(p, mPaint); } - private void drawLine(Path path, float x, CoordinateSystem coordSystem) - { + private void drawLine(Path path, float x, CoordinateSystem coordSystem) { mPoints[0] = x; mPoints[1] = (float) mMinMax.min; mPoints[2] = x; mPoints[3] = (float) mMinMax.max; coordSystem.mapPoints(mPoints); - if (FunctionRenderer2.isRealNumber(mPoints[0]) && FunctionRenderer2.isRealNumber(mPoints[1])) - { + if (FunctionRenderer2.isRealNumber(mPoints[0]) && FunctionRenderer2.isRealNumber(mPoints[1])) { path.lineTo(mPoints[0], mPoints[1]); } - if (FunctionRenderer2.isRealNumber(mPoints[2]) && FunctionRenderer2.isRealNumber(mPoints[3])) - { + if (FunctionRenderer2.isRealNumber(mPoints[2]) && FunctionRenderer2.isRealNumber(mPoints[3])) { path.lineTo(mPoints[2], mPoints[3]); } path.moveTo(mPoints[0], mPoints[1]); } - private void drawUsingSamplePoints(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) - { + private void drawUsingSamplePoints(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { float[] points = new float[2]; final double pixelWidth = viewPort.width() / (double) canvas.getWidth(); int start = Arrays.binarySearch(mSamplePoints, viewPort.left); - if (start < 0) - { + if (start < 0) { start = -start - 2; } - if (start < 0) - { + if (start < 0) { start = 0; } int end = Arrays.binarySearch(mSamplePoints, viewPort.right); - if (end < 0) - { + if (end < 0) { end = -end; } - if (end >= mSamplePoints.length) - { + if (end >= mSamplePoints.length) { end = mSamplePoints.length; } @@ -146,14 +126,12 @@ private void drawUsingSamplePoints(Canvas canvas, RectF viewPort, CoordinateSyst coordSystem.mapPoints(points); p.moveTo(points[0], points[1]); - for (int i = start + 1; i < end; i++) - { + for (int i = start + 1; i < end; i++) { double x = mSamplePoints[i]; final double y = mFunction.value(x); mMinMax.addValue(y); - if (x >= lastX + pixelWidth) - { + if (x >= lastX + pixelWidth) { drawLine(p, (float) x, coordSystem); lastX = x; mMinMax.clear(); @@ -163,26 +141,21 @@ private void drawUsingSamplePoints(Canvas canvas, RectF viewPort, CoordinateSyst canvas.drawPath(p, mPaint); } - private static class MinMax - { + private static class MinMax { double min = Double.NaN; double max = Double.NaN; - public void addValue(double value) - { - if (value < min || Double.isNaN(min)) - { + public void addValue(double value) { + if (value < min || Double.isNaN(min)) { min = value; } - if (value > max || Double.isNaN(max)) - { + if (value > max || Double.isNaN(max)) { max = value; } } - public void clear() - { + public void clear() { min = Double.NaN; max = Double.NaN; } From 642eebcb6c39296dcb42fff73cec27bc632932ce Mon Sep 17 00:00:00 2001 From: Stephen Gowen Date: Mon, 13 Apr 2015 21:49:08 -0500 Subject: [PATCH 42/44] Tweaking LineRender to handle the origin correctly (though I'm not entirely confident this is good enough yet) --- src/com/devsmart/plotter/LineRenderer.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/com/devsmart/plotter/LineRenderer.java b/src/com/devsmart/plotter/LineRenderer.java index d4a7330..10b6b6a 100644 --- a/src/com/devsmart/plotter/LineRenderer.java +++ b/src/com/devsmart/plotter/LineRenderer.java @@ -34,12 +34,14 @@ public LineRenderer(List linesFromOriginList, int color) { @Override public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { float[] point = new float[2]; + float[] origin = {0, 0}; + coordSystem.mapPoints(origin); for (XYPair xyPair : mLinesFromOriginList) { - if (viewPort.contains(xyPair.x, xyPair.y)) { + if (viewPort.contains(xyPair.x, 0)) { point[0] = xyPair.x; point[1] = xyPair.y; coordSystem.mapPoints(point); - canvas.drawLine(point[0], 0, point[0], point[1], mPaint); + canvas.drawLine(point[0], origin[0], point[0], point[1], mPaint); } } } From a4eda30b83f0b4d27096a315730a67999a272dc7 Mon Sep 17 00:00:00 2001 From: Stephen Gowen Date: Mon, 13 Apr 2015 21:50:59 -0500 Subject: [PATCH 43/44] That contains method is actually just making me mad, haha --- src/com/devsmart/plotter/LineRenderer.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/com/devsmart/plotter/LineRenderer.java b/src/com/devsmart/plotter/LineRenderer.java index 10b6b6a..dd83502 100644 --- a/src/com/devsmart/plotter/LineRenderer.java +++ b/src/com/devsmart/plotter/LineRenderer.java @@ -37,12 +37,10 @@ public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { float[] origin = {0, 0}; coordSystem.mapPoints(origin); for (XYPair xyPair : mLinesFromOriginList) { - if (viewPort.contains(xyPair.x, 0)) { - point[0] = xyPair.x; - point[1] = xyPair.y; - coordSystem.mapPoints(point); - canvas.drawLine(point[0], origin[0], point[0], point[1], mPaint); - } + point[0] = xyPair.x; + point[1] = xyPair.y; + coordSystem.mapPoints(point); + canvas.drawLine(point[0], origin[0], point[0], point[1], mPaint); } } From f6399d6640ce18174f82cce8a360998d4cae325c Mon Sep 17 00:00:00 2001 From: Stephen Gowen Date: Wed, 15 Apr 2015 21:46:49 -0500 Subject: [PATCH 44/44] Fixing line renderer wackiness --- src/com/devsmart/plotter/LineRenderer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/devsmart/plotter/LineRenderer.java b/src/com/devsmart/plotter/LineRenderer.java index dd83502..3942c11 100644 --- a/src/com/devsmart/plotter/LineRenderer.java +++ b/src/com/devsmart/plotter/LineRenderer.java @@ -26,7 +26,7 @@ public XYPair(float x, float y) { public LineRenderer(List linesFromOriginList, int color) { mLinesFromOriginList = linesFromOriginList; mPaint.setColor(color); - mPaint.setStrokeWidth(2.0f); + mPaint.setStrokeWidth(1.0f); mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.STROKE); } @@ -40,7 +40,7 @@ public void draw(Canvas canvas, RectF viewPort, CoordinateSystem coordSystem) { point[0] = xyPair.x; point[1] = xyPair.y; coordSystem.mapPoints(point); - canvas.drawLine(point[0], origin[0], point[0], point[1], mPaint); + canvas.drawLine(point[0], origin[1], point[0], point[1], mPaint); } }