123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533 |
- /*
- * Created by Daniel Nadeau
- * daniel.nadeau01@gmail.com
- * danielnadeau.blogspot.com
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
- */
- package com.echo.holographlibrary;
- import android.content.Context;
- import android.graphics.Bitmap;
- import android.graphics.Bitmap.Config;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.graphics.Path;
- import android.graphics.Path.Direction;
- import android.graphics.Point;
- import android.graphics.PorterDuffXfermode;
- import android.graphics.Region;
- import android.util.AttributeSet;
- import android.util.TypedValue;
- import android.view.MotionEvent;
- import android.view.View;
- import java.util.ArrayList;
- public class LineGraph extends View {
-
- private ArrayList<Line> lines = new ArrayList<Line>();
- Paint paint = new Paint();
- private float minY = 0, minX = 0;
- private float maxY = 0, maxX = 0;
- private double rangeYRatio = 0;
- private double rangeXRatio = 0;
- private boolean isMaxYUserSet = false;
- private boolean isMaxXUserSet = false;
- private int lineToFill = -1;
- private int indexSelected = -1;
- private OnPointClickedListener listener;
- private Bitmap fullImage;
- private boolean shouldUpdate = false;
-
- public LineGraph(Context context){
- super(context);
- this.setWillNotDraw(false);
- }
-
- public LineGraph(Context context, AttributeSet attrs) {
- super(context, attrs);
- this.setWillNotDraw(false);
- }
- public void setMinY(float minY){
-
- }
-
- public void removeAllLines(){
- while (lines.size() > 0){
- lines.remove(0);
- }
- shouldUpdate = true;
- postInvalidate();
- }
-
- public void addLine(Line line) {
- lines.add(line);
- shouldUpdate = true;
- postInvalidate();
- }
- public void addPointToLine(int lineIndex, double x, double y){
- addPointToLine(lineIndex, (float) x, (float) y);
- }
- public void addPointToLine(int lineIndex, float x, float y){
- LinePoint p = new LinePoint(x, y);
- addPointToLine(lineIndex, p);
- }
-
- public double getRangeYRatio(){
- return rangeYRatio;
- }
-
- public void setRangeYRatio(double rr){
- this.rangeYRatio = rr;
- }
- public double getRangeXRatio(){
- return rangeXRatio;
- }
-
- public void setRangeXRatio(double rr){
- this.rangeXRatio = rr;
- }
- public void addPointToLine(int lineIndex, LinePoint point){
- Line line = getLine(lineIndex);
- line.addPoint(point);
- lines.set(lineIndex, line);
- resetLimits();
- shouldUpdate = true;
- postInvalidate();
- }
-
- public void addPointsToLine(int lineIndex, LinePoint[] points){
- Line line = getLine(lineIndex);
- for(LinePoint point : points){
- line.addPoint(point);
- }
- lines.set(lineIndex, line);
- resetLimits();
- shouldUpdate = true;
- postInvalidate();
- }
-
- public void removeAllPointsAfter(int lineIndex, double x){
- removeAllPointsBetween(lineIndex, x, getMaxX());
- }
- public void removeAllPointsBefore(int lineIndex, double x){
- removeAllPointsBetween(lineIndex, getMinX(), x);
- }
-
- public void removeAllPointsBetween(int lineIndex, double startX, double finishX){
- Line line = getLine(lineIndex);
- LinePoint[] pts = new LinePoint[line.getPoints().size()];
- pts = line.getPoints().toArray(pts);
- for(LinePoint point : pts){
- if(point.getX() >= startX && point.getX() <= finishX)
- line.removePoint(point);
- }
- lines.set(lineIndex, line);
- resetLimits();
- shouldUpdate = true;
- postInvalidate();
- }
- public void removePointsFromLine(int lineIndex, LinePoint[] points){
- Line line = getLine(lineIndex);
- for(LinePoint point : points){
- line.removePoint(point);
- }
- lines.set(lineIndex, line);
- resetLimits();
- shouldUpdate = true;
- postInvalidate();
- }
- public void removePointFromLine(int lineIndex, float x, float y){
- LinePoint p = null;
- Line line = getLine(lineIndex);
- p = line.getPoint(x, y);
- removePointFromLine(lineIndex, p);
- }
- public void removePointFromLine(int lineIndex, LinePoint point){
- Line line = getLine(lineIndex);
- line.removePoint(point);
- lines.set(lineIndex, line);
- resetLimits();
- shouldUpdate = true;
- postInvalidate();
- }
-
- public void resetYLimits(){
- float range = getMaxY() - getMinY();
- setRangeY(getMinY()-range*getRangeYRatio(), getMaxY()+range*getRangeYRatio());
- }
- public void resetXLimits(){
- float range = getMaxX() - getMinX();
- setRangeX(getMinX()-range*getRangeXRatio(), getMaxX()+range*getRangeXRatio());
- }
- public void resetLimits() {
- resetYLimits();
- resetXLimits();
- }
- public ArrayList<Line> getLines() {
- return lines;
- }
- public void setLineToFill(int indexOfLine) {
- this.lineToFill = indexOfLine;
- shouldUpdate = true;
- postInvalidate();
- }
- public int getLineToFill(){
- return lineToFill;
- }
- public void setLines(ArrayList<Line> lines) {
- this.lines = lines;
- }
- public Line getLine(int index) {
- return lines.get(index);
- }
- public int getSize(){
- return lines.size();
- }
-
- public void setRangeY(float min, float max) {
- minY = min;
- maxY = max;
- isMaxYUserSet = true;
- }
- private void setRangeY(double min, double max){
- minY = (float)min;
- maxY = (float)max;
- isMaxXUserSet = true;
- }
- public void setRangeX(float min, float max) {
- minX = min;
- maxX = max;
- }
- private void setRangeX(double min, double max){
- minX = (float)min;
- maxX = (float)max;
- }
- public float getMaxY(){
- float max = lines.get(0).getPoint(0).getY();
- for (Line line : lines){
- for (LinePoint point : line.getPoints()){
- max = point.getY() > max ? point.getY() : max;
- }
- }
- maxY = max;
- return maxY;
- }
- public float getMinY(){
- float min = lines.get(0).getPoint(0).getY();
- for (Line line : lines){
- for (LinePoint point : line.getPoints()){
- min = point.getY() < min ? point.getY() : min;
- }
- }
- minY = min;
- return minY;
- }
- public float getMinLimY(){
- return minY;
- }
- public float getMaxLimY(){
- return maxY;
- }
- public float getMinLimX(){
- return minX;
- }
- public float getMaxLimX(){
- if (isMaxXUserSet) {
- return maxX;
- }
- else {
- return getMaxX();
- }
- }
- public float getMaxX(){
- float max = lines.size() > 0 ? lines.get(0).getPoint(0).getX() : 0;
- for (Line line : lines){
- for (LinePoint point : line.getPoints()){
- max = point.getX() > max ? point.getX() : max;
- }
- }
- maxX = max;
- return maxX;
-
- }
- public float getMinX(){
- float min = lines.size() > 0 ? lines.get(0).getPoint(0).getX() : 0;
- for (Line line : lines){
- for (LinePoint point : line.getPoints()){
- min = point.getX() < min ? point.getX() : min;
- }
- }
- minX = min;
- return minX;
- }
-
-
- public void onDraw(Canvas ca) {
- super.onDraw(ca);
- if (fullImage == null || shouldUpdate) {
- fullImage = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888);
- Canvas canvas = new Canvas(fullImage);
-
- paint.reset();
- Path path = new Path();
- float bottomPadding = 10, topPadding = 10;
- float sidePadding = 10;
- float usableHeight = getHeight() - bottomPadding - topPadding;
- float usableWidth = getWidth() - 2*sidePadding;
- float maxY = getMaxLimY();
- float minY = getMinLimY();
- float maxX = getMaxLimX();
- float minX = getMinLimX();
-
- int lineCount = 0;
- for (Line line : lines){
- int count = 0;
- float firstXPixels = 0, lastXPixels = 0, newYPixels = 0;
- float lastYPixels = 0, newXPixels = 0;
-
- if (lineCount == lineToFill){
- paint.setColor(Color.BLACK);
- paint.setAlpha(30);
- paint.setStrokeWidth(2);
- for (int i = 10; i-getWidth() < getHeight(); i = i+20){
- canvas.drawLine(i, getHeight()-bottomPadding, 0, getHeight()-bottomPadding-i, paint);
- }
-
- paint.reset();
-
- paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.CLEAR));
- for (LinePoint p : line.getPoints()){
- float yPercent = (p.getY()-minY)/(maxY - minY);
- float xPercent = (p.getX()-minX)/(maxX - minX);
- if (count == 0){
- lastXPixels = sidePadding + (xPercent*usableWidth);
- lastYPixels = getHeight() - bottomPadding - (usableHeight*yPercent);
- firstXPixels = lastXPixels;
- path.moveTo(lastXPixels, lastYPixels);
- } else {
- newXPixels = sidePadding + (xPercent*usableWidth);
- newYPixels = getHeight() - bottomPadding - (usableHeight*yPercent);
- path.lineTo(newXPixels, newYPixels);
- Path pa = new Path();
- pa.moveTo(lastXPixels, lastYPixels);
- pa.lineTo(newXPixels, newYPixels);
- pa.lineTo(newXPixels, 0);
- pa.lineTo(lastXPixels, 0);
- pa.close();
- canvas.drawPath(pa, paint);
- lastXPixels = newXPixels;
- lastYPixels = newYPixels;
- }
- count++;
- }
-
- path.reset();
-
- path.moveTo(0, getHeight()-bottomPadding);
- path.lineTo(sidePadding, getHeight()-bottomPadding);
- path.lineTo(sidePadding, 0);
- path.lineTo(0, 0);
- path.close();
- canvas.drawPath(path, paint);
-
- path.reset();
-
- path.moveTo(getWidth(), getHeight()-bottomPadding);
- path.lineTo(getWidth()-sidePadding, getHeight()-bottomPadding);
- path.lineTo(getWidth()-sidePadding, 0);
- path.lineTo(getWidth(), 0);
- path.close();
-
- canvas.drawPath(path, paint);
-
- }
-
- lineCount++;
- }
-
- paint.reset();
-
- paint.setColor(Color.BLACK);
- paint.setAlpha(50);
- paint.setAntiAlias(true);
- canvas.drawLine(sidePadding, getHeight() - bottomPadding, getWidth()-sidePadding, getHeight()-bottomPadding, paint);
- paint.setAlpha(255);
-
- for (Line line : lines){
- int count = 0;
- float lastXPixels = 0, newYPixels = 0;
- float lastYPixels = 0, newXPixels = 0;
-
- paint.setColor(line.getColor());
- paint.setStrokeWidth(getStrokeWidth(line));
-
- for (LinePoint p : line.getPoints()){
- float yPercent = (p.getY()-minY)/(maxY - minY);
- float xPercent = (p.getX()-minX)/(maxX - minX);
- if (count == 0){
- lastXPixels = sidePadding + (xPercent*usableWidth);
- lastYPixels = getHeight() - bottomPadding - (usableHeight*yPercent);
- } else {
- newXPixels = sidePadding + (xPercent*usableWidth);
- newYPixels = getHeight() - bottomPadding - (usableHeight*yPercent);
- canvas.drawLine(lastXPixels, lastYPixels, newXPixels, newYPixels, paint);
- lastXPixels = newXPixels;
- lastYPixels = newYPixels;
- }
- count++;
- }
- }
-
-
- int pointCount = 0;
-
- for (Line line : lines){
- paint.setColor(line.getColor());
- paint.setStrokeWidth(getStrokeWidth(line));
- paint.setStrokeCap(Paint.Cap.ROUND);
-
- if (line.isShowingPoints()){
- for (LinePoint p : line.getPoints()){
- float yPercent = (p.getY()-minY)/(maxY - minY);
- float xPercent = (p.getX()-minX)/(maxX - minX);
- float xPixels = sidePadding + (xPercent*usableWidth);
- float yPixels = getHeight() - bottomPadding - (usableHeight*yPercent);
- int outerRadius;
- if (line.isUsingDips()) {
- outerRadius = getPixelForDip(line.getStrokeWidth() + 4);
- }
- else {
- outerRadius = line.getStrokeWidth() + 4;
- }
- int innerRadius = outerRadius / 2;
- paint.setColor(Color.parseColor(p.getColor()));
- canvas.drawCircle(xPixels, yPixels, outerRadius, paint);
- paint.setColor(Color.WHITE);
- canvas.drawCircle(xPixels, yPixels, innerRadius, paint);
-
- Path path2 = new Path();
- path2.addCircle(xPixels, yPixels, 30, Direction.CW);
- p.setPath(path2);
- p.setRegion(new Region((int)(xPixels-30), (int)(yPixels-30), (int)(xPixels+30), (int)(yPixels+30)));
-
- if (indexSelected == pointCount && listener != null){
- paint.setColor(Color.parseColor(p.getColor()));
- paint.setAlpha(100);
- canvas.drawPath(p.getPath(), paint);
- paint.setAlpha(255);
- }
-
- pointCount++;
- }
- }
- }
-
- shouldUpdate = false;
- }
-
- ca.drawBitmap(fullImage, 0, 0, null);
-
-
- }
- private int getStrokeWidth(Line line) {
- int strokeWidth;
- if (line.isUsingDips()) {
- strokeWidth = getPixelForDip(line.getStrokeWidth());
- }
- else {
- strokeWidth = line.getStrokeWidth();
- }
- return strokeWidth;
- }
- private int getPixelForDip(int dipValue) {
- return (int) TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP,
- dipValue,
- getResources().getDisplayMetrics());
- }
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- Point point = new Point();
- point.x = (int) event.getX();
- point.y = (int) event.getY();
-
- int count = 0;
- int lineCount = 0;
- int pointCount = 0;
-
- Region r = new Region();
- for (Line line : lines){
- pointCount = 0;
- for (LinePoint p : line.getPoints()){
-
- if (p.getPath() != null && p.getRegion() != null){
- r.setPath(p.getPath(), p.getRegion());
- if (r.contains((int)point.x,(int) point.y) && event.getAction() == MotionEvent.ACTION_DOWN){
- indexSelected = count;
- } else if (event.getAction() == MotionEvent.ACTION_UP){
- if (r.contains((int)point.x,(int) point.y) && listener != null){
- listener.onClick(lineCount, pointCount);
- }
- indexSelected = -1;
- }
- }
-
- pointCount++;
- count++;
- }
- lineCount++;
-
- }
-
- if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_UP){
- shouldUpdate = true;
- postInvalidate();
- }
-
-
- return true;
- }
-
- public void setOnPointClickedListener(OnPointClickedListener listener) {
- this.listener = listener;
- }
-
- public interface OnPointClickedListener {
- abstract void onClick(int lineIndex, int pointIndex);
- }
- }
|