mirror of
https://github.com/nasa/openmct.git
synced 2025-06-12 12:18:16 +00:00
MCTChart preserves precision of plot values
This commit is contained in:
@ -11,10 +11,10 @@ define(
|
|||||||
function PlotController($scope) {
|
function PlotController($scope) {
|
||||||
var plotHistory = [];
|
var plotHistory = [];
|
||||||
var isLive = true;
|
var isLive = true;
|
||||||
var maxDomain = 0;
|
var maxDomain = +new Date();
|
||||||
var domainOffset = +new Date();
|
|
||||||
var subscriptions = [];
|
var subscriptions = [];
|
||||||
var setToDefaultViewport = function() {
|
var setToDefaultViewport = function() {
|
||||||
|
// TODO: We shouldn't set the viewport until we have received data or something has given us a reasonable viewport.
|
||||||
$scope.viewport = {
|
$scope.viewport = {
|
||||||
topLeft: {
|
topLeft: {
|
||||||
domain: maxDomain - DOMAIN_INTERVAL,
|
domain: maxDomain - DOMAIN_INTERVAL,
|
||||||
@ -35,7 +35,7 @@ define(
|
|||||||
};
|
};
|
||||||
$scope.displayableDomain = function(domainValue) {
|
$scope.displayableDomain = function(domainValue) {
|
||||||
// TODO: Call format function provided by domain object.
|
// TODO: Call format function provided by domain object.
|
||||||
return new Date(domainValue + domainOffset).toUTCString();
|
return new Date(domainValue).toUTCString();
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.series = [];
|
$scope.series = [];
|
||||||
@ -43,10 +43,7 @@ define(
|
|||||||
$scope.rectangles = [];
|
$scope.rectangles = [];
|
||||||
|
|
||||||
var updateSeriesFromTelemetry = function(series, seriesIndex, telemetry) {
|
var updateSeriesFromTelemetry = function(series, seriesIndex, telemetry) {
|
||||||
if (typeof domainOffset === 'undefined') {
|
var domainValue = telemetry.getDomainValue(telemetry.getPointCount() - 1);
|
||||||
domainOffset = telemetry.getDomainValue(telemetry.getPointCount() - 1);
|
|
||||||
}
|
|
||||||
var domainValue = telemetry.getDomainValue(telemetry.getPointCount() - 1) - domainOffset;
|
|
||||||
var rangeValue = telemetry.getRangeValue(telemetry.getPointCount() - 1);
|
var rangeValue = telemetry.getRangeValue(telemetry.getPointCount() - 1);
|
||||||
// Track the biggest domain we've seen for sticky-ness.
|
// Track the biggest domain we've seen for sticky-ness.
|
||||||
maxDomain = Math.max(maxDomain, domainValue);
|
maxDomain = Math.max(maxDomain, domainValue);
|
||||||
|
@ -10,6 +10,26 @@ define(
|
|||||||
|
|
||||||
var TEMPLATE = "<canvas style='position: absolute; background: none; width: 100%; height: 100%;'></canvas>";
|
var TEMPLATE = "<canvas style='position: absolute; background: none; width: 100%; height: 100%;'></canvas>";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offsetter adjusts domain and range values by a fixed amount,
|
||||||
|
* generally increasing the precision of the 32 bit float representation
|
||||||
|
* required for plotting.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function Offsetter(domainOffset, rangeOffset) {
|
||||||
|
this.domainOffset = domainOffset;
|
||||||
|
this.rangeOffset = rangeOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
Offsetter.prototype.domain = function(dataDomain) {
|
||||||
|
return dataDomain - this.domainOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
Offsetter.prototype.range = function(dataRange) {
|
||||||
|
return dataRange - this.rangeOffset;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MCTChart draws charts utilizing a drawAPI.
|
* MCTChart draws charts utilizing a drawAPI.
|
||||||
*
|
*
|
||||||
@ -22,7 +42,8 @@ define(
|
|||||||
isDestroyed = false,
|
isDestroyed = false,
|
||||||
activeInterval,
|
activeInterval,
|
||||||
drawAPI,
|
drawAPI,
|
||||||
lines = [];
|
lines = [],
|
||||||
|
offset;
|
||||||
|
|
||||||
drawAPI = DrawLoader.getDrawAPI(canvas);
|
drawAPI = DrawLoader.getDrawAPI(canvas);
|
||||||
|
|
||||||
@ -34,15 +55,35 @@ define(
|
|||||||
if (isDestroyed) {
|
if (isDestroyed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
requestAnimationFrame(redraw);
|
requestAnimationFrame(redraw);
|
||||||
canvas.width = canvas.offsetWidth;
|
canvas.width = canvas.offsetWidth;
|
||||||
canvas.height = canvas.offsetHeight;
|
canvas.height = canvas.offsetHeight;
|
||||||
drawAPI.clear();
|
drawAPI.clear();
|
||||||
|
createOffset();
|
||||||
|
if (!offset) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
updateViewport();
|
updateViewport();
|
||||||
drawSeries();
|
drawSeries();
|
||||||
drawRectangles();
|
drawRectangles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createOffset() {
|
||||||
|
if (offset) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!$scope.viewport ||
|
||||||
|
!$scope.viewport.topLeft ||
|
||||||
|
!$scope.viewport.bottomRight) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
offset = new Offsetter(
|
||||||
|
$scope.viewport.topLeft.domain,
|
||||||
|
$scope.viewport.topLeft.range
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function drawIfResized() {
|
function drawIfResized() {
|
||||||
if (canvas.width !== canvas.offsetWidth ||
|
if (canvas.width !== canvas.offsetWidth ||
|
||||||
canvas.height !== canvas.offsetHeight) {
|
canvas.height !== canvas.offsetHeight) {
|
||||||
@ -59,6 +100,9 @@ define(
|
|||||||
|
|
||||||
function drawSeries() {
|
function drawSeries() {
|
||||||
// TODO: Don't regenerate lines on each frame.
|
// TODO: Don't regenerate lines on each frame.
|
||||||
|
if (!$scope.series || !$scope.series.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
lines = $scope.series.map(lineFromSeries);
|
lines = $scope.series.map(lineFromSeries);
|
||||||
lines.forEach(function(line) {
|
lines.forEach(function(line) {
|
||||||
drawAPI.drawLine(
|
drawAPI.drawLine(
|
||||||
@ -73,8 +117,14 @@ define(
|
|||||||
if ($scope.rectangles) {
|
if ($scope.rectangles) {
|
||||||
$scope.rectangles.forEach(function(rect) {
|
$scope.rectangles.forEach(function(rect) {
|
||||||
drawAPI.drawSquare(
|
drawAPI.drawSquare(
|
||||||
[rect.start.domain, rect.start.range],
|
[
|
||||||
[rect.end.domain, rect.end.range],
|
offset.domain(rect.start.domain),
|
||||||
|
offset.range(rect.start.range)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
offset.domain(rect.end.domain),
|
||||||
|
offset.range(rect.end.range)
|
||||||
|
],
|
||||||
rect.color
|
rect.color
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -83,13 +133,23 @@ define(
|
|||||||
|
|
||||||
function updateViewport() {
|
function updateViewport() {
|
||||||
var dimensions = [
|
var dimensions = [
|
||||||
Math.abs($scope.viewport.topLeft.domain - $scope.viewport.bottomRight.domain),
|
Math.abs(
|
||||||
Math.abs($scope.viewport.topLeft.range - $scope.viewport.bottomRight.range)
|
offset.domain($scope.viewport.topLeft.domain) -
|
||||||
|
offset.domain($scope.viewport.bottomRight.domain)
|
||||||
|
),
|
||||||
|
Math.abs(
|
||||||
|
offset.range($scope.viewport.topLeft.range) -
|
||||||
|
offset.range($scope.viewport.bottomRight.range)
|
||||||
|
)
|
||||||
];
|
];
|
||||||
|
|
||||||
var origin = [
|
var origin = [
|
||||||
$scope.viewport.topLeft.domain,
|
offset.domain(
|
||||||
$scope.viewport.bottomRight.range
|
$scope.viewport.topLeft.domain
|
||||||
|
),
|
||||||
|
offset.range(
|
||||||
|
$scope.viewport.bottomRight.range
|
||||||
|
)
|
||||||
];
|
];
|
||||||
|
|
||||||
drawAPI.setDimensions(
|
drawAPI.setDimensions(
|
||||||
@ -113,8 +173,8 @@ define(
|
|||||||
// appears minimal.
|
// appears minimal.
|
||||||
var lineBuffer = new Float32Array(20000);
|
var lineBuffer = new Float32Array(20000);
|
||||||
for (var i = 0; i < series.data.length; i++) {
|
for (var i = 0; i < series.data.length; i++) {
|
||||||
lineBuffer[2*i] = series.data[i].domain;
|
lineBuffer[2*i] = offset.domain(series.data[i].domain);
|
||||||
lineBuffer[2*i+1] = series.data[i].range;
|
lineBuffer[2*i+1] = offset.range(series.data[i].range);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
color: series.color,
|
color: series.color,
|
||||||
@ -123,15 +183,11 @@ define(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function initializeLines() {
|
|
||||||
lines = $scope.series.map(lineFromSeries);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onSeriesDataAdd(event, seriesIndex, points) {
|
function onSeriesDataAdd(event, seriesIndex, points) {
|
||||||
var line = lines[seriesIndex];
|
var line = lines[seriesIndex];
|
||||||
points.forEach(function (point) {
|
points.forEach(function (point) {
|
||||||
line.buffer[2*line.pointCount] = point.domain;
|
line.buffer[2*line.pointCount] = offset.domain(point.domain);
|
||||||
line.buffer[2*line.pointCount+1] = point.range;
|
line.buffer[2*line.pointCount+1] = offset.range(point.range);
|
||||||
line.pointCount += 1;
|
line.pointCount += 1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -139,8 +195,6 @@ define(
|
|||||||
// Check for resize, on a timer
|
// Check for resize, on a timer
|
||||||
activeInterval = $interval(drawIfResized, 1000);
|
activeInterval = $interval(drawIfResized, 1000);
|
||||||
|
|
||||||
// Initialize series
|
|
||||||
$scope.$watch('series', initializeLines);
|
|
||||||
$scope.$on('series:data:add', onSeriesDataAdd);
|
$scope.$on('series:data:add', onSeriesDataAdd);
|
||||||
redraw();
|
redraw();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user