mirror of
https://github.com/nasa/openmct.git
synced 2024-12-19 05:07:52 +00:00
[Plot] Complete specs for plot
Complete specs for transitioned plot view, WTD-533.
This commit is contained in:
parent
2f475fc17a
commit
870172ec6f
@ -13,7 +13,7 @@
|
|||||||
{
|
{
|
||||||
"key": "mctChart",
|
"key": "mctChart",
|
||||||
"implementation": "MCTChart.js",
|
"implementation": "MCTChart.js",
|
||||||
"depends": [ "$interval" ]
|
"depends": [ "$interval", "$log" ]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"controllers": [
|
"controllers": [
|
||||||
|
@ -36,7 +36,7 @@ define(
|
|||||||
buffer;
|
buffer;
|
||||||
|
|
||||||
if (!gl) {
|
if (!gl) {
|
||||||
return false;
|
throw new Error("WebGL unavailable.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize shaders
|
// Initialize shaders
|
||||||
|
@ -14,15 +14,23 @@ define(
|
|||||||
*
|
*
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function MCTChart($interval) {
|
function MCTChart($interval, $log) {
|
||||||
|
|
||||||
function linkChart(scope, element) {
|
function linkChart(scope, element) {
|
||||||
var canvas = element.find("canvas")[0],
|
var canvas = element.find("canvas")[0],
|
||||||
|
chart;
|
||||||
|
|
||||||
|
// Try to initialize GLChart, which allows drawing using WebGL.
|
||||||
|
// This may fail, particularly where browsers do not support
|
||||||
|
// WebGL, so catch that here.
|
||||||
|
try {
|
||||||
chart = new GLChart(canvas);
|
chart = new GLChart(canvas);
|
||||||
|
} catch (e) {
|
||||||
|
$log.warn("Cannot initialize mct-chart; " + e.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
function doDraw() {
|
function doDraw(draw) {
|
||||||
var draw = scope.draw;
|
|
||||||
|
|
||||||
canvas.width = canvas.offsetWidth;
|
canvas.width = canvas.offsetWidth;
|
||||||
canvas.height = canvas.offsetHeight;
|
canvas.height = canvas.offsetHeight;
|
||||||
chart.clear();
|
chart.clear();
|
||||||
@ -57,7 +65,7 @@ define(
|
|||||||
function drawIfResized() {
|
function drawIfResized() {
|
||||||
if (canvas.width !== canvas.offsetWidth ||
|
if (canvas.width !== canvas.offsetWidth ||
|
||||||
canvas.height !== canvas.offsetHeight) {
|
canvas.height !== canvas.offsetHeight) {
|
||||||
doDraw();
|
doDraw(scope.draw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,103 @@ define(
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
describe("A WebGL chart", function () {
|
describe("A WebGL chart", function () {
|
||||||
|
var mockCanvas,
|
||||||
|
mockGL,
|
||||||
|
glChart;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockCanvas = jasmine.createSpyObj("canvas", [ "getContext" ]);
|
||||||
|
mockGL = jasmine.createSpyObj(
|
||||||
|
"gl",
|
||||||
|
[
|
||||||
|
"createShader",
|
||||||
|
"compileShader",
|
||||||
|
"shaderSource",
|
||||||
|
"attachShader",
|
||||||
|
"createProgram",
|
||||||
|
"linkProgram",
|
||||||
|
"useProgram",
|
||||||
|
"enableVertexAttribArray",
|
||||||
|
"getAttribLocation",
|
||||||
|
"getUniformLocation",
|
||||||
|
"createBuffer",
|
||||||
|
"lineWidth",
|
||||||
|
"enable",
|
||||||
|
"blendFunc",
|
||||||
|
"viewport",
|
||||||
|
"clear",
|
||||||
|
"uniform2fv",
|
||||||
|
"uniform4fv",
|
||||||
|
"bufferData",
|
||||||
|
"bindBuffer",
|
||||||
|
"vertexAttribPointer",
|
||||||
|
"drawArrays"
|
||||||
|
]
|
||||||
|
);
|
||||||
|
mockGL.ARRAY_BUFFER = "ARRAY_BUFFER";
|
||||||
|
mockGL.DYNAMIC_DRAW = "DYNAMIC_DRAW";
|
||||||
|
mockGL.TRIANGLE_FAN = "TRIANGLE_FAN";
|
||||||
|
mockGL.LINE_STRIP = "LINE_STRIP";
|
||||||
|
|
||||||
|
// Echo back names for uniform locations, so we can
|
||||||
|
// test which of these are set for certain operations.
|
||||||
|
mockGL.getUniformLocation.andCallFake(function (a, name) {
|
||||||
|
return name;
|
||||||
|
});
|
||||||
|
|
||||||
|
mockCanvas.getContext.andReturn(mockGL);
|
||||||
|
|
||||||
|
glChart = new GLChart(mockCanvas);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("allows the canvas to be cleared", function () {
|
||||||
|
glChart.clear();
|
||||||
|
expect(mockGL.clear).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("doees not construct if WebGL is unavailable", function () {
|
||||||
|
mockCanvas.getContext.andReturn(undefined);
|
||||||
|
expect(function () {
|
||||||
|
return new GLChart(mockCanvas);
|
||||||
|
}).toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("allows dimensions to be set", function () {
|
||||||
|
glChart.setDimensions([120, 120], [0, 10]);
|
||||||
|
expect(mockGL.uniform2fv)
|
||||||
|
.toHaveBeenCalledWith("uDimensions", [120, 120]);
|
||||||
|
expect(mockGL.uniform2fv)
|
||||||
|
.toHaveBeenCalledWith("uOrigin", [0, 10]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("allows lines to be drawn", function () {
|
||||||
|
var testBuffer = [ 0, 1, 3, 8 ],
|
||||||
|
testColor = [ 0.25, 0.33, 0.66, 1.0 ],
|
||||||
|
testPoints = 2;
|
||||||
|
glChart.drawLine(testBuffer, testColor, testPoints);
|
||||||
|
expect(mockGL.bufferData).toHaveBeenCalledWith(
|
||||||
|
mockGL.ARRAY_BUFFER,
|
||||||
|
testBuffer,
|
||||||
|
mockGL.DYNAMIC_DRAW
|
||||||
|
);
|
||||||
|
expect(mockGL.uniform4fv)
|
||||||
|
.toHaveBeenCalledWith("uColor", testColor);
|
||||||
|
expect(mockGL.drawArrays)
|
||||||
|
.toHaveBeenCalledWith("LINE_STRIP", 0, testPoints);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("allows squares to be drawn", function () {
|
||||||
|
var testMin = [0, 1],
|
||||||
|
testMax = [10, 10],
|
||||||
|
testColor = [ 0.25, 0.33, 0.66, 1.0 ];
|
||||||
|
|
||||||
|
glChart.drawSquare(testMin, testMax, testColor);
|
||||||
|
|
||||||
|
expect(mockGL.uniform4fv)
|
||||||
|
.toHaveBeenCalledWith("uColor", testColor);
|
||||||
|
expect(mockGL.drawArrays)
|
||||||
|
.toHaveBeenCalledWith("TRIANGLE_FAN", 0, 4);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
@ -9,6 +9,147 @@ define(
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
describe("The mct-chart directive", function () {
|
describe("The mct-chart directive", function () {
|
||||||
|
var mockInterval,
|
||||||
|
mockLog,
|
||||||
|
mockScope,
|
||||||
|
mockElement,
|
||||||
|
mockCanvas,
|
||||||
|
mockGL,
|
||||||
|
mctChart;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockInterval =
|
||||||
|
jasmine.createSpy("$interval");
|
||||||
|
mockLog =
|
||||||
|
jasmine.createSpyObj("$log", ["warn", "info", "debug"]);
|
||||||
|
mockScope =
|
||||||
|
jasmine.createSpyObj("$scope", ["$watchCollection"]);
|
||||||
|
mockElement =
|
||||||
|
jasmine.createSpyObj("element", ["find"]);
|
||||||
|
|
||||||
|
|
||||||
|
// mct-chart uses GLChart, so it needs WebGL API
|
||||||
|
mockCanvas = jasmine.createSpyObj("canvas", [ "getContext" ]);
|
||||||
|
mockGL = jasmine.createSpyObj(
|
||||||
|
"gl",
|
||||||
|
[
|
||||||
|
"createShader",
|
||||||
|
"compileShader",
|
||||||
|
"shaderSource",
|
||||||
|
"attachShader",
|
||||||
|
"createProgram",
|
||||||
|
"linkProgram",
|
||||||
|
"useProgram",
|
||||||
|
"enableVertexAttribArray",
|
||||||
|
"getAttribLocation",
|
||||||
|
"getUniformLocation",
|
||||||
|
"createBuffer",
|
||||||
|
"lineWidth",
|
||||||
|
"enable",
|
||||||
|
"blendFunc",
|
||||||
|
"viewport",
|
||||||
|
"clear",
|
||||||
|
"uniform2fv",
|
||||||
|
"uniform4fv",
|
||||||
|
"bufferData",
|
||||||
|
"bindBuffer",
|
||||||
|
"vertexAttribPointer",
|
||||||
|
"drawArrays"
|
||||||
|
]
|
||||||
|
);
|
||||||
|
mockGL.ARRAY_BUFFER = "ARRAY_BUFFER";
|
||||||
|
mockGL.DYNAMIC_DRAW = "DYNAMIC_DRAW";
|
||||||
|
mockGL.TRIANGLE_FAN = "TRIANGLE_FAN";
|
||||||
|
mockGL.LINE_STRIP = "LINE_STRIP";
|
||||||
|
|
||||||
|
// Echo back names for uniform locations, so we can
|
||||||
|
// test which of these are set for certain operations.
|
||||||
|
mockGL.getUniformLocation.andCallFake(function (a, name) {
|
||||||
|
return name;
|
||||||
|
});
|
||||||
|
|
||||||
|
mockElement.find.andReturn([mockCanvas]);
|
||||||
|
mockCanvas.getContext.andReturn(mockGL);
|
||||||
|
|
||||||
|
mctChart = new MCTChart(mockInterval, mockLog);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("is applicable at the element level", function () {
|
||||||
|
expect(mctChart.restrict).toEqual("E");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("places a 'draw' attribute in-scope", function () {
|
||||||
|
// Should ask Angular for the draw attribute
|
||||||
|
expect(mctChart.scope.draw).toEqual("=");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("watches for changes in the drawn object", function () {
|
||||||
|
mctChart.link(mockScope, mockElement);
|
||||||
|
expect(mockScope.$watchCollection)
|
||||||
|
.toHaveBeenCalledWith("draw", jasmine.any(Function));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("issues one draw call per line", function () {
|
||||||
|
mctChart.link(mockScope, mockElement);
|
||||||
|
mockScope.$watchCollection.mostRecentCall.args[1]({
|
||||||
|
lines: [ {}, {}, {} ]
|
||||||
|
});
|
||||||
|
expect(mockGL.drawArrays.calls.length).toEqual(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("issues one draw call per box", function () {
|
||||||
|
mctChart.link(mockScope, mockElement);
|
||||||
|
mockScope.$watchCollection.mostRecentCall.args[1]({
|
||||||
|
boxes: [
|
||||||
|
{ start: [0, 0], end: [1, 1] },
|
||||||
|
{ start: [0, 0], end: [1, 1] },
|
||||||
|
{ start: [0, 0], end: [1, 1] },
|
||||||
|
{ start: [0, 0], end: [1, 1] }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
expect(mockGL.drawArrays.calls.length).toEqual(4);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not fail if no draw object is in scope", function () {
|
||||||
|
mctChart.link(mockScope, mockElement);
|
||||||
|
expect(mockScope.$watchCollection.mostRecentCall.args[1])
|
||||||
|
.not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("draws on canvas resize", function () {
|
||||||
|
mctChart.link(mockScope, mockElement);
|
||||||
|
|
||||||
|
// Should track canvas size in an interval
|
||||||
|
expect(mockInterval).toHaveBeenCalledWith(
|
||||||
|
jasmine.any(Function),
|
||||||
|
jasmine.any(Number)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify pre-condition
|
||||||
|
expect(mockGL.clear).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
mockCanvas.width = 100;
|
||||||
|
mockCanvas.offsetWidth = 150;
|
||||||
|
mockCanvas.height = 200;
|
||||||
|
mockCanvas.offsetHeight = 200;
|
||||||
|
mockInterval.mostRecentCall.args[0]();
|
||||||
|
|
||||||
|
// Use clear as an indication that drawing has occurred
|
||||||
|
expect(mockGL.clear).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("warns if no WebGL context is available", function () {
|
||||||
|
mockCanvas.getContext.andReturn(undefined);
|
||||||
|
mctChart.link(mockScope, mockElement);
|
||||||
|
expect(mockLog.warn).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("logs nothing in nominal situations (WebGL available)", function () {
|
||||||
|
// Complement the previous test
|
||||||
|
mctChart.link(mockScope, mockElement);
|
||||||
|
expect(mockLog.warn).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
Loading…
Reference in New Issue
Block a user