How to display text dynamically on pie chart in android? - android

I have worked on pie chart in android. I found an excellent solution from http://tutorials-android.blogspot.in/2011/05/how-create-pie-chart-in-android.html and worked on that. I am able to display the pie chart with colors but in my application in addition to colors I need to display the text also dynamically on that pie chart. How can I display text dynamically on those pie chart slices?
Please help me regarding this...Will be thankful...

To draw piechart you had use very long process.....Hope this help you..
public class Demo extends Activity {
/** Called when the activity is first created. */
float values[]={500,400,300,200,100};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LinearLayout linear=(LinearLayout) findViewById(R.id.linear);
values=calculateData(values);
linear.addView(new MyGraphview(this,values));
}
private float[] calculateData(float[] data) {
// TODO Auto-generated method stub
float total=0;
for(int i=0;i<data.length;i++)
{
total+=data[i];
}
for(int i=0;i<data.length;i++)
{
data[i]=360*(data[i]/total);
}
return data;
}
public class MyGraphview extends View
{
private Paint paint=new Paint(Paint.ANTI_ALIAS_FLAG);
private float[] value_degree;
private int[] COLORS={Color.BLUE,Color.GREEN,Color.GRAY,Color.CYAN,Color.RED};
RectF rectf = new RectF (10, 10, 200, 200);
int temp=0;
public MyGraphview(Context context, float[] values) {
super(context);
value_degree=new float[values.length];
for(int i=0;i<values.length;i++)
{
value_degree[i]=values[i];
}
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
for (int i = 0; i < value_degree.length; i++) {//values2.length; i++) {
if (i == 0) {
paint.setColor(COLORS[i]);
canvas.drawArc(rectf, 0, value_degree[i], true, paint);
}
else
{
temp += (int) value_degree[i - 1];
paint.setColor(COLORS[i]);
canvas.drawArc(rectf, temp, value_degree[i], true, paint);
}
}
}
}
}
Which set the color according to values in decending order...
And for text,you can set dynamic text separately and give color square in front of text:)

To draw text at the centre of each pie chart segment you need to calculate the centre of each segment. The centre of each text item to paint on that segment should align with that centre point - which is achieved by subtracting half the text bounds width from the central x coord (or using paint.setTextAlign(Align.CENTER); ) and half the text bound height from the central y coord.
As for finding the centre of a segment, it requires just a little bit more consideration than using simple geometry.
The central coords of a segment can be found by:
x = (/* radius of pie chart */ /2)*cos(/*angle in RADIANS */) [angle in radians = Math.toRadians(/*half the sweep angle in degrees*/)
y = (/* radius of pie chart */ /2)*sin(/*angle in RADIANS */)
Almost there... dont forget to add the x and y coords of the centre of your pie chart to the above x and y values, otherwise you're trying to paint on a circle centring on (0,0) in your custom view!
Say your pie chart is centred at the actual centre of your view, you want to be adding:
x += getWidth()/2;
y += getHeight()/2;
Last but not least, accounting for the length of the text to be painted - get the bounds of your text using, for example:
Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setTextAlign(Align.CENTER); // This centres the text horizontally
String labelText = "TEST";
Rect textBounds = new Rect();
paint.getTextBounds(labelText, 0, labelText.length(), textBounds);
y -= textBounds.height()/2;
Then your text should appear correctly.

You can use the library called MPAndroidChart, which is very simple and easy to use. Simply import this
compile 'com.github.PhilJay:MPAndroidChart:v3.0.1'
and add this line in your gradle file
allprojects {
repositories {
maven { url "https://jitpack.io" }
}
}
Hope this will help you.

#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mState != IS_READY_TO_DRAW) {
return;
}
canvas.drawColor(mBgcolor);
mBagpaints.setAntiAlias(true);
mBagpaints.setStyle(Paint.Style.FILL);
mBagpaints.setColor(0x88FF0000);
mBagpaints.setStrokeWidth(0.0f);
mLinePaints.setAntiAlias(true);
mLinePaints.setColor(0xff000000);
mLinePaints.setStrokeWidth(3.0f);
mLinePaints.setStyle(Paint.Style.STROKE);
RectF mOvals = new RectF(mGapleft, mGapTop, mWidth - mGapright, mHeight
- mGapBottm);
mStart = START_INC;
PieDetailsItem item;
for (int i = 0; i < mdataArray.size(); i++) {
item = (PieDetailsItem) mdataArray.get(i);
mBagpaints.setColor(item.color);
mSweep = (float) 360* ((float) item.count / (float) mMaxConnection);
canvas.drawArc(mOvals, mStart, mSweep, true, mBagpaints);
canvas.drawArc(mOvals, mStart, mSweep, true, mLinePaints);
mStart = mStart + mSweep;
// set your text here
canvas.drawText("here is some text", mStart, someYvalue, mLinePaints);
}
mState = IS_DRAW;
}
Just some drawText() calls ought to work fine.
You'll have to do a little math to decide where your y coordinate should be

Related

Move a ball on Grid path randomly in Canvas Android

Requirement is to keep a ball moving on the Grid path generated in Canvas. I have generated a Grid in canvas but not able to understand how to move the ball randomly means starting point show be different on the path. I am sharing what I have done. I have also plotted the ball in the screen but not getting the point how to put the ball exactly on the grid line randomly and start moving it
public class PixelGridView extends View {
//number of row and column
int horizontalGridCount = 11;
private Drawable horiz;
private Drawable vert;
private final float width;
long mInterpolateTime;
PointF mImageSource = new PointF();
public PixelGridView(#NonNull Context context) {
this(context, null);
}
public PixelGridView(#NonNull Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
horiz = new ColorDrawable(Color.WHITE);
horiz.setAlpha(160);
vert = new ColorDrawable(Color.WHITE);
vert.setAlpha(160);
width = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, .9f, context.getResources().getDisplayMetrics());
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
horiz.setBounds(left, 0, right, (int) width);
vert.setBounds(0, top, (int) width, bottom);
}
private float getLinePosition(int lineNumber) {
int lineCount = horizontalGridCount;
return (1f / (lineCount + 1)) * (lineNumber + 1f);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//drawTask.start();
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.WHITE);
paint.setAntiAlias(true);
canvas.drawCircle(120, 110, 10, paint);
int count = horizontalGridCount;
for (int n = 0; n < count; n++) {
float pos = getLinePosition(n);
// Draw horizontal line
canvas.translate(0, pos * getHeight());
Log.e("Position1", "" + pos * getHeight());
horiz.draw(canvas);
canvas.translate(0, -pos * getHeight());
// Draw vertical line
canvas.translate(pos * getHeight(), 0);
Log.e("Position2", "" + pos * getHeight());
vert.draw(canvas);
canvas.translate(-pos * getHeight(), 0);
}
}
}[![Canvas Image][1]][1]
//MainActivity
public class PathAnimationActivity extends AppCompatActivity {
LinearLayout rlLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_path);
rlLayout=findViewById(R.id.rlLayout);
PixelGridView pixelGrid = new PixelGridView(this);
rlLayout.addView(pixelGrid);
}
}
First thing i have noticed it that you haven't used invalidate (); at the end because thats critical in order to animate the canvas ( redraw the frames ) so please include that .
there may be several ways to achieve what you want follows is my idea
this canvas need to be divided into multiple x , y divided planes as follows and save them in array of points which you can randomize and give those points to ball to move ,
Step 1, get the canvas size
step 2, divide is in x and y coordinate depending on size of each device varies so you need to control that factor via Screen size
step 3, save the coordinates in matrix or array
step 4, set position of balls from those arrays values ( randomly can you define the random limits as per the max and min values of x and y from the coordinates division .
example , function move will take ball object and x, y are the positions move (ball, x, y ); and you can randomize the x and y based on max and min limits of your coordinates division example total y lines and total x lines values
in order to get an idea about how to move the ball on canvas you can see this code here : https://github.com/pintspin/ball_animation

Canvas.drawLines() produces gaps between lines

I use drawLines() on my dataset of points. It's drawn perfectly when it starts from (0,0), but when the dataset starts from another point it produces some gaps.
Here the chart starting with (0, 0) (added small line at left bottom):
Here it starts from from (83, 56) and produces gap:
What I've tried:
Setting on/off anti-alias.
Different datasets (they all produce gap at the top y point if there is nothing drawn at (0, 0).
I've read about trying drawPath(), but since I need to draw lots of lines it was said to be not as effecient as drawLines().
Here are some snippets from my project:
My dataset:
x = {
0,12,83,84,84,121,121,128,128,151,151,173,173,203,203,217,217,224,224,229,229,253,253,294,294,305,305,331,331,355,355,364,364,409,409,411,411,416,416,431,431,448,448,497,497,504,504,508,508,536,536,582,582,586,586,630,630,646,646,660,660,689,689,728,728,761,761,768,768,798,798,822,822,860,860,894,894,908,908,952,952,996,996,1039,1039,1085,1085,1085,1085,1099,1099,1119,1119,1133,1133,1169
}
y = {
0,12,56,115,115,220,220,232,232,170,170,350,350,117,117,157,157,205,205,290,290,184,184,127,127,181,181,231,231,210,210,278,278,142,142,120,120,299,299,29,29,290,290,50,50,258,258,127,127,203,203,168,168,27,27,27,27,83,83,116,116,228,228,295,295,62,62,299,299,121,121,216,216,266,266,164,164,234,234,116,116,182,182,130,130,208,208,218,218,202,202,85,85,59,59,114
}
How I set my Paint:
private void init() {
chartPaint = new Paint();
chartPaint.setStyle(Paint.Style.STROKE);
chartPaint.setStrokeWidth(4);
chartPaint.setColor(color);
}
My onDraw():
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
// let chart start from the most left without gaps
canvas.translate(0, viewHeight);
// TODO: find place to move calcs outside onDraw()
final float xScale = (float) viewWidth / (Util.getMax(x) - Util.getMin(x));
final float yScale = (float) -viewHeight / (Util.getMax(y) - Util.getMin(y));
valuesScaled = new float[values.length];
for (int i = 0; i < values.length; i++) {
valuesScaled[i] = (i%2==0) ? values[i] * xScale : values[i] * yScale;
}
canvas.drawLines(valuesScaled, chartPaint);
canvas.restore();
}
values array is where x and y arrays are stored alternatively, i.e. first 4 elements of values are {x[0], y[0], x[1], y[1], ...}
viewWidth and viewHeight are taken from onSizeChange().

How to animate a line in android?

I need to draw a line from point A(x1,y1) to point B(x2, y2). But instead of just show the line, I need to see the line was actually drawn - little bit by little bit, at a controllable speed - from point A to point B. I've tried alarms and loops for this but cant find my solution.I am working on surface view. Please give solution for this
U can do it like this:
private int startX = 0;
private int startY = 0;
private int endX = 0;
private int endY = 0;
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG) {
{
setDither(true);
setColor(Color.RED);
}
};
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawLine(startX, startY, endX, endY, paint);
if (endX != 300 && endY != 300) { // set end points
endY++;
endX++;
postInvalidateDelayed(15); // set time here
}
}

Redrawing canvas, for updating and then setting text on it not working

I have canvas which draws pie chart for me. After I change radio button to disagree position, my pie chart has to show different values. I am doing this with Listener (setted up on radio group). It is working but for updating the canvas (not adding and overdrawing, I have to clear it first and redraw with new values) I use this:
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
Under the piechart I want to write number of percent. It is working without that line what is on top. But after I execute the line, only piechart is redrawn (with new values) but text with percentage is not shown (even if I set text to that again):
if (checkedId == R.id.agreeRadio) {
values[0] += 1;
values[1] -= 1;
setupPieChart();
setupPercentageValueToGraph();
}
Method calculating percentage and writing it:
public void setupPercentageValueToGraph() {
float[] degrees = calculateData(values);
// get percentage number from values
float percentage = (degrees[0] / (degrees[0] + degrees[1])) * 100;
// setup color of the number shown red/green
if (percentage >= 50) {
percentageTV.setTextColor(Color.parseColor("#47B243"));
} else {
percentageTV.setTextColor(Color.parseColor("#DB262A"));
}
// set the text
percentageTV.setText((int) percentage + "%");
}
Method to set piechart to linearLayout:
public void setupPieChart() {
float[] degrees = calculateData(values);
graphLayout.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
graphLayout.addView(new MyGraphView(this, degrees, size));
}
Class which is drawing the piechart where that clear is used:
public class MyGraphView extends View {
public static final int PADDING = 4;
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private float[] value_degree;
int strokeWidth;
private int[] COLORS = { Color.parseColor("#47B243"),
Color.parseColor("#DB262A") };
// size of bigger half circle
RectF rectf = new RectF(2, 2, 62, 62);
// size of smaller half circle
RectF rectf2 = new RectF(9, 9, 55, 55);
// size of the smallest half circle
RectF rectf3 = new RectF(16, 16, 48, 48);
int temp = 0;
public MyGraphView(Context context, float[] values, int size) {
super(context);
// setting up size of pie chart dynamically
int difference = size / 9;
rectf.set(PADDING, PADDING, size + PADDING, size + PADDING);
rectf2.set(difference + PADDING, difference + PADDING, size
- difference + PADDING, size - difference + PADDING);
rectf3.set(difference * 2 + PADDING, difference * 2 + PADDING, size
- difference * 2 + PADDING, size - difference * 2 +
PADDING);
// setting up brush size
strokeWidth = size / 15;
// assign degrees of agree and disagree to array
value_degree = new float[values.length];
for (int i = 0; i < values.length; i++) {
value_degree[i] = values[i];
}
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
//canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
for (int i = 0; i < value_degree.length; i++) {
// set type of "brush"
paint.setStrokeWidth(strokeWidth);
paint.setStyle(Paint.Style.STROKE);
// set shadow
paint.setShadowLayer(2, 1, 1, Color.BLACK);
// setLayerType(LAYER_TYPE_SOFTWARE, paint);
// agree
if (i == 0) {
final Path path = new Path();
paint.setColor(COLORS[i]);
// draw 3 paths to show 3 curves
path.addArc(rectf, 180, value_degree[i] - 4);
path.addArc(rectf2, 180, value_degree[i] - 5);
path.addArc(rectf3, 180, value_degree[i] - 6);
// draw the path
canvas.drawPath(path, paint);
// disagree
} else {
temp += (int) value_degree[i - 1];
paint.setColor(COLORS[i]);
final Path path = new Path();
path.addArc(rectf, temp + 180 + 4, value_degree[i] - 4);
path.addArc(rectf2, temp + 180 + 5, value_degree[i] - 5);
path.addArc(rectf3, temp + 180 + 6, value_degree[i] - 6);
// draw the path
canvas.drawPath(path, paint);
}
}
}
}
Any idea why text is not written? Or any other way how to update piechart after radiobutton is changed?
Finally I found a way how to do it. To draw the text on the same canvas as graph was drawn:
// draw the number of percent under piechart
// setup brush
Paint paint2 = new Paint(Paint.ANTI_ALIAS_FLAG);
// set shadow
paint2.setShadowLayer(3, 2, 2, Color.parseColor("#404040"));
// fill it not stroke
paint2.setStyle(Style.FILL);
// set text family + make it bold
paint2.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
// convert dp to pixels and setup the size of text
int MY_DIP_VALUE = 23; // 5dp
int pixel = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, MY_DIP_VALUE,
getResources()
.getDisplayMetrics());
// setup color of the number shown red/green
if (percent >= 50) {
paint2.setColor(COLORS[0]);
} else {
paint2.setColor(COLORS[1]);
}
// draw the text
paint2.setTextSize(pixel);
float textWidth = paint2.measureText(percent + "%");
canvas.drawText(percent + "%", size / 2 - textWidth / 2 + PADDING,
size, paint2);
I have removed TextView and did few little changes, but the key was to draw it. Still dont understand why I was not able to write text on it but had to draw but it is working!

DrawLine function changes color of my lines, when it shouldn't

This is the onDraw method I have:
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(bitmap, 0, 0, mBitmapPaint); // Deseneaza Bitmapul mutabil
if (shapes.size() > 0) {
for (ShapeFromLines shapesfromline : shapes) {
if (shapesfromline.size() > 1) {
LogService.log("", "shapes: " + shapesfromline.size());
float startx, starty;
startx = shapesfromline.get(0).stopX;
starty = shapesfromline.get(0).stopY;
for (int i = 1; i < shapesfromline.size(); i++) {
LogService.log("", "----size color in ondraw: " + shapesfromline.get(i).getPaint().getColor());
canvas.drawLine(startx, starty, shapesfromline.get(i).getStopX(), shapesfromline.get(i).stopY, shapesfromline.get(i).getPaint());
LogService.log("", "shapes: drawn");
startx = shapesfromline.get(i).stopX;
starty = shapesfromline.get(i).stopY;
}
}
}
}
for (int i = 0; i < bitmaps.size(); i++) {
if ((bitmaps.get(i).bitmap != null)) {
canvas.save();
canvas.rotate(bitmaps.get(i).rectrotateVal, bitmaps.get(i).pX + (bitmaps.get(i).bitmap.getWidth() / 2), bitmaps.get(i).pY + (bitmaps.get(i).bitmap.getHeight() / 2));
mBitmapPaint.setAlpha(bitmaps.get(i).alpha);
// canvas.drawRect(bitmaps.get(i).rect, cPaint);
canvas.drawBitmap(bitmaps.get(i).bitmap, bitmaps.get(i).pX, bitmaps.get(i).pY, mBitmapPaint);
canvas.restore();
}
}
mBitmapPaint.setAlpha(255);
canvas.drawPath(mPath, paint);
}
}
As you can I I have some Shapes (each shape is created from an arraylist of points named ShapesFromLines. Now the first point of my shape is from the touchDown (ontouchevent), where I save the current location. then the other points are saved on touch up. When you press the screen the first time it will draw a point, then the second time, it will connect those 2 points, then 3, etc. I save the X,Y and Paint on each point.
As you can see, I have a logservice on draw, which returns the paint value for those points. Now I have a function with a color picker that changes the color of the current path. But this manages to change the color of all my straight lines. Now I checked, when I want to add a picture, the main paint is set to transparent. And then the lines are transparent, but the points (that should be connected) have the right color. Any ideea what could be wrong?
when I created the objects, i passed the paint as a reference, and when changing it, it would change the paint also.
I did this to fix it:
Paint linepaint = new Paint();
linepaint.setColor(paint.getColor());
linepaint.setAlpha(paint.getAlpha());
linepaint.setAntiAlias(true);
linepaint.setDither(true);
linepaint.setStyle(paint.getStyle());
linepaint.setStrokeJoin(paint.getStrokeJoin());
linepaint.setStrokeCap(paint.getStrokeCap());
linepaint.setStrokeWidth(paint.getStrokeWidth());
pointsForLines.add(new Points(stopX, stopY, linepaint));
Where paint was the global paint I was using before

Categories

Resources