%PDF- %PDF-
Direktori : /backups/router/usr/local/opnsense/www/js/ |
Current File : //backups/router/usr/local/opnsense/www/js/chartjs-plugin-streaming.js |
/*! * chartjs-plugin-streaming v2.0.0 * 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) { const point = controller.getParsed(i); if (point && !(point[axis] < max)) { break; } } start = i + 2; } else { start = 0; } for (i = start; i < length; ++i) { const point = controller.getParsed(i); if (!point || !(point[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"; 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.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) { chart.update = update; }, beforeUpdate(chart) { const {scales, elements} = chart.options; const tooltip = chart.tooltip; helpers.each(scales, ({type}) => { if (type === 'realtime') { elements.line.capBezierPoints = false; } }); if (tooltip) { tooltip.update = update$1; } 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' } }; const registerables = [StreamingPlugin, RealTimeScale]; chart_js.Chart.register(registerables); return registerables; })));