[Plot] Add JSDoc

Add inline comments to Plot scripts. WTD-533.
This commit is contained in:
Victor Woeltjen 2014-12-02 14:38:03 -08:00
parent 870172ec6f
commit 622f1f8be7
10 changed files with 494 additions and 27 deletions

View File

@ -1,4 +1,4 @@
/*global define,Promise,Float32Array*/
/*global define,Float32Array*/
/**
* Module defining GLPlot. Created by vwoeltje on 11/12/14.
@ -8,6 +8,7 @@ define(
function () {
"use strict";
// WebGL shader sources (for drawing plain colors)
var FRAGMENT_SHADER = [
"precision mediump float;",
"uniform vec4 uColor;",
@ -24,6 +25,13 @@ define(
"}"
].join('\n');
/**
* Create a new chart which uses WebGL for rendering.
*
* @constructor
* @param {CanvasElement} canvas the canvas object to render upon
* @throws {Error} an error is thrown if WebGL is unavailable.
*/
function GLChart(canvas) {
var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"),
vertexShader,
@ -35,6 +43,7 @@ define(
uOrigin,
buffer;
// Ensure a context was actually available before proceeding
if (!gl) {
throw new Error("WebGL unavailable.");
}
@ -47,25 +56,33 @@ define(
gl.shaderSource(fragmentShader, FRAGMENT_SHADER);
gl.compileShader(fragmentShader);
// Assemble vertex/fragment shaders into programs
program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
// Get locations for attribs/uniforms from the
// shader programs (to pass values into shaders at draw-time)
aVertexPosition = gl.getAttribLocation(program, "aVertexPosition");
gl.enableVertexAttribArray(aVertexPosition);
uColor = gl.getUniformLocation(program, "uColor");
uDimensions = gl.getUniformLocation(program, "uDimensions");
uOrigin = gl.getUniformLocation(program, "uOrigin");
gl.enableVertexAttribArray(aVertexPosition);
// Create a buffer to holds points which will be drawn
buffer = gl.createBuffer();
// Use a line width of 2.0 for legibility
gl.lineWidth(2.0);
// Enable blending, for smoothness
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
// Utility function to handle drawing of a buffer;
// drawType will determine whether this is a box, line, etc.
function doDraw(drawType, buf, color, points) {
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, buf, gl.DYNAMIC_DRAW);
@ -75,23 +92,51 @@ define(
}
return {
/**
* Clear the chart.
*/
clear: function () {
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clear(gl.COLOR_BUFFER_BIT + gl.DEPTH_BUFFER_BIT);
},
/**
* Set the logical boundaries of the chart.
* @param {number[]} dimensions the horizontal and
* vertical dimensions of the chart
* @param {number[]} origin the horizontal/vertical
* origin of the chart
*/
setDimensions: function (dimensions, origin) {
gl.uniform2fv(uDimensions, dimensions);
gl.uniform2fv(uOrigin, origin);
},
/**
* Draw the supplied buffer as a line strip (a sequence
* of line segments), in the chosen color.
* @param {Float32Array} buf the line strip to draw,
* in alternating x/y positions
* @param {number[]} color the color to use when drawing
* the line, as an RGBA color where each element
* is in the range of 0.0-1.0
* @param {number} points the number of points to draw
*/
drawLine: function (buf, color, points) {
doDraw(gl.LINE_STRIP, buf, color, points);
},
/**
* Draw a rectangle extending from one corner to another,
* in the chosen color.
* @param {number[]} min the first corner of the rectangle
* @param {number[]} max the opposite corner
* @param {number[]} color the color to use when drawing
* the rectangle, as an RGBA color where each element
* is in the range of 0.0-1.0
*/
drawSquare: function (min, max, color) {
doDraw(gl.TRIANGLE_FAN, new Float32Array(
min.concat([min[0], max[1]]).concat(max).concat([max[0], min[1]])
), color, 4);
},
gl: gl
}
};
}
return GLChart;

View File

@ -1,4 +1,4 @@
/*global define,Promise*/
/*global define*/
/**
* Module defining MCTChart. Created by vwoeltje on 11/12/14.
@ -11,6 +11,34 @@ define(
var TEMPLATE = "<canvas style='position: absolute; background: none; width: 100%; height: 100%;'></canvas>";
/**
* The mct-chart directive provides a canvas element which can be
* drawn upon, to support Plot view and similar visualizations.
*
* This directive takes one attribute, "draw", which is an Angular
* expression which will be two-way bound to a drawing object. This
* drawing object should contain:
*
* * `dimensions`: An object describing the logical bounds of the
* drawable area, containing two fields:
* * `origin`: The position, in logical coordinates, of the
* lower-left corner of the chart area. A two-element array.
* * `dimensions`: A two-element array containing the width
* and height of the chart area, in logical coordinates.
* * `lines`: An array of lines to be drawn, where each line is
* expressed as an object containing:
* * `buffer`: A Float32Array containing points in the line,
* in logical coordinate, in sequential x/y pairs.
* * `color`: The color of the line, as a four-element RGBA
* array, where each element is in the range of 0.0-1.0
* * `points`: The number of points in the line.
* * `boxes`: An array of rectangles to draw in the chart area
* (used for marquee zoom). Each is an object containing:
* * `start`: The first corner of the rectangle (as a two-element
* array, logical coordinates)
* * `end`: The opposite corner of the rectangle (again, as a
* two-element array)
* * `color`: The color of the box, as a four-element RGBA
* array, where each element is in the range of 0.0-1.0
*
* @constructor
*/
@ -30,20 +58,29 @@ define(
return;
}
// Handle drawing, based on contents of the "draw" object
// in scope
function doDraw(draw) {
// Ensure canvas context has same resolution
// as canvas element
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
// Clear previous contents
chart.clear();
// Nothing to draw if no draw object defined
if (!draw) {
return;
}
// Set logical boundaries for the chart
chart.setDimensions(
draw.dimensions || [1, 1],
draw.origin || [0, 0]
);
// Draw line segments
(draw.lines || []).forEach(function (line) {
chart.drawLine(
line.buffer,
@ -52,6 +89,7 @@ define(
);
});
// Draw boxes (e.g. marquee zoom rect)
(draw.boxes || []).forEach(function (box) {
chart.drawSquare(
box.start,
@ -62,6 +100,9 @@ define(
}
// Issue a drawing call, if-and-only-if canvas size
// has changed. This will be called on a timer, since
// there is no event to depend on.
function drawIfResized() {
if (canvas.width !== canvas.offsetWidth ||
canvas.height !== canvas.offsetHeight) {
@ -69,14 +110,25 @@ define(
}
}
// Check for resize, on a timer
$interval(drawIfResized, 1000);
// Watch "draw" for external changes to the set of
// things to be drawn.
scope.$watchCollection("draw", doDraw);
}
return {
// Apply directive only to elements
restrict: "E",
// Template to use (a canvas element)
template: TEMPLATE,
// Link function; set up scope
link: linkChart,
// Initial, isolate scope for the directive
scope: { draw: "=" }
};
}

View File

@ -1,4 +1,4 @@
/*global define,moment,Promise*/
/*global define*/
/**
* Module defining PlotController. Created by vwoeltje on 11/12/14.
@ -32,6 +32,13 @@ define(
RANGE_TICKS = 7;
/**
* The PlotController is responsible for any computation/logic
* associated with displaying the plot view. Specifically, these
* responsibilities include:
*
* * Describing axes and labeling.
* * Handling user interactions.
* * Deciding what needs to be drawn in the chart area.
*
* @constructor
*/
@ -50,6 +57,8 @@ define(
formatter.formatDomainValue)(v);
}
// Converts from pixel coordinates to domain-range,
// to interpret mouse gestures.
function mousePositionToDomainRange(mousePosition) {
return new PlotPosition(
mousePosition.x,
@ -60,11 +69,36 @@ define(
).getPosition();
}
// Utility function to get the mouse position (in x,y
// pixel coordinates in the canvas area) from a mouse
// event object.
function toMousePosition($event) {
var target = $event.target,
bounds = target.getBoundingClientRect();
return {
x: $event.clientX - bounds.left,
y: $event.clientY - bounds.top,
width: bounds.width,
height: bounds.height
};
}
// Convert a domain-range position to a displayable
// position. This will subtract the domain offset, which
// is used to bias domain values to minimize loss-of-precision
// associated with conversion to a 32-bit floating point
// format (which is needed in the chart area itself, by WebGL.)
function toDisplayable(position) {
return [ position[0] - domainOffset, position[1] ];
}
// Update the drawable marquee area to reflect current
// mouse position (or don't show it at all, if no marquee
// zoom is in progress)
function updateMarqueeBox() {
// Express this as a box in the draw object, which
// is passed to an mct-chart in the template for rendering.
$scope.draw.boxes = marqueeStart ?
[{
start: toDisplayable(mousePositionToDomainRange(marqueeStart)),
@ -73,9 +107,12 @@ define(
}] : undefined;
}
// Update the bounds (origin and dimensions) of the drawing area.
function updateDrawingBounds() {
var panZoom = panZoomStack.getPanZoom();
// Communicate pan-zoom state from stack to the draw object
// which is passed to mct-chart in the template.
$scope.draw.dimensions = panZoom.dimensions;
$scope.draw.origin = [
panZoom.origin[0] - domainOffset,
@ -83,6 +120,7 @@ define(
];
}
// Update tick marks in scope.
function updateTicks() {
var tickGenerator = new PlotTickGenerator(panZoomStack, formatter);
@ -92,6 +130,8 @@ define(
tickGenerator.generateRangeTicks(RANGE_TICKS);
}
// Populate the scope with axis information (specifically, options
// available for each axis.)
function setupAxes(metadatas) {
$scope.axes = [
new PlotAxis("domain", metadatas, AXIS_DEFAULTS[0]),
@ -99,34 +139,48 @@ define(
];
}
// Respond to newly-available telemetry data; update the
// drawing area accordingly.
function plotTelemetry() {
var prepared, data, telemetry;
var prepared, datas, telemetry;
// Get a reference to the TelemetryController
telemetry = $scope.telemetry;
// Nothing to plot without TelemetryController
if (!telemetry) {
return;
}
// Ensure axes have been initialized (we will want to
// get the active axis below)
if (!$scope.axes) {
setupAxes(telemetry.getMetadata());
}
data = telemetry.getResponse();
// Get data sets
datas = telemetry.getResponse();
// Prepare data sets for rendering
prepared = new PlotPreparer(
data,
datas,
($scope.axes[0].active || {}).key,
($scope.axes[1].active || {}).key
);
// Fit to the boundaries of the data, but don't
// override any user-initiated pan-zoom changes.
panZoomStack.setBasePanZoom(
prepared.getOrigin(),
prepared.getDimensions()
);
// Track the domain offset, used to bias domain values
// to minimize loss of precision when converted to 32-bit
// floating point values for display.
domainOffset = prepared.getDomainOffset();
// Draw the buffers. Select color by index.
$scope.draw.lines = prepared.getBuffers().map(function (buf, i) {
return {
buffer: buf,
@ -140,19 +194,11 @@ define(
updateTicks();
}
function toMousePosition($event) {
var target = $event.target,
bounds = target.getBoundingClientRect();
return {
x: $event.clientX - bounds.left,
y: $event.clientY - bounds.top,
width: bounds.width,
height: bounds.height
};
}
// Perform a marquee zoom.
function marqueeZoom(start, end) {
// Determine what boundary is described by the marquee,
// in domain-range values. Use the minima for origin, so that
// it doesn't matter what direction the user marqueed in.
var a = mousePositionToDomainRange(start),
b = mousePositionToDomainRange(end),
origin = [
@ -164,7 +210,10 @@ define(
Math.max(a[1], b[1]) - origin[1]
];
// Push the new state onto the pan-zoom stack
panZoomStack.pushPanZoom(origin, dimensions);
// Make sure tick marks reflect new bounds
updateTicks();
}
@ -173,25 +222,49 @@ define(
$scope.draw = {};
return {
/**
* Get the color (as a style-friendly string) to use
* for plotting the trace at the specified index.
* @param {number} index the index of the trace
* @returns {string} the color, in #RRGGBB form
*/
getColor: function (index) {
return PlotPalette.getStringColor(index);
},
/**
* Get the coordinates (as displayable text) for the
* current mouse position.
* @returns {string[]} the displayable domain and range
* coordinates over which the mouse is hovered
*/
getHoverCoordinates: function () {
return mousePosition ?
mousePositionToDomainRange(
mousePosition
).map(formatValue) : [];
},
/**
* Handle mouse movement over the chart area.
* @param $event the mouse event
*/
hover: function ($event) {
mousePosition = toMousePosition($event);
if (marqueeStart) {
updateMarqueeBox();
}
},
/**
* Initiate a marquee zoom action.
* @param $event the mouse event
*/
startMarquee: function ($event) {
mousePosition = marqueeStart = toMousePosition($event);
updateMarqueeBox();
},
/**
* Complete a marquee zoom action.
* @param $event the mouse event
*/
endMarquee: function ($event) {
mousePosition = toMousePosition($event);
if (marqueeStart) {
@ -201,13 +274,26 @@ define(
updateDrawingBounds();
}
},
/**
* Check if the plot is zoomed or panned out
* of its default state (to determine whether back/unzoom
* controls should be shown)
* @returns {boolean} true if not in default state
*/
isZoomed: function () {
return panZoomStack.getDepth() > 1;
},
/**
* Undo the most recent pan/zoom change and restore
* the prior state.
*/
stepBackPanZoom: function () {
panZoomStack.popPanZoom();
updateDrawingBounds();
},
/**
* Undo all pan/zoom changes and restore the initial state.
*/
unzoom: function () {
panZoomStack.clearPanZoom();
updateDrawingBounds();

View File

@ -5,10 +5,30 @@ define(
function () {
"use strict";
/**
* A PlotAxis provides a template-ready set of options
* for the domain or range axis, sufficient to populate
* selectors.
*
* @constructor
* @param {string} axisType the field in metadatas to
* look at for axis options; usually one of
* "domains" or "ranges"
* @param {object[]} metadatas metadata objects, as
* returned by the `getMetadata()` method of
* a `telemetry` capability.
* @param {object} defaultValue the value to use for the
* active state in the event that no options are
* found; should contain "name" and "key" at
* minimum.
*
*/
function PlotAxis(axisType, metadatas, defaultValue) {
var keys = {},
options = [];
// Look through all metadata objects and assemble a list
// of all possible domain or range options
function buildOptionsForMetadata(m) {
(m[axisType] || []).forEach(function (option) {
if (!keys[option.key]) {
@ -24,7 +44,18 @@ define(
// 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)
*/
options: options,
/**
* The currently chosen option for this axis. An
* initial value is provided; this will be updated
* directly form the plot template.
*/
active: options[0] || defaultValue
};
}

View File

@ -5,8 +5,15 @@ define(
function () {
"use strict";
// Date format to use for domain values; in particular,
// use day-of-year instead of month/day
var DATE_FORMAT = "YYYY-DDD HH:mm:ss";
/**
* The PlotFormatter is responsible for formatting (as text
* for display) values along either the domain or range of a
* plot.
*/
function PlotFormatter() {
function formatDomainValue(v) {
return moment.utc(v).format(DATE_FORMAT);
@ -17,7 +24,20 @@ define(
}
return {
/**
* Format a domain value.
* @param {number} v the domain value; a timestamp
* in milliseconds since start of 1970
* @returns {string} a textual representation of the
* data and time, suitable for display.
*/
formatDomainValue: formatDomainValue,
/**
* Format a range value.
* @param {number} v the range value; a numeric value
* @returns {string} a textual representation of the
* value, suitable for display.
*/
formatRangeValue: formatRangeValue
};
}

View File

@ -52,18 +52,57 @@ define(
}).concat([1]); // RGBA
});
/**
* PlotPalette allows a consistent set of colors to be retrieved
* by index, in various color formats. All PlotPalette methods are
* static, so there is no need for a constructor call; using
* this will simply return PlotPalette itself.
* @constructor
*/
function PlotPalette() {
return PlotPalette;
}
/**
* Look up a color in the plot's palette, by index.
* This will be returned as a three element array of RGB
* values, as integers in the range of 0-255.
* @param {number} i the index of the color to look up
* @return {number[]} the color, as integer RGB values
*/
PlotPalette.getIntegerColor = function (i) {
return integerPalette[Math.floor(i) % integerPalette.length];
};
/**
* Look up a color in the plot's palette, by index.
* This will be returned as a three element array of RGB
* values, in the range of 0.0-1.0.
*
* This format is present specifically to support use with
* WebGL, which expects colors of that form.
*
* @param {number} i the index of the color to look up
* @return {number[]} the color, as floating-point RGB values
*/
PlotPalette.getFloatColor = function (i) {
return floatPalette[Math.floor(i) % floatPalette.length];
};
/**
* Look up a color in the plot's palette, by index.
* This will be returned as a string using #-prefixed
* six-digit RGB hex notation (e.g. #FF0000)
* See http://www.w3.org/TR/css3-color/#rgb-color.
*
* This format is useful for representing colors in in-line
* styles.
*
* @param {number} i the index of the color to look up
* @return {string} the color, as a style-friendly string
*/
PlotPalette.getStringColor = function (i) {
return stringPalette[Math.floor(i) % stringPalette.length];
};

View File

@ -5,9 +5,30 @@ define(
function () {
"use strict";
/**
* The PlotPanZoomStack is responsible for maintaining the
* pan-zoom state of a plot (expressed as a boundary starting
* at an origin and extending to certain dimensions) in a
* stack, to support the back and unzoom buttons in plot controls.
*
* Dimensions and origins are here described each by two-element
* arrays, where the first element describes a value or quantity
* along the domain axis, and the second element describes the same
* along the range axis.
*
* @constructor
* @param {number[]} origin the plot's origin, initially
* @param {number[]} dimensions the plot's dimensions, initially
*/
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;
}
@ -43,13 +64,70 @@ define(
}
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
*/
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
*/
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.)
*/
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
*/
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.
*/
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
*/
getPanZoom: getPanZoom,
/**
* Get the current origin, as represented on the top of the
* stack.
* @returns {number[]} the current plot origin
*/
getOrigin: getOrigin,
/**
* Get the current dimensions, as represented on the top of
* the stack.
* @returns {number[]} the current plot dimensions
*/
getDimensions: getDimensions
};
}

View File

@ -5,27 +5,65 @@ define(
function () {
"use strict";
/**
* A PlotPosition converts from pixel coordinates to domain-range
* coordinates, based on the current plot boundary as described on
* the pan-zoom stack.
*
* These coordinates are not updated after construction; that is,
* they represent the result of the conversion at the time the
* PlotPosition was instantiated. Care should be taken when retaining
* PlotPosition objects across changes to the pan-zoom stack.
*
* @constructor
* @param {number} x the horizontal pixel position in the plot area
* @param {number} y the vertical pixel position in the plot area
* @param {number} width the width of the plot area
* @param {number} height the height of the plot area
* @param {PanZoomStack} panZoomStack the applicable pan-zoom stack,
* used to determine the plot's domain-range boundaries.
*/
function PlotPosition(x, y, width, height, panZoomStack) {
var panZoom = panZoomStack.getPanZoom(),
origin = panZoom.origin,
dimensions = panZoom.dimensions,
position;
function convert(v, i) {
return v * dimensions[i] + origin[i];
}
if (!dimensions || !origin) {
// We need both dimensions and origin to compute a position
position = [];
} else {
position = [ x / width, (height - y) / height ].map(function (v, i) {
return v * dimensions[i] + origin[i];
});
// Convert from pixel to domain-range space.
// Note that range is reversed from the y-axis in pixel space
//(positive range points up, positive pixel-y points down)
position = [ x / width, (height - y) / height ].map(convert);
}
return {
/**
* Get the domain value corresponding to this pixel position.
* @returns {number} the domain value
*/
getDomain: function () {
return position[0];
},
/**
* Get the range value corresponding to this pixel position.
* @returns {number} the range value
*/
getRange: function () {
return position[1];
},
/**
* Get the domain and values corresponding to this
* pixel position.
* @returns {number[]} an array containing the domain and
* the range value, in that order
*/
getPosition: function () {
return position;
}

View File

@ -10,6 +10,16 @@ define(
function identity(x) { return x; }
/**
* The PlotPreparer is responsible for handling data sets and
* preparing them to be rendered. It creates a WebGL-plottable
* Float32Array for each trace, and tracks the boundaries of the
* data sets (since this is convenient to do during the same pass).
* @constructor
* @param {Telemetry[]} datas telemetry data objects
* @param {string} domain the key to use when looking up domain values
* @param {string} range the key to use when looking up range values
*/
function PlotPreparer(datas, domain, range) {
var index,
vertices = [],
@ -23,14 +33,18 @@ define(
// Remove any undefined data sets
datas = (datas || []).filter(identity);
// Filter out un
// Do a first pass to determine the domain offset.
// This will be use to reduce the magnitude of domain values
// in the buffer, to minimize loss-of-precision when
// converting to a 32-bit float.
datas.forEach(function (data) {
domainOffset = Math.min(data.getDomainValue(0, domain), domainOffset);
});
// Assemble buffers, and track bounds of the data present
datas.forEach(function (data, i) {
vertices.push([]);
for (index = 0; index < data.getPointCount(); index = index + 1) {
for (index = 0; index < data.getPointCount(); index += 1) {
x = data.getDomainValue(index, domain);
y = data.getRangeValue(index, range);
vertices[i].push(x - domainOffset);
@ -42,23 +56,62 @@ define(
}
});
// If range is empty, add some padding
if (max[1] === min[1]) {
max[1] = max[1] + 1.0;
min[1] = min[1] - 1.0;
}
// Convert to Float32Array
buffers = vertices.map(function (v) { return new Float32Array(v); });
return {
/**
* Get the dimensions which bound all data in the provided
* data sets. This is given as a two-element array where the
* first element is domain, and second is range.
* @returns {number[]} the dimensions which bound this data set
*/
getDimensions: function () {
return [max[0] - min[0], max[1] - min[1]];
},
/**
* Get the origin of this data set's boundary.
* This is given as a two-element array where the
* first element is domain, and second is range.
* The domain value here is not adjusted by the domain offset.
* @returns {number[]} the origin of this data set's boundary
*/
getOrigin: function () {
return min;
},
/**
* Get the domain offset; this offset will have been subtracted
* from all domain values in all buffers returned by this
* preparer, in order to minimize loss-of-precision due to
* conversion to the 32-bit float format needed by WebGL.
* @returns {number} the domain offset
*/
getDomainOffset: function () {
return domainOffset;
},
/**
* Get all renderable buffers for this data set. This will
* be returned as an array which can be correlated back to
* the provided telemetry data objects (from the constructor
* call) by index.
*
* Internally, these are flattened; each buffer contains a
* sequence of alternating domain and range values.
*
* All domain values in all buffers will have been adjusted
* from their original values by subtraction of the domain
* offset; this minimizes loss-of-precision resulting from
* the conversion to 32-bit floats, which may otherwise
* cause aliasing artifacts (particularly for timestamps)
*
* @returns {Float32Array[]} the buffers for these traces
*/
getBuffers: function () {
return buffers;
}

View File

@ -5,8 +5,22 @@ define(
function () {
"use strict";
/**
* The PlotTickGenerator provides labels for ticks along the
* domain and range axes of the plot, to support the plot
* template.
*
* @constructor
* @param {PlotPanZoomStack} panZoomStack the pan-zoom stack for
* this plot, used to determine plot boundaries
* @param {PlotFormatter} formatter used to format (for display)
* domain and range values.
*/
function PlotTickGenerator(panZoomStack, formatter) {
// Generate ticks; interpolate from start up to
// start + span in count steps, using the provided
// formatter to represent each value.
function generateTicks(start, span, count, format) {
var step = span / (count - 1),
result = [],
@ -23,6 +37,11 @@ define(
return {
/**
* Generate tick marks for the domain axis.
* @param {number} count the number of ticks
* @returns {string[]} labels for those ticks
*/
generateDomainTicks: function (count) {
var panZoom = panZoomStack.getPanZoom();
return generateTicks(
@ -32,6 +51,12 @@ define(
formatter.formatDomainValue
);
},
/**
* Generate tick marks for the range axis.
* @param {number} count the number of ticks
* @returns {string[]} labels for those ticks
*/
generateRangeTicks: function (count) {
var panZoom = panZoomStack.getPanZoom();
return generateTicks(