Beispiel #1
0
 /**
  * Update the hoverEntry with the currently hovered entry, or none if none is hovered. Repaints
  * and informs listeners if something has changed.
  *
  * @param p Where the mouse is currently.
  */
 private void updateHoverEntry(Point p) {
   long hoverEntryBefore = hoverEntry;
   hoverEntry = findHoverEntry(p);
   // If something has changed, then redraw.
   if (hoverEntry != hoverEntryBefore) {
     repaint();
     if (listener != null) {
       if (hoverEntry == -1) {
         listener.noItemSelected();
       } else {
         StreamInfoHistoryItem item = history.get(hoverEntry);
         if (item == null) {
           /**
            * This shouldn't happen, because the hover entry is set just before and selected from
            * the current data (and it should all be in the EDT), but apparently it still happens
            * on rare occasions.
            */
           LOGGER.warning("Hovered Entry " + hoverEntry + " was null");
           hoverEntry = -1;
         } else {
           listener.itemSelected(item.getViewers(), item.getTitle(), item.getGame());
         }
       }
     }
   }
 }
Beispiel #2
0
 /**
  * Updates the map of colors used for rendering. This creates the alternating colors based on the
  * full stream status, which should only be changed when new data is set.
  */
 private void makeColors() {
   colors.clear();
   Iterator<Entry<Long, StreamInfoHistoryItem>> it = history.entrySet().iterator();
   String prevStatus = null;
   Color currentColor = FIRST_COLOR;
   while (it.hasNext()) {
     Entry<Long, StreamInfoHistoryItem> entry = it.next();
     long time = entry.getKey();
     StreamInfoHistoryItem item = entry.getValue();
     String newStatus = item.getStatusAndGame();
     // Only change color if neither the previous nor the new status
     // are null (offline) and the previous and new status are not equal.
     if (prevStatus != null && newStatus != null && !prevStatus.equals(newStatus)) {
       // Change color
       if (currentColor == FIRST_COLOR) {
         currentColor = SECOND_COLOR;
       } else {
         currentColor = FIRST_COLOR;
       }
     }
     colors.put(time, currentColor);
     // Save this status as previous status, but only if it's not
     // offline.
     if (newStatus != null) {
       prevStatus = newStatus;
     }
   }
 }
Beispiel #3
0
  /**
   * Update the start/end/duration/min/max variables which can be changed when the data changes as
   * well when the displayed range changes.
   */
  private void updateVars() {
    long startAt = getStartAt(currentRange);
    long endAt = getEndAt();
    int max = 0;
    int min = -1;
    long start = -1;
    long end = -1;
    for (Long time : history.keySet()) {
      if (time < startAt) {
        continue;
      }
      if (endAt > startAt && time > endAt) {
        continue;
      }
      // Start/End time
      if (start == -1) {
        start = time;
      }
      end = time;
      // Max/min value
      StreamInfoHistoryItem historyObj = history.get(time);
      int viewerCount = historyObj.getViewers();
      if (viewerCount < min || min == -1) {
        min = viewerCount;
      }
      if (viewerCount == -1) {
        min = 0;
      }
      if (viewerCount > max) {
        max = viewerCount;
      }
    }

    maxValue = max;
    minValue = min;
    startTime = start;
    endTime = end;
    duration = end - start;
  }
Beispiel #4
0
  /**
   * Draw the text and graph.
   *
   * @param g
   */
  @Override
  public void paintComponent(Graphics g) {
    locations.clear();

    // Background
    g.setColor(background_color);
    g.fillRect(0, 0, getWidth(), getHeight());

    // This color is used for everything until drawing the points
    g.setColor(foreground_color);

    // Anti-Aliasing
    Graphics2D g2 = (Graphics2D) g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    // Font
    FontMetrics fontMetrics = g.getFontMetrics(FONT);
    int fontHeight = fontMetrics.getHeight();
    g.setFont(FONT);

    int topTextY = fontMetrics.getAscent();

    // Margins
    int vMargin = fontHeight + MARGIN;
    int hMargin = MARGIN;

    // Calculate actual usable size
    double width = getWidth() - hMargin * 2;
    double height = getHeight() - vMargin * 2;

    boolean drawLowerLine = height > -vMargin;

    // If there is any data and no hovered entry is shown, draw current
    // viewercount
    int nowTextX = 0;
    if (history != null && hoverEntry == -1) {
      Integer viewers = history.get(endTime).getViewers();
      long ago = System.currentTimeMillis() - endTime;
      String text;
      if (ago > CONSIDERED_AS_NOW) {
        text = "latest: " + Helper.formatViewerCount(viewers);
      } else {
        text = "now: " + Helper.formatViewerCount(viewers);
      }
      if (viewers == -1) {
        text = "Stream offline";
      }
      nowTextX = getWidth() - fontMetrics.stringWidth(text);
      g.drawString(text, nowTextX, topTextY);
    }

    // Default text when no data is present
    if (history == null || history.size() < 2) {
      String text = "No viewer history yet";
      int textWidth = fontMetrics.stringWidth(text);
      int y = getHeight() / 2 + fontMetrics.getDescent();
      int x = (getWidth() - textWidth) / 2;
      boolean drawInfoText = false;
      if (history != null && y < topTextY + fontHeight + 4 && x + textWidth + 7 > nowTextX) {
        if (drawLowerLine || nowTextX > textWidth + 5) {
          if (drawLowerLine) {
            y = getHeight() - 2;
          } else {
            y = topTextY;
          }
          x = 0;
          drawInfoText = true;
        }
      } else {
        drawInfoText = true;
      }
      if (drawInfoText) {
        g.drawString(text, x, y);
      }
      return;
    }

    // ----------
    // From here only when actual data is to be rendered

    // Show info on hovered entry
    String maxValueText = "max: " + Helper.formatViewerCount(maxValue);
    int maxValueEnd = fontMetrics.stringWidth(maxValueText);
    boolean displayMaxValue = true;

    if (hoverEntry != -1) {
      Integer viewers = history.get(hoverEntry).getViewers();
      Date d = new Date(hoverEntry);
      String text = "Viewers: " + Helper.formatViewerCount(viewers) + " (" + sdf.format(d) + ")";
      if (viewers == -1) {
        text = "Stream offline (" + sdf.format(d) + ")";
      }
      int x = getWidth() - fontMetrics.stringWidth(text);
      if (maxValueEnd > x) {
        displayMaxValue = false;
      }
      g.drawString(text, x, topTextY);
    }

    String minText = "min: " + Helper.formatViewerCount(minValue);
    int minTextWidth = fontMetrics.stringWidth(minText);

    // Draw Times
    if (drawLowerLine) {
      String timeText = makeTimesText(startTime, endTime);
      int timeTextWidth = fontMetrics.stringWidth(timeText);
      int textX = getWidth() - timeTextWidth;
      g.drawString(timeText, textX, getHeight() - 1);

      if (minValue >= 1000 && timeTextWidth + minTextWidth > width) {
        minText = "min: " + minValue / 1000 + "k";
      }
    }

    // Draw min/max if necessary
    if (isShowingInfo()) {
      if (displayMaxValue) {
        g.drawString(maxValueText, 0, topTextY);
      }
      if (drawLowerLine) {
        g.drawString(minText, 0, getHeight() - 1);
      } else if (maxValueEnd + minTextWidth + 29 < nowTextX) {
        g.drawString(minText, maxValueEnd + 10, topTextY);
      }
    }

    // If height available for the graph is too small, don't draw graph
    if (height < 5) {
      return;
    }

    // Calculation factors for calculating the points location
    int range = maxValue - minValue;
    if (showFullRange) {
      range = maxValue;
    }
    if (range == 0) {
      // Prevent division by zero
      range = 1;
    }
    double pixelPerViewer = height / range;
    double pixelPerTime = width / duration;

    // Go through all entries and calculate positions

    int prevX = -1;
    int prevY = -1;
    Iterator<Entry<Long, StreamInfoHistoryItem>> it = history.entrySet().iterator();
    while (it.hasNext()) {
      Entry<Long, StreamInfoHistoryItem> entry = it.next();

      // Get time and value to draw next
      long time = entry.getKey();
      if (time < startTime || time > endTime) {
        continue;
      }
      long offsetTime = time - startTime;

      int viewers = entry.getValue().getViewers();
      if (viewers == -1) {
        viewers = 0;
      }

      // Calculate point location
      int x = (int) (hMargin + offsetTime * pixelPerTime);
      int y;
      if (showFullRange) {
        y = (int) (-vMargin + getHeight() - (viewers) * pixelPerViewer);
      } else {
        y = (int) (-vMargin + getHeight() - (viewers - minValue) * pixelPerViewer);
      }

      // Draw connecting line
      if (prevX != -1) {
        g.drawLine(x, y, prevX, prevY);
      }

      // Save point coordinates to be able to draw the line next loop
      prevX = x;
      prevY = y;

      // Save point locations to draw points and to find entries on hover
      locations.put(new Point(x, y), time);
    }

    // Draw points (after lines, so they are in front)
    for (Point point : locations.keySet()) {
      int x = point.x;
      int y = point.y;
      long seconds = locations.get(point);

      StreamInfoHistoryItem historyObject = history.get(seconds);

      // Highlight hovered entry
      if (seconds == hoverEntry) {
        g.setColor(HOVER_COLOR);
      } else {
        // Draw offline points differently
        if (!historyObject.isOnline()) {
          g.setColor(OFFLINE_COLOR);
        } else {
          g.setColor(colors.get(seconds));
        }
      }
      g.fillOval(x - POINT_SIZE / 2, y - POINT_SIZE / 2, POINT_SIZE, POINT_SIZE);
    }
  }