@Override
  public void startPlay() {
    if (model != null && !model.isPlaying()) {
      model.setPlaying(true);
      playExecutor =
          Executors.newScheduledThreadPool(
              1,
              new ThreadFactory() {

                @Override
                public Thread newThread(Runnable r) {
                  return new Thread(r, "Timeline animator");
                }
              });
      playExecutor.scheduleAtFixedRate(
          new Runnable() {

            @Override
            public void run() {
              double min = model.getCustomMin();
              double max = model.getCustomMax();
              double duration = max - min;
              double step = (duration * model.getPlayStep()) * 0.95;
              double from = model.getIntervalStart();
              double to = model.getIntervalEnd();
              boolean bothBounds = model.getPlayMode().equals(TimelineModel.PlayMode.TWO_BOUNDS);
              boolean someAction = false;
              if (bothBounds) {
                if (step > 0 && to < max) {
                  from += step;
                  to += step;
                  someAction = true;
                } else if (step < 0 && from > min) {
                  from += step;
                  to += step;
                  someAction = true;
                }
              } else {
                if (step > 0 && to < max) {
                  to += step;
                  someAction = true;
                } else if (step < 0 && from > min) {
                  from += step;
                  someAction = true;
                }
              }

              if (someAction) {
                from = Math.max(from, min);
                to = Math.min(to, max);
                setInterval(from, to);
              } else {
                stopPlay();
              }
            }
          },
          model.getPlayDelay(),
          model.getPlayDelay(),
          TimeUnit.MILLISECONDS);
      fireTimelineModelEvent(
          new TimelineModelEvent(TimelineModelEvent.EventType.PLAY_START, model, null));
    }
  }