package org.ripple.power.ui.graphics.chart; import java.awt.Frame; import java.awt.Graphics; import java.awt.image.BufferedImage; import javax.swing.JPanel; import org.ripple.power.ui.graphics.LColor; import org.ripple.power.ui.graphics.LFont; import org.ripple.power.ui.graphics.LImage; public class ChartBaseCanvas extends JPanel { /** * */ private static final long serialVersionUID = 1L; int p_width = 0; int p_height = 0; int p_paddtop = 8; int p_paddright = 8; int p_paddbottom = 8; int p_paddleft = 8; boolean p_xscale_auto = true; boolean p_yscale_auto = true; boolean p_border_vis = true; boolean p_grid_vis = true; boolean p_axis_vis = true; boolean p_xtext_vis = true; boolean p_ytext_vis = true; boolean p_xtext_bottom = true; boolean p_ytext_left = true; boolean p_grid_aa = true; int p_background_color = LColor.white.getARGB(); int p_border_color = LColor.white.getARGB(); int p_grid_color = LColor.white.getARGB(); int p_axis_color = LColor.white.getARGB(); int p_text_color = LColor.white.getARGB(); float p_border_width = dipToPixel(1.0f); float p_grid_width = dipToPixel(1.0f); float p_axis_width = dipToPixel(1.0f); float p_text_size = dipToPixel(12.0f); boolean bRedraw = false; float sX, sY, dX, dY, eX, eY; float mXmin, mXmax, mYmin, mYmax; float mXminGrid, mXmaxGrid, mYminGrid, mYmaxGrid, mXdivGrid, mYdivGrid; int mXgridNum, mYgridNum; float aX, bX, aY, bY; public float offsetX = -5, offsetY = 0; Canvas mCnv = null; Bitmap mBmp = null; Paint mPntBorder = new Paint(); Paint mPntGrid = new Paint(); Paint mPntAxis = new Paint(); Paint mPntText = new Paint(); Path mPath = new Path(); private LImage _myImage; private Canvas _myCanvas; private LColor _background = LColor.black; public void repaint() { bRedraw = true; update(getGraphics()); super.repaint(); } public void update(Graphics g) { paint(g); } @Override public void paint(Graphics g) { if (_myImage != null) { synchronized (_myImage) { _myCanvas.drawClear(_background, p_width, p_height); onDraw(_myCanvas); if (_myImage != null && g != null) { g.drawImage(_myImage.getBufferedImage(), 0, 0, this); } } } } public ChartBaseCanvas(int w, int h) { update(w, h); } public void update(int w, int h) { this._myImage = new LImage(w, h, BufferedImage.TYPE_INT_ARGB); this._myCanvas = new Canvas(_myImage.getLGraphics()); this.p_width = w; this.p_height = h; initPaint(); } public ChartBaseCanvas(Frame frame) { this(frame.getWidth(), frame.getHeight()); } public int getWidth() { return p_width; } public int getHeight() { return p_height; } protected void initPaint() { mPntBorder.setStyle(Style.STROKE); mPntBorder.setColor(p_border_color); mPntBorder.setStrokeWidth(p_border_width); mPntBorder.setAntiAlias(p_grid_aa); mPntGrid.setStyle(Style.STROKE); mPntGrid.setColor(p_grid_color); mPntGrid.setStrokeWidth(p_grid_width); mPntGrid.setPathEffect(new DashPathEffect(new float[] { 2, 2 }, 0)); mPntGrid.setAntiAlias(p_grid_aa); mPntAxis.setStyle(Style.STROKE); mPntAxis.setColor(p_axis_color); mPntAxis.setStrokeWidth(p_axis_width); mPntAxis.setAntiAlias(p_grid_aa); mPntText.setColor(p_text_color); mPntText.setTypeface(LFont.getFont(14)); mPntText.setTextSize(p_text_size); mPntText.setStyle(Style.FILL); mPntText.setAntiAlias(true); setBackgroundColor(p_background_color); } public void reset() { mBmp = Bitmap.createBitmap(p_width, p_height); mCnv = new Canvas(mBmp); } public void setAxisVis(boolean a) { p_axis_vis = a; } public void onDraw(Canvas cnv) { if ((mBmp == null) || (bRedraw)) { getViewSizes(); getXYminmax(); if (p_xscale_auto) { calcXgridRange(); } if (p_yscale_auto) { calcYgridRange(); } calcXYcoefs(); reset(); if (p_grid_vis) { drawGrid(); } if (p_xtext_vis) { drawXlabel(); } if (p_ytext_vis) { drawYlabel(); } if (p_border_vis) { drawBorder(); } if (p_axis_vis) { drawAxis(); } bRedraw = false; } cnv.drawBitmap(mBmp, 0, 0); } public void setPadding(int pad) { p_paddtop = pad; p_paddright = pad; p_paddbottom = pad; p_paddleft = pad; } public void setPaddingDip(int pad) { p_paddtop = (int) dipToPixel(pad); p_paddright = (int) dipToPixel(pad); p_paddbottom = (int) dipToPixel(pad); p_paddleft = (int) dipToPixel(pad); } public void setPadding(int paddtop, int padright, int paddbot, int padleft) { p_paddtop = paddtop; p_paddright = padright; p_paddbottom = paddbot; p_paddleft = padleft; } public void setPaddingDip(int paddtop, int padright, int paddbot, int padleft) { p_paddtop = (int) dipToPixel(paddtop); p_paddright = (int) dipToPixel(padright); p_paddbottom = (int) dipToPixel(paddbot); p_paddleft = (int) dipToPixel(padleft); } public void setBackgroundColor(int color) { p_background_color = color; } public void setXgrid(boolean autoXscale, float xmin, float xmax, int num) { p_xscale_auto = autoXscale; if (!autoXscale) { mXminGrid = xmin; mXmaxGrid = xmax; mXgridNum = num; mXdivGrid = (xmax - xmin) / num; } } public void setYgrid(boolean autoYscale, float ymin, float ymax, int num) { p_yscale_auto = autoYscale; if (!autoYscale) { mYminGrid = ymin; mYmaxGrid = ymax; mYgridNum = num; mYdivGrid = (ymax - ymin) / num; } } public void setGridVis(boolean bBorderShow, boolean bGridShow, boolean bAxisShow) { p_border_vis = bBorderShow; p_grid_vis = bGridShow; p_axis_vis = bAxisShow; bRedraw = true; } public void setGridColor(int borderColor, int gridColor, int axisColor) { p_border_color = borderColor; p_grid_color = gridColor; p_axis_color = axisColor; initPaint(); bRedraw = true; } public void setGridWidth(float borderWidth, float gridWidth, float axisWidth) { p_border_width = borderWidth; p_grid_width = gridWidth; p_axis_width = axisWidth; initPaint(); bRedraw = true; } public void setGridWidthDip(float borderWidth, float gridWidth, float axisWidth) { p_border_width = dipToPixel(borderWidth); p_grid_width = dipToPixel(gridWidth); p_axis_width = dipToPixel(axisWidth); initPaint(); bRedraw = true; } public void setGridAA(boolean antialias) { p_grid_aa = antialias; initPaint(); bRedraw = true; } public void setTextVis(boolean xtext, boolean ytext, boolean xbottom, boolean yleft) { p_xtext_vis = xtext; p_ytext_vis = ytext; p_xtext_bottom = xbottom; p_ytext_left = yleft; bRedraw = true; } public void setTextStyle(int color, float size) { p_text_color = color; p_text_size = dipToPixel(size); initPaint(); bRedraw = true; } protected void getViewSizes() { p_width = getWidth(); p_height = getHeight(); sX = p_paddleft; sY = p_paddtop; eX = p_width - p_paddright; eY = p_height - p_paddbottom; if (p_ytext_vis && p_ytext_left) { sX += 3 * p_text_size; } if (p_ytext_vis && !p_ytext_left) { eX -= 3 * p_text_size; } if (p_xtext_vis && p_xtext_bottom) { eY -= p_text_size + 2; } if (p_xtext_vis && !p_xtext_bottom) { sY += p_text_size + 2; } dX = eX - sX; dY = eY - sY; } protected void getXYminmax() { mXmin = -9; mXmax = 9; mYmin = -90; mYmax = 90; } public void setLeft(int p) { this.p_paddleft = p; } public void setTop(int p) { this.p_paddtop = p; } public void setBottom(int p) { this.p_paddbottom = p; } public void setRight(int p) { this.p_paddright = p; } protected void calcXgridRange() { mXdivGrid = (float) Math.pow(10, Math.floor(Math.log10(Math.abs(mXmax - mXmin)))); mXminGrid = (float) (mXdivGrid * Math.floor(mXmin / mXdivGrid)); mXmaxGrid = (float) (mXdivGrid * Math.ceil(mXmax / mXdivGrid)); mXgridNum = (int) ((mXmaxGrid - mXminGrid) / mXdivGrid); if ((dX / dY) < 1.2) { if (mXgridNum <= 2) { mXgridNum *= 5; } else if (mXgridNum == 3) { mXgridNum *= 3; } else if (mXgridNum <= 5) { mXgridNum *= 2; } } else { if (mXgridNum <= 2) { mXgridNum *= 6; } else if (mXgridNum == 3) { mXgridNum *= 4; } else if (mXgridNum == 4) { mXgridNum *= 3; } else if (mXgridNum <= 6) { mXgridNum *= 2; } } } protected void calcYgridRange() { mYdivGrid = (float) Math.pow(10, Math.floor(Math.log10(Math.abs(mYmax - mYmin)))); mYminGrid = (float) (mYdivGrid * Math.floor(mYmin / mYdivGrid)); mYmaxGrid = (float) (mYdivGrid * Math.ceil(mYmax / mYdivGrid)); mYgridNum = (int) ((mYmaxGrid - mYminGrid) / mYdivGrid); if ((dY / dX) < 1.2) { if (mYgridNum <= 2) { mYgridNum *= 5; } else if (mYgridNum <= 3) { mYgridNum *= 3; } else if (mYgridNum <= 5) { mYgridNum *= 2; } } else { if (mYgridNum <= 2) { mYgridNum *= 6; } else if (mYgridNum == 3) { mYgridNum *= 4; } else if (mYgridNum == 4) { mYgridNum *= 3; } else if (mYgridNum <= 6) { mYgridNum *= 2; } } } protected void calcXYcoefs() { aX = (float) dX / Math.abs(mXmaxGrid - mXminGrid); bX = (float) mXminGrid; aY = (float) dY / Math.abs(mYmaxGrid - mYminGrid); bY = (float) mYminGrid; } protected void drawGrid() { mPath.reset(); for (int ii = 1; ii < mXgridNum; ii++) { mPath.moveTo(sX + ii * (dX / mXgridNum), sY); mPath.lineTo(sX + ii * (dX / mXgridNum), eY); } for (int ii = 1; ii < mYgridNum; ii++) { mPath.moveTo(sX, sY + ii * (dY / mYgridNum)); mPath.lineTo(eX, sY + ii * (dY / mYgridNum)); } mCnv.drawPath(mPath, mPntGrid); } protected void drawXlabel() { mPntText.setTextAlign(Align.CENTER); mPath.reset(); if (p_xtext_bottom) { for (int ii = 1; ii < mXgridNum; ii++) { mPath.moveTo(sX + ii * (dX / mXgridNum), eY - 3); mPath.lineTo(sX + ii * (dX / mXgridNum), eY + 3); float ff = mXminGrid + ii * (mXmaxGrid - mXminGrid) / mXgridNum; mCnv.drawText(String.format("%.1f", ff), sX + ii * (dX / mXgridNum), eY + p_text_size + 2, mPntText); } } else { for (int ii = 1; ii < mXgridNum; ii++) { mPath.moveTo(sX + ii * (dX / mXgridNum), sY - 3); mPath.lineTo(sX + ii * (dX / mXgridNum), sY + 3); float ff = mXminGrid + ii * (mXmaxGrid - mXminGrid) / mXgridNum; mCnv.drawText(String.format("%.1f", ff), sX + ii * (dX / mXgridNum), sY - p_text_size + 2, mPntText); } } mCnv.drawPath(mPath, mPntAxis); } private String mYLabelFlag = null; public void setYLabelFlag(String label) { this.mYLabelFlag = label; } protected void drawYlabel() { if (p_ytext_left) { mPntText.setTextAlign(Align.RIGHT); } else { mPntText.setTextAlign(Align.LEFT); } mPath.reset(); if (p_ytext_left) { for (int ii = 1; ii < mYgridNum; ii++) { mPath.moveTo(sX - 3, eY - ii * (dY / mYgridNum)); mPath.lineTo(sX + 3, eY - ii * (dY / mYgridNum)); float ff = mYminGrid + ii * (mYmaxGrid - mYminGrid) / mYgridNum; if (mYLabelFlag == null) { mCnv.drawText(String.format("%s", (int) ff), sX - 6, eY - ii * (dY / mYgridNum) + p_text_size / 2, mPntText); } else { mCnv.drawText(String.format("%s%s", (int) ff, mYLabelFlag), sX - 6, eY - ii * (dY / mYgridNum) + p_text_size / 2, mPntText); } } } else { for (int ii = 1; ii < mYgridNum; ii++) { mPath.moveTo(eX - 3, eY - ii * (dY / mYgridNum)); mPath.lineTo(eX + 3, eY - ii * (dY / mYgridNum)); float ff = mYminGrid + ii * (mYmaxGrid - mYminGrid) / mYgridNum; if (mYLabelFlag == null) { mCnv.drawText(String.format("%s%s", (int) ff, mYLabelFlag), eX + 6, eY - ii * (dY / mYgridNum) + p_text_size / 2, mPntText); } else { mCnv.drawText(String.format("%s%s", (int) ff, mYLabelFlag), eX + 6, eY - ii * (dY / mYgridNum) + p_text_size / 2, mPntText); } } } mCnv.drawPath(mPath, mPntAxis); } protected void drawBorder() { mPath.reset(); mPath.moveTo(sX, sY); mPath.lineTo(eX, sY); mPath.lineTo(eX, eY); mPath.lineTo(sX, eY); mPath.lineTo(sX, sY); mCnv.drawPath(mPath, mPntBorder); } protected void drawAxis() { mPath.reset(); mPath.moveTo(sX - bX * aX, sY); mPath.lineTo(sX - bX * aX, eY); mPath.moveTo(sX, eY + bY * aY); mPath.lineTo(eX, eY + bY * aY); mCnv.drawPath(mPath, mPntAxis); } public LColor getBackground() { return _background; } public void setBackground(LColor b) { this._background = b; super.setBackground(b); } protected float dipToPixel(float dips) { return dips; } }