From eb30472a76b0f06728aabefcaf08f0453f4893d1 Mon Sep 17 00:00:00 2001 From: Ziver Koc Date: Thu, 1 Mar 2018 15:59:08 +0100 Subject: [PATCH] Some work done on charts --- src/zutil/chart/AbstractChart.java | 105 +++++++-------------- src/zutil/chart/ChartData.java | 142 ++++++++++++++--------------- src/zutil/chart/LineAxis.java | 75 +++++++++++++++ src/zutil/chart/LineChart.java | 60 ++++++------ test/zutil/chart/ChartTest.java | 21 +++-- 5 files changed, 221 insertions(+), 182 deletions(-) create mode 100755 src/zutil/chart/LineAxis.java diff --git a/src/zutil/chart/AbstractChart.java b/src/zutil/chart/AbstractChart.java index 7b29512..d3c201c 100755 --- a/src/zutil/chart/AbstractChart.java +++ b/src/zutil/chart/AbstractChart.java @@ -33,7 +33,6 @@ import java.util.logging.Logger; public abstract class AbstractChart extends JPanel{ private static final Logger logger = LogUtil.getLogger(); - private static final long serialVersionUID = 1L; /** The offset from the borders of the panel in pixels */ public static final int PADDING = 20; @@ -46,72 +45,24 @@ public abstract class AbstractChart extends JPanel{ protected void paintComponent(Graphics g){ - Graphics2D g2 = (Graphics2D)g; + Graphics2D g2 = (Graphics2D) g; + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); - Rectangle bound = drawScale( g2 ); + Rectangle bound = drawAxis( g2, new Rectangle(0, 0, getWidth(), getHeight())); drawChart( g2, bound ); } - protected Rectangle drawScale(Graphics2D g2){ - if( data == null ) - return null; - // update values - width = this.getWidth(); - height = this.getHeight(); - Rectangle bound = new Rectangle(); - - // Values - int stepLength = 7; - - /////// Temp values - // Calculate Font sizes - FontMetrics metric = g2.getFontMetrics(); - int fontHeight = metric.getHeight(); - int fontXWidth = 0; - int fontYWidth = 0; - for( Point p : data.getPoints() ){ - int length = 0; - String tmp = data.getXString( p.x ); - if( tmp != null ) length = metric.stringWidth( tmp ); - else length = metric.stringWidth( ""+p.x ); - fontXWidth = Math.max(length, fontXWidth); - - tmp = data.getXString( p.y ); - if( tmp != null ) length = metric.stringWidth( tmp ); - else length = metric.stringWidth( ""+p.y ); - fontYWidth = Math.max(length, fontYWidth); - } - // Calculate origo - Point origo = new Point( PADDING+fontYWidth+stepLength, height-PADDING-fontHeight-stepLength ); - bound.x = (int) (origo.getX()+1); - bound.y = PADDING; - bound.width = width-bound.x-PADDING; - bound.height = (int) (origo.getY()-PADDING-1); - // Calculate Axis scales - double xScale = (double)(Math.abs(data.getMaxX())+Math.abs(data.getMinX()))/bound.width; - double yScale = (double)(Math.abs(data.getMaxY())+Math.abs(data.getMinY()))/bound.height; - - - /////// Draw - // Y Axis - g2.draw( new Line2D.Double( origo.getX(), PADDING, origo.getX(), origo.getY() )); - // X Axis - g2.draw( new Line2D.Double( origo.getX(), origo.getY(), width-PADDING, origo.getY() )); - // Y Axis steps and labels - g2.draw( new Line2D.Double( origo.getX(), origo.getY(), origo.getX()-stepLength, origo.getY() )); - g2.draw( new Line2D.Double( origo.getX(), PADDING, origo.getX()-stepLength, PADDING )); - - // X Axis steps and labels - g2.draw( new Line2D.Double( width-PADDING, origo.getY(), width-PADDING, origo.getY()+stepLength )); - - // DEBUG - /* - g2.setColor(Color.red); - g2.drawRect(bound.x, bound.y, bound.width, bound.height); - */ - return bound; - } + /** + * This method will draw the axis of the chart + * + * @param g2 is the Graphics object that will paint the chart + * @param bound is the bounds of the axis, the drawing should not exceed this bound + */ + protected abstract Rectangle drawAxis(Graphics2D g2, Rectangle bound); /** * This method is called after the chart scale has been drawn. @@ -133,22 +84,34 @@ public abstract class AbstractChart extends JPanel{ } /** - * Converts a x value to ax pixel coordinate + * Converts a x value to a x pixel coordinate * - * @param x is the x data value - * @return pixel coordinate, or 0 if the chart have not been drawn yet. + * @param x is the x data value + * @param scale is the data scale + * @param bound is the drawing boundds + * @return a x pixel coordinate */ - protected int getXCoordinate(int x){ - return 0; + static protected double getXCoordinate(double x, double scale, Rectangle bound){ + return bound.x + x * scale; } /** * Converts a y value to a y pixel coordinate * - * @param y is the y data value - * @return pixel coordinate, or 0 if the chart have not been drawn yet. + * @param y is the y data value + * @param scale is the data scale + * @param bound is the drawing boundds + * @return a y pixel coordinate */ - protected int getYCoordinate(int y){ - return 0; + static protected double getYCoordinate(double y, double scale, Rectangle bound){ + return bound.y + bound.height - ( y * scale ); + } + + static protected double getXScale(ChartData data, Rectangle bound){ + return (double) bound.width / (Math.abs(data.getMaxX()) + Math.abs(data.getMinX())); + } + + static protected double getYScale(ChartData data, Rectangle bound){ + return (double) bound.height / (Math.abs(data.getMaxY()) + Math.abs(data.getMinY())); } } diff --git a/src/zutil/chart/ChartData.java b/src/zutil/chart/ChartData.java index 6f87d67..ff53b73 100755 --- a/src/zutil/chart/ChartData.java +++ b/src/zutil/chart/ChartData.java @@ -30,77 +30,77 @@ import java.util.HashMap; import java.util.List; public class ChartData { - - private HashMap xStrings; - private HashMap yStrings; - private int maxx; - private int minx; - private int maxy; - private int miny; - private ArrayList points; - - - public ChartData(){ - xStrings = new HashMap(); - yStrings = new HashMap(); - - points = new ArrayList(); - } - - public void setXValueString(int x, String name){ - xStrings.put(x, name); - } - public void setYValueString(int y, String name){ - yStrings.put(y, name); - } + private HashMap xStrings; + private HashMap yStrings; + private int maxX; + private int minX; + private int maxY; + private int minY; - - public void addPoint(int x, int y){ - points.add( new Point( x, y)); - setMaxMin(x, y); - } - public void addPoint(int y){ - points.add( new Point( maxx, y)); - maxx++; - setMaxMin(maxx, y); - } - public void addPoint(String x, int y){ - xStrings.put(maxx, x); - points.add( new Point( maxx, y)); - maxx++; - setMaxMin(maxx, y); - } - - - private void setMaxMin(int x, int y){ - if( x > maxx ) maxx = x; - else if( x < minx ) minx = x; - - if( y > maxy ) maxx = y; - else if( y < miny ) minx = y; - } - - public int getMaxX(){ - return maxx; - } - public int getMinX(){ - return minx; - } - public int getMaxY(){ - return maxy; - } - public int getMinY(){ - return miny; - } - public String getXString(int x){ - return xStrings.get(x); - } - public String getYString(int y){ - return yStrings.get(y); - } - - protected List getPoints(){ - return points; - } + private ArrayList points; + + + public ChartData(){ + xStrings = new HashMap(); + yStrings = new HashMap(); + + points = new ArrayList(); + } + + public void setXValueString(int x, String name){ + xStrings.put(x, name); + } + public void setYValueString(int y, String name){ + yStrings.put(y, name); + } + + + public void addPoint(int x, int y){ + points.add( new Point( x, y)); + setMaxMin(x, y); + } + public void addPoint(int y){ + points.add( new Point(maxX, y)); + maxX++; + setMaxMin(maxX, y); + } + public void addPoint(String x, int y){ + xStrings.put(maxX, x); + points.add( new Point(maxX, y)); + maxX++; + setMaxMin(maxX, y); + } + + + private void setMaxMin(int x, int y){ + if( x > maxX) maxX = x; + if( x < minX) minX = x; + + if( y > maxY) maxY = y; + if( y < minY) minY = y; + } + + public int getMaxX(){ + return maxX; + } + public int getMinX(){ + return minX; + } + public int getMaxY(){ + return maxY; + } + public int getMinY(){ + return minY; + } + public String getXString(int x){ + return xStrings.get(x); + } + public String getYString(int y){ + return yStrings.get(y); + } + + protected List getPoints(){ + return points; + } } diff --git a/src/zutil/chart/LineAxis.java b/src/zutil/chart/LineAxis.java new file mode 100755 index 0000000..2c606ec --- /dev/null +++ b/src/zutil/chart/LineAxis.java @@ -0,0 +1,75 @@ +package zutil.chart; + +import java.awt.*; +import java.awt.geom.Line2D; + +/** + * + */ +public abstract class LineAxis extends AbstractChart{ + + @Override + protected Rectangle drawAxis(Graphics2D g2, Rectangle bound){ + if( data == null ) + return null; + + width = bound.width; + height = bound.height; + chartBound = new Rectangle(); + int stepLength = 7; + + // ********************************** + // Calculate Font sizes + // ********************************** + + FontMetrics metric = g2.getFontMetrics(); + int fontHeight = metric.getHeight(); + int fontXWidth = 0; + int fontYWidth = 0; + for( Point p : data.getPoints() ){ + int length; + String tmp = data.getXString( p.x ); + if( tmp != null ) length = metric.stringWidth( tmp ); + else length = metric.stringWidth( ""+p.x ); + fontXWidth = Math.max(length, fontXWidth); + + tmp = data.getXString( p.y ); + if( tmp != null ) length = metric.stringWidth( tmp ); + else length = metric.stringWidth( ""+p.y ); + fontYWidth = Math.max(length, fontYWidth); + } + + // Calculate origo + + Point origo = new Point( + PADDING + fontYWidth + stepLength, + height - PADDING - fontHeight - stepLength ); + chartBound.x = (int) (origo.getX() + 1); + chartBound.y = PADDING; + chartBound.width = width - chartBound.x - PADDING; + chartBound.height = (int) (origo.getY() - PADDING - 1); + + // ********************************** + // Draw + // ********************************** + + g2.setColor(Color.LIGHT_GRAY); + g2.setStroke(new BasicStroke(1.5f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); + + // Y Axis + g2.draw( new Line2D.Double( origo.getX(), PADDING, origo.getX(), origo.getY() )); + // X Axis + g2.draw( new Line2D.Double( origo.getX(), origo.getY(), width-PADDING, origo.getY() )); + // Y Axis steps and labels + + // X Axis steps and labels + + // DEBUG + /* + g2.setColor(Color.red); + g2.drawRect(bound.x, bound.y, bound.width, bound.height); + */ + return chartBound; + } + +} diff --git a/src/zutil/chart/LineChart.java b/src/zutil/chart/LineChart.java index f5f74a4..d3f62db 100755 --- a/src/zutil/chart/LineChart.java +++ b/src/zutil/chart/LineChart.java @@ -27,36 +27,36 @@ package zutil.chart; import java.awt.*; import java.awt.geom.Line2D; -public class LineChart extends AbstractChart{ - private static final long serialVersionUID = 1L; +public class LineChart extends LineAxis{ + private static final long serialVersionUID = 1L; - @Override - protected void drawChart(Graphics2D g2, Rectangle bound) { - // TODO Auto-generated method stub - drawLine(g2, 50, 50,100,150); - drawLine(g2, 100,150,150,100); - drawLine(g2, 150,100,200,300); - drawLine(g2, 200,300,250,40); - } + @Override + protected void drawChart(Graphics2D g2, Rectangle bound) { + g2.setPaint(new Color(237,28,36)); + g2.setStroke(new BasicStroke(2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - private void drawLine(Graphics2D g2, float x1, float y1, float x2, float y2){ - // Shadow - g2.setPaint(new Color(220,220,220)); - g2.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.draw( new Line2D.Float(x1, y1+2, x2, y2+2)); - // Smoth shadow - g2.setPaint(new Color(230,230,230)); - g2.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.draw( new Line2D.Float(x1+1, y1+3, x2-1, y2+3)); - - // Line border - g2.setPaint(new Color(255,187,187)); - g2.setStroke(new BasicStroke(4.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.draw( new Line2D.Float(x1, y1, x2, y2)); - - // Line - g2.setPaint(new Color(237,28,36)); - g2.setStroke(new BasicStroke(2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.draw( new Line2D.Float(x1, y1, x2, y2)); - } + // Calculate position + + double xScale = getXScale(data, bound); + double yScale = getYScale(data, bound); + + // Draw lines + + Point prevP = null; + for(Point p : data.getPoints()){ + if (prevP != null) + drawLine(g2, bound, xScale, yScale, prevP.x, prevP.y, p.x, p.y); + prevP = p; + } + } + + private void drawLine(Graphics2D g2, Rectangle bound, double xScale, double yScale, + double x1, double y1, double x2, double y2){ + // Line + g2.draw(new Line2D.Double( + getXCoordinate(x1, xScale, bound), + getYCoordinate(y1, yScale, bound), + getXCoordinate(x2, xScale, bound), + getYCoordinate(y2, yScale, bound))); + } } diff --git a/test/zutil/chart/ChartTest.java b/test/zutil/chart/ChartTest.java index 7cd8e93..25fe105 100755 --- a/test/zutil/chart/ChartTest.java +++ b/test/zutil/chart/ChartTest.java @@ -41,21 +41,22 @@ public class ChartTest extends JFrame{ public ChartTest(){ ChartData data = new ChartData(); + data.addPoint(0,0); data.addPoint(1,1); - data.addPoint(2,1); - data.addPoint(3,1); - data.addPoint(4,1); - data.addPoint(5,1); - data.addPoint(6,1); - data.addPoint(7,1); - data.addPoint(8,1); + data.addPoint(2,2); + data.addPoint(3,3); + data.addPoint(4,4); + data.addPoint(5,5); + data.addPoint(6,6); + data.addPoint(7,7); + data.addPoint(8,8); LineChart chart = new LineChart(); chart.setChartData( data ); - this.add( chart ); + add( chart ); - this.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); - this.setSize(600, 400); + setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); + setSize(600, 400); } }