Я подумал, что было бы интересно создать график временной шкалы с нуля, используя Java Swing.
Вот GUI, который я придумал. Возможно, вам придется щелкнуть изображение правой кнопкой мыши и выбрать «Открыть ссылку в новой вкладке», чтобы четко увидеть детали.
Первое, что я сделал, чтобы создать класс Event
. Я использовал поля LocalDateTime
для хранения начала и конца события.
Я добавил поле Color
в конструктор класса Event
, чтобы события на графике можно было рисовать разными цветами. В приведенном выше примере я использовал синий для личного времени и черный для рабочего времени.
Затем я создал класс TimeLine
для хранения List
событий.
Затем я создал временная шкала в конструкторе основного класса TimeLinePlot
.
Наконец, я создал JFrame
и рисунок JPanel
. Я нарисовал график временной шкалы на чертеже JPanel
.
Этот код не предназначен для полного решения. Этот код предназначен для того, чтобы показать OP и другим, как создать график временной шкалы.
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TimeLinePlot implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new TimeLinePlot());
}
private final int plotWidth;
private final int plotHeight;
private final int margin;
private int increment;
private final String[] xAxis;
private final TimeLine timeLine;
public TimeLinePlot() {
this.plotWidth = 1000;
this.plotHeight = 500;
this.margin = 50;
this.timeLine = generateTimeLine();
this.xAxis = createXAxis();
}
private TimeLine generateTimeLine() {
TimeLine timeLine = new TimeLine();
Event event = new Event("Breakfast", Color.BLUE,
"5/29/2020 7:00AM", "5/29/2020 8:00AM");
timeLine.addEvent(event);
event = new Event("Shower", Color.BLUE,
"5/29/2020 8:00AM", "5/29/2020 8:30AM");
timeLine.addEvent(event);
event = new Event("Stack Overflow", Color.BLACK,
"5/29/2020 8:30AM", "5/29/2020 11:45AM");
timeLine.addEvent(event);
event = new Event("Lunch", Color.BLUE,
"5/29/2020 11:30AM", "5/29/2020 12:30PM");
timeLine.addEvent(event);
event = new Event("Stack Overflow", Color.BLACK,
"5/29/2020 12:00PM", "5/29/2020 4:30PM");
timeLine.addEvent(event);
return timeLine;
}
private String[] createXAxis() {
LocalDateTime startDateTime =
timeLine.getEarliestStartDate();
LocalDateTime endDateTime =
timeLine.getLatestEndDate();
Duration duration = Duration.between(
startDateTime, endDateTime);
// System.out.println(duration);
if (duration.toDays() > 0L) {
// TODO Figure out a multi-day timeline
return new String[0];
} else {
long minutes = duration.toMinutes();
int hours = (int) Math.ceil(minutes / 60D);
// System.out.println(hours);
increment = 1;
if (hours > 12) {
increment = 2;
hours /= 2;
}
String[] axis = new String[hours + 1];
LocalDateTime dateTime = startDateTime;
for (int i = 0; i <= hours; i += increment) {
axis[i] = createTimeLabel(dateTime);
dateTime = dateTime.plusHours(increment);
}
// System.out.println(Arrays.asList(axis));
return axis;
}
}
private String createTimeLabel(LocalDateTime dateTime) {
return dateTime.format(
DateTimeFormatter.ofPattern("h:mm a"));
}
@Override
public void run() {
JFrame frame = new JFrame("Time Line Plot");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TimeLinePanel timeLinePanel = new TimeLinePanel(
plotWidth, plotHeight, margin, timeLine,
increment, xAxis);
frame.add(timeLinePanel, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public class TimeLinePanel extends JPanel {
private static final long serialVersionUID = 1L;
private final int plotWidth;
private final int plotHeight;
private final int margin;
private final int tickLength;
private final int increment;
private final String[] xAxis;
private final TimeLine timeLine;
public TimeLinePanel(int plotWidth, int plotHeight,
int margin, TimeLine timeLine, int increment,
String[] xAxis) {
this.plotWidth = plotWidth;
this.plotHeight = plotHeight;
this.margin = margin;
this.tickLength = 20;
this.increment = increment;
this.timeLine = timeLine;
this.xAxis = xAxis;
this.setPreferredSize(new Dimension(
plotWidth, plotHeight));
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.setFont(getFont().deriveFont(14f)
.deriveFont(Font.BOLD));
createXAxis(g2d);
createTimeLines(g2d);
}
private void createXAxis(Graphics2D g2d) {
int height = plotHeight - margin;
int width = plotWidth - margin * 4;
int pixelGap = width / (xAxis.length - 1);
int x = margin + margin;
int x1 = x;
int y = height - tickLength - 10;
g2d.setColor(Color.BLACK);
g2d.setStroke(new BasicStroke(3f));
FontMetrics metrics = g2d.getFontMetrics(getFont());
for (int i = 0; i < xAxis.length; i++) {
g2d.drawLine(x, y, x, y + tickLength);
int a = x - metrics.stringWidth(xAxis[i]) / 2;
int b = y + tickLength + metrics.getHeight() / 2 +
metrics.getAscent();
g2d.drawString(xAxis[i], a, b);
x += pixelGap;
}
g2d.drawLine(x1, y, x - pixelGap, y);
}
private void createTimeLines(Graphics2D g2d) {
LocalDateTime earliestStartTime =
timeLine.getEarliestStartDate();
List<Event> events = timeLine.getEvents();
int height = plotHeight - margin;
int width = plotWidth - margin * 4;
int pixelGapH = height / events.size();
int pixelGapW = width / (xAxis.length - 1);
int x = margin + margin;
int y = height - tickLength - 30;
g2d.setStroke(new BasicStroke(9f));
FontMetrics metrics = g2d.getFontMetrics(getFont());
for (int i = events.size() - 1; i >= 0; i--) {
Event event = events.get(i);
LocalDateTime startTime = event.getStartTime();
LocalDateTime endTime = event.getEndTime();
Duration duration1 = Duration.between(
earliestStartTime, startTime);
Duration duration2 = Duration.between(
earliestStartTime, endTime);
long minutes1 = duration1.toMinutes();
long minutes2 = duration2.toMinutes();
String text = event.getName();
int a1 = x + (int) (Math.round((double) minutes1 *
pixelGapW * increment / 60D));
int a2 = x + (int) (Math.round((double) minutes2 *
pixelGapW * increment / 60D));
int a = a1 + ((a2 - a1) / 2) -
(metrics.stringWidth(text) / 2) - 4;
int b = y - 8;
g2d.setColor(event.getColor());
g2d.drawLine(a1, y, a2, y);
g2d.drawString(text, a, b);
y -= pixelGapH;
}
}
}
public class TimeLine {
private List<Event> events;
public TimeLine() {
this.events = new ArrayList<>();
}
public void addEvent(Event event) {
this.events.add(event);
}
public List<Event> getEvents() {
return events;
}
public LocalDateTime getEarliestStartDate() {
LocalDateTime minimumStartDateTime = null;
for (Event event : events) {
if (minimumStartDateTime == null ||
event.getStartTime().compareTo(
minimumStartDateTime) < 0) {
minimumStartDateTime = event.getStartTime();
}
}
return minimumStartDateTime;
}
public LocalDateTime getLatestEndDate() {
LocalDateTime maximumEndDateTime = null;
for (Event event : events) {
if (maximumEndDateTime == null ||
event.getEndTime().compareTo(
maximumEndDateTime) > 0) {
maximumEndDateTime = event.getEndTime();
}
}
return maximumEndDateTime;
}
}
public class Event {
private final DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("M/d/yyyy h:mma");
private Color color;
private final String name;
private final LocalDateTime startTime;
private final LocalDateTime endTime;
public Event(String name, Color color, String startTimeString,
String endTimeString) {
this.name = name;
this.color = color;
this.startTime = LocalDateTime.parse(startTimeString,
formatter);
this.endTime = LocalDateTime.parse(endTimeString,
formatter);
}
public String getName() {
return name;
}
public Color getColor() {
return color;
}
public LocalDateTime getStartTime() {
return startTime;
}
public LocalDateTime getEndTime() {
return endTime;
}
}
}