text: /*!
   * chartjs-plugin-streaming v2.0.0-beta.2
   * https://nagix.github.io/chartjs-plugin-streaming
   * (c) 2017-2021 Akihiko Kusanagi
   * Released under the MIT license
   */
  (function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('chart.js'), require('chart.js/helpers')) :
  typeof define === 'function' && define.amd ? define(['chart.js', 'chart.js/helpers'], factory) :
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.ChartStreaming = factory(global.Chart, global.Chart.helpers));
  }(this, (function (chart_js, helpers) { 'use strict';
  
  function clamp(value, lower, upper) {
    return Math.min(Math.max(value, lower), upper);
  }
  function resolveOption(scale, key) {
    const realtimeOpts = scale.options.realtime;
    const streamingOpts = scale.chart.options.plugins.streaming;
    return helpers.valueOrDefault(realtimeOpts[key], streamingOpts[key]);
  }
  function getAxisMap(element, {x, y}, {xAxisID, yAxisID}) {
    const axisMap = {};
    helpers.each(x, key => {
      axisMap[key] = {axisId: xAxisID};
    });
    helpers.each(y, key => {
      axisMap[key] = {axisId: yAxisID};
    });
    return axisMap;
  }
  const cancelAnimFrame = (function() {
    if (typeof window === 'undefined') {
      return helpers.noop;
    }
    return window.cancelAnimationFrame;
  }());
  function startFrameRefreshTimer(context, func) {
    if (!context.frameRequestID) {
      const refresh = () => {
        const nextRefresh = context.nextRefresh || 0;
        const now = Date.now();
        if (nextRefresh <= now) {
          const newFrameRate = helpers.callback(func);
          const frameDuration = 1000 / (Math.max(newFrameRate, 0) || 30);
          const newNextRefresh = context.nextRefresh + frameDuration || 0;
          context.nextRefresh = newNextRefresh > now ? newNextRefresh : now + frameDuration;
        }
        context.frameRequestID = helpers.requestAnimFrame.call(window, refresh);
      };
      context.frameRequestID = helpers.requestAnimFrame.call(window, refresh);
    }
  }
  function stopFrameRefreshTimer(context) {
    const frameRequestID = context.frameRequestID;
    if (frameRequestID) {
      cancelAnimFrame.call(window, frameRequestID);
      delete context.frameRequestID;
    }
  }
  function stopDataRefreshTimer(context) {
    const refreshTimerID = context.refreshTimerID;
    if (refreshTimerID) {
      clearInterval(refreshTimerID);
      delete context.refreshTimerID;
      delete context.refreshInterval;
    }
  }
  function startDataRefreshTimer(context, func, interval) {
    if (!context.refreshTimerID) {
      context.refreshTimerID = setInterval(() => {
        const newInterval = helpers.callback(func);
        if (context.refreshInterval !== newInterval && !isNaN(newInterval)) {
          stopDataRefreshTimer(context);
          startDataRefreshTimer(context, func, newInterval);
        }
      }, interval || 0);
      context.refreshInterval = interval || 0;
    }
  }
  
  function scaleValue(scale, value, fallback) {
    value = typeof value === 'number' ? value : scale.parse(value);
    return helpers.isFinite(value) ?
      {value: scale.getPixelForValue(value), transitionable: true} :
      {value: fallback};
  }
  function updateBoxAnnotation(element, chart, options) {
    const {scales, chartArea} = chart;
    const {xScaleID, yScaleID, xMin, xMax, yMin, yMax} = options;
    const xScale = scales[xScaleID];
    const yScale = scales[yScaleID];
    const {top, left, bottom, right} = chartArea;
    const streaming = element.$streaming = {};
    if (xScale) {
      const min = scaleValue(xScale, xMin, left);
      const max = scaleValue(xScale, xMax, right);
      const reverse = min.value > max.value;
      if (min.transitionable) {
        streaming[reverse ? 'x2' : 'x'] = {axisId: xScaleID};
      }
      if (max.transitionable) {
        streaming[reverse ? 'x' : 'x2'] = {axisId: xScaleID};
      }
      if (min.transitionable !== max.transitionable) {
        streaming.width = {axisId: xScaleID, reverse: min.transitionable};
      }
    }
    if (yScale) {
      const min = scaleValue(yScale, yMin, top);
      const max = scaleValue(yScale, yMax, bottom);
      const reverse = min.value > max.value;
      if (min.transitionable) {
        streaming[reverse ? 'y2' : 'y'] = {axisId: yScaleID};
      }
      if (max.transitionable) {
        streaming[reverse ? 'y' : 'y2'] = {axisId: yScaleID};
      }
      if (min.transitionable !== max.transitionable) {
        streaming.height = {axisId: yScaleID, reverse: min.transitionable};
      }
    }
  }
  function updateLineAnnotation(element, chart, options) {
    const {scales, chartArea} = chart;
    const {scaleID, value} = options;
    const scale = scales[scaleID];
    const {top, left, bottom, right} = chartArea;
    const streaming = element.$streaming = {};
    if (scale) {
      const isHorizontal = scale.isHorizontal();
      const pixel = scaleValue(scale, value);
      if (pixel.transitionable) {
        streaming[isHorizontal ? 'x' : 'y'] = {axisId: scaleID};
        streaming[isHorizontal ? 'x2' : 'y2'] = {axisId: scaleID};
      }
      return isHorizontal ? {top, bottom} : {left, right};
    }
    const {xScaleID, yScaleID, xMin, xMax, yMin, yMax} = options;
    const xScale = scales[xScaleID];
    const yScale = scales[yScaleID];
    const clip = {};
    if (xScale) {
      const min = scaleValue(xScale, xMin);
      const max = scaleValue(xScale, xMax);
      if (min.transitionable) {
        streaming.x = {axisId: xScaleID};
      } else {
        clip.left = left;
      }
      if (max.transitionable) {
        streaming.x2 = {axisId: xScaleID};
      } else {
        clip.right = right;
      }
    }
    if (yScale) {
      const min = scaleValue(yScale, yMin);
      const max = scaleValue(yScale, yMax);
      if (min.transitionable) {
        streaming.y = {axisId: yScaleID};
      } else {
        clip.top = top;
      }
      if (max.transitionable) {
        streaming.y2 = {axisId: yScaleID};
      } else {
        clip.bottom = bottom;
      }
    }
    return clip;
  }
  function updatePointAnnotation(element, chart, options) {
    const scales = chart.scales;
    const {xScaleID, yScaleID, xValue, yValue} = options;
    const xScale = scales[xScaleID];
    const yScale = scales[yScaleID];
    const streaming = element.$streaming = {};
    if (xScale) {
      const x = scaleValue(xScale, xValue);
      if (x.transitionable) {
        streaming.x = {axisId: xScaleID};
      }
    }
    if (yScale) {
      const y = scaleValue(yScale, yValue);
      if (y.transitionable) {
        streaming.y = {axisId: yScaleID};
      }
    }
  }
  function initAnnotationPlugin() {
    const BoxAnnotation = chart_js.registry.getElement('boxAnnotation');
    const LineAnnotation = chart_js.registry.getElement('lineAnnotation');
    const PointAnnotation = chart_js.registry.getElement('pointAnnotation');
    const resolveBoxAnnotationProperties = BoxAnnotation.prototype.resolveElementProperties;
    const resolveLineAnnotationProperties = LineAnnotation.prototype.resolveElementProperties;
    const resolvePointAnnotationProperties = PointAnnotation.prototype.resolveElementProperties;
    BoxAnnotation.prototype.resolveElementProperties = function(chart, options) {
      updateBoxAnnotation(this, chart, options);
      return resolveBoxAnnotationProperties.call(this, chart, options);
    };
    LineAnnotation.prototype.resolveElementProperties = function(chart, options) {
      const chartArea = chart.chartArea;
      chart.chartArea = updateLineAnnotation(this, chart, options);
      const properties = resolveLineAnnotationProperties.call(this, chart, options);
      chart.chartArea = chartArea;
      return properties;
    };
    PointAnnotation.prototype.resolveElementProperties = function(chart, options) {
      updatePointAnnotation(this, chart, options);
      return resolvePointAnnotationProperties.call(this, chart, options);
    };
  }
  function attachChart$1(plugin, chart) {
    const streaming = chart.$streaming;
    if (streaming.annotationPlugin !== plugin) {
      const afterUpdate = plugin.afterUpdate;
      initAnnotationPlugin();
      streaming.annotationPlugin = plugin;
      plugin.afterUpdate = (_chart, args, options) => {
        const mode = args.mode;
        const animationOpts = options.animation;
        if (mode === 'quiet') {
          options.animation = false;
        }
        afterUpdate.call(this, _chart, args, options);
        if (mode === 'quiet') {
          options.animation = animationOpts;
        }
      };
    }
  }
  function getElements(chart) {
    const plugin = chart.$streaming.annotationPlugin;
    if (plugin) {
      const state = plugin._getState(chart);
      return state && state.elements || [];
    }
    return [];
  }
  function detachChart$1(chart) {
    delete chart.$streaming.annotationPlugin;
  }
  
  const transitionKeys$1 = {x: ['x', 'caretX'], y: ['y', 'caretY']};
  function update$1(...args) {
    const me = this;
    const element = me.getActiveElements()[0];
    if (element) {
      const meta = me._chart.getDatasetMeta(element.datasetIndex);
      me.$streaming = getAxisMap(me, transitionKeys$1, meta);
    } else {
      me.$streaming = {};
    }
    me.constructor.prototype.update.call(me, ...args);
  }
  
  const chartStates = new WeakMap();
  function getState(chart) {
    let state = chartStates.get(chart);
    if (!state) {
      state = {originalScaleOptions: {}};
      chartStates.set(chart, state);
    }
    return state;
  }
  function removeState(chart) {
    chartStates.delete(chart);
  }
  function storeOriginalScaleOptions(chart) {
    const {originalScaleOptions} = getState(chart);
    const scales = chart.scales;
    helpers.each(scales, scale => {
      const id = scale.id;
      if (!originalScaleOptions[id]) {
        originalScaleOptions[id] = {
          duration: resolveOption(scale, 'duration'),
          delay: resolveOption(scale, 'delay')
        };
      }
    });
    helpers.each(originalScaleOptions, (opt, key) => {
      if (!scales[key]) {
        delete originalScaleOptions[key];
      }
    });
    return originalScaleOptions;
  }
  function zoomRealTimeScale(scale, zoom, center, limits) {
    const {chart, axis} = scale;
    const {minDuration = 0, maxDuration = Infinity, minDelay = -Infinity, maxDelay = Infinity} = limits && limits[axis] || {};
    const realtimeOpts = scale.options.realtime;
    const duration = resolveOption(scale, 'duration');
    const delay = resolveOption(scale, 'delay');
    const newDuration = clamp(duration * (2 - zoom), minDuration, maxDuration);
    let maxPercent, newDelay;
    storeOriginalScaleOptions(chart);
    if (scale.isHorizontal()) {
      maxPercent = (scale.right - center.x) / (scale.right - scale.left);
    } else {
      maxPercent = (scale.bottom - center.y) / (scale.bottom - scale.top);
    }
    newDelay = delay + maxPercent * (duration - newDuration);
    realtimeOpts.duration = newDuration;
    realtimeOpts.delay = clamp(newDelay, minDelay, maxDelay);
    return newDuration !== scale.max - scale.min;
  }
  function panRealTimeScale(scale, delta, limits) {
    const {chart, axis} = scale;
    const {minDelay = -Infinity, maxDelay = Infinity} = limits && limits[axis] || {};
    const delay = resolveOption(scale, 'delay');
    const newDelay = delay + (scale.getValueForPixel(delta) - scale.getValueForPixel(0));
    storeOriginalScaleOptions(chart);
    scale.options.realtime.delay = clamp(newDelay, minDelay, maxDelay);
    return true;
  }
  function resetRealTimeScaleOptions(chart) {
    const originalScaleOptions = storeOriginalScaleOptions(chart);
    helpers.each(chart.scales, scale => {
      const realtimeOptions = scale.options.realtime;
      if (realtimeOptions) {
        const original = originalScaleOptions[scale.id];
        if (original) {
          realtimeOptions.duration = original.duration;
          realtimeOptions.delay = original.delay;
        } else {
          delete realtimeOptions.duration;
          delete realtimeOptions.delay;
        }
      }
    });
  }
  function initZoomPlugin(plugin) {
    plugin.zoomFunctions.realtime = zoomRealTimeScale;
    plugin.panFunctions.realtime = panRealTimeScale;
  }
  function attachChart(plugin, chart) {
    const streaming = chart.$streaming;
    if (streaming.zoomPlugin !== plugin) {
      const resetZoom = streaming.resetZoom = chart.resetZoom;
      initZoomPlugin(plugin);
      chart.resetZoom = transition => {
        resetRealTimeScaleOptions(chart);
        resetZoom(transition);
      };
      streaming.zoomPlugin = plugin;
    }
  }
  function detachChart(chart) {
    const streaming = chart.$streaming;
    if (streaming.zoomPlugin) {
      chart.resetZoom = streaming.resetZoom;
      removeState(chart);
      delete streaming.resetZoom;
      delete streaming.zoomPlugin;
    }
  }
  
  const INTERVALS = {
    millisecond: {
      common: true,
      size: 1,
      steps: [1, 2, 5, 10, 20, 50, 100, 250, 500]
    },
    second: {
      common: true,
      size: 1000,
      steps: [1, 2, 5, 10, 15, 30]
    },
    minute: {
      common: true,
      size: 60000,
      steps: [1, 2, 5, 10, 15, 30]
    },
    hour: {
      common: true,
      size: 3600000,
      steps: [1, 2, 3, 6, 12]
    },
    day: {
      common: true,
      size: 86400000,
      steps: [1, 2, 5]
    },
    week: {
      common: false,
      size: 604800000,
      steps: [1, 2, 3, 4]
    },
    month: {
      common: true,
      size: 2.628e9,
      steps: [1, 2, 3]
    },
    quarter: {
      common: false,
      size: 7.884e9,
      steps: [1, 2, 3, 4]
    },
    year: {
      common: true,
      size: 3.154e10
    }
  };
  const UNITS = Object.keys(INTERVALS);
  function determineStepSize(min, max, unit, capacity) {
    const range = max - min;
    const {size: milliseconds, steps} = INTERVALS[unit];
    let factor;
    if (!steps) {
      return Math.ceil(range / (capacity * milliseconds));
    }
    for (let i = 0, ilen = steps.length; i < ilen; ++i) {
      factor = steps[i];
      if (Math.ceil(range / (milliseconds * factor)) <= capacity) {
        break;
      }
    }
    return factor;
  }
  function determineUnitForAutoTicks(minUnit, min, max, capacity) {
    const range = max - min;
    const ilen = UNITS.length;
    for (let i = UNITS.indexOf(minUnit); i < ilen - 1; ++i) {
      const {common, size, steps} = INTERVALS[UNITS[i]];
      const factor = steps ? steps[steps.length - 1] : Number.MAX_SAFE_INTEGER;
      if (common && Math.ceil(range / (factor * size)) <= capacity) {
        return UNITS[i];
      }
    }
    return UNITS[ilen - 1];
  }
  function determineMajorUnit(unit) {
    for (let i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i) {
      if (INTERVALS[UNITS[i]].common) {
        return UNITS[i];
      }
    }
  }
  function addTick(ticks, time, timestamps) {
    if (!timestamps) {
      ticks[time] = true;
    } else if (timestamps.length) {
      const {lo, hi} = helpers._lookup(timestamps, time);
      const timestamp = timestamps[lo] >= time ? timestamps[lo] : timestamps[hi];
      ticks[timestamp] = true;
    }
  }
  const datasetPropertyKeys = [
    'pointBackgroundColor',
    'pointBorderColor',
    'pointBorderWidth',
    'pointRadius',
    'pointRotation',
    'pointStyle',
    'pointHitRadius',
    'pointHoverBackgroundColor',
    'pointHoverBorderColor',
    'pointHoverBorderWidth',
    'pointHoverRadius',
    'backgroundColor',
    'borderColor',
    'borderSkipped',
    'borderWidth',
    'hoverBackgroundColor',
    'hoverBorderColor',
    'hoverBorderWidth',
    'hoverRadius',
    'hitRadius',
    'radius',
    'rotation'
  ];
  function clean(scale) {
    const {chart, id, max} = scale;
    const duration = resolveOption(scale, 'duration');
    const delay = resolveOption(scale, 'delay');
    const ttl = resolveOption(scale, 'ttl');
    const pause = resolveOption(scale, 'pause');
    const min = Date.now() - (isNaN(ttl) ? duration + delay : ttl);
    let i, start, count, removalRange;
    helpers.each(chart.data.datasets, (dataset, datasetIndex) => {
      const meta = chart.getDatasetMeta(datasetIndex);
      const axis = id === meta.xAxisID && 'x' || id === meta.yAxisID && 'y';
      if (axis) {
        const controller = meta.controller;
        const data = dataset.data;
        const length = data.length;
        if (pause) {
          for (i = 0; i < length; ++i) {
            if (!(controller.getParsed(i)[axis] < max)) {
              break;
            }
          }
          start = i + 2;
        } else {
          start = 0;
        }
        for (i = start; i < length; ++i) {
          if (!(controller.getParsed(i)[axis] <= min)) {
            break;
          }
        }
        count = i - start;
        if (isNaN(ttl)) {
          count = Math.max(count - 2, 0);
        }
        data.splice(start, count);
        helpers.each(datasetPropertyKeys, key => {
          if (helpers.isArray(dataset[key])) {
            dataset[key].splice(start, count);
          }
        });
        helpers.each(dataset.datalabels, value => {
          if (helpers.isArray(value)) {
            value.splice(start, count);
          }
        });
        if (typeof data[0] !== 'object') {
          removalRange = {
            start: start,
            count: count
          };
        }
        helpers.each(chart._active, (item, index) => {
          if (item.datasetIndex === datasetIndex && item.index >= start) {
            if (item.index >= start + count) {
              item.index -= count;
            } else {
              chart._active.splice(index, 1);
            }
          }
        }, null, true);
      }
    });
    if (removalRange) {
      chart.data.labels.splice(removalRange.start, removalRange.count);
    }
  }
  function transition(element, id, translate) {
    const animations = element.$animations || {};
    helpers.each(element.$streaming, (item, key) => {
      if (item.axisId === id) {
        const delta = item.reverse ? -translate : translate;
        const animation = animations[key];
        if (helpers.isFinite(element[key])) {
          element[key] -= delta;
        }
        if (animation) {
          animation._from -= delta;
          animation._to -= delta;
        }
      }
    });
  }
  function scroll(scale) {
    const {chart, id, $realtime: realtime} = scale;
    const duration = resolveOption(scale, 'duration');
    const delay = resolveOption(scale, 'delay');
    const isHorizontal = scale.isHorizontal();
    const length = isHorizontal ? scale.width : scale.height;
    const now = Date.now();
    const tooltip = chart.tooltip;
    const annotations = getElements(chart);
    let offset = length * (now - realtime.head) / duration;
    if (isHorizontal === !!scale.options.reverse) {
      offset = -offset;
    }
    helpers.each(chart.data.datasets, (dataset, datasetIndex) => {
      const meta = chart.getDatasetMeta(datasetIndex);
      const {data: elements = [], dataset: element} = meta;
      for (let i = 0, ilen = elements.length; i < ilen; ++i) {
        transition(elements[i], id, offset);
      }
      if (element) {
        transition(element, id, offset);
        delete element._path;
      }
    });
    for (let i = 0, ilen = annotations.length; i < ilen; ++i) {
      transition(annotations[i], id, offset);
    }
    if (tooltip) {
      transition(tooltip, id, offset);
    }
    scale.max = now - delay;
    scale.min = scale.max - duration;
    realtime.head = now;
  }
  class RealTimeScale extends chart_js.TimeScale {
    constructor(props) {
      super(props);
      this.$realtime = this.$realtime || {};
    }
    init(scaleOpts, opts) {
      const me = this;
      super.init(scaleOpts, opts);
      startDataRefreshTimer(me.$realtime, () => {
        const chart = me.chart;
        const onRefresh = resolveOption(me, 'onRefresh');
        helpers.callback(onRefresh, [chart], me);
        clean(me);
        chart.update('quiet');
        return resolveOption(me, 'refresh');
      });
    }
    update(maxWidth, maxHeight, margins) {
      const me = this;
      const {$realtime: realtime, options} = me;
      const {bounds, offset, ticks: ticksOpts} = options;
      const {autoSkip, source, major: majorTicksOpts} = ticksOpts;
      const majorEnabled = majorTicksOpts.enabled;
      if (resolveOption(me, 'pause')) {
        stopFrameRefreshTimer(realtime);
      } else {
        if (!realtime.frameRequestID) {
          realtime.head = Date.now();
        }
        startFrameRefreshTimer(realtime, () => {
          const chart = me.chart;
          const streaming = chart.$streaming;
          scroll(me);
          if (streaming) {
            helpers.callback(streaming.render, [chart]);
          }
          return resolveOption(me, 'frameRate');
        });
      }
      options.bounds = undefined;
      options.offset = false;
      ticksOpts.autoSkip = false;
      ticksOpts.source = source === 'auto' ? '' : source;
      majorTicksOpts.enabled = true;
      super.update(maxWidth, maxHeight, margins);
      options.bounds = bounds;
      options.offset = offset;
      ticksOpts.autoSkip = autoSkip;
      ticksOpts.source = source;
      majorTicksOpts.enabled = majorEnabled;
    }
    buildTicks() {
      const me = this;
      const duration = resolveOption(me, 'duration');
      const delay = resolveOption(me, 'delay');
      const max = me.$realtime.head - delay;
      const min = max - duration;
      const maxArray = [1e15, max];
      const minArray = [-1e15, min];
      Object.defineProperty(me, 'min', {
        get: () => minArray.shift(),
        set: helpers.noop
      });
      Object.defineProperty(me, 'max', {
        get: () => maxArray.shift(),
        set: helpers.noop
      });
      const ticks = super.buildTicks();
      delete me.min;
      delete me.max;
      me.min = min;
      me.max = max;
      return ticks;
    }
    calculateLabelRotation() {
      const ticksOpts = this.options.ticks;
      const maxRotation = ticksOpts.maxRotation;
      ticksOpts.maxRotation = ticksOpts.minRotation || 0;
      super.calculateLabelRotation();
      ticksOpts.maxRotation = maxRotation;
    }
    fit() {
      const me = this;
      const options = me.options;
      super.fit();
      if (options.ticks.display && options.display && me.isHorizontal()) {
        me.paddingLeft = 3;
        me.paddingRight = 3;
        me._handleMargins();
      }
    }
    draw(chartArea) {
      const me = this;
      const {chart, ctx} = me;
      const area = me.isHorizontal() ?
        {
          left: chartArea.left,
          top: 0,
          right: chartArea.right,
          bottom: chart.height
        } : {
          left: 0,
          top: chartArea.top,
          right: chart.width,
          bottom: chartArea.bottom
        };
      me._gridLineItems = null;
      me._labelItems = null;
      helpers.clipArea(ctx, area);
      super.draw(chartArea);
      helpers.unclipArea(ctx);
    }
    destroy() {
      const realtime = this.$realtime;
      stopFrameRefreshTimer(realtime);
      stopDataRefreshTimer(realtime);
    }
    _generate() {
      const me = this;
      const adapter = me._adapter;
      const duration = resolveOption(me, 'duration');
      const delay = resolveOption(me, 'delay');
      const refresh = resolveOption(me, 'refresh');
      const max = me.$realtime.head - delay;
      const min = max - duration;
      const capacity = me._getLabelCapacity(min);
      const {time: timeOpts, ticks: ticksOpts} = me.options;
      const minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, capacity);
      const major = determineMajorUnit(minor);
      const stepSize = timeOpts.stepSize || determineStepSize(min, max, minor, capacity);
      const weekday = minor === 'week' ? timeOpts.isoWeekday : false;
      const majorTicksEnabled = ticksOpts.major.enabled;
      const hasWeekday = helpers.isNumber(weekday) || weekday === true;
      const interval = INTERVALS[minor];
      const ticks = {};
      let first = min;
      let time, count;
      if (hasWeekday) {
        first = +adapter.startOf(first, 'isoWeek', weekday);
      }
      first = +adapter.startOf(first, hasWeekday ? 'day' : minor);
      if (adapter.diff(max, min, minor) > 100000 * stepSize) {
        throw new Error(min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor);
      }
      time = first;
      if (majorTicksEnabled && major && !hasWeekday && !timeOpts.round) {
        time = +adapter.startOf(time, major);
        time = +adapter.add(time, ~~((first - time) / (interval.size * stepSize)) * stepSize, minor);
      }
      const timestamps = ticksOpts.source === 'data' && me.getDataTimestamps();
      for (count = 0; time < max + refresh; time = +adapter.add(time, stepSize, minor), count++) {
        addTick(ticks, time, timestamps);
      }
      if (time === max + refresh || count === 1) {
        addTick(ticks, time, timestamps);
      }
      return Object.keys(ticks).sort((a, b) => a - b).map(x => +x);
    }
  }
  RealTimeScale.id = 'realtime';
  RealTimeScale.defaults = {
    bounds: 'data',
    adapters: {},
    time: {
      parser: false,
      unit: false,
      round: false,
      isoWeekday: false,
      minUnit: 'millisecond',
      displayFormats: {}
    },
    realtime: {},
    ticks: {
      autoSkip: false,
      source: 'auto',
      major: {
        enabled: true
      }
    }
  };
  chart_js.defaults.describe('scale.realtime', {
    _scriptable: name => name !== 'onRefresh'
  });
  
  var version = "2.0.0-beta.2";
  
  chart_js.defaults.set('transitions', {
    quiet: {
      animation: {
        duration: 0
      }
    }
  });
  const transitionKeys = {x: ['x', 'cp1x', 'cp2x'], y: ['y', 'cp1y', 'cp2y']};
  function update(mode) {
    const me = this;
    if (mode === 'quiet') {
      helpers.each(me.data.datasets, (dataset, datasetIndex) => {
        const controller = me.getDatasetMeta(datasetIndex).controller;
        controller._setStyle = function(element, index, _mode, active) {
          chart_js.Chart.DatasetController.prototype._setStyle.call(this, element, index, 'quiet', active);
        };
      });
    }
    chart_js.Chart.prototype.update.call(me, mode);
    if (mode === 'quiet') {
      helpers.each(me.data.datasets, (dataset, datasetIndex) => {
        delete me.getDatasetMeta(datasetIndex).controller._setStyle;
      });
    }
  }
  function render(chart) {
    const streaming = chart.$streaming;
    chart.render();
    if (streaming.lastMouseEvent) {
      setTimeout(() => {
        const lastMouseEvent = streaming.lastMouseEvent;
        if (lastMouseEvent) {
          chart._eventHandler(lastMouseEvent);
        }
      }, 0);
    }
  }
  var StreamingPlugin = {
    id: 'streaming',
    version,
    beforeInit(chart) {
      const streaming = chart.$streaming = chart.$streaming || {render};
      const canvas = streaming.canvas = chart.canvas;
      const mouseEventListener = streaming.mouseEventListener = event => {
        const pos = helpers.getRelativePosition(event, chart);
        streaming.lastMouseEvent = {
          type: 'mousemove',
          chart: chart,
          native: event,
          x: pos.x,
          y: pos.y
        };
      };
      canvas.addEventListener('mousedown', mouseEventListener);
      canvas.addEventListener('mouseup', mouseEventListener);
    },
    afterInit(chart) {
      const tooltip = chart.tooltip;
      chart.update = update;
      if (tooltip) {
        tooltip.update = update$1;
      }
    },
    beforeUpdate(chart) {
      const {scales, elements} = chart.options;
      helpers.each(scales, ({type}) => {
        if (type === 'realtime') {
          elements.line.capBezierPoints = false;
        }
      });
      try {
        const plugin = chart_js.registry.getPlugin('annotation');
        attachChart$1(plugin, chart);
      } catch (e) {
        detachChart$1(chart);
      }
      try {
        const plugin = chart_js.registry.getPlugin('zoom');
        attachChart(plugin, chart);
      } catch (e) {
        detachChart(chart);
      }
    },
    beforeDatasetUpdate(chart, args) {
      const {meta, mode} = args;
      if (mode === 'quiet') {
        const {controller, $animations} = meta;
        if ($animations && $animations.visible && $animations.visible._active) {
          controller.updateElement = helpers.noop;
          controller.updateSharedOptions = helpers.noop;
        }
      }
    },
    afterDatasetUpdate(chart, args) {
      const {meta, mode} = args;
      const {data: elements = [], dataset: element, controller} = meta;
      for (let i = 0, ilen = elements.length; i < ilen; ++i) {
        elements[i].$streaming = getAxisMap(elements[i], transitionKeys, meta);
      }
      if (element) {
        element.$streaming = getAxisMap(element, transitionKeys, meta);
      }
      if (mode === 'quiet') {
        delete controller.updateElement;
        delete controller.updateSharedOptions;
      }
    },
    beforeDatasetDraw(chart, args) {
      const {ctx, chartArea, width, height} = chart;
      const {xAxisID, yAxisID, controller} = args.meta;
      const area = {
        left: 0,
        top: 0,
        right: width,
        bottom: height
      };
      if (xAxisID && controller.getScaleForId(xAxisID) instanceof RealTimeScale) {
        area.left = chartArea.left;
        area.right = chartArea.right;
      }
      if (yAxisID && controller.getScaleForId(yAxisID) instanceof RealTimeScale) {
        area.top = chartArea.top;
        area.bottom = chartArea.bottom;
      }
      helpers.clipArea(ctx, area);
    },
    afterDatasetDraw(chart) {
      helpers.unclipArea(chart.ctx);
    },
    beforeEvent(chart, args) {
      const streaming = chart.$streaming;
      const event = args.event;
      if (event.type === 'mousemove') {
        streaming.lastMouseEvent = event;
      } else if (event.type === 'mouseout') {
        delete streaming.lastMouseEvent;
      }
    },
    destroy(chart) {
      const {scales, $streaming: streaming, tooltip} = chart;
      const {canvas, mouseEventListener} = streaming;
      delete chart.update;
      if (tooltip) {
        delete tooltip.update;
      }
      canvas.removeEventListener('mousedown', mouseEventListener);
      canvas.removeEventListener('mouseup', mouseEventListener);
      helpers.each(scales, scale => {
        if (scale instanceof RealTimeScale) {
          scale.destroy();
        }
      });
    },
    defaults: {
      duration: 10000,
      delay: 0,
      frameRate: 30,
      refresh: 1000,
      onRefresh: null,
      pause: false,
      ttl: undefined
    },
    descriptors: {
      _scriptable: name => name !== 'onRefresh'
    }
  };
  
  chart_js.Chart.register(StreamingPlugin, RealTimeScale);
  
  return StreamingPlugin;
  
  })));
  