class 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);
    }

    // Cache the transformed line paths for reuse below.
    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);
      }
    }

    // 1st pass - draw all the lines in the background.
    for (int i = 0; i < transformedPaths.size(); ++i) {
      drawLine(g2d, transformedPaths.get(i), configs.get(i));
    }

    // 2nd pass - call each custom renderer instances to redraw any regions/lines as needed.
    myCustomRenderers.forEach(renderer -> renderer.renderLines(this, g2d, transformedPaths, myLinePathSeries));

    addDebugInfo("Draw time: %.2fms", (System.nanoTime() - drawStartTime) / 1e6);
  }

  @VisibleForTesting public  LineChart(@NotNull LineChartModel model, @NotNull LineChartReducer reducer);
  public  LineChart(@NotNull LineChartModel model);
  public  LineChart(@NotNull List<RangedContinuousSeries> data);

}