Android Open Source - line-chart-view Line Chart View






From Project

Back to project page line-chart-view.

License

The source code is released under:

MIT License

If you think the Android project line-chart-view listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package org.hogel.android.linechartview;
/*w w  w  .java2s.c o m*/
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.Shape;
import android.util.AttributeSet;
import android.view.View;

import java.util.ArrayList;
import java.util.List;

public class LineChartView extends View {

    private static final long DEFAULT_MAX_X = 1000;

    private static final long DEFAULT_MAX_Y = 1000;

    public static class Point {
        private long x;

        private long y;

        public Point() {
        }

        public Point(long x, long y) {
            this.x = x;
            this.y = y;
        }

        public long getX() {
            return x;
        }

        public void setX(long x) {
            this.x = x;
        }

        public long getY() {
            return y;
        }

        public void setY(long y) {
            this.y = y;
        }
    }

    protected final List<Point> points;

    protected final Paint paint = new Paint();

    protected final Paint labelPaint = new Paint();

    protected final Paint borderPaint = new Paint();

    protected final ShapeDrawable chartDrawable;

    protected final ShapeDrawable yLabelDrawable;

    protected final ShapeDrawable xLabelDrawable;

    protected LineChartStyle lineChartStyle;

    protected Long manualXGridUnit = null;

    protected Long manualYGridUnit = null;

    protected long yLabelWidth = 0;

    protected long xLabelHeight = 0;

    protected long chartTopMargin = 0;

    protected long chartRightMargin = 0;

    protected List<Long> manualXLabels = null;

    protected List<Long> manualYLabels = null;

    protected Long manualMinX = null;

    protected Long manualMaxX = null;

    protected Long manualMinY = null;

    protected Long manualMaxY = null;

    public LineChartView(Context context) {
        this(context, new ArrayList<Point>());
    }

    public LineChartView(Context context, AttributeSet attrs) {
        super(context, attrs);

        points = new ArrayList<>();
        lineChartStyle = new LineChartStyle();

        paint.setAntiAlias(true);

        yLabelDrawable = new ShapeDrawable();
        xLabelDrawable = new ShapeDrawable();

        chartDrawable = new ShapeDrawable();

        updateIfEditMode();
        updateDrawables();
    }

    public LineChartView(Context context, List<Point> points) {
        this(context, points, new LineChartStyle());
    }

    public LineChartView(Context context, LineChartStyle lineChartStyle) {
        this(context, new ArrayList<Point>(), lineChartStyle);
    }

    public LineChartView(Context context, List<Point> points, LineChartStyle lineChartStyle) {
        super(context);
        this.points = points;
        this.lineChartStyle = lineChartStyle;
        paint.setAntiAlias(true);

        yLabelDrawable = new ShapeDrawable();
        xLabelDrawable = new ShapeDrawable();

        chartDrawable = new ShapeDrawable();
        updateDrawables();
    }

    public void updateDrawables() {
        drawXLabels(xLabelDrawable);
        drawYLabels(yLabelDrawable);
        drawLineChart(chartDrawable);
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        yLabelDrawable.draw(canvas);
        xLabelDrawable.draw(canvas);
        chartDrawable.draw(canvas);
    }

    protected void drawYLabels(ShapeDrawable labelDrawable) {
        Shape labelsShape = new Shape() {
            @Override
            public void draw(Canvas canvas, Paint paint) {
                labelPaint.setTextAlign(Paint.Align.RIGHT);
                labelPaint.setTextSize(lineChartStyle.getLabelTextSize());
                labelPaint.setColor(lineChartStyle.getLabelTextColor());

                long minY = getMinY();
                long maxY = getMaxY();
                long yrange = maxY - minY;

                float height = getHeight();

                float left = getYLabelWidth();
                List<Long> yLabels = getYLabels();
                for (long y : yLabels) {
                    String label = formatYLabel(y);
                    float yCoordinate = getYCoordinate(height, y, minY, yrange);
                    canvas.drawText(label, left, yCoordinate, labelPaint);
                }
            }
        };
        measureYLabel();
        labelDrawable.setBounds(0, 0, getWidth(), getHeight());
        labelDrawable.setShape(labelsShape);
    }

    protected void measureYLabel() {
        labelPaint.setTextAlign(Paint.Align.RIGHT);
        labelPaint.setTextSize(lineChartStyle.getLabelTextSize());

        long minY = getMinY();
        long maxY = getMaxY();
        long yGridUnit = getYGridUnit();

        yLabelWidth = 0;
        chartTopMargin = 0;

        long y = minY;
        Rect textBounds = new Rect();

        while (y <= maxY) {
            String label = formatYLabel(y);
            labelPaint.getTextBounds(label, 0, label.length(), textBounds);
            if (textBounds.width() > yLabelWidth) {
                yLabelWidth = textBounds.width();
            }
            chartTopMargin = textBounds.height();
            y += yGridUnit;
        }
    }

    protected String formatYLabel(long y) {
        if (lineChartStyle.getYLabelFormatter() != null) {
            return lineChartStyle.getYLabelFormatter().format(y);
        }
        return String.format("%,d", y);
    }

    protected void drawXLabels(ShapeDrawable labelDrawable) {
        Shape labelsShape = new Shape() {
            @Override
            public void draw(Canvas canvas, Paint paint) {
                labelPaint.setTextAlign(Paint.Align.CENTER);
                labelPaint.setTextSize(lineChartStyle.getLabelTextSize());
                labelPaint.setColor(lineChartStyle.getLabelTextColor());

                long minX = getMinX();
                long maxX = getMaxX();
                long xrange = maxX - minX;

                float width = getWidth();
                float height = getHeight();

                float labelHeight = height - lineChartStyle.getXLabelMargin();
                Rect textBounds = new Rect();
                List<Long> xLabels = getXLabels();
                for (long x : xLabels) {
                    String label = formatXLabel(x);
                    labelPaint.getTextBounds(label, 0, label.length(), textBounds);
                    float xCoordinate = getXCoordinate(width, x, minX, xrange);
                    canvas.drawText(label, xCoordinate, labelHeight, labelPaint);
                }
            }
        };
        measureXLabel();
        labelDrawable.setBounds(0, 0, getWidth(), getHeight());
        labelDrawable.setShape(labelsShape);
    }

    protected void measureXLabel() {
        labelPaint.setTextAlign(Paint.Align.CENTER);
        labelPaint.setTextSize(lineChartStyle.getLabelTextSize());

        long minX = getRawMinX();
        long maxX = getMaxX();
        long xGridUnit = getXGridUnit();

        xLabelHeight = 0;
        chartRightMargin = 0;

        long x = minX;
        Rect textBounds = new Rect();

        while (x <= maxX) {
            String label = formatXLabel(x);
            labelPaint.getTextBounds(label, 0, label.length(), textBounds);
            int height = (int) (textBounds.height() + lineChartStyle.getXLabelMargin() * 2);
            if (height > xLabelHeight) {
                xLabelHeight = height;
            }
            chartRightMargin = textBounds.width() / 2;
            x += xGridUnit;
        }
    }

    protected String formatXLabel(long x) {
        if (lineChartStyle.getXLabelFormatter() != null) {
            return lineChartStyle.getXLabelFormatter().format(x);
        }
        return String.format("%,d", x);
    }

    protected void drawLineChart(ShapeDrawable chartDrawable) {
        Shape chartShape = new Shape() {
            @Override
            public void draw(Canvas canvas, Paint paint) {
                long minX = getMinX();
                long maxX = getMaxX();
                long xrange = maxX - minX;

                long minY = getMinY();
                long maxY = getMaxY();
                long yrange = maxY - minY;

                float width = getWidth();
                float height = getHeight();
                float left = getChartLeftMargin();
                float top = getChartTopMargin();
                float right = width - getChartRightMargin();
                float bottom = height - getChartBottomMargin();

                drawChartFrame(canvas, left, top, right, bottom);

                drawXGrid(canvas, minX, xrange);
                drawYGrid(canvas, minY, yrange);

                List<LineChartStyle.Border> borders = lineChartStyle.getBorders();
                for (LineChartStyle.Border border : borders) {
                    drawChartBorder(canvas, border, left, top, right, bottom);
                }

                drawLines(canvas, minX, xrange, minY, yrange);

                if (lineChartStyle.isDrawPoint()) {
                    drawPoints(canvas, minX, xrange, minY, yrange);
                }
            }
        };
        chartDrawable.setBounds(0, 0, getWidth(), getHeight());
        chartDrawable.setShape(chartShape);
    }

    protected void drawChartFrame(Canvas canvas, float left, float top, float right, float bottom) {
        canvas.save();
        canvas.clipRect(left, top, right, bottom);
        canvas.drawColor(lineChartStyle.getBackgroundColor());
        canvas.restore();
    }

    protected void drawChartBorder(Canvas canvas, LineChartStyle.Border border, float left, float top, float right, float bottom) {
        borderPaint.setColor(border.getColor());
        borderPaint.setStrokeWidth(border.getWidth());

        float fixWidth = border.getWidth() / 2;
        float leftFix = border.left() ? fixWidth : 0;
        float topFix = border.top() ? fixWidth : 0;
        float bottomFix = border.bottom() ? fixWidth : 0;
        float rightFix = border.right() ? fixWidth : 0;
        if (border.left()) {
            canvas.drawLine(left, top - topFix, left, bottom + bottomFix, borderPaint);
        }
        if (border.top()) {
            canvas.drawLine(left - leftFix, top, right + rightFix, top, borderPaint);
        }
        if (border.right()) {
            canvas.drawLine(right, top - topFix, right, bottom + bottomFix, borderPaint);
        }
        if (border.bottom()) {
            canvas.drawLine(left - leftFix, bottom, right + rightFix, bottom, borderPaint);
        }
    }

    public float getChartLeftMargin() {
        return getYLabelWidth() + lineChartStyle.getYLabelMargin();
    }

    public float getChartTopMargin() {
        return chartTopMargin;
    }

    public float getChartRightMargin() {
        return chartRightMargin;
    }

    public float getChartBottomMargin() {
        return getXLabelHeight() + lineChartStyle.getXLabelMargin();
    }

    public void clearManualMinX() {
        manualMinX = null;
        updateDrawables();
    }

    public void setManualMinX(long minX) {
        manualMinX = minX;
        updateDrawables();
    }

    public long getMinX() {
        if (manualMinX != null) {
            return manualMinX;
        }
        return getRawMinX();
    }

    public long getRawMinX() {
        if (points.isEmpty()) {
            return 0;
        }
        return points.get(0).getX();
    }

    public void clearManualMaxX(){
        manualMaxX = null;
        updateDrawables();
    }

    public void setManualMaxX(long maxX) {
        manualMaxX = maxX;
        updateDrawables();
    }

    public long getMaxX() {
        if (manualMaxX != null) {
            return manualMaxX;
        }
        long rawMaxX = getRawMaxX();
        long step = getUnit(getAbsMaxX());
        return (long) ((Math.floor(1.0 * rawMaxX / step) + 1) * step);
    }

    public long getRawMaxX() {
        if (points.isEmpty()) {
            return DEFAULT_MAX_X;
        }
        return points.get(points.size() - 1).getX();
    }

    protected long getAbsMaxX() {
        if (points.isEmpty()) {
            return DEFAULT_MAX_X;
        }
        long absMaxX = Long.MIN_VALUE;
        for (Point point : points) {
            long x = Math.abs(point.getX());
            if (x > absMaxX) {
                absMaxX = x;
            }
        }
        return absMaxX;
    }

    protected float getXCoordinate(float width, Point point, long minX, long xrange) {
        return getXCoordinate(width, point.getX(), minX, xrange);
    }

    protected float getXCoordinate(float width, long x, long minX, long xrange) {
        return getXCoordinate(width, x, minX, xrange, true);
    }

    protected float getXCoordinate(float width, long x, long minX, long xrange, boolean inChartArea) {
        if (inChartArea) {
            float left = getChartLeftMargin();
            float right = getChartRightMargin();
            float margin = left + right;
            return (width - margin) * (x - minX) * 1.0f / (xrange) + left;
        } else {
            return width * (x - minX) * 1.0f / xrange;
        }
    }

    protected long getAbsMaxY() {
        if (points.isEmpty()) {
            return DEFAULT_MAX_Y;
        }
        long absMaxY = Long.MIN_VALUE;
        for (Point point : points) {
            long y = Math.abs(point.getY());
            if (y > absMaxY) {
                absMaxY = y;
            }
        }
        return absMaxY;
    }

    public void clearManualMinY() {
        manualMinY = null;
        updateDrawables();
    }

    public void setManualMinY(long minY) {
        manualMinY = minY;
        updateDrawables();
    }

    public long getMinY() {
        if (manualMinY != null) {
            return manualMinY;
        }
        long rawMinY = getRawMinY();
        long step = getUnit(getAbsMaxY());
        return (long) ((Math.ceil(1.0 * rawMinY / step) - 1) * step);
    }

    public long getRawMinY() {
        if (points.isEmpty()) {
            return 0;
        }
        long minY = Long.MAX_VALUE;
        for (Point point : points) {
            long y = point.getY();
            if (y < minY) {
                minY = y;
            }
        }
        return minY;
    }

    public void clearManualMaxY() {
        manualMaxY = null;
        updateDrawables();
    }

    public void setManualMaxY(long maxY) {
        manualMaxY = maxY;
        updateDrawables();
    }

    public long getMaxY() {
        if (manualMaxY != null) {
            return manualMaxY;
        }
        long rawMaxY = getRawMaxY();
        long step = getUnit(getAbsMaxY());
        return (long) ((Math.floor(1.0 * rawMaxY / step) + 1) * step);
    }

    public long getRawMaxY() {
        if (points.isEmpty()) {
            return DEFAULT_MAX_Y;
        }
        long maxY = Long.MIN_VALUE;
        for (Point point : points) {
            long y = point.getY();
            if (y > maxY) {
                maxY = y;
            }
        }
        return maxY;
    }

    protected long getUnit(long maxValue) {
        int digits = (int) Math.log10(maxValue);
        long unit = (long) Math.pow(10, digits);
        return unit;
    }

    protected float getYCoordinate(float height, Point point, long minY, long yrange) {
        return getYCoordinate(height, point.getY(), minY, yrange);
    }

    protected float getYCoordinate(float height, long y, long minY, long yrange) {
        return getYCoordinate(height, y, minY, yrange, true);
    }

    protected float getYCoordinate(float height, long y, long minY, long yrange, boolean inChartArea) {
        if (inChartArea) {
            float top = getChartTopMargin();
            float bottom = getChartBottomMargin();
            float margin = top + bottom;
            return (height - margin) * (1.0f - (y - minY) * 1.0f / (yrange)) + top;
        } else {
            return height * (1.0f - (y - minY) * 1.0f / yrange);
        }
    }

    protected void drawXGrid(Canvas canvas, long minX, long xrange) {
        long maxX = getMaxX();
        long xGridUnit = getXGridUnit();

        float width = getWidth();
        float height = getHeight();

        float top = getChartTopMargin();
        float bottom = height - getChartBottomMargin();

        paint.setColor(lineChartStyle.getGridColor());
        paint.setStrokeWidth(lineChartStyle.getGridWidth());

        long x = calcMinGridValue(minX, xGridUnit);

        while (x <= maxX) {
            float xCoordinate = getXCoordinate(width, x, minX, xrange);
            canvas.drawLine(xCoordinate, bottom, xCoordinate, top, paint);
            x += xGridUnit;
        }
    }

    protected void drawYGrid(Canvas canvas, long minY, long yrange) {
        long yGridUnit = getYGridUnit();
        long maxY = getMaxY();

        float width = getWidth();
        float height = getHeight();

        float left = getChartLeftMargin();
        float right = width - getChartRightMargin();

        paint.setColor(lineChartStyle.getGridColor());
        paint.setStrokeWidth(lineChartStyle.getGridWidth());

        long y = calcMinGridValue(minY, yGridUnit);
        while (y <= maxY) {
            float yCoordinate = getYCoordinate(height, y, minY, yrange);
            canvas.drawLine(left, yCoordinate, right, yCoordinate, paint);
            y += yGridUnit;
        }
    }

    protected void drawLines(Canvas canvas, long minX, long xrange, long minY, long yrange) {
        Point prevPoint = null;
        float px = 0.0f, py = 0.0f;

        float width = getWidth();
        float height = getHeight();

        paint.setColor(lineChartStyle.getLineColor());
        paint.setStrokeWidth(lineChartStyle.getLineWidth());
        for (Point point : points) {
            float x = getXCoordinate(width, point, minX, xrange);
            float y = getYCoordinate(height, point, minY, yrange);
            if (prevPoint != null) {
                canvas.drawLine(px, py, x, y, paint);
            }
            prevPoint = point;
            px = x;
            py = y;
        }
    }

    protected void drawPoints(Canvas canvas, long minX, long xrange, long minY, long yrange) {
        float width = getWidth();
        float height = getHeight();

        for (Point point : points) {
            float x = getXCoordinate(width, point, minX, xrange);
            float y = getYCoordinate(height, point, minY, yrange);

            paint.setColor(lineChartStyle.getLineColor());
            canvas.drawCircle(x, y, lineChartStyle.getPointSize(), paint);

            if (lineChartStyle.isDrawPointCenter()) {
                paint.setColor(lineChartStyle.getBackgroundColor());
                canvas.drawCircle(x, y, lineChartStyle.getPointCenterSize(), paint);
            }
        }
    }

    public void clearManualXGridUnit() {
        manualXGridUnit = null;
        updateDrawables();
    }

    public void setManualXGridUnit(long xGridUnit) {
        manualXGridUnit = xGridUnit;
        updateDrawables();
    }

    public long getXGridUnit() {
        if (manualXGridUnit != null) {
            return manualXGridUnit;
        }
        return getUnit(getAbsMaxX());
    }

    public void clearManualYGridUnit() {
        manualYGridUnit = null;
        updateDrawables();
    }

    public void setManualYGridUnit(long yGridUnit) {
        manualYGridUnit = yGridUnit;
        updateDrawables();
    }

    public long getYGridUnit() {
        if (manualYGridUnit != null) {
            return manualYGridUnit;
        }
        return getUnit(getAbsMaxY());
    }

    public List<Long> getXLabels() {
        if (manualXLabels != null) {
            return manualXLabels;
        }

        long minX = getMinX();
        long maxX = getMaxX();
        long xGridUnit = getXGridUnit();
        long x = calcMinGridValue(minX, xGridUnit);
        List<Long> xLabels = new ArrayList<>();
        while (x <= maxX) {
            xLabels.add(x);
            x += xGridUnit;
        }
        return xLabels;
    }

    public void clearManualXLabels() {
        manualXLabels = null;
        updateDrawables();
    }

    public void setManualXLabels(List<Long> labels) {
        manualXLabels = labels;
        updateDrawables();
    }

    public List<Long> getYLabels() {
        if (manualYLabels != null) {
            return manualYLabels;
        }

        long minY = getMinY();
        long maxY = getMaxY();
        long yGridUnit = getYGridUnit();
        long y = calcMinGridValue(minY, yGridUnit);
        List<Long> yLabels = new ArrayList<>();
        while (y <= maxY) {
            yLabels.add(y);
            y += yGridUnit;
        }
        return yLabels;
    }

    public void clearManualYLabels() {
        manualYLabels = null;
        updateDrawables();
    }

    public void setManualYLabels(List<Long> labels) {
        manualYLabels = labels;
        updateDrawables();
    }

    protected long calcMinGridValue(long min, long gridUnit) {
        return (long) (Math.ceil(1.0 * min / gridUnit) * gridUnit);
    }

    public float getYLabelWidth() {
        if (lineChartStyle.getYLabelWidth() != LineChartStyle.AUTO_WIDTH) {
            return lineChartStyle.getYLabelWidth();
        }
        return yLabelWidth;
    }

    public float getXLabelHeight() {
        if (lineChartStyle.getXLabelHeight() != LineChartStyle.AUTO_HEIGHT) {
            return lineChartStyle.getXLabelHeight();
        }
        return xLabelHeight;
    }

    public LineChartStyle getStyle() {
        return lineChartStyle;
    }

    public void setStyle(LineChartStyle lineChartStyle) {
        this.lineChartStyle = lineChartStyle;
        updateDrawables();
    }

    public List<Point> getPoints() {
        return points;
    }

    public void setPoints(List<Point> points) {
        this.points.clear();
        this.points.addAll(points);
        updateDrawables();
    }

    private void updateIfEditMode() {
        if (!isInEditMode()) {
            return;
        }
        List<Point> points = new ArrayList<>();
        points.add(new LineChartView.Point(-17, -100));
        points.add(new LineChartView.Point(4, 200));
        points.add(new LineChartView.Point(5, 400));
        points.add(new LineChartView.Point(6, 1100));
        points.add(new LineChartView.Point(7, 700));
        setPoints(points);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        updateDrawables();
    }
}




Java Source Code List

org.hogel.android.linechartview.DateLineChartView.java
org.hogel.android.linechartview.LineChartStyle.java
org.hogel.android.linechartview.LineChartViewTest.java
org.hogel.android.linechartview.LineChartView.java
org.hogel.android.linechartview.ViewTestBase.java
org.hogel.android.linechartviewdemo.DateLineChartActivity.java
org.hogel.android.linechartviewdemo.LineChartActivity.java
org.hogel.android.linechartviewdemo.MainActivity.java