package com.handstudio.android.hzgrapherlib.graphview; import java.util.WeakHashMap; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.DashPathEffect; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.Rect; import android.util.Log; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceHolder.Callback; import android.view.SurfaceView; import com.handstudio.android.hzgrapherlib.canvas.GraphCanvasWrapper; import com.handstudio.android.hzgrapherlib.error.ErrorCode; import com.handstudio.android.hzgrapherlib.error.ErrorDetector; import com.handstudio.android.hzgrapherlib.vo.GraphNameBox; import com.handstudio.android.hzgrapherlib.vo.bargraph.BarGraph; import com.handstudio.android.hzgrapherlib.vo.bargraph.BarGraphVO; public class BarGraphView extends SurfaceView implements Callback{ public static final String TAG = "BarGraphView"; private Context mContext; private SurfaceHolder mHolder; private DrawThread mDrawThread; private BarGraphVO mBarGraphVO = null; //Constructor public BarGraphView(Context context, BarGraphVO vo) { super(context); Log.i(TAG, "BarGraphView generator."); mContext = context; mBarGraphVO = vo; initView(context, vo); } private void initView(Context context, BarGraphVO vo) { ErrorCode ec = ErrorDetector.checkGraphObject(vo); ec.printError(); mHolder = getHolder(); mHolder.addCallback(this); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceCreated(SurfaceHolder holder) { Log.i(TAG, "surfaceCreated()"); if(mDrawThread == null){ mDrawThread = new DrawThread(mHolder, getContext()); mDrawThread.start(); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { Log.i(TAG, "surfaceDestroyed()"); if(mDrawThread != null){ mDrawThread.setRunFlag(false); mDrawThread = null; } } private static final Object touchLock = new Object(); // touch synchronize @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); if(mDrawThread == null ){ return false; } if(action == MotionEvent.ACTION_DOWN){ synchronized (touchLock) { mDrawThread.isDirty = true; } return true; }else if(action == MotionEvent.ACTION_MOVE){ synchronized (touchLock) { mDrawThread.isDirty = true; } return true; }else if(action == MotionEvent.ACTION_UP){ synchronized (touchLock) { mDrawThread.isDirty = true; } return true; } return super.onTouchEvent(event); } class DrawThread extends Thread{ SurfaceHolder mHolder; Context mCtx; boolean isRun = true; boolean isDirty = true; Matrix matrix = new Matrix(); int height = getHeight(); int width = getWidth(); //graph length int xLength = width - (mBarGraphVO.getPaddingLeft() + mBarGraphVO.getPaddingRight() + mBarGraphVO.getMarginRight()); int yLength = height - (mBarGraphVO.getPaddingBottom() + mBarGraphVO.getPaddingTop() + mBarGraphVO.getMarginTop()); //chart length int chartXLength = width - (mBarGraphVO.getPaddingLeft() + mBarGraphVO.getPaddingRight()); int chartYLength = height - (mBarGraphVO.getPaddingBottom() + mBarGraphVO.getPaddingTop()); Paint p = new Paint(); Paint pCircle = new Paint(); Paint pLine = new Paint(); Paint pBaseLine = new Paint(); Paint pBaseLineD = new Paint(); Paint pBaseLineX = new Paint(); Paint pMarkText = new Paint(); //animation float anim = 0.0f; boolean isAnimation = false; boolean isDrawRegion = false; long animStartTime = -1; WeakHashMap<Integer, Bitmap> arrIcon = new WeakHashMap<Integer, Bitmap>(); Bitmap bg = null; public DrawThread(SurfaceHolder holder, Context context) { mHolder = holder; mCtx = context; int bgResource = mBarGraphVO.getGraphBG(); if(bgResource != -1){ Bitmap tempBg = BitmapFactory.decodeResource(getResources(), bgResource); bg = Bitmap.createScaledBitmap(tempBg, width, height, true); tempBg.recycle(); } } public void setRunFlag(boolean bool){ isRun = bool; } @Override public void run() { Canvas canvas = null; GraphCanvasWrapper graphCanvasWrapper = null; animStartTime = System.currentTimeMillis(); setPaint(); isAnimation(); while (isRun) { if(!isDirty){ try { Thread.sleep(100); } catch (InterruptedException e1) { e1.printStackTrace(); } continue; } canvas = mHolder.lockCanvas(); graphCanvasWrapper = new GraphCanvasWrapper(canvas, width, height, mBarGraphVO.getPaddingLeft(), mBarGraphVO.getPaddingBottom()); synchronized (mHolder) { synchronized (touchLock) { try{ canvas.drawColor(Color.WHITE); if(bg != null){ canvas.drawBitmap(bg, 0, 0, null); } drawBaseLine(graphCanvasWrapper); drawBaseMark(graphCanvasWrapper); drawBaseText(graphCanvasWrapper); drawBaseLineGuide(graphCanvasWrapper); drawGraphName(canvas); if(isAnimation){ drawGraphWithAnimation(graphCanvasWrapper); } else{ drawGraphWithoutAnimation(graphCanvasWrapper); } } catch(Exception e){ e.printStackTrace(); } finally{ if(graphCanvasWrapper.getCanvas() != null){ mHolder.unlockCanvasAndPost(canvas); } } } } } } private void setPaint(){ pBaseLine = new Paint(); pBaseLine.setFlags(Paint.ANTI_ALIAS_FLAG); pBaseLine.setAntiAlias(true); pBaseLine.setFilterBitmap(true); pBaseLine.setColor(Color.GRAY); pBaseLine.setStrokeWidth(3); pBaseLineD = new Paint(); pBaseLineD.setFlags(Paint.ANTI_ALIAS_FLAG); pBaseLineD.setAntiAlias(true); pBaseLineD.setFilterBitmap(true); pBaseLineD.setColor(0xffcccccc); pBaseLineD.setStrokeWidth(1); pBaseLineD.setStyle(Style.STROKE); pBaseLineD.setPathEffect(new DashPathEffect(new float[] {10,5}, 0)); pMarkText = new Paint(); pMarkText.setFlags(Paint.ANTI_ALIAS_FLAG); pMarkText.setAntiAlias(true); pMarkText.setColor(Color.BLACK); } private void isAnimation(){ if(mBarGraphVO.isAnimationShow()){ isAnimation = true; }else { isAnimation = false; } } private void drawBaseLine(GraphCanvasWrapper graphCanvas){ graphCanvas.drawLine(0, 0, chartXLength, 0, pBaseLine); graphCanvas.drawLine(0, 0, 0, chartYLength, pBaseLine); } private void drawBaseMark(GraphCanvasWrapper graphCanvas){ //draw y axis for (int i = 1; mBarGraphVO.getIncrementY() * i <= mBarGraphVO.getMaxValueY(); i++) { float y = yLength * mBarGraphVO.getIncrementY() * i/mBarGraphVO.getMaxValueY(); graphCanvas.drawLine(0, y, -10, y, pBaseLine); } // for (int i = 1; mBarGraphVO.getIncrementX() * i <= mBarGraphVO.getMaxValueX(); i++) { // float x = xLength * mBarGraphVO.getIncrementX() * i / mBarGraphVO.getMaxValueX(); // graphCanvas.drawLine(x, 0, x, -10, pBaseLine); // } //draw x axis for (int i = 0; i < mBarGraphVO.getLegendArr().length; i++) { float x = xLength * mBarGraphVO.getIncrementX() * (i+1)/mBarGraphVO.getMaxValueX(); graphCanvas.drawLine(x, 0, x, -10, pBaseLine); } } private void drawBaseText(GraphCanvasWrapper graphCanvas){ //draw X axis // for (int i = 0; mBarGraphVO.getIncrementX() * i <= mBarGraphVO.getMaxValueX(); i++){ // float x = xLength * mBarGraphVO.getIncrementX() * i/mBarGraphVO.getMaxValueX(); // String mark = Float.toString(mBarGraphVO.getIncrementX() * i); // pMarkText.measureText(mark); // pMarkText.setTextSize(20); // Rect rect = new Rect(); // pMarkText.getTextBounds(mark, 0, mark.length(), rect); // graphCanvas.drawText(mark, x -(rect.width()/2), -(20 + rect.height()), pMarkText); // } for (int i = 0; i < mBarGraphVO.getLegendArr().length; i++) { float x = xLength * mBarGraphVO.getIncrementX() * (i+1)/mBarGraphVO.getMaxValueX(); String mark = mBarGraphVO.getLegendArr()[i]; pMarkText.measureText(mark); pMarkText.setTextSize(20); Rect rect = new Rect(); pMarkText.getTextBounds(mark, 0, mark.length(), rect); graphCanvas.drawText(mark, x -(rect.width()/2), -(20 + rect.height()), pMarkText); } //draw Y axis for (int i = 0; mBarGraphVO.getIncrementY() * i <= mBarGraphVO.getMaxValueY(); i++){ String mark = Float.toString(mBarGraphVO.getIncrementY() * i); float y = yLength * mBarGraphVO.getIncrementY() * i/mBarGraphVO.getMaxValueY(); pMarkText.measureText(mark); pMarkText.setTextSize(20); Rect rect = new Rect(); pMarkText.getTextBounds(mark, 0, mark.length(), rect); graphCanvas.drawText(mark, -(rect.width() + 20), y-rect.height()/2, pMarkText); } } private void drawBaseLineGuide(GraphCanvasWrapper graphCanvas){ //draw Y axis for (int i = 1; mBarGraphVO.getIncrementY() * i <= mBarGraphVO.getMaxValueY(); i++) { float y = yLength * mBarGraphVO.getIncrementY() * i/mBarGraphVO.getMaxValueY(); graphCanvas.drawLine(0, y, chartXLength, y, pBaseLineD); } // for (int i = 1; mBarGraphVO.getIncrementY() * i <= mBarGraphVO.getMaxValueY(); i++) { // float x = xLength * mBarGraphVO.getIncrementY() * i / mBarGraphVO.getMaxValueY(); // graphCanvas.drawLine(x, 0, x, chartYLength, pBaseLineD); // } } private void drawGraphName(Canvas canvas) { GraphNameBox gnb = mBarGraphVO.getGraphNameBox(); if(gnb != null){ int nameboxWidth = 0; int nameboxHeight = 0; int nameboxIconWidth = gnb.getNameboxIconWidth(); int nameboxIconHeight = gnb.getNameboxIconHeight(); int nameboxMarginTop = gnb.getNameboxMarginTop(); int nameboxMarginRight = gnb.getNameboxMarginRight(); int nameboxPadding = gnb.getNameboxPadding(); int nameboxTextIconMargin = gnb.getNameboxIconMargin(); int nameboxIconMargin = gnb.getNameboxIconMargin(); int nameboxTextSize = gnb.getNameboxTextSize(); int maxTextWidth = 0; int maxTextHeight = 0; Paint nameRextPaint = new Paint(); nameRextPaint.setFlags(Paint.ANTI_ALIAS_FLAG); nameRextPaint.setAntiAlias(true); //text anti alias nameRextPaint.setFilterBitmap(true); // bitmap anti alias nameRextPaint.setColor(Color.BLUE); nameRextPaint.setStrokeWidth(3); nameRextPaint.setStyle(Style.STROKE); Paint pIcon = new Paint(); pIcon.setFlags(Paint.ANTI_ALIAS_FLAG); pIcon.setAntiAlias(true); //text anti alias pIcon.setFilterBitmap(true); // bitmap anti alias pIcon.setColor(Color.BLUE); pIcon.setStrokeWidth(3); pIcon.setStyle(Style.FILL_AND_STROKE); Paint pNameText = new Paint(); pNameText.setFlags(Paint.ANTI_ALIAS_FLAG); pNameText.setAntiAlias(true); //text anti alias pNameText.setTextSize(nameboxTextSize); pNameText.setColor(Color.BLACK); int graphSize = mBarGraphVO.getArrGraph().size(); for (int i = 0; i < graphSize; i++) { String text = mBarGraphVO.getArrGraph().get(i).getName(); Rect rect = new Rect(); pNameText.getTextBounds(text, 0, text.length(), rect); if(rect.width() > maxTextWidth){ maxTextWidth = rect.width(); maxTextHeight = rect.height(); } mBarGraphVO.getArrGraph().get(i).getName(); } nameboxWidth = 1 * maxTextWidth + nameboxTextIconMargin + nameboxIconWidth; int maxCellHight = maxTextHeight; if(nameboxIconHeight > maxTextHeight){ maxCellHight = nameboxIconHeight; } nameboxHeight = graphSize * maxCellHight + (graphSize-1) * nameboxIconMargin; canvas.drawRect(width - (nameboxMarginRight + nameboxWidth) - nameboxPadding*2, nameboxMarginTop, width - nameboxMarginRight, nameboxMarginTop + nameboxHeight + nameboxPadding*2, nameRextPaint); for (int i = 0; i < graphSize; i++) { BarGraph graph = mBarGraphVO.getArrGraph().get(i); pIcon.setColor(graph.getColor()); canvas.drawRect(width - (nameboxMarginRight + nameboxWidth) - nameboxPadding, nameboxMarginTop + (maxCellHight * i) + nameboxPadding + (nameboxIconMargin * i), width - (nameboxMarginRight + maxTextWidth) - nameboxPadding - nameboxTextIconMargin, nameboxMarginTop + maxCellHight * (i+1) + nameboxPadding + nameboxIconMargin * i, pIcon); String text = graph.getName(); canvas.drawText(text, width - (nameboxMarginRight + maxTextWidth) - nameboxPadding, nameboxMarginTop + maxTextHeight/2 + maxCellHight * i + maxCellHight/2 + nameboxPadding + nameboxIconMargin * i, pNameText); } } } private void drawGraphWithoutAnimation(GraphCanvasWrapper canvas){ Log.d(TAG, "drawGraphWithoutAnimation"); Paint barGraphRegionPaint = new Paint(); barGraphRegionPaint.setFlags(Paint.ANTI_ALIAS_FLAG); barGraphRegionPaint.setAntiAlias(true); //text anti alias barGraphRegionPaint.setFilterBitmap(true); // bitmap anti alias barGraphRegionPaint.setStrokeWidth(0); Paint barPercentPaint = new Paint(); barPercentPaint.setFlags(Paint.ANTI_ALIAS_FLAG); barPercentPaint.setAntiAlias(true); barPercentPaint.setColor(Color.WHITE); barPercentPaint.setTextSize(20); float yBottom = 0; float yBottomOld = 0; //x축 반복 for(int i=0; i< mBarGraphVO.getLegendArr().length; i++){ float xLeft = xLength * mBarGraphVO.getIncrementX() * (i+1)/mBarGraphVO.getMaxValueX() - mBarGraphVO.getBarWidth() / 2; float xRight = xLeft + mBarGraphVO.getBarWidth(); float totalYLength = 0; for (int j = 0; j < mBarGraphVO.getArrGraph().size(); j++) { totalYLength += yLength * mBarGraphVO.getArrGraph().get(j).getCoordinateArr()[i]/mBarGraphVO.getMaxValueY(); } //x축 각 섹션별 반복 for (int j = 0; j < mBarGraphVO.getArrGraph().size(); j++) { BarGraph graph = mBarGraphVO.getArrGraph().get(j); yBottomOld = yBottom; yBottom += yLength * graph.getCoordinateArr()[i]/mBarGraphVO.getMaxValueY(); barGraphRegionPaint.setColor(mBarGraphVO.getArrGraph().get(j).getColor()); canvas.drawRect(xLeft, yBottomOld, xRight, yBottom, barGraphRegionPaint); int percentage = (int) (((yBottom - yBottomOld)*100)/totalYLength); if(percentage != 0){ String mark = String.valueOf(percentage)+"%"; barPercentPaint.measureText(mark); Rect rect = new Rect(); barPercentPaint.getTextBounds(mark, 0, mark.length(), rect); canvas.drawText(mark, xRight-((xRight-xLeft)/2)-rect.width()/2, yBottom-((yBottom-yBottomOld)/2)-rect.height()/2, barPercentPaint); } } yBottom = 0; } } private void drawGraphWithAnimation(GraphCanvasWrapper canvas){ Log.d(TAG, "drawGraphWithAnimation"); Paint barGraphRegionPaint = new Paint(); barGraphRegionPaint.setFlags(Paint.ANTI_ALIAS_FLAG); barGraphRegionPaint.setAntiAlias(true); //text anti alias barGraphRegionPaint.setFilterBitmap(true); // bitmap anti alias barGraphRegionPaint.setStrokeWidth(0); // Paint barPercentPaint = new Paint(); // barPercentPaint.setFlags(Paint.ANTI_ALIAS_FLAG); // barPercentPaint.setAntiAlias(true); // barPercentPaint.setColor(Color.WHITE); // barPercentPaint.setTextSize(20); long curTime = System.currentTimeMillis(); long gapTime = curTime - animStartTime; long totalAnimDuration = mBarGraphVO.getAnimation().getDuration(); if(gapTime >= totalAnimDuration){ gapTime = totalAnimDuration; isDirty = false; } float yBottomOld = 0; //x축 반복 for(int i=0; i< mBarGraphVO.getLegendArr().length; i++){ float xLeft = xLength * mBarGraphVO.getIncrementX() * (i+1)/mBarGraphVO.getMaxValueX() - mBarGraphVO.getBarWidth() / 2; float xRight = xLeft + mBarGraphVO.getBarWidth(); float totalYLength = 0; for (int j = 0; j < mBarGraphVO.getArrGraph().size(); j++) { totalYLength += yLength * mBarGraphVO.getArrGraph().get(j).getCoordinateArr()[i]/mBarGraphVO.getMaxValueY(); } float yGap = (totalYLength / totalAnimDuration) * gapTime; Log.d(TAG, "yGap = "+yGap); barGraphRegionPaint.setColor(mBarGraphVO.getArrGraph().get(0).getColor()); canvas.drawRect(xLeft, yBottomOld, xRight, yGap, barGraphRegionPaint); } } } }