// Derived from Chromium WebRTC Internals Dashboard - see Acknowledgements for full license details // The maximum number of data points buffered for each stats. Old data points // will be shifted out when the buffer is full. export const MAX_STATS_DATA_POINT_BUFFER_SIZE = 1000; /** * A TimelineDataSeries collects an ordered series of (time, value) pairs, * and converts them to graph points. It also keeps track of its color and * current visibility state. * It keeps MAX_STATS_DATA_POINT_BUFFER_SIZE data points at most. Old data * points will be dropped when it reaches this size. */ export class TimelineDataSeries { constructor(statsType) { // List of DataPoints in chronological order. this.dataPoints_ = []; // Default color. Should always be overridden prior to display. this.color_ = 'red'; // Whether or not the data series should be drawn. this.isVisible_ = true; this.cacheStartTime_ = null; this.cacheStepSize_ = 0; this.cacheValues_ = []; this.statsType_ = statsType; } /** * @override */ toJSON() { if (this.dataPoints_.length < 1) { return {}; } const values = []; for (let i = 0; i < this.dataPoints_.length; ++i) { values.push(this.dataPoints_[i].value); } return { startTime: this.dataPoints_[0].time, endTime: this.dataPoints_[this.dataPoints_.length - 1].time, statsType: this.statsType_, values: JSON.stringify(values), }; } /** * Adds a DataPoint to |this| with the specified time and value. * DataPoints are assumed to be received in chronological order. */ addPoint(timeTicks, value) { const time = new Date(timeTicks); this.dataPoints_.push(new DataPoint(time, value)); if (this.dataPoints_.length > MAX_STATS_DATA_POINT_BUFFER_SIZE) { this.dataPoints_.shift(); } } isVisible() { return this.isVisible_; } show(isVisible) { this.isVisible_ = isVisible; } getColor() { return this.color_; } setColor(color) { this.color_ = color; } getCount() { return this.dataPoints_.length; } /** * Returns a list containing the values of the data series at |count| * points, starting at |startTime|, and |stepSize| milliseconds apart. * Caches values, so showing/hiding individual data series is fast. */ getValues(startTime, stepSize, count) { // Use cached values, if we can. if (this.cacheStartTime_ === startTime && this.cacheStepSize_ === stepSize && this.cacheValues_.length === count) { return this.cacheValues_; } // Do all the work. this.cacheValues_ = this.getValuesInternal_(startTime, stepSize, count); this.cacheStartTime_ = startTime; this.cacheStepSize_ = stepSize; return this.cacheValues_; } /** * Returns the cached |values| in the specified time period. */ getValuesInternal_(startTime, stepSize, count) { const values = []; let nextPoint = 0; let currentValue = 0; let time = startTime; for (let i = 0; i < count; ++i) { while (nextPoint < this.dataPoints_.length && this.dataPoints_[nextPoint].time < time) { currentValue = this.dataPoints_[nextPoint].value; ++nextPoint; } values[i] = currentValue; time += stepSize; } return values; } } /** * A single point in a data series. Each point has a time, in the form of * milliseconds since the Unix epoch, and a numeric value. */ class DataPoint { constructor(time, value) { this.time = time; this.value = value; } }