mirror of
https://github.com/nasa/openmct.git
synced 2024-12-20 21:53:08 +00:00
[Code Style] Begin using prototypes in Plot bundle
WTD-1482
This commit is contained in:
parent
175490e1f7
commit
18bc7d3637
@ -62,26 +62,22 @@ define(
|
||||
|
||||
(metadatas || []).forEach(buildOptionsForMetadata);
|
||||
|
||||
// Plot axis will be used directly from the Angular
|
||||
// template, so expose properties directly to facilitate
|
||||
// two-way data binding (for drop-down menus)
|
||||
return {
|
||||
/**
|
||||
* The set of options applicable for this axis;
|
||||
* an array of objects, where each object contains a
|
||||
* "key" field and a "name" field (for machine- and
|
||||
* human-readable names respectively)
|
||||
* @memberof platform/features/plot.PlotAxis#
|
||||
*/
|
||||
options: options,
|
||||
/**
|
||||
* The currently chosen option for this axis. An
|
||||
* initial value is provided; this will be updated
|
||||
* directly form the plot template.
|
||||
* @memberof platform/features/plot.PlotAxis#
|
||||
*/
|
||||
active: options[0] || defaultValue
|
||||
};
|
||||
/**
|
||||
* The currently chosen option for this axis. An
|
||||
* initial value is provided; this will be updated
|
||||
* directly form the plot template.
|
||||
* @memberof platform/features/plot.PlotAxis#
|
||||
*/
|
||||
this.active = options[0] || defaultValue;
|
||||
|
||||
/**
|
||||
* The set of options applicable for this axis;
|
||||
* an array of objects, where each object contains a
|
||||
* "key" field and a "name" field (for machine- and
|
||||
* human-readable names respectively)
|
||||
* @memberof platform/features/plot.PlotAxis#
|
||||
*/
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
return PlotAxis;
|
||||
|
@ -21,26 +21,32 @@
|
||||
*****************************************************************************/
|
||||
/*global define,Float32Array*/
|
||||
|
||||
/**
|
||||
* Prepares data to be rendered in a GL Plot. Handles
|
||||
* the conversion from data API to displayable buffers.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
'use strict';
|
||||
|
||||
var MAX_POINTS = 86400,
|
||||
INITIAL_SIZE = 675; // 1/128 of MAX_POINTS
|
||||
|
||||
/**
|
||||
* Tracks the limit state of telemetry objects being plotted.
|
||||
* @memberof platform/features/plot
|
||||
* @constructor
|
||||
* @param {TelemetryHandle} handle the handle to telemetry access
|
||||
* @param {platform/telemetry.TelemetryHandle} handle the handle
|
||||
* to telemetry access
|
||||
* @param {string} range the key to use when looking up range values
|
||||
*/
|
||||
function PlotLimitTracker(handle, range) {
|
||||
var legendClasses = {};
|
||||
this.handle = handle;
|
||||
this.range = range;
|
||||
this.legendClasses = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Update limit states to reflect the latest data.
|
||||
*/
|
||||
PlotLimitTracker.prototype.update = function () {
|
||||
var legendClasses = {},
|
||||
range = this.range,
|
||||
handle = this.handle;
|
||||
|
||||
function updateLimit(telemetryObject) {
|
||||
var limit = telemetryObject.getCapability('limit'),
|
||||
@ -52,17 +58,21 @@ define(
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
update: function () {
|
||||
legendClasses = {};
|
||||
handle.getTelemetryObjects().forEach(updateLimit);
|
||||
},
|
||||
getLegendClass: function (domainObject) {
|
||||
var id = domainObject && domainObject.getId();
|
||||
return id && legendClasses[id];
|
||||
}
|
||||
};
|
||||
}
|
||||
handle.getTelemetryObjects().forEach(updateLimit);
|
||||
|
||||
this.legendClasses = legendClasses;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the CSS class associated with any limit violations for this
|
||||
* telemetry object.
|
||||
* @param {DomainObject} domainObject the telemetry object to check
|
||||
* @returns {string} the CSS class name, if any
|
||||
*/
|
||||
PlotLimitTracker.prototype.getLegendClass = function (domainObject) {
|
||||
var id = domainObject && domainObject.getId();
|
||||
return id && this.legendClasses[id];
|
||||
};
|
||||
|
||||
return PlotLimitTracker;
|
||||
|
||||
|
@ -33,6 +33,47 @@ define(
|
||||
* @constructor
|
||||
*/
|
||||
function PlotLine(buffer) {
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a point to this plot line.
|
||||
* @param {number} domainValue the domain value
|
||||
* @param {number} rangeValue the range value
|
||||
*/
|
||||
PlotLine.prototype.addPoint = function (domainValue, rangeValue) {
|
||||
var buffer = this.buffer,
|
||||
index;
|
||||
|
||||
// Make sure we got real/useful values here...
|
||||
if (domainValue !== undefined && rangeValue !== undefined) {
|
||||
index = buffer.findInsertionIndex(domainValue);
|
||||
|
||||
// Already in the buffer? Skip insertion
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Insert the point
|
||||
if (!buffer.insertPoint(domainValue, rangeValue, index)) {
|
||||
// If insertion failed, trim from the beginning...
|
||||
buffer.trim(1);
|
||||
// ...and try again.
|
||||
buffer.insertPoint(domainValue, rangeValue, index);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a series of telemetry data to this plot line.
|
||||
* @param {TelemetrySeries} series the data series
|
||||
* @param {string} [domain] the key indicating which domain
|
||||
* to use when looking up data from this series
|
||||
* @param {string} [range] the key indicating which range
|
||||
* to use when looking up data from this series
|
||||
*/
|
||||
PlotLine.prototype.addSeries = function (series, domain, range) {
|
||||
var buffer = this.buffer;
|
||||
|
||||
// Insert a time-windowed data series into the buffer
|
||||
function insertSeriesWindow(seriesWindow) {
|
||||
@ -60,62 +101,19 @@ define(
|
||||
}
|
||||
}
|
||||
|
||||
function createWindow(series, domain, range) {
|
||||
return new PlotSeriesWindow(
|
||||
series,
|
||||
domain,
|
||||
range,
|
||||
0,
|
||||
series.getPointCount()
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Add a point to this plot line.
|
||||
* @param {number} domainValue the domain value
|
||||
* @param {number} rangeValue the range value
|
||||
* @memberof platform/features/plot.PlotLine
|
||||
*/
|
||||
addPoint: function (domainValue, rangeValue) {
|
||||
var index;
|
||||
// Make sure we got real/useful values here...
|
||||
if (domainValue !== undefined && rangeValue !== undefined) {
|
||||
index = buffer.findInsertionIndex(domainValue);
|
||||
|
||||
// Already in the buffer? Skip insertion
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Insert the point
|
||||
if (!buffer.insertPoint(domainValue, rangeValue, index)) {
|
||||
// If insertion failed, trim from the beginning...
|
||||
buffer.trim(1);
|
||||
// ...and try again.
|
||||
buffer.insertPoint(domainValue, rangeValue, index);
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Add a series of telemetry data to this plot line.
|
||||
* @param {TelemetrySeries} series the data series
|
||||
* @param {string} [domain] the key indicating which domain
|
||||
* to use when looking up data from this series
|
||||
* @param {string} [range] the key indicating which range
|
||||
* to use when looking up data from this series
|
||||
* @memberof platform/features/plot.PlotLine
|
||||
*/
|
||||
addSeries: function (series, domain, range) {
|
||||
// Should try to add via insertion if a
|
||||
// clear insertion point is available;
|
||||
// if not, should split and add each half.
|
||||
// Insertion operation also needs to factor out
|
||||
// redundant timestamps, for overlapping data
|
||||
insertSeriesWindow(createWindow(series, domain, range));
|
||||
}
|
||||
};
|
||||
}
|
||||
// Should try to add via insertion if a
|
||||
// clear insertion point is available;
|
||||
// if not, should split and add each half.
|
||||
// Insertion operation also needs to factor out
|
||||
// redundant timestamps, for overlapping data
|
||||
insertSeriesWindow(new PlotSeriesWindow(
|
||||
series,
|
||||
domain,
|
||||
range,
|
||||
0,
|
||||
series.getPointCount()
|
||||
));
|
||||
};
|
||||
|
||||
return PlotLine;
|
||||
}
|
||||
|
@ -35,236 +35,235 @@ define(
|
||||
* @constructor
|
||||
*/
|
||||
function PlotLineBuffer(domainOffset, initialSize, maxSize) {
|
||||
var buffer = new Float32Array(initialSize * 2),
|
||||
rangeExtrema = [ Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY ],
|
||||
length = 0;
|
||||
|
||||
// Binary search for an insertion index
|
||||
function binSearch(value, min, max) {
|
||||
var mid = Math.floor((min + max) / 2),
|
||||
found = buffer[mid * 2];
|
||||
|
||||
// On collisions, insert at same index
|
||||
if (found === value) {
|
||||
return mid;
|
||||
}
|
||||
|
||||
// Otherwise, if we're down to a single index,
|
||||
// we've found our insertion point
|
||||
if (min >= max) {
|
||||
// Compare the found timestamp with the search
|
||||
// value to decide if we'll insert after or before.
|
||||
return min + ((found < value) ? 1 : 0);
|
||||
}
|
||||
|
||||
// Finally, do the recursive step
|
||||
if (found < value) {
|
||||
return binSearch(value, mid + 1, max);
|
||||
} else {
|
||||
return binSearch(value, min, mid - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Increase the size of the buffer
|
||||
function doubleBufferSize() {
|
||||
var sz = Math.min(maxSize * 2, buffer.length * 2),
|
||||
canDouble = sz > buffer.length,
|
||||
doubled = canDouble && new Float32Array(sz);
|
||||
|
||||
if (canDouble) {
|
||||
doubled.set(buffer); // Copy contents of original
|
||||
buffer = doubled;
|
||||
}
|
||||
|
||||
return canDouble;
|
||||
}
|
||||
|
||||
// Decrease the size of the buffer
|
||||
function halveBufferSize() {
|
||||
var sz = Math.max(initialSize * 2, buffer.length / 2),
|
||||
canHalve = sz < buffer.length;
|
||||
|
||||
if (canHalve) {
|
||||
buffer = new Float32Array(buffer.subarray(0, sz));
|
||||
}
|
||||
|
||||
return canHalve;
|
||||
}
|
||||
|
||||
// Set a value in the buffer
|
||||
function setValue(index, domainValue, rangeValue) {
|
||||
buffer[index * 2] = domainValue - domainOffset;
|
||||
buffer[index * 2 + 1] = rangeValue;
|
||||
// Track min/max of range values (min/max for
|
||||
// domain values can be read directly from buffer)
|
||||
rangeExtrema[0] = Math.min(rangeExtrema[0], rangeValue);
|
||||
rangeExtrema[1] = Math.max(rangeExtrema[1], rangeValue);
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Get the WebGL-displayable buffer of points to plot.
|
||||
* @returns {Float32Array} displayable buffer for this line
|
||||
* @memberof platform/features/plot.PlotLineBuffer#
|
||||
*/
|
||||
getBuffer: function () {
|
||||
return buffer;
|
||||
},
|
||||
/**
|
||||
* Get the number of points stored in this buffer.
|
||||
* @returns {number} the number of points stored
|
||||
* @memberof platform/features/plot.PlotLineBuffer#
|
||||
*/
|
||||
getLength: function () {
|
||||
return length;
|
||||
},
|
||||
/**
|
||||
* Get the min/max range values that are currently in this
|
||||
* buffer. Unlike range extrema, these will change as the
|
||||
* buffer gets trimmed.
|
||||
* @returns {number[]} min, max domain values
|
||||
* @memberof platform/features/plot.PlotLineBuffer#
|
||||
*/
|
||||
getDomainExtrema: function () {
|
||||
// Since these are ordered in the buffer, assume
|
||||
// these are the values at the first and last index
|
||||
return [
|
||||
buffer[0] + domainOffset,
|
||||
buffer[length * 2 - 2] + domainOffset
|
||||
];
|
||||
},
|
||||
/**
|
||||
* Get the min/max range values that have been observed for this
|
||||
* buffer. Note that these values may have been trimmed out at
|
||||
* some point.
|
||||
* @returns {number[]} min, max range values
|
||||
* @memberof platform/features/plot.PlotLineBuffer#
|
||||
*/
|
||||
getRangeExtrema: function () {
|
||||
return rangeExtrema;
|
||||
},
|
||||
/**
|
||||
* Remove values from this buffer.
|
||||
* Normally, values are removed from the start
|
||||
* of the buffer; a truthy value in the second argument
|
||||
* will cause values to be removed from the end.
|
||||
* @param {number} count number of values to remove
|
||||
* @param {boolean} [fromEnd] true if the most recent
|
||||
* values should be removed
|
||||
* @memberof platform/features/plot.PlotLineBuffer#
|
||||
*/
|
||||
trim: function (count, fromEnd) {
|
||||
// If we're removing values from the start...
|
||||
if (!fromEnd) {
|
||||
// ...do so by shifting buffer contents over
|
||||
buffer.set(buffer.subarray(2 * count));
|
||||
}
|
||||
// Reduce used buffer size accordingly
|
||||
length -= count;
|
||||
// Finally, if less than half of the buffer is being
|
||||
// used, free up some memory.
|
||||
if (length < buffer.length / 4) {
|
||||
halveBufferSize();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Insert data from the provided series at the specified
|
||||
* index. If this would exceed the buffer's maximum capacity,
|
||||
* this operation fails and the buffer is unchanged.
|
||||
* @param {TelemetrySeries} series the series to insert
|
||||
* @param {number} index the index at which to insert this
|
||||
* series
|
||||
* @returns {boolean} true if insertion succeeded; otherwise
|
||||
* false
|
||||
* @memberof platform/features/plot.PlotLineBuffer#
|
||||
*/
|
||||
insert: function (series, index) {
|
||||
var sz = series.getPointCount(),
|
||||
i;
|
||||
|
||||
// Don't allow append after the end; that doesn't make sense
|
||||
index = Math.min(index, length);
|
||||
|
||||
// Resize if necessary
|
||||
while (sz > ((buffer.length / 2) - length)) {
|
||||
if (!doubleBufferSize()) {
|
||||
// Can't make room for this, insertion fails
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Shift data over if necessary
|
||||
if (index < length) {
|
||||
buffer.set(
|
||||
buffer.subarray(index * 2, length * 2),
|
||||
(index + sz) * 2
|
||||
);
|
||||
}
|
||||
|
||||
// Insert data into the set
|
||||
for (i = 0; i < sz; i += 1) {
|
||||
setValue(
|
||||
i + index,
|
||||
series.getDomainValue(i),
|
||||
series.getRangeValue(i)
|
||||
);
|
||||
}
|
||||
|
||||
// Increase the length
|
||||
length += sz;
|
||||
|
||||
// Indicate that insertion was successful
|
||||
return true;
|
||||
},
|
||||
/**
|
||||
* Append a single data point.
|
||||
* @memberof platform/features/plot.PlotLineBuffer#
|
||||
*/
|
||||
insertPoint: function (domainValue, rangeValue, index) {
|
||||
// Don't allow
|
||||
index = Math.min(length, index);
|
||||
|
||||
// Ensure there is space for this point
|
||||
if (length >= (buffer.length / 2)) {
|
||||
if (!doubleBufferSize()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Put the data in the buffer
|
||||
setValue(length, domainValue, rangeValue);
|
||||
|
||||
// Update length
|
||||
length += 1;
|
||||
|
||||
// Indicate that this was successful
|
||||
return true;
|
||||
},
|
||||
/**
|
||||
* Find an index for inserting data with this
|
||||
* timestamp. The second argument indicates whether
|
||||
* we are searching for insert-before or insert-after
|
||||
* positions.
|
||||
* Timestamps are meant to be unique, so if a collision
|
||||
* occurs, this will return -1.
|
||||
* @param {number} timestamp timestamp to insert
|
||||
* @returns {number} the index for insertion (or -1)
|
||||
* @memberof platform/features/plot.PlotLineBuffer#
|
||||
*/
|
||||
findInsertionIndex: function (timestamp) {
|
||||
var value = timestamp - domainOffset;
|
||||
|
||||
// Handle empty buffer case and check for an
|
||||
// append opportunity (which is most common case for
|
||||
// real-time data so is optimized-for) before falling
|
||||
// back to a binary search for the insertion point.
|
||||
return (length < 1) ? 0 :
|
||||
(value > buffer[length * 2 - 2]) ? length :
|
||||
binSearch(value, 0, length - 1);
|
||||
}
|
||||
};
|
||||
this.buffer = new Float32Array(initialSize * 2);
|
||||
this.rangeExtrema =
|
||||
[ Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY ];
|
||||
this.length = 0;
|
||||
this.domainOffset = domainOffset;
|
||||
this.initialSize = initialSize;
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
// Binary search for an insertion index
|
||||
PlotLineBuffer.prototype.binSearch = function (value, min, max) {
|
||||
var mid = Math.floor((min + max) / 2),
|
||||
found = this.buffer[mid * 2];
|
||||
|
||||
// On collisions, insert at same index
|
||||
if (found === value) {
|
||||
return mid;
|
||||
}
|
||||
|
||||
// Otherwise, if we're down to a single index,
|
||||
// we've found our insertion point
|
||||
if (min >= max) {
|
||||
// Compare the found timestamp with the search
|
||||
// value to decide if we'll insert after or before.
|
||||
return min + ((found < value) ? 1 : 0);
|
||||
}
|
||||
|
||||
// Finally, do the recursive step
|
||||
if (found < value) {
|
||||
return this.binSearch(value, mid + 1, max);
|
||||
} else {
|
||||
return this.binSearch(value, min, mid - 1);
|
||||
}
|
||||
};
|
||||
|
||||
// Increase the size of the buffer
|
||||
PlotLineBuffer.prototype.doubleBufferSize = function () {
|
||||
var sz = Math.min(this.maxSize * 2, this.buffer.length * 2),
|
||||
canDouble = sz > this.buffer.length,
|
||||
doubled = canDouble && new Float32Array(sz);
|
||||
|
||||
if (canDouble) {
|
||||
doubled.set(this.buffer); // Copy contents of original
|
||||
this.buffer = doubled;
|
||||
}
|
||||
|
||||
return canDouble;
|
||||
};
|
||||
|
||||
// Decrease the size of the buffer
|
||||
PlotLineBuffer.prototype.halveBufferSize = function () {
|
||||
var sz = Math.max(this.initialSize * 2, this.buffer.length / 2),
|
||||
canHalve = sz < this.buffer.length;
|
||||
|
||||
if (canHalve) {
|
||||
this.buffer = new Float32Array(this.buffer.subarray(0, sz));
|
||||
}
|
||||
|
||||
return canHalve;
|
||||
};
|
||||
|
||||
// Set a value in the buffer
|
||||
PlotLineBuffer.prototype.setValue = function (index, domainValue, rangeValue) {
|
||||
this.buffer[index * 2] = domainValue - this.domainOffset;
|
||||
this.buffer[index * 2 + 1] = rangeValue;
|
||||
// Track min/max of range values (min/max for
|
||||
// domain values can be read directly from buffer)
|
||||
this.rangeExtrema[0] = Math.min(this.rangeExtrema[0], rangeValue);
|
||||
this.rangeExtrema[1] = Math.max(this.rangeExtrema[1], rangeValue);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the WebGL-displayable buffer of points to plot.
|
||||
* @returns {Float32Array} displayable buffer for this line
|
||||
*/
|
||||
PlotLineBuffer.prototype.getBuffer = function () {
|
||||
return this.buffer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the number of points stored in this buffer.
|
||||
* @returns {number} the number of points stored
|
||||
*/
|
||||
PlotLineBuffer.prototype.getLength = function () {
|
||||
return this.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the min/max range values that are currently in this
|
||||
* buffer. Unlike range extrema, these will change as the
|
||||
* buffer gets trimmed.
|
||||
* @returns {number[]} min, max domain values
|
||||
*/
|
||||
PlotLineBuffer.prototype.getDomainExtrema = function () {
|
||||
// Since these are ordered in the buffer, assume
|
||||
// these are the values at the first and last index
|
||||
return [
|
||||
this.buffer[0] + this.domainOffset,
|
||||
this.buffer[this.length * 2 - 2] + this.domainOffset
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the min/max range values that have been observed for this
|
||||
* buffer. Note that these values may have been trimmed out at
|
||||
* some point.
|
||||
* @returns {number[]} min, max range values
|
||||
*/
|
||||
PlotLineBuffer.prototype.getRangeExtrema = function () {
|
||||
return this.rangeExtrema;
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove values from this buffer.
|
||||
* Normally, values are removed from the start
|
||||
* of the buffer; a truthy value in the second argument
|
||||
* will cause values to be removed from the end.
|
||||
* @param {number} count number of values to remove
|
||||
* @param {boolean} [fromEnd] true if the most recent
|
||||
* values should be removed
|
||||
*/
|
||||
PlotLineBuffer.prototype.trim = function (count, fromEnd) {
|
||||
// If we're removing values from the start...
|
||||
if (!fromEnd) {
|
||||
// ...do so by shifting buffer contents over
|
||||
this.buffer.set(this.buffer.subarray(2 * count));
|
||||
}
|
||||
// Reduce used buffer size accordingly
|
||||
this.length -= count;
|
||||
// Finally, if less than half of the buffer is being
|
||||
// used, free up some memory.
|
||||
if (this.length < this.buffer.length / 4) {
|
||||
this.halveBufferSize();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Insert data from the provided series at the specified
|
||||
* index. If this would exceed the buffer's maximum capacity,
|
||||
* this operation fails and the buffer is unchanged.
|
||||
* @param {TelemetrySeries} series the series to insert
|
||||
* @param {number} index the index at which to insert this
|
||||
* series
|
||||
* @returns {boolean} true if insertion succeeded; otherwise
|
||||
* false
|
||||
*/
|
||||
PlotLineBuffer.prototype.insert = function (series, index) {
|
||||
var sz = series.getPointCount(),
|
||||
i;
|
||||
|
||||
// Don't allow append after the end; that doesn't make sense
|
||||
index = Math.min(index, this.length);
|
||||
|
||||
// Resize if necessary
|
||||
while (sz > ((this.buffer.length / 2) - this.length)) {
|
||||
if (!this.doubleBufferSize()) {
|
||||
// Can't make room for this, insertion fails
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Shift data over if necessary
|
||||
if (index < this.length) {
|
||||
this.buffer.set(
|
||||
this.buffer.subarray(index * 2, this.length * 2),
|
||||
(index + sz) * 2
|
||||
);
|
||||
}
|
||||
|
||||
// Insert data into the set
|
||||
for (i = 0; i < sz; i += 1) {
|
||||
this.setValue(
|
||||
i + index,
|
||||
series.getDomainValue(i),
|
||||
series.getRangeValue(i)
|
||||
);
|
||||
}
|
||||
|
||||
// Increase the length
|
||||
this.length += sz;
|
||||
|
||||
// Indicate that insertion was successful
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Append a single data point.
|
||||
* @memberof platform/features/plot.PlotLineBuffer#
|
||||
*/
|
||||
PlotLineBuffer.prototype.insertPoint = function (domainValue, rangeValue) {
|
||||
// Ensure there is space for this point
|
||||
if (this.length >= (this.buffer.length / 2)) {
|
||||
if (!this.doubleBufferSize()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Put the data in the buffer
|
||||
this.setValue(this.length, domainValue, rangeValue);
|
||||
|
||||
// Update length
|
||||
this.length += 1;
|
||||
|
||||
// Indicate that this was successful
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Find an index for inserting data with this
|
||||
* timestamp. The second argument indicates whether
|
||||
* we are searching for insert-before or insert-after
|
||||
* positions.
|
||||
* Timestamps are meant to be unique, so if a collision
|
||||
* occurs, this will return -1.
|
||||
* @param {number} timestamp timestamp to insert
|
||||
* @returns {number} the index for insertion (or -1)
|
||||
*/
|
||||
PlotLineBuffer.prototype.findInsertionIndex = function (timestamp) {
|
||||
var value = timestamp - this.domainOffset;
|
||||
|
||||
// Handle empty buffer case and check for an
|
||||
// append opportunity (which is most common case for
|
||||
// real-time data so is optimized-for) before falling
|
||||
// back to a binary search for the insertion point.
|
||||
return (this.length < 1) ? 0 :
|
||||
(value > this.buffer[this.length * 2 - 2]) ? this.length :
|
||||
this.binSearch(value, 0, this.length - 1);
|
||||
};
|
||||
|
||||
return PlotLineBuffer;
|
||||
}
|
||||
);
|
||||
|
@ -44,124 +44,100 @@ define(
|
||||
*/
|
||||
function PlotPanZoomStack(origin, dimensions) {
|
||||
// Use constructor parameters as the stack's initial state
|
||||
var stack = [{ origin: origin, dimensions: dimensions }];
|
||||
|
||||
// Various functions which follow are simply wrappers for
|
||||
// normal stack-like array methods, with the exception that
|
||||
// they prevent undesired modification and enforce that this
|
||||
// stack must remain non-empty.
|
||||
// See JSDoc for specific methods below for more detail.
|
||||
function getDepth() {
|
||||
return stack.length;
|
||||
}
|
||||
|
||||
function pushPanZoom(origin, dimensions) {
|
||||
stack.push({ origin: origin, dimensions: dimensions });
|
||||
}
|
||||
|
||||
function popPanZoom() {
|
||||
if (stack.length > 1) {
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
function clearPanZoom() {
|
||||
stack = [stack[0]];
|
||||
}
|
||||
|
||||
function setBasePanZoom(origin, dimensions) {
|
||||
stack[0] = { origin: origin, dimensions: dimensions };
|
||||
}
|
||||
|
||||
function getPanZoom() {
|
||||
return stack[stack.length - 1];
|
||||
}
|
||||
|
||||
function getOrigin() {
|
||||
return getPanZoom().origin;
|
||||
}
|
||||
|
||||
function getDimensions() {
|
||||
return getPanZoom().dimensions;
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Get the current stack depth; that is, the number
|
||||
* of items on the stack. A depth of one means that no
|
||||
* panning or zooming relative to the base value has
|
||||
* been applied.
|
||||
* @returns {number} the depth of the stack
|
||||
* @memberof platform/features/plot.PlotPanZoomStack#
|
||||
*/
|
||||
getDepth: getDepth,
|
||||
|
||||
/**
|
||||
* Push a new pan-zoom state onto the stack; this will
|
||||
* become the active pan-zoom state.
|
||||
* @param {number[]} origin the new origin
|
||||
* @param {number[]} dimensions the new dimensions
|
||||
* @memberof platform/features/plot.PlotPanZoomStack#
|
||||
*/
|
||||
pushPanZoom: pushPanZoom,
|
||||
|
||||
/**
|
||||
* Pop a pan-zoom state from the stack. Whatever pan-zoom
|
||||
* state was previously present will become current.
|
||||
* If called when there is only one pan-zoom state on the
|
||||
* stack, this acts as a no-op (that is, the lowest
|
||||
* pan-zoom state on the stack cannot be popped, to ensure
|
||||
* that some pan-zoom state is always available.)
|
||||
* @memberof platform/features/plot.PlotPanZoomStack#
|
||||
*/
|
||||
popPanZoom: popPanZoom,
|
||||
|
||||
/**
|
||||
* Set the base pan-zoom state; that is, the state at the
|
||||
* bottom of the stack. This allows the "unzoomed" state of
|
||||
* a plot to be updated (e.g. as new data comes in) without
|
||||
* interfering with the user's chosen zoom level.
|
||||
* @param {number[]} origin the base origin
|
||||
* @param {number[]} dimensions the base dimensions
|
||||
* @memberof platform/features/plot.PlotPanZoomStack#
|
||||
*/
|
||||
setBasePanZoom: setBasePanZoom,
|
||||
|
||||
/**
|
||||
* Clear the pan-zoom stack down to its bottom element;
|
||||
* in effect, pop all elements but the last, e.g. to remove
|
||||
* any temporary user modifications to pan-zoom state.
|
||||
* @memberof platform/features/plot.PlotPanZoomStack#
|
||||
*/
|
||||
clearPanZoom: clearPanZoom,
|
||||
|
||||
/**
|
||||
* Get the current pan-zoom state (the state at the top
|
||||
* of the stack), expressed as an object with "origin" and
|
||||
* "dimensions" fields.
|
||||
* @returns {object} the current pan-zoom state
|
||||
* @memberof platform/features/plot.PlotPanZoomStack#
|
||||
*/
|
||||
getPanZoom: getPanZoom,
|
||||
|
||||
/**
|
||||
* Get the current origin, as represented on the top of the
|
||||
* stack.
|
||||
* @returns {number[]} the current plot origin
|
||||
* @memberof platform/features/plot.PlotPanZoomStack#
|
||||
*/
|
||||
getOrigin: getOrigin,
|
||||
|
||||
/**
|
||||
* Get the current dimensions, as represented on the top of
|
||||
* the stack.
|
||||
* @returns {number[]} the current plot dimensions
|
||||
* @memberof platform/features/plot.PlotPanZoomStack#
|
||||
*/
|
||||
getDimensions: getDimensions
|
||||
};
|
||||
this.stack = [{ origin: origin, dimensions: dimensions }];
|
||||
}
|
||||
|
||||
// Various functions which follow are simply wrappers for
|
||||
// normal stack-like array methods, with the exception that
|
||||
// they prevent undesired modification and enforce that this
|
||||
// stack must remain non-empty.
|
||||
// See JSDoc for specific methods below for more detail.
|
||||
|
||||
/**
|
||||
* Get the current stack depth; that is, the number
|
||||
* of items on the stack. A depth of one means that no
|
||||
* panning or zooming relative to the base value has
|
||||
* been applied.
|
||||
* @returns {number} the depth of the stack
|
||||
*/
|
||||
PlotPanZoomStack.prototype.getDepth = function getDepth() {
|
||||
return this.stack.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* Push a new pan-zoom state onto the stack; this will
|
||||
* become the active pan-zoom state.
|
||||
* @param {number[]} origin the new origin
|
||||
* @param {number[]} dimensions the new dimensions
|
||||
*/
|
||||
PlotPanZoomStack.prototype.pushPanZoom = function (origin, dimensions) {
|
||||
this.stack.push({ origin: origin, dimensions: dimensions });
|
||||
};
|
||||
|
||||
/**
|
||||
* Pop a pan-zoom state from the stack. Whatever pan-zoom
|
||||
* state was previously present will become current.
|
||||
* If called when there is only one pan-zoom state on the
|
||||
* stack, this acts as a no-op (that is, the lowest
|
||||
* pan-zoom state on the stack cannot be popped, to ensure
|
||||
* that some pan-zoom state is always available.)
|
||||
*/
|
||||
PlotPanZoomStack.prototype.popPanZoom = function popPanZoom() {
|
||||
if (stack.length > 1) {
|
||||
this.stack.pop();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the base pan-zoom state; that is, the state at the
|
||||
* bottom of the stack. This allows the "unzoomed" state of
|
||||
* a plot to be updated (e.g. as new data comes in) without
|
||||
* interfering with the user's chosen zoom level.
|
||||
* @param {number[]} origin the base origin
|
||||
* @param {number[]} dimensions the base dimensions
|
||||
* @memberof platform/features/plot.PlotPanZoomStack#
|
||||
*/
|
||||
PlotPanZoomStack.prototype.setBasePanZoom = function (origin, dimensions) {
|
||||
this.stack[0] = { origin: origin, dimensions: dimensions };
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear the pan-zoom stack down to its bottom element;
|
||||
* in effect, pop all elements but the last, e.g. to remove
|
||||
* any temporary user modifications to pan-zoom state.
|
||||
*/
|
||||
PlotPanZoomStack.prototype.clearPanZoom = function clearPanZoom() {
|
||||
this.stack = [this.stack[0]];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current pan-zoom state (the state at the top
|
||||
* of the stack), expressed as an object with "origin" and
|
||||
* "dimensions" fields.
|
||||
* @returns {object} the current pan-zoom state
|
||||
*/
|
||||
PlotPanZoomStack.prototype.getPanZoom = function getPanZoom() {
|
||||
return this.stack[this.stack.length - 1];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current origin, as represented on the top of the
|
||||
* stack.
|
||||
* @returns {number[]} the current plot origin
|
||||
*/
|
||||
PlotPanZoomStack.prototype.getOrigin = function getOrigin() {
|
||||
return this.getPanZoom().origin;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current dimensions, as represented on the top of
|
||||
* the stack.
|
||||
* @returns {number[]} the current plot dimensions
|
||||
*/
|
||||
PlotPanZoomStack.prototype.getDimensions = function getDimensions() {
|
||||
return this.getPanZoom().dimensions;
|
||||
};
|
||||
|
||||
return PlotPanZoomStack;
|
||||
}
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user