Skip to content

Instantly share code, notes, and snippets.

@MehdiFal
Created November 9, 2018 09:25
Show Gist options
  • Save MehdiFal/36d0883632166a2b8e92211972f5dacb to your computer and use it in GitHub Desktop.
Save MehdiFal/36d0883632166a2b8e92211972f5dacb to your computer and use it in GitHub Desktop.
<com.test.graphvisualizer.Graph
android:id="@+id/graph"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:paddingLeft="35dp"
android:paddingStart="35dp"
android:paddingRight="35dp"
android:paddingEnd="35dp"
android:paddingTop="100dp"
android:paddingBottom="100dp"
app:gradColorStart="@color/greenDark"
app:gradColorEnd="@color/greenLight"
app:markerColor="@color/greenDark"
app:connectedLinesColor="@color/greenDark"
app:guidelinesColor="@color/gray"
app:graduationColor="@color/gray" />
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="Graph">
<attr name="gradColorStart" format="color"/>
<attr name="gradColorEnd" format="color"/>
<attr name="markerColor" format="color"/>
<attr name="connectedLinesColor" format="color"/>
<attr name="guidelinesColor" format="color"/>
<attr name="graduationColor" format="color"/>
</declare-styleable>
</resources>
public class Graph extends View {
private Paint paint;
private Paint gradientPaint;
private Paint connectionPaint;
private Path path;
private int markerColor;
private int connectedLinesColor;
private int guidelinesColor;
private int graduationColor;
private int graphHeight;
private int weeksCount;
private int weekWidth;
private int maxXGraduation;
private int maxYGraduation;
private List<Marker> markers;
public Graph (Context context) {
super (context);
init (context, null, 0, 0);
}
public Graph (Context context, @Nullable AttributeSet attrs) {
super (context, attrs);
init (context, attrs, 0, 0);
}
public Graph (Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super (context, attrs, defStyleAttr);
init (context, attrs, defStyleAttr, 0);
}
@RequiresApi (api = Build.VERSION_CODES.LOLLIPOP)
public Graph (Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super (context, attrs, defStyleAttr, defStyleRes);
init (context, attrs, defStyleAttr, defStyleRes);
}
private void init (Context context, AttributeSet attrs, int defStyle, int defStyleRes) {
paint = new Paint (Paint.ANTI_ALIAS_FLAG);
path = new Path ();
final TypedArray typedArray = context.obtainStyledAttributes (attrs, R.styleable.Graph, defStyle, defStyleRes);
int defaultColor = getResources ().getColor (R.color.colorPrimary);
markerColor = typedArray.getColor (R.styleable.Graph_markerColor, defaultColor);
connectedLinesColor = typedArray.getColor (R.styleable.Graph_connectedLinesColor, defaultColor);
guidelinesColor = typedArray.getColor (R.styleable.Graph_guidelinesColor, defaultColor);
graduationColor = typedArray.getColor (R.styleable.Graph_graduationColor, defaultColor);
int gradColorStart = typedArray.getColor (R.styleable.Graph_gradColorStart, defaultColor);
int gradColorEnd = typedArray.getColor (R.styleable.Graph_gradColorEnd, defaultColor);
LinearGradient gradient = new LinearGradient (
getPaddingLeft (),
getPaddingTop (),
getPaddingRight (),
getHeight () - getPaddingBottom (),
new int[] { gradColorStart, gradColorEnd },
null,
Shader.TileMode.CLAMP
);
gradientPaint = new Paint (Paint.ANTI_ALIAS_FLAG);
gradientPaint.setStyle (Paint.Style.FILL);
gradientPaint.setShader (gradient);
connectionPaint = new Paint ();
connectionPaint.setColor (connectedLinesColor);
connectionPaint.setStrokeWidth (3);
typedArray.recycle ();
}
@Override
protected void onDraw (Canvas canvas) {
super.onDraw (canvas);
if (markers == null) {
return;
}
drawSkeleton (canvas);
drawGraduations (canvas);
drawConnectPoints (canvas);
colorAreaBelowPoints (canvas);
}
private void drawSkeleton (Canvas canvas) {
// draw Y axis
weekWidth = (getWidth () - getPaddingLeft () - getPaddingRight ()) / weeksCount;
graphHeight = getHeight () - getPaddingTop () - getPaddingBottom ();
initSkeletonPaint ();
int maxY = getHeight () - getPaddingBottom ();
int x = getPaddingLeft ();
for (int i = 0; i < weeksCount; i ++) {
path.moveTo (x, getPaddingTop ());
path.lineTo (x, maxY);
canvas.drawPath (path, paint);
path.reset ();
x += weekWidth;
}
path.reset ();
paint.reset ();
}
private void initSkeletonPaint () {
paint.setStyle (Paint.Style.STROKE);
paint.setStrokeWidth (2);
paint.setColor (guidelinesColor);
float [] interval = new float [graphHeight / 10];
for (int i = 0; i < interval.length; i ++) {
interval [i] = 10;
}
paint.setPathEffect (new DashPathEffect (interval, 0f));
}
private void drawGraduations (Canvas canvas) {
initGraduationsPaint ();
int x = getWidth () - getPaddingRight ();
float distY = (100f * graphHeight) / maxYGraduation;
float y = getHeight () - getPaddingBottom ();
for (int i = 0; i <= maxYGraduation; i += 100) {
canvas.drawText (String.valueOf (i), x, y, paint);
y -= distY;
}
path.reset ();
paint.reset ();
}
private void initGraduationsPaint () {
paint.setColor (graduationColor);
paint.setTextAlign (Paint.Align.LEFT);
paint.setTextSize (40);
}
private void drawConnectPoints (Canvas canvas) {
initPointsPaint ();
float distBetweenPoints = ((float) weekWidth) / 7;
float centerX = getPaddingLeft ();
float prevX = -1f;
float prevY = -1f;
for (Marker marker : markers) {
float centerY = (getHeight () - getPaddingBottom ()) - (marker.getValue () * graphHeight) / maxYGraduation;
if (prevX != -1f) {
canvas.drawLine (prevX, prevY, centerX, centerY, connectionPaint);
}
prevX = centerX;
prevY = centerY;
canvas.drawCircle (centerX, centerY, 7, paint);
centerX += distBetweenPoints;
}
paint.reset ();
}
private void initPointsPaint () {
paint.setStyle (Paint.Style.FILL);
paint.setStrokeWidth (5);
paint.setColor (markerColor);
}
private void colorAreaBelowPoints (Canvas canvas) {
path.moveTo (getPaddingLeft (), getHeight () - getPaddingBottom ());
float centerX = getPaddingLeft ();
float distBetweenPoints = ((float) weekWidth) / 7;
for (Marker marker : markers) {
float centerY = (getHeight () - getPaddingBottom ()) - (marker.getValue () * graphHeight) / maxYGraduation;
path.lineTo (centerX, centerY);
centerX += distBetweenPoints;
}
float firstY = (getHeight () - getPaddingBottom ()) - (markers.get (0).getValue () * graphHeight) / maxYGraduation;
float lastX = centerX - distBetweenPoints;
path.lineTo (lastX, getHeight () - getPaddingBottom ());
path.lineTo (getPaddingLeft (), firstY);
canvas.drawPath (path, gradientPaint);
path.reset ();
}
public void setData (List<Marker> markers) {
this.markers = markers;
int maxY = maxValue (markers);
maxXGraduation = markers.size () + 1;
maxYGraduation = ((maxY / 100) + 1) * 100;
for (Marker marker : markers) {
weeksCount = Math.max (weeksCount, marker.getWeek ());
}
invalidate ();
}
private int maxValue (List<Marker> markers) {
int maxValue = 0;
for (Marker marker : markers) {
maxValue = Math.max (maxValue, marker.getValue ());
}
return maxValue;
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
setContentView (R.layout.activity_main);
Graph graph = findViewById (R.id.graph);
graph.setData (markers ());
}
private List<Marker> markers () {
List<Marker> markers = new ArrayList<> ();
markers.add (new Marker (0, 1, 1, 1));
markers.add (new Marker (200, 2, 1, 1));
markers.add (new Marker (100, 3, 1, 1));
markers.add (new Marker (150, 4, 1, 1));
markers.add (new Marker (50, 5, 1, 1));
markers.add (new Marker (0, 6, 1, 1));
markers.add (new Marker (350, 7, 1, 1));
markers.add (new Marker (320, 1, 2, 1));
markers.add (new Marker (320, 2, 2, 1));
markers.add (new Marker (275, 3, 2, 1));
markers.add (new Marker (0, 4, 2, 1));
markers.add (new Marker (0, 5, 2, 1));
markers.add (new Marker (200, 6, 2, 1));
markers.add (new Marker (30, 7, 2, 1));
markers.add (new Marker (550, 1, 3, 1));
markers.add (new Marker (80, 2, 3, 1));
markers.add (new Marker (110, 3, 3, 1));
markers.add (new Marker (50, 4, 3, 1));
markers.add (new Marker (50, 5, 3, 1));
markers.add (new Marker (80, 6, 3, 1));
markers.add (new Marker (50, 7, 3, 1));
markers.add (new Marker (0, 1, 4, 1));
markers.add (new Marker (30, 2, 4, 1));
markers.add (new Marker (70, 3, 4, 1));
markers.add (new Marker (110, 4, 4, 1));
markers.add (new Marker (70, 5, 4, 1));
markers.add (new Marker (0, 6, 4, 1));
markers.add (new Marker (30, 7, 4, 1));
markers.add (new Marker (70, 1, 5, 1));
markers.add (new Marker (130, 2, 5, 1));
markers.add (new Marker (250, 3, 5, 1));
return markers;
}
}
public class Marker {
private int value;
private int day;
private int week;
private int month;
public Marker (int value, int day, int week, int month) {
this.value = value;
this.day = day;
this.week = week;
this.month = month;
}
public int getValue () {
return value;
}
public void setValue (int value) {
this.value = value;
}
public int getDay () {
return day;
}
public void setDay (int day) {
this.day = day;
}
public int getWeek () {
return week;
}
public void setWeek (int week) {
this.week = week;
}
public int getMonth () {
return month;
}
public void setMonth (int month) {
this.month = month;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment