LineChart extends AnimatedComponent { @Override protected void draw(Graphics2D g2d, Dimension dim) { long now = System.nanoTime(); long drawStartTime = now; if (now - myLastCount > 1e9) { myLastDraws = myDraws; myLastRedraws = myRedraws; myDraws = 0; myRedraws = 0; myLastCount = now; } myDraws++; if (myRedraw) { myRedraw = false; redraw(dim); myRedraws++; } else { addDebugInfo("postAnimate time: 0 ms"); } addDebugInfo("Draws in the last second %d", myLastDraws); addDebugInfo("Redraws in the last second %d", myLastRedraws); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); AffineTransform scale = new AffineTransform(dim.getWidth(), 0, 0, dim.getHeight() - myTopPadding, myXOffset, myYOffset + myTopPadding); if (myShowMaxLine) { g2d.setColor(myMaxLineColor); g2d.setStroke(new BasicStroke(1, CAP_SQUARE, JOIN_MITER, 10, new float[]{3.0f, 3.0f}, 0.0f)); g2d.drawLine(myMaxLineMargin, 0, dim.width, 0); } List<Path2D> transformedPaths = new ArrayList<>(myLinePaths.size()); List<LineConfig> configs = new ArrayList<>(myLinePaths.size()); for (int i = 0; i < myLinePaths.size(); ++i) { Path2D scaledPath = new Path2D.Float(myLinePaths.get(i), scale); LineConfig config = getLineConfig(myLinePathSeries.get(i)); configs.add(config); scaledPath = myReducer.reducePath(scaledPath, config); transformedPaths.add(scaledPath); if (isDrawDebugInfo()) { int count = 0; PathIterator it = scaledPath.getPathIterator(null); while (!it.isDone()) { ++count; it.next(); } addDebugInfo("# of points drawn: %d", count); } } for (int i = 0; i < transformedPaths.size(); ++i) { drawLine(g2d, transformedPaths.get(i), configs.get(i)); } myCustomRenderers.forEach(renderer -> renderer.renderLines(this, g2d, transformedPaths, myLinePathSeries)); addDebugInfo("Draw time: %.2fms", (System.nanoTime() - drawStartTime) / 1e6); } @VisibleForTesting  LineChart(@NotNull LineChartModel model, @NotNull LineChartReducer reducer);  LineChart(@NotNull LineChartModel model);  LineChart(@NotNull List<RangedContinuousSeries> data); void configure(@NotNull RangedContinuousSeries series, @NotNull LineConfig config); void addCustomRenderer(@NotNull LineChartCustomRenderer renderer); @NotNull LineConfig getLineConfig(RangedContinuousSeries rangedContinuousSeries); static void drawLine(@NotNull Graphics2D g2d,
                              @NotNull Path2D path,
                              @NotNull LineConfig config); void setShowMaxLine(boolean showMaxLine); void setMaxLineColor(@NotNull Color maxLineColor); void setMaxLineMargin(int maxLineMargin); void setRenderOffset(int xOffset, int yOffset); void setTopPadding(int padding); void setFillEndGap(boolean fillEndGap);  }
@Test public void testNoRenderWithEmptyRange() { LineChartModel model = new LineChartModel(); Range xRange = new Range(0, 10); Range yRange = new Range(0, 0); DefaultDataSeries<Long> testSeries = new DefaultDataSeries<>(); for (int i = 0; i < 11; i++) { testSeries.add(i, (long)i); } RangedContinuousSeries rangedSeries = new RangedContinuousSeries("test", xRange, yRange, testSeries); model.add(rangedSeries); LineChart chart = new LineChart(model); chart.setSize(100, 100); Graphics2D fakeGraphics = mock(Graphics2D.class); when(fakeGraphics.create()).thenReturn(fakeGraphics); doThrow(new AssertionError()).when(fakeGraphics).draw(any(Shape.class)); chart.paint(fakeGraphics); }