之前用Matlab写过一个绘制甘特图的例子,现在想用java再实现以下,其实原理很简单,就是canvas API的一些基本使用。
利用java swing中的Canvas画图工具画的一个甘特图实例,可以自适应窗口的变化而变化。下面给出代码:
package com.canvas.plot; import java.awt.Canvas; import java.awt.Color; import java.awt.Graphics; import org.ejml.data.DenseMatrix64F; import com.sim.common.MatrixHelper; public class CanvasGante extends Canvas { private static final long serialVersionUID = 1L; private final static int margin_left = 20;// 图像左边距 private final static int margin_top = 100;// 图像上边距 private final static int margin_right = 20;// 图像右边距 private final static int margin_buttom = 80;// 图像下边距 private final static int label_width = 40;// 任务标签 private final static int block_width = 40;// 块高度 private final static int block_height = 25;// 块高度 private final static int num_x_divide = 10;// x轴刻度个数 private double[][] data; public double[][] getData() { return data; } public void setData(double[][] data) { this.data = data; } // 颜色数组,以区分不同的原油类型 private final static Color[] colors = { new Color(255, 255, 255), new Color(0, 0, 0), new Color(127, 127, 127), new Color(195, 195, 195), new Color(136, 0, 21), new Color(185, 122, 87), new Color(237, 28, 36), new Color(255, 174, 201), new Color(255, 127, 39), new Color(255, 242, 0), new Color(239, 228, 176), new Color(34, 117, 76), new Color(181, 230, 29), new Color(0, 162, 232), new Color(153, 217, 234), new Color(63, 72, 204), new Color(112, 146, 190), new Color(163, 73, 164), new Color(200, 191, 231), new Color(89, 173, 154), new Color(8, 193, 194), new Color(9, 253, 76), new Color(153, 217, 234), new Color(199, 73, 4) }; public void paint(Graphics g) { super.paint(g); g.setPaintMode(); // 切记,这里要获取Graphics的长和宽,而不是Form的长和宽 int width = g.getClipBounds().width; int height = g.getClipBounds().height; DenseMatrix64F dataMatrix = new DenseMatrix64F(data); double[] col_max = MatrixHelper.getColMax(dataMatrix).data; int numOfOilType = (int) col_max[4];// 原油种类数 int maxTime = (int) col_max[3];// 最后的任务的完成时间 int numOfTasks = (int) col_max[0];// 任务的种类数 double scale_x = 1.0 * (width - margin_left - margin_right - label_width) / maxTime;// 图像大小变化尺度 double scale_y = 1.0 * (height - margin_top - margin_buttom - label_width) / 600 * 100;// 图像大小变化尺度【参考原始比例】 // 绘制详细的调度数据 for (int i = 0; i < data.length; i++) { // 使用不同的颜色填充封闭的矩形区域 int color = (int) data[i][4] - 1; // 不显示停运 if (color > 0) { // 计算矩形区域所在位置和宽度 int data_x = (int) (margin_left + label_width + data[i][2] * scale_x); int data_y = (int) (margin_top + 1.0 * (data[i][0] - 1) * scale_y); int data_width = (int) (1.0 * (data[i][3] - data[i][2]) * scale_x); // 绘制矩形区域,并设置矩形区域的标注 g.setColor(colors[color]); g.fill3DRect(data_x, data_y, data_width, block_height, false); int tank = (int) data[i][1]; g.setColor(Color.black); g.drawString("T" + tank + "", data_x, data_y); } } // 标识x轴刻度 for (int i = 0; i < num_x_divide; i++) { int x1 = (int) (margin_left + label_width + (i + 1) * (width - margin_left - margin_right - label_width) / num_x_divide); int y1 = (int) (margin_top + numOfTasks * scale_y - 10); int x2 = (int) (margin_left + label_width + (i + 1) * (width - margin_left - margin_right - label_width) / num_x_divide); int y2 = (int) (margin_top + numOfTasks * scale_y); g.setColor(Color.black); g.drawLine(x1, y1, x2, y2); g.drawString((i + 1) * maxTime / 10.0 + "", x2 - 15, y2 + 15); } // 标识y轴刻度 for (int i = 0; i < numOfTasks; i++) { int x = margin_left; int y = (int) (margin_top + 1.0 * (numOfTasks - i - 1) * scale_y + block_height / 1.5); if (i < 4) { g.drawString("DS" + (i + 1) + "", x, y); } else { g.drawString("PIPE" + (i - 3) + "", x, y); } } // 绘制坐标轴 int x1 = margin_left + label_width; int y1 = (int) (margin_top + numOfTasks * scale_y); int x2 = width - margin_right; int y2 = (int) (margin_top + numOfTasks * scale_y); g.setColor(Color.black); g.drawLine(x1, y1, x2, y2);// x轴 int x3 = margin_left + label_width; int y3 = margin_top; int x4 = margin_left + label_width; int y4 = (int) (margin_top + numOfTasks * scale_y); g.drawLine(x3, y3, x4, y4);// y轴 // 绘制legend for (int i = 0; i < numOfOilType; i++) { // 计算矩形区域所在位置和宽度 int x = (int) (margin_left + label_width + i * 3 * block_height); int y = height - margin_buttom; // 使用不同的颜色填充封闭的矩形区域 g.setColor(colors[i]); g.fill3DRect(x, y, block_width, block_height, true); // 设置标签 int oilType = i + 1; g.setColor(Color.black); g.drawString("#" + oilType + "", x, y); } } } package com.canvas.plot; import javax.swing.JFrame; public class ChartFrame { // 窗口大小 private final static int width = 1200; private final static int height = 600; // 格式:蒸馏塔/管道 油罐 开始时间 结束时间 原油类型 public static double[][] data1 = { { 2.0, 2.0, 0.0, 47.9, 1.0 }, { 1.0, 5.0, 0.0, 100.0, 3.0 }, { 3.0, 6.0, 0.0, 60.0, 5.0 }, { 4.0, 8.0, 231.4, 279.4, 9.0 }, { 5.0, 9.0, 239.6, 258.1, 9.0 }, { 6.0, 8.0, 50.0, 86.0, 6.0 }, { 4.0, 1.0, 197.0, 200.0, 8.0 }, { 4.0, 9.0, 200.0, 231.4, 9.0 }, { 1.0, 4.0, 244.0, 314.0, 8.0 }, { 5.0, 7.0, 258.1, 268.1, 8.0 }, { 3.0, 11.0, 264.0, 300.2, 10.0 }, { 5.0, 2.0, 268.1, 298.3, 9.0 }, { 4.0, 1.0, 279.4, 300.2, 9.0 }, { 2.0, 3.0, 281.4, 361.6, 11.0 }, { 5.0, 8.0, 298.3, 301.9, 8.0 }, { 4.0, 9.0, 300.2, 323.9, 9.0 }, { 1.0, 7.0, 314.0, 354.0, 8.0 }, { 4.0, 2.0, 323.9, 372.3, 9.0 }, { 1.0, 8.0, 354.0, 372.2, 8.0 }, { 2.0, 10.0, 361.6, 391.5, 11.0 }, { 2.0, 5.0, 391.5, 416.9, 11.0 } }; // 格式:蒸馏塔/管道 油罐 开始时间 结束时间 原油类型 public static double[][] data2 = { { 2.0, 2.0, 0.0, 47.9, 1.0 }, { 1.0, 5.0, 0.0, 100.0, 3.0 }, { 3.0, 6.0, 0.0, 60.0, 5.0 }, { 4.0, 9.0, 0.0, 35.2, 7.0 }, { 6.0, 8.0, 0.0, 50.0, 6.0 }, { 5.0, 11.0, 0.0, 13.6, 8.0 }, { 5.0, 4.0, 13.6, 24.0, 8.0 }, { 5.0, 1.0, 24.0, 36.0, 4.0 }, { 4.0, 10.0, 35.2, 65.6, 8.0 }, { 5.0, 9.0, 36.0, 75.5, 8.0 }, { 2.0, 3.0, 47.9, 125.7, 2.0 }, { 6.0, 8.0, 50.0, 86.0, 6.0 }, { 4.0, 1.0, 197.0, 200.0, 8.0 }, { 4.0, 9.0, 200.0, 231.4, 9.0 }, { 5.0, 4.0, 203.9, 217.9, 8.0 }, { 6.0, 5.0, 207.1, 220.7, 11.0 }, { 5.0, 11.0, 217.9, 229.2, 10.0 }, { 5.0, 1.0, 229.2, 239.6, 9.0 }, { 4.0, 8.0, 231.4, 279.4, 9.0 }, { 5.0, 9.0, 239.6, 258.1, 9.0 }, { 1.0, 4.0, 244.0, 314.0, 8.0 }, { 5.0, 7.0, 258.1, 268.1, 8.0 }, { 3.0, 11.0, 264.0, 300.2, 10.0 }, { 5.0, 2.0, 268.1, 298.3, 9.0 }, { 4.0, 1.0, 279.4, 300.2, 9.0 }, { 2.0, 3.0, 281.4, 361.6, 11.0 }, { 5.0, 8.0, 298.3, 301.9, 8.0 }, { 4.0, 9.0, 300.2, 323.9, 9.0 }, { 1.0, 7.0, 314.0, 354.0, 8.0 }, { 4.0, 2.0, 323.9, 372.3, 9.0 }, { 1.0, 8.0, 354.0, 372.2, 8.0 }, { 2.0, 10.0, 361.6, 391.5, 11.0 }, { 2.0, 5.0, 391.5, 416.9, 11.0 } }; // 格式:蒸馏塔/管道 油罐 开始时间 结束时间 原油类型 public static double[][] data3 = { { 2.0, 2.0, 0.0, 47.9, 1.0 }, { 1.0, 5.0, 0.0, 100.0, 3.0 }, { 4.0, 9.0, 0.0, 35.2, 7.0 }, { 6.0, 8.0, 0.0, 50.0, 6.0 }, { 5.0, 11.0, 0.0, 13.6, 8.0 }, { 5.0, 4.0, 13.6, 24.0, 8.0 }, { 5.0, 1.0, 24.0, 36.0, 4.0 }, { 4.0, 10.0, 35.2, 65.6, 8.0 }, { 5.0, 9.0, 36.0, 75.5, 8.0 }, { 2.0, 3.0, 47.9, 125.7, 2.0 }, { 6.0, 8.0, 50.0, 86.0, 6.0 }, { 3.0, 7.0, 60.0, 128.0, 4.0 }, { 4.0, 11.0, 65.6, 92.8, 8.0 }, { 5.0, 2.0, 75.5, 102.7, 10.0 }, { 6.0, 6.0, 86.0, 140.4, 11.0 }, { 4.0, 4.0, 92.8, 113.6, 8.0 }, { 1.0, 1.0, 100.0, 160.0, 4.0 }, { 5.0, 11.0, 102.7, 109.9, 4.0 }, { 5.0, 0.0, 109.9, 113.6, 0.0 }, { 4.0, 9.0, 113.6, 164.2, 8.0 }, { 5.0, 4.0, 113.6, 130.0, 8.0 }, { 2.0, 8.0, 125.7, 179.6, 6.0 }, { 3.0, 2.0, 128.0, 264.0, 10.0 }, { 5.0, 7.0, 130.0, 145.0, 8.0 }, { 6.0, 3.0, 140.4, 183.3, 11.0 }, { 5.0, 0.0, 145.0, 160.0, 0.0 }, { 1.0, 11.0, 160.0, 196.0, 4.0 }, { 5.0, 1.0, 160.0, 161.9, 8.0 }, { 5.0, 0.0, 161.9, 164.2, 0.0 }, { 5.0, 9.0, 164.2, 179.9, 9.0 }, { 2.0, 6.0, 179.6, 281.4, 11.0 }, { 5.0, 8.0, 179.9, 203.9, 9.0 }, { 6.0, 10.0, 183.3, 207.1, 11.0 }, { 1.0, 7.0, 196.0, 244.0, 8.0 }, { 4.0, 1.0, 197.0, 200.0, 8.0 }, { 4.0, 9.0, 200.0, 231.4, 9.0 }, { 5.0, 4.0, 203.9, 217.9, 8.0 }, { 6.0, 5.0, 207.1, 220.7, 11.0 }, { 5.0, 11.0, 217.9, 229.2, 10.0 }, { 5.0, 1.0, 229.2, 239.6, 9.0 }, { 4.0, 8.0, 231.4, 279.4, 9.0 }, { 5.0, 9.0, 239.6, 258.1, 9.0 }, { 1.0, 4.0, 244.0, 314.0, 8.0 }, { 5.0, 7.0, 258.1, 268.1, 8.0 }, { 3.0, 11.0, 264.0, 300.2, 10.0 }, { 5.0, 2.0, 268.1, 298.3, 9.0 }, { 4.0, 1.0, 279.4, 300.2, 9.0 }, { 2.0, 3.0, 281.4, 361.6, 11.0 }, { 5.0, 8.0, 298.3, 301.9, 8.0 }, { 4.0, 9.0, 300.2, 323.9, 9.0 }, { 1.0, 7.0, 314.0, 354.0, 8.0 }, { 4.0, 2.0, 323.9, 372.3, 9.0 }, { 1.0, 8.0, 354.0, 372.2, 8.0 }, { 2.0, 10.0, 361.6, 391.5, 11.0 }, { 2.0, 5.0, 391.5, 416.9, 11.0 } }; private JFrame frame; private CanvasGante canvas; public ChartFrame() { frame = new JFrame("原油调度甘特图"); canvas = new CanvasGante(); // 将窗口定位到屏幕中间 int screenWidth = (int) java.awt.Toolkit.getDefaultToolkit().getScreenSize().width; int screenHeight = (int) java.awt.Toolkit.getDefaultToolkit().getScreenSize().height; frame.setBounds(screenWidth / 2 - width / 2, screenHeight / 2 - height / 2, width, height); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.setVisible(true); frame.add(canvas); } public void updateCanvas(double[][] data) { canvas.setData(data); canvas.repaint(); } public static void main(String[] args) throws InterruptedException { ChartFrame frame = new ChartFrame(); Thread thread = new Thread(new Runnable() { @Override public void run() { try { for (int i = 1; i < Integer.MAX_VALUE; i++) { if (i % 3 == 0) { frame.updateCanvas(data1); } else if (i % 3 == 1) { frame.updateCanvas(data2); } else if (i % 3 == 2) { frame.updateCanvas(data3); } Thread.sleep(1000); } } catch (InterruptedException e) { e.printStackTrace(); } } }); thread.start(); } }