Java: Как визуализировать / построить временные интервалы - PullRequest
0 голосов
/ 29 мая 2020

У меня есть таблица со следующей структурой:

[interval_name, start_time, end_time]

Я хотел бы визуализировать эти временные интервалы на графике с ось времени, Что-то вроде этой , но явно намного красивее. Есть ли для этого бесплатная библиотека java? есть идеи, как визуализировать это самостоятельно?

большое спасибо всем :)

1 Ответ

0 голосов
/ 29 мая 2020

Я подумал, что было бы интересно создать график временной шкалы с нуля, используя Java Swing.

Вот GUI, который я придумал. Возможно, вам придется щелкнуть изображение правой кнопкой мыши и выбрать «Открыть ссылку в новой вкладке», чтобы четко увидеть детали.

Timeline Plot

Первое, что я сделал, чтобы создать класс 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;
        }

    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...