mirror of
https://github.com/nasa/openmct.git
synced 2025-04-25 13:29:51 +00:00
[Plot] Fill in specs
Fill in specs for elements used by the PlotController in order to improve coverage of the plot bundle. WTD-533.
This commit is contained in:
parent
ae05ed903b
commit
2f475fc17a
@ -17,23 +17,18 @@ define(
|
|||||||
min = [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY],
|
min = [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY],
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
xLabels = {},
|
|
||||||
yLabels = {},
|
|
||||||
yUnits = {},
|
|
||||||
domainOffset = Number.POSITIVE_INFINITY,
|
domainOffset = Number.POSITIVE_INFINITY,
|
||||||
buffers;
|
buffers;
|
||||||
|
|
||||||
datas = datas || [];
|
// Remove any undefined data sets
|
||||||
|
datas = (datas || []).filter(identity);
|
||||||
|
|
||||||
datas.filter(identity).forEach(function (data) {
|
// Filter out un
|
||||||
|
datas.forEach(function (data) {
|
||||||
domainOffset = Math.min(data.getDomainValue(0, domain), domainOffset);
|
domainOffset = Math.min(data.getDomainValue(0, domain), domainOffset);
|
||||||
});
|
});
|
||||||
|
|
||||||
datas.forEach(function (data, i) {
|
datas.forEach(function (data, i) {
|
||||||
if (!data) {
|
|
||||||
return; // skip null data
|
|
||||||
}
|
|
||||||
|
|
||||||
vertices.push([]);
|
vertices.push([]);
|
||||||
for (index = 0; index < data.getPointCount(); index = index + 1) {
|
for (index = 0; index < data.getPointCount(); index = index + 1) {
|
||||||
x = data.getDomainValue(index, domain);
|
x = data.getDomainValue(index, domain);
|
||||||
@ -45,18 +40,6 @@ define(
|
|||||||
max[0] = Math.max(max[0], x);
|
max[0] = Math.max(max[0], x);
|
||||||
max[1] = Math.max(max[1], y);
|
max[1] = Math.max(max[1], y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.getDomainLabel) {
|
|
||||||
xLabels[data.getDomainLabel(domain)] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.getRangeLabel) {
|
|
||||||
yLabels[data.getRangeLabel(range)] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.getRangeUnits) {
|
|
||||||
yUnits[data.getRangeUnits(range)] = true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (max[1] === min[1]) {
|
if (max[1] === min[1]) {
|
||||||
@ -64,10 +47,6 @@ define(
|
|||||||
min[1] = min[1] - 1.0;
|
min[1] = min[1] - 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
xLabels = Object.keys(xLabels).sort();
|
|
||||||
yLabels = Object.keys(yLabels).sort();
|
|
||||||
yUnits = Object.keys(yUnits).sort();
|
|
||||||
|
|
||||||
buffers = vertices.map(function (v) { return new Float32Array(v); });
|
buffers = vertices.map(function (v) { return new Float32Array(v); });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -9,6 +9,54 @@ define(
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
describe("A plot axis", function () {
|
describe("A plot axis", function () {
|
||||||
|
var testMetadatas = [
|
||||||
|
{
|
||||||
|
tests: [
|
||||||
|
{ key: "t0", name: "T0" },
|
||||||
|
{ key: "t1", name: "T1" }
|
||||||
|
],
|
||||||
|
someKey: "some value"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tests: [
|
||||||
|
{ key: "t0", name: "T0" },
|
||||||
|
{ key: "t2", name: "T2" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tests: [
|
||||||
|
{ key: "t3", name: "T3" },
|
||||||
|
{ key: "t4", name: "T4" },
|
||||||
|
{ key: "t5", name: "T5" },
|
||||||
|
{ key: "t6", name: "T6" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
testDefault = { key: "test", name: "Test" },
|
||||||
|
controller = new PlotAxis("tests", testMetadatas, testDefault);
|
||||||
|
|
||||||
|
it("pulls out a list of domain or range options", function () {
|
||||||
|
// Should have filtered out duplicates, etc
|
||||||
|
expect(controller.options).toEqual([
|
||||||
|
{ key: "t0", name: "T0" },
|
||||||
|
{ key: "t1", name: "T1" },
|
||||||
|
{ key: "t2", name: "T2" },
|
||||||
|
{ key: "t3", name: "T3" },
|
||||||
|
{ key: "t4", name: "T4" },
|
||||||
|
{ key: "t5", name: "T5" },
|
||||||
|
{ key: "t6", name: "T6" }
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("chooses the first option as a default", function () {
|
||||||
|
expect(controller.active).toEqual({ key: "t0", name: "T0" });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("falls back to a provided default if no options are present", function () {
|
||||||
|
expect(new PlotAxis("tests", [{}], testDefault).active)
|
||||||
|
.toEqual(testDefault);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
@ -9,6 +9,21 @@ define(
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
describe("The plot formatter", function () {
|
describe("The plot formatter", function () {
|
||||||
|
var formatter;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
formatter = new PlotFormatter();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("formats domains using YYYY-DDD style", function () {
|
||||||
|
expect(formatter.formatDomainValue(402513731000)).toEqual(
|
||||||
|
"1982-276 17:22:11"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("formats ranges as values", function () {
|
||||||
|
expect(formatter.formatRangeValue(10)).toEqual("10.0");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
@ -9,6 +9,96 @@ define(
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
describe("The plot palette", function () {
|
describe("The plot palette", function () {
|
||||||
|
it("can be used as a constructor", function () {
|
||||||
|
// PlotPalette has all static methods, so make
|
||||||
|
// sure it returns itself if used as a constructor.
|
||||||
|
expect(new PlotPalette()).toBe(PlotPalette);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("has 30 unique colors in an integer format", function () {
|
||||||
|
// Integer format may be useful internal to the application.
|
||||||
|
// RGB 0-255
|
||||||
|
var i, j;
|
||||||
|
|
||||||
|
// Used to verify one of R, G, B in loop below
|
||||||
|
function verifyChannel(c) {
|
||||||
|
expect(typeof c).toEqual("number");
|
||||||
|
expect(c <= 255).toBeTruthy();
|
||||||
|
expect(c >= 0).toBeTruthy();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 30; i += 1) {
|
||||||
|
// Verify that we got an array of numbers
|
||||||
|
expect(Array.isArray(PlotPalette.getIntegerColor(i)))
|
||||||
|
.toBeTruthy();
|
||||||
|
expect(PlotPalette.getIntegerColor(i).length).toEqual(3);
|
||||||
|
|
||||||
|
// Verify all three channels for type and range
|
||||||
|
PlotPalette.getIntegerColor(i).forEach(verifyChannel);
|
||||||
|
|
||||||
|
// Verify uniqueness
|
||||||
|
for (j = i + 1; j < 30; j += 1) {
|
||||||
|
expect(PlotPalette.getIntegerColor(i)).not.toEqual(
|
||||||
|
PlotPalette.getIntegerColor(j)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it("has 30 unique colors in a floating-point format", function () {
|
||||||
|
// Float format is useful to WebGL.
|
||||||
|
// RGB 0.0-1.1
|
||||||
|
var i, j;
|
||||||
|
|
||||||
|
// Used to verify one of R, G, B in loop below
|
||||||
|
function verifyChannel(c) {
|
||||||
|
expect(typeof c).toEqual("number");
|
||||||
|
expect(c <= 1.0).toBeTruthy();
|
||||||
|
expect(c >= 0.0).toBeTruthy();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 30; i += 1) {
|
||||||
|
// Verify that we got an array of numbers
|
||||||
|
expect(Array.isArray(PlotPalette.getFloatColor(i)))
|
||||||
|
.toBeTruthy();
|
||||||
|
expect(PlotPalette.getFloatColor(i).length).toEqual(4);
|
||||||
|
|
||||||
|
// Verify all three channels for type and range
|
||||||
|
PlotPalette.getFloatColor(i).forEach(verifyChannel);
|
||||||
|
|
||||||
|
// Verify uniqueness
|
||||||
|
for (j = i + 1; j < 30; j += 1) {
|
||||||
|
expect(PlotPalette.getFloatColor(i)).not.toEqual(
|
||||||
|
PlotPalette.getFloatColor(j)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it("has 30 unique colors in a string format", function () {
|
||||||
|
// String format is useful in stylesheets
|
||||||
|
// #RRGGBB in hex
|
||||||
|
var i, j, c;
|
||||||
|
|
||||||
|
|
||||||
|
for (i = 0; i < 30; i += 1) {
|
||||||
|
c = PlotPalette.getStringColor(i);
|
||||||
|
|
||||||
|
// Verify that we #-style color strings
|
||||||
|
expect(typeof c).toEqual('string');
|
||||||
|
expect(c.length).toEqual(7);
|
||||||
|
expect(/^#[0-9a-fA-F]+$/.test(c)).toBeTruthy();
|
||||||
|
|
||||||
|
// Verify uniqueness
|
||||||
|
for (j = i + 1; j < 30; j += 1) {
|
||||||
|
expect(PlotPalette.getStringColor(i)).not.toEqual(
|
||||||
|
PlotPalette.getStringColor(j)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
@ -9,6 +9,72 @@ define(
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
describe("A plot pan-zoom stack", function () {
|
describe("A plot pan-zoom stack", function () {
|
||||||
|
var panZoomStack,
|
||||||
|
initialOrigin,
|
||||||
|
initialDimensions,
|
||||||
|
otherOrigins,
|
||||||
|
otherDimensions;
|
||||||
|
|
||||||
|
// Shorthand for verifying getOrigin, getDimensions, and getPanZoom,
|
||||||
|
// which should always agree.
|
||||||
|
function verifyPanZoom(origin, dimensions) {
|
||||||
|
expect(panZoomStack.getOrigin()).toEqual(origin);
|
||||||
|
expect(panZoomStack.getDimensions()).toEqual(dimensions);
|
||||||
|
expect(panZoomStack.getPanZoom()).toEqual({
|
||||||
|
origin: origin,
|
||||||
|
dimensions: dimensions
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
initialOrigin = [ 4, 2 ];
|
||||||
|
initialDimensions = [ 600, 400 ];
|
||||||
|
otherOrigins = [ [8, 6], [12, 9] ];
|
||||||
|
otherDimensions = [ [400, 300], [200, 300] ];
|
||||||
|
panZoomStack =
|
||||||
|
new PlotPanZoomStack(initialOrigin, initialDimensions);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("starts off reporting its initial values", function () {
|
||||||
|
verifyPanZoom(initialOrigin, initialDimensions);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("allows origin/dimensions pairs to be pushed/popped", function () {
|
||||||
|
panZoomStack.pushPanZoom(otherOrigins[0], otherDimensions[0]);
|
||||||
|
verifyPanZoom(otherOrigins[0], otherDimensions[0]);
|
||||||
|
panZoomStack.pushPanZoom(otherOrigins[1], otherDimensions[1]);
|
||||||
|
verifyPanZoom(otherOrigins[1], otherDimensions[1]);
|
||||||
|
panZoomStack.popPanZoom();
|
||||||
|
verifyPanZoom(otherOrigins[0], otherDimensions[0]);
|
||||||
|
panZoomStack.popPanZoom();
|
||||||
|
verifyPanZoom(initialOrigin, initialDimensions);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("reports current stack depth", function () {
|
||||||
|
expect(panZoomStack.getDepth()).toEqual(1);
|
||||||
|
panZoomStack.pushPanZoom(otherOrigins[0], otherDimensions[0]);
|
||||||
|
expect(panZoomStack.getDepth()).toEqual(2);
|
||||||
|
panZoomStack.pushPanZoom(otherOrigins[1], otherDimensions[1]);
|
||||||
|
expect(panZoomStack.getDepth()).toEqual(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("allows base pan zoom to be restored", function () {
|
||||||
|
panZoomStack.pushPanZoom(otherOrigins[0], otherDimensions[0]);
|
||||||
|
panZoomStack.pushPanZoom(otherOrigins[1], otherDimensions[1]);
|
||||||
|
panZoomStack.clearPanZoom();
|
||||||
|
verifyPanZoom(initialOrigin, initialDimensions);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("allows base pan zoom to be changed", function () {
|
||||||
|
panZoomStack.pushPanZoom(otherOrigins[0], otherDimensions[0]);
|
||||||
|
panZoomStack.setBasePanZoom(otherOrigins[1], otherDimensions[1]);
|
||||||
|
// Should not have changed current top-of-stack
|
||||||
|
verifyPanZoom(otherOrigins[0], otherDimensions[0]);
|
||||||
|
|
||||||
|
// Clear the stack - should be at our new base pan-zoom state
|
||||||
|
panZoomStack.clearPanZoom();
|
||||||
|
verifyPanZoom(otherOrigins[1], otherDimensions[1]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
@ -9,6 +9,40 @@ define(
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
describe("A plot position", function () {
|
describe("A plot position", function () {
|
||||||
|
var mockPanZoom,
|
||||||
|
testOrigin = [ 10, 20 ],
|
||||||
|
testDimensions = [ 800, 10 ];
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockPanZoom = jasmine.createSpyObj(
|
||||||
|
"panZoomStack",
|
||||||
|
[ "getPanZoom" ]
|
||||||
|
);
|
||||||
|
mockPanZoom.getPanZoom.andReturn({
|
||||||
|
origin: testOrigin,
|
||||||
|
dimensions: testDimensions
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("transforms pixel coordinates to domain-range", function () {
|
||||||
|
var position = new PlotPosition(42, 450, 100, 1000, mockPanZoom);
|
||||||
|
// Domain: .42 * 800 + 10 = 346
|
||||||
|
// Range: .55 * 10 + 20 = 25.5
|
||||||
|
// Notably, y-axis is reversed between pixel space and range
|
||||||
|
expect(position.getPosition()).toEqual([346, 25.5]);
|
||||||
|
expect(position.getDomain()).toEqual(346);
|
||||||
|
expect(position.getRange()).toEqual(25.5);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("treats a position as undefined if no pan-zoom state is present", function () {
|
||||||
|
var position;
|
||||||
|
|
||||||
|
mockPanZoom.getPanZoom.andReturn({});
|
||||||
|
position = new PlotPosition(1, 2, 100, 100, mockPanZoom);
|
||||||
|
expect(position.getDomain()).toBeUndefined();
|
||||||
|
expect(position.getRange()).toBeUndefined();
|
||||||
|
expect(position.getPosition()).toEqual([]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
@ -8,7 +8,58 @@ define(
|
|||||||
function (PlotPreparer) {
|
function (PlotPreparer) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
var START = 123456;
|
||||||
|
|
||||||
describe("A plot preparer", function () {
|
describe("A plot preparer", function () {
|
||||||
|
|
||||||
|
function makeMockData(scale) {
|
||||||
|
var mockData = jasmine.createSpyObj(
|
||||||
|
"data" + scale,
|
||||||
|
[ "getPointCount", "getDomainValue", "getRangeValue" ]
|
||||||
|
);
|
||||||
|
mockData.getPointCount.andReturn(1000);
|
||||||
|
mockData.getDomainValue.andCallFake(function (i) {
|
||||||
|
return START + i * 1000;
|
||||||
|
});
|
||||||
|
mockData.getRangeValue.andCallFake(function (i) {
|
||||||
|
return Math.sin(i / 100) * scale;
|
||||||
|
});
|
||||||
|
return mockData;
|
||||||
|
}
|
||||||
|
|
||||||
|
it("fits to provided data sets", function () {
|
||||||
|
var datas = [1, 2, 3].map(makeMockData),
|
||||||
|
preparer = new PlotPreparer(datas);
|
||||||
|
|
||||||
|
expect(preparer.getDomainOffset()).toEqual(START);
|
||||||
|
expect(preparer.getOrigin()[0]).toBeCloseTo(START, 3);
|
||||||
|
expect(preparer.getOrigin()[1]).toBeCloseTo(-3, 3);
|
||||||
|
expect(preparer.getDimensions()[0]).toBeCloseTo(999000, 3);
|
||||||
|
expect(preparer.getDimensions()[1]).toBeCloseTo(6, 3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("looks up values using a specified domain and range", function () {
|
||||||
|
var datas = [makeMockData(1)],
|
||||||
|
preparer = new PlotPreparer(datas, "testDomain", "testRange");
|
||||||
|
|
||||||
|
expect(datas[0].getDomainValue).toHaveBeenCalledWith(
|
||||||
|
jasmine.any(Number),
|
||||||
|
"testDomain"
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(datas[0].getRangeValue).toHaveBeenCalledWith(
|
||||||
|
jasmine.any(Number),
|
||||||
|
"testRange"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("provides a default range if data set is flat", function () {
|
||||||
|
var datas = [makeMockData(0)],
|
||||||
|
preparer = new PlotPreparer(datas);
|
||||||
|
|
||||||
|
expect(preparer.getDimensions[1]).not.toEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
@ -9,6 +9,46 @@ define(
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
describe("A plot tick generator", function () {
|
describe("A plot tick generator", function () {
|
||||||
|
var mockPanZoomStack,
|
||||||
|
mockFormatter,
|
||||||
|
generator;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockPanZoomStack = jasmine.createSpyObj(
|
||||||
|
"panZoomStack",
|
||||||
|
[ "getPanZoom" ]
|
||||||
|
);
|
||||||
|
mockFormatter = jasmine.createSpyObj(
|
||||||
|
"formatter",
|
||||||
|
[ "formatDomainValue", "formatRangeValue" ]
|
||||||
|
);
|
||||||
|
|
||||||
|
mockPanZoomStack.getPanZoom.andReturn({
|
||||||
|
origin: [ 0, 0 ],
|
||||||
|
dimensions: [ 100, 100 ]
|
||||||
|
});
|
||||||
|
|
||||||
|
generator =
|
||||||
|
new PlotTickGenerator(mockPanZoomStack, mockFormatter);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("provides tick marks for range", function () {
|
||||||
|
expect(generator.generateRangeTicks(11).length).toEqual(11);
|
||||||
|
|
||||||
|
// Should have used range formatter
|
||||||
|
expect(mockFormatter.formatRangeValue).toHaveBeenCalled();
|
||||||
|
expect(mockFormatter.formatDomainValue).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it("provides tick marks for domain", function () {
|
||||||
|
expect(generator.generateDomainTicks(11).length).toEqual(11);
|
||||||
|
|
||||||
|
// Should have used domain formatter
|
||||||
|
expect(mockFormatter.formatRangeValue).not.toHaveBeenCalled();
|
||||||
|
expect(mockFormatter.formatDomainValue).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
Loading…
x
Reference in New Issue
Block a user