java.lang.Object
net.i2p.router.web.GraphRenderer

class GraphRendererextends Object
Generate the RRD graph png images, including the combined rate graph.
  • Field Details

    • _log

      private final Log _log
      Logger for graph rendering.
    • _listener

      private final GraphListener _listener
      Source of the stat data being graphed.
    • _context

      private final I2PAppContext _context
      The app context.
    • PROP_THEME_NAME

      private static final String PROP_THEME_NAME
      Config key for the console theme.
      See Also:
    • DEFAULT_THEME

      private static final String DEFAULT_THEME
      Theme assumed when none is configured.
      See Also:
    • TRANSPARENT

      private static final Color TRANSPARENT
      Nothing drawn: the canvas margin, the chrome-less sidebar tiles' axes and the grid a tile too small for one cannot show anything against whatever the page puts behind.
    • GRID_COLOR_HIDDEN

      private static final Color GRID_COLOR_HIDDEN
      Minor grid colour for a tile with no room for a grid, which hides it outright.
    • FRAME_COLOR

      private static final Color FRAME_COLOR
      The plot border, which no theme draws; the gridlines carry the frame instead.
    • SPARKLINE_AREA_COLOR

      private static final Color SPARKLINE_AREA_COLOR
      Fill for the wide, chrome-less sidebar sparkline.

      Neutral on purpose: that tile carries no legend and no labels, so its colour must not read as a first plot from the themed palette.

    • MIN_LINE_WIDTH

      private static final float MIN_LINE_WIDTH
      Narrowest stroke a theme may ask for; below this a plot disappears.
      See Also:
    • SPARKLINE_LINE_WIDTH

      private static final float SPARKLINE_LINE_WIDTH
      Stroke width for the sidebar sparkline.

      A legibility decision: at 250x50 with nothing else drawn, a hairline nearly vanishes. See lineWidth(GraphRenderer.GraphRenderConfig).

      See Also:
    • CROWDED_LINE_WIDTH

      private static final float CROWDED_LINE_WIDTH
      Stroke width for a tile carrying enough periods that a heavier line would merge them.

      A legibility decision, and the reason a theme's width is not obeyed unconditionally. See lineWidth(GraphRenderer.GraphRenderConfig).

      See Also:
    • PROP_FILL

      private static final String PROP_FILL
      Whether to render every series as a filled path under a thin line. @since 0.9.71+.
      See Also:
    • ARROW_COLOR

      private static final Color ARROW_COLOR
      The arrow on an axis break, which no theme draws.

      Already rrd4j's own default, so setting it is stating the intent rather than changing anything - which is the point: it used to be set for two of the four themes only, implying the arrow was a dark-theme decision when it never was.

    • IS_WIN

      private static final boolean IS_WIN
      Whether we are running on Windows.
    • PROP_SMOOTH

      private static final String PROP_SMOOTH
      Config key for line smoothing.
      See Also:
    • PROP_ZERO_BASE

      private static final String PROP_ZERO_BASE
      Keep the historical zero-floored y-axis even when the window's data lives in a narrow band far from zero. Off by default, so the data-driven floor applies.
      See Also:
    • PROP_FONT_MONO

      private static final String PROP_FONT_MONO
      Config key for the unit label font.
      See Also:
    • PROP_FONT_LEGEND

      private static final String PROP_FONT_LEGEND
      Config key for the legend font.
      See Also:
    • PROP_FONT_TITLE

      private static final String PROP_FONT_TITLE
      Config key for the title font.
      See Also:
    • SIZE_MONO

      private static final int SIZE_MONO
      Default unit label font size.
      See Also:
    • SIZE_LEGEND

      private static final int SIZE_LEGEND
      Default legend font size.
      See Also:
    • SIZE_TITLE

      private static final int SIZE_TITLE
      Default title font size.
      See Also:
    • AXIS_FLOOR_MARGIN

      private static final double AXIS_FLOOR_MARGIN
      Headroom left under the data minimum, as a fraction of the window's data range.

      Proportional rather than absolute, so it behaves the same for a rate that hovers around 0.05 and one that sits at 100,000.

      See Also:
    • GRID_STROKE

      private static final Stroke GRID_STROKE
      The stroke drawing the graph grid lines.
    • CAMEL_CASE_PATTERN

      private static final Pattern CAMEL_CASE_PATTERN
      Matches the start of a camel case word in a stat name.
    • LOCAL_DATE_FMT

      private static final ThreadLocal<SimpleDateFormat> LOCAL_DATE_FMT
      SimpleDateFormats are expensive to construct and not thread-safe, so cache one per thread for each timezone variant instead of allocating new ones on every render(OutputStream) call.
    • UTC_DATE_FMT

      private static final ThreadLocal<SimpleDateFormat> UTC_DATE_FMT
      Per-thread UTC date format for the graph labels.
    • GE

      private static final GraphicsEnvironment GE
      Graphics environment holding the available fonts.
    • FONTLIST

      private static final List<String> FONTLIST
      Font families available on this system.
    • STAT_META

      private static final Map<String, GraphRenderer.StatMeta> STAT_META
      Known stat metadata — add entries for new stats instead of extending heuristics.
    • CONDENSED_PERIODS

      private static final int CONDENSED_PERIODS
      Periods at or above which a narrow unsmoothed tile counts as condensed.

      The graphs page's narrow variant packs a few hundred minutes into a sub-400px frame; well below this a narrow tile has room for its points to separate.

      See Also:
    • TITLE_REPLACEMENTS

      private static final List<Map.Entry<String,String>> TITLE_REPLACEMENTS
      Title replacement rules, ordered by key length descending (longest first) so that longer prefixes are matched before their shorter ancestors. Each entry: key maps to replacement.
    • TITLE_POST_REPLACEMENTS

      private static final List<Map.Entry<String,String>> TITLE_POST_REPLACEMENTS
      Post-processing replacements applied after prefix rules. These fix artifacts created by earlier replacements (e.g., "[Tunnel] [Tunnel]").
    • FONT_CONFIGS

      private static final Map<String, GraphRenderer.FontConfig> FONT_CONFIGS
      Per-language font configuration. Legend uses title candidates.
  • Constructor Details

    • GraphRenderer

      public GraphRenderer(I2PAppContext ctx, GraphListener lsnr)
      Binds a renderer to the listener whose RRD it draws.
      Parameters:
      ctx - the app context, for console properties, logging and translations
      lsnr - the listener supplying the RRD, the rate and the router clock
  • Method Details

    • filledLineWidth

      private float filledLineWidth(GraphRenderer.GraphRenderConfig cfg)
      Stroke width for the line overlaid on a filled plot.

      The line drawn over a filled area is not the plot line, so --graph_plotLineWidth and its plain, wide and condensed siblings do not apply to it; it has --graph_plotLineWidthFilled. It used to be half the plot width, which tied an edge that exists to keep the fill readable to a weight chosen for a line that is not being drawn.

      Reads only the filled family. An edge on a fill does not take its weight from the plot line it sits on - letting it track that meant the two could never be set apart - but it does answer the same three questions the plot line does, through its own plain, wide and condensed variables. The width test is shared with lineWidth(GraphRenderer.GraphRenderConfig) so the two families switch at the same frame width; the values are not shared.

      Parameters:
      cfg - the render configuration
      Returns:
      stroke width in pixels
      See Also:
    • render

      public void render(OutputStream out) throws IOException
      Renders the whole archive at the default size, with legend, grid and title.
      Parameters:
      out - where the SVG is written
      Throws:
      IOException - if the graph cannot be produced
    • render

      public void render(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, int endp, boolean showCredit) throws IOException
      Single graph, drawn as a filled area under a line.
      Parameters:
      out - where the SVG is written
      width - image width in pixels
      height - image height in pixels
      hideLegend - true to omit the legend
      hideGrid - true to omit the grid lines
      hideTitle - true to omit the derived title
      showEvents - true to plot the event count rather than the stat
      periodCount - periods in the window; zero or more than the archive draws all of them
      endp - number of periods before now
      showCredit - true to show the signature line
      Throws:
      IOException - if the graph cannot be produced
    • render

      public void render(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, int endp, boolean showCredit, GraphListener lsnr2, String titleOverride, boolean showRestarts) throws IOException
      Single or two-data-source graph.
      Parameters:
      out - where the SVG is written
      width - image width in pixels
      height - image height in pixels
      hideLegend - true to omit the legend
      hideGrid - true to omit the grid lines
      hideTitle - true to omit the derived title
      showEvents - true to plot the event count rather than the stat
      periodCount - periods in the window; zero or more than the archive draws all of them
      endp - number of periods before now
      showCredit - true to show the signature line
      lsnr2 - 2nd data source to plot on same graph, or null. Not recommended for events.
      titleOverride - If non-null, overrides the title
      showRestarts - if true, draw the vertical restart lines and "Router restarted" label
      Throws:
      IOException - if the graph cannot be produced
    • render

      public void render(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, int endp, boolean showCredit, GraphListener lsnr2, String titleOverride, boolean showRestarts, boolean meta) throws IOException
      As render(OutputStream), but optionally emitting the plot metadata rather than the image.
      Parameters:
      out - where the SVG is written
      width - image width in pixels
      height - image height in pixels
      hideLegend - true to omit the legend
      hideGrid - true to omit the grid lines
      hideTitle - true to omit the derived title
      showEvents - true to plot the event count rather than the stat
      periodCount - periods in the window; zero or more than the archive draws all of them
      endp - number of periods before now
      showCredit - true to show the signature line
      lsnr2 - 2nd data source to plot on same graph, or null. Not recommended for events.
      titleOverride - title to draw, or null for the primary stat description
      showRestarts - true to draw a vertical line per router restart
      meta - true to write the geometry and series as JSON instead of drawing
      Throws:
      IOException - if the graph cannot be produced
    • render

      public void render(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, int endp, boolean showCredit, List<GraphListener> extras, String titleOverride, boolean showRestarts) throws IOException
      Render a graph with any number of extra series overlaid. All series share one axis, so they must measure the same thing; see GraphGroups. The primary is drawn first and supplies the axis range; each extra is drawn as a line, never an area, and is named in the legend.
      Parameters:
      out - where the SVG is written
      width - image width in pixels
      height - image height in pixels
      hideLegend - true to omit the legend
      hideGrid - true to omit the grid lines
      hideTitle - true to omit the derived title
      showEvents - true to plot the event count rather than the stat
      periodCount - periods in the window; zero or more than the archive draws all of them
      endp - number of periods before now
      showCredit - true to show the signature line
      extras - extra series in legend order, or null or empty for none
      titleOverride - title to draw, or null for the primary stat description
      showRestarts - true to draw a vertical line per router restart
      Throws:
      IOException - if the graph cannot be produced
    • render

      public void render(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, int endp, boolean showCredit, List<GraphListener> extras, String titleOverride, boolean showRestarts, boolean meta) throws IOException
      As render(OutputStream), but optionally emitting the plot metadata rather than the image.
      Parameters:
      out - where the SVG is written
      width - image width in pixels
      height - image height in pixels
      hideLegend - true to omit the legend
      hideGrid - true to omit the grid lines
      hideTitle - true to omit the derived title
      showEvents - true to plot the event count rather than the stat
      periodCount - periods in the window; zero or more than the archive draws all of them
      endp - number of periods before now
      showCredit - true to show the signature line
      extras - extra series in legend order, or null or empty for none
      titleOverride - title to draw, or null for the primary stat description
      showRestarts - true to draw a vertical line per router restart
      meta - true to write the geometry and series as JSON instead of drawing
      Throws:
      IOException - if the graph cannot be produced
    • renderLines

      public void renderLines(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, int endp, boolean showCredit, List<GraphListener> extras, String titleOverride, boolean showRestarts) throws IOException
      Render a graph with every series, including the primary, drawn as a line.

      Used for combined graphs. Filling the primary would put a solid block behind the other series and hide any that cross it, which defeats the point of overlaying them.

      Parameters:
      out - where the SVG is written
      width - image width in pixels
      height - image height in pixels
      hideLegend - true to omit the legend
      hideGrid - true to omit the grid lines
      hideTitle - true to omit the derived title
      showEvents - true to plot the event count rather than the stat
      periodCount - periods in the window; zero or more than the archive draws all of them
      endp - number of periods before now
      showCredit - true to show the signature line
      extras - extra series in legend order, or null or empty for none
      titleOverride - title to draw, or null for the primary stat description
      showRestarts - true to draw a vertical line per router restart
      Throws:
      IOException - if the graph cannot be produced
      See Also:
    • renderLines

      public void renderLines(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, int endp, boolean showCredit, List<GraphListener> extras, String titleOverride, boolean showRestarts, boolean meta) throws IOException
      Parameters:
      out - where the SVG is written
      width - image width in pixels
      height - image height in pixels
      hideLegend - true to omit the legend
      hideGrid - true to omit the grid lines
      hideTitle - true to omit the derived title
      showEvents - true to plot the event count rather than the stat
      periodCount - periods in the window; zero or more than the archive draws all of them
      endp - number of periods before now
      showCredit - true to show the signature line
      extras - extra series in legend order, or null or empty for none
      titleOverride - title to draw, or null for the primary stat description
      showRestarts - true to draw a vertical line per router restart
      meta - true to write the geometry and series as JSON instead of drawing
      Throws:
      IOException - if the graph cannot be produced
    • buildRenderConfig

      private GraphRenderer.GraphRenderConfig buildRenderConfig(int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, int endp, boolean showCredit, List<GraphListener> extras, String titleOverride, boolean showRestarts)
      Builds the immutable render configuration from parameters and context.
      Parameters:
      width - image width in pixels
      height - image height in pixels
      hideLegend - true to omit the legend
      hideGrid - true to omit the grid lines
      hideTitle - true to omit the derived title
      showEvents - true to plot the event count rather than the stat
      periodCount - periods in the window; zero or more than the archive draws all of them
      endp - number of periods before now; ignored unless positive
      showCredit - true to show the signature line
      extras - extra series in legend order, or null or empty for none
      titleOverride - title to draw, or null for the primary stat description
      showRestarts - true to draw a vertical line per router restart
      Returns:
      the assembled configuration, never null
    • buildRenderConfig

      private GraphRenderer.GraphRenderConfig buildRenderConfig(int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, int endp, boolean showCredit, List<GraphListener> extras, String titleOverride, boolean showRestarts, boolean allLines, boolean meta)
      Assemble the render settings for one graph.
      Parameters:
      width - image width in pixels
      height - image height in pixels
      hideLegend - true to omit the legend
      hideGrid - true to omit the grid lines
      hideTitle - true to omit the derived title
      showEvents - true to plot the event count rather than the stat
      periodCount - periods in the window; zero or more than the archive draws all of them
      endp - number of periods before now; ignored unless positive
      showCredit - true to show the signature line
      extras - extra series in legend order, or null or empty for none
      titleOverride - title to draw, or null for the primary stat description
      showRestarts - true to draw a vertical line per router restart
      allLines - draw the primary as a line rather than a filled area
      meta - true to write the geometry and series as JSON instead of drawing
      Returns:
      the assembled configuration, never null
    • configureDownsampler

      private void configureDownsampler(RrdGraphDef def, GraphRenderer.GraphRenderConfig cfg)
      Caps how many points are plotted so that each has room to be drawn.

      Uncapped, the renderer is handed roughly one point per pixel, and once points are closer together than a pixel a value change falls inside a single column with no width to draw across. The cap is derived from the width instead, and only applied when smoothing is on, so the default rendering is untouched.

      Parameters:
      def - the graph definition
      cfg - the render configuration
    • configureTimeZone

      private void configureTimeZone(RrdGraphDef def, boolean useUtc)
      Sets the graph's time zone.
      Parameters:
      def - the graph definition
      useUtc - whether to use UTC
    • configureFonts

      private void configureFonts(RrdGraphDef def, GraphRenderer.GraphRenderConfig cfg)
      Sets the graph's fonts from the config.
      Parameters:
      def - the graph definition
      cfg - the render configuration
    • configureBaseAndDecimals

      private void configureBaseAndDecimals(GraphRenderer.GraphRenderConfig cfg)
      Derives the unit base and decimal places for the stat.
      Parameters:
      cfg - the render configuration to update
    • axisFloor

      static double axisFloor(double dataMin, double dataMax, boolean forceZero)
      Choose the y-axis floor for a window, so a series that lives in a narrow band far from zero is not flattened against a zero baseline.

      Only the floor is ever returned. The ceiling and the tick rounding are left to rrd4j, which snaps the floor down to cover any value that does not fit and otherwise rounds both ends to its own idea of a sensible label value.

      Pure, so the decision can be unit tested without a router, an RRD or a clock.

      Parameters:
      dataMin - smallest finite value in the window, NaN if none
      dataMax - largest finite value in the window, NaN if none
      forceZero - true to keep the historical zero-floored axis
      Returns:
      the floor to pass to RrdGraphDef.setMinValue
    • resolveAxisRange

      private void resolveAxisRange(GraphRenderer.GraphRenderConfig cfg)
      Measure the window's data range so axisFloor(double, double, boolean) has something to scale.

      The values cannot be taken off the definition before the graph is built: rrd4j computes them internally, while rendering. So this reads the same window from the listener's already-open RRD - the read RrdGraph performs a moment later anyway - and reduces it in one pass.

      Skipped entirely when a floor could not take effect anyway: forceZero asks for the historical axis, and usesMrtgScaling(GraphRenderer.GraphRenderConfig) means rrd4j rebuilds the range itself.

      Parameters:
      cfg - the render configuration, whose range fields are filled in
    • fetchWindow

      private double[] fetchWindow(GraphListener lsnr, String dsName, long startSec, long endSec)
      Read one datasource over the render window.
      Parameters:
      lsnr - the listener holding the RRD, or null
      dsName - datasource to read
      startSec - window start, in seconds
      endSec - window end, in seconds
      Returns:
      the archived values, or null if they could not be read
    • accumulateRange

      private static void accumulateRange(GraphRenderer.GraphRenderConfig cfg, double[] values)
      Fold one series into the running range, ignoring missing and infinite points.

      One pass over a primitive array: no boxing, no sorting, nothing allocated per point.

      Parameters:
      cfg - the render configuration, updated in place
      values - archived values, or null if unavailable
    • usesMrtgScaling

      private static boolean usesMrtgScaling(GraphRenderer.GraphRenderConfig cfg)
      Whether rrd4j scales the value axis itself, ignoring a floor set on the definition.

      With RrdGraphDef.setAltYMrtg(boolean) on, rrd4j's MRTG range expansion rebuilds the y range from the maximum alone and pins the floor at zero, so a floor set on the definition cannot move it. Small graphs turn the option off, which is why they are the ones the data-driven floor helps.

      Mirrors the decision in configureGridAndRendering(RrdGraphDef, GraphRenderer.GraphRenderConfig) so the two cannot drift apart, and is only read after configureBaseAndDecimals(GraphRenderer.GraphRenderConfig) has filled in noDecimalPlace.

      Parameters:
      cfg - the render configuration
      Returns:
      true if rrd4j overwrites the range, so axisFloor(double, double, boolean) cannot take effect
    • configureTitle

      private void configureTitle(RrdGraphDef def, GraphRenderer.GraphRenderConfig cfg)
      Sets the graph title and vertical label.
      Parameters:
      def - the graph definition
      cfg - the render configuration
    • configureDataSources

      private void configureDataSources(RrdGraphDef def, GraphRenderer.GraphRenderConfig cfg) throws IOException
      Adds the stat's data sources to the graph.
      Parameters:
      def - the graph definition
      cfg - the render configuration
      Throws:
      IOException - if the rrd file cannot be read
    • configureArea

      private void configureArea(RrdGraphDef def, GraphRenderer.GraphRenderConfig cfg)
      Draw the primary as a filled area, which is how a single-value graph has always been rendered.

      The one exception is the wide, chrome-less sparkline used in the sidebar, which stays a neutral grey: it is drawn small and unlabelled, so it takes a colour from neither the theme nor the plot palette and must not imply a second series.

      Parameters:
      def - the graph definition being built
      cfg - render configuration; the sparkline special case keys off its width, height and hide flags
    • configureLegend

      private void configureLegend(RrdGraphDef def, GraphRenderer.GraphRenderConfig cfg)
      Adds the legend lines to the graph.
      Parameters:
      def - the graph definition
      cfg - the render configuration
    • renderGroup

      public boolean renderGroup(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, int end, boolean showCredit, GraphListener primary, List<GraphListener> extras, String titleOverride, boolean showRestarts) throws IOException
      Render a combined graph of several stats as overlaid lines.
      Parameters:
      out - where the SVG is written
      width - image width in pixels
      height - image height in pixels
      hideLegend - true to omit the legend
      hideGrid - true to omit the grid lines
      hideTitle - true to omit the derived title
      showEvents - unused; event mode is not supported for combined graphs
      periodCount - periods in the window; zero or more than the archive draws all of them
      end - number of periods before now
      showCredit - true to show the signature line
      primary - the series drawn first; also supplies the axis range
      extras - the remaining series, in legend order
      titleOverride - title to draw, or null for the primary stat description
      showRestarts - true to draw a vertical line per router restart
      Returns:
      true if a graph was written
      Throws:
      IOException - if the graph cannot be produced
    • configureExtraDataSources

      private void configureExtraDataSources(RrdGraphDef def, GraphRenderer.GraphRenderConfig cfg) throws IOException
      Declare and plot every extra series of a combined graph.

      Each member becomes its own datasource drawn as a line, never an area, with a per-series colour and its description in the legend. Areas are reserved for the primary series: filling several overlaid series hides whichever one is behind.

      The max/min/avg/now summary block is emitted for the first extra series only when there is exactly one, matching the long-standing combined-bandwidth graph. With more, four legend lines per series would bury the plot.

      Parameters:
      def - the graph definition being built
      cfg - render configuration; extras, theme, fillSeries and numberFormat drive the series rendering
      Throws:
      IOException - if a listener's datasource names cannot be read
    • addSummaryPrints

      private void addSummaryPrints(RrdGraphDef def, String plotName, String suffix, String numberFormat)
      Emit the max/min/avg/now legend block for one series.
      Parameters:
      def - the graph definition being built
      plotName - the series' datasource name to summarize
      suffix - appended to the min/max/avg/last ids so they do not collide with the primary's
      numberFormat - the rrd format string for each printed value
    • lineWidth

      private float lineWidth(GraphRenderer.GraphRenderConfig cfg)
      Stroke width for a plotted series.

      Three cases are decided here rather than by the theme, because each is a fact about one layout rather than a look the console wants:

      • Grouped graphs stack up to six lines on one axis and are drawn thinner so they stay separable and the dense case does not fill in.
      • The sidebar sparkline is drawn thick because it is small and unlabelled, and a hairline nearly vanishes at that size.
      • A tile carrying many periods is drawn thinner for the same reason the grouped case is: the series is crowded.

      Everything else - an ordinary plot, including one carrying a group of series - takes its weight from the theme. Grouping used to short-circuit to a hard-coded ALL_LINES_WIDTH of 1.5 before any variable was read, which meant --graph_plotLineWidth and --graph_plotLineWidthWide never reached a combined graph and a theme had no way to weight one. The theme now governs, and the constants left here are the cases where a layout reason, not taste, sets the weight: a bare sparkline that a hairline would erase, and a tile crowded enough that any weight merges the series.

      Parameters:
      cfg - the render configuration
      Returns:
      stroke width in pixels
    • isSparkline

      private static boolean isSparkline(GraphRenderer.GraphRenderConfig cfg)
      Whether a frame is the wide, chrome-less sidebar sparkline.

      Identified by its exact size with every other element hidden, which is the only combination the console requests and the only one drawn unlabelled.

      Parameters:
      cfg - the render configuration to classify
      Returns:
      true if the frame is the 250x50 sparkline with title, legend and grid all hidden
    • isCrowdedTile

      private static boolean isCrowdedTile(GraphRenderer.GraphRenderConfig cfg)
      Whether a tile is carrying enough periods that a thicker line would merge them.

      A wide tile keeps the thicker line because it has room to show the crowding; the narrow form is what needs thinning.

      Parameters:
      cfg - the render configuration to classify
      Returns:
      true at 720 or more periods, or 480 or more on a tile 600 pixels wide or less
    • isCondensedTile

      static boolean isCondensedTile(GraphRenderer.GraphRenderConfig cfg)
      Whether a tile is narrow and carrying condensed data, and so takes the theme's condensed plot width.

      Separate from isCrowdedTile(GraphRenderer.GraphRenderConfig) because the two answer different questions. A crowded tile has enough periods that any width merges the series, so it takes a fixed hairline. A condensed tile is merely narrow for the number of periods it carries, so the weight stays the theme's to set - thinner than an ordinary plot, but not a hairline.

      Deliberately independent of smoothing. Smoothing used to exempt a tile from this, because an unsmoothed polyline crowds where a rounded curve does not - but smoothing is itself only a default, and a stepped series is what a user asking for step gets. Gating on it meant the same tile was drawn at two different weights depending on a setting whose value nobody reading the graph could see.

      Parameters:
      cfg - the render configuration
      Returns:
      true if a narrow, period-dense tile takes the theme's condensed plot width
    • extraSeriesColor

      static Color extraSeriesColor(String theme, boolean allLines, int extraIndex)
      The colour for an extra series: plot ordinal 1, i.e. the theme's second hue.

      A frame carries at most two plots (GraphGroups.MAX_SERIES), so "which colour is the extra series" has exactly one answer and it is a themeable one. The two-series bandwidth graph predates grouping and keeps the exact colour it always shipped with.

      Parameters:
      theme - console theme name
      allLines - whether the primary is drawn as a line rather than a filled area
      extraIndex - zero-based position among the extra series
      Returns:
      the colour for that series
    • extraPlot

      private static int extraPlot(int extraIndex)
      Which plot slot an extra series occupies.

      The primary always takes slot 0, so extras start at 1 and, since a frame carries at most two plots, every extra past the first clamps onto slot 1.

      Every per-plot lookup for an extra series goes through here. Its stroke colour, its fill and its value shading. They used to compute the ordinal separately and one of them disagreed, which gave a series one plot's colour and another plot's gradient.

      Parameters:
      extraIndex - zero-based position among the extra series
      Returns:
      the plot ordinal, never less than 1
    • extraPlotForTest

      static int extraPlotForTest(int extraIndex)
      Which plot slot an extra series occupies. Package-visible so a test can pin it.
      Parameters:
      extraIndex - zero-based position among the extra series
      Returns:
      the plot ordinal, never less than 1
    • extraLineShadeForTest

      static Color[] extraLineShadeForTest(String theme, int extraIndex)
      The value-shade stops an extra series would be drawn with.

      Exposed so a test can check that the extra series asks for its own plot's stops rather than a neighbouring plot's. Comparing colours could not catch that, because every shipped theme draws both plots flat and a flat plot has no stops to compare.

      Parameters:
      theme - console theme name
      extraIndex - zero-based position among the extra series
      Returns:
      bottom-to-top stops, or null when that plot is flat
    • paletteColor

      private static Color paletteColor(String theme, int plot)
      The stroke colour for a plot on a frame, from the theme's CSS variables or the built-in palette.
      Parameters:
      theme - console theme name
      plot - the plot ordinal; a frame carries at most two
      Returns:
      the colour, never null
    • plotPathPaint

      private static Paint plotPathPaint(String theme, int plot, int frameHeight)
      The fill for a plot as something to paint with: the theme's colour, or a gradient between two of them.
      Parameters:
      theme - console theme name
      plot - the plot ordinal; a frame carries at most two
      frameHeight - the frame's height in pixels, which a gradient spans
      Returns:
      the paint, never null
    • plotLineShade

      private static Color[] plotLineShade(String theme, int plot)
      The stops that shade one plot line by its value, or null for a flat line.

      Passed per line rather than set once on the definition, so two plots on one axis are shaded independently - the same independence their colours have.

      Parameters:
      theme - the console theme name
      plot - the plot ordinal, 0 for the first line and 1 for the second
      Returns:
      bottom-to-top stops, or null when the theme named one colour or fewer
    • paletteColorForTest

      static Color paletteColorForTest(String theme)
      Package-visible accessor so tests can compare a series against the primary.
      Parameters:
      theme - console theme name
      Returns:
      the first plot's stroke colour, never null
    • configureRestartMarkers

      private void configureRestartMarkers(RrdGraphDef def, GraphRenderer.GraphRenderConfig cfg)
      Adds the router restart markers to the graph.
      Parameters:
      def - the graph definition
      cfg - the render configuration
    • configureCommentsAndSignature

      private void configureCommentsAndSignature(RrdGraphDef def, GraphRenderer.GraphRenderConfig cfg)
      Adds the comments and signature text to the graph.
      Parameters:
      def - the graph definition
      cfg - the render configuration
    • configureGridAndRendering

      private void configureGridAndRendering(RrdGraphDef def, GraphRenderer.GraphRenderConfig cfg)
      Sets the grid style and rendering options.
      Parameters:
      def - the graph definition
      cfg - the render configuration
    • renderGraph

      private void renderGraph(RrdGraphDef def, OutputStream out, GraphRenderer.GraphRenderConfig cfg) throws IOException
      Renders the graph and writes the image.
      Parameters:
      def - the graph definition
      out - where the image is written
      cfg - the render configuration
      Throws:
      IOException - if the image cannot be written
    • applyDash

      private static void applyDash(RrdGraphDef def, GraphRenderer.GraphRenderConfig cfg)
      Hand the theme's dot pattern to the renderer.

      A theme may state only the dot length, in which case jrobin derives the gap from the stroke width. When it states a gap too, that value is used unless it would merge the dots, which is decided in RrdGraphConstants.minimumDashGap. A dot length of zero, from --graph_plotDash:0, asks for a solid line and leaves no gap to set.

      Parameters:
      def - the graph definition being built
      cfg - render configuration; its theme selects the dot and gap values
    • applyTheme

      private static void applyTheme(RrdGraphDef def, GraphRenderer.GraphRenderConfig cfg)
      Apply the theme's colours to the graph definition.

      Every one of them is the theme's to state in its own console.css; this class holds only the fallbacks for a stylesheet that declares nothing, so a frame reads as part of the page it is drawn on.

      Parameters:
      def - the graph definition being built
      cfg - render configuration; its theme and frame size select the colours
    • gridStroke

      private static Stroke gridStroke(float dot, float gap)
      The stroke gridlines are drawn with, from a theme's stated dot and gap.
      Parameters:
      dot - ink length of one dot; zero asks for solid gridlines
      gap - space after the dot, or zero to derive it from the stroke width
      Returns:
      a 1-pixel-wide dashed stroke, or a solid one when dot is zero
    • deriveTitle

      private static String deriveTitle(String name)
      Derive a human-readable graph title from the rate stat name. Pure function — no side effects — uses ordered prefix map for deterministic results.
      Parameters:
      name - the raw rate stat name, e.g. tunnel.buildClient
      Returns:
      the display title: prefix and post replacements applied, then word-capitalized
    • selectFontNames

      private static GraphRenderer.FontNames selectFontNames(String lang)
      Per-language font family selection for graph rendering. Pure function — no side effects — so it is safe to call from any thread.
      Parameters:
      lang - the active UI language code (e.g. "en", "zh", "jp", "ko")
      Returns:
      resolved mono / legend / title family names for the current platform
    • _t

      private String _t(String s)
      Translate a string.
      Parameters:
      s - the message key to translate
      Returns:
      the translated string; returned untranslated on Windows with a zh locale, whose RRD font lacks the CJK glyphs
    • _t

      private String _t(String s, String o)
      Translate a string with a parameter.
      Parameters:
      s - the message key, with the value substituted for {0}
      o - the value replacing the {0} placeholder
      Returns:
      the translated string; on Windows with a zh locale only the substitution is applied