javaswingchartscustom-painting

Is there a way to display an item in the middle of a custom painted chart in Swing?


Is there a way to display an item in the middle of the chart?

Using the chart to output values from the database.

I'd like to place the next item in the center of each pie.

Is there a way? Below is the code.

This is Chart Image

public class DrawingPiePanel extends JPanel {
    public DrawingPiePanel() {
    }

    private static final long serialVersionUID = 1L;

    Admin ad = Login.ad;

    String month = ad.year1 + "-01";

    kiosk_dao dao = new kiosk_dao();
    int Kor = dao.SelectSaleMonthRestaurant(month, "한식");
    int Ch = dao.SelectSaleMonthRestaurant(month, "중식");
    int Jp = dao.SelectSaleMonthRestaurant(month, "일식");
    int We = dao.SelectSaleMonthRestaurant(month, "양식");

    public void paint(Graphics g) {
        g.clearRect(0, 0, getWidth(), getHeight());

        int Total = Kor + Ch + Jp + We;
        if (Total != 0) {
            int arc1 = (int) 360.0 * Kor / Total;
            int arc2 = (int) 360.0 * Ch / Total;
            int arc3 = (int) 360.0 * Jp / Total;
            int arc4 = 360 - (arc1 + arc2 + arc3);

            double KorPer = (double) Kor / (double) Total * 100;
            double ChPer = (double) Ch / (double) Total * 100;
            double JpPer = (double) Jp / (double) Total * 100;
            double WePer = (double) We / (double) Total * 100;

            g.setColor(Color.YELLOW);
            g.fillArc(50, 20, 200, 200, 0, arc1);
            g.setColor(Color.RED);
            g.fillArc(50, 20, 200, 200, arc1, arc2);
            g.setColor(Color.BLUE);
            g.fillArc(50, 20, 200, 200, arc1 + arc2, arc3);
            g.setColor(Color.GREEN);
            g.fillArc(50, 20, 200, 200, arc1 + arc2 + arc3, arc4);
            g.setColor(Color.BLACK);
            g.setFont(new Font("굴림체", Font.PLAIN, 12));
            g.drawString(" 한식: 노랑" + String.format("%.2f", KorPer) + "%", 300, 150);
            g.drawString(" 중식: 빨강" + String.format("%.2f", ChPer) + "%", 300, 170);
            g.drawString(" 일식: 파랑" + String.format("%.2f", JpPer) + "%", 300, 190);
            g.drawString(" 양식: 초록" + String.format("%.2f", WePer) + "%", 300, 210);
            g.drawString(" 총매출액: " + Total + " 원", 300, 230);
        }

    }

}

Solution

  • I tried to use a Shape to draw the arcs and an Area to calculate the center of the filled arc.

    It does a reasonable job, but not perfect:

    import java.awt.*;
    import javax.swing.*;
    import javax.swing.event.*;
    import java.awt.geom.*;
    
    public class DrawPie extends JPanel
    {
        @Override
        protected void paintComponent(Graphics g)
        {
            super.paintComponent(g);
    
            Graphics2D g2d = (Graphics2D)g.create();
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    
            drawArc(g2d, Color.YELLOW, 0, 70, "Y");
            drawArc(g2d, Color.RED, 70, 80, "R");
            drawArc(g2d, Color.BLUE, 150, 90, "B");
            drawArc(g2d, Color.GREEN, 240, 120, "G");
    
            g2d.dispose();
        }
    
        private void drawArc(Graphics2D g2d, Color color, int start, int extent, String text)
        {
            g2d.setColor( color );
            Shape shape = new Arc2D.Double(50, 50, 200, 200, start, extent, Arc2D.PIE);
            g2d.fill( shape );
    
            Rectangle bounds = new Area(shape).getBounds();
            System.out.println(bounds);
            int centerX = bounds.x + (bounds.width / 2) - 5;
            int centerY = bounds.y + (bounds.height / 2) + 7;
            g2d.setColor( Color.BLACK );
            g2d.drawString(text, centerX, centerY);
        }
    
        @Override
        public Dimension getPreferredSize()
        {
            return new Dimension(300, 300);
        }
    
        public static void main(String[] args)
        {
            EventQueue.invokeLater(() ->
            {
                JFrame f = new JFrame();
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.add(new JScrollPane(new DrawPie()));
                f.pack();
                f.setLocationRelativeTo(null);
                f.setVisible(true);
            });
        }
    }
    

    The adjustments to the centerX/Y values was a shortcut for using the real FontMetrics of the Graphics class. The X value should be half the width of the text you draw and the Y value should be the height test you draw. You can try playing with the real FontMetrics to see if it makes a difference.

    Note, this is an example of an "minimal, reproducible example". Only the code directly related to the question is included in the example. Anybody can copy/paste/compile and text. In the future all questions should include an MRE to demonstrate the problem.

    Edit:

    My second attempt which attempts to use Andrew's suggestion to determine a point on a line that is half the arc angle and half the radius.

    import java.awt.*;
    import javax.swing.*;
    import javax.swing.event.*;
    import java.awt.geom.*;
    
    public class DrawPie extends JPanel
    {
        private int inset = 25;
        private int radius = 100;
        private int diameter = radius * 2;
        private int translation = inset + radius;
    
        @Override
        protected void paintComponent(Graphics g)
        {
            super.paintComponent(g);
    
            Graphics2D g2d = (Graphics2D)g.create();
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    
            drawArc(g2d, Color.YELLOW, 0, 70, "Y");
            drawArc(g2d, Color.RED, 70, 90, "R");
            drawArc(g2d, Color.CYAN, 160, 80, "B");
            drawArc(g2d, Color.GREEN, 240, 120, "G");
    
            g2d.dispose();
        }
    
        private void drawArc(Graphics2D g2d, Color color, int start, int extent, String text)
        {
            g2d.setColor( color );
            Shape shape = new Arc2D.Double(inset, inset, diameter, diameter, start, extent, Arc2D.PIE);
            g2d.fill( shape );
    
            double radians = Math.toRadians(90 + start + (extent / 2));
            int centerX = (int)(Math.sin(radians) * radius / 2);
            int centerY = (int)(Math.cos(radians) * radius / 2);
            g2d.setColor( Color.BLACK );
            g2d.drawString(text, centerX + translation, centerY + translation);
        }
    
    
        @Override
        public Dimension getPreferredSize()
        {
            int size = (inset * 2) + diameter;
            return new Dimension(300, 300);
        }
    
        public static void main(String[] args)
        {
            EventQueue.invokeLater(() ->
            {
                JFrame f = new JFrame();
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.add(new JScrollPane(new DrawPie()));
                f.pack();
                f.setLocationRelativeTo(null);
                f.setVisible(true);
            });
        }
    }
    

    Don't know why I needed to add "90" when converting the angle to radians?