Canvas.drawLine is filling like a shape - android

I'm trying to draw a ECG Graph, that consist of a thin line, but when I invoke the Canvas drawLine method, the method fills the top of the line like a shape
This is the class that paint the Graph:
public class ECGView extends View{
private Bitmap mBitmap;
private Paint mPaint = new Paint();
private Canvas mCanvas = new Canvas();
private final float MAX_MILISECONDS = 5000f;
private final float INTERVAL = 4;
private float maxValue = 0;
private float minValue = 1023;
private float maxX;
private float deltaX;
private float lastX;
private float maxY;
private float deltaY;
private float lastY;
private int lineColor = Color.argb(192, 0, 0, 128);
public ECGView(Context context) {
super(context);
mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(lineColor);
mPaint.setStyle(Style.STROKE);
//mPaint.setStrokeWidth(0.5f);
lastX = 0;
lastY = 0;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
mCanvas.setBitmap(mBitmap);
mCanvas.drawColor(0xFFFFFFFF);
maxY = h;
maxX = w;
deltaX = maxX/(MAX_MILISECONDS/INTERVAL);
lastX = maxX;
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
if(mBitmap != null){
final Canvas cavas = mCanvas;
if(lastX >= maxX){
lastX = 0;
cavas.drawColor(0xFFFFFFFF);
}
canvas.drawBitmap(mBitmap, 0, 0, null);
}
super.onDraw(canvas);
}
public synchronized void addData(short[] values){
if(mBitmap != null){
final Canvas canvas = mCanvas;
final Paint paint = mPaint;
for(short value : values){
if(value > maxValue) maxValue = value;
if(value < minValue) minValue = value;
if(minValue == maxValue)
deltaY = maxY/1023.0f;
else{
deltaY =maxY/(maxValue-minValue);
value -= minValue;
}
final float newX = lastX+deltaX;
final float newY = deltaY*value;
canvas.drawLine(lastX, lastY, newX, newY, paint);
lastX += deltaX;
invalidate();
}
}
}
}
Am I missing something?

You're not updating lastY, so it's drawing each line from y=0(the top) to the current position.

Related

canvas.drawPath() is not drawing in real-time

As building upon this drawing library here, the library didn't provide a way to change stroke color or width of a single one but only changing those properties of all of the drawen strokes at the same time. So I decided to seperate each stroke with its own property to be drawen. However now the drawing stroke is not appearing in real-time when moving the finger on the screen. The whole stroke only appears upon the touch_up() function. I assume the problem is from canvas.drawPath(myPath, myPaint); in the onDraw() function but I can not manage to find what causes the problem. Does anyone know what the problem of the strokes not drawing in real-time is? Or how to fix it?
DrawingView.java:
public class DrawingView extends View {
private Paint canvasPaint;
private Canvas drawCanvas;
private Bitmap canvasBitmap;
private ArrayList<Path> paths = new ArrayList<Path>();
private ArrayList<Path> undonePaths = new ArrayList<Path>();
private ArrayList<float[]> PointsCal = new ArrayList<float[]>();
private ArrayList<float[]> Points = new ArrayList<float[]>();
private ArrayList<Integer> id = new ArrayList<Integer>();
private int counter;
public static WebSocket ws;
private OkHttpClient client;
Context myContext;
Stroke drawnStroke;
private List<Stroke> allStrokes;
public DrawingView(Context context, AttributeSet attr) {
super(context, attr);
setupDrawing();
myContext = context;
}
private void setupDrawing() {
allStrokes = new ArrayList<Stroke>();
drawnStroke = new Stroke();
canvasPaint = new Paint(Paint.DITHER_FLAG);
drawCanvas = new Canvas();
drawnStroke.paint.setAntiAlias(true);
drawnStroke.paint.setStyle(Paint.Style.STROKE);
drawnStroke.paint.setStrokeJoin(Paint.Join.ROUND);
drawnStroke.paint.setStrokeCap(Paint.Cap.ROUND);
counter = 0;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
drawCanvas = new Canvas(canvasBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
if (allStrokes != null) {
for (Stroke stroke : allStrokes) {
if (stroke != null) {
Path myPath = stroke.getPath();
Paint myPaint = stroke.getPaint();
myPaint.setAntiAlias(true);
myPaint.setStyle(Paint.Style.STROKE);
//this function below is not rendering in real time
canvas.drawPath(myPath, myPaint);
}
}
}
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touch_start(float x, float y) {
drawnStroke.getPaint().setColor(UserSettings.color);
drawnStroke.getPaint().setStrokeWidth(UserSettings.width);
drawnStroke.getPath().moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
drawnStroke.path.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
private void touch_up() {
drawnStroke.path.lineTo(mX, mY);
drawCanvas.drawPath(drawnStroke.path, drawnStroke.paint);
allStrokes.add(drawnStroke);
drawnStroke = new Stroke();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
float coordinates[] = {0f, 0f};
float coord[] = {0f, 0f};
String eventString;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
coordinates[0] = x;
coordinates[1] = y;
PointsCal.add(coordinates);
Points.add(coordinates);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
coordinates[0] = x;
coordinates[1] = y;
PointsCal.add(coordinates);
coord[0] = coordinates[0] - PointsCal.get(PointsCal.size() - 2)[0];
coord[1] = coordinates[1] - PointsCal.get(PointsCal.size() - 2)[1];
Points.add(coord);
break;
case MotionEvent.ACTION_UP:
touch_up();
coordinates[0] = x;
coordinates[1] = y;
PointsCal.add(coordinates);
coord[0] = coordinates[0] - PointsCal.get(PointsCal.size() - 2)[0];
coord[1] = coordinates[1] - PointsCal.get(PointsCal.size() - 2)[1];
Points.add(coord);
String sample = "";
if (Points.size() > 2) {
counter++;
id.add(counter);
sample += ("#" + counter);
for (int i = 0; i < Points.size(); i++) {
sample += ("#" + Arrays.toString(Points.get(i)));
}
} else {
paths.remove(paths.size() - 1);
}
Points.clear();
PointsCal.clear();
invalidate();
break;
}
return true;
}
I believe this is because allStrokes.add(drawnStroke); is not called until the private method touch_up is called, so when iterating over allStrokes for drawing purposes, the current stroke is omitted. Try moving that line of code to touch_start.

How to plot dots on the pattern in a uniform distance in a canvas

What i have: Using the below code i am able to draw a pattern(Ex: Line) in the canvas.
What i am planning to do Or How to do this: I am trying to plot dots on that pattern in a uniform distance. (Hope i am clear)
ActDrawPaintImage.java
public class ActDrawPaintImage extends AppCompatActivity implements ColorPickerDialog.OnColorChangedListener {
MyView mv;
AlertDialog dialog;
#Bind(R.id.toolbar)
Toolbar mToolbar;
#Bind(R.id.btnNxtId)
Button btnNxtId;
private Paint mPaint;
private MaskFilter mEmboss;
private MaskFilter mBlur;
LinearLayout canvasLayoutId;
boolean mDotToDraw=false;
private int BRUSHSIZE=20;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_draw_paint_image);
//Bind the views
ButterKnife.bind(this);
initToolbar();
onClickSet();
//ADD THE VIEW WHERE THE IMAGE IS DRAWN
setTheCanvasView();
//SET BRUSH PROPERTIES
setUpBrushProperties();
mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 },0.4f, 6, 3.5f);
mBlur = new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL);
}
private void onClickSet() {
btnNxtId.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mDotToDraw==false){
mDotToDraw=true;
}else{
mDotToDraw=false;
}
}
});
}
private void setTheCanvasView() {
mv= new MyView(this);
mv.setDrawingCacheEnabled(true);
canvasLayoutId=(LinearLayout) findViewById(R.id.canvasLayoutId);
canvasLayoutId.addView(mv);
}
private void setUpBrushProperties() {
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(ContextCompat.getColor(ActDrawPaintImage.this, R.color.pattern_color));
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(BRUSHSIZE);
}
private void initToolbar() {
setSupportActionBar(mToolbar);
setTitle(getString(R.string.app_name));
mToolbar.setTitleTextColor(ContextCompat.getColor(ActDrawPaintImage.this, R.color.white));
}
public void colorChanged(int color) {
mPaint.setColor(color);
}
public class MyView extends View {
private static final float MINP = 0.25f;
private static final float MAXP = 0.75f;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
Context context;
private int width;
private int height;
public MyView(Context c) {
super(c);
context=c;
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width=w;
height=h;
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));
//mPaint.setMaskFilter(null);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
//Create a pointer and log the output
Log.d("POINTS", x + "," + y);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if(mDotToDraw==false){
touch_start(x, y);
}else{
touch_draw_circle(x, y);
}
invalidate();
break;
case MotionEvent.ACTION_MOVE:
if(mDotToDraw==false){
touch_move(x, y);
}else{
}
invalidate();
break;
case MotionEvent.ACTION_UP:
if(mDotToDraw==false){
touch_up();
}else{
}
invalidate();
break;
}
return true;
}
private void touch_draw_circle(float x, float y) {
/*int radius;
radius = 30;
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.WHITE);
mCanvas.drawPaint(paint);
// Use Color.parseColor to define HTML colors
paint.setColor(Color.parseColor("#FF0000"));
mCanvas.drawCircle(x / 2, y / 2, radius, paint);*/
// mPath.quadTo(x, y, x + 0.1f, y);
/*Paint mPaint = new Paint();*/
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(ContextCompat.getColor(ActDrawPaintImage.this, R.color.white));
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(BRUSHSIZE);
mPath.addCircle(x, y, mPaint.getStrokeWidth()/4f, Path.Direction.CW);
}
public void clear()
{
mBitmap = Bitmap.createBitmap(width,height , Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
invalidate();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
new MenuInflater(this).inflate(R.menu.draw_paint_image, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
mPaint.setXfermode(null);
mPaint.setAlpha(0xFF);
switch (item.getItemId()) {
case R.id.COLOR_MENU_ID:
new ColorPickerDialog(this, this, mPaint.getColor()).show();
return true;
case R.id.EMBOSS_MENU_ID:
if (mPaint.getMaskFilter() != mEmboss) {
mPaint.setMaskFilter(mEmboss);
} else {
mPaint.setMaskFilter(null);
}
return true;
case R.id.BLUR_MENU_ID:
if (mPaint.getMaskFilter() != mBlur) {
mPaint.setMaskFilter(mBlur);
} else {
mPaint.setMaskFilter(null);
}
return true;
case R.id.ERASE_MENU_ID:
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
mPaint.setAlpha(0x80);
return true;
case R.id.Clear:
mv.clear();
return true;
case R.id.Save:
AlertDialog.Builder editalert = new AlertDialog.Builder(ActDrawPaintImage.this);
editalert.setTitle("Please Enter the name with which you want to Save");
final EditText input = new EditText(ActDrawPaintImage.this);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.FILL_PARENT);
input.setLayoutParams(lp);
editalert.setView(input);
editalert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
String name= input.getText().toString();
Bitmap bitmap = mv.getDrawingCache();
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
File file = new File("/sdcard/"+name+".png");
try
{
if(!file.exists())
{
file.createNewFile();
}
FileOutputStream ostream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 10, ostream);
ostream.close();
mv.invalidate();
}
catch (Exception e)
{
e.printStackTrace();
}finally
{
mv.setDrawingCacheEnabled(false);
}
}
});
editalert.show();
return true;
}
return super.onOptionsItemSelected(item);
}
}
EDIT
public class ActDrawPaintImage extends AppCompatActivity implements ColorPickerDialog.OnColorChangedListener {
MyView mv;
AlertDialog dialog;
#Bind(R.id.toolbar)
Toolbar mToolbar;
#Bind(R.id.btnNxtId)
Button btnNxtId;
private Paint mPaint;
private MaskFilter mEmboss;
private MaskFilter mBlur;
LinearLayout canvasLayoutId;
boolean mDotToDraw=false;
private int BRUSHSIZE=20;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_draw_paint_image);
//Bind the views
ButterKnife.bind(this);
initToolbar();
onClickSet();
//ADD THE VIEW WHERE THE IMAGE IS DRAWN
setTheCanvasView();
//SET BRUSH PROPERTIES
setUpBrushProperties();
mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 },0.4f, 6, 3.5f);
mBlur = new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL);
}
private void onClickSet() {
btnNxtId.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mDotToDraw==false){
mDotToDraw=true;
}else{
mDotToDraw=false;
}
}
});
}
private void setTheCanvasView() {
mv= new MyView(this);
mv.setDrawingCacheEnabled(true);
canvasLayoutId=(LinearLayout) findViewById(R.id.canvasLayoutId);
canvasLayoutId.addView(mv);
}
private void setUpBrushProperties() {
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(ContextCompat.getColor(ActDrawPaintImage.this, R.color.pattern_color));
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(BRUSHSIZE);
}
private void initToolbar() {
setSupportActionBar(mToolbar);
setTitle(getString(R.string.app_name));
mToolbar.setTitleTextColor(ContextCompat.getColor(ActDrawPaintImage.this, R.color.white));
}
public void colorChanged(int color) {
mPaint.setColor(color);
}
public class MyView extends View {
private static final float MINP = 0.25f;
private static final float MAXP = 0.75f;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
Context context;
private int width;
private int height;
PathMeasure pathMeasure;
float[] position = new float[2];
float[] slope = new float[2]; // slope will give you the tangent of the position on the path. Not sure if you need this.
public MyView(Context c) {
super(c);
context=c;
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
pathMeasure = new PathMeasure(mPath, false);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width=w;
height=h;
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
drawPlotPoints(canvas); // you should be able to implement this alone. It should draw a dot at a given x/y.
canvas.drawPath(mPath, mPaint);
}
private void drawPlotPoints(Canvas canvas) {
int amountOfPoints = (int)(pathMeasure.getLength() / 120f);
for (float distance = 0; distance <= 1; distance += 1f / amountOfPoints) {
pathMeasure.getPosTan(distance, position, slope);
touch_draw_circle(position[0], position[1]);
}
}
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
}
//drawPlotPoints(x,y);
}
private void touch_up() {
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));
//mPaint.setMaskFilter(null);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
//Create a pointer and log the output
//Log.d("POINTS", x + "," + y);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if(mDotToDraw==false){
touch_start(x, y);
}else{
touch_draw_circle(x, y);
}
invalidate();
break;
case MotionEvent.ACTION_MOVE:
if(mDotToDraw==false){
touch_move(x, y);
}else{
}
invalidate();
break;
case MotionEvent.ACTION_UP:
if(mDotToDraw==false){
touch_up();
}else{
}
invalidate();
break;
}
return true;
}
private void touch_draw_circle(float x, float y) {
/*int radius;
radius = 30;
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.WHITE);
mCanvas.drawPaint(paint);
// Use Color.parseColor to define HTML colors
paint.setColor(Color.parseColor("#FF0000"));
mCanvas.drawCircle(x / 2, y / 2, radius, paint);*/
// mPath.quadTo(x, y, x + 0.1f, y);
/*Paint mPaint = new Paint();*/
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(ContextCompat.getColor(ActDrawPaintImage.this, R.color.white));
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(BRUSHSIZE);
mPath.addCircle(x, y, mPaint.getStrokeWidth()/4f, Path.Direction.CW);
}
public void clear()
{
mBitmap = Bitmap.createBitmap(width,height , Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
invalidate();
}
}
}
I am getting output as below:
I am trying to get output as like this:
If I understood you correctly, you're trying to discover certain positions on a given path, then draw dots on them where the distance between each dot should be the same.
You can achieve this using a PathMeasure object. Example:
boolean forceClose = false; //(set to true if you want to close the path or leave it open).
PathMeasure pathMeasure = new PathMeasure(path, forceClose);
float[] position = new float[2];
float[] slope = new float[2]; // slope will give you the tangent of the position on the path. Not sure if you need this.
for (float distance = 0; distance <= 1; distance += 1f / AMOUNT_OF_POINTS) {
pathMeasure.getPosTan(distance, position, slope);
drawDotAtPosition(position[0], position[1]); // you should be able to implement this alone. It should draw a dot at a given x/y.
}
The getPosTan method will give you the position on a given path after a certain ratio of the length has passed. This ratio is defined by AMOUNT_OF_POINTS which you can set to anything for a constant amount of points no matter what the length of the path is, or you could calculate it according to the length of the path:
// this will produce an amount of points equal to 1 point per 10 pixels along the whole path
int amountOfPoints = (int)(pathMeasure.getLength() / 10f);
Hope this helps.
I made this a while back, its not exactly my best work but it worked at the time. Maybe you can use it as a reference.
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
public class line_graph extends View
{
private int padding = 0;
private int width = 0;//this is automatically
private int height = 0;
private Paint paint = new Paint();
private String[] labels;// labels for each column
private int[][] values;// values for each column
private String[] labelsHeadings;// headings for each segment of data
private float xInterval = 0;//space between x grid lines
private float yInterval = 0;//space between y grid lines
private int RowLineCount = 0; // amount of y grid lines
private float scale = 1; // this is automatically set according to the screen density
private int labelSpaceLeft = 0;// space on the left for labels
private int labelSpaceBottom = 0;// space on the bottom for labels
private int keySpace = 0;// space on the bottom for the key
private Path path = new Path();// bothe these paths are used for the shaded effect on the line graph
private Path path2 = new Path();
public line_graph(Context context)
{
this(context, null, 0);
}
public line_graph(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public line_graph(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
if(isInEditMode())
return;
scale = context.getResources().getDisplayMetrics().density;
labelSpaceLeft = (int)(40 * scale);
labelSpaceBottom = (int)(85 * scale);
keySpace = (int)(40 * scale);
}
public void setup(String[] labels, int[][] values, String[] labelsHeadings, int padding)
{
this.labels = labels;
this.values = values;
this.padding = padding;
this.labelsHeadings = labelsHeadings;
invalidate();
}
#Override
protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld){
super.onSizeChanged(xNew, yNew, xOld, yOld);
width = xNew;
height = yNew;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isInEditMode())
return;
try {
paint.reset();
paint.setAntiAlias(true);
paint.setTextSize(16);
paint.setTextAlign(Paint.Align.RIGHT);
int maxValue = 0;
for (int i = 0; i < values.length; i++) {
for (int j = 0; j < values[i].length; j++) {
maxValue = Math.max(maxValue, values[i][j]);
}
}
float innerWidth = width - padding * 2 - labelSpaceLeft;
float innerHeight = height - padding * 2 - labelSpaceBottom - keySpace;
float lx = padding;
paint.setTextAlign(Paint.Align.LEFT);
for (int i = 0; i < values.length; i++) {
paint.setColor(getNextColour(i));
//calculate space for circles
lx += 15 * scale;
//calculate space key label
if (labelsHeadings.length > i) {
lx += padding + paint.measureText(labelsHeadings[i]);
if (i < values.length - 1 && lx + paint.measureText(labelsHeadings[i + 1]) > width) {
lx = padding + labelSpaceLeft;
innerHeight += paint.ascent();
}
}
}
lx = padding + labelSpaceLeft;
float ly = innerHeight + padding*2 + labelSpaceBottom;
paint.setTextAlign(Paint.Align.LEFT);
for (int i = 0; i < values.length; i++) {
paint.setColor(getNextColour(i));
//draw circles
canvas.drawOval(new RectF(lx - 5 * scale, ly - 5 * scale, lx + 5 * scale, ly + 5 * scale), paint);
lx += 15 * scale;
//draw key label
canvas.drawText(labelsHeadings[i], lx, ly - paint.ascent() / 2, paint);
if (labelsHeadings.length > i) {
lx += padding + paint.measureText(labelsHeadings[i]);
if (i < values.length - 1 && lx + paint.measureText(labelsHeadings[i + 1]) > width) {
lx = padding + labelSpaceLeft;
ly -= paint.ascent();
innerHeight += paint.ascent();
}
}
}
xInterval = innerWidth / (labels.length-1);
RowLineCount = (int) Math.min(Math.max(innerHeight / Math.ceil(40 * scale), 2), maxValue/2);
yInterval = innerHeight / RowLineCount;
int currentValue = maxValue;
float y;
paint.setTextAlign(Paint.Align.RIGHT);
for (int i = 0; i < RowLineCount+1; i++) {
//draw left label
y = yInterval * i + padding;
paint.setColor(0xffaaaaaa);
canvas.drawText(String.valueOf(currentValue), labelSpaceLeft, y - paint.ascent()/2, paint);
currentValue = Math.max(currentValue - maxValue/RowLineCount,0);
//draw x grid line
paint.setColor(0xffeeeeee);
canvas.drawLine(padding + labelSpaceLeft, y, innerWidth + padding + labelSpaceLeft, y, paint);
}
float x;
for (int i = 0; i < labels.length; i++) {
//draw bottom label rotated
x = xInterval * i + padding + labelSpaceLeft;
if(i != labels.length) {
canvas.save();
canvas.rotate(300, x, innerHeight + padding*2 - paint.ascent()/2);
paint.setColor(0xffaaaaaa);
canvas.drawText(labels[i], x, innerHeight + padding*2 - paint.ascent()/2, paint);
canvas.restore();
}
//draw y grid line
paint.setColor(0xffeeeeee);
canvas.drawLine(x, padding, x, innerHeight + padding, paint);
}
paint.setStyle(Paint.Style.FILL);
for (int i = 0; i < values.length; i++) {
paint.setColor(getNextColour(i));
path.rewind();
path2.rewind();
for (int j = 0; j < values[i].length; j++)
{
x = xInterval * j + padding + labelSpaceLeft;
y = innerHeight + padding - (innerHeight * values[i][j] / maxValue);
//draw lines
if(j == 0) {
path2.moveTo(padding + labelSpaceLeft, innerHeight + padding);
path.moveTo(x, y);
}
else
path.lineTo(x,y);
path2.lineTo(x, y);
//canvas.drawLine(xOld,yOld,x,y,paint);
//draw circles
canvas.drawOval(new RectF(x - 5 * scale, y - 5 * scale, x + 5 * scale, y + 5 * scale), paint);
}
//draw line
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2);
canvas.drawPath(path, paint);
//draw shaded area
path2.lineTo(innerWidth + padding + labelSpaceLeft, innerHeight + padding);
paint.setARGB(20, Color.red(paint.getColor()), Color.green(paint.getColor()), Color.blue(paint.getColor()));
paint.setStyle(Paint.Style.FILL);
canvas.drawPath(path2, paint);
}
}
catch (Exception ignored){}
}
//used to get the next color in the series
public static int getNextColour(int index)
{
int[] colours = new int[]{0xFF4CAF50,
0xFF9C27B0,
0xFFF44336,
0xFF00BCD4,
0xFFE91E63,
0xFF03A9F4,
0xFFFF9800,
//0xFFFFEB3B,//removed bright yellow
0xFF9E9E9E,
0xFF795548,
0xFF8BC34A,
0xFF607D8B,
0xFF009688,
0xFFFFC107,
0xFF673AB7,
0xFF2196F3,
0xFFCDDC39,
0xFF3F51B5,
0xFFFF5722};
return colours[index % colours.length];
}
}
its used like this:
line_graph graph = (line_graph)findViewById(R.id.lineGraph);
graph.setup(
//labels
new String[]{"heading1","heading2","heading3","heading4","heading5","heading6","heading7"},
//Values
new int[][]{new int[]{1,4,8,2,5,9,12},new int[]{2,5,2,8,5,2,6},new int[]{8,2,9,23,7,1,11}},
//Series Headings
new String[]{"Series 1", "Series 2", "Series 3"},
//Padding
20);
xml:
<line_graph
android:id="#+id/lineGraph"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
it looks like this:
And yes i do realize this could be made better and that it had poor exception handling. But its just an example.

Why does resize make my image look strange?

I have a relative layout on which i add a view. this is the code in the activity:
paint = (RelativeLayout) findViewById(R.id.paint);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
myView = new CustomImage(getBaseContext());
paint.addView(myView);
String imagePath = (String) getIntent().getExtras().get("selectedImagePath");
LogService.log("PaintActivity", "Imagepath: " + imagePath);
// Drawable background = BitmapDrawable.createFromPath(imagePath);
// bitmap = ((BitmapDrawable) background).getBitmap();
try {
fis = new FileInputStream(imagePath);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
mBitmap = loadBitmap(fis.getFD());
bitmap = getResizedBitmap(mBitmap, 412*2, 1024*2);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
LogService.log("PaintActivity", "Bitmap = " + mBitmap);
myView.setBitmap(bitmap);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFF000000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(50);
myView.setPaint(mPaint);
}
}, 50);
This is my View:
public class CustomImage extends View {
private boolean hasResized = false;
private Bitmap bitmap, bitmap2;
public Context context;
Paint paint;
private Canvas canvas;
public String text = null;
private Paint mBitmapPaint, paintText;
private Path mPath = new Path();
private float mX, mY, pX, pY, tX, tY;
private static final float TOUCH_TOLERANCE = 4;
private float screenDensity;
int height, width;
private Bitmap mBitmap;
private RandomAccessFile randomAccessFile;
private int bh;
private int bw;
public CustomImage(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
public CustomImage(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CustomImage(Context context) {
super(context);
init(context);
}
private void init(Context context) {
this.context = context;
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
}
public void setImg(Context context, Canvas canvas, Bitmap bitmapw, int width, int height) {
bw = bitmapw.getWidth();
bh = bitmapw.getHeight();
float scaleWidth = ((float) width)/ bw;
float scaleHeight = ((float) height)/ bh;
System.out.println("CustomImage.setImg()");
bitmap = bitmapw;
}
public void setPaint(Paint paint) {
this.paint = paint;
LogService.log("in setPaint", "paint = " + paint);
}
public void setBitmap(Bitmap bitmap) throws Exception {
File file = new File("/mnt/sdcard/sample/temp.txt");
file.getParentFile().mkdirs();
randomAccessFile = new RandomAccessFile(file, "rw");
int bWidth = bitmap.getWidth();
int bHeight = bitmap.getHeight();
FileChannel channel = randomAccessFile.getChannel();
MappedByteBuffer map = channel.map(MapMode.READ_WRITE, 0, bWidth*bHeight*4);
bitmap.copyPixelsToBuffer(map);
bitmap.recycle();
this.bitmap = Bitmap.createBitmap(bWidth, bHeight, Config.ARGB_8888);
map.position(0);
this.bitmap.copyPixelsFromBuffer(map);
channel.close();
randomAccessFile.close();
// this.bitmap = bitmap;
// canvas = new Canvas();
}
public void setBitmap2(Bitmap bitmap) {
bitmap2 = bitmap;
invalidate();
}
public void getText(String text) {
this.text = text;
paintText = new Paint();
paintText.setColor(0xFFFFFFFF);
paintText.setStrokeWidth(10);
paintText.setTextSize(20);
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bitmap, 0, 0, mBitmapPaint);
if (PaintActivity.isPic == 1) {
if (bitmap2 != null) {
canvas.drawBitmap(bitmap2, mX, mY, mBitmapPaint);
pX = mX;
pY = mY;
}
if(text != null){
canvas.drawText(text, tX, tY, paintText);
}
} else if (PaintActivity.isPic == 2) {
if(text != null){
canvas.drawText(text, mX, mY, paintText);
tX = mX;
tY = mY;
}
if (bitmap2 != null) {
canvas.drawBitmap(bitmap2, pX, pY, mBitmapPaint);
}
}else{
canvas.drawPath(mPath, paint);
if (bitmap2 != null) {
canvas.drawBitmap(bitmap2, pX, pY, mBitmapPaint);
}
if(text != null){
canvas.drawText(text, tX, tY, paintText);
}
}
}
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
canvas.drawPoint(x, y, paint);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if ((dx >= TOUCH_TOLERANCE) || (dy >= TOUCH_TOLERANCE)) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
mPath.moveTo(mX, mY);
canvas.drawPath(mPath, paint);
mPath.reset();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
System.out.println("CustomImage.onSizeChanged()");
super.onSizeChanged(w, h, oldw, oldh);
if ((w != 0) && (h != 0)) {
if (!hasResized) {
hasResized = true;
renderImage();
}
}
}
public void renderImage() {
System.out.println("======in renderimage=======w " + getMeasuredWidth() + "h " + getMeasuredHeight());
width = getMeasuredWidth();
height = getMeasuredHeight();
canvas = new Canvas(bitmap);
setImg(context, canvas, bitmap, width, height);
}
}
As you can see, I have a resizing function in the activity:
public Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth) {
int width = bm.getWidth();
int height = bm.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// create a matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(scaleWidth, scaleHeight);
// recreate the new Bitmap
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
return resizedBitmap;
}
Now if i comment this function out of the code, the image looks normal, but not scaled. If i leave it there, then i get an ugly image, but it is resized. Example:
normal not resized: http://imgur.com/BD5Pp,YWDTi
altered but resized pic: http://imgur.com/BD5Pp,YWDTi#1
As OP stated answering my question, the bitmap is converted to RGB_565, which is a known bug in createBitmap() - #16211, fixed in Android 3.0. It affects createScaledBitmap() as well. The bitmap wouldn't look distorted if it remained ARGB_8888.
As a workaround you have to create target bitmap manually (which gives you full control of the pixel format), then create canvas attached to this bitmap and paint a scaled version of the original bitmap on it. Here's a sample from my project:
public class BitmapUtils {
private static Matrix matrix = new Matrix();
private static Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG);
public static final Bitmap resizeBitmap(Bitmap bitmap, float scale, Bitmap.Config targetConfig) {
int srcWidth = bitmap.getWidth();
int srcHeight = bitmap.getHeight();
int newWidth = (int) (srcWidth * scale);
int newHeight = (int) (srcHeight * scale);
float sx = newWidth / (float) srcWidth;
float sy = newHeight / (float) srcHeight;
matrix.setScale(sx, sy);
Bitmap target = Bitmap.createBitmap(newWidth, newHeight, targetConfig);
Canvas c = new Canvas(target);
c.drawBitmap(bitmap, matrix, paint);
return target;
}
}
Note: this code is not reentrant, due to global matrix instance. Also, it takes scale as parameter, but adapting it to your needs (new width/height as parameters) is trivial.

How to implement touch smooth image eraser in android?

I have already seen fingurePaint.java from API demos. I want to implement touch smooth eraser to erase parts of the image by touch move in android.
fingurePaint told me to implement this
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
But this is not working to erase the image. It is working to erase something which is drawn by touch.
public class SandboxView extends View implements OnTouchListener {
public final Bitmap bitmap;
private final int width;
private final int height;
private Matrix transform = new Matrix();
private Vector2D position = new Vector2D();
private float scale = 1;
private float angle = 0;
public boolean isInitialized = false;
private TouchManager touchManager = new TouchManager(2);
final GestureDetector mGesDetect;
// Debug helpers to draw lines between the two touch points
private Vector2D vca = null;
private Vector2D vcb = null;
private Vector2D vpa = null;
private Vector2D vpb = null;
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private Path mPath;
private Canvas mCanvas;
private Paint mPaint;
private Paint mBitmapPaint;
public SandboxView(Context context, Bitmap bitmap) {
super(context);
this.bitmap = bitmap;
this.width = bitmap.getWidth();
this.height = bitmap.getHeight();
this.mGesDetect = new GestureDetector(context, new DoubleTapGestureDetector());
setOnTouchListener(this);
}
private float getDegreesFromRadians(float angle) {
return (float)(angle * 360.0 / Math.PI);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!isInitialized) {
Bitmap mBitmap = bitmap.createBitmap(320, 480, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
mPaint = new Paint();
mPath = new Path();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFFFF0000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(12);
mPaint.setAlpha(0);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
mPaint.setAntiAlias(true);
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
int w = getWidth();
int h = getHeight();
position.set(w / 2, h / 2);
isInitialized = true;
}
if(isEraser==1){
canvas.drawColor(80000000);
canvas.drawBitmap(bitmap, transform, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
else{
Paint paint = new Paint();
transform.reset();
transform.postTranslate(-width / 2.0f, -height / 2.0f);
transform.postRotate(getDegreesFromRadians(angle));
transform.postScale(scale, scale);
transform.postTranslate(position.getX(), position.getY());
canvas.drawBitmap(bitmap, transform, paint);
try {
/*paint.setColor(0xFF007F00);
canvas.drawCircle(vca.getX(), vca.getY(), 64, paint);
paint.setColor(0xFF7F0000);
canvas.drawCircle(vcb.getX(), vcb.getY(), 64, paint);
paint.setColor(0xFFFF0000);
canvas.drawLine(vpa.getX(), vpa.getY(), vpb.getX(), vpb.getY(), paint);
paint.setColor(0xFF00FF00);
canvas.drawLine(vca.getX(), vca.getY(), vcb.getX(), vcb.getY(), paint);*/
}
catch(NullPointerException e) {
// Just being lazy here...
}
}
}
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
mCanvas.drawPath(mPath, mPaint);
mPath.reset();
}
#Override
public boolean onTouch(View v, MotionEvent event) {
if(isEraser ==1){
float x = event.getX();
float y = event.getY();
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
else{
vca = null;
vcb = null;
vpa = null;
vpb = null;
mGesDetect.onTouchEvent(event);
try {
touchManager.update(event);
if (touchManager.getPressCount() == 1) {
vca = touchManager.getPoint(0);
vpa = touchManager.getPreviousPoint(0);
position.add(touchManager.moveDelta(0));
}
else {
if (touchManager.getPressCount() == 2) {
vca = touchManager.getPoint(0);
vpa = touchManager.getPreviousPoint(0);
vcb = touchManager.getPoint(1);
vpb = touchManager.getPreviousPoint(1);
Vector2D current = touchManager.getVector(0, 1);
Vector2D previous = touchManager.getPreviousVector(0, 1);
float currentDistance = current.getLength();
float previousDistance = previous.getLength();
if (previousDistance != 0) {
scale *= currentDistance / previousDistance;
}
angle -= Vector2D.getSignedAngleBetween(current, previous);
}
}
invalidate();
}
catch(Throwable t) {
// So lazy...
}
return true;
}
}
class DoubleTapGestureDetector extends GestureDetector.SimpleOnGestureListener {
#Override
public boolean onDoubleTap(MotionEvent e) {
colorseekbar.setVisibility(View.INVISIBLE);
opacityseekbar.setVisibility(View.INVISIBLE);
return true;
}
}
}
So please help me to erase the parts of image by using touch move.
Thanks in advance.
First Declar your paint with all property in your constructor.
Write this code in your onDraw() method
#Override
protected void onDraw(Canvas canvas)
{
System.out.println("come in on draw......");
canvas.drawColor(Color.TRANSPARENT);
canvas.drawBitmap(mBitmap, 0, 0, mPaint);
if(eraser==true)
mPaint.setColor(Color.TRANSPARENT):
else
mPaint.setColor(Color.RED):
canvas.drawPath(mPath, mPaint);
super.dispatchDraw(canvas);
}
second solution:
call below method in your touch_move() method
mBitmap.setPixel(x, y, Color.TRANSPARENT); This method will change your bitmap you have to pass only X,Y & COLOR
public void changeBitmap(int x, int y, Bitmap mBitmap)
{
Bitmap tempBitmap = Bitmap.createBitmap(mBitmap); //Edited code
tempBitmap.setPixel(x, y, Color.TRANSPARENT);
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
changeBitmap(x, y, your_bitmap)
}
}
Isn't it better to invert this case ? Just paint on your image with background color and after all when saving, merge those layers if needed.
Define a temporary canvas and bitmap then draw your path or line, circle, image anything on touch events and then pass this temporary bitmap to canvas in onDraw your work will done properly, and also if you want to do erasing then do your erasing on that temporary canvas.
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
TemporaryBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_4444);
TemporaryCanvas = new Canvas(TemporaryBitmap);
}
TemporaryCanvas.drawColor(0, PorterDuff.Mode.clear);
public void onDraw(Canvas canv){
canv.drawBitmap(TemporaryBitmap, matrix, paint);

Trying to write a simple drawing program for android

I'm trying to figure out how to wite a simple drawing program in Android. I saw a sample program that stored each stroke in a array, then played back the array when the screen needed to be updated. To me this did not seem to proctical. I would like to draw in a bitmap, and the update would just draw the bitmap instad of every stroke. ( i could not figure out how to do this in android)
Any thoughts
?
Ted
Look at the Android samples: there are a couple of moderately complicated bits, but this is from the Sensors.java api demo in the Android SDK. It demonstrates the bitmap manipulation:
private class GraphView extends View implements SensorEventListener
{
private Bitmap mBitmap;
private Paint mPaint = new Paint();
private Canvas mCanvas = new Canvas();
private Path mPath = new Path();
private RectF mRect = new RectF();
private float mLastValues[] = new float[3*2];
private float mOrientationValues[] = new float[3];
private int mColors[] = new int[3*2];
private float mLastX;
private float mScale[] = new float[2];
private float mYOffset;
private float mMaxX;
private float mSpeed = 1.0f;
private float mWidth;
private float mHeight;
public GraphView(Context context) {
super(context);
mColors[0] = Color.argb(192, 255, 64, 64);
mColors[1] = Color.argb(192, 64, 128, 64);
mColors[2] = Color.argb(192, 64, 64, 255);
mColors[3] = Color.argb(192, 64, 255, 255);
mColors[4] = Color.argb(192, 128, 64, 128);
mColors[5] = Color.argb(192, 255, 255, 64);
mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
mRect.set(-0.5f, -0.5f, 0.5f, 0.5f);
mPath.arcTo(mRect, 0, 180);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
mCanvas.setBitmap(mBitmap);
mCanvas.drawColor(0xFFFFFFFF);
mYOffset = h * 0.5f;
mScale[0] = - (h * 0.5f * (1.0f / (SensorManager.STANDARD_GRAVITY * 2)));
mScale[1] = - (h * 0.5f * (1.0f / (SensorManager.MAGNETIC_FIELD_EARTH_MAX)));
mWidth = w;
mHeight = h;
if (mWidth < mHeight) {
mMaxX = w;
} else {
mMaxX = w-50;
}
mLastX = mMaxX;
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
synchronized (this) {
if (mBitmap != null) {
final Paint paint = mPaint;
final Path path = mPath;
final int outer = 0xFFC0C0C0;
final int inner = 0xFFff7010;
if (mLastX >= mMaxX) {
mLastX = 0;
final Canvas cavas = mCanvas;
final float yoffset = mYOffset;
final float maxx = mMaxX;
final float oneG = SensorManager.STANDARD_GRAVITY * mScale[0];
paint.setColor(0xFFAAAAAA);
cavas.drawColor(0xFFFFFFFF);
cavas.drawLine(0, yoffset, maxx, yoffset, paint);
cavas.drawLine(0, yoffset+oneG, maxx, yoffset+oneG, paint);
cavas.drawLine(0, yoffset-oneG, maxx, yoffset-oneG, paint);
}
canvas.drawBitmap(mBitmap, 0, 0, null);
float[] values = mOrientationValues;
if (mWidth < mHeight) {
float w0 = mWidth * 0.333333f;
float w = w0 - 32;
float x = w0*0.5f;
for (int i=0 ; i<3 ; i++) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.translate(x, w*0.5f + 4.0f);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
paint.setColor(outer);
canvas.scale(w, w);
canvas.drawOval(mRect, paint);
canvas.restore();
canvas.scale(w-5, w-5);
paint.setColor(inner);
canvas.rotate(-values[i]);
canvas.drawPath(path, paint);
canvas.restore();
x += w0;
}
} else {
float h0 = mHeight * 0.333333f;
float h = h0 - 32;
float y = h0*0.5f;
for (int i=0 ; i<3 ; i++) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.translate(mWidth - (h*0.5f + 4.0f), y);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
paint.setColor(outer);
canvas.scale(h, h);
canvas.drawOval(mRect, paint);
canvas.restore();
canvas.scale(h-5, h-5);
paint.setColor(inner);
canvas.rotate(-values[i]);
canvas.drawPath(path, paint);
canvas.restore();
y += h0;
}
}
}
}
}
public void onSensorChanged(SensorEvent event) {
//Log.d(TAG, "sensor: " + sensor + ", x: " + values[0] + ", y: " + values[1] + ", z: " + values[2]);
synchronized (this) {
if (mBitmap != null) {
final Canvas canvas = mCanvas;
final Paint paint = mPaint;
if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {
for (int i=0 ; i<3 ; i++) {
mOrientationValues[i] = event.values[i];
}
} else {
float deltaX = mSpeed;
float newX = mLastX + deltaX;
int j = (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) ? 1 : 0;
for (int i=0 ; i<3 ; i++) {
int k = i+j*3;
final float v = mYOffset + event.values[i] * mScale[j];
paint.setColor(mColors[k]);
canvas.drawLine(mLastX, mLastValues[k], newX, v, paint);
mLastValues[k] = v;
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mLastX += mSpeed;
}
invalidate();
}
}
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}

Categories

Resources