Back to project page SDCardTrac.
The source code is released under:
GNU General Public License
If you think the Android project SDCardTrac listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
/** * This file is part of GraphView.// w w w .ja v a 2s . c om * * GraphView is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GraphView is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GraphView. If not, see <http://www.gnu.org/licenses/lgpl.html>. * * Copyright Jonas Gehring */ package com.jjoe64.graphview; import java.text.NumberFormat; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Align; import android.graphics.Rect; import android.graphics.RectF; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.LinearLayout; import com.jjoe64.graphview.GraphViewSeries.GraphViewSeriesStyle; import com.jjoe64.graphview.GraphViewStyle.GridStyle; import com.jjoe64.graphview.compatible.ScaleGestureDetector; /** * GraphView is a Android View for creating zoomable and scrollable graphs. * This is the abstract base class for all graphs. Extend this class and implement {@link #drawSeries(android.graphics.Canvas, GraphViewDataInterface[], float, float, float, double, double, double, double, float, com.jjoe64.graphview.GraphViewSeries.GraphViewSeriesStyle)} to display a custom graph. * Use {@link com.jjoe64.graphview.LineGraphView} for creating a line chart. * * @author jjoe64 - jonas gehring - http://www.jjoe64.com * * Copyright (C) 2011 Jonas Gehring * Licensed under the GNU Lesser General Public License (LGPL) * http://www.gnu.org/licenses/lgpl.html */ abstract public class GraphView extends LinearLayout { static final private class GraphViewConfig { static final float BORDER = 20; } private class GraphViewContentView extends View { private float lastTouchEventX; private float graphwidth; private boolean scrollingStarted; static final float RESIST_MOVE_THRESHOLD = 2.0f; // difference in X to not detect as move private float origDown; /** * @param context */ public GraphViewContentView(Context context) { super(context); setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); } /** * @param canvas */ @Override protected void onDraw(Canvas canvas) { paint.setAntiAlias(true); // normal paint.setStrokeWidth(0); float border = GraphViewConfig.BORDER; float horstart = 0; float height = getHeight(); float width = getWidth() - 1; double maxY = getMaxY(); double minY = getMinY(); double maxX = getMaxX(false); double minX = getMinX(false); double diffX = maxX - minX; // measure bottom text if (labelTextHeight == null || horLabelTextWidth == null) { paint.setTextSize(getGraphViewStyle().getTextSize()); double testX = ((getMaxX(true)-getMinX(true))*0.783)+getMinX(true); String testLabel = formatLabel(testX, true, 0, 0); paint.getTextBounds(testLabel, 0, testLabel.length(), textBounds); labelTextHeight = (textBounds.height()); horLabelTextWidth = (textBounds.width()); } border += labelTextHeight; float graphheight = height - (2 * border); graphwidth = width; if (horlabels == null) { horlabels = generateHorlabels(graphwidth); } if (verlabels == null) { verlabels = generateVerlabels(graphheight); } // vertical lines if(graphViewStyle.getGridStyle() != GridStyle.HORIZONTAL) { paint.setTextAlign(Align.LEFT); int vers = verlabels.length - 1; for (int i = 0; i < verlabels.length; i++) { paint.setColor(graphViewStyle.getGridColor()); float y = ((graphheight / vers) * i) + border; canvas.drawLine(horstart, y, width, y, paint); } } drawHorizontalLabels(canvas, border, horstart, height, horlabels, graphwidth); paint.setColor(graphViewStyle.getHorizontalLabelsColor()); paint.setTextAlign(Align.CENTER); canvas.drawText(title, (graphwidth / 2) + horstart, border - 4, paint); if (maxY == minY) { // if min/max is the same, fake it so that we can render a line if(maxY == 0) { // if both are zero, change the values to prevent division by zero maxY = 1.0d; minY = 0.0d; } else { maxY = maxY*1.05d; minY = minY*0.95d; } } double diffY = maxY - minY; paint.setStrokeCap(Paint.Cap.ROUND); for (int i=0; i<graphSeries.size(); i++) { drawSeries(canvas, _values(i), graphwidth, graphheight, border, minX, minY, diffX, diffY, horstart, graphSeries.get(i).style); } if (showLegend) drawLegend(canvas, height, width); } private void onMoveGesture(float f) { // view port update if (viewportSize != 0) { viewportStart -= f*viewportSize/graphwidth; // minimal and maximal view limit double minX = getMinX(true); double maxX = getMaxX(true); if (viewportStart < minX) { viewportStart = minX; } else if (viewportStart+viewportSize > maxX) { viewportStart = maxX - viewportSize; } // labels have to be regenerated if (!staticHorizontalLabels) horlabels = null; if (!staticVerticalLabels) verlabels = null; viewVerLabels.invalidate(); } // Invalidate selection for (int i=0; i<graphSeries.size(); i++) { graphSeries.get(i).style.highlightPoints = false; } invalidate(); } /** * @param event */ @Override public boolean onTouchEvent(MotionEvent event) { //if (!isScrollable() || isDisableTouch()) { if (isDisableTouch()) { return super.onTouchEvent(event); } boolean handled = false; // first scale if (scalable && scaleDetector != null) { scaleDetector.onTouchEvent(event); handled = scaleDetector.isInProgress(); } if (!handled) { boolean hadMoved = false; // if not scaled, scroll if ((event.getAction() & MotionEvent.ACTION_DOWN) == MotionEvent.ACTION_DOWN && (event.getAction() & MotionEvent.ACTION_MOVE) == 0) { scrollingStarted = true; handled = true; if (!((event.getAction() & MotionEvent.ACTION_UP) == MotionEvent.ACTION_UP)) { origDown = event.getX(); handleSelect(event, false, false, 0); } } if ((event.getAction() & MotionEvent.ACTION_UP) == MotionEvent.ACTION_UP) { if ((lastTouchEventX != 0) && !resistMove(origDown, event.getX())) hadMoved = true; else hadMoved = false; scrollingStarted = false; lastTouchEventX = 0; handled = true; // Sample select callback if (!hadMoved) { handleSelect(event, true, false, 0); } } if ((event.getAction() & MotionEvent.ACTION_MOVE) == MotionEvent.ACTION_MOVE) { if (isScrollable() && scrollingStarted) { if (lastTouchEventX != 0) { onMoveGesture(event.getX() - lastTouchEventX); } lastTouchEventX = event.getX(); handled = true; } } //Log.d("GraphView", "on touch event scale not handled " + lastTouchEventX // + " event " + event.toString() + " moved " + hadMoved + " ox " + origDown); if (handled) invalidate(); } else { // currently scaling scrollingStarted = false; lastTouchEventX = 0; } return handled; } // Resist a move if movement is small private boolean resistMove(float initX, float finalX) { if (Math.abs(initX - finalX) > RESIST_MOVE_THRESHOLD) { return false; } else { return true; } } } /** * one data set for a graph series */ static public class GraphViewData implements GraphViewDataInterface { public final double valueX; public final double valueY; public GraphViewData(double valueX, double valueY) { super(); this.valueX = valueX; this.valueY = valueY; } @Override public double getX() { return valueX; } @Override public double getY() { return valueY; } } public enum LegendAlign { TOP, MIDDLE, BOTTOM } private class VerLabelsView extends View { /** * @param context */ public VerLabelsView(Context context) { super(context); setLayoutParams(new LayoutParams( getGraphViewStyle().getVerticalLabelsWidth()==0?100:getGraphViewStyle().getVerticalLabelsWidth() , LayoutParams.FILL_PARENT)); } /** * @param canvas */ @Override protected void onDraw(Canvas canvas) { // normal paint.setStrokeWidth(0); // measure bottom text if (labelTextHeight == null || verLabelTextWidth == null) { paint.setTextSize(getGraphViewStyle().getTextSize()); double testY = ((getMaxY()-getMinY())*0.783)+getMinY(); String testLabel = formatLabel(testY, false, 0, 0); paint.getTextBounds(testLabel, 0, testLabel.length(), textBounds); labelTextHeight = (textBounds.height()); verLabelTextWidth = (textBounds.width()); } if (getGraphViewStyle().getVerticalLabelsWidth()==0 && getLayoutParams().width != verLabelTextWidth+GraphViewConfig.BORDER) { setLayoutParams(new LayoutParams( (int) (verLabelTextWidth+GraphViewConfig.BORDER), LayoutParams.FILL_PARENT)); } else if (getGraphViewStyle().getVerticalLabelsWidth()!=0 && getGraphViewStyle().getVerticalLabelsWidth() != getLayoutParams().width) { setLayoutParams(new LayoutParams( getGraphViewStyle().getVerticalLabelsWidth(), LayoutParams.FILL_PARENT)); } float border = GraphViewConfig.BORDER; border += labelTextHeight; float height = getHeight(); float graphheight = height - (2 * border); if (verlabels == null) { verlabels = generateVerlabels(graphheight); } // vertical labels paint.setTextAlign(getGraphViewStyle().getVerticalLabelsAlign()); int labelsWidth = getWidth(); int labelsOffset = 0; if (getGraphViewStyle().getVerticalLabelsAlign() == Align.RIGHT) { labelsOffset = labelsWidth; } else if (getGraphViewStyle().getVerticalLabelsAlign() == Align.CENTER) { labelsOffset = labelsWidth / 2; } int vers = verlabels.length - 1; for (int i = 0; i < verlabels.length; i++) { float y = ((graphheight / vers) * i) + border; paint.setColor(graphViewStyle.getVerticalLabelsColor()); canvas.drawText(verlabels[i], labelsOffset, y, paint); } // reset paint.setTextAlign(Align.LEFT); } } // Arguments are the event that occured and whether that finishes the select private boolean handleSelect(MotionEvent inEvent, boolean finished, boolean force, int forceSelect) { GraphViewDataInterface[] data; boolean retVal = false; data = graphSeries.get(0).values; if (finished) { int selectIndex = 1; double selectSample = 0; int startPoint = 0; boolean viewBefore = false; // Calculate nearest sample point if (force && forceSelect < data.length) selectSample = data[forceSelect].getX(); else selectSample = GraphView.this.transformPointToSample (inEvent.getX(), GraphViewConfig.BORDER, graphViewContentView.getWidth()); for (GraphViewDataInterface i : data) { if (i.getX() >= selectSample) { break; } if (i.getX() < viewportStart) { startPoint = selectIndex; viewBefore = true; } selectIndex++; } if (viewBefore) startPoint++; else startPoint = 0; if (selectIndex >= data.length) selectIndex = data.length - 1; boolean redrawIt = false; // Check if point is in view if (viewportSize != 0) { if (data[selectIndex].getX() > (viewportStart + viewportSize)) { viewportStart = data[selectIndex].getX() - (viewportSize / 2); redrawIt = true; } else if (data[selectIndex].getX() < viewportStart) { if (data[selectIndex].getX() > (viewportSize / 2)) viewportStart = data[selectIndex].getX() - (viewportSize / 2); else viewportStart = data[selectIndex].getX(); redrawIt = true; } if (redrawIt) redrawAll(); } else startPoint = 0; // Call overriden method if (selectHandler != null && !redrawIt) selectHandler.onGraphSelect(selectIndex, startPoint); retVal = !redrawIt; } return retVal; } // Helper to move to selected index public void gotoSample(int seriesInd, int sampleInd) { GraphViewDataInterface[] data; data = graphSeries.get(seriesInd).values; if (sampleInd < data.length) { handleSelect(null, true, true, sampleInd); } } abstract public interface GraphSelectHandler { // Function to call overridable user callback for select events abstract public void onGraphSelect(int selectIndex, int startPoint); } protected final Paint paint; private String[] horlabels; private String[] verlabels; private String title; private boolean scrollable; private boolean disableTouch; private double viewportStart; private double viewportSize; private final View viewVerLabels; private ScaleGestureDetector scaleDetector; private boolean scalable; private final NumberFormat[] numberformatter = new NumberFormat[2]; private final List<GraphViewSeries> graphSeries; private boolean showLegend = false; private LegendAlign legendAlign = LegendAlign.MIDDLE; private boolean manualYAxis; private boolean manualMaxY; private boolean manualMinY; private double manualMaxYValue; private double manualMinYValue; protected GraphViewStyle graphViewStyle; private final GraphViewContentView graphViewContentView; private CustomLabelFormatter customLabelFormatter; private Integer labelTextHeight; private Integer horLabelTextWidth; private Integer verLabelTextWidth; private final Rect textBounds = new Rect(); private boolean staticHorizontalLabels; private boolean staticVerticalLabels; private boolean showHorizontalLabels = true; private boolean showVerticalLabels = true; private GraphSelectHandler selectHandler; public GraphView(Context context, AttributeSet attrs) { this(context, attrs.getAttributeValue(null, "title")); int width = attrs.getAttributeIntValue("android", "layout_width", LayoutParams.MATCH_PARENT); int height = attrs.getAttributeIntValue("android", "layout_height", LayoutParams.MATCH_PARENT); setLayoutParams(new LayoutParams(width, height)); } /** * @param context * @param title [optional] */ public GraphView(Context context, String title) { super(context); setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); if (title == null) this.title = ""; else this.title = title; graphViewStyle = new GraphViewStyle(); graphViewStyle.useTextColorFromTheme(context); paint = new Paint(); graphSeries = new ArrayList<GraphViewSeries>(); viewVerLabels = new VerLabelsView(context); addView(viewVerLabels); graphViewContentView = new GraphViewContentView(context); addView(graphViewContentView, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT, 1)); } private GraphViewDataInterface[] _values(int idxSeries) { GraphViewDataInterface[] values = graphSeries.get(idxSeries).values; synchronized (values) { if (viewportStart == 0 && viewportSize == 0) { // all data return values; } else { // viewport List<GraphViewDataInterface> listData = new ArrayList<GraphViewDataInterface>(); for (int i=0; i<values.length; i++) { if (values[i].getX() >= viewportStart) { if (values[i].getX() > viewportStart+viewportSize) { listData.add(values[i]); // one more for nice scrolling break; } else { listData.add(values[i]); } } else { if (listData.isEmpty()) { listData.add(values[i]); } listData.set(0, values[i]); // one before, for nice scrolling } } return listData.toArray(new GraphViewDataInterface[listData.size()]); } } } /** * add a series of data to the graph * @param series */ public void addSeries(GraphViewSeries series) { series.addGraphView(this); graphSeries.add(series); redrawAll(); } protected void drawHorizontalLabels(Canvas canvas, float border, float horstart, float height, String[] horlabels, float graphwidth) { // horizontal labels + lines int hors = horlabels.length - 1; for (int i = 0; i < horlabels.length; i++) { paint.setColor(graphViewStyle.getGridColor()); float x = ((graphwidth / hors) * i) + horstart; if(graphViewStyle.getGridStyle() != GridStyle.VERTICAL) { canvas.drawLine(x, height - border, x, border, paint); } if(showHorizontalLabels) { paint.setTextAlign(Align.CENTER); if (i==horlabels.length-1) paint.setTextAlign(Align.RIGHT); if (i==0) paint.setTextAlign(Align.LEFT); paint.setColor(graphViewStyle.getHorizontalLabelsColor()); canvas.drawText(horlabels[i], x, height - 4, paint); } } } protected void drawLegend(Canvas canvas, float height, float width) { float textSize = paint.getTextSize(); int spacing = getGraphViewStyle().getLegendSpacing(); int border = getGraphViewStyle().getLegendBorder(); int legendWidth = getGraphViewStyle().getLegendWidth(); int shapeSize = (int) (textSize*0.8d); Log.d("GraphView", "draw legend size: "+paint.getTextSize()); // rect paint.setARGB(180, 100, 100, 100); float legendHeight = (shapeSize+spacing)*graphSeries.size() +2*border -spacing; float lLeft = width-legendWidth - border*2; float lTop; switch (legendAlign) { case TOP: lTop = 0; break; case MIDDLE: lTop = height/2 - legendHeight/2; break; default: lTop = height - GraphViewConfig.BORDER - legendHeight - getGraphViewStyle().getLegendMarginBottom(); } float lRight = lLeft+legendWidth; float lBottom = lTop+legendHeight; canvas.drawRoundRect(new RectF(lLeft, lTop, lRight, lBottom), 8, 8, paint); for (int i=0; i<graphSeries.size(); i++) { paint.setColor(graphSeries.get(i).style.color); canvas.drawRect(new RectF(lLeft+border, lTop+border+(i*(shapeSize+spacing)), lLeft+border+shapeSize, lTop+border+(i*(shapeSize+spacing))+shapeSize), paint); if (graphSeries.get(i).description != null) { paint.setColor(Color.WHITE); paint.setTextAlign(Align.LEFT); canvas.drawText(graphSeries.get(i).description, lLeft+border+shapeSize+spacing, lTop+border+shapeSize+(i*(shapeSize+spacing)), paint); } } } abstract protected void drawSeries(Canvas canvas, GraphViewDataInterface[] values, float graphwidth, float graphheight, float border, double minX, double minY, double diffX, double diffY, float horstart, GraphViewSeriesStyle style); /** * Highlights a sample in the graph. Graph should be redrawn after this call * * @param series and sample index to be highlighted, enable flag */ public void highlightSample(int seriesIndex, boolean enable, int sampleIndex) { if (graphSeries.get(seriesIndex) != null) { graphSeries.get(seriesIndex).style.highlightPoints = enable; graphSeries.get(seriesIndex).style.highlightSample = sampleIndex; // Redraw the graph redrawAll(); } } /** * formats the label * use #setCustomLabelFormatter or static labels if you want custom labels * * @param value x and y values * @param isValueX if false, value y wants to be formatted * @deprecated use {@link #setCustomLabelFormatter(CustomLabelFormatter)} * @return value to display */ @Deprecated protected String formatLabel(double value, boolean isValueX, int index, int lastIndex) { if (customLabelFormatter != null) { String label = customLabelFormatter.formatLabel(value, isValueX, index, lastIndex); if (label != null) { return label; } } int i = isValueX ? 1 : 0; if (numberformatter[i] == null) { numberformatter[i] = NumberFormat.getNumberInstance(); double highestvalue = isValueX ? getMaxX(false) : getMaxY(); double lowestvalue = isValueX ? getMinX(false) : getMinY(); if (highestvalue - lowestvalue < 0.1) { numberformatter[i].setMaximumFractionDigits(6); } else if (highestvalue - lowestvalue < 1) { numberformatter[i].setMaximumFractionDigits(4); } else if (highestvalue - lowestvalue < 20) { numberformatter[i].setMaximumFractionDigits(3); } else if (highestvalue - lowestvalue < 100) { numberformatter[i].setMaximumFractionDigits(1); } else { numberformatter[i].setMaximumFractionDigits(0); } } return numberformatter[i].format(value); } private String[] generateHorlabels(float graphwidth) { int numLabels = getGraphViewStyle().getNumHorizontalLabels()-1; if (numLabels < 0) { if (graphwidth <= 0) graphwidth = 1f; numLabels = (int) (graphwidth/(horLabelTextWidth*2)); } String[] labels = new String[numLabels+1]; double min = getMinX(false); double max = getMaxX(false); for (int i=0; i<=numLabels; i++) { labels[i] = formatLabel(min + ((max-min)*i/numLabels), true, i, numLabels); } return labels; } synchronized private String[] generateVerlabels(float graphheight) { int numLabels = getGraphViewStyle().getNumVerticalLabels()-1; if (numLabels < 0) { if (graphheight <= 0) graphheight = 1f; numLabels = (int) (graphheight/(labelTextHeight*3)); if (numLabels == 0) { Log.w("GraphView", "Height of Graph is smaller than the label text height, so no vertical labels were shown!"); } } String[] labels = new String[numLabels+1]; double min = getMinY(); double max = getMaxY(); if (max == min) { // if min/max is the same, fake it so that we can render a line if(max == 0) { // if both are zero, change the values to prevent division by zero max = 1.0d; min = 0.0d; } else { max = max*1.05d; min = min*0.95d; } } for (int i=0; i<=numLabels; i++) { labels[numLabels-i] = formatLabel(min + ((max-min)*i/numLabels), false, i, numLabels); } return labels; } /** * @return the custom label formatter, if there is one. otherwise null */ public CustomLabelFormatter getCustomLabelFormatter() { return customLabelFormatter; } /** * @return the graphview style. it will never be null. */ public GraphViewStyle getGraphViewStyle() { return graphViewStyle; } /** * get the position of the legend * @return */ public LegendAlign getLegendAlign() { return legendAlign; } /** * @return legend width * @deprecated use {@link GraphViewStyle#getLegendWidth()} */ @Deprecated public float getLegendWidth() { return getGraphViewStyle().getLegendWidth(); } /** * returns the maximal X value of the current viewport (if viewport is set) * otherwise maximal X value of all data. * @param ignoreViewport * * warning: only override this, if you really know want you're doing! */ protected double getMaxX(boolean ignoreViewport) { // if viewport is set, use this if (!ignoreViewport && viewportSize != 0) { return viewportStart+viewportSize; } else { // otherwise use the max x value // values must be sorted by x, so the last value has the largest X value double highest = 0; if (graphSeries.size() > 0) { GraphViewDataInterface[] values = graphSeries.get(0).values; if (values.length == 0) { highest = 0; } else { highest = values[values.length-1].getX(); } for (int i=1; i<graphSeries.size(); i++) { values = graphSeries.get(i).values; if (values.length > 0) { highest = Math.max(highest, values[values.length-1].getX()); } } } return highest; } } /** * returns the maximal Y value of all data. * * warning: only override this, if you really know want you're doing! */ protected double getMaxY() { double largest; if (manualYAxis || manualMaxY) { largest = manualMaxYValue; } else { largest = Integer.MIN_VALUE; for (int i=0; i<graphSeries.size(); i++) { GraphViewDataInterface[] values = _values(i); for (int ii=0; ii<values.length; ii++) if (values[ii].getY() > largest) largest = values[ii].getY(); } } return largest; } /** * returns the minimal X value of the current viewport (if viewport is set) * otherwise minimal X value of all data. * @param ignoreViewport * * warning: only override this, if you really know want you're doing! */ protected double getMinX(boolean ignoreViewport) { // if viewport is set, use this if (!ignoreViewport && viewportSize != 0) { return viewportStart; } else { // otherwise use the min x value // values must be sorted by x, so the first value has the smallest X value double lowest = 0; if (graphSeries.size() > 0) { GraphViewDataInterface[] values = graphSeries.get(0).values; if (values.length == 0) { lowest = 0; } else { lowest = values[0].getX(); } for (int i=1; i<graphSeries.size(); i++) { values = graphSeries.get(i).values; if (values.length > 0) { lowest = Math.min(lowest, values[0].getX()); } } } return lowest; } } /** * returns the minimal Y value of all data. * * warning: only override this, if you really know want you're doing! */ protected double getMinY() { double smallest; if (manualYAxis || manualMinY) { smallest = manualMinYValue; } else { smallest = Integer.MAX_VALUE; for (int i=0; i<graphSeries.size(); i++) { GraphViewDataInterface[] values = _values(i); for (int ii=0; ii<values.length; ii++) if (values[ii].getY() < smallest) smallest = values[ii].getY(); } } return smallest; } /** * returns the size of the Viewport * */ public double getViewportSize(){ return viewportSize; } public double getViewportStart() { return viewportStart; } public boolean isDisableTouch() { return disableTouch; } public boolean isScrollable() { return scrollable; } public boolean isShowLegend() { return showLegend; } /** * forces graphview to invalide all views and caches. * Normally there is no need to call this manually. */ public void redrawAll() { if (!staticVerticalLabels) verlabels = null; if (!staticHorizontalLabels) horlabels = null; numberformatter[0] = null; numberformatter[1] = null; labelTextHeight = null; horLabelTextWidth = null; verLabelTextWidth = null; invalidate(); viewVerLabels.invalidate(); graphViewContentView.invalidate(); } /** * removes all series */ public void removeAllSeries() { for (GraphViewSeries s : graphSeries) { s.removeGraphView(this); } while (!graphSeries.isEmpty()) { graphSeries.remove(0); } redrawAll(); } /** * removes a series * @param series series to remove */ public void removeSeries(GraphViewSeries series) { series.removeGraphView(this); graphSeries.remove(series); redrawAll(); } /** * removes series * @param index */ public void removeSeries(int index) { if (index < 0 || index >= graphSeries.size()) { throw new IndexOutOfBoundsException("No series at index " + index); } removeSeries(graphSeries.get(index)); } /** * scrolls to the last x-value * @throws IllegalStateException if scrollable == false */ public void scrollToEnd() { if (!scrollable) throw new IllegalStateException("This GraphView is not scrollable."); double max = getMaxX(true); viewportStart = max-viewportSize; // don't clear labels width/height cache // so that the display is not flickering if (!staticVerticalLabels) verlabels = null; if (!staticHorizontalLabels) horlabels = null; invalidate(); viewVerLabels.invalidate(); graphViewContentView.invalidate(); } /** * set a custom label formatter * @param customLabelFormatter */ public void setCustomLabelFormatter(CustomLabelFormatter customLabelFormatter) { this.customLabelFormatter = customLabelFormatter; } /** * The user can disable any touch gestures, this is useful if you are using a real time graph, but don't want the user to interact * @param disableTouch */ public void setDisableTouch(boolean disableTouch) { this.disableTouch = disableTouch; } /** * set custom graphview style * @param style */ public void setGraphViewStyle(GraphViewStyle style) { graphViewStyle = style; labelTextHeight = null; } /** * set's static horizontal labels (from left to right) * @param horlabels if null, labels were generated automatically */ public void setHorizontalLabels(String[] horlabels) { staticHorizontalLabels = horlabels != null; this.horlabels = horlabels; } /** * legend position * @param legendAlign */ public void setLegendAlign(LegendAlign legendAlign) { this.legendAlign = legendAlign; } /** * legend width * @param legendWidth * @deprecated use {@link GraphViewStyle#setLegendWidth(int)} */ @Deprecated public void setLegendWidth(float legendWidth) { getGraphViewStyle().setLegendWidth((int)legendWidth); } /** * you have to set the bounds {@link #setManualYAxisBounds(double, double)}. That automatically enables manualYAxis-flag. * if you want to disable the menual y axis, call this method with false. * @param manualYAxis */ public void setManualYAxis(boolean manualYAxis) { this.manualYAxis = manualYAxis; } /** * if you want to disable the menual y axis maximum bound, call this method with false. */ public void setManualMaxY(boolean manualMaxY) { this.manualMaxY = manualMaxY; } /** * if you want to disable the menual y axis minimum bound, call this method with false. */ public void setManualMinY(boolean manualMinY) { this.manualMinY = manualMinY; } /** * set manual Y axis limit * @param max * @param min */ public void setManualYAxisBounds(double max, double min) { manualMaxYValue = max; manualMinYValue = min; manualYAxis = true; } /* * set manual Y axis max limit * @param max */ public void setManualYMaxBound(double max) { manualMaxYValue = max; manualMaxY = true; } /* * set manual Y axis min limit * @param min */ public void setManualYMinBound(double min) { manualMinYValue = min; manualMinY = true; } /** * this forces scrollable = true * @param scalable */ synchronized public void setScalable(boolean scalable) { this.scalable = scalable; if (scalable == true && scaleDetector == null) { scrollable = true; // automatically forces this scaleDetector = new ScaleGestureDetector(getContext(), new ScaleGestureDetector.SimpleOnScaleGestureListener() { @Override public boolean onScale(ScaleGestureDetector detector) { double center = viewportStart + viewportSize / 2; viewportSize /= detector.getScaleFactor(); viewportStart = center - viewportSize / 2; // viewportStart must not be < minX double minX = getMinX(true); if (viewportStart < minX) { viewportStart = minX; } // viewportStart + viewportSize must not be > maxX double maxX = getMaxX(true); if (viewportSize == 0) { viewportSize = maxX; } double overlap = viewportStart + viewportSize - maxX; if (overlap > 0) { // scroll left if (viewportStart-overlap > minX) { viewportStart -= overlap; } else { // maximal scale viewportStart = minX; viewportSize = maxX - viewportStart; } } redrawAll(); return true; } }); } } /** * the user can scroll (horizontal) the graph. This is only useful if you use a viewport {@link #setViewPort(double, double)} which doesn't displays all data. * @param scrollable */ public void setScrollable(boolean scrollable) { this.scrollable = scrollable; } public void setShowLegend(boolean showLegend) { this.showLegend = showLegend; } /** * sets the title of graphview * @param title */ public void setTitle(String title) { this.title = title; } /** * set's static vertical labels (from top to bottom) * @param verlabels if null, labels were generated automatically */ public void setVerticalLabels(String[] verlabels) { staticVerticalLabels = verlabels != null; this.verlabels = verlabels; } /** * set's the viewport for the graph. * @see #setManualYAxisBounds(double, double) to limit the y-viewport * @param start x-value * @param size */ public void setViewPort(double start, double size) { if (size<0) { throw new IllegalArgumentException("Viewport size must be greater than 0!"); } viewportStart = start; viewportSize = size; } /** * Sets whether horizontal labels are drawn or not. * * @param showHorizontalLabels */ public void setShowHorizontalLabels(boolean showHorizontalLabels) { this.showHorizontalLabels = showHorizontalLabels; redrawAll(); } /** * Gets are horizontal labels drawn. * * @return {@code True} if horizontal labels are drawn */ public boolean getShowHorizontalLabels() { return showHorizontalLabels; } /** * Sets whether vertical labels are drawn or not. * * @param showVerticalLabels */ public void setShowVerticalLabels(boolean showVerticalLabels) { this.showVerticalLabels = showVerticalLabels; if(this.showVerticalLabels) { addView(viewVerLabels, 0); } else { removeView(viewVerLabels); } } /** * Gets are vertical labels are drawn. * * @return {@code True} if vertical labels are drawn */ public boolean getShowVerticalLabels() { return showVerticalLabels; } /* * For OnSelect callback */ /** * Set's the select handler class for 1st series in graph * @param handle instance */ public void setSelectHandler(GraphSelectHandler handle) { selectHandler = handle; } abstract double transformPointToSample(double point, float border, int wid); }