• 【java/awt】绘制直方图例子,此例适应于值有正有负的情况


    注意当前只是初稿状态,还有待修改。

    先上图:

    代码:

    package flexChart;
    
    import java.awt.BasicStroke;
    import java.awt.Color;
    import java.awt.Font;
    import java.awt.FontMetrics;
    import java.awt.Graphics2D;
    import java.awt.RenderingHints;
    import java.awt.Stroke;
    import java.awt.geom.AffineTransform;
    import java.awt.image.BufferedImage;
    import java.io.FileOutputStream;
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.imageio.ImageIO;
    
    
    
    
    
    // 直方图的柱类
    class Bar{
        String name;
        int value;
        
        public Bar(String name,int value) {
            this.name=name;
            this.value=value;
        }
    }
    
    // 点类
    class Point{
        public Point(float x,float y) {
            this.x=x;
            this.y=y;
        }
        float x;
        float y;
    }
    
    /**
     * 直方图
     * @author ufo
     * 2022年2月15日
     */
    public class FlexChartMaker {
        // 图片宽度
        private final int WIDTH;
        
        // 图片高度
        private final int HEIGHT;
        
        // 上下边界宽度
        private final int MARGIN;
        
        // 标题栏高度
        private final int TITLE_HEIGHT;
        
        // img对象
        private BufferedImage img;
        
        // 绘图环境
        private Graphics2D g2d;
        
        // 直方图数据
        private List<Bar> bars;
        
        private int yStart=0;
        
        /**
         * 构造函数
         * @param width
         * @param height
         * @param margin
         * @param titleHeight
         */
        public FlexChartMaker(int width,int height,int margin,int titleHeight) {
            this.WIDTH=width;
            this.HEIGHT=height;
            this.MARGIN=margin;
            this.TITLE_HEIGHT=titleHeight;
            
            this.img=new BufferedImage(this.WIDTH,this.HEIGHT,BufferedImage.TYPE_INT_RGB);
            this.g2d=(Graphics2D)img.getGraphics();
        }
        
        // 写入图片
        public void write2File(String path) {
            try {
                ImageIO.write(this.img, "PNG", new FileOutputStream(path));
            } catch (Exception e) {
                e.printStackTrace();
            } 
        }
        
        // 绘制图案
        public void draw() {
            // 消除线条锯齿  
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            
            // 白色底漆
            g2d.setColor(Color.white);
            g2d.fillRect(0, 0, this.WIDTH, this.HEIGHT);
            // 画脚标
            g2d.setFont(new Font("黑体",Font.PLAIN,8));
            FontMetrics fm1=g2d.getFontMetrics();
            String text="逆火狂飙绘制";
            int textWidth=fm1.stringWidth(text);
            g2d.setColor(Color.black);
            g2d.drawString(text,(this.WIDTH-textWidth)/2,this.HEIGHT-this.MARGIN/2);
            
            // 标题栏区域
            g2d.setColor(new Color(135,206,200));
            g2d.fillRect(this.MARGIN, this.MARGIN, this.WIDTH-2*this.MARGIN, this.TITLE_HEIGHT);
            // 画标题
            g2d.setFont(new Font("宋体",Font.BOLD,36));
            FontMetrics fm2=g2d.getFontMetrics();
            text="g2d绘制直方图示例";
            textWidth=fm2.stringWidth(text);
            g2d.setColor(Color.white);
            g2d.drawString(text,(this.WIDTH-textWidth)/2,this.MARGIN+this.TITLE_HEIGHT/2+10);
            
            // 天蓝色可绘制区域
            g2d.setColor(new Color(135,206,235));
            g2d.fillRect(this.MARGIN, this.MARGIN+this.TITLE_HEIGHT, this.WIDTH-2*this.MARGIN, this.HEIGHT-2*this.MARGIN-this.TITLE_HEIGHT);
        
            // 算y起点
            int max=-this.HEIGHT;
            int min= this.HEIGHT;
            
            // 取极值
            for(Bar b:bars) {
                if(b.value>max) {
                    max=b.value;
                }
                
                if(b.value<min) {
                    min=b.value;
                }
            }
            System.out.println("max="+max+" min="+min);
            
            int yZero=0;
            if(max>0 && min>0) {
                yZero=this.HEIGHT-this.MARGIN;            
            }else if(max<0 && min<0) {
                yZero=this.TITLE_HEIGHT+this.MARGIN;
            }else if(max>0 && min<0) {
                yZero=(this.HEIGHT-2*this.MARGIN-this.TITLE_HEIGHT)/2+this.TITLE_HEIGHT+this.MARGIN;
                this.yStart=yZero;
                
                // 基准线
                g2d.setColor(Color.yellow);
                g2d.setStroke(new BasicStroke(1.0f));
                g2d.drawLine(this.MARGIN,yZero, this.WIDTH-this.MARGIN, yZero);
                
                // 进行坐标变换,上面为屏幕坐标系,下面为平面直角坐标系(笛卡尔坐标系)
                resetCoodinate(yZero);
                
                // 绘图区域的端点
                int xStart=0;
                int xEnd=xStart+this.WIDTH-2*this.MARGIN;      
                int yMin=yZero-(this.HEIGHT-this.MARGIN);
                int yMax=(this.HEIGHT)-yZero-this.MARGIN;
                System.out.println(String.format("xStart=%d,xEnd=%d,yMin=%d,yMax=%d,", xStart,xEnd,yMin,yMax));
    
                // 柱子数量
                final int barCnt=this.bars.size();
                
                // 竖向网格线开始
                final float stepx=(this.WIDTH-2*this.MARGIN)/barCnt;
                final float CW=stepx/3;// CW:Column Width
                
                // LINE_TYPE_DASHED   
                Stroke dashed=new BasicStroke(1,BasicStroke.CAP_BUTT,   
                                                          BasicStroke.JOIN_BEVEL,   0,   
                                                          new   float[]{16,   4},   0);
                g2d.setColor(Color.gray);
                
                for(int i=0;i<barCnt;i++) {
                    float x=i*stepx;
                    
                    g2d.setStroke(new BasicStroke(1.0f));
                    g2d.drawLine((int)x, yMin, (int)x, yMax);
                    
                    g2d.setStroke(dashed);
                    g2d.drawLine((int)(x+CW), yMin, (int)(x+CW), yMax);
                    g2d.drawLine((int)(x+2*CW), yMin, (int)(x+2*CW), yMax);
                }
                // 竖向网格线结束
                
                // 以最指定比例
                float maxCnt=-1;
                for(Bar b:bars) {
                    int abs=Math.abs(b.value);
                    if(abs>maxCnt) {
                        maxCnt=abs;
                    }
                }
                final float ratio=yMax/maxCnt;
                
                // 横向网格线开始
                final float stepy=(yMax-yMin)/barCnt;
                final float GH=stepy/3;// GH:Grid Width
                
                for(int i=0;i<=barCnt;i++){
                    float y=yMin+i*stepy;
                    
                    g2d.setStroke(new BasicStroke(1.0f));
                    g2d.drawLine(xStart,(int)y, xEnd, (int)y);
                    
                    g2d.setFont(new Font("宋体",Font.BOLD,16));
                    g2d.setColor(Color.black);
                    int yValue=(int)(y*maxCnt/yMax);
                    putString(g2d,yValue+"",15,(int)y);
                    
                    if(i>0) {
                        g2d.setStroke(dashed);
                        yValue=(int)((y-GH)*maxCnt/yMax);
                        g2d.drawLine(xStart,(int)(y-GH), xEnd, (int)(y-GH));
                        putString(g2d,yValue+"",xEnd+15,(int)(y-GH));
                        
                        g2d.drawLine(xStart,(int)(y-2*GH), xEnd, (int)(y-2*GH));
                    }
                }
                // 横向网格线结束
                
                // --往下是画柱状图
                for(int i=0;i<this.bars.size();i++){
                    Bar bar=this.bars.get(i);
                    
                    float x=i*stepx+(CW);
                    float w=CW;
                    
                    float y=0,h=0;
                    if(bar.value>0) {
                        y=0;            
                        h=bar.value*ratio;
                    }else {
                        y=bar.value*ratio;
                        h=Math.abs(bar.value*ratio);
                    }
                    
                    g2d.setColor(getColor(i));
                    g2d.fillRect((int)x, (int)y, (int)(w), (int)(h));
    
                    // 在柱子顶写文字
                    float textX=x+CW/2+17;
                    float textY=y+h/2;
                    g2d.setFont(new Font("宋体",Font.BOLD,16));
                    g2d.setColor(Color.black);
                    putString(g2d,bar.name+"="+bar.value,(int)(textX),(int)(textY));
                }
            }
            
     
        }
        
        // 重置屏幕坐标系为笛卡尔坐标系
        private void resetCoodinate(int yStart) {
            AffineTransform trans = new AffineTransform();
            trans.translate(this.MARGIN,this.HEIGHT-yStart+this.TITLE_HEIGHT);
            trans.rotate(getRad(180.0),0,0);
            trans.scale(-1,1);        
            this.g2d.setTransform(trans);
        }
        
        // 添加一项直方图柱子
        public void addBar(String name,int value) {
            if(bars==null) {
                bars=new ArrayList<Bar>();
            }
            
            bars.add(new Bar(name,value));
        }
        
        // 传入度数,返回弧度
        private static double getRad(double degree) {
            return degree*Math.PI/180.0f;
        }
        
        // 取一种颜色
        private static Color getColor(int idx) {
            Color[] colors= {Color.red,Color.yellow,Color.blue,Color.magenta,Color.green,Color.orange,Color.cyan};
            
            int i=idx % colors.length;
            return colors[i];
        }
        
        // 写文字
        private void putString(Graphics2D g2d,String text,int x,int y) {
            AffineTransform previousTrans = g2d.getTransform();
            
            AffineTransform newtrans = new AffineTransform();
    
            FontMetrics fm2=g2d.getFontMetrics();
            int textWidth=fm2.stringWidth(text);
            
            newtrans.translate(x-textWidth/2, (this.HEIGHT-this.yStart+this.TITLE_HEIGHT)-y);
            
            g2d.setTransform(newtrans);
            g2d.drawString(text,0,0);
            
            g2d.setTransform(previousTrans);
        }
        
        public static void main(String[] args) {
            FlexChartMaker fcm=new FlexChartMaker(1200,960,20,80);
            
            fcm.addBar("a", 180);
            fcm.addBar("b", 40);
            fcm.addBar("c", -122);
            fcm.addBar("d", 30);
            fcm.addBar("e", 30);
            fcm.addBar("f", 20);
            
            fcm.draw();
            fcm.write2File("c:\\hy\\220215.png");
            System.out.println("图片做成");
        }
    }

    END

  • 相关阅读:
    Codeforces 700A As Fast As Possible(二分答案)
    BZOJ 1196 [HNOI2006]公路修建问题(二分答案+并查集)
    Codeforces 701C They Are Everywhere(Two pointers+STL)
    Codeforces 430B Balls Game(Two Pointers)
    CSU 1812 三角形和矩形
    CSU 1804 有向无环图
    CSU 1803 2016
    CSU 1808 地铁
    CodeForces 707B Bakery
    CodeForces 707A Brain's Photos
  • 原文地址:https://www.cnblogs.com/heyang78/p/15896152.html
Copyright © 2020-2023  润新知