Compare commits
	
		
			12 Commits
		
	
	
		
			plot-perfo
			...
			vista-r34.
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					c869b42982 | ||
| 
						 | 
					0a4879d938 | ||
| 
						 | 
					7d8987422d | ||
| 
						 | 
					761064f487 | ||
| 
						 | 
					9f640c24fb | ||
| 
						 | 
					5e3ca00b2a | ||
| 
						 | 
					1283c1a4c7 | ||
| 
						 | 
					41e9e97a71 | ||
| 
						 | 
					27eabdd867 | ||
| 
						 | 
					2ebb5d2cf0 | ||
| 
						 | 
					9a537e2e0d | ||
| 
						 | 
					8eec5062b4 | 
@@ -30,7 +30,8 @@ define([
 | 
			
		||||
        amplitude: 1,
 | 
			
		||||
        period: 10,
 | 
			
		||||
        offset: 0,
 | 
			
		||||
        dataRateInHz: 1
 | 
			
		||||
        dataRateInHz: 1,
 | 
			
		||||
        phase: 0
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    function GeneratorProvider() {
 | 
			
		||||
@@ -50,9 +51,12 @@ define([
 | 
			
		||||
            'amplitude',
 | 
			
		||||
            'period',
 | 
			
		||||
            'offset',
 | 
			
		||||
            'dataRateInHz'
 | 
			
		||||
            'dataRateInHz',
 | 
			
		||||
            'phase',
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        request = request || {};
 | 
			
		||||
 | 
			
		||||
        var workerRequest = {};
 | 
			
		||||
 | 
			
		||||
        props.forEach(function (prop) {
 | 
			
		||||
@@ -67,7 +71,7 @@ define([
 | 
			
		||||
            }
 | 
			
		||||
            workerRequest[prop] = Number(workerRequest[prop]);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        workerRequest.name = domainObject.name;
 | 
			
		||||
        return workerRequest;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										80
									
								
								example/generator/StateGeneratorProvider.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								example/generator/StateGeneratorProvider.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,80 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
 | 
			
		||||
], function (
 | 
			
		||||
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    function StateGeneratorProvider() {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function pointForTimestamp(timestamp, duration, name) {
 | 
			
		||||
        return {
 | 
			
		||||
            name: name,
 | 
			
		||||
            utc: Math.floor(timestamp / duration) * duration,
 | 
			
		||||
            value: Math.floor(timestamp / duration) % 2
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    StateGeneratorProvider.prototype.supportsSubscribe = function (domainObject) {
 | 
			
		||||
        return domainObject.type === 'example.state-generator';
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    StateGeneratorProvider.prototype.subscribe = function (domainObject, callback) {
 | 
			
		||||
        var duration = domainObject.telemetry.duration * 1000;
 | 
			
		||||
 | 
			
		||||
        var interval = setInterval(function () {
 | 
			
		||||
            var now = Date.now();
 | 
			
		||||
            callback(pointForTimestamp(now, duration, domainObject.name));
 | 
			
		||||
        }, duration);
 | 
			
		||||
 | 
			
		||||
        return function () {
 | 
			
		||||
            clearInterval(interval);
 | 
			
		||||
        };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    StateGeneratorProvider.prototype.supportsRequest = function (domainObject, options) {
 | 
			
		||||
        return domainObject.type === 'example.state-generator';
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    StateGeneratorProvider.prototype.request = function (domainObject, options) {
 | 
			
		||||
        var start = options.start;
 | 
			
		||||
        var end = options.end;
 | 
			
		||||
        var duration = domainObject.telemetry.duration * 1000;
 | 
			
		||||
        if (options.strategy === 'latest' || options.size === 1) {
 | 
			
		||||
            start = end;
 | 
			
		||||
        }
 | 
			
		||||
        var data = [];
 | 
			
		||||
        while (start <= end && data.length < 5000) {
 | 
			
		||||
            data.push(pointForTimestamp(start, duration, domainObject.name));
 | 
			
		||||
            start += 5000;
 | 
			
		||||
        }
 | 
			
		||||
        return Promise.resolve(data);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return StateGeneratorProvider;
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
@@ -62,10 +62,11 @@
 | 
			
		||||
                self.postMessage({
 | 
			
		||||
                    id: message.id,
 | 
			
		||||
                    data: {
 | 
			
		||||
                        name: data.name,
 | 
			
		||||
                        utc: nextStep,
 | 
			
		||||
                        yesterday: nextStep - 60*60*24*1000,
 | 
			
		||||
                        sin: sin(nextStep, data.period, data.amplitude, data.offset),
 | 
			
		||||
                        cos: cos(nextStep, data.period, data.amplitude, data.offset)
 | 
			
		||||
                        sin: sin(nextStep, data.period, data.amplitude, data.offset, data.phase),
 | 
			
		||||
                        cos: cos(nextStep, data.period, data.amplitude, data.offset, data.phase)
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
                nextStep += step;
 | 
			
		||||
@@ -82,21 +83,22 @@
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function onRequest(message) {
 | 
			
		||||
        var data = message.data;
 | 
			
		||||
        if (data.end == undefined) {
 | 
			
		||||
            data.end = Date.now();
 | 
			
		||||
        var request = message.data;
 | 
			
		||||
        if (request.end == undefined) {
 | 
			
		||||
            request.end = Date.now();
 | 
			
		||||
        }
 | 
			
		||||
        if (data.start == undefined){
 | 
			
		||||
            data.start = data.end - FIFTEEN_MINUTES;
 | 
			
		||||
        if (request.start == undefined){
 | 
			
		||||
            request.start = request.end - FIFTEEN_MINUTES;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var now = Date.now();
 | 
			
		||||
        var start = data.start;
 | 
			
		||||
        var end = data.end > now ? now : data.end;
 | 
			
		||||
        var amplitude = data.amplitude;
 | 
			
		||||
        var period = data.period;
 | 
			
		||||
        var offset = data.offset;
 | 
			
		||||
        var dataRateInHz = data.dataRateInHz;
 | 
			
		||||
        var start = request.start;
 | 
			
		||||
        var end = request.end > now ? now : request.end;
 | 
			
		||||
        var amplitude = request.amplitude;
 | 
			
		||||
        var period = request.period;
 | 
			
		||||
        var offset = request.offset;
 | 
			
		||||
        var dataRateInHz = request.dataRateInHz;
 | 
			
		||||
        var phase = request.phase;
 | 
			
		||||
 | 
			
		||||
        var step = 1000 / dataRateInHz;
 | 
			
		||||
        var nextStep = start - (start % step) + step;
 | 
			
		||||
@@ -105,10 +107,11 @@
 | 
			
		||||
 | 
			
		||||
        for (; nextStep < end && data.length < 5000; nextStep += step) {
 | 
			
		||||
            data.push({
 | 
			
		||||
                name: request.name,
 | 
			
		||||
                utc: nextStep,
 | 
			
		||||
                yesterday: nextStep - 60*60*24*1000,
 | 
			
		||||
                sin: sin(nextStep, period, amplitude, offset),
 | 
			
		||||
                cos: cos(nextStep, period, amplitude, offset)
 | 
			
		||||
                sin: sin(nextStep, period, amplitude, offset, phase),
 | 
			
		||||
                cos: cos(nextStep, period, amplitude, offset, phase)
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        self.postMessage({
 | 
			
		||||
@@ -117,14 +120,14 @@
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function cos(timestamp, period, amplitude, offset) {
 | 
			
		||||
    function cos(timestamp, period, amplitude, offset, phase) {
 | 
			
		||||
        return amplitude *
 | 
			
		||||
            Math.cos(timestamp / period / 1000 * Math.PI * 2) + offset;
 | 
			
		||||
            Math.cos(phase + (timestamp / period / 1000 * Math.PI * 2)) + offset;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function sin(timestamp, period, amplitude, offset) {
 | 
			
		||||
    function sin(timestamp, period, amplitude, offset, phase) {
 | 
			
		||||
        return amplitude *
 | 
			
		||||
            Math.sin(timestamp / period / 1000 * Math.PI * 2) + offset;
 | 
			
		||||
            Math.sin(phase + (timestamp / period / 1000 * Math.PI * 2)) + offset;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function sendError(error, message) {
 | 
			
		||||
 
 | 
			
		||||
@@ -23,10 +23,12 @@
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    "./GeneratorProvider",
 | 
			
		||||
    "./SinewaveLimitCapability"
 | 
			
		||||
    "./SinewaveLimitCapability",
 | 
			
		||||
    "./StateGeneratorProvider"
 | 
			
		||||
], function (
 | 
			
		||||
    GeneratorProvider,
 | 
			
		||||
    SinewaveLimitCapability
 | 
			
		||||
    SinewaveLimitCapability,
 | 
			
		||||
    StateGeneratorProvider
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    var legacyExtensions = {
 | 
			
		||||
@@ -46,6 +48,75 @@ define([
 | 
			
		||||
                openmct.legacyExtension(type, extension)
 | 
			
		||||
            })
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        openmct.types.addType("example.state-generator", {
 | 
			
		||||
            name: "State Generator",
 | 
			
		||||
            description: "For development use.  Generates test enumerated telemetry by cycling through a given set of states",
 | 
			
		||||
            cssClass: "icon-telemetry",
 | 
			
		||||
            creatable: true,
 | 
			
		||||
            form: [
 | 
			
		||||
                {
 | 
			
		||||
                    name: "State Duration (seconds)",
 | 
			
		||||
                    control: "textfield",
 | 
			
		||||
                    cssClass: "l-input-sm l-numeric",
 | 
			
		||||
                    key: "duration",
 | 
			
		||||
                    required: true,
 | 
			
		||||
                    property: [
 | 
			
		||||
                        "telemetry",
 | 
			
		||||
                        "duration"
 | 
			
		||||
                    ],
 | 
			
		||||
                    pattern: "^\\d*(\\.\\d*)?$"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            initialize: function (object) {
 | 
			
		||||
                object.telemetry = {
 | 
			
		||||
                    duration: 5,
 | 
			
		||||
                    values: [
 | 
			
		||||
                        {
 | 
			
		||||
                            key: "name",
 | 
			
		||||
                            name: "Name"
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            key: "utc",
 | 
			
		||||
                            name: "Time",
 | 
			
		||||
                            format: "utc",
 | 
			
		||||
                            hints: {
 | 
			
		||||
                                domain: 1
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            key: "state",
 | 
			
		||||
                            source: "value",
 | 
			
		||||
                            name: "State",
 | 
			
		||||
                            format: "enum",
 | 
			
		||||
                            enumerations: [
 | 
			
		||||
                                {
 | 
			
		||||
                                    value: 0,
 | 
			
		||||
                                    string: "OFF"
 | 
			
		||||
                                },
 | 
			
		||||
                                {
 | 
			
		||||
                                    value: 1,
 | 
			
		||||
                                    string: "ON"
 | 
			
		||||
                                }
 | 
			
		||||
                            ],
 | 
			
		||||
                            hints: {
 | 
			
		||||
                                range: 1
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            key: "value",
 | 
			
		||||
                            name: "Value",
 | 
			
		||||
                            hints: {
 | 
			
		||||
                                range: 2
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        openmct.telemetry.addProvider(new StateGeneratorProvider());
 | 
			
		||||
 | 
			
		||||
        openmct.types.addType("generator", {
 | 
			
		||||
            name: "Sine Wave Generator",
 | 
			
		||||
            description: "For development use. Generates example streaming telemetry data using a simple sine wave algorithm.",
 | 
			
		||||
@@ -99,6 +170,18 @@ define([
 | 
			
		||||
                        "dataRateInHz"
 | 
			
		||||
                    ],
 | 
			
		||||
                    pattern: "^\\d*(\\.\\d*)?$"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    name: "Phase (radians)",
 | 
			
		||||
                    control: "textfield",
 | 
			
		||||
                    cssClass: "l-input-sm l-numeric",
 | 
			
		||||
                    key: "phase",
 | 
			
		||||
                    required: true,
 | 
			
		||||
                    property: [
 | 
			
		||||
                        "telemetry",
 | 
			
		||||
                        "phase"
 | 
			
		||||
                    ],
 | 
			
		||||
                    pattern: "^\\d*(\\.\\d*)?$"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            initialize: function (object) {
 | 
			
		||||
@@ -107,7 +190,12 @@ define([
 | 
			
		||||
                    amplitude: 1,
 | 
			
		||||
                    offset: 0,
 | 
			
		||||
                    dataRateInHz: 1,
 | 
			
		||||
                    phase: 0,
 | 
			
		||||
                    values: [
 | 
			
		||||
                        {
 | 
			
		||||
                            key: "name",
 | 
			
		||||
                            name: "Name"
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            key: "utc",
 | 
			
		||||
                            name: "Time",
 | 
			
		||||
@@ -127,6 +215,8 @@ define([
 | 
			
		||||
                        {
 | 
			
		||||
                            key: "sin",
 | 
			
		||||
                            name: "Sine",
 | 
			
		||||
                            format: 'printf',
 | 
			
		||||
                            sprintf: '%0.2f',
 | 
			
		||||
                            hints: {
 | 
			
		||||
                                range: 1
 | 
			
		||||
                            }
 | 
			
		||||
@@ -134,6 +224,8 @@ define([
 | 
			
		||||
                        {
 | 
			
		||||
                            key: "cos",
 | 
			
		||||
                            name: "Cosine",
 | 
			
		||||
                            format: 'printf',
 | 
			
		||||
                            sprintf: '%0.2f',
 | 
			
		||||
                            hints: {
 | 
			
		||||
                                range: 2
 | 
			
		||||
                            }
 | 
			
		||||
@@ -142,6 +234,7 @@ define([
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        openmct.telemetry.addProvider(new GeneratorProvider());
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -48,8 +48,9 @@ define([
 | 
			
		||||
                "https://www.hq.nasa.gov/alsj/a16/AS16-117-18748.jpg"
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
        function pointForTimestamp(timestamp) {
 | 
			
		||||
        function pointForTimestamp(timestamp, name) {
 | 
			
		||||
            return {
 | 
			
		||||
                name: name,
 | 
			
		||||
                utc: Math.floor(timestamp / 5000) * 5000,
 | 
			
		||||
                url: IMAGE_SAMPLES[Math.floor(timestamp / 5000) % IMAGE_SAMPLES.length]
 | 
			
		||||
            };
 | 
			
		||||
@@ -61,7 +62,7 @@ define([
 | 
			
		||||
            },
 | 
			
		||||
            subscribe: function (domainObject, callback) {
 | 
			
		||||
                var interval = setInterval(function () {
 | 
			
		||||
                    callback(pointForTimestamp(Date.now()));
 | 
			
		||||
                    callback(pointForTimestamp(Date.now(), domainObject.name));
 | 
			
		||||
                }, 5000);
 | 
			
		||||
 | 
			
		||||
                return function (interval) {
 | 
			
		||||
@@ -79,8 +80,8 @@ define([
 | 
			
		||||
                var start = options.start;
 | 
			
		||||
                var end = options.end;
 | 
			
		||||
                var data = [];
 | 
			
		||||
                while (start < end && data.length < 5000) {
 | 
			
		||||
                    data.push(pointForTimestamp(start));
 | 
			
		||||
                while (start <= end && data.length < 5000) {
 | 
			
		||||
                    data.push(pointForTimestamp(start, domainObject.name));
 | 
			
		||||
                    start += 5000;
 | 
			
		||||
                }
 | 
			
		||||
                return Promise.resolve(data);
 | 
			
		||||
@@ -93,7 +94,7 @@ define([
 | 
			
		||||
                    options.strategy === 'latest';
 | 
			
		||||
            },
 | 
			
		||||
            request: function (domainObject, options) {
 | 
			
		||||
                return Promise.resolve([pointForTimestamp(Date.now())]);
 | 
			
		||||
                return Promise.resolve([pointForTimestamp(Date.now(), domainObject.name)]);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@@ -109,6 +110,10 @@ define([
 | 
			
		||||
                initialize: function (object) {
 | 
			
		||||
                    object.telemetry = {
 | 
			
		||||
                        values: [
 | 
			
		||||
                            {
 | 
			
		||||
                                name: 'Name',
 | 
			
		||||
                                key: 'name'
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                name: 'Time',
 | 
			
		||||
                                key: 'utc',
 | 
			
		||||
 
 | 
			
		||||
@@ -58,11 +58,7 @@
 | 
			
		||||
        position: relative;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .w-mct-example {
 | 
			
		||||
        div {
 | 
			
		||||
            margin-bottom: $interiorMarginLg;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    .w-mct-example > div { margin-bottom: $interiorMarginLg; }
 | 
			
		||||
 | 
			
		||||
    code,
 | 
			
		||||
    pre {
 | 
			
		||||
 
 | 
			
		||||
@@ -49,7 +49,8 @@ requirejs.config({
 | 
			
		||||
        "d3-format": "node_modules/d3-format/build/d3-format.min",
 | 
			
		||||
        "d3-interpolate": "node_modules/d3-interpolate/build/d3-interpolate.min",
 | 
			
		||||
        "d3-time": "node_modules/d3-time/build/d3-time.min",
 | 
			
		||||
        "d3-time-format": "node_modules/d3-time-format/build/d3-time-format.min"
 | 
			
		||||
        "d3-time-format": "node_modules/d3-time-format/build/d3-time-format.min",
 | 
			
		||||
        "printj": "node_modules/printj/dist/printj.min"
 | 
			
		||||
    },
 | 
			
		||||
    "shim": {
 | 
			
		||||
        "angular": {
 | 
			
		||||
 
 | 
			
		||||
@@ -49,6 +49,7 @@
 | 
			
		||||
    "mkdirp": "^0.5.1",
 | 
			
		||||
    "moment": "^2.11.1",
 | 
			
		||||
    "node-bourbon": "^4.2.3",
 | 
			
		||||
    "printj": "^1.1.0",
 | 
			
		||||
    "requirejs": "2.1.x",
 | 
			
		||||
    "split": "^1.0.0"
 | 
			
		||||
  },
 | 
			
		||||
 
 | 
			
		||||
@@ -99,7 +99,7 @@ $plotXBarH: 32px;
 | 
			
		||||
$plotLegendH: 20px;
 | 
			
		||||
$plotSwatchD: 8px;
 | 
			
		||||
// 1: Top, 2: right, 3: bottom, 4: left
 | 
			
		||||
$plotDisplayArea: ($plotLegendH + $interiorMargin, 0, $plotXBarH, $plotYBarW);
 | 
			
		||||
$plotDisplayArea: (0, 0, $plotXBarH, $plotYBarW);
 | 
			
		||||
/* min plot height is based on user testing to find minimum useful height */
 | 
			
		||||
$plotMinH: 95px;
 | 
			
		||||
/*************** Bubbles */
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,7 @@
 | 
			
		||||
    * Use https://icomoon.io/app with icomoon-project-openmct-symbols-12px.json
 | 
			
		||||
    * to generate font files
 | 
			
		||||
    */
 | 
			
		||||
    font-family: 'symbolsfont 12px';
 | 
			
		||||
    font-family: 'symbolsfont-12px';
 | 
			
		||||
    src: url($dirCommonRes + 'fonts/symbols/openmct-symbols-12px.eot');
 | 
			
		||||
    src: url($dirCommonRes + 'fonts/symbols/openmct-symbols-12px.eot?#iefix') format('embedded-opentype'),
 | 
			
		||||
    url($dirCommonRes + 'fonts/symbols/openmct-symbols-12px.woff') format('woff'),
 | 
			
		||||
@@ -248,6 +248,12 @@ a.disabled {
 | 
			
		||||
    color: rgba(#fff, 0.2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comma-list span {
 | 
			
		||||
    &:not(:first-child) {
 | 
			
		||||
        &:before { content: ', '; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.test-stripes {
 | 
			
		||||
    @include bgDiagonalStripes();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -44,6 +44,12 @@
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.t-alert-unsynced {
 | 
			
		||||
    @extend .icon-alert-triangle;
 | 
			
		||||
    color: $colorPausedBg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.bar .ui-symbol {
 | 
			
		||||
	display: inline-block;
 | 
			
		||||
}
 | 
			
		||||
@@ -81,18 +87,5 @@
 | 
			
		||||
            @include transform(scale(0.3));
 | 
			
		||||
            z-index: 2;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
/*        .t-item-icon-glyph {
 | 
			
		||||
            &:after {
 | 
			
		||||
                color: $colorIconLink;
 | 
			
		||||
                content: '\e921'; //$glyph-icon-link;
 | 
			
		||||
                height: auto; width: auto;
 | 
			
		||||
                position: absolute;
 | 
			
		||||
                left: 0; top: 0; right: 0; bottom: 20%;
 | 
			
		||||
                @include transform-origin(bottom left);
 | 
			
		||||
                @include transform(scale(0.3));
 | 
			
		||||
                z-index: 2;
 | 
			
		||||
            }
 | 
			
		||||
        }*/
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -53,6 +53,7 @@
 | 
			
		||||
    .l-inspector-part {
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        padding-right: $interiorMargin;
 | 
			
		||||
 | 
			
		||||
        .tree .form {
 | 
			
		||||
            margin-left: $treeVCW + $interiorMarginLg;
 | 
			
		||||
        }
 | 
			
		||||
@@ -78,6 +79,7 @@
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            .form-row {
 | 
			
		||||
                // To be replaced with .inspector-config, see below.
 | 
			
		||||
                @include align-items(center);
 | 
			
		||||
                border: none !important;
 | 
			
		||||
                margin-bottom: 0 !important;
 | 
			
		||||
@@ -99,15 +101,12 @@
 | 
			
		||||
        position: relative;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ul li {
 | 
			
		||||
        margin-bottom: $interiorMarginLg;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    em.t-inspector-part-header {
 | 
			
		||||
        border-radius: $basicCr;
 | 
			
		||||
        background-color: $colorInspectorSectionHeaderBg;
 | 
			
		||||
        color: $colorInspectorSectionHeaderFg;
 | 
			
		||||
        margin-bottom: $interiorMargin;
 | 
			
		||||
        margin-top: $interiorMarginLg;
 | 
			
		||||
        //margin-bottom: $interiorMargin;
 | 
			
		||||
        padding: floor($formTBPad * .75) $formLRPad;
 | 
			
		||||
        text-transform: uppercase;
 | 
			
		||||
    }
 | 
			
		||||
@@ -201,3 +200,102 @@ mct-representation:not(.s-status-editing) .l-inspect {
 | 
			
		||||
        pointer-events: inherit;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NEW COMPACT FORM, FOR USE IN INSPECTOR
 | 
			
		||||
// ul > li > label, control
 | 
			
		||||
// Make a new UL for each form section
 | 
			
		||||
// Allow control-first, controls-below
 | 
			
		||||
 | 
			
		||||
.l-inspect .tree ul li,
 | 
			
		||||
.inspector-config ul li {
 | 
			
		||||
    padding: 2px 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.inspector-config {
 | 
			
		||||
    $labelW: 40%;
 | 
			
		||||
    $minW: $labelW;
 | 
			
		||||
    ul {
 | 
			
		||||
        margin-bottom: $interiorMarginLg;
 | 
			
		||||
        li {
 | 
			
		||||
            @include display(flex);
 | 
			
		||||
            @include flex-wrap(wrap);
 | 
			
		||||
            @include align-items(center);
 | 
			
		||||
            label,
 | 
			
		||||
            .control {
 | 
			
		||||
                @include display(flex);
 | 
			
		||||
                min-width: $minW;
 | 
			
		||||
            }
 | 
			
		||||
            label {
 | 
			
		||||
                line-height: inherit;
 | 
			
		||||
                padding: $interiorMarginSm 0;
 | 
			
		||||
                width: $labelW;
 | 
			
		||||
            }
 | 
			
		||||
            .control {
 | 
			
		||||
                @include flex-grow(1);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &:not(.section-header) {
 | 
			
		||||
                &:not(.connects-to-previous) {
 | 
			
		||||
                    //border-top: 1px solid $colorFormLines;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &.connects-to-previous {
 | 
			
		||||
                padding-top: 0 !important;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &.section-header {
 | 
			
		||||
                margin-top: $interiorMarginLg;
 | 
			
		||||
                border-top: 1px solid $colorFormLines;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &.controls-first {
 | 
			
		||||
                .control {
 | 
			
		||||
                    @include flex-grow(0);
 | 
			
		||||
                    margin-right: $interiorMargin;
 | 
			
		||||
                    min-width: 0;
 | 
			
		||||
                    order: 1;
 | 
			
		||||
                    width: auto;
 | 
			
		||||
                }
 | 
			
		||||
                label {
 | 
			
		||||
                    @include flex-grow(1);
 | 
			
		||||
                    order: 2;
 | 
			
		||||
                    width: auto;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            &.controls-under {
 | 
			
		||||
                display: block;
 | 
			
		||||
                .control, label {
 | 
			
		||||
                    display: block;
 | 
			
		||||
                    width: auto;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                ul li {
 | 
			
		||||
                    border-top: none !important;
 | 
			
		||||
                    padding: 0;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .form-error {
 | 
			
		||||
        // Block element that visually flags an error and contains a message
 | 
			
		||||
        background-color: $colorFormFieldErrorBg;
 | 
			
		||||
        color: $colorFormFieldErrorFg;
 | 
			
		||||
        border-radius: $basicCr;
 | 
			
		||||
        display: block;
 | 
			
		||||
        padding: 1px 6px;
 | 
			
		||||
        &:before {
 | 
			
		||||
            content: $glyph-icon-alert-triangle;
 | 
			
		||||
            display: inline;
 | 
			
		||||
            font-family: symbolsfont;
 | 
			
		||||
            margin-right: $interiorMarginSm;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tree .inspector-config {
 | 
			
		||||
    margin-left: $treeVCW + $interiorMarginLg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -70,6 +70,7 @@
 | 
			
		||||
@import "fixed-position";
 | 
			
		||||
@import "lists/tabular";
 | 
			
		||||
@import "plots/plots-main";
 | 
			
		||||
@import "plots/legend";
 | 
			
		||||
@import "iframe";
 | 
			
		||||
@import "views";
 | 
			
		||||
@import "items/item";
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.l-view-section {
 | 
			
		||||
    //@include test(orange, 0.1);
 | 
			
		||||
	@include absPosDefault(0);
 | 
			
		||||
	h2 {
 | 
			
		||||
		color: #fff;
 | 
			
		||||
 
 | 
			
		||||
@@ -150,6 +150,26 @@
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******************************************************** VIEW CONTROLS */
 | 
			
		||||
// Expand/collapse > and v arrows, used in tree and plot legend
 | 
			
		||||
// Moved this over from a tree-only context 5/18/17
 | 
			
		||||
 | 
			
		||||
.view-control {
 | 
			
		||||
    @extend .ui-symbol;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    height: 1em; width: 1em;
 | 
			
		||||
    line-height: inherit;
 | 
			
		||||
    &:before {
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        @include trans-prop-nice(transform, 100ms);
 | 
			
		||||
        content: $glyph-icon-arrow-right;
 | 
			
		||||
        @include transform-origin(center);
 | 
			
		||||
    }
 | 
			
		||||
    &.expanded:before {
 | 
			
		||||
        @include transform(rotate(90deg));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******************************************************** CUSTOM CHECKBOXES */
 | 
			
		||||
label.checkbox.custom,
 | 
			
		||||
label.radio.custom {
 | 
			
		||||
 
 | 
			
		||||
@@ -398,10 +398,6 @@ body.desktop .t-message-list {
 | 
			
		||||
    .object-header {
 | 
			
		||||
        .t-object-alert {
 | 
			
		||||
            display: inline;
 | 
			
		||||
            &.t-alert-unsynced {
 | 
			
		||||
                @extend .icon-alert-triangle;
 | 
			
		||||
                color: $colorPausedBg;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,53 +20,70 @@
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
.l-palette {
 | 
			
		||||
	$d: 16px;
 | 
			
		||||
	$colorsPerRow: 10;
 | 
			
		||||
	$m: 1;
 | 
			
		||||
 | 
			
		||||
	box-sizing: border-box;
 | 
			
		||||
	padding: $interiorMargin !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	.l-palette-row {
 | 
			
		||||
		@include clearfix;
 | 
			
		||||
		line-height: $d;
 | 
			
		||||
		width: ($d * $colorsPerRow) + ($m * $colorsPerRow);
 | 
			
		||||
.l-palette-row {
 | 
			
		||||
    $d: 16px;
 | 
			
		||||
    $m: 1;
 | 
			
		||||
    $colorsPerRow: 10;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-wrap: wrap;
 | 
			
		||||
    line-height: $d;
 | 
			
		||||
    width: ($d * $colorsPerRow) + ($m * $colorsPerRow);
 | 
			
		||||
 | 
			
		||||
        &.l-option-row {
 | 
			
		||||
            margin-bottom: $interiorMargin;
 | 
			
		||||
            .s-palette-item {
 | 
			
		||||
                border-color: $colorPaletteFg;
 | 
			
		||||
    &.l-option-row {
 | 
			
		||||
        margin-bottom: $interiorMargin;
 | 
			
		||||
        .s-palette-item {
 | 
			
		||||
            border-color: $colorPaletteFg;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .l-palette-item {
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        display: block;
 | 
			
		||||
        height: $d; width: $d;
 | 
			
		||||
        min-width: $d;
 | 
			
		||||
        line-height: $d * 0.9;
 | 
			
		||||
        margin: 0 ($m * 1px) ($m * 1px) 0;
 | 
			
		||||
        position: relative;
 | 
			
		||||
        text-align: center;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.s-palette-item {
 | 
			
		||||
    border: 1px solid transparent;
 | 
			
		||||
    color: $colorPaletteFg;
 | 
			
		||||
    text-shadow: $shdwPaletteFg;
 | 
			
		||||
    @include trans-prop-nice-fade(0.25s);
 | 
			
		||||
    &:hover {
 | 
			
		||||
        @include trans-prop-nice-fade(0);
 | 
			
		||||
        border-color: $colorPaletteSelected !important;
 | 
			
		||||
    }
 | 
			
		||||
    &.selected {
 | 
			
		||||
        border-color: $colorPaletteSelected;
 | 
			
		||||
        box-shadow: $shdwPaletteSelected; //Needed to see selection rect on light colored swatches
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.l-palette-item-label {
 | 
			
		||||
    margin-left: $interiorMargin;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.l-inline-palette {
 | 
			
		||||
    .l-palette-row {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        .l-palette-item {
 | 
			
		||||
            //@include display(flex);
 | 
			
		||||
            @include flex(1 0 auto);
 | 
			
		||||
            margin: 1px;
 | 
			
		||||
            min-width: auto;
 | 
			
		||||
            width: auto;
 | 
			
		||||
            &:before {
 | 
			
		||||
                content: '';
 | 
			
		||||
                padding-top: 75%;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		.l-palette-item {
 | 
			
		||||
			box-sizing: border-box;
 | 
			
		||||
			display: block;
 | 
			
		||||
			float: left;
 | 
			
		||||
			height: $d; width: $d;
 | 
			
		||||
			line-height: $d * 0.9;
 | 
			
		||||
			margin: 0 ($m * 1px) ($m * 1px) 0;
 | 
			
		||||
            position: relative;
 | 
			
		||||
			text-align: center;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		.s-palette-item {
 | 
			
		||||
            border: 1px solid transparent;
 | 
			
		||||
            color: $colorPaletteFg;
 | 
			
		||||
            text-shadow: $shdwPaletteFg;
 | 
			
		||||
            @include trans-prop-nice-fade(0.25s);
 | 
			
		||||
			&:hover {
 | 
			
		||||
				@include trans-prop-nice-fade(0);
 | 
			
		||||
				border-color: $colorPaletteSelected !important;
 | 
			
		||||
			}
 | 
			
		||||
            &.selected {
 | 
			
		||||
                border-color: $colorPaletteSelected;
 | 
			
		||||
                box-shadow: $shdwPaletteSelected; //Needed to see selection rect on light colored swatches
 | 
			
		||||
            }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		.l-palette-item-label {
 | 
			
		||||
			margin-left: $interiorMargin;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -34,18 +34,7 @@ body.touch {
 | 
			
		||||
		line-height: $mobileTreeItemH !important;
 | 
			
		||||
		.view-control {
 | 
			
		||||
            font-size: 1em;
 | 
			
		||||
            margin-right: $interiorMargin;
 | 
			
		||||
            width: ceil($mobileTreeItemH * 0.75);
 | 
			
		||||
            &.has-children {
 | 
			
		||||
                &:before {
 | 
			
		||||
                    content: $glyph-icon-arrow-down;
 | 
			
		||||
                    left: 50%;
 | 
			
		||||
                    @include transform(translateX(-50%) rotate(-90deg));
 | 
			
		||||
                }
 | 
			
		||||
                &.expanded:before {
 | 
			
		||||
                    @include transform(translateX(-50%) rotate(0deg));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            width: ceil($mobileTreeItemH * 0.5);
 | 
			
		||||
		}
 | 
			
		||||
		.t-object-label {
 | 
			
		||||
			line-height: inherit;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										208
									
								
								platform/commonUI/general/res/sass/plots/_legend.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										208
									
								
								platform/commonUI/general/res/sass/plots/_legend.scss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,208 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
.gl-plot {
 | 
			
		||||
    .gl-plot-legend {
 | 
			
		||||
        min-height: $plotLegendH;
 | 
			
		||||
 | 
			
		||||
        .view-control {
 | 
			
		||||
            font-size: 1em;
 | 
			
		||||
            margin-right: $interiorMarginSm;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        table {
 | 
			
		||||
            table-layout: fixed;
 | 
			
		||||
            tr {
 | 
			
		||||
                display: table-row;
 | 
			
		||||
            }
 | 
			
		||||
            th,
 | 
			
		||||
            td {
 | 
			
		||||
                @include ellipsize(); // Note: this won't work if table-layout uses anything other than fixed.
 | 
			
		||||
                display: table-cell;
 | 
			
		||||
                padding: 1px 3px; // Tighter than standard tabular padding
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &.hover-on-plot {
 | 
			
		||||
            // User is hovering over the plot to get a value at a point
 | 
			
		||||
            .hover-value-enabled {
 | 
			
		||||
                background-color: $legendHoverValueBg;
 | 
			
		||||
                border-radius: $smallCr;
 | 
			
		||||
                padding: 0 $interiorMarginSm;
 | 
			
		||||
                &:before {
 | 
			
		||||
                    opacity: 0.5;
 | 
			
		||||
                }
 | 
			
		||||
                &.cursor-hover,
 | 
			
		||||
                .value-to-display-nearestTimestamp,
 | 
			
		||||
                .value-to-display-nearestValue
 | 
			
		||||
                {
 | 
			
		||||
                    @extend .icon-crosshair-12px;
 | 
			
		||||
                    &:before {
 | 
			
		||||
                        font-size: 9px;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                &.value-to-display-min:before {
 | 
			
		||||
                    content: 'MIN ';
 | 
			
		||||
                }
 | 
			
		||||
                &.value-to-display-max:before {
 | 
			
		||||
                    content: 'MAX ';
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &.plot-legend-collapsed .plot-wrapper-expanded-legend { display: none; }
 | 
			
		||||
    &.plot-legend-expanded .plot-wrapper-collapsed-legend { display: none; }
 | 
			
		||||
 | 
			
		||||
    /***************** GENERAL STYLES, ALL STATES */
 | 
			
		||||
    .plot-legend-item {
 | 
			
		||||
        // General styles for legend items, both expanded and collapsed legend states
 | 
			
		||||
        .plot-series-color-swatch {
 | 
			
		||||
            border-radius: $smallCr;
 | 
			
		||||
            border: 1px solid $colorBodyBg;
 | 
			
		||||
            display: inline-block;
 | 
			
		||||
            height: $plotSwatchD;
 | 
			
		||||
            width: $plotSwatchD;
 | 
			
		||||
        }
 | 
			
		||||
        .plot-series-name {
 | 
			
		||||
            display: inline;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .plot-series-value {
 | 
			
		||||
            @include ellipsize();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /***************** GENERAL STYLES, COLLAPSED */
 | 
			
		||||
    &.plot-legend-collapsed {
 | 
			
		||||
        // .plot-legend-item is a span of spans.
 | 
			
		||||
        &.plot-legend-top .gl-plot-legend { margin-bottom: $interiorMargin; }
 | 
			
		||||
        &.plot-legend-bottom .gl-plot-legend { margin-top: $interiorMargin; }
 | 
			
		||||
        &.plot-legend-right .gl-plot-legend { margin-left: $interiorMargin; }
 | 
			
		||||
        &.plot-legend-left .gl-plot-legend { margin-right: $interiorMargin; }
 | 
			
		||||
 | 
			
		||||
        .plot-legend-item {
 | 
			
		||||
            display: flex;
 | 
			
		||||
            align-items: center;
 | 
			
		||||
            &:not(:first-child) {
 | 
			
		||||
                margin-left: $interiorMarginLg;
 | 
			
		||||
            }
 | 
			
		||||
            .plot-series-swatch-and-name,
 | 
			
		||||
            .plot-series-value {
 | 
			
		||||
                @include ellipsize();
 | 
			
		||||
                flex: 1 1 auto;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            .plot-series-swatch-and-name {
 | 
			
		||||
                margin-right: $interiorMarginSm;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            .plot-series-value {
 | 
			
		||||
                text-align: left;
 | 
			
		||||
                width: 170px;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /***************** GENERAL STYLES, EXPANDED */
 | 
			
		||||
    &.plot-legend-expanded {
 | 
			
		||||
        .gl-plot-legend {
 | 
			
		||||
            max-height: 70%;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .plot-wrapper-expanded-legend {
 | 
			
		||||
            overflow-y: auto;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &.plot-legend-top .gl-plot-legend {
 | 
			
		||||
            margin-bottom: $interiorMargin;
 | 
			
		||||
        }
 | 
			
		||||
        &.plot-legend-bottom .gl-plot-legend {
 | 
			
		||||
            margin-top: $interiorMargin;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /***************** TOP OR BOTTOM */
 | 
			
		||||
    &.plot-legend-top,
 | 
			
		||||
    &.plot-legend-bottom {
 | 
			
		||||
        // General styles when legend is on the top or bottom
 | 
			
		||||
        @extend .l-flex-col;
 | 
			
		||||
        &.plot-legend-collapsed {
 | 
			
		||||
            // COLLAPSED ON TOP OR BOTTOM
 | 
			
		||||
            .plot-wrapper-collapsed-legend {
 | 
			
		||||
                display: flex;
 | 
			
		||||
                flex: 1 1 auto;
 | 
			
		||||
                overflow: hidden;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /***************** EITHER SIDE */
 | 
			
		||||
    &.plot-legend-left,
 | 
			
		||||
    &.plot-legend-right {
 | 
			
		||||
        @extend .l-flex-row;
 | 
			
		||||
        // If the legend is expanded, use flex-col instead so that the legend gets the width it needs.
 | 
			
		||||
        &.plot-legend-expanded {
 | 
			
		||||
            // EXPANDED, ON EITHER SIDE
 | 
			
		||||
            @extend .l-flex-col;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &.plot-legend-collapsed {
 | 
			
		||||
            // COLLAPSED, ON EITHER SIDE
 | 
			
		||||
            .gl-plot-legend {
 | 
			
		||||
                max-height: inherit;
 | 
			
		||||
                width: 25%;
 | 
			
		||||
            }
 | 
			
		||||
            .plot-wrapper-collapsed-legend {
 | 
			
		||||
                display: flex;
 | 
			
		||||
                flex-flow: column nowrap;
 | 
			
		||||
                min-width: 0;
 | 
			
		||||
                flex: 1 1 auto;
 | 
			
		||||
                overflow-y: auto;
 | 
			
		||||
            }
 | 
			
		||||
            .plot-legend-item {
 | 
			
		||||
                margin-bottom: 1px;
 | 
			
		||||
                margin-left: 0;
 | 
			
		||||
                flex-wrap: wrap;
 | 
			
		||||
                .plot-series-swatch-and-name {
 | 
			
		||||
                    flex: 0 1 auto;
 | 
			
		||||
                    min-width: 20%;
 | 
			
		||||
                }
 | 
			
		||||
                .plot-series-value {
 | 
			
		||||
                    flex: 0 1 auto;
 | 
			
		||||
                    width: auto;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /***************** ON BOTTOM OR RIGHT */
 | 
			
		||||
    &.plot-legend-right:not(.plot-legend-expanded),
 | 
			
		||||
    &.plot-legend-bottom {
 | 
			
		||||
        .gl-plot-legend {
 | 
			
		||||
            order: 2;
 | 
			
		||||
        }
 | 
			
		||||
        .plot-wrapper-axis-and-display-area {
 | 
			
		||||
            order: 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -20,18 +20,64 @@
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
.abs.holder-plot {
 | 
			
		||||
    // Fend off the scrollbar when less than min-height;
 | 
			
		||||
    right: $interiorMargin;
 | 
			
		||||
    right: $interiorMargin; // Fend off the scrollbar when less than min-height;
 | 
			
		||||
    .t-object-alert.t-alert-unsynced {
 | 
			
		||||
        display: none;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/********************************************* STACKED PLOT LAYOUT */
 | 
			
		||||
.t-plot-stacked {
 | 
			
		||||
    .l-view-section {
 | 
			
		||||
        //  Make this a flex container
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-flow: column nowrap;
 | 
			
		||||
        .gl-plot.child-frame {
 | 
			
		||||
            mct-plot { 
 | 
			
		||||
                display: flex; 
 | 
			
		||||
                flex: 1 1 auto;
 | 
			
		||||
                height: 100%;
 | 
			
		||||
                position: relative;
 | 
			
		||||
            }
 | 
			
		||||
            flex: 1 1 auto;
 | 
			
		||||
            &:not(:first-child) {
 | 
			
		||||
                margin-top: $interiorMargin;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .s-status-timeconductor-unsynced .holder-plot {
 | 
			
		||||
        .t-object-alert.t-alert-unsynced {
 | 
			
		||||
            display: block;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.gl-plot {
 | 
			
		||||
	color: $colorPlotFg;
 | 
			
		||||
    display: flex;
 | 
			
		||||
	font-size: 0.7rem;
 | 
			
		||||
	position: relative;
 | 
			
		||||
	width: 100%;
 | 
			
		||||
	height: 100%;
 | 
			
		||||
    min-height: $plotMinH;
 | 
			
		||||
 | 
			
		||||
    /********************************************* AXIS AND DISPLAY AREA */
 | 
			
		||||
    .plot-wrapper-axis-and-display-area {
 | 
			
		||||
        margin-top: $interiorMargin; // Keep the top tick label from getting clipped
 | 
			
		||||
        position: relative;
 | 
			
		||||
        flex: 1 1 auto;
 | 
			
		||||
        .t-object-alert {
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            display: block;
 | 
			
		||||
            font-size: 1.5em;
 | 
			
		||||
            top: $interiorMarginSm; left: $interiorMarginSm;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .gl-plot-wrapper-display-area-and-x-axis {
 | 
			
		||||
        // Holds the plot area and the X-axis only
 | 
			
		||||
        position: absolute;
 | 
			
		||||
@@ -49,7 +95,6 @@
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .gl-plot-axis-area.gl-plot-x {
 | 
			
		||||
            //@include test(green);
 | 
			
		||||
            top: auto;
 | 
			
		||||
            right: 0;
 | 
			
		||||
            bottom: 0;
 | 
			
		||||
@@ -63,7 +108,7 @@
 | 
			
		||||
	.gl-plot-axis-area {
 | 
			
		||||
		position: absolute;
 | 
			
		||||
		&.gl-plot-y {
 | 
			
		||||
			top: $plotLegendH + $interiorMargin;
 | 
			
		||||
			top: nth($plotDisplayArea, 1);
 | 
			
		||||
			right: auto;
 | 
			
		||||
			bottom: nth($plotDisplayArea, 3);
 | 
			
		||||
			left: 0;
 | 
			
		||||
@@ -158,17 +203,6 @@
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	.gl-plot-legend {
 | 
			
		||||
		position: absolute;
 | 
			
		||||
		top: 0;
 | 
			
		||||
		right: 0;
 | 
			
		||||
		bottom: auto;
 | 
			
		||||
		left: 0;
 | 
			
		||||
		height: $plotLegendH;
 | 
			
		||||
		overflow-x: hidden;
 | 
			
		||||
		overflow-y: auto;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/****************************** Limits and Out-of-Bounds data */
 | 
			
		||||
 | 
			
		||||
	.l-limit-bar,
 | 
			
		||||
@@ -235,39 +269,6 @@
 | 
			
		||||
    border: 1px solid $colorPlotAreaBorder;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.gl-plot-legend,
 | 
			
		||||
.legend {
 | 
			
		||||
	.plot-legend-item,
 | 
			
		||||
	.legend-item {
 | 
			
		||||
		display: inline-block;
 | 
			
		||||
		margin-right: $interiorMarginLg;
 | 
			
		||||
		margin-bottom: $interiorMarginSm;
 | 
			
		||||
		span {
 | 
			
		||||
			vertical-align: middle;
 | 
			
		||||
		}
 | 
			
		||||
		.plot-color-swatch,
 | 
			
		||||
		.color-swatch {
 | 
			
		||||
			border-radius: 2px;
 | 
			
		||||
			display: inline-block;
 | 
			
		||||
			height: $plotSwatchD;
 | 
			
		||||
			width: $plotSwatchD;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.gl-plot-legend {
 | 
			
		||||
	.plot-legend-item {
 | 
			
		||||
		border-radius: $smallCr;
 | 
			
		||||
		line-height: 1.5em;
 | 
			
		||||
		padding: 0px $itemPadLR;
 | 
			
		||||
		.plot-color-swatch {
 | 
			
		||||
			border: 1px solid $colorBodyBg;
 | 
			
		||||
			height: $plotSwatchD + 1;
 | 
			
		||||
			width: $plotSwatchD + 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tick {
 | 
			
		||||
	position: absolute;
 | 
			
		||||
	border: 0 $colorPlotHash solid;
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@
 | 
			
		||||
ul.tree {
 | 
			
		||||
    @include menuUlReset();
 | 
			
		||||
    @include user-select(none);
 | 
			
		||||
    li {
 | 
			
		||||
    > li {
 | 
			
		||||
        display: block;
 | 
			
		||||
        position: relative;
 | 
			
		||||
    }
 | 
			
		||||
@@ -53,12 +53,10 @@ ul.tree {
 | 
			
		||||
    .view-control {
 | 
			
		||||
        color: $colorItemTreeVC;
 | 
			
		||||
        margin-right: $interiorMargin;
 | 
			
		||||
        height: 100%;
 | 
			
		||||
        line-height: inherit;
 | 
			
		||||
        width: $treeVCW;
 | 
			
		||||
        &:before { display: none; }
 | 
			
		||||
        &.has-children {
 | 
			
		||||
            &:before { display: block; }
 | 
			
		||||
        &:before { display: block; }
 | 
			
		||||
        &.no-children {
 | 
			
		||||
            &:before { display: none; }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -83,9 +83,9 @@ define([
 | 
			
		||||
        this.activeObject = domainObject;
 | 
			
		||||
 | 
			
		||||
        if (domainObject && domainObject.hasCapability('composition')) {
 | 
			
		||||
            $(this.toggleView.elements()).addClass('has-children');
 | 
			
		||||
            $(this.toggleView.elements()).removeClass('no-children');
 | 
			
		||||
        } else {
 | 
			
		||||
            $(this.toggleView.elements()).removeClass('has-children');
 | 
			
		||||
            $(this.toggleView.elements()).addClass('no-children');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (domainObject && domainObject.hasCapability('status')) {
 | 
			
		||||
 
 | 
			
		||||
@@ -181,6 +181,8 @@ $colorPlotHash: $colorTick;
 | 
			
		||||
$stylePlotHash: dashed;
 | 
			
		||||
$colorPlotAreaBorder: $colorInteriorBorder;
 | 
			
		||||
$colorPlotLabelFg: pushBack($colorPlotFg, 20%);
 | 
			
		||||
$legendCollapsedNameMaxW: 50%;
 | 
			
		||||
$legendHoverValueBg: rgba($colorBodyFg, 0.1);
 | 
			
		||||
 | 
			
		||||
// Tree
 | 
			
		||||
$colorItemTreeHoverBg: pullForward($colorBodyBg, $hoverRatioPercent);
 | 
			
		||||
 
 | 
			
		||||
@@ -181,6 +181,8 @@ $colorPlotHash: $colorTick;
 | 
			
		||||
$stylePlotHash: dashed;
 | 
			
		||||
$colorPlotAreaBorder: $colorInteriorBorder;
 | 
			
		||||
$colorPlotLabelFg: pushBack($colorPlotFg, 20%);
 | 
			
		||||
$legendCollapsedNameMaxW: 50%;
 | 
			
		||||
$legendHoverValueBg: rgba($colorBodyFg, 0.2);
 | 
			
		||||
 | 
			
		||||
// Tree
 | 
			
		||||
$colorItemTreeHoverBg: pullForward($colorBodyBg, $hoverRatioPercent);
 | 
			
		||||
 
 | 
			
		||||
@@ -336,46 +336,6 @@ define([
 | 
			
		||||
                            "conversion": "number[]"
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "telemetry.panel",
 | 
			
		||||
                    "name": "Telemetry Panel",
 | 
			
		||||
                    "cssClass": "icon-telemetry-panel",
 | 
			
		||||
                    "description": "A panel for collecting telemetry elements.",
 | 
			
		||||
                    "priority": 899,
 | 
			
		||||
                    "delegates": [
 | 
			
		||||
                        "telemetry"
 | 
			
		||||
                    ],
 | 
			
		||||
                    "features": "creation",
 | 
			
		||||
                    "contains": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "has": "telemetry"
 | 
			
		||||
                        }
 | 
			
		||||
                    ],
 | 
			
		||||
                    "model": {
 | 
			
		||||
                        "composition": []
 | 
			
		||||
                    },
 | 
			
		||||
                    "properties": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "name": "Layout Grid",
 | 
			
		||||
                            "control": "composite",
 | 
			
		||||
                            "items": [
 | 
			
		||||
                                {
 | 
			
		||||
                                    "name": "Horizontal grid (px)",
 | 
			
		||||
                                    "control": "textfield",
 | 
			
		||||
                                    "cssClass": "l-input-sm l-numeric"
 | 
			
		||||
                                },
 | 
			
		||||
                                {
 | 
			
		||||
                                    "name": "Vertical grid (px)",
 | 
			
		||||
                                    "control": "textfield",
 | 
			
		||||
                                    "cssClass": "l-input-sm l-numeric"
 | 
			
		||||
                                }
 | 
			
		||||
                            ],
 | 
			
		||||
                            "pattern": "^(\\d*[1-9]\\d*)?$",
 | 
			
		||||
                            "property": "layoutGrid",
 | 
			
		||||
                            "conversion": "number[]"
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                }
 | 
			
		||||
            ]
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,37 +0,0 @@
 | 
			
		||||
# Plot README
 | 
			
		||||
 | 
			
		||||
## Chart 
 | 
			
		||||
 | 
			
		||||
The `mct-chart` directive is used to support drawing of simple charts. It is 
 | 
			
		||||
present to support the Plot view, and its functionality is limited to the 
 | 
			
		||||
functionality that is relevant for that view.
 | 
			
		||||
 | 
			
		||||
This directive is used at the element level and takes one attribute, `draw` 
 | 
			
		||||
which is an Angular expression which will should evaluate to a drawing object. 
 | 
			
		||||
This drawing object should contain the following properties:
 | 
			
		||||
 | 
			
		||||
* `dimensions`: The size, in logical coordinates, of the chart area. A 
 | 
			
		||||
two-element array or numbers. 
 | 
			
		||||
* `origin`: The position, in logical coordinates, of the lower-left corner of 
 | 
			
		||||
the chart area. A two-element array or numbers. 
 | 
			
		||||
* `lines`: An array of lines (e.g. as a plot line) to draw, where each line is 
 | 
			
		||||
expressed as an object containing: 
 | 
			
		||||
    * `buffer`: A Float32Array containing points in the line, in logical 
 | 
			
		||||
    coordinates, in sequential x,y pairs. 
 | 
			
		||||
    * `color`: The color of the line, as a four-element RGBA array, where 
 | 
			
		||||
    each element is a number 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. Each is an object 
 | 
			
		||||
containing: 
 | 
			
		||||
    * `start`: The first corner of the rectangle, as a two-element array of 
 | 
			
		||||
    numbers, in logical coordinates. 
 | 
			
		||||
    * `end`: The opposite corner of the rectangle, as a two-element array of 
 | 
			
		||||
    numbers, in logical coordinates. color : The color of the line, as a 
 | 
			
		||||
    four-element RGBA array, where each element is a number in the range of 
 | 
			
		||||
    0.0-1.0. 
 | 
			
		||||
 | 
			
		||||
While `mct-chart` is intended to support plots specifically, it does perform 
 | 
			
		||||
some useful management of canvas objects (e.g. choosing between WebGL and Canvas 
 | 
			
		||||
2D APIs for drawing based on browser support) so its usage is recommended when 
 | 
			
		||||
its supported drawing primitives are sufficient for other charting tasks. 
 | 
			
		||||
 
 | 
			
		||||
@@ -1,157 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    "./src/MCTChart",
 | 
			
		||||
    "./src/PlotController",
 | 
			
		||||
    "./src/policies/PlotViewPolicy",
 | 
			
		||||
    "./src/PlotOptionsController",
 | 
			
		||||
    "./src/services/ExportImageService",
 | 
			
		||||
    "text!./res/templates/plot.html",
 | 
			
		||||
    "text!./res/templates/plot-options-browse.html",
 | 
			
		||||
    'legacyRegistry'
 | 
			
		||||
], function (
 | 
			
		||||
    MCTChart,
 | 
			
		||||
    PlotController,
 | 
			
		||||
    PlotViewPolicy,
 | 
			
		||||
    PlotOptionsController,
 | 
			
		||||
    exportImageService,
 | 
			
		||||
    plotTemplate,
 | 
			
		||||
    plotOptionsBrowseTemplate,
 | 
			
		||||
    legacyRegistry
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    legacyRegistry.register("platform/features/plot", {
 | 
			
		||||
        "name": "Plot view for telemetry",
 | 
			
		||||
        "extensions": {
 | 
			
		||||
            "views": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Plot",
 | 
			
		||||
                    "key": "plot",
 | 
			
		||||
                    "cssClass": "icon-sine",
 | 
			
		||||
                    "template": plotTemplate,
 | 
			
		||||
                    "needs": [
 | 
			
		||||
                        "telemetry"
 | 
			
		||||
                    ],
 | 
			
		||||
                    "priority": "preferred",
 | 
			
		||||
                    "delegation": true
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "directives": [
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "mctChart",
 | 
			
		||||
                    "implementation": MCTChart,
 | 
			
		||||
                    "depends": [
 | 
			
		||||
                        "$interval",
 | 
			
		||||
                        "$log"
 | 
			
		||||
                    ]
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "controllers": [
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "PlotController",
 | 
			
		||||
                    "implementation": PlotController,
 | 
			
		||||
                    "depends": [
 | 
			
		||||
                        "$scope",
 | 
			
		||||
                        "$element",
 | 
			
		||||
                        "exportImageService",
 | 
			
		||||
                        "telemetryFormatter",
 | 
			
		||||
                        "telemetryHandler",
 | 
			
		||||
                        "throttle",
 | 
			
		||||
                        "PLOT_FIXED_DURATION",
 | 
			
		||||
                        "openmct"
 | 
			
		||||
                    ]
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "PlotOptionsController",
 | 
			
		||||
                    "implementation": PlotOptionsController,
 | 
			
		||||
                    "depends": [
 | 
			
		||||
                        "$scope"
 | 
			
		||||
                    ]
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "services": [
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "exportImageService",
 | 
			
		||||
                    "implementation": exportImageService,
 | 
			
		||||
                    "depends": [
 | 
			
		||||
                        "$q",
 | 
			
		||||
                        "$timeout",
 | 
			
		||||
                        "$log",
 | 
			
		||||
                        "EXPORT_IMAGE_TIMEOUT"
 | 
			
		||||
                    ]
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "constants": [
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "PLOT_FIXED_DURATION",
 | 
			
		||||
                    "value": 900000,
 | 
			
		||||
                    "priority": "fallback",
 | 
			
		||||
                    "comment": "Fifteen minutes."
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "EXPORT_IMAGE_TIMEOUT",
 | 
			
		||||
                    "value": 500,
 | 
			
		||||
                    "priority": "fallback"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "policies": [
 | 
			
		||||
                {
 | 
			
		||||
                    "category": "view",
 | 
			
		||||
                    "implementation": PlotViewPolicy,
 | 
			
		||||
                    "depends": [
 | 
			
		||||
                        "openmct"
 | 
			
		||||
                    ]
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "representations": [
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "plot-options-browse",
 | 
			
		||||
                    "template": plotOptionsBrowseTemplate
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "licenses": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "FileSaver.js",
 | 
			
		||||
                    "version": "0.0.2",
 | 
			
		||||
                    "author": "Eli Grey",
 | 
			
		||||
                    "description": "File download initiator (for file exports)",
 | 
			
		||||
                    "website": "https://github.com/eligrey/FileSaver.js/",
 | 
			
		||||
                    "copyright": "Copyright © 2015 Eli Grey.",
 | 
			
		||||
                    "license": "license-mit",
 | 
			
		||||
                    "link": "https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "html2canvas",
 | 
			
		||||
                    "version": "0.4.1",
 | 
			
		||||
                    "author": "Niklas von Hertzen",
 | 
			
		||||
                    "description": "JavaScript HTML renderer",
 | 
			
		||||
                    "website": "https://github.com/niklasvh/html2canvas",
 | 
			
		||||
                    "copyright": "Copyright © 2012 Niklas von Hertzen.",
 | 
			
		||||
                    "license": "license-mit",
 | 
			
		||||
                    "link": "https://github.com/niklasvh/html2canvas/blob/master/LICENSE"
 | 
			
		||||
                }
 | 
			
		||||
            ]
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
@@ -1,70 +0,0 @@
 | 
			
		||||
<!--
 | 
			
		||||
 Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 Administration. All rights reserved.
 | 
			
		||||
 | 
			
		||||
 Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 You may obtain a copy of the License at
 | 
			
		||||
 http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 | 
			
		||||
 Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 License for the specific language governing permissions and limitations
 | 
			
		||||
 under the License.
 | 
			
		||||
 | 
			
		||||
 Open MCT includes source code licensed under additional open source
 | 
			
		||||
 licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 this source code distribution or the Licensing information page available
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
<div ng-controller="PlotOptionsController" class="flex-elem grows l-inspector-part">
 | 
			
		||||
    <em class="t-inspector-part-header" title="Display properties for this object">Plot Options</em>
 | 
			
		||||
    <mct-form
 | 
			
		||||
            ng-model="configuration.plot.xAxis"
 | 
			
		||||
            structure="xAxisForm"
 | 
			
		||||
            name="xAxisFormState"
 | 
			
		||||
            class="flex-elem l-flex-row no-margin">
 | 
			
		||||
    </mct-form>
 | 
			
		||||
    <mct-form
 | 
			
		||||
            ng-model="configuration.plot.yAxis"
 | 
			
		||||
            structure="yAxisForm"
 | 
			
		||||
            name="yAxisFormState"
 | 
			
		||||
            class="flex-elem l-flex-row no-margin">
 | 
			
		||||
    </mct-form>
 | 
			
		||||
    <div class="form">
 | 
			
		||||
        <div class="section-header ng-binding ng-scope">
 | 
			
		||||
            Plot Series
 | 
			
		||||
        </div>
 | 
			
		||||
        <ul class="first flex-elem grows vscroll">
 | 
			
		||||
            <ul class="tree">
 | 
			
		||||
                <li ng-repeat="child in children">
 | 
			
		||||
                    <span ng-controller="ToggleController as toggle">
 | 
			
		||||
                        <span ng-controller="TreeNodeController as treeNode">
 | 
			
		||||
                            <span class="tree-item menus-to-left">
 | 
			
		||||
                                <span
 | 
			
		||||
                                    class='ui-symbol view-control flex-elem has-children'
 | 
			
		||||
                                    ng-class="{ expanded: toggle.isActive() }"
 | 
			
		||||
                                    ng-click="toggle.toggle(); treeNode.trackExpansion()">
 | 
			
		||||
                                </span>
 | 
			
		||||
                                <mct-representation
 | 
			
		||||
                                    class="rep-object-label"
 | 
			
		||||
                                    key="'label'"
 | 
			
		||||
                                    mct-object="child">
 | 
			
		||||
                                </mct-representation>
 | 
			
		||||
                            </span>
 | 
			
		||||
                        </span>
 | 
			
		||||
                        <mct-form
 | 
			
		||||
                            ng-class="{hidden: !toggle.isActive()}"
 | 
			
		||||
                            ng-model="configuration.plot.series[$index]"
 | 
			
		||||
                            structure="plotSeriesForm"
 | 
			
		||||
                            name="plotOptionsState"
 | 
			
		||||
                            class="flex-elem l-flex-row">
 | 
			
		||||
                        </mct-form>
 | 
			
		||||
                    </span>
 | 
			
		||||
                </li>
 | 
			
		||||
            </ul>
 | 
			
		||||
        </ul>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
@@ -1,165 +0,0 @@
 | 
			
		||||
<!--
 | 
			
		||||
 Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 Administration. All rights reserved.
 | 
			
		||||
 | 
			
		||||
 Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 You may obtain a copy of the License at
 | 
			
		||||
 http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 | 
			
		||||
 Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 License for the specific language governing permissions and limitations
 | 
			
		||||
 under the License.
 | 
			
		||||
 | 
			
		||||
 Open MCT includes source code licensed under additional open source
 | 
			
		||||
 licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 this source code distribution or the Licensing information page available
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
<span ng-controller="PlotController as plot"
 | 
			
		||||
      class="abs holder holder-plot has-control-bar">
 | 
			
		||||
    <div class="l-control-bar" ng-show="!plot.hideExportButtons">
 | 
			
		||||
         <span class="l-btn-set">
 | 
			
		||||
            <a class="s-button t-export labeled icon-download"
 | 
			
		||||
               ng-click="plot.exportPNG()"
 | 
			
		||||
               title="Export This View's Data as PNG">
 | 
			
		||||
                PNG
 | 
			
		||||
            </a>
 | 
			
		||||
            <a class="s-button t-export labeled"
 | 
			
		||||
               ng-click="plot.exportJPG()"
 | 
			
		||||
               title="Export This View's Data as JPG">
 | 
			
		||||
                JPG
 | 
			
		||||
            </a>
 | 
			
		||||
        </span>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="l-view-section">
 | 
			
		||||
        <div class="gl-plot"
 | 
			
		||||
             ng-style="{ height: 100 / plot.getSubPlots().length + '%'}"
 | 
			
		||||
             ng-repeat="subplot in plot.getSubPlots()">
 | 
			
		||||
            <div class="gl-plot-legend">
 | 
			
		||||
                <span class='plot-legend-item'
 | 
			
		||||
                        ng-repeat="telemetryObject in subplot.getTelemetryObjects()"
 | 
			
		||||
                        ng-class="plot.getLegendClass(telemetryObject)">
 | 
			
		||||
                    <span class='plot-color-swatch'
 | 
			
		||||
                          ng-style="{ 'background-color': plot.getColor($index) }">
 | 
			
		||||
                    </span>
 | 
			
		||||
                    <span class='title-label'>{{telemetryObject.getModel().name}}</span>
 | 
			
		||||
                </span>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="gl-plot-axis-area gl-plot-y">
 | 
			
		||||
                <div class="gl-plot-label gl-plot-y-label">
 | 
			
		||||
                    {{axes[1].active.name}}
 | 
			
		||||
                </div>
 | 
			
		||||
                <div ng-repeat="tick in subplot.getRangeTicks()"
 | 
			
		||||
                     class="gl-plot-tick gl-plot-y-tick-label"
 | 
			
		||||
                     ng-style="{ bottom: (100 * $index / (subplot.getRangeTicks().length - 1)) + '%' }">
 | 
			
		||||
                    {{tick.label | reverse}}
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="gl-plot-y-options gl-plot-local-controls"
 | 
			
		||||
                     ng-if="axes[1].options.length > 1">
 | 
			
		||||
                    <div class='form-control shell select'>
 | 
			
		||||
                        <select class="form-control input shell"
 | 
			
		||||
                                ng-model="axes[1].active"
 | 
			
		||||
                                ng-options="option.name for option in axes[1].options">
 | 
			
		||||
                        </select>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="gl-plot-wrapper-display-area-and-x-axis">
 | 
			
		||||
                <mct-include key="'time-of-interest'"
 | 
			
		||||
                             class="l-toi-holder show-val"
 | 
			
		||||
                             ng-if="toiPerc"
 | 
			
		||||
                             ng-class="{ 'pinned': toiPinned, 'val-to-left': toiPerc > 80 }"
 | 
			
		||||
                             ng-style="{'left': toiPerc + '%'}"></mct-include>
 | 
			
		||||
 | 
			
		||||
                <div class="gl-plot-coords"
 | 
			
		||||
                     ng-if="subplot.isHovering() && subplot.getHoverCoordinates()">
 | 
			
		||||
                    {{subplot.getHoverCoordinates()}}
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                <div class="gl-plot-display-area"
 | 
			
		||||
                     ng-mouseenter="subplot.isHovering(true);"
 | 
			
		||||
                     ng-mouseleave="subplot.isHovering(false)"
 | 
			
		||||
                     ng-class="{ loading: plot.isRequestPending() }">
 | 
			
		||||
 | 
			
		||||
                    <!-- Out-of-bounds data indicators -->
 | 
			
		||||
                    <!-- ng-show is temporarily hard-coded in next element -->
 | 
			
		||||
                    <div ng-show="false" class="l-oob-data l-oob-data-up"></div>
 | 
			
		||||
                    <div ng-show="false" class="l-oob-data l-oob-data-dwn"></div>
 | 
			
		||||
                    <div class="gl-plot-hash hash-v"
 | 
			
		||||
                         ng-repeat="tick in subplot.getDomainTicks()"
 | 
			
		||||
                         ng-style="{ left: (100 * $index / (subplot.getDomainTicks().length - 1)) + '%', height: '100%' }"
 | 
			
		||||
                         ng-show="$index > 0 && $index < (subplot.getDomainTicks().length - 1)">
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="gl-plot-hash hash-h"
 | 
			
		||||
                         ng-repeat="tick in subplot.getRangeTicks()"
 | 
			
		||||
                         ng-style="{ bottom: (100 * $index / (subplot.getRangeTicks().length - 1)) + '%', width: '100%' }"
 | 
			
		||||
                         ng-show="$index > 0 && $index < (subplot.getRangeTicks().length - 1)">
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <mct-chart draw="subplot.getDrawingObject()"
 | 
			
		||||
                               ng-if="subplot.getTelemetryObjects().length > 0"
 | 
			
		||||
                               ng-mousemove="subplot.hover($event)"
 | 
			
		||||
                               mct-drag="subplot.continueDrag($event)"
 | 
			
		||||
                               mct-drag-down="subplot.startDrag($event)"
 | 
			
		||||
                               mct-drag-up="subplot.endDrag($event); plot.update()">
 | 
			
		||||
                    </mct-chart>
 | 
			
		||||
                    <!-- TODO: Move into correct position; make part of group; infer from set of actions -->
 | 
			
		||||
                    <div class="l-local-controls gl-plot-local-controls t-plot-display-controls"
 | 
			
		||||
                         ng-if="$first">
 | 
			
		||||
                        <a class="s-button icon-arrow-left"
 | 
			
		||||
                           ng-click="plot.stepBackPanZoom()"
 | 
			
		||||
                           ng-show="plot.isZoomed()"
 | 
			
		||||
                           title="Restore previous pan/zoom">
 | 
			
		||||
                        </a>
 | 
			
		||||
                        <a class="s-button icon-arrows-out"
 | 
			
		||||
                           ng-click="plot.unzoom()"
 | 
			
		||||
                           ng-show="plot.isZoomed()"
 | 
			
		||||
                           title="Reset pan/zoom">
 | 
			
		||||
                        </a>
 | 
			
		||||
                        <div class="menu-element s-menu-button menus-to-left {{plot.getMode().cssClass}}"
 | 
			
		||||
                             ng-if="plot.getModeOptions().length > 1"
 | 
			
		||||
                             ng-controller="ClickAwayController as toggle">
 | 
			
		||||
                            <span class="l-click-area" ng-click="toggle.toggle()"></span>
 | 
			
		||||
                            <span>{{plot.getMode().name}}</span>
 | 
			
		||||
                            <div class="menu" ng-show="toggle.isActive()">
 | 
			
		||||
                                <ul>
 | 
			
		||||
                                    <li ng-repeat="option in plot.getModeOptions()"
 | 
			
		||||
                                        ng-click="plot.setMode(option); toggle.setState(false)"
 | 
			
		||||
                                        class="{{option.cssClass}}">
 | 
			
		||||
                                        {{option.name}}
 | 
			
		||||
                                    </li>
 | 
			
		||||
                                </ul>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div ng-if="$last" class="gl-plot-axis-area gl-plot-x">
 | 
			
		||||
                    <div ng-repeat="tick in subplot.getDomainTicks()"
 | 
			
		||||
                         class="gl-plot-tick gl-plot-x-tick-label"
 | 
			
		||||
                         ng-show="$index > 0 && $index < (subplot.getDomainTicks().length - 1)"
 | 
			
		||||
                         ng-style="{ left: (100 * $index / (subplot.getDomainTicks().length - 1)) + '%' }">
 | 
			
		||||
                        {{tick.label | reverse}}
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="gl-plot-label gl-plot-x-label">
 | 
			
		||||
                        {{axes[0].active.name}}
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="gl-plot-x-options gl-plot-local-controls"
 | 
			
		||||
                         ng-if="axes[0].options.length > 1">
 | 
			
		||||
                        <div class='form-control shell select'>
 | 
			
		||||
                            <select class="form-control input shell"
 | 
			
		||||
                                    ng-model="axes[0].active"
 | 
			
		||||
                                    ng-options="option.name for option in axes[0].options">
 | 
			
		||||
                            </select>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</span>
 | 
			
		||||
@@ -1,117 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Create a new chart which uses Canvas's 2D API for rendering.
 | 
			
		||||
         *
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @implements {platform/features/plot.Chart}
 | 
			
		||||
         * @param {CanvasElement} canvas the canvas object to render upon
 | 
			
		||||
         * @throws {Error} an error is thrown if Canvas's 2D API is unavailable.
 | 
			
		||||
         */
 | 
			
		||||
        function Canvas2DChart(canvas) {
 | 
			
		||||
            this.canvas = canvas;
 | 
			
		||||
            this.c2d = canvas.getContext('2d');
 | 
			
		||||
            this.width = canvas.width;
 | 
			
		||||
            this.height = canvas.height;
 | 
			
		||||
            this.dimensions = [this.width, this.height];
 | 
			
		||||
            this.origin = [0, 0];
 | 
			
		||||
 | 
			
		||||
            if (!this.c2d) {
 | 
			
		||||
                throw new Error("Canvas 2d API unavailable.");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Convert from logical to physical x coordinates
 | 
			
		||||
        Canvas2DChart.prototype.x = function (v) {
 | 
			
		||||
            return ((v - this.origin[0]) / this.dimensions[0]) * this.width;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Convert from logical to physical y coordinates
 | 
			
		||||
        Canvas2DChart.prototype.y = function (v) {
 | 
			
		||||
            return this.height -
 | 
			
		||||
                ((v - this.origin[1]) / this.dimensions[1]) * this.height;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Set the color to be used for drawing operations
 | 
			
		||||
        Canvas2DChart.prototype.setColor = function (color) {
 | 
			
		||||
            var mappedColor = color.map(function (c, i) {
 | 
			
		||||
                return i < 3 ? Math.floor(c * 255) : (c);
 | 
			
		||||
            }).join(',');
 | 
			
		||||
            this.c2d.strokeStyle = "rgba(" + mappedColor + ")";
 | 
			
		||||
            this.c2d.fillStyle = "rgba(" + mappedColor + ")";
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        Canvas2DChart.prototype.clear = function () {
 | 
			
		||||
            var canvas = this.canvas;
 | 
			
		||||
            this.width = canvas.width;
 | 
			
		||||
            this.height = canvas.height;
 | 
			
		||||
            this.c2d.clearRect(0, 0, this.width, this.height);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        Canvas2DChart.prototype.setDimensions = function (newDimensions, newOrigin) {
 | 
			
		||||
            this.dimensions = newDimensions;
 | 
			
		||||
            this.origin = newOrigin;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        Canvas2DChart.prototype.drawLine = function (buf, color, points) {
 | 
			
		||||
            var i;
 | 
			
		||||
 | 
			
		||||
            this.setColor(color);
 | 
			
		||||
 | 
			
		||||
            // Configure context to draw two-pixel-thick lines
 | 
			
		||||
            this.c2d.lineWidth = 2;
 | 
			
		||||
 | 
			
		||||
            // Start a new path...
 | 
			
		||||
            if (buf.length > 1) {
 | 
			
		||||
                this.c2d.beginPath();
 | 
			
		||||
                this.c2d.moveTo(this.x(buf[0]), this.y(buf[1]));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // ...and add points to it...
 | 
			
		||||
            for (i = 2; i < points * 2; i = i + 2) {
 | 
			
		||||
                this.c2d.lineTo(this.x(buf[i]), this.y(buf[i + 1]));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // ...before finally drawing it.
 | 
			
		||||
            this.c2d.stroke();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        Canvas2DChart.prototype.drawSquare = function (min, max, color) {
 | 
			
		||||
            var x1 = this.x(min[0]),
 | 
			
		||||
                y1 = this.y(min[1]),
 | 
			
		||||
                w = this.x(max[0]) - x1,
 | 
			
		||||
                h = this.y(max[1]) - y1;
 | 
			
		||||
 | 
			
		||||
            this.setColor(color);
 | 
			
		||||
            this.c2d.fillRect(x1, y1, w, h);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return Canvas2DChart;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,160 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Module defining GLPlot. Created by vwoeltje on 11/12/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
 | 
			
		||||
        // WebGL shader sources (for drawing plain colors)
 | 
			
		||||
        var FRAGMENT_SHADER = [
 | 
			
		||||
                "precision mediump float;",
 | 
			
		||||
                "uniform vec4 uColor;",
 | 
			
		||||
                "void main(void) {",
 | 
			
		||||
                "gl_FragColor = uColor;",
 | 
			
		||||
                "}"
 | 
			
		||||
            ].join('\n'),
 | 
			
		||||
            VERTEX_SHADER = [
 | 
			
		||||
                "attribute vec2 aVertexPosition;",
 | 
			
		||||
                "uniform vec2 uDimensions;",
 | 
			
		||||
                "uniform vec2 uOrigin;",
 | 
			
		||||
                "void main(void) {",
 | 
			
		||||
                "gl_Position = vec4(2.0 * ((aVertexPosition - uOrigin) / uDimensions) - vec2(1,1), 0, 1);",
 | 
			
		||||
                "}"
 | 
			
		||||
            ].join('\n');
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Create a new chart which uses WebGL for rendering.
 | 
			
		||||
         *
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @implements {platform/features/plot.Chart}
 | 
			
		||||
         * @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", { preserveDrawingBuffer: true }) ||
 | 
			
		||||
                    canvas.getContext("experimental-webgl", { preserveDrawingBuffer: true }),
 | 
			
		||||
                vertexShader,
 | 
			
		||||
                fragmentShader,
 | 
			
		||||
                program,
 | 
			
		||||
                aVertexPosition,
 | 
			
		||||
                uColor,
 | 
			
		||||
                uDimensions,
 | 
			
		||||
                uOrigin;
 | 
			
		||||
 | 
			
		||||
            // Ensure a context was actually available before proceeding
 | 
			
		||||
            if (!gl) {
 | 
			
		||||
                throw new Error("WebGL unavailable.");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Initialize shaders
 | 
			
		||||
            vertexShader = gl.createShader(gl.VERTEX_SHADER);
 | 
			
		||||
            gl.shaderSource(vertexShader, VERTEX_SHADER);
 | 
			
		||||
            gl.compileShader(vertexShader);
 | 
			
		||||
            fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
 | 
			
		||||
            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");
 | 
			
		||||
            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
 | 
			
		||||
            this.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);
 | 
			
		||||
 | 
			
		||||
            this.gl = gl;
 | 
			
		||||
            this.aVertexPosition = aVertexPosition;
 | 
			
		||||
            this.uColor = uColor;
 | 
			
		||||
            this.uDimensions = uDimensions;
 | 
			
		||||
            this.uOrigin = uOrigin;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Utility function to handle drawing of a buffer;
 | 
			
		||||
        // drawType will determine whether this is a box, line, etc.
 | 
			
		||||
        GLChart.prototype.doDraw = function (drawType, buf, color, points) {
 | 
			
		||||
            var gl = this.gl;
 | 
			
		||||
            gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
 | 
			
		||||
            gl.bufferData(gl.ARRAY_BUFFER, buf, gl.DYNAMIC_DRAW);
 | 
			
		||||
            gl.vertexAttribPointer(this.aVertexPosition, 2, gl.FLOAT, false, 0, 0);
 | 
			
		||||
            gl.uniform4fv(this.uColor, color);
 | 
			
		||||
            gl.drawArrays(drawType, 0, points);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        GLChart.prototype.clear = function () {
 | 
			
		||||
            var gl = this.gl;
 | 
			
		||||
 | 
			
		||||
            // Set the viewport size; note that we use the width/height
 | 
			
		||||
            // that our WebGL context reports, which may be lower
 | 
			
		||||
            // resolution than the canvas we requested.
 | 
			
		||||
            gl.viewport(
 | 
			
		||||
                0,
 | 
			
		||||
                0,
 | 
			
		||||
                gl.drawingBufferWidth,
 | 
			
		||||
                gl.drawingBufferHeight
 | 
			
		||||
            );
 | 
			
		||||
            gl.clear(gl.COLOR_BUFFER_BIT + gl.DEPTH_BUFFER_BIT);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        GLChart.prototype.setDimensions = function (dimensions, origin) {
 | 
			
		||||
            var gl = this.gl;
 | 
			
		||||
            if (dimensions && dimensions.length > 0 &&
 | 
			
		||||
                origin && origin.length > 0) {
 | 
			
		||||
                gl.uniform2fv(this.uDimensions, dimensions);
 | 
			
		||||
                gl.uniform2fv(this.uOrigin, origin);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        GLChart.prototype.drawLine = function (buf, color, points) {
 | 
			
		||||
            this.doDraw(this.gl.LINE_STRIP, buf, color, points);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        GLChart.prototype.drawSquare = function (min, max, color) {
 | 
			
		||||
            this.doDraw(this.gl.TRIANGLE_FAN, new Float32Array(
 | 
			
		||||
                min.concat([min[0], max[1]]).concat(max).concat([max[0], min[1]])
 | 
			
		||||
            ), color, 4);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return GLChart;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,250 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Module defining MCTChart. Created by vwoeltje on 11/12/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ["./GLChart", "./Canvas2DChart"],
 | 
			
		||||
    function (GLChart, Canvas2DChart) {
 | 
			
		||||
 | 
			
		||||
        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
 | 
			
		||||
         *
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @constructor
 | 
			
		||||
         */
 | 
			
		||||
        function MCTChart($interval, $log) {
 | 
			
		||||
            // Get an underlying chart implementation
 | 
			
		||||
            function getChart(Charts, canvas) {
 | 
			
		||||
                // Try the first available option...
 | 
			
		||||
                var Chart = Charts[0];
 | 
			
		||||
 | 
			
		||||
                // This function recursively try-catches all options;
 | 
			
		||||
                // if these all fail, issue a warning.
 | 
			
		||||
                if (!Chart) {
 | 
			
		||||
                    $log.warn("Cannot initialize mct-chart.");
 | 
			
		||||
                    return undefined;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Try first option; if it fails, try remaining options
 | 
			
		||||
                try {
 | 
			
		||||
                    return new Chart(canvas);
 | 
			
		||||
                } catch (e) {
 | 
			
		||||
                    $log.warn([
 | 
			
		||||
                        "Could not instantiate chart",
 | 
			
		||||
                        Chart.name,
 | 
			
		||||
                        ";",
 | 
			
		||||
                        e.message
 | 
			
		||||
                    ].join(" "));
 | 
			
		||||
 | 
			
		||||
                    return getChart(Charts.slice(1), canvas);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function linkChart(scope, element) {
 | 
			
		||||
                var canvas = element.find("canvas")[0],
 | 
			
		||||
                    activeInterval,
 | 
			
		||||
                    chart;
 | 
			
		||||
 | 
			
		||||
                // 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,
 | 
			
		||||
                            line.color,
 | 
			
		||||
                            line.points
 | 
			
		||||
                        );
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    // Draw boxes (e.g. marquee zoom rect)
 | 
			
		||||
                    (draw.boxes || []).forEach(function (box) {
 | 
			
		||||
                        chart.drawSquare(
 | 
			
		||||
                            box.start,
 | 
			
		||||
                            box.end,
 | 
			
		||||
                            box.color
 | 
			
		||||
                        );
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // 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) {
 | 
			
		||||
                        doDraw(scope.draw);
 | 
			
		||||
                        scope.$apply();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Stop watching for changes to size (scope destroyed)
 | 
			
		||||
                function releaseInterval() {
 | 
			
		||||
                    if (activeInterval) {
 | 
			
		||||
                        $interval.cancel(activeInterval);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Switch from WebGL to plain 2D if context is lost
 | 
			
		||||
                function fallbackFromWebGL() {
 | 
			
		||||
                    element.html(TEMPLATE);
 | 
			
		||||
                    canvas = element.find("canvas")[0];
 | 
			
		||||
                    chart = getChart([Canvas2DChart], canvas);
 | 
			
		||||
                    if (chart) {
 | 
			
		||||
                        doDraw(scope.draw);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Try to initialize a chart.
 | 
			
		||||
                chart = getChart([GLChart, Canvas2DChart], canvas);
 | 
			
		||||
 | 
			
		||||
                // If that failed, there's nothing more we can do here.
 | 
			
		||||
                // (A warning will already have been issued)
 | 
			
		||||
                if (!chart) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // WebGL is a bit of a special case; it may work, then fail
 | 
			
		||||
                // later for various reasons, so we need to listen for this
 | 
			
		||||
                // and fall back to plain canvas drawing when it occurs.
 | 
			
		||||
                canvas.addEventListener("webglcontextlost", fallbackFromWebGL);
 | 
			
		||||
 | 
			
		||||
                // Check for resize, on a timer
 | 
			
		||||
                activeInterval = $interval(drawIfResized, 1000, 0, false);
 | 
			
		||||
 | 
			
		||||
                // Watch "draw" for external changes to the set of
 | 
			
		||||
                // things to be drawn.
 | 
			
		||||
                scope.$watchCollection("draw", doDraw);
 | 
			
		||||
 | 
			
		||||
                // Stop checking for resize when scope is destroyed
 | 
			
		||||
                scope.$on("$destroy", releaseInterval);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            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: "=" }
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * @interface platform/features/plot.Chart
 | 
			
		||||
         * @private
 | 
			
		||||
         */
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Clear the chart.
 | 
			
		||||
         * @method platform/features/plot.Chart#clear
 | 
			
		||||
         */
 | 
			
		||||
        /**
 | 
			
		||||
         * 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
 | 
			
		||||
         * @memberof platform/features/plot.Chart#setDimensions
 | 
			
		||||
         */
 | 
			
		||||
        /**
 | 
			
		||||
         * 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
 | 
			
		||||
         * @memberof platform/features/plot.Chart#drawLine
 | 
			
		||||
         */
 | 
			
		||||
        /**
 | 
			
		||||
         * 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
 | 
			
		||||
         * @memberof platform/features/plot.Chart#drawSquare
 | 
			
		||||
         */
 | 
			
		||||
 | 
			
		||||
        return MCTChart;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@@ -1,437 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This bundle adds a "Plot" view for numeric telemetry data.
 | 
			
		||||
 * @namespace platform/features/plot
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    [
 | 
			
		||||
        "./elements/PlotUpdater",
 | 
			
		||||
        "./elements/PlotPalette",
 | 
			
		||||
        "./elements/PlotAxis",
 | 
			
		||||
        "./elements/PlotLimitTracker",
 | 
			
		||||
        "./elements/PlotTelemetryFormatter",
 | 
			
		||||
        "./modes/PlotModeOptions",
 | 
			
		||||
        "./SubPlotFactory"
 | 
			
		||||
    ],
 | 
			
		||||
    function (
 | 
			
		||||
        PlotUpdater,
 | 
			
		||||
        PlotPalette,
 | 
			
		||||
        PlotAxis,
 | 
			
		||||
        PlotLimitTracker,
 | 
			
		||||
        PlotTelemetryFormatter,
 | 
			
		||||
        PlotModeOptions,
 | 
			
		||||
        SubPlotFactory
 | 
			
		||||
    ) {
 | 
			
		||||
 | 
			
		||||
        var AXIS_DEFAULTS = [
 | 
			
		||||
                { "name": "Time" },
 | 
			
		||||
                { "name": "Value" }
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 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.
 | 
			
		||||
         *
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @constructor
 | 
			
		||||
         */
 | 
			
		||||
        function PlotController(
 | 
			
		||||
            $scope,
 | 
			
		||||
            $element,
 | 
			
		||||
            exportImageService,
 | 
			
		||||
            telemetryFormatter,
 | 
			
		||||
            telemetryHandler,
 | 
			
		||||
            throttle,
 | 
			
		||||
            PLOT_FIXED_DURATION,
 | 
			
		||||
            openmct
 | 
			
		||||
        ) {
 | 
			
		||||
            var self = this,
 | 
			
		||||
                plotTelemetryFormatter =
 | 
			
		||||
                    new PlotTelemetryFormatter(telemetryFormatter),
 | 
			
		||||
                subPlotFactory =
 | 
			
		||||
                    new SubPlotFactory(plotTelemetryFormatter),
 | 
			
		||||
                cachedObjects = [],
 | 
			
		||||
                updater,
 | 
			
		||||
                lastBounds,
 | 
			
		||||
                lastRange,
 | 
			
		||||
                lastDomain,
 | 
			
		||||
                handle;
 | 
			
		||||
            var timeAPI = openmct.time;
 | 
			
		||||
 | 
			
		||||
            // Populate the scope with axis information (specifically, options
 | 
			
		||||
            // available for each axis.)
 | 
			
		||||
            function setupAxes(metadatas) {
 | 
			
		||||
                $scope.axes.forEach(function (axis) {
 | 
			
		||||
                    axis.updateMetadata(metadatas);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Trigger an update of a specific subplot;
 | 
			
		||||
            // used in a loop to update all subplots.
 | 
			
		||||
            function updateSubplot(subplot) {
 | 
			
		||||
                subplot.update();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Set up available modes (stacked/overlaid), based on the
 | 
			
		||||
            // set of telemetry objects in this plot view.
 | 
			
		||||
            function setupModes(telemetryObjects) {
 | 
			
		||||
                if (cachedObjects !== telemetryObjects) {
 | 
			
		||||
                    cachedObjects = telemetryObjects;
 | 
			
		||||
                    self.modeOptions = new PlotModeOptions(
 | 
			
		||||
                        telemetryObjects || [],
 | 
			
		||||
                        subPlotFactory
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Change the displayable bounds
 | 
			
		||||
            function setBasePanZoom(bounds) {
 | 
			
		||||
                var start = bounds.start,
 | 
			
		||||
                    end = bounds.end;
 | 
			
		||||
                if (updater) {
 | 
			
		||||
                    updater.setDomainBounds(start, end);
 | 
			
		||||
                    self.update();
 | 
			
		||||
                }
 | 
			
		||||
                lastBounds = bounds;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Reinstantiate the plot updater (e.g. because we have a
 | 
			
		||||
            // new subscription.) This will clear the plot.
 | 
			
		||||
            function recreateUpdater() {
 | 
			
		||||
                var domain = $scope.axes[0].active.key,
 | 
			
		||||
                    range = $scope.axes[1].active.key,
 | 
			
		||||
                    duration = PLOT_FIXED_DURATION;
 | 
			
		||||
 | 
			
		||||
                updater = new PlotUpdater(handle, domain, range, duration);
 | 
			
		||||
                lastDomain = domain;
 | 
			
		||||
                lastRange = range;
 | 
			
		||||
 | 
			
		||||
                self.limitTracker = new PlotLimitTracker(handle, range);
 | 
			
		||||
 | 
			
		||||
                // Keep any externally-provided bounds
 | 
			
		||||
                if (lastBounds) {
 | 
			
		||||
                    setBasePanZoom(lastBounds);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function getUpdater() {
 | 
			
		||||
                if (!updater) {
 | 
			
		||||
                    recreateUpdater();
 | 
			
		||||
                }
 | 
			
		||||
                return updater;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Handle new telemetry data in this plot
 | 
			
		||||
            function updateValues() {
 | 
			
		||||
                self.pending = false;
 | 
			
		||||
                if (handle) {
 | 
			
		||||
                    setupModes(handle.getTelemetryObjects());
 | 
			
		||||
                    setupAxes(handle.getMetadata());
 | 
			
		||||
                    getUpdater().update();
 | 
			
		||||
                    self.modeOptions.getModeHandler().plotTelemetry(updater);
 | 
			
		||||
                    self.limitTracker.update();
 | 
			
		||||
                    self.update();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Display new historical data as it becomes available
 | 
			
		||||
            function addHistoricalData(domainObject, series) {
 | 
			
		||||
                self.pending = false;
 | 
			
		||||
                getUpdater().addHistorical(domainObject, series);
 | 
			
		||||
                self.modeOptions.getModeHandler().plotTelemetry(updater);
 | 
			
		||||
                self.update();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Issue a new request for historical telemetry
 | 
			
		||||
            function requestTelemetry() {
 | 
			
		||||
                if (handle) {
 | 
			
		||||
                    handle.request({}, addHistoricalData);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Requery for data entirely
 | 
			
		||||
            function replot() {
 | 
			
		||||
                if (handle) {
 | 
			
		||||
                    updater = undefined;
 | 
			
		||||
                    requestTelemetry();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function changeTimeOfInterest(timeOfInterest) {
 | 
			
		||||
                if (timeOfInterest !== undefined) {
 | 
			
		||||
                    var bounds = timeAPI.bounds();
 | 
			
		||||
                    var range = bounds.end - bounds.start;
 | 
			
		||||
                    $scope.toiPerc = ((timeOfInterest - bounds.start) / range) * 100;
 | 
			
		||||
                    $scope.toiPinned = true;
 | 
			
		||||
                } else {
 | 
			
		||||
                    $scope.toiPerc = undefined;
 | 
			
		||||
                    $scope.toiPinned = false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Create a new subscription; telemetrySubscriber gets
 | 
			
		||||
            // to do the meaningful work here.
 | 
			
		||||
            function subscribe(domainObject) {
 | 
			
		||||
                if (handle) {
 | 
			
		||||
                    handle.unsubscribe();
 | 
			
		||||
                }
 | 
			
		||||
                handle = domainObject && telemetryHandler.handle(
 | 
			
		||||
                    domainObject,
 | 
			
		||||
                    updateValues,
 | 
			
		||||
                    true // Lossless
 | 
			
		||||
                );
 | 
			
		||||
                replot();
 | 
			
		||||
 | 
			
		||||
                changeTimeOfInterest(timeAPI.timeOfInterest());
 | 
			
		||||
                timeAPI.on("timeOfInterest", changeTimeOfInterest);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Release the current subscription (called when scope is destroyed)
 | 
			
		||||
            function releaseSubscription() {
 | 
			
		||||
                if (handle) {
 | 
			
		||||
                    handle.unsubscribe();
 | 
			
		||||
                    handle = undefined;
 | 
			
		||||
                }
 | 
			
		||||
                timeAPI.off("timeOfInterest", changeTimeOfInterest);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function requery() {
 | 
			
		||||
                self.pending = true;
 | 
			
		||||
                releaseSubscription();
 | 
			
		||||
                subscribe($scope.domainObject);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function updateDomainFormat() {
 | 
			
		||||
                var domainAxis = $scope.axes[0];
 | 
			
		||||
                plotTelemetryFormatter
 | 
			
		||||
                    .setDomainFormat(domainAxis.active.format);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function domainRequery(newDomain) {
 | 
			
		||||
                if (newDomain !== lastDomain) {
 | 
			
		||||
                    updateDomainFormat();
 | 
			
		||||
                    requery();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function rangeRequery(newRange) {
 | 
			
		||||
                if (newRange !== lastRange) {
 | 
			
		||||
                    requery();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Respond to a display bounds change (requery for data)
 | 
			
		||||
            function changeDisplayBounds(event, bounds, follow) {
 | 
			
		||||
                //'hack' for follow mode
 | 
			
		||||
                if (follow === true) {
 | 
			
		||||
                    setBasePanZoom(bounds);
 | 
			
		||||
                } else {
 | 
			
		||||
                    var domainAxis = $scope.axes[0];
 | 
			
		||||
 | 
			
		||||
                    if (bounds.domain) {
 | 
			
		||||
                        domainAxis.chooseOption(bounds.domain);
 | 
			
		||||
                    }
 | 
			
		||||
                    updateDomainFormat();
 | 
			
		||||
                    setBasePanZoom(bounds);
 | 
			
		||||
                    requery();
 | 
			
		||||
                }
 | 
			
		||||
                self.setUnsynchedStatus($scope.domainObject, follow && self.isZoomed());
 | 
			
		||||
                changeTimeOfInterest(timeAPI.timeOfInterest());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.modeOptions = new PlotModeOptions([], subPlotFactory);
 | 
			
		||||
            this.updateValues = updateValues;
 | 
			
		||||
 | 
			
		||||
            // Create a throttled update function
 | 
			
		||||
            this.scheduleUpdate = throttle(function () {
 | 
			
		||||
                self.modeOptions.getModeHandler().getSubPlots()
 | 
			
		||||
                    .forEach(updateSubplot);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            self.pending = true;
 | 
			
		||||
            self.$element = $element;
 | 
			
		||||
            self.exportImageService = exportImageService;
 | 
			
		||||
 | 
			
		||||
            // Initialize axes; will get repopulated when telemetry
 | 
			
		||||
            // metadata becomes available.
 | 
			
		||||
            $scope.axes = [
 | 
			
		||||
                new PlotAxis("domains", [], AXIS_DEFAULTS[0]),
 | 
			
		||||
                new PlotAxis("ranges", [], AXIS_DEFAULTS[1])
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
            //Are some initialized bounds defined?
 | 
			
		||||
            var bounds = timeAPI.bounds();
 | 
			
		||||
            if (bounds &&
 | 
			
		||||
                bounds.start !== undefined &&
 | 
			
		||||
                bounds.end !== undefined) {
 | 
			
		||||
                changeDisplayBounds(undefined, timeAPI.bounds(), timeAPI.clock() !== undefined);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Watch for changes to the selected axis
 | 
			
		||||
            $scope.$watch("axes[0].active.key", domainRequery);
 | 
			
		||||
            $scope.$watch("axes[1].active.key", rangeRequery);
 | 
			
		||||
 | 
			
		||||
            // Subscribe to telemetry when a domain object becomes available
 | 
			
		||||
            $scope.$watch('domainObject', subscribe);
 | 
			
		||||
 | 
			
		||||
            // Respond to external bounds changes
 | 
			
		||||
            $scope.$on("telemetry:display:bounds", changeDisplayBounds);
 | 
			
		||||
 | 
			
		||||
            // Unsubscribe when the plot is destroyed
 | 
			
		||||
            $scope.$on("$destroy", releaseSubscription);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 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
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.getColor = function (index) {
 | 
			
		||||
            return PlotPalette.getStringColor(index);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 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
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.isZoomed = function () {
 | 
			
		||||
            return this.modeOptions.getModeHandler().isZoomed();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Undo the most recent pan/zoom change and restore
 | 
			
		||||
         * the prior state.
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.stepBackPanZoom = function () {
 | 
			
		||||
            return this.modeOptions.getModeHandler().stepBackPanZoom();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Undo all pan/zoom changes and restore the initial state.
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.unzoom = function () {
 | 
			
		||||
            return this.modeOptions.getModeHandler().unzoom();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Get the mode options (Stacked/Overlaid) that are applicable
 | 
			
		||||
         * for this plot.
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.getModeOptions = function () {
 | 
			
		||||
            return this.modeOptions.getModeOptions();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Get the current mode that is applicable to this plot. This
 | 
			
		||||
         * will include key, name, and cssClass fields.
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.getMode = function () {
 | 
			
		||||
            return this.modeOptions.getMode();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Set the mode which should be active in this plot.
 | 
			
		||||
         * @param mode one of the mode options returned from
 | 
			
		||||
         *        getModeOptions()
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.setMode = function (mode) {
 | 
			
		||||
            this.modeOptions.setMode(mode);
 | 
			
		||||
            this.updateValues();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Get all individual plots contained within this Plot view.
 | 
			
		||||
         * (Multiple may be contained when in Stacked mode).
 | 
			
		||||
         * @returns {SubPlot[]} all subplots in this Plot view
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.getSubPlots = function () {
 | 
			
		||||
            return this.modeOptions.getModeHandler().getSubPlots();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Get the CSS class to apply to the legend for this domain
 | 
			
		||||
         * object; this will reflect limit state.
 | 
			
		||||
         * @returns {string} the CSS class
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.getLegendClass = function (telemetryObject) {
 | 
			
		||||
            return this.limitTracker &&
 | 
			
		||||
                this.limitTracker.getLegendClass(telemetryObject);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Explicitly update all plots.
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.update = function () {
 | 
			
		||||
            this.scheduleUpdate();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Check if a request is pending (to show the wait spinner)
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.isRequestPending = function () {
 | 
			
		||||
            // Placeholder; this should reflect request state
 | 
			
		||||
            // when requesting historical telemetry
 | 
			
		||||
            return this.pending;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        PlotController.prototype.setUnsynchedStatus = function (domainObject, status) {
 | 
			
		||||
            if (domainObject.hasCapability('status')) {
 | 
			
		||||
                domainObject.getCapability('status').set('timeconductor-unsynced', status);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Export the plot to PNG
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.exportPNG = function () {
 | 
			
		||||
            var self = this;
 | 
			
		||||
            self.hideExportButtons = true;
 | 
			
		||||
            self.exportImageService.exportPNG(self.$element[0], "plot.png").finally(function () {
 | 
			
		||||
                self.hideExportButtons = false;
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Export the plot to JPG
 | 
			
		||||
         */
 | 
			
		||||
        PlotController.prototype.exportJPG = function () {
 | 
			
		||||
            var self = this;
 | 
			
		||||
            self.hideExportButtons = true;
 | 
			
		||||
            self.exportImageService.exportJPG(self.$element[0], "plot.jpg").finally(function () {
 | 
			
		||||
                self.hideExportButtons = false;
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return PlotController;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@@ -1,195 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    ['./PlotOptionsForm'],
 | 
			
		||||
    function (PlotOptionsForm) {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Notes on implementation of plot options
 | 
			
		||||
         *
 | 
			
		||||
         * Multiple y-axes will have to be handled with multiple forms as
 | 
			
		||||
         * they will need to be stored on distinct model object
 | 
			
		||||
         *
 | 
			
		||||
         * Likewise plot series options per-child will need to be separate
 | 
			
		||||
         * forms.
 | 
			
		||||
         */
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * The LayoutController is responsible for supporting the
 | 
			
		||||
         * Layout view. It arranges frames according to saved configuration
 | 
			
		||||
         * and provides methods for updating these based on mouse
 | 
			
		||||
         * movement.
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @param {Scope} $scope the controller's Angular scope
 | 
			
		||||
         */
 | 
			
		||||
        function PlotOptionsController($scope) {
 | 
			
		||||
 | 
			
		||||
            var self = this;
 | 
			
		||||
            this.$scope = $scope;
 | 
			
		||||
            this.domainObject = $scope.domainObject;
 | 
			
		||||
            this.configuration = this.domainObject.getModel().configuration || {};
 | 
			
		||||
            this.plotOptionsForm = new PlotOptionsForm();
 | 
			
		||||
            this.composition = [];
 | 
			
		||||
            this.watches = [];
 | 
			
		||||
 | 
			
		||||
            /*
 | 
			
		||||
             Listen for changes to the domain object and update the object's
 | 
			
		||||
             children.
 | 
			
		||||
             */
 | 
			
		||||
            this.mutationListener = this.domainObject.getCapability('mutation').listen(function (model) {
 | 
			
		||||
                if (self.hasCompositionChanged(self.composition, model.composition)) {
 | 
			
		||||
                    self.updateChildren();
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            /*
 | 
			
		||||
             Set form structures on scope
 | 
			
		||||
             */
 | 
			
		||||
            $scope.plotSeriesForm = this.plotOptionsForm.plotSeriesForm;
 | 
			
		||||
            $scope.xAxisForm = this.plotOptionsForm.xAxisForm;
 | 
			
		||||
            $scope.yAxisForm = this.plotOptionsForm.yAxisForm;
 | 
			
		||||
 | 
			
		||||
            $scope.$on("$destroy", function () {
 | 
			
		||||
                //Clean up any listeners on destruction of controller
 | 
			
		||||
                self.mutationListener();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            this.defaultConfiguration();
 | 
			
		||||
            this.updateChildren();
 | 
			
		||||
 | 
			
		||||
            /*
 | 
			
		||||
             * Setup a number of watches for changes to form values. On
 | 
			
		||||
             * change, update the model configuration via mutation
 | 
			
		||||
             */
 | 
			
		||||
            $scope.$watchCollection('configuration.plot.yAxis', function (newValue, oldValue) {
 | 
			
		||||
                self.updateConfiguration(newValue, oldValue);
 | 
			
		||||
            });
 | 
			
		||||
            $scope.$watchCollection('configuration.plot.xAxis', function (newValue, oldValue) {
 | 
			
		||||
                self.updateConfiguration(newValue, oldValue);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            this.watchSeries();
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Unregister all watches for series data (ie. the configuration for
 | 
			
		||||
         * child objects)
 | 
			
		||||
         * @private
 | 
			
		||||
         */
 | 
			
		||||
        PlotOptionsController.prototype.clearSeriesWatches = function () {
 | 
			
		||||
            this.watches.forEach(function (watch) {
 | 
			
		||||
                watch();
 | 
			
		||||
            });
 | 
			
		||||
            this.watches = [];
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Attach watches for each object in the plot's composition
 | 
			
		||||
         * @private
 | 
			
		||||
         */
 | 
			
		||||
        PlotOptionsController.prototype.watchSeries = function () {
 | 
			
		||||
            var self = this;
 | 
			
		||||
 | 
			
		||||
            this.clearSeriesWatches();
 | 
			
		||||
 | 
			
		||||
            (self.$scope.children || []).forEach(function (child, index) {
 | 
			
		||||
                self.watches.push(
 | 
			
		||||
                    self.$scope.$watchCollection(
 | 
			
		||||
                        'configuration.plot.series[' + index + ']',
 | 
			
		||||
                        function (newValue, oldValue) {
 | 
			
		||||
                            self.updateConfiguration(newValue, oldValue);
 | 
			
		||||
                        }
 | 
			
		||||
                    )
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Determine whether the changes to the model that triggered a
 | 
			
		||||
         * mutation event were purely compositional.
 | 
			
		||||
         *
 | 
			
		||||
         * @private
 | 
			
		||||
         */
 | 
			
		||||
        PlotOptionsController.prototype.hasCompositionChanged = function (oldComposition, newComposition) {
 | 
			
		||||
            // Framed slightly strangely, but the boolean logic is
 | 
			
		||||
            // easier to follow for the unchanged case.
 | 
			
		||||
            var isUnchanged = oldComposition === newComposition ||
 | 
			
		||||
                    (
 | 
			
		||||
                        oldComposition.length === newComposition.length &&
 | 
			
		||||
                        oldComposition.every(function (currentValue, index) {
 | 
			
		||||
                            return newComposition[index] && currentValue === newComposition[index];
 | 
			
		||||
                        })
 | 
			
		||||
                    );
 | 
			
		||||
            return !isUnchanged;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Default the plot options model
 | 
			
		||||
         *
 | 
			
		||||
         * @private
 | 
			
		||||
         */
 | 
			
		||||
        PlotOptionsController.prototype.defaultConfiguration = function () {
 | 
			
		||||
            this.configuration.plot = this.configuration.plot || {};
 | 
			
		||||
            this.configuration.plot.xAxis = this.configuration.plot.xAxis || {};
 | 
			
		||||
            this.configuration.plot.yAxis = this.configuration.plot.yAxis || {}; // y-axes will be associative array keyed on axis key
 | 
			
		||||
            this.configuration.plot.series = this.configuration.plot.series || []; // series will be associative array keyed on sub-object id
 | 
			
		||||
            this.$scope.configuration = this.configuration;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * When a child is added to, or removed from a plot, update the
 | 
			
		||||
         * plot options model
 | 
			
		||||
         * @private
 | 
			
		||||
         */
 | 
			
		||||
        PlotOptionsController.prototype.updateChildren = function () {
 | 
			
		||||
            var self = this;
 | 
			
		||||
            this.domainObject.useCapability('composition').then(function (children) {
 | 
			
		||||
                self.$scope.children = children;
 | 
			
		||||
                self.composition = self.domainObject.getModel().composition;
 | 
			
		||||
                children.forEach(function (child, index) {
 | 
			
		||||
                    self.configuration.plot.series[index] =
 | 
			
		||||
                        self.configuration.plot.series[index] || {'id': child.getId()};
 | 
			
		||||
                });
 | 
			
		||||
                self.watchSeries();
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * On changes to the form, update the configuration on the domain
 | 
			
		||||
         * object
 | 
			
		||||
         * @private
 | 
			
		||||
         */
 | 
			
		||||
        PlotOptionsController.prototype.updateConfiguration = function () {
 | 
			
		||||
            var self = this;
 | 
			
		||||
            this.domainObject.useCapability('mutation', function (model) {
 | 
			
		||||
                model.configuration = model.configuration || {};
 | 
			
		||||
                model.configuration.plot = self.configuration.plot;
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return PlotOptionsController;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@@ -1,150 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * A class for encapsulating structure and behaviour of the plot
 | 
			
		||||
         * options form
 | 
			
		||||
         * @memberOf platform/features/plot
 | 
			
		||||
         * @param topic
 | 
			
		||||
         * @constructor
 | 
			
		||||
         */
 | 
			
		||||
        function PlotOptionsForm() {
 | 
			
		||||
 | 
			
		||||
            /*
 | 
			
		||||
             Defined below are the form structures for the plot options.
 | 
			
		||||
             */
 | 
			
		||||
            this.xAxisForm = {
 | 
			
		||||
                'name': 'x-axis',
 | 
			
		||||
                'sections': [{
 | 
			
		||||
                    'name': 'x-axis',
 | 
			
		||||
                    'rows': [
 | 
			
		||||
                        {
 | 
			
		||||
                            'name': 'Domain',
 | 
			
		||||
                            'control': 'select',
 | 
			
		||||
                            'key': 'key',
 | 
			
		||||
                            'options': [
 | 
			
		||||
                                {'name': 'SCET', 'value': 'scet'},
 | 
			
		||||
                                {'name': 'SCLK', 'value': 'sclk'},
 | 
			
		||||
                                {'name': 'LST', 'value': 'lst'}
 | 
			
		||||
                            ]
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                }]};
 | 
			
		||||
 | 
			
		||||
            this.yAxisForm = {
 | 
			
		||||
                'name': 'y-axis',
 | 
			
		||||
                'sections': [{
 | 
			
		||||
                    // Will need to be repeated for each y-axis, with a
 | 
			
		||||
                    // distinct name for each. Ideally the name of the axis
 | 
			
		||||
                    // itself.
 | 
			
		||||
                    'name': 'y-axis',
 | 
			
		||||
                    'rows': [
 | 
			
		||||
                    {
 | 
			
		||||
                        'name': 'Range',
 | 
			
		||||
                        'control': 'select',
 | 
			
		||||
                        'key': 'key',
 | 
			
		||||
                        'options': [
 | 
			
		||||
                            {'name': 'EU', 'value': 'eu'},
 | 
			
		||||
                            {'name': 'DN', 'value': 'dn'},
 | 
			
		||||
                            {'name': 'Status', 'value': 'status'}
 | 
			
		||||
                        ]
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        'name': 'Autoscale',
 | 
			
		||||
                        'control': 'checkbox',
 | 
			
		||||
                        'key': 'autoscale'
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        'name': 'Min',
 | 
			
		||||
                        'control': 'textfield',
 | 
			
		||||
                        'key': 'min',
 | 
			
		||||
                        'pattern': '[0-9]',
 | 
			
		||||
                        'inputsize' : 'sm'
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        'name': 'Max',
 | 
			
		||||
                        'control': 'textfield',
 | 
			
		||||
                        'key': 'max',
 | 
			
		||||
                        'pattern': '[0-9]',
 | 
			
		||||
                        'inputsize' : 'sm'
 | 
			
		||||
                    }
 | 
			
		||||
                ]
 | 
			
		||||
                }]
 | 
			
		||||
            };
 | 
			
		||||
            this.plotSeriesForm = {
 | 
			
		||||
                'name': 'Series Options',
 | 
			
		||||
                'sections': [
 | 
			
		||||
                    {
 | 
			
		||||
                        rows: [
 | 
			
		||||
                        {
 | 
			
		||||
                            'name': 'Color',
 | 
			
		||||
                            'control': 'color',
 | 
			
		||||
                            'key': 'color'
 | 
			
		||||
                        }]
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        'rows': [
 | 
			
		||||
                            {
 | 
			
		||||
                                'name': 'Markers',
 | 
			
		||||
                                'control': 'checkbox',
 | 
			
		||||
                                'key': 'markers',
 | 
			
		||||
                                'layout': 'control-first'
 | 
			
		||||
                            }
 | 
			
		||||
                        ]
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        'rows': [
 | 
			
		||||
                            {
 | 
			
		||||
                                'name': 'No Line',
 | 
			
		||||
                                'control': 'radio',
 | 
			
		||||
                                'key': 'lineType',
 | 
			
		||||
                                'value': 'noLine',
 | 
			
		||||
                                'layout': 'control-first'
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                'name': 'Step Line',
 | 
			
		||||
                                'control': 'radio',
 | 
			
		||||
                                'key': 'lineType',
 | 
			
		||||
                                'value': 'stepLine',
 | 
			
		||||
                                'layout': 'control-first'
 | 
			
		||||
                            },
 | 
			
		||||
                            {
 | 
			
		||||
                                'name': 'Linear Line',
 | 
			
		||||
                                'control': 'radio',
 | 
			
		||||
                                'key': 'lineType',
 | 
			
		||||
                                'value': 'linearLine',
 | 
			
		||||
                                'layout': 'control-first'
 | 
			
		||||
                            }
 | 
			
		||||
                        ]
 | 
			
		||||
                    }
 | 
			
		||||
                ]
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return PlotOptionsForm;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@@ -1,415 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    [
 | 
			
		||||
        './elements/PlotPosition',
 | 
			
		||||
        './elements/PlotTickGenerator'
 | 
			
		||||
    ],
 | 
			
		||||
    function (PlotPosition, PlotTickGenerator) {
 | 
			
		||||
 | 
			
		||||
        var DOMAIN_TICKS = 5,
 | 
			
		||||
            RANGE_TICKS = 7;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * A SubPlot is an individual plot within a Plot View (which
 | 
			
		||||
         * may contain multiple plots, specifically when in Stacked
 | 
			
		||||
         * plot mode.)
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @param {DomainObject[]} telemetryObjects the domain objects
 | 
			
		||||
         *        which will be plotted in this sub-plot
 | 
			
		||||
         * @param {PlotPanZoomStack} panZoomStack the stack of pan-zoom
 | 
			
		||||
         *        states which is applicable to this sub-plot
 | 
			
		||||
         * @param {TelemetryFormatter} telemetryFormatter the telemetry
 | 
			
		||||
         *        formatting service; used to convert domain/range values
 | 
			
		||||
         *        from telemetry data sets to a human-readable form.
 | 
			
		||||
         */
 | 
			
		||||
        function SubPlot(telemetryObjects, panZoomStack, telemetryFormatter) {
 | 
			
		||||
            // We are used from a template often, so maintain
 | 
			
		||||
            // state in local variables to allow for fast look-up,
 | 
			
		||||
            // as is normal for controllers.
 | 
			
		||||
            this.telemetryObjects = telemetryObjects;
 | 
			
		||||
            this.domainTicks = [];
 | 
			
		||||
            this.rangeTicks = [];
 | 
			
		||||
            this.formatter = telemetryFormatter;
 | 
			
		||||
            this.draw = {};
 | 
			
		||||
            this.hovering = false;
 | 
			
		||||
            this.panZoomStack = panZoomStack;
 | 
			
		||||
 | 
			
		||||
            // Start with the right initial drawing bounds,
 | 
			
		||||
            // tick marks
 | 
			
		||||
            this.updateDrawingBounds();
 | 
			
		||||
            this.updateTicks();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Tests whether this subplot has domain data to show for the current pan/zoom level. Absence of domain data
 | 
			
		||||
         * implies that there is no range data displayed either
 | 
			
		||||
         * @returns {boolean} true if domain data exists for the current pan/zoom level
 | 
			
		||||
         */
 | 
			
		||||
        SubPlot.prototype.hasDomainData = function () {
 | 
			
		||||
            return this.panZoomStack &&
 | 
			
		||||
                this.panZoomStack.getDimensions()[0] > 0;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Utility function for filtering out empty strings.
 | 
			
		||||
        function isNonEmpty(v) {
 | 
			
		||||
            return typeof v === 'string' && v !== "";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Converts from pixel coordinates to domain-range,
 | 
			
		||||
        // to interpret mouse gestures.
 | 
			
		||||
        SubPlot.prototype.mousePositionToDomainRange = function (mousePosition) {
 | 
			
		||||
            return new PlotPosition(
 | 
			
		||||
                mousePosition.x,
 | 
			
		||||
                mousePosition.y,
 | 
			
		||||
                mousePosition.width,
 | 
			
		||||
                mousePosition.height,
 | 
			
		||||
                this.panZoomStack
 | 
			
		||||
            ).getPosition();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Utility function to get the mouse position (in x,y
 | 
			
		||||
        // pixel coordinates in the canvas area) from a mouse
 | 
			
		||||
        // event object.
 | 
			
		||||
        SubPlot.prototype.toMousePosition = function ($event) {
 | 
			
		||||
            var bounds = this.subPlotBounds;
 | 
			
		||||
 | 
			
		||||
            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.)
 | 
			
		||||
        SubPlot.prototype.toDisplayable = function (position) {
 | 
			
		||||
            return [position[0] - this.domainOffset, position[1]];
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Update the current hover coordinates
 | 
			
		||||
        SubPlot.prototype.updateHoverCoordinates = function () {
 | 
			
		||||
            var formatter = this.formatter;
 | 
			
		||||
 | 
			
		||||
            // Utility, for map/forEach loops. Index 0 is domain,
 | 
			
		||||
            // index 1 is range.
 | 
			
		||||
            function formatValue(v, i) {
 | 
			
		||||
                return i ?
 | 
			
		||||
                    formatter.formatRangeValue(v) :
 | 
			
		||||
                    formatter.formatDomainValue(v);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.hoverCoordinates = this.mousePosition &&
 | 
			
		||||
                this.mousePositionToDomainRange(this.mousePosition)
 | 
			
		||||
                    .map(formatValue)
 | 
			
		||||
                    .filter(isNonEmpty)
 | 
			
		||||
                    .join(", ");
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Update the drawable marquee area to reflect current
 | 
			
		||||
        // mouse position (or don't show it at all, if no marquee
 | 
			
		||||
        // zoom is in progress)
 | 
			
		||||
        SubPlot.prototype.updateMarqueeBox = function () {
 | 
			
		||||
            // Express this as a box in the draw object, which
 | 
			
		||||
            // is passed to an mct-chart in the template for rendering.
 | 
			
		||||
            this.draw.boxes = this.marqueeStart ?
 | 
			
		||||
                [{
 | 
			
		||||
                    start: this.toDisplayable(
 | 
			
		||||
                        this.mousePositionToDomainRange(this.marqueeStart)
 | 
			
		||||
                    ),
 | 
			
		||||
                    end: this.toDisplayable(
 | 
			
		||||
                        this.mousePositionToDomainRange(this.mousePosition)
 | 
			
		||||
                    ),
 | 
			
		||||
                    color: [1, 1, 1, 0.5]
 | 
			
		||||
                }] : undefined;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Update the bounds (origin and dimensions) of the drawing area.
 | 
			
		||||
        SubPlot.prototype.updateDrawingBounds = function () {
 | 
			
		||||
            var panZoom = this.panZoomStack.getPanZoom();
 | 
			
		||||
 | 
			
		||||
            // Communicate pan-zoom state from stack to the draw object
 | 
			
		||||
            // which is passed to mct-chart in the template.
 | 
			
		||||
            this.draw.dimensions = panZoom.dimensions;
 | 
			
		||||
            this.draw.origin = [
 | 
			
		||||
                panZoom.origin[0] - this.domainOffset,
 | 
			
		||||
                panZoom.origin[1]
 | 
			
		||||
            ];
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Update tick marks in scope.
 | 
			
		||||
        SubPlot.prototype.updateTicks = function () {
 | 
			
		||||
            var tickGenerator =
 | 
			
		||||
                new PlotTickGenerator(this.panZoomStack, this.formatter);
 | 
			
		||||
 | 
			
		||||
            this.domainTicks =
 | 
			
		||||
                tickGenerator.generateDomainTicks(DOMAIN_TICKS);
 | 
			
		||||
            this.rangeTicks =
 | 
			
		||||
                tickGenerator.generateRangeTicks(RANGE_TICKS);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        SubPlot.prototype.updatePan = function () {
 | 
			
		||||
            var start, current, delta, nextOrigin;
 | 
			
		||||
 | 
			
		||||
            // Clear the previous panning pan-zoom state
 | 
			
		||||
            this.panZoomStack.popPanZoom();
 | 
			
		||||
 | 
			
		||||
            // Calculate what the new resulting pan-zoom should be
 | 
			
		||||
            start = this.mousePositionToDomainRange(
 | 
			
		||||
                this.panStart,
 | 
			
		||||
                this.panZoomStack
 | 
			
		||||
            );
 | 
			
		||||
            current = this.mousePositionToDomainRange(
 | 
			
		||||
                this.mousePosition,
 | 
			
		||||
                this.panZoomStack
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            delta = [current[0] - start[0], current[1] - start[1]];
 | 
			
		||||
            nextOrigin = [
 | 
			
		||||
                this.panStartBounds.origin[0] - delta[0],
 | 
			
		||||
                this.panStartBounds.origin[1] - delta[1]
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
            // ...and push a new one at the current mouse position
 | 
			
		||||
            this.panZoomStack
 | 
			
		||||
                .pushPanZoom(nextOrigin, this.panStartBounds.dimensions);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Get the set of domain objects which are being
 | 
			
		||||
         * represented in this sub-plot.
 | 
			
		||||
         * @returns {DomainObject[]} the domain objects which
 | 
			
		||||
         *          will have data plotted in this sub-plot
 | 
			
		||||
         */
 | 
			
		||||
        SubPlot.prototype.getTelemetryObjects = function () {
 | 
			
		||||
            return this.telemetryObjects;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Get ticks mark information appropriate for using in the
 | 
			
		||||
         * template for this sub-plot's domain axis, as prepared
 | 
			
		||||
         * by the PlotTickGenerator.
 | 
			
		||||
         * @returns {Array} tick marks for the domain axis
 | 
			
		||||
         */
 | 
			
		||||
        SubPlot.prototype.getDomainTicks = function () {
 | 
			
		||||
            return this.domainTicks;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Get ticks mark information appropriate for using in the
 | 
			
		||||
         * template for this sub-plot's range axis, as prepared
 | 
			
		||||
         * by the PlotTickGenerator.
 | 
			
		||||
         * @returns {Array} tick marks for the range axis
 | 
			
		||||
         */
 | 
			
		||||
        SubPlot.prototype.getRangeTicks = function () {
 | 
			
		||||
            return this.rangeTicks;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Get the drawing object associated with this sub-plot;
 | 
			
		||||
         * this object will be passed to the mct-chart in which
 | 
			
		||||
         * this sub-plot's lines will be plotted, as its "draw"
 | 
			
		||||
         * attribute, and should have the same internal format
 | 
			
		||||
         * expected by that directive.
 | 
			
		||||
         * @return {object} the drawing object
 | 
			
		||||
         */
 | 
			
		||||
        SubPlot.prototype.getDrawingObject = function () {
 | 
			
		||||
            return this.draw;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 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
 | 
			
		||||
         */
 | 
			
		||||
        SubPlot.prototype.getHoverCoordinates = function () {
 | 
			
		||||
            return this.hoverCoordinates;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Handle mouse movement over the chart area.
 | 
			
		||||
         * @param $event the mouse event
 | 
			
		||||
         * @memberof platform/features/plot.SubPlot#
 | 
			
		||||
         */
 | 
			
		||||
        SubPlot.prototype.hover = function ($event) {
 | 
			
		||||
            this.hovering = true;
 | 
			
		||||
            this.subPlotBounds = $event.target.getBoundingClientRect();
 | 
			
		||||
            this.mousePosition = this.toMousePosition($event);
 | 
			
		||||
            //If there is a domain to display, show hover coordinates, otherwise hover coordinates are meaningless
 | 
			
		||||
            if (this.hasDomainData()) {
 | 
			
		||||
                this.updateHoverCoordinates();
 | 
			
		||||
            }
 | 
			
		||||
            if (this.marqueeStart) {
 | 
			
		||||
                this.updateMarqueeBox();
 | 
			
		||||
            }
 | 
			
		||||
            if (this.panStart) {
 | 
			
		||||
                this.updatePan();
 | 
			
		||||
                this.updateDrawingBounds();
 | 
			
		||||
                this.updateTicks();
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Continue a previously-start pan or zoom gesture.
 | 
			
		||||
         * @param $event the mouse event
 | 
			
		||||
         * @memberof platform/features/plot.SubPlot#
 | 
			
		||||
         */
 | 
			
		||||
        SubPlot.prototype.continueDrag = function ($event) {
 | 
			
		||||
            this.mousePosition = this.toMousePosition($event);
 | 
			
		||||
            if (this.marqueeStart) {
 | 
			
		||||
                this.updateMarqueeBox();
 | 
			
		||||
            }
 | 
			
		||||
            if (this.panStart) {
 | 
			
		||||
                this.updatePan();
 | 
			
		||||
                this.updateDrawingBounds();
 | 
			
		||||
                this.updateTicks();
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Initiate a marquee zoom action.
 | 
			
		||||
         * @param $event the mouse event
 | 
			
		||||
         */
 | 
			
		||||
        SubPlot.prototype.startDrag = function ($event) {
 | 
			
		||||
            this.subPlotBounds = $event.target.getBoundingClientRect();
 | 
			
		||||
            this.mousePosition = this.toMousePosition($event);
 | 
			
		||||
            // Treat any modifier key as a pan
 | 
			
		||||
            if ($event.altKey || $event.shiftKey || $event.ctrlKey) {
 | 
			
		||||
                // Start panning
 | 
			
		||||
                this.panStart = this.mousePosition;
 | 
			
		||||
                this.panStartBounds = this.panZoomStack.getPanZoom();
 | 
			
		||||
                // We're starting a pan, so add this back as a
 | 
			
		||||
                // state on the stack; it will get replaced
 | 
			
		||||
                // during the pan.
 | 
			
		||||
                this.panZoomStack.pushPanZoom(
 | 
			
		||||
                    this.panStartBounds.origin,
 | 
			
		||||
                    this.panStartBounds.dimensions
 | 
			
		||||
                );
 | 
			
		||||
                $event.preventDefault();
 | 
			
		||||
            } else {
 | 
			
		||||
                // Start marquee zooming
 | 
			
		||||
                this.marqueeStart = this.mousePosition;
 | 
			
		||||
                this.updateMarqueeBox();
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Complete a marquee zoom action.
 | 
			
		||||
         * @param $event the mouse event
 | 
			
		||||
         */
 | 
			
		||||
        SubPlot.prototype.endDrag = function ($event) {
 | 
			
		||||
            var self = this;
 | 
			
		||||
 | 
			
		||||
            // 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 = self.mousePositionToDomainRange(start),
 | 
			
		||||
                    b = self.mousePositionToDomainRange(end),
 | 
			
		||||
                    origin = [
 | 
			
		||||
                        Math.min(a[0], b[0]),
 | 
			
		||||
                        Math.min(a[1], b[1])
 | 
			
		||||
                    ],
 | 
			
		||||
                    dimensions = [
 | 
			
		||||
                        Math.max(a[0], b[0]) - origin[0],
 | 
			
		||||
                        Math.max(a[1], b[1]) - origin[1]
 | 
			
		||||
                    ];
 | 
			
		||||
 | 
			
		||||
                // Proceed with zoom if zoom dimensions are non zeros
 | 
			
		||||
                if (!(dimensions[0] === 0 && dimensions[1] === 0)) {
 | 
			
		||||
                    // Push the new state onto the pan-zoom stack
 | 
			
		||||
                    self.panZoomStack.pushPanZoom(origin, dimensions);
 | 
			
		||||
 | 
			
		||||
                    // Make sure tick marks reflect new bounds
 | 
			
		||||
                    self.updateTicks();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.mousePosition = this.toMousePosition($event);
 | 
			
		||||
            this.subPlotBounds = undefined;
 | 
			
		||||
            if (this.marqueeStart) {
 | 
			
		||||
                marqueeZoom(this.marqueeStart, this.mousePosition);
 | 
			
		||||
                this.marqueeStart = undefined;
 | 
			
		||||
                this.updateMarqueeBox();
 | 
			
		||||
                this.updateDrawingBounds();
 | 
			
		||||
                this.updateTicks();
 | 
			
		||||
            }
 | 
			
		||||
            if (this.panStart) {
 | 
			
		||||
                // End panning
 | 
			
		||||
                this.panStart = undefined;
 | 
			
		||||
                this.panStartBounds = undefined;
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Update the drawing bounds, marquee box, and
 | 
			
		||||
         * tick marks for this subplot.
 | 
			
		||||
         */
 | 
			
		||||
        SubPlot.prototype.update = function () {
 | 
			
		||||
            this.updateDrawingBounds();
 | 
			
		||||
            this.updateMarqueeBox();
 | 
			
		||||
            this.updateTicks();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Set the domain offset associated with this sub-plot.
 | 
			
		||||
         * A domain offset is subtracted from all domain
 | 
			
		||||
         * before lines are drawn to avoid artifacts associated
 | 
			
		||||
         * with the use of 32-bit floats when domain values
 | 
			
		||||
         * are often timestamps (due to insufficient precision.)
 | 
			
		||||
         * A SubPlot will be drawing boxes (for marquee zoom) in
 | 
			
		||||
         * the same offset coordinate space, so it needs to know
 | 
			
		||||
         * the value of this to position that marquee box
 | 
			
		||||
         * correctly.
 | 
			
		||||
         * @param {number} value the domain offset
 | 
			
		||||
         */
 | 
			
		||||
        SubPlot.prototype.setDomainOffset = function (value) {
 | 
			
		||||
            this.domainOffset = value;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * When used with no argument, check whether or not the user
 | 
			
		||||
         * is currently hovering over this subplot. When used with
 | 
			
		||||
         * an argument, set that state.
 | 
			
		||||
         * @param {boolean} [state] the new hovering state
 | 
			
		||||
         * @returns {boolean} the hovering state
 | 
			
		||||
         */
 | 
			
		||||
        SubPlot.prototype.isHovering = function (state) {
 | 
			
		||||
            if (state !== undefined) {
 | 
			
		||||
                this.hovering = state;
 | 
			
		||||
            }
 | 
			
		||||
            return this.hovering;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return SubPlot;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@@ -1,59 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    ["./SubPlot"],
 | 
			
		||||
    function (SubPlot) {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Utility factory; wraps the SubPlot constructor and adds
 | 
			
		||||
         * in a reference to the telemetryFormatter, which will be
 | 
			
		||||
         * used to represent telemetry values (timestamps or data
 | 
			
		||||
         * values) as human-readable strings.
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @constructor
 | 
			
		||||
         */
 | 
			
		||||
        function SubPlotFactory(telemetryFormatter) {
 | 
			
		||||
            this.telemetryFormatter = telemetryFormatter;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Instantiate a new sub-plot.
 | 
			
		||||
         * @param {DomainObject[]} telemetryObjects the domain objects
 | 
			
		||||
         *        which will be plotted in this sub-plot
 | 
			
		||||
         * @param {PlotPanZoomStack} panZoomStack the stack of pan-zoom
 | 
			
		||||
         *        states which is applicable to this sub-plot
 | 
			
		||||
         * @returns {SubPlot} the instantiated sub-plot
 | 
			
		||||
         * @method
 | 
			
		||||
         */
 | 
			
		||||
        SubPlotFactory.prototype.createSubPlot = function (telemetryObjects, panZoomStack) {
 | 
			
		||||
            return new SubPlot(
 | 
			
		||||
                telemetryObjects,
 | 
			
		||||
                panZoomStack,
 | 
			
		||||
                this.telemetryFormatter
 | 
			
		||||
            );
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return SubPlotFactory;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,134 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * A PlotAxis provides a template-ready set of options
 | 
			
		||||
         * for the domain or range axis, sufficient to populate
 | 
			
		||||
         * selectors.
 | 
			
		||||
         *
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @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) {
 | 
			
		||||
            this.axisType = axisType;
 | 
			
		||||
            this.defaultValue = defaultValue;
 | 
			
		||||
            this.optionKeys = {};
 | 
			
		||||
 | 
			
		||||
            /**
 | 
			
		||||
             * 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 = 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 = [];
 | 
			
		||||
 | 
			
		||||
            // Initialize options from metadata objects
 | 
			
		||||
            this.updateMetadata(metadatas);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Update axis options to reflect current metadata.
 | 
			
		||||
         * @param {TelemetryMetadata[]} metadata objects describing
 | 
			
		||||
         *        applicable telemetry
 | 
			
		||||
         */
 | 
			
		||||
        PlotAxis.prototype.updateMetadata = function (metadatas) {
 | 
			
		||||
            var axisType = this.axisType,
 | 
			
		||||
                optionKeys = this.optionKeys,
 | 
			
		||||
                newOptions = {},
 | 
			
		||||
                toAdd = [];
 | 
			
		||||
 | 
			
		||||
            function isValid(option) {
 | 
			
		||||
                return option && optionKeys[option.key];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            metadatas.forEach(function (m) {
 | 
			
		||||
                (m[axisType] || []).forEach(function (option) {
 | 
			
		||||
                    var key = option.key;
 | 
			
		||||
                    if (!optionKeys[key] && !newOptions[key]) {
 | 
			
		||||
                        toAdd.push(option);
 | 
			
		||||
                    }
 | 
			
		||||
                    newOptions[key] = true;
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            optionKeys = this.optionKeys = newOptions;
 | 
			
		||||
 | 
			
		||||
            // General approach here is to avoid changing object
 | 
			
		||||
            // instances unless something has really changed, since
 | 
			
		||||
            // Angular is watching; don't want to trigger extra digests.
 | 
			
		||||
            if (!this.options.every(isValid)) {
 | 
			
		||||
                this.options = this.options.filter(isValid);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (toAdd.length > 0) {
 | 
			
		||||
                this.options = this.options.concat(toAdd);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!isValid(this.active)) {
 | 
			
		||||
                this.active = this.options[0] || this.defaultValue;
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Change the domain/range selection for this axis. If the
 | 
			
		||||
         * provided `key` is not recognized as an option, no change
 | 
			
		||||
         * will occur.
 | 
			
		||||
         * @param {string} key the identifier for the domain/range
 | 
			
		||||
         */
 | 
			
		||||
        PlotAxis.prototype.chooseOption = function (key) {
 | 
			
		||||
            var self = this;
 | 
			
		||||
            this.options.forEach(function (option) {
 | 
			
		||||
                if (option.key === key) {
 | 
			
		||||
                    self.active = option;
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return PlotAxis;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,78 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Tracks the limit state of telemetry objects being plotted.
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @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) {
 | 
			
		||||
            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'),
 | 
			
		||||
                    datum = handle.getDatum(telemetryObject);
 | 
			
		||||
 | 
			
		||||
                if (limit && datum) {
 | 
			
		||||
                    legendClasses[telemetryObject.getId()] =
 | 
			
		||||
                        (limit.evaluate(datum, range) || {}).cssClass;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            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;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,118 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    ['./PlotSeriesWindow'],
 | 
			
		||||
    function (PlotSeriesWindow) {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Represents a single line or trace of a plot.
 | 
			
		||||
         * @param {{PlotLineBuffer}} buffer the plot buffer
 | 
			
		||||
         * @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) {
 | 
			
		||||
                var count = seriesWindow.getPointCount();
 | 
			
		||||
 | 
			
		||||
                function doInsert() {
 | 
			
		||||
                    var firstTimestamp = seriesWindow.getDomainValue(0),
 | 
			
		||||
                        lastTimestamp = seriesWindow.getDomainValue(count - 1),
 | 
			
		||||
                        startIndex = buffer.findInsertionIndex(firstTimestamp),
 | 
			
		||||
                        endIndex = buffer.findInsertionIndex(lastTimestamp);
 | 
			
		||||
 | 
			
		||||
                    // Does the whole series fit in between two adjacent indexes?
 | 
			
		||||
                    if ((startIndex === endIndex) && startIndex > -1) {
 | 
			
		||||
                        // Insert it in between
 | 
			
		||||
                        buffer.insert(seriesWindow, startIndex);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        // Split it up, and add the two halves
 | 
			
		||||
                        seriesWindow.split().forEach(insertSeriesWindow);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Only insert if there are points to insert
 | 
			
		||||
                if (count > 0) {
 | 
			
		||||
                    doInsert();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // 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;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,268 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Contains the buffer used to draw a plot.
 | 
			
		||||
         * @param {number} domainOffset number to subtract from domain values
 | 
			
		||||
         * @param {number} initialSize initial buffer size
 | 
			
		||||
         * @param {number} maxSize maximum buffer size
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @constructor
 | 
			
		||||
         */
 | 
			
		||||
        function PlotLineBuffer(domainOffset, initialSize, maxSize) {
 | 
			
		||||
            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;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@@ -1,133 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Plot palette. Defines colors for various plot lines.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    function () {
 | 
			
		||||
 | 
			
		||||
        // Prepare different forms of the palette, since we wish to
 | 
			
		||||
        // describe colors in several ways (as RGB 0-255, as
 | 
			
		||||
        // RGB 0.0-1.0, or as stylesheet-appropriate #-prefixed colors).
 | 
			
		||||
        var integerPalette = [
 | 
			
		||||
            [0x20, 0xB2, 0xAA],
 | 
			
		||||
            [0x9A, 0xCD, 0x32],
 | 
			
		||||
            [0xFF, 0x8C, 0x00],
 | 
			
		||||
            [0xD2, 0xB4, 0x8C],
 | 
			
		||||
            [0x40, 0xE0, 0xD0],
 | 
			
		||||
            [0x41, 0x69, 0xFF],
 | 
			
		||||
            [0xFF, 0xD7, 0x00],
 | 
			
		||||
            [0x6A, 0x5A, 0xCD],
 | 
			
		||||
            [0xEE, 0x82, 0xEE],
 | 
			
		||||
            [0xCC, 0x99, 0x66],
 | 
			
		||||
            [0x99, 0xCC, 0xCC],
 | 
			
		||||
            [0x66, 0xCC, 0x33],
 | 
			
		||||
            [0xFF, 0xCC, 0x00],
 | 
			
		||||
            [0xFF, 0x66, 0x33],
 | 
			
		||||
            [0xCC, 0x66, 0xFF],
 | 
			
		||||
            [0xFF, 0x00, 0x66],
 | 
			
		||||
            [0xFF, 0xFF, 0x00],
 | 
			
		||||
            [0x80, 0x00, 0x80],
 | 
			
		||||
            [0x00, 0x86, 0x8B],
 | 
			
		||||
            [0x00, 0x8A, 0x00],
 | 
			
		||||
            [0xFF, 0x00, 0x00],
 | 
			
		||||
            [0x00, 0x00, 0xFF],
 | 
			
		||||
            [0xF5, 0xDE, 0xB3],
 | 
			
		||||
            [0xBC, 0x8F, 0x8F],
 | 
			
		||||
            [0x46, 0x82, 0xB4],
 | 
			
		||||
            [0xFF, 0xAF, 0xAF],
 | 
			
		||||
            [0x43, 0xCD, 0x80],
 | 
			
		||||
            [0xCD, 0xC1, 0xC5],
 | 
			
		||||
            [0xA0, 0x52, 0x2D],
 | 
			
		||||
            [0x64, 0x95, 0xED]
 | 
			
		||||
        ], stringPalette = integerPalette.map(function (arr) {
 | 
			
		||||
            // Convert to # notation for use in styles
 | 
			
		||||
            return '#' + arr.map(function (c) {
 | 
			
		||||
                return (c < 16 ? '0' : '') + c.toString(16);
 | 
			
		||||
            }).join('');
 | 
			
		||||
        }), floatPalette = integerPalette.map(function (arr) {
 | 
			
		||||
            return arr.map(function (c) {
 | 
			
		||||
                return c / 255.0;
 | 
			
		||||
            }).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.
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @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];
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return PlotPalette;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,141 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 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.
 | 
			
		||||
         *
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @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
 | 
			
		||||
            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 (this.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;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,167 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    ['./PlotPanZoomStack'],
 | 
			
		||||
    function (PlotPanZoomStack) {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * A plot pan zoom stack group provides a collection of individual
 | 
			
		||||
         * pan-zoom stacks that synchronize upon the domain axis, but
 | 
			
		||||
         * remain independent upon the range axis. This supports panning
 | 
			
		||||
         * and zooming in stacked-plot mode (and, importantly,
 | 
			
		||||
         * stepping back through those states.)
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @param {number} count the number of stacks to include in this
 | 
			
		||||
         *        group
 | 
			
		||||
         */
 | 
			
		||||
        function PlotPanZoomStackGroup(count) {
 | 
			
		||||
            var self = this;
 | 
			
		||||
 | 
			
		||||
            // Push a pan-zoom state; the index argument identifies
 | 
			
		||||
            // which stack originated the request (all other stacks
 | 
			
		||||
            // will ignore the range part of the change.)
 | 
			
		||||
            function pushPanZoom(origin, dimensions, index) {
 | 
			
		||||
                self.stacks.forEach(function (stack, i) {
 | 
			
		||||
                    if (i === index) {
 | 
			
		||||
                        // Do a normal push for the specified stack
 | 
			
		||||
                        stack.pushPanZoom(origin, dimensions);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        // For other stacks, do a push, but repeat
 | 
			
		||||
                        // their current range axis bounds.
 | 
			
		||||
                        stack.pushPanZoom(
 | 
			
		||||
                            [origin[0], stack.getOrigin()[1]],
 | 
			
		||||
                            [dimensions[0], stack.getDimensions()[1]]
 | 
			
		||||
                        );
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            // Decorate a pan-zoom stack; returns an object with
 | 
			
		||||
            // the same interface, but whose stack-mutation methods
 | 
			
		||||
            // effect all items in the group.
 | 
			
		||||
            function decorateStack(stack, index) {
 | 
			
		||||
                var result = Object.create(stack);
 | 
			
		||||
 | 
			
		||||
                // Use the methods defined above
 | 
			
		||||
                result.pushPanZoom = function (origin, dimensions) {
 | 
			
		||||
                    pushPanZoom(origin, dimensions, index);
 | 
			
		||||
                };
 | 
			
		||||
                result.setBasePanZoom = function () {
 | 
			
		||||
                    self.setBasePanZoom.apply(self, arguments);
 | 
			
		||||
                };
 | 
			
		||||
                result.popPanZoom = function () {
 | 
			
		||||
                    self.popPanZoom.apply(self, arguments);
 | 
			
		||||
                };
 | 
			
		||||
                result.clearPanZoom = function () {
 | 
			
		||||
                    self.clearPanZoom.apply(self, arguments);
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                return result;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Create the stacks in this group ...
 | 
			
		||||
            this.stacks = [];
 | 
			
		||||
            while (this.stacks.length < count) {
 | 
			
		||||
                this.stacks.push(new PlotPanZoomStack([], []));
 | 
			
		||||
            }
 | 
			
		||||
            // ... and their decorated-to-synchronize versions.
 | 
			
		||||
            this.decoratedStacks = this.stacks.map(decorateStack);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Pop a pan-zoom state from all stacks in the group.
 | 
			
		||||
         * If called when there is only one pan-zoom state on each
 | 
			
		||||
         * 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.)
 | 
			
		||||
         */
 | 
			
		||||
        PlotPanZoomStackGroup.prototype.popPanZoom = function () {
 | 
			
		||||
            this.stacks.forEach(function (stack) {
 | 
			
		||||
                stack.popPanZoom();
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Set the base pan-zoom state for all stacks in this group.
 | 
			
		||||
         * This changes the state at the bottom of each stack.
 | 
			
		||||
         * This allows the "unzoomed" state of plots to be updated
 | 
			
		||||
         * (e.g. as new data comes in) without
 | 
			
		||||
         * interfering with the user's chosen pan/zoom states.
 | 
			
		||||
         * @param {number[]} origin the base origin
 | 
			
		||||
         * @param {number[]} dimensions the base dimensions
 | 
			
		||||
         */
 | 
			
		||||
        PlotPanZoomStackGroup.prototype.setBasePanZoom = function (origin, dimensions) {
 | 
			
		||||
            this.stacks.forEach(function (stack) {
 | 
			
		||||
                stack.setBasePanZoom(origin, dimensions);
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Clear all pan-zoom stacks in this group down to
 | 
			
		||||
         * their bottom element; in effect, pop all elements
 | 
			
		||||
         * but the last, e.g. to remove any temporary user
 | 
			
		||||
         * modifications to pan-zoom state.
 | 
			
		||||
         */
 | 
			
		||||
        PlotPanZoomStackGroup.prototype.clearPanZoom = function () {
 | 
			
		||||
            this.stacks.forEach(function (stack) {
 | 
			
		||||
                stack.clearPanZoom();
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Get the current stack depth; that is, the number
 | 
			
		||||
         * of items on each stack in the group.
 | 
			
		||||
         * A depth of one means that no
 | 
			
		||||
         * panning or zooming relative to the base value has
 | 
			
		||||
         * been applied.
 | 
			
		||||
         * @returns {number} the depth of the stacks in this group
 | 
			
		||||
         */
 | 
			
		||||
        PlotPanZoomStackGroup.prototype.getDepth = function () {
 | 
			
		||||
            // All stacks are kept in sync, so look up depth
 | 
			
		||||
            // from the first one.
 | 
			
		||||
            return this.stacks.length > 0 ? this.stacks[0].getDepth() : 0;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Get a specific pan-zoom stack in this group.
 | 
			
		||||
         * Stacks are specified by index; this index must be less
 | 
			
		||||
         * than the count provided at construction time, and must
 | 
			
		||||
         * not be less than zero.
 | 
			
		||||
         * The stack returned by this function will be synchronized
 | 
			
		||||
         * to other stacks in this group; that is, mutating that
 | 
			
		||||
         * stack directly will result in other stacks in this group
 | 
			
		||||
         * undergoing similar updates to ensure that domain bounds
 | 
			
		||||
         * remain the same.
 | 
			
		||||
         * @param {number} index the index of the stack to get
 | 
			
		||||
         * @returns {PlotPanZoomStack} the pan-zoom stack in the
 | 
			
		||||
         *          group identified by that index
 | 
			
		||||
         */
 | 
			
		||||
        PlotPanZoomStackGroup.prototype.getPanZoomStack = function (index) {
 | 
			
		||||
            return this.decoratedStacks[index];
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return PlotPanZoomStackGroup;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,95 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 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.
 | 
			
		||||
         *
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @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;
 | 
			
		||||
 | 
			
		||||
            function convert(v, i) {
 | 
			
		||||
                return v * dimensions[i] + origin[i];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!dimensions || !origin) {
 | 
			
		||||
                // We need both dimensions and origin to compute a position
 | 
			
		||||
                this.position = [];
 | 
			
		||||
            } else {
 | 
			
		||||
                // 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)
 | 
			
		||||
                this.position =
 | 
			
		||||
                    [x / width, (height - y) / height].map(convert);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Get the domain value corresponding to this pixel position.
 | 
			
		||||
         * @returns {number} the domain value
 | 
			
		||||
         */
 | 
			
		||||
        PlotPosition.prototype.getDomain = function () {
 | 
			
		||||
            return this.position[0];
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Get the range value corresponding to this pixel position.
 | 
			
		||||
         * @returns {number} the range value
 | 
			
		||||
         */
 | 
			
		||||
        PlotPosition.prototype.getRange = function () {
 | 
			
		||||
            return this.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
 | 
			
		||||
         */
 | 
			
		||||
        PlotPosition.prototype.getPosition = function () {
 | 
			
		||||
            return this.position;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return PlotPosition;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,153 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Prepares data to be rendered in a GL Plot. Handles
 | 
			
		||||
 * the conversion from data API to displayable buffers.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    function () {
 | 
			
		||||
 | 
			
		||||
        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).
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @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 = [],
 | 
			
		||||
                max = [Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY],
 | 
			
		||||
                min = [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY],
 | 
			
		||||
                x,
 | 
			
		||||
                y,
 | 
			
		||||
                domainOffset = Number.POSITIVE_INFINITY;
 | 
			
		||||
 | 
			
		||||
            // Remove any undefined data sets
 | 
			
		||||
            datas = (datas || []).filter(identity);
 | 
			
		||||
 | 
			
		||||
            // 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 += 1) {
 | 
			
		||||
                    x = data.getDomainValue(index, domain);
 | 
			
		||||
                    y = data.getRangeValue(index, range);
 | 
			
		||||
                    vertices[i].push(x - domainOffset);
 | 
			
		||||
                    vertices[i].push(y);
 | 
			
		||||
                    min[0] = Math.min(min[0], x);
 | 
			
		||||
                    min[1] = Math.min(min[1], y);
 | 
			
		||||
                    max[0] = Math.max(max[0], x);
 | 
			
		||||
                    max[1] = Math.max(max[1], y);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // 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
 | 
			
		||||
            this.buffers = vertices.map(function (v) {
 | 
			
		||||
                return new Float32Array(v);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            this.min = min;
 | 
			
		||||
            this.max = max;
 | 
			
		||||
            this.domainOffset = domainOffset;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 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
 | 
			
		||||
         */
 | 
			
		||||
        PlotPreparer.prototype.getDimensions = function () {
 | 
			
		||||
            var max = this.max, min = this.min;
 | 
			
		||||
            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
 | 
			
		||||
         */
 | 
			
		||||
        PlotPreparer.prototype.getOrigin = function () {
 | 
			
		||||
            return this.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
 | 
			
		||||
         */
 | 
			
		||||
        PlotPreparer.prototype.getDomainOffset = function () {
 | 
			
		||||
            return this.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
 | 
			
		||||
         */
 | 
			
		||||
        PlotPreparer.prototype.getBuffers = function () {
 | 
			
		||||
            return this.buffers;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return PlotPreparer;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,80 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Provides a window on a telemetry data series, to support
 | 
			
		||||
         * insertion into a plot line.
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @implements {TelemetrySeries}
 | 
			
		||||
         */
 | 
			
		||||
        function PlotSeriesWindow(series, domain, range, start, end) {
 | 
			
		||||
            this.series = series;
 | 
			
		||||
            this.domain = domain;
 | 
			
		||||
            this.range = range;
 | 
			
		||||
            this.start = start;
 | 
			
		||||
            this.end = end;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        PlotSeriesWindow.prototype.getPointCount = function () {
 | 
			
		||||
            return this.end - this.start;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        PlotSeriesWindow.prototype.getDomainValue = function (index) {
 | 
			
		||||
            return this.series.getDomainValue(index + this.start, this.domain);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        PlotSeriesWindow.prototype.getRangeValue = function (index) {
 | 
			
		||||
            return this.series.getRangeValue(index + this.start, this.range);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Split this series into two series of equal (or nearly-equal) size.
 | 
			
		||||
         * @returns {PlotSeriesWindow[]} two series
 | 
			
		||||
         */
 | 
			
		||||
        PlotSeriesWindow.prototype.split = function () {
 | 
			
		||||
            var mid = Math.floor((this.end + this.start) / 2);
 | 
			
		||||
            return ((this.end - this.start) > 1) ?
 | 
			
		||||
                [
 | 
			
		||||
                    new PlotSeriesWindow(
 | 
			
		||||
                        this.series,
 | 
			
		||||
                        this.domain,
 | 
			
		||||
                        this.range,
 | 
			
		||||
                        this.start,
 | 
			
		||||
                        mid
 | 
			
		||||
                    ),
 | 
			
		||||
                    new PlotSeriesWindow(
 | 
			
		||||
                        this.series,
 | 
			
		||||
                        this.domain,
 | 
			
		||||
                        this.range,
 | 
			
		||||
                        mid,
 | 
			
		||||
                        this.end
 | 
			
		||||
                    )
 | 
			
		||||
                ] : [];
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return PlotSeriesWindow;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,76 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
 | 
			
		||||
        var DIGITS = 3;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Wraps a `TelemetryFormatter` to provide formats for domain and
 | 
			
		||||
         * range values; provides a single place to track domain/range
 | 
			
		||||
         * formats within a plot, allowing other plot elements to simply
 | 
			
		||||
         * request that values be formatted.
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @implements {platform/telemetry.TelemetryFormatter}
 | 
			
		||||
         * @param {TelemetryFormatter} telemetryFormatter the formatter
 | 
			
		||||
         *        to wrap.
 | 
			
		||||
         */
 | 
			
		||||
        function PlotTelemetryFormatter(telemetryFormatter) {
 | 
			
		||||
            this.telemetryFormatter = telemetryFormatter;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Specify the format to use for domain values.
 | 
			
		||||
         * @param {string} key the format's identifier
 | 
			
		||||
         */
 | 
			
		||||
        PlotTelemetryFormatter.prototype.setDomainFormat = function (key) {
 | 
			
		||||
            this.domainFormat = key;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Specify the format to use for range values.
 | 
			
		||||
         * @param {string} key the format's identifier
 | 
			
		||||
         */
 | 
			
		||||
        PlotTelemetryFormatter.prototype.setRangeFormat = function (key) {
 | 
			
		||||
            this.rangeFormat = key;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        PlotTelemetryFormatter.prototype.formatDomainValue = function (value) {
 | 
			
		||||
            return this.telemetryFormatter
 | 
			
		||||
                .formatDomainValue(value, this.domainFormat);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        PlotTelemetryFormatter.prototype.formatRangeValue = function (value) {
 | 
			
		||||
            if (typeof value === 'number') {
 | 
			
		||||
                return value.toFixed(DIGITS);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return this.telemetryFormatter
 | 
			
		||||
                .formatRangeValue(value, this.rangeFormat);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return PlotTelemetryFormatter;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,102 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    [],
 | 
			
		||||
    function () {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * The PlotTickGenerator provides labels for ticks along the
 | 
			
		||||
         * domain and range axes of the plot, to support the plot
 | 
			
		||||
         * template.
 | 
			
		||||
         *
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @param {PlotPanZoomStack} panZoomStack the pan-zoom stack for
 | 
			
		||||
         *        this plot, used to determine plot boundaries
 | 
			
		||||
         * @param {TelemetryFormatter} formatter used to format (for display)
 | 
			
		||||
         *        domain and range values.
 | 
			
		||||
         */
 | 
			
		||||
        function PlotTickGenerator(panZoomStack, formatter) {
 | 
			
		||||
            this.panZoomStack = panZoomStack;
 | 
			
		||||
            this.formatter = formatter;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // For phantomjs compatibility, for headless testing
 | 
			
		||||
        // (Function.prototype.bind unsupported)
 | 
			
		||||
        function bind(fn, thisObj) {
 | 
			
		||||
            return fn.bind ? fn.bind(thisObj) : function () {
 | 
			
		||||
                return fn.apply(thisObj, arguments);
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Generate ticks; interpolate from start up to
 | 
			
		||||
        // start + span in count steps, using the provided
 | 
			
		||||
        // formatter to represent each value.
 | 
			
		||||
        PlotTickGenerator.prototype.generateTicks = function (start, span, count, format) {
 | 
			
		||||
            var step = span / (count - 1),
 | 
			
		||||
                result = [],
 | 
			
		||||
                i;
 | 
			
		||||
 | 
			
		||||
            for (i = 0; i < count; i += 1) {
 | 
			
		||||
                result.push({
 | 
			
		||||
                    //If data to show, display label for each tick line, otherwise show lines but suppress labels.
 | 
			
		||||
                    label: span > 0 ? format(i * step + start) : ''
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return result;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Generate tick marks for the domain axis.
 | 
			
		||||
         * @param {number} count the number of ticks
 | 
			
		||||
         * @returns {string[]} labels for those ticks
 | 
			
		||||
         */
 | 
			
		||||
        PlotTickGenerator.prototype.generateDomainTicks = function (count) {
 | 
			
		||||
            var panZoom = this.panZoomStack.getPanZoom();
 | 
			
		||||
            return this.generateTicks(
 | 
			
		||||
                panZoom.origin[0],
 | 
			
		||||
                panZoom.dimensions[0],
 | 
			
		||||
                count,
 | 
			
		||||
                bind(this.formatter.formatDomainValue, this.formatter)
 | 
			
		||||
            );
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Generate tick marks for the range axis.
 | 
			
		||||
         * @param {number} count the number of ticks
 | 
			
		||||
         * @returns {string[]} labels for those ticks
 | 
			
		||||
         */
 | 
			
		||||
        PlotTickGenerator.prototype.generateRangeTicks = function (count) {
 | 
			
		||||
            var panZoom = this.panZoomStack.getPanZoom();
 | 
			
		||||
            return this.generateTicks(
 | 
			
		||||
                panZoom.origin[1],
 | 
			
		||||
                panZoom.dimensions[1],
 | 
			
		||||
                count,
 | 
			
		||||
                bind(this.formatter.formatRangeValue, this.formatter)
 | 
			
		||||
            );
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return PlotTickGenerator;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,353 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    ['./PlotLine', './PlotLineBuffer'],
 | 
			
		||||
    function (PlotLine, PlotLineBuffer) {
 | 
			
		||||
 | 
			
		||||
        var MAX_POINTS = 86400,
 | 
			
		||||
            PADDING_RATIO = 0.10, // Padding percentage for top & bottom
 | 
			
		||||
            INITIAL_SIZE = 675; // 1/128 of MAX_POINTS
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 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).
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @param {TelemetryHandle} handle the handle to telemetry access
 | 
			
		||||
         * @param {string} domain the key to use when looking up domain values
 | 
			
		||||
         * @param {string} range the key to use when looking up range values
 | 
			
		||||
         * @param {number} fixedDuration maximum plot duration to display
 | 
			
		||||
         * @param {number} maxPoints maximum number of points to display
 | 
			
		||||
         */
 | 
			
		||||
        function PlotUpdater(handle, domain, range, fixedDuration, maxPoints) {
 | 
			
		||||
            this.handle = handle;
 | 
			
		||||
            this.domain = domain;
 | 
			
		||||
            this.range = range;
 | 
			
		||||
            this.fixedDuration = fixedDuration;
 | 
			
		||||
            this.maxPoints = maxPoints;
 | 
			
		||||
 | 
			
		||||
            this.ids = [];
 | 
			
		||||
            this.lines = {};
 | 
			
		||||
            this.buffers = {};
 | 
			
		||||
            this.bufferArray = [];
 | 
			
		||||
 | 
			
		||||
            // Use a default MAX_POINTS if none is provided
 | 
			
		||||
            this.maxPoints = maxPoints !== undefined ? maxPoints : MAX_POINTS;
 | 
			
		||||
            this.dimensions = [0, 0];
 | 
			
		||||
            this.origin = [0, 0];
 | 
			
		||||
 | 
			
		||||
            // Initially prepare state for these objects.
 | 
			
		||||
            // Note that this may be an empty array at this time,
 | 
			
		||||
            // so we also need to check during update cycles.
 | 
			
		||||
            this.update();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Look up a domain object's id (for mapping, below)
 | 
			
		||||
        function getId(domainObject) {
 | 
			
		||||
            return domainObject.getId();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Used in the reduce step of updateExtrema
 | 
			
		||||
        function reduceExtrema(a, b) {
 | 
			
		||||
            return [Math.min(a[0], b[0]), Math.max(a[1], b[1])];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Convert a domain/range extrema to plot dimensions
 | 
			
		||||
        function dimensionsOf(extrema) {
 | 
			
		||||
            return extrema[1] - extrema[0];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Convert a domain/range extrema to a plot origin
 | 
			
		||||
        function originOf(extrema) {
 | 
			
		||||
            return extrema[0];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check if this set of ids matches the current set of ids
 | 
			
		||||
        // (used to detect if line preparation can be skipped)
 | 
			
		||||
        PlotUpdater.prototype.idsMatch = function (nextIds) {
 | 
			
		||||
            var ids = this.ids;
 | 
			
		||||
            return ids.length === nextIds.length &&
 | 
			
		||||
                nextIds.every(function (id, index) {
 | 
			
		||||
                    return ids[index] === id;
 | 
			
		||||
                });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Prepare plot lines for this group of telemetry objects
 | 
			
		||||
        PlotUpdater.prototype.prepareLines = function (telemetryObjects) {
 | 
			
		||||
            var nextIds = telemetryObjects.map(getId),
 | 
			
		||||
                next = {},
 | 
			
		||||
                self = this;
 | 
			
		||||
 | 
			
		||||
            // Detect if we already have everything we need prepared
 | 
			
		||||
            if (this.idsMatch(nextIds)) {
 | 
			
		||||
                // Nothing to prepare, move on
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Built up a set of ids. Note that we can only
 | 
			
		||||
            // create plot lines after our domain offset has
 | 
			
		||||
            // been determined.
 | 
			
		||||
            if (this.domainOffset !== undefined) {
 | 
			
		||||
                // Update list of ids in use
 | 
			
		||||
                this.ids = nextIds;
 | 
			
		||||
 | 
			
		||||
                // Create buffers for these objects
 | 
			
		||||
                this.bufferArray = this.ids.map(function (id) {
 | 
			
		||||
                    self.buffers[id] = self.buffers[id] || new PlotLineBuffer(
 | 
			
		||||
                        self.domainOffset,
 | 
			
		||||
                        INITIAL_SIZE,
 | 
			
		||||
                        self.maxPoints
 | 
			
		||||
                    );
 | 
			
		||||
                    next[id] =
 | 
			
		||||
                        self.lines[id] || new PlotLine(self.buffers[id]);
 | 
			
		||||
                    return self.buffers[id];
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // If there are no more lines, clear the domain offset
 | 
			
		||||
            if (Object.keys(next).length < 1) {
 | 
			
		||||
                this.domainOffset = undefined;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Update to the current set of lines
 | 
			
		||||
            this.lines = next;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Initialize the domain offset, based on these observed values
 | 
			
		||||
        PlotUpdater.prototype.initializeDomainOffset = function (values) {
 | 
			
		||||
            this.domainOffset =
 | 
			
		||||
                ((this.domainOffset === undefined) && (values.length > 0)) ?
 | 
			
		||||
                        (values.reduce(function (a, b) {
 | 
			
		||||
                            return (a || 0) + (b || 0);
 | 
			
		||||
                        }, 0) / values.length) :
 | 
			
		||||
                        this.domainOffset;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Expand range slightly so points near edges are visible
 | 
			
		||||
        PlotUpdater.prototype.expandRange = function () {
 | 
			
		||||
            var padding = PADDING_RATIO * this.dimensions[1],
 | 
			
		||||
                top;
 | 
			
		||||
            padding = Math.max(padding, 1.0);
 | 
			
		||||
            top = Math.ceil(this.origin[1] + this.dimensions[1] + padding / 2);
 | 
			
		||||
            this.origin[1] = Math.floor(this.origin[1] - padding / 2);
 | 
			
		||||
            this.dimensions[1] = top - this.origin[1];
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Update dimensions and origin based on extrema of plots
 | 
			
		||||
        PlotUpdater.prototype.updateBounds = function () {
 | 
			
		||||
            var bufferArray = this.bufferArray.filter(function (lineBuffer) {
 | 
			
		||||
                    return lineBuffer.getLength() > 0; // Ignore empty lines
 | 
			
		||||
                }),
 | 
			
		||||
                priorDomainOrigin = this.origin[0],
 | 
			
		||||
                priorDomainDimensions = this.dimensions[0];
 | 
			
		||||
 | 
			
		||||
            if (bufferArray.length > 0) {
 | 
			
		||||
                this.domainExtrema = bufferArray.map(function (lineBuffer) {
 | 
			
		||||
                    return lineBuffer.getDomainExtrema();
 | 
			
		||||
                }).reduce(reduceExtrema);
 | 
			
		||||
 | 
			
		||||
                this.rangeExtrema = bufferArray.map(function (lineBuffer) {
 | 
			
		||||
                    return lineBuffer.getRangeExtrema();
 | 
			
		||||
                }).reduce(reduceExtrema);
 | 
			
		||||
 | 
			
		||||
                // Calculate best-fit dimensions
 | 
			
		||||
                this.dimensions = [this.domainExtrema, this.rangeExtrema]
 | 
			
		||||
                    .map(dimensionsOf);
 | 
			
		||||
                this.origin = [this.domainExtrema, this.rangeExtrema]
 | 
			
		||||
                    .map(originOf);
 | 
			
		||||
 | 
			
		||||
                // Enforce some minimum visible area
 | 
			
		||||
                this.expandRange();
 | 
			
		||||
 | 
			
		||||
                // Suppress domain changes when pinned
 | 
			
		||||
                if (this.hasSpecificDomainBounds) {
 | 
			
		||||
                    this.origin[0] = priorDomainOrigin;
 | 
			
		||||
                    this.dimensions[0] = priorDomainDimensions;
 | 
			
		||||
                    if (this.following) {
 | 
			
		||||
                        this.origin[0] = Math.max(
 | 
			
		||||
                            this.domainExtrema[1] - this.dimensions[0],
 | 
			
		||||
                            this.origin[0]
 | 
			
		||||
                        );
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // ...then enforce a fixed duration if needed
 | 
			
		||||
                if (this.fixedDuration !== undefined) {
 | 
			
		||||
                    this.origin[0] = this.origin[0] + this.dimensions[0] -
 | 
			
		||||
                        this.fixedDuration;
 | 
			
		||||
                    this.dimensions[0] = this.fixedDuration;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Add latest data for this domain object
 | 
			
		||||
        PlotUpdater.prototype.addPointFor = function (domainObject) {
 | 
			
		||||
            var line = this.lines[domainObject.getId()];
 | 
			
		||||
            if (line) {
 | 
			
		||||
                line.addPoint(
 | 
			
		||||
                    this.handle.getDomainValue(domainObject, this.domain),
 | 
			
		||||
                    this.handle.getRangeValue(domainObject, this.range)
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Update with latest data.
 | 
			
		||||
         */
 | 
			
		||||
        PlotUpdater.prototype.update = function update() {
 | 
			
		||||
            var objects = this.handle.getTelemetryObjects(),
 | 
			
		||||
                self = this;
 | 
			
		||||
 | 
			
		||||
            // Initialize domain offset if necessary
 | 
			
		||||
            if (this.domainOffset === undefined) {
 | 
			
		||||
                this.initializeDomainOffset(objects.map(function (obj) {
 | 
			
		||||
                    return self.handle.getDomainValue(obj, self.domain);
 | 
			
		||||
                }).filter(function (value) {
 | 
			
		||||
                    return typeof value === 'number';
 | 
			
		||||
                }));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Make sure lines are available
 | 
			
		||||
            this.prepareLines(objects);
 | 
			
		||||
 | 
			
		||||
            // Add new data
 | 
			
		||||
            objects.forEach(function (domainObject, index) {
 | 
			
		||||
                self.addPointFor(domainObject, index);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Then, update extrema
 | 
			
		||||
            this.updateBounds();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 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
 | 
			
		||||
         */
 | 
			
		||||
        PlotUpdater.prototype.getDimensions = function () {
 | 
			
		||||
            return this.dimensions;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 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
 | 
			
		||||
         */
 | 
			
		||||
        PlotUpdater.prototype.getOrigin = function () {
 | 
			
		||||
            return this.origin;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 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
 | 
			
		||||
         * @memberof platform/features/plot.PlotUpdater#
 | 
			
		||||
         */
 | 
			
		||||
        PlotUpdater.prototype.getDomainOffset = function () {
 | 
			
		||||
            return this.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
 | 
			
		||||
         * @memberof platform/features/plot.PlotUpdater#
 | 
			
		||||
         */
 | 
			
		||||
        PlotUpdater.prototype.getLineBuffers = function () {
 | 
			
		||||
            return this.bufferArray;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Set the start and end boundaries (usually time) for the
 | 
			
		||||
         * domain axis of this updater.
 | 
			
		||||
         */
 | 
			
		||||
        PlotUpdater.prototype.setDomainBounds = function (start, end) {
 | 
			
		||||
            this.fixedDuration = end - start;
 | 
			
		||||
            this.origin[0] = start;
 | 
			
		||||
            this.dimensions[0] = this.fixedDuration;
 | 
			
		||||
 | 
			
		||||
            // Suppress follow behavior if we have windowed in on the past
 | 
			
		||||
            this.hasSpecificDomainBounds = true;
 | 
			
		||||
            this.following =
 | 
			
		||||
                !this.domainExtrema || (end >= this.domainExtrema[1]);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Fill in historical data.
 | 
			
		||||
         */
 | 
			
		||||
        PlotUpdater.prototype.addHistorical = function (domainObject, series) {
 | 
			
		||||
            var count = series ? series.getPointCount() : 0,
 | 
			
		||||
                line;
 | 
			
		||||
 | 
			
		||||
            // Nothing to do if it's an empty series
 | 
			
		||||
            if (count < 1) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Initialize domain offset if necessary
 | 
			
		||||
            if (this.domainOffset === undefined) {
 | 
			
		||||
                this.initializeDomainOffset([
 | 
			
		||||
                    series.getDomainValue(0, this.domain),
 | 
			
		||||
                    series.getDomainValue(count - 1, this.domain)
 | 
			
		||||
                ]);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Make sure lines are available
 | 
			
		||||
            this.prepareLines(this.handle.getTelemetryObjects());
 | 
			
		||||
 | 
			
		||||
            // Look up the line for this domain object
 | 
			
		||||
            line = this.lines[domainObject.getId()];
 | 
			
		||||
 | 
			
		||||
            // ...and put the data into it.
 | 
			
		||||
            if (line) {
 | 
			
		||||
                line.addSeries(series, this.domain, this.range);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Update extrema
 | 
			
		||||
            this.updateBounds();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return PlotUpdater;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@@ -1,155 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    ["./PlotOverlayMode", "./PlotStackMode"],
 | 
			
		||||
    function (PlotOverlayMode, PlotStackMode) {
 | 
			
		||||
 | 
			
		||||
        var STACKED = {
 | 
			
		||||
                key: "stacked",
 | 
			
		||||
                name: "Stacked",
 | 
			
		||||
                cssClass: "icon-plot-stacked",
 | 
			
		||||
                Constructor: PlotStackMode
 | 
			
		||||
            },
 | 
			
		||||
            OVERLAID = {
 | 
			
		||||
                key: "overlaid",
 | 
			
		||||
                name: "Overlaid",
 | 
			
		||||
                cssClass: "icon-plot-overlay",
 | 
			
		||||
                Constructor: PlotOverlayMode
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Handles distinct behavior associated with different
 | 
			
		||||
         * plot modes.
 | 
			
		||||
         *
 | 
			
		||||
         * @interface platform/features/plot.PlotModeHandler
 | 
			
		||||
         * @private
 | 
			
		||||
         */
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Plot telemetry to the sub-plot(s) managed by this mode.
 | 
			
		||||
         * @param {platform/features/plot.PlotUpdater} updater a source
 | 
			
		||||
         *        of data that is ready to plot
 | 
			
		||||
         * @method platform/features/plot.PlotModeHandler#plotTelemetry
 | 
			
		||||
         */
 | 
			
		||||
        /**
 | 
			
		||||
         * Get all sub-plots to be displayed in this mode; used
 | 
			
		||||
         * to populate the plot template.
 | 
			
		||||
         * @return {platform/features/plot.SubPlot[]} all sub-plots to
 | 
			
		||||
         *         display in this mode
 | 
			
		||||
         * @method platform/features/plot.PlotModeHandler#getSubPlots
 | 
			
		||||
         */
 | 
			
		||||
        /**
 | 
			
		||||
         * Check if we are not in our base pan-zoom state (that is,
 | 
			
		||||
         * there are some temporary user modifications to the
 | 
			
		||||
         * current pan-zoom state.)
 | 
			
		||||
         * @returns {boolean} true if not in the base pan-zoom state
 | 
			
		||||
         * @method platform/features/plot.PlotModeHandler#isZoomed
 | 
			
		||||
         */
 | 
			
		||||
        /**
 | 
			
		||||
         * Undo the most recent pan/zoom change and restore
 | 
			
		||||
         * the prior state.
 | 
			
		||||
         * @method platform/features/plot.PlotModeHandler#stepBackPanZoom
 | 
			
		||||
         */
 | 
			
		||||
        /**
 | 
			
		||||
         * Undo all pan/zoom change and restore the base state.
 | 
			
		||||
         * @method platform/features/plot.PlotModeHandler#unzoom
 | 
			
		||||
         */
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Determines which plotting modes (stacked/overlaid)
 | 
			
		||||
         * are applicable in a given plot view, maintains current
 | 
			
		||||
         * selection state thereof, and provides handlers for the
 | 
			
		||||
         * different behaviors associated with these modes.
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @param {DomainObject[]} telemetryObjects the telemetry objects being
 | 
			
		||||
         *        represented in this plot view
 | 
			
		||||
         * @param {platform/features/plot.SubPlotFactory} subPlotFactory a
 | 
			
		||||
         *        factory for creating sub-plots
 | 
			
		||||
         */
 | 
			
		||||
        function PlotModeOptions(telemetryObjects, subPlotFactory) {
 | 
			
		||||
            this.options = telemetryObjects.length > 1 ?
 | 
			
		||||
                    [OVERLAID, STACKED] : [OVERLAID];
 | 
			
		||||
            this.mode = this.options[0]; // Initial selection (overlaid)
 | 
			
		||||
            this.telemetryObjects = telemetryObjects;
 | 
			
		||||
            this.subPlotFactory = subPlotFactory;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Get a handler for the current mode. This will handle
 | 
			
		||||
         * plotting telemetry, providing subplots for the template,
 | 
			
		||||
         * and view-level interactions with pan-zoom state.
 | 
			
		||||
         * @returns {PlotOverlayMode|PlotStackMode} a handler
 | 
			
		||||
         *          for the current mode
 | 
			
		||||
         */
 | 
			
		||||
        PlotModeOptions.prototype.getModeHandler = function () {
 | 
			
		||||
            // Lazily initialize
 | 
			
		||||
            if (!this.modeHandler) {
 | 
			
		||||
                this.modeHandler = new this.mode.Constructor(
 | 
			
		||||
                    this.telemetryObjects,
 | 
			
		||||
                    this.subPlotFactory
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
            return this.modeHandler;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Get all mode options available for each plot. Each
 | 
			
		||||
         * mode contains a `name` and `cssClass` field suitable
 | 
			
		||||
         * for display in a template.
 | 
			
		||||
         * @return {Array} the available modes
 | 
			
		||||
         */
 | 
			
		||||
        PlotModeOptions.prototype.getModeOptions = function () {
 | 
			
		||||
            return this.options;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Get the plotting mode option currently in use.
 | 
			
		||||
         * This will be one of the elements returned from
 | 
			
		||||
         * `getModeOptions`.
 | 
			
		||||
         * @return {*} the current mode
 | 
			
		||||
         */
 | 
			
		||||
        PlotModeOptions.prototype.getMode = function () {
 | 
			
		||||
            return this.mode;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Set the plotting mode option to use.
 | 
			
		||||
         * The passed argument must be one of the options
 | 
			
		||||
         * returned by `getModeOptions`.
 | 
			
		||||
         * @param {object} option one of the plot mode options
 | 
			
		||||
         *        from `getModeOptions`
 | 
			
		||||
         */
 | 
			
		||||
        PlotModeOptions.prototype.setMode = function (option) {
 | 
			
		||||
            if (this.mode !== option) {
 | 
			
		||||
                this.mode = option;
 | 
			
		||||
                // Clear the existing mode handler, so it
 | 
			
		||||
                // can be instantiated next time it's needed.
 | 
			
		||||
                this.modeHandler = undefined;
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        return PlotModeOptions;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,88 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    ["../SubPlot", "../elements/PlotPalette", "../elements/PlotPanZoomStack"],
 | 
			
		||||
    function (SubPlot, PlotPalette, PlotPanZoomStack) {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Handles plotting in Overlaid mode. In overlaid mode, there
 | 
			
		||||
         * is one sub-plot which contains all plotted objects.
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @implements {platform/features/plot.PlotModeHandler}
 | 
			
		||||
         * @param {DomainObject[]} the domain objects to be plotted
 | 
			
		||||
         */
 | 
			
		||||
        function PlotOverlayMode(telemetryObjects, subPlotFactory) {
 | 
			
		||||
            this.panZoomStack = new PlotPanZoomStack([], []);
 | 
			
		||||
            this.subplot = subPlotFactory.createSubPlot(
 | 
			
		||||
                telemetryObjects,
 | 
			
		||||
                this.panZoomStack
 | 
			
		||||
            );
 | 
			
		||||
            this.subplots = [this.subplot];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        PlotOverlayMode.prototype.plotTelemetry = function (updater) {
 | 
			
		||||
            // Fit to the boundaries of the data, but don't
 | 
			
		||||
            // override any user-initiated pan-zoom changes.
 | 
			
		||||
            this.panZoomStack.setBasePanZoom(
 | 
			
		||||
                updater.getOrigin(),
 | 
			
		||||
                updater.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.
 | 
			
		||||
            this.subplot.setDomainOffset(updater.getDomainOffset());
 | 
			
		||||
 | 
			
		||||
            // Draw the buffers. Select color by index.
 | 
			
		||||
            this.subplot.getDrawingObject().lines =
 | 
			
		||||
                updater.getLineBuffers().map(function (buf, i) {
 | 
			
		||||
                    return {
 | 
			
		||||
                        buffer: buf.getBuffer(),
 | 
			
		||||
                        color: PlotPalette.getFloatColor(i),
 | 
			
		||||
                        points: buf.getLength()
 | 
			
		||||
                    };
 | 
			
		||||
                });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        PlotOverlayMode.prototype.getSubPlots = function () {
 | 
			
		||||
            return this.subplots;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        PlotOverlayMode.prototype.isZoomed = function () {
 | 
			
		||||
            return this.panZoomStack.getDepth() > 1;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        PlotOverlayMode.prototype.stepBackPanZoom = function () {
 | 
			
		||||
            this.panZoomStack.popPanZoom();
 | 
			
		||||
            this.subplot.update();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        PlotOverlayMode.prototype.unzoom = function () {
 | 
			
		||||
            this.panZoomStack.clearPanZoom();
 | 
			
		||||
            this.subplot.update();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return PlotOverlayMode;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,104 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    ["../SubPlot", "../elements/PlotPalette", "../elements/PlotPanZoomStackGroup"],
 | 
			
		||||
    function (SubPlot, PlotPalette, PlotPanZoomStackGroup) {
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Handles plotting in Stacked mode. In stacked mode, there
 | 
			
		||||
         * is one sub-plot for each plotted object.
 | 
			
		||||
         * @memberof platform/features/plot
 | 
			
		||||
         * @constructor
 | 
			
		||||
         * @implements {platform/features/plot.PlotModeHandler}
 | 
			
		||||
         * @param {DomainObject[]} the domain objects to be plotted
 | 
			
		||||
         */
 | 
			
		||||
        function PlotStackMode(telemetryObjects, subPlotFactory) {
 | 
			
		||||
            var self = this;
 | 
			
		||||
 | 
			
		||||
            this.panZoomStackGroup =
 | 
			
		||||
                new PlotPanZoomStackGroup(telemetryObjects.length);
 | 
			
		||||
 | 
			
		||||
            this.subplots = telemetryObjects.map(function (telemetryObject, i) {
 | 
			
		||||
                    return subPlotFactory.createSubPlot(
 | 
			
		||||
                        [telemetryObject],
 | 
			
		||||
                        self.panZoomStackGroup.getPanZoomStack(i)
 | 
			
		||||
                    );
 | 
			
		||||
                });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        PlotStackMode.prototype.plotTelemetryTo = function (subplot, prepared, index) {
 | 
			
		||||
            var buffer = prepared.getLineBuffers()[index];
 | 
			
		||||
 | 
			
		||||
            // Track the domain offset, used to bias domain values
 | 
			
		||||
            // to minimize loss of precision when converted to 32-bit
 | 
			
		||||
            // floating point values for display.
 | 
			
		||||
            subplot.setDomainOffset(prepared.getDomainOffset());
 | 
			
		||||
 | 
			
		||||
            // Draw the buffers. Always use the 0th color, because there
 | 
			
		||||
            // is one line per plot.
 | 
			
		||||
            subplot.getDrawingObject().lines = [{
 | 
			
		||||
                buffer: buffer.getBuffer(),
 | 
			
		||||
                color: PlotPalette.getFloatColor(0),
 | 
			
		||||
                points: buffer.getLength()
 | 
			
		||||
            }];
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        PlotStackMode.prototype.plotTelemetry = function (prepared) {
 | 
			
		||||
            var self = this;
 | 
			
		||||
            // Fit to the boundaries of the data, but don't
 | 
			
		||||
            // override any user-initiated pan-zoom changes.
 | 
			
		||||
            this.panZoomStackGroup.setBasePanZoom(
 | 
			
		||||
                prepared.getOrigin(),
 | 
			
		||||
                prepared.getDimensions()
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            this.subplots.forEach(function (subplot, index) {
 | 
			
		||||
                self.plotTelemetryTo(subplot, prepared, index);
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        PlotStackMode.prototype.getSubPlots = function () {
 | 
			
		||||
            return this.subplots;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        PlotStackMode.prototype.isZoomed = function () {
 | 
			
		||||
            return this.panZoomStackGroup.getDepth() > 1;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        PlotStackMode.prototype.stepBackPanZoom = function () {
 | 
			
		||||
            this.panZoomStackGroup.popPanZoom();
 | 
			
		||||
            this.subplots.forEach(function (subplot) {
 | 
			
		||||
                subplot.update();
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        PlotStackMode.prototype.unzoom = function () {
 | 
			
		||||
            this.panZoomStackGroup.clearPanZoom();
 | 
			
		||||
            this.subplots.forEach(function (subplot) {
 | 
			
		||||
                subplot.update();
 | 
			
		||||
            });
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return PlotStackMode;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,95 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MergeModelsSpec. Created by vwoeltje on 11/6/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ["../src/Canvas2DChart"],
 | 
			
		||||
    function (Canvas2DChart) {
 | 
			
		||||
 | 
			
		||||
        describe("A canvas 2d chart", function () {
 | 
			
		||||
            var mockCanvas,
 | 
			
		||||
                mock2d,
 | 
			
		||||
                chart;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockCanvas = jasmine.createSpyObj("canvas", ["getContext"]);
 | 
			
		||||
                mock2d = jasmine.createSpyObj(
 | 
			
		||||
                    "2d",
 | 
			
		||||
                    [
 | 
			
		||||
                        "clearRect",
 | 
			
		||||
                        "beginPath",
 | 
			
		||||
                        "moveTo",
 | 
			
		||||
                        "lineTo",
 | 
			
		||||
                        "stroke",
 | 
			
		||||
                        "fillRect"
 | 
			
		||||
                    ]
 | 
			
		||||
                );
 | 
			
		||||
                mockCanvas.getContext.andReturn(mock2d);
 | 
			
		||||
 | 
			
		||||
                chart = new Canvas2DChart(mockCanvas);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Note that tests below are less specific than they
 | 
			
		||||
            // could be, esp. w.r.t. arguments to drawing calls;
 | 
			
		||||
            // this is a fallback option so is a lower test priority.
 | 
			
		||||
 | 
			
		||||
            it("allows the canvas to be cleared", function () {
 | 
			
		||||
                chart.clear();
 | 
			
		||||
                expect(mock2d.clearRect).toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("does not construct if 2D is unavailable", function () {
 | 
			
		||||
                mockCanvas.getContext.andReturn(undefined);
 | 
			
		||||
                expect(function () {
 | 
			
		||||
                    return new Canvas2DChart(mockCanvas);
 | 
			
		||||
                }).toThrow();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("allows dimensions to be set", function () {
 | 
			
		||||
                // No return value, just verify API is present
 | 
			
		||||
                chart.setDimensions([120, 120], [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;
 | 
			
		||||
                chart.drawLine(testBuffer, testColor, testPoints);
 | 
			
		||||
                expect(mock2d.beginPath).toHaveBeenCalled();
 | 
			
		||||
                expect(mock2d.lineTo.calls.length).toEqual(1);
 | 
			
		||||
                expect(mock2d.stroke).toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("allows squares to be drawn", function () {
 | 
			
		||||
                var testMin = [0, 1],
 | 
			
		||||
                    testMax = [10, 10],
 | 
			
		||||
                    testColor = [0.25, 0.33, 0.66, 1.0];
 | 
			
		||||
 | 
			
		||||
                chart.drawSquare(testMin, testMax, testColor);
 | 
			
		||||
                expect(mock2d.fillRect).toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,143 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MergeModelsSpec. Created by vwoeltje on 11/6/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ["../src/GLChart"],
 | 
			
		||||
    function (GLChart) {
 | 
			
		||||
 | 
			
		||||
        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("does 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);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("uses buffer sizes reported by WebGL", function () {
 | 
			
		||||
                // Make sure that GLChart uses the GL buffer size, which may
 | 
			
		||||
                // differ from what canvas requested. WTD-852
 | 
			
		||||
                mockCanvas.width = 300;
 | 
			
		||||
                mockCanvas.height = 150;
 | 
			
		||||
                mockGL.drawingBufferWidth = 200;
 | 
			
		||||
                mockGL.drawingBufferHeight = 175;
 | 
			
		||||
 | 
			
		||||
                glChart.clear();
 | 
			
		||||
 | 
			
		||||
                expect(mockGL.viewport).toHaveBeenCalledWith(0, 0, 200, 175);
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,216 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MergeModelsSpec. Created by vwoeltje on 11/6/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ["../src/MCTChart"],
 | 
			
		||||
    function (MCTChart) {
 | 
			
		||||
 | 
			
		||||
        describe("The mct-chart directive", function () {
 | 
			
		||||
            var mockInterval,
 | 
			
		||||
                mockLog,
 | 
			
		||||
                mockScope,
 | 
			
		||||
                mockElement,
 | 
			
		||||
                mockCanvas,
 | 
			
		||||
                mockGL,
 | 
			
		||||
                mockC2d,
 | 
			
		||||
                mockPromise,
 | 
			
		||||
                mctChart;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockInterval =
 | 
			
		||||
                    jasmine.createSpy("$interval");
 | 
			
		||||
                mockLog =
 | 
			
		||||
                    jasmine.createSpyObj("$log", ["warn", "info", "debug"]);
 | 
			
		||||
                mockScope = jasmine.createSpyObj(
 | 
			
		||||
                    "$scope",
 | 
			
		||||
                    ["$watchCollection", "$on", "$apply"]
 | 
			
		||||
                );
 | 
			
		||||
                mockElement =
 | 
			
		||||
                    jasmine.createSpyObj("element", ["find", "html"]);
 | 
			
		||||
                mockInterval.cancel = jasmine.createSpy("cancelInterval");
 | 
			
		||||
                mockPromise = jasmine.createSpyObj("promise", ["then"]);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                // mct-chart uses GLChart, so it needs WebGL API
 | 
			
		||||
                mockCanvas =
 | 
			
		||||
                    jasmine.createSpyObj("canvas", ["getContext", "addEventListener"]);
 | 
			
		||||
                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"
 | 
			
		||||
                    ]
 | 
			
		||||
                );
 | 
			
		||||
                mockC2d = jasmine.createSpyObj('c2d', ['clearRect']);
 | 
			
		||||
                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.andCallFake(function (type) {
 | 
			
		||||
                    return { webgl: mockGL, '2d': mockC2d }[type];
 | 
			
		||||
                });
 | 
			
		||||
                mockInterval.andReturn(mockPromise);
 | 
			
		||||
 | 
			
		||||
                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),
 | 
			
		||||
                    0,
 | 
			
		||||
                    false
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                // 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("falls back to Canvas 2d API if WebGL context is lost", function () {
 | 
			
		||||
                mctChart.link(mockScope, mockElement);
 | 
			
		||||
                expect(mockCanvas.addEventListener)
 | 
			
		||||
                    .toHaveBeenCalledWith("webglcontextlost", jasmine.any(Function));
 | 
			
		||||
                expect(mockCanvas.getContext).not.toHaveBeenCalledWith('2d');
 | 
			
		||||
                mockCanvas.addEventListener.mostRecentCall.args[1]();
 | 
			
		||||
                expect(mockCanvas.getContext).toHaveBeenCalledWith('2d');
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("logs nothing in nominal situations (WebGL available)", function () {
 | 
			
		||||
                // Complement the previous test
 | 
			
		||||
                mctChart.link(mockScope, mockElement);
 | 
			
		||||
                expect(mockLog.warn).not.toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Avoid resource leaks
 | 
			
		||||
            it("stops polling for size changes on destroy", function () {
 | 
			
		||||
                mctChart.link(mockScope, mockElement);
 | 
			
		||||
 | 
			
		||||
                // Should be listening for a destroy event
 | 
			
		||||
                expect(mockScope.$on).toHaveBeenCalledWith(
 | 
			
		||||
                    "$destroy",
 | 
			
		||||
                    jasmine.any(Function)
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                // Precondition - interval still active
 | 
			
		||||
                expect(mockInterval.cancel).not.toHaveBeenCalled();
 | 
			
		||||
 | 
			
		||||
                // Broadcast a $destroy
 | 
			
		||||
                mockScope.$on.mostRecentCall.args[1]();
 | 
			
		||||
 | 
			
		||||
                // Should have stopped the interval
 | 
			
		||||
                expect(mockInterval.cancel).toHaveBeenCalledWith(mockPromise);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,403 +0,0 @@
 | 
			
		||||
/*global angular*/
 | 
			
		||||
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MergeModelsSpec. Created by vwoeltje on 11/6/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ["../src/PlotController"],
 | 
			
		||||
    function (PlotController) {
 | 
			
		||||
 | 
			
		||||
        describe("The plot controller", function () {
 | 
			
		||||
            var mockScope,
 | 
			
		||||
                mockElement,
 | 
			
		||||
                mockExportImageService,
 | 
			
		||||
                mockFormatter,
 | 
			
		||||
                mockHandler,
 | 
			
		||||
                mockThrottle,
 | 
			
		||||
                mockHandle,
 | 
			
		||||
                mockDomainObject,
 | 
			
		||||
                mockSeries,
 | 
			
		||||
                mockStatusCapability,
 | 
			
		||||
                controller,
 | 
			
		||||
                mockConductor;
 | 
			
		||||
 | 
			
		||||
            function bind(method, thisObj) {
 | 
			
		||||
                return function () {
 | 
			
		||||
                    return method.apply(thisObj, arguments);
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function fireEvent(name, args) {
 | 
			
		||||
                mockScope.$on.calls.forEach(function (call) {
 | 
			
		||||
                    if (call.args[0] === name) {
 | 
			
		||||
                        call.args[1].apply(null, args || []);
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            function fireWatch(expr, value) {
 | 
			
		||||
                mockScope.$watch.calls.forEach(function (call) {
 | 
			
		||||
                    if (call.args[0] === expr) {
 | 
			
		||||
                        call.args[1].apply(null, [value]);
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockScope = jasmine.createSpyObj(
 | 
			
		||||
                    "$scope",
 | 
			
		||||
                    ["$watch", "$on", "$emit"]
 | 
			
		||||
                );
 | 
			
		||||
                mockElement = angular.element('<div />');
 | 
			
		||||
                mockExportImageService = jasmine.createSpyObj(
 | 
			
		||||
                    "ExportImageService",
 | 
			
		||||
                    ["exportJPG", "exportPNG"]
 | 
			
		||||
                );
 | 
			
		||||
                mockFormatter = jasmine.createSpyObj(
 | 
			
		||||
                    "formatter",
 | 
			
		||||
                    ["formatDomainValue", "formatRangeValue"]
 | 
			
		||||
                );
 | 
			
		||||
                mockDomainObject = jasmine.createSpyObj(
 | 
			
		||||
                    "domainObject",
 | 
			
		||||
                    ["getId", "getModel", "getCapability", "hasCapability"]
 | 
			
		||||
                );
 | 
			
		||||
                mockHandler = jasmine.createSpyObj(
 | 
			
		||||
                    "telemetrySubscriber",
 | 
			
		||||
                    ["handle"]
 | 
			
		||||
                );
 | 
			
		||||
                mockThrottle = jasmine.createSpy("throttle");
 | 
			
		||||
                mockHandle = jasmine.createSpyObj(
 | 
			
		||||
                    "subscription",
 | 
			
		||||
                    [
 | 
			
		||||
                        "unsubscribe",
 | 
			
		||||
                        "getTelemetryObjects",
 | 
			
		||||
                        "getMetadata",
 | 
			
		||||
                        "getDomainValue",
 | 
			
		||||
                        "getRangeValue",
 | 
			
		||||
                        "getDatum",
 | 
			
		||||
                        "request"
 | 
			
		||||
                    ]
 | 
			
		||||
                );
 | 
			
		||||
                mockSeries = jasmine.createSpyObj(
 | 
			
		||||
                    'series',
 | 
			
		||||
                    ['getPointCount', 'getDomainValue', 'getRangeValue']
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                mockStatusCapability = jasmine.createSpyObj(
 | 
			
		||||
                    "statusCapability",
 | 
			
		||||
                    ["set"]
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                mockHandler.handle.andReturn(mockHandle);
 | 
			
		||||
                mockThrottle.andCallFake(function (fn) {
 | 
			
		||||
                    return fn;
 | 
			
		||||
                });
 | 
			
		||||
                mockHandle.getTelemetryObjects.andReturn([mockDomainObject]);
 | 
			
		||||
                mockHandle.getMetadata.andReturn([{}]);
 | 
			
		||||
                mockHandle.getDomainValue.andReturn(123);
 | 
			
		||||
                mockHandle.getRangeValue.andReturn(42);
 | 
			
		||||
                mockScope.domainObject = mockDomainObject;
 | 
			
		||||
 | 
			
		||||
                mockConductor = jasmine.createSpyObj('conductor', [
 | 
			
		||||
                    'on',
 | 
			
		||||
                    'off',
 | 
			
		||||
                    'bounds',
 | 
			
		||||
                    'timeSystem',
 | 
			
		||||
                    'timeOfInterest',
 | 
			
		||||
                    'follow'
 | 
			
		||||
                ]);
 | 
			
		||||
 | 
			
		||||
                mockConductor.bounds.andReturn({});
 | 
			
		||||
 | 
			
		||||
                controller = new PlotController(
 | 
			
		||||
                    mockScope,
 | 
			
		||||
                    mockElement,
 | 
			
		||||
                    mockExportImageService,
 | 
			
		||||
                    mockFormatter,
 | 
			
		||||
                    mockHandler,
 | 
			
		||||
                    mockThrottle,
 | 
			
		||||
                    undefined,
 | 
			
		||||
                    {time: mockConductor}
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("provides plot colors", function () {
 | 
			
		||||
                // PlotPalette will have its own tests
 | 
			
		||||
                expect(controller.getColor(0))
 | 
			
		||||
                    .toEqual(jasmine.any(String));
 | 
			
		||||
 | 
			
		||||
                // Colors should be unique
 | 
			
		||||
                expect(controller.getColor(0))
 | 
			
		||||
                    .not.toEqual(controller.getColor(1));
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("subscribes to telemetry when a domain object appears in scope", function () {
 | 
			
		||||
                // Make sure we're using the right watch here
 | 
			
		||||
                expect(mockScope.$watch.mostRecentCall.args[0])
 | 
			
		||||
                    .toEqual("domainObject");
 | 
			
		||||
                // Make an object available
 | 
			
		||||
                mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
 | 
			
		||||
                // Should have subscribed
 | 
			
		||||
                expect(mockHandler.handle).toHaveBeenCalledWith(
 | 
			
		||||
                    mockDomainObject,
 | 
			
		||||
                    jasmine.any(Function),
 | 
			
		||||
                    true // Lossless
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("draws lines when data becomes available", function () {
 | 
			
		||||
                // Make an object available
 | 
			
		||||
                mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
 | 
			
		||||
 | 
			
		||||
                // Verify precondition
 | 
			
		||||
                controller.getSubPlots().forEach(function (subplot) {
 | 
			
		||||
                    expect(subplot.getDrawingObject().lines)
 | 
			
		||||
                        .not.toBeDefined();
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Make sure there actually are subplots being verified
 | 
			
		||||
                expect(controller.getSubPlots().length > 0).toBeTruthy();
 | 
			
		||||
 | 
			
		||||
                // Broadcast data
 | 
			
		||||
                mockHandler.handle.mostRecentCall.args[1]();
 | 
			
		||||
 | 
			
		||||
                controller.getSubPlots().forEach(function (subplot) {
 | 
			
		||||
                    expect(subplot.getDrawingObject().lines)
 | 
			
		||||
                        .toBeDefined();
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("unsubscribes when domain object changes", function () {
 | 
			
		||||
                // Make an object available
 | 
			
		||||
                mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
 | 
			
		||||
                // Verify precondition - shouldn't unsubscribe yet
 | 
			
		||||
                expect(mockHandle.unsubscribe).not.toHaveBeenCalled();
 | 
			
		||||
                // Remove the domain object
 | 
			
		||||
                mockScope.$watch.mostRecentCall.args[1](undefined);
 | 
			
		||||
                // Should have unsubscribed
 | 
			
		||||
                expect(mockHandle.unsubscribe).toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            it("changes modes depending on number of objects", function () {
 | 
			
		||||
                // Act like one object is available
 | 
			
		||||
                mockHandle.getTelemetryObjects.andReturn([
 | 
			
		||||
                    mockDomainObject
 | 
			
		||||
                ]);
 | 
			
		||||
 | 
			
		||||
                // Make an object available; invoke handler's callback
 | 
			
		||||
                mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
 | 
			
		||||
                mockHandler.handle.mostRecentCall.args[1]();
 | 
			
		||||
 | 
			
		||||
                expect(controller.getModeOptions().length).toEqual(1);
 | 
			
		||||
 | 
			
		||||
                // Act like one object is available
 | 
			
		||||
                mockHandle.getTelemetryObjects.andReturn([
 | 
			
		||||
                    mockDomainObject,
 | 
			
		||||
                    mockDomainObject,
 | 
			
		||||
                    mockDomainObject
 | 
			
		||||
                ]);
 | 
			
		||||
 | 
			
		||||
                // Make an object available; invoke handler's callback
 | 
			
		||||
                mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
 | 
			
		||||
                mockHandler.handle.mostRecentCall.args[1]();
 | 
			
		||||
 | 
			
		||||
                expect(controller.getModeOptions().length).toEqual(2);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Interface tests follow; these will be delegated (mostly
 | 
			
		||||
            // to PlotModeOptions, which is tested separately).
 | 
			
		||||
            it("provides access to available plot mode options", function () {
 | 
			
		||||
                expect(Array.isArray(controller.getModeOptions()))
 | 
			
		||||
                    .toBeTruthy();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("provides a current plot mode", function () {
 | 
			
		||||
                expect(controller.getMode().name)
 | 
			
		||||
                    .toEqual(jasmine.any(String));
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("allows plot mode to be changed", function () {
 | 
			
		||||
                expect(function () {
 | 
			
		||||
                    controller.setMode(controller.getMode());
 | 
			
		||||
                }).not.toThrow();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("provides an array of sub-plots", function () {
 | 
			
		||||
                expect(Array.isArray(controller.getSubPlots()))
 | 
			
		||||
                    .toBeTruthy();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("allows plots to be updated", function () {
 | 
			
		||||
                expect(bind(controller.update, controller)).not.toThrow();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("allows changing pan-zoom state", function () {
 | 
			
		||||
                expect(bind(controller.isZoomed, controller)).not.toThrow();
 | 
			
		||||
                expect(bind(controller.stepBackPanZoom, controller)).not.toThrow();
 | 
			
		||||
                expect(bind(controller.unzoom, controller)).not.toThrow();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("sets status when plot becomes detached from time conductor", function () {
 | 
			
		||||
                mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
 | 
			
		||||
 | 
			
		||||
                function boundsEvent() {
 | 
			
		||||
                    fireEvent("telemetry:display:bounds", [
 | 
			
		||||
                        {},
 | 
			
		||||
                        { start: 10, end: 100 },
 | 
			
		||||
                        true
 | 
			
		||||
                    ]);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                mockDomainObject.hasCapability.andCallFake(function (name) {
 | 
			
		||||
                    return name === "status";
 | 
			
		||||
                });
 | 
			
		||||
                mockDomainObject.getCapability.andReturn(mockStatusCapability);
 | 
			
		||||
                spyOn(controller, "isZoomed");
 | 
			
		||||
 | 
			
		||||
                //Mock zoomed in state
 | 
			
		||||
                controller.isZoomed.andReturn(true);
 | 
			
		||||
                boundsEvent();
 | 
			
		||||
                expect(mockStatusCapability.set).toHaveBeenCalledWith("timeconductor-unsynced", true);
 | 
			
		||||
 | 
			
		||||
                //"Reset" zoom
 | 
			
		||||
                controller.isZoomed.andReturn(false);
 | 
			
		||||
                boundsEvent();
 | 
			
		||||
                expect(mockStatusCapability.set).toHaveBeenCalledWith("timeconductor-unsynced", false);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("indicates if a request is pending", function () {
 | 
			
		||||
                mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
 | 
			
		||||
                expect(controller.isRequestPending()).toBeTruthy();
 | 
			
		||||
                mockHandle.request.mostRecentCall.args[1](
 | 
			
		||||
                    mockDomainObject,
 | 
			
		||||
                    mockSeries
 | 
			
		||||
                );
 | 
			
		||||
                expect(controller.isRequestPending()).toBeFalsy();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("requests historical telemetry", function () {
 | 
			
		||||
                mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
 | 
			
		||||
                expect(mockHandle.request).toHaveBeenCalled();
 | 
			
		||||
                mockHandle.request.mostRecentCall.args[1](
 | 
			
		||||
                    mockDomainObject,
 | 
			
		||||
                    mockSeries
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("unsubscribes when destroyed", function () {
 | 
			
		||||
                // Make an object available
 | 
			
		||||
                mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
 | 
			
		||||
                // Make sure $destroy is what's listened for
 | 
			
		||||
                expect(mockScope.$on.mostRecentCall.args[0]).toEqual('$destroy');
 | 
			
		||||
                // Also verify precondition
 | 
			
		||||
                expect(mockHandle.unsubscribe).not.toHaveBeenCalled();
 | 
			
		||||
                // Destroy the scope
 | 
			
		||||
                fireEvent("$destroy");
 | 
			
		||||
                // Should have unsubscribed
 | 
			
		||||
                expect(mockHandle.unsubscribe).toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("requeries when displayable bounds change", function () {
 | 
			
		||||
                mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
 | 
			
		||||
                expect(mockHandle.request.calls.length).toEqual(1);
 | 
			
		||||
                fireEvent("telemetry:display:bounds", [
 | 
			
		||||
                    {},
 | 
			
		||||
                    { start: 10, end: 100 }
 | 
			
		||||
                ]);
 | 
			
		||||
                expect(mockHandle.request.calls.length).toEqual(2);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("requeries when user changes domain selection", function () {
 | 
			
		||||
                mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
 | 
			
		||||
                expect(mockHandle.request.calls.length).toEqual(1);
 | 
			
		||||
                fireWatch("axes[0].active.key", 'someNewKey');
 | 
			
		||||
                expect(mockHandle.request.calls.length).toEqual(2);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("requeries when user changes range selection", function () {
 | 
			
		||||
                mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
 | 
			
		||||
                expect(mockHandle.request.calls.length).toEqual(1);
 | 
			
		||||
                fireWatch("axes[1].active.key", 'someNewKey');
 | 
			
		||||
                expect(mockHandle.request.calls.length).toEqual(2);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("maintains externally-provided domain axis bounds after data is received", function () {
 | 
			
		||||
                mockSeries.getPointCount.andReturn(3);
 | 
			
		||||
                mockSeries.getRangeValue.andReturn(42);
 | 
			
		||||
                mockSeries.getDomainValue.andCallFake(function (i) {
 | 
			
		||||
                    return 2500 + i * 2500;
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
 | 
			
		||||
                fireEvent("telemetry:display:bounds", [
 | 
			
		||||
                    {},
 | 
			
		||||
                    {start: 0, end: 10000}
 | 
			
		||||
                ]);
 | 
			
		||||
                mockHandle.request.mostRecentCall.args[1](
 | 
			
		||||
                    mockDomainObject,
 | 
			
		||||
                    mockSeries
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                // Pan-zoom state should reflect bounds set externally;
 | 
			
		||||
                // domain axis should not have shrunk to fit data.
 | 
			
		||||
                expect(
 | 
			
		||||
                    controller.getSubPlots()[0].panZoomStack.getOrigin()[0]
 | 
			
		||||
                ).toEqual(0);
 | 
			
		||||
                expect(
 | 
			
		||||
                    controller.getSubPlots()[0].panZoomStack.getDimensions()[0]
 | 
			
		||||
                ).toEqual(10000);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("provides classes for legends based on limit state", function () {
 | 
			
		||||
                var mockTelemetryObjects = mockHandle.getTelemetryObjects();
 | 
			
		||||
 | 
			
		||||
                mockHandle.getDatum.andReturn({});
 | 
			
		||||
                mockTelemetryObjects.forEach(function (mockObject, i) {
 | 
			
		||||
                    var id = 'object-' + i,
 | 
			
		||||
                        mockLimitCapability =
 | 
			
		||||
                            jasmine.createSpyObj('limit-' + id, ['evaluate']);
 | 
			
		||||
 | 
			
		||||
                    mockObject.getId.andReturn(id);
 | 
			
		||||
                    mockObject.getCapability.andCallFake(function (key) {
 | 
			
		||||
                        return (key === 'limit') && mockLimitCapability;
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    mockLimitCapability.evaluate
 | 
			
		||||
                        .andReturn({ cssClass: 'alarm-' + id });
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
 | 
			
		||||
                mockHandler.handle.mostRecentCall.args[1]();
 | 
			
		||||
 | 
			
		||||
                mockTelemetryObjects.forEach(function (mockTelemetryObject) {
 | 
			
		||||
                    expect(controller.getLegendClass(mockTelemetryObject))
 | 
			
		||||
                        .toEqual('alarm-' + mockTelemetryObject.getId());
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,147 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    ['../src/PlotOptionsController'],
 | 
			
		||||
    function (PlotOptionsController) {
 | 
			
		||||
 | 
			
		||||
        describe("The Plot Options controller", function () {
 | 
			
		||||
            var plotOptionsController,
 | 
			
		||||
                mockDomainObject,
 | 
			
		||||
                mockMutationCapability,
 | 
			
		||||
                mockUseCapabilities,
 | 
			
		||||
                mockCompositionCapability,
 | 
			
		||||
                mockComposition,
 | 
			
		||||
                mockUnlisten,
 | 
			
		||||
                mockChildOne,
 | 
			
		||||
                mockChildTwo,
 | 
			
		||||
                model,
 | 
			
		||||
                mockScope;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                model = {
 | 
			
		||||
                    composition: ['childOne']
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                mockChildOne = jasmine.createSpyObj('domainObject', [
 | 
			
		||||
                   'getId'
 | 
			
		||||
                ]);
 | 
			
		||||
                mockChildOne.getId.andReturn('childOne');
 | 
			
		||||
 | 
			
		||||
                mockChildTwo = jasmine.createSpyObj('childTwo', [
 | 
			
		||||
                    'getId'
 | 
			
		||||
                ]);
 | 
			
		||||
                mockChildOne.getId.andReturn('childTwo');
 | 
			
		||||
 | 
			
		||||
                mockCompositionCapability = jasmine.createSpyObj('compositionCapability', [
 | 
			
		||||
                    'then'
 | 
			
		||||
                ]);
 | 
			
		||||
                mockComposition = [
 | 
			
		||||
                    mockChildOne
 | 
			
		||||
                ];
 | 
			
		||||
                mockCompositionCapability.then.andCallFake(function (callback) {
 | 
			
		||||
                    callback(mockComposition);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                mockUseCapabilities = jasmine.createSpyObj('useCapabilities', [
 | 
			
		||||
                    'composition',
 | 
			
		||||
                    'mutation'
 | 
			
		||||
                ]);
 | 
			
		||||
                mockUseCapabilities.composition.andReturn(mockCompositionCapability);
 | 
			
		||||
 | 
			
		||||
                mockMutationCapability = jasmine.createSpyObj('mutationCapability', [
 | 
			
		||||
                    'listen'
 | 
			
		||||
                ]);
 | 
			
		||||
                mockUnlisten = jasmine.createSpy('unlisten');
 | 
			
		||||
                mockMutationCapability.listen.andReturn(mockUnlisten);
 | 
			
		||||
 | 
			
		||||
                mockDomainObject = jasmine.createSpyObj('domainObject', [
 | 
			
		||||
                    'getModel',
 | 
			
		||||
                    'useCapability',
 | 
			
		||||
                    'getCapability'
 | 
			
		||||
                ]);
 | 
			
		||||
                mockDomainObject.useCapability.andCallFake(function (capability) {
 | 
			
		||||
                    return mockUseCapabilities[capability]();
 | 
			
		||||
                });
 | 
			
		||||
                mockDomainObject.getCapability.andReturn(mockMutationCapability);
 | 
			
		||||
                mockDomainObject.getModel.andReturn(model);
 | 
			
		||||
 | 
			
		||||
                mockScope = jasmine.createSpyObj('scope', [
 | 
			
		||||
                    '$on',
 | 
			
		||||
                    '$watchCollection'
 | 
			
		||||
                ]);
 | 
			
		||||
                mockScope.domainObject = mockDomainObject;
 | 
			
		||||
 | 
			
		||||
                function noop() {}
 | 
			
		||||
                mockScope.$watchCollection.andReturn(noop);
 | 
			
		||||
 | 
			
		||||
                plotOptionsController = new PlotOptionsController(mockScope);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("sets form definitions on scope", function () {
 | 
			
		||||
                expect(mockScope.xAxisForm).toBeDefined();
 | 
			
		||||
                expect(mockScope.yAxisForm).toBeDefined();
 | 
			
		||||
                expect(mockScope.plotSeriesForm).toBeDefined();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("sets object children on scope", function () {
 | 
			
		||||
                expect(mockScope.children).toBe(mockComposition);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("on changes in object composition, updates the form", function () {
 | 
			
		||||
                expect(mockMutationCapability.listen).toHaveBeenCalled();
 | 
			
		||||
                expect(mockScope.children).toBe(mockComposition);
 | 
			
		||||
                expect(mockScope.children.length).toBe(1);
 | 
			
		||||
                mockComposition.push(mockChildTwo);
 | 
			
		||||
                model.composition.push('childTwo');
 | 
			
		||||
                mockMutationCapability.listen.mostRecentCall.args[0](model);
 | 
			
		||||
                expect(mockScope.children).toBe(mockComposition);
 | 
			
		||||
                expect(mockScope.children.length).toBe(2);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("on changes in form values, updates the object model", function () {
 | 
			
		||||
                var scopeConfiguration = mockScope.configuration,
 | 
			
		||||
                    objModel = mockDomainObject.getModel();
 | 
			
		||||
 | 
			
		||||
                scopeConfiguration.plot.yAxis.autoScale = true;
 | 
			
		||||
                scopeConfiguration.plot.yAxis.key = 'eu';
 | 
			
		||||
                scopeConfiguration.plot.xAxis.key = 'lst';
 | 
			
		||||
 | 
			
		||||
                expect(mockScope.$watchCollection).toHaveBeenCalled();
 | 
			
		||||
                mockScope.$watchCollection.calls[0].args[1]();
 | 
			
		||||
                expect(mockDomainObject.useCapability).toHaveBeenCalledWith('mutation', jasmine.any(Function));
 | 
			
		||||
 | 
			
		||||
                mockDomainObject.useCapability.mostRecentCall.args[1](objModel);
 | 
			
		||||
                expect(objModel.configuration.plot.yAxis.autoScale).toBe(true);
 | 
			
		||||
                expect(objModel.configuration.plot.yAxis.key).toBe('eu');
 | 
			
		||||
                expect(objModel.configuration.plot.xAxis.key).toBe('lst');
 | 
			
		||||
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("cleans up listeners on destruction of the controller", function () {
 | 
			
		||||
                mockScope.$on.mostRecentCall.args[1]();
 | 
			
		||||
                expect(mockUnlisten).toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,47 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    ['../src/PlotOptionsForm'],
 | 
			
		||||
    function (PlotOptionsForm) {
 | 
			
		||||
 | 
			
		||||
        describe("The Plot Options form", function () {
 | 
			
		||||
            var plotOptionsForm;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
 | 
			
		||||
                plotOptionsForm = new PlotOptionsForm();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("defines form specs for x-axis, y-axis, and series data", function () {
 | 
			
		||||
                expect(plotOptionsForm.xAxisForm).toBeDefined();
 | 
			
		||||
                expect(plotOptionsForm.xAxisForm.sections).toBeDefined();
 | 
			
		||||
                expect(plotOptionsForm.xAxisForm.sections[0].rows).toBeDefined();
 | 
			
		||||
                expect(plotOptionsForm.xAxisForm.sections[0].rows.length).toBeGreaterThan(0);
 | 
			
		||||
 | 
			
		||||
                expect(plotOptionsForm.yAxisForm).toBeDefined();
 | 
			
		||||
                expect(plotOptionsForm.plotSeriesForm).toBeDefined();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,66 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MergeModelsSpec. Created by vwoeltje on 11/6/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ["../src/SubPlotFactory"],
 | 
			
		||||
    function (SubPlotFactory) {
 | 
			
		||||
 | 
			
		||||
        describe("The sub-plot factory", function () {
 | 
			
		||||
            var mockDomainObject,
 | 
			
		||||
                mockPanZoomStack,
 | 
			
		||||
                mockFormatter,
 | 
			
		||||
                factory;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockDomainObject = jasmine.createSpyObj(
 | 
			
		||||
                    "domainObject",
 | 
			
		||||
                    ["getId", "getModel", "getCapability"]
 | 
			
		||||
                );
 | 
			
		||||
                mockPanZoomStack = jasmine.createSpyObj(
 | 
			
		||||
                    "panZoomStack",
 | 
			
		||||
                    ["getPanZoom"]
 | 
			
		||||
                );
 | 
			
		||||
                mockFormatter = jasmine.createSpyObj(
 | 
			
		||||
                    "formatter",
 | 
			
		||||
                    ["formatDomainValue", "formatRangeValue"]
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                mockPanZoomStack.getPanZoom.andReturn({
 | 
			
		||||
                    origin: [0, 0],
 | 
			
		||||
                    dimensions: [100, 100]
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                factory = new SubPlotFactory(mockFormatter);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("creates sub-plots", function () {
 | 
			
		||||
                expect(factory.createSubPlot(
 | 
			
		||||
                    [mockDomainObject],
 | 
			
		||||
                    mockPanZoomStack
 | 
			
		||||
                ).getTelemetryObjects()).toEqual([mockDomainObject]);
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,208 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MergeModelsSpec. Created by vwoeltje on 11/6/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ["../src/SubPlot"],
 | 
			
		||||
    function (SubPlot) {
 | 
			
		||||
 | 
			
		||||
        describe("A sub-plot", function () {
 | 
			
		||||
            var mockDomainObject,
 | 
			
		||||
                mockPanZoomStack,
 | 
			
		||||
                mockFormatter,
 | 
			
		||||
                mockElement,
 | 
			
		||||
                testDomainObjects,
 | 
			
		||||
                testOrigin,
 | 
			
		||||
                testDimensions,
 | 
			
		||||
                subplot;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockDomainObject = jasmine.createSpyObj(
 | 
			
		||||
                    "domainObject",
 | 
			
		||||
                    ["getId", "getModel", "getCapability"]
 | 
			
		||||
                );
 | 
			
		||||
                mockPanZoomStack = jasmine.createSpyObj(
 | 
			
		||||
                    "panZoomStack",
 | 
			
		||||
                    [
 | 
			
		||||
                        "getDepth",
 | 
			
		||||
                        "pushPanZoom",
 | 
			
		||||
                        "popPanZoom",
 | 
			
		||||
                        "setBasePanZoom",
 | 
			
		||||
                        "clearPanZoom",
 | 
			
		||||
                        "getPanZoom",
 | 
			
		||||
                        "getOrigin",
 | 
			
		||||
                        "getDimensions"
 | 
			
		||||
                    ]
 | 
			
		||||
                );
 | 
			
		||||
                mockFormatter = jasmine.createSpyObj(
 | 
			
		||||
                    "formatter",
 | 
			
		||||
                    ["formatDomainValue", "formatRangeValue"]
 | 
			
		||||
                );
 | 
			
		||||
                mockElement = jasmine.createSpyObj(
 | 
			
		||||
                    "element",
 | 
			
		||||
                    ["getBoundingClientRect"]
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                testOrigin = [5, 10];
 | 
			
		||||
                testDimensions = [3000, 1000];
 | 
			
		||||
                testDomainObjects = [mockDomainObject, mockDomainObject];
 | 
			
		||||
 | 
			
		||||
                mockPanZoomStack.getOrigin.andReturn(testOrigin);
 | 
			
		||||
                mockPanZoomStack.getDimensions.andReturn(testDimensions);
 | 
			
		||||
                mockPanZoomStack.getPanZoom.andReturn(
 | 
			
		||||
                    { origin: testOrigin, dimensions: testDimensions }
 | 
			
		||||
                );
 | 
			
		||||
                mockElement.getBoundingClientRect.andReturn(
 | 
			
		||||
                    { left: 10, top: 20, width: 100, height: 100 }
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                subplot = new SubPlot(
 | 
			
		||||
                    testDomainObjects,
 | 
			
		||||
                    mockPanZoomStack,
 | 
			
		||||
                    mockFormatter
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            it("provides a getter for its plotted objects", function () {
 | 
			
		||||
                expect(subplot.getTelemetryObjects())
 | 
			
		||||
                    .toEqual(testDomainObjects);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("exposes tick marks", function () {
 | 
			
		||||
                // Just test availability; details are tested
 | 
			
		||||
                // in PlotTickFormatter
 | 
			
		||||
                expect(Array.isArray(subplot.getDomainTicks()))
 | 
			
		||||
                    .toBeTruthy();
 | 
			
		||||
                expect(Array.isArray(subplot.getRangeTicks()))
 | 
			
		||||
                    .toBeTruthy();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("allows hovering state to be tracked", function () {
 | 
			
		||||
                expect(subplot.isHovering()).toBeFalsy();
 | 
			
		||||
                expect(subplot.isHovering(true)).toBeTruthy();
 | 
			
		||||
                expect(subplot.isHovering()).toBeTruthy();
 | 
			
		||||
                expect(subplot.isHovering(false)).toBeFalsy();
 | 
			
		||||
                expect(subplot.isHovering()).toBeFalsy();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("provides hovering coordinates", function () {
 | 
			
		||||
                // Should be empty when not hovering
 | 
			
		||||
                expect(subplot.getHoverCoordinates())
 | 
			
		||||
                    .toBeUndefined();
 | 
			
		||||
 | 
			
		||||
                // Start hovering
 | 
			
		||||
                subplot.hover({ target: mockElement });
 | 
			
		||||
 | 
			
		||||
                // Should now have coordinates to display
 | 
			
		||||
                expect(subplot.getHoverCoordinates())
 | 
			
		||||
                    .toEqual(jasmine.any(String));
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("supports marquee zoom", function () {
 | 
			
		||||
                expect(mockPanZoomStack.pushPanZoom).not.toHaveBeenCalled();
 | 
			
		||||
 | 
			
		||||
                // Simulate a marquee zoom. Note that the mockElement
 | 
			
		||||
                // is 100 by 100 and starts at 10,20
 | 
			
		||||
                subplot.startDrag({
 | 
			
		||||
                    target: mockElement,
 | 
			
		||||
                    clientX: 60,
 | 
			
		||||
                    clientY: 45
 | 
			
		||||
                });
 | 
			
		||||
                subplot.hover({
 | 
			
		||||
                    target: mockElement,
 | 
			
		||||
                    clientX: 75,
 | 
			
		||||
                    clientY: 85
 | 
			
		||||
                });
 | 
			
		||||
                subplot.endDrag({
 | 
			
		||||
                    target: mockElement,
 | 
			
		||||
                    clientX: 80,
 | 
			
		||||
                    clientY: 95
 | 
			
		||||
                });
 | 
			
		||||
                // ... so the origin should be 50%,25% into current dimensions,
 | 
			
		||||
                //     and new dimensions should be 20%,50% thereof
 | 
			
		||||
 | 
			
		||||
                expect(mockPanZoomStack.pushPanZoom).toHaveBeenCalledWith(
 | 
			
		||||
                    [
 | 
			
		||||
                        testOrigin[0] + testDimensions[0] * 0.50,
 | 
			
		||||
                        testOrigin[1] + testDimensions[1] * 0.25
 | 
			
		||||
                    ],
 | 
			
		||||
                    [
 | 
			
		||||
                        testDimensions[0] * 0.20,
 | 
			
		||||
                        testDimensions[1] * 0.50
 | 
			
		||||
                    ]
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it ("indicates when there is domain data shown", function () {
 | 
			
		||||
                expect(subplot.hasDomainData()).toEqual(true);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it ("indicates when there is no domain data shown", function () {
 | 
			
		||||
                mockPanZoomStack.getDimensions.andReturn([0,0]);
 | 
			
		||||
                expect(subplot.hasDomainData()).toEqual(false);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("disallows marquee zoom when start and end Marquee is at the same position", function () {
 | 
			
		||||
                expect(mockPanZoomStack.pushPanZoom).not.toHaveBeenCalled();
 | 
			
		||||
 | 
			
		||||
                // Simulate a marquee zoom. Note that the mockElement
 | 
			
		||||
                // is 100 by 100 and starts at 10,20
 | 
			
		||||
                subplot.startDrag({
 | 
			
		||||
                    target: mockElement,
 | 
			
		||||
                    clientX: 60,
 | 
			
		||||
                    clientY: 45
 | 
			
		||||
                });
 | 
			
		||||
                subplot.hover({
 | 
			
		||||
                    target: mockElement,
 | 
			
		||||
                    clientX: 75,
 | 
			
		||||
                    clientY: 85
 | 
			
		||||
                });
 | 
			
		||||
                subplot.endDrag({
 | 
			
		||||
                    target: mockElement,
 | 
			
		||||
                    clientX: 60,
 | 
			
		||||
                    clientY: 45
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                expect(mockPanZoomStack.pushPanZoom).not.toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("provides access to a drawable object", function () {
 | 
			
		||||
                expect(typeof subplot.getDrawingObject()).toEqual('object');
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("allows a domain offset to be provided", function () {
 | 
			
		||||
                // Domain object is needed to adjust canvas coordinates
 | 
			
		||||
                // to avoid loss-of-precision associated with converting
 | 
			
		||||
                // to 32 bit floats.
 | 
			
		||||
                subplot.setDomainOffset(3);
 | 
			
		||||
                subplot.update();
 | 
			
		||||
                // Should have adjusted the origin accordingly
 | 
			
		||||
                expect(subplot.getDrawingObject().origin[0])
 | 
			
		||||
                    .toEqual(2);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,107 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MergeModelsSpec. Created by vwoeltje on 11/6/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ["../../src/elements/PlotAxis"],
 | 
			
		||||
    function (PlotAxis) {
 | 
			
		||||
 | 
			
		||||
        describe("A plot axis", function () {
 | 
			
		||||
            var testMetadatas,
 | 
			
		||||
                testDefault,
 | 
			
		||||
                axis;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                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" };
 | 
			
		||||
                axis = new PlotAxis("tests", testMetadatas, testDefault);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("pulls out a list of domain or range options", function () {
 | 
			
		||||
                // Should have filtered out duplicates, etc
 | 
			
		||||
                expect(axis.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(axis.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);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("allows options to be chosen by key", function () {
 | 
			
		||||
                axis.chooseOption("t3");
 | 
			
		||||
                expect(axis.active).toEqual({ key: "t3", name: "T3" });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("reflects changes to applicable metadata", function () {
 | 
			
		||||
                axis.updateMetadata([testMetadatas[1]]);
 | 
			
		||||
                expect(axis.options).toEqual([
 | 
			
		||||
                    { key: "t0", name: "T0" },
 | 
			
		||||
                    { key: "t2", name: "T2" }
 | 
			
		||||
                ]);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("returns the same array instance for unchanged metadata", function () {
 | 
			
		||||
                // ...to avoid triggering extra digest cycles.
 | 
			
		||||
                var oldInstance = axis.options;
 | 
			
		||||
                axis.updateMetadata(testMetadatas);
 | 
			
		||||
                expect(axis.options).toBe(oldInstance);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,100 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    ["../../src/elements/PlotLimitTracker"],
 | 
			
		||||
    function (PlotLimitTracker) {
 | 
			
		||||
 | 
			
		||||
        describe("A plot's limit tracker", function () {
 | 
			
		||||
            var mockHandle,
 | 
			
		||||
                testRange,
 | 
			
		||||
                mockTelemetryObjects,
 | 
			
		||||
                testData,
 | 
			
		||||
                tracker;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                testRange = "some-range";
 | 
			
		||||
                testData = {};
 | 
			
		||||
                mockHandle = jasmine.createSpyObj(
 | 
			
		||||
                    'handle',
 | 
			
		||||
                    ['getTelemetryObjects', 'getDatum']
 | 
			
		||||
                );
 | 
			
		||||
                mockTelemetryObjects = ['a', 'b', 'c'].map(function (id, i) {
 | 
			
		||||
                    var mockTelemetryObject = jasmine.createSpyObj(
 | 
			
		||||
                            'object-' + id,
 | 
			
		||||
                            ['getId', 'getCapability', 'getModel']
 | 
			
		||||
                        ),
 | 
			
		||||
                        mockLimitCapability = jasmine.createSpyObj(
 | 
			
		||||
                            'limit-' + id,
 | 
			
		||||
                            ['evaluate']
 | 
			
		||||
                        );
 | 
			
		||||
                    testData[id] = { id: id, value: i };
 | 
			
		||||
                    mockTelemetryObject.getId.andReturn(id);
 | 
			
		||||
                    mockTelemetryObject.getCapability.andCallFake(function (key) {
 | 
			
		||||
                        return key === 'limit' && mockLimitCapability;
 | 
			
		||||
                    });
 | 
			
		||||
                    mockLimitCapability.evaluate
 | 
			
		||||
                        .andReturn({ cssClass: 'alarm-' + id});
 | 
			
		||||
                    return mockTelemetryObject;
 | 
			
		||||
                });
 | 
			
		||||
                mockHandle.getTelemetryObjects.andReturn(mockTelemetryObjects);
 | 
			
		||||
                mockHandle.getDatum.andCallFake(function (telemetryObject) {
 | 
			
		||||
                    return testData[telemetryObject.getId()];
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                tracker = new PlotLimitTracker(mockHandle, testRange);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("initially provides no limit state", function () {
 | 
			
		||||
                mockTelemetryObjects.forEach(function (mockTelemetryObject) {
 | 
			
		||||
                    expect(tracker.getLegendClass(mockTelemetryObject))
 | 
			
		||||
                        .toBeUndefined();
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            describe("when asked to update", function () {
 | 
			
		||||
                beforeEach(function () {
 | 
			
		||||
                    tracker.update();
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                it("evaluates limits using the limit capability", function () {
 | 
			
		||||
                    mockTelemetryObjects.forEach(function (mockTelemetryObject) {
 | 
			
		||||
                        var id = mockTelemetryObject.getId(),
 | 
			
		||||
                            mockLimit =
 | 
			
		||||
                                mockTelemetryObject.getCapability('limit');
 | 
			
		||||
                        expect(mockLimit.evaluate)
 | 
			
		||||
                            .toHaveBeenCalledWith(testData[id], testRange);
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                it("exposes legend classes returned by the limit capability", function () {
 | 
			
		||||
                    mockTelemetryObjects.forEach(function (mockTelemetryObject) {
 | 
			
		||||
                        var id = mockTelemetryObject.getId();
 | 
			
		||||
                        expect(tracker.getLegendClass(mockTelemetryObject))
 | 
			
		||||
                            .toEqual('alarm-' + id);
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,167 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MergeModelsSpec. Created by vwoeltje on 11/6/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ["../../src/elements/PlotLineBuffer"],
 | 
			
		||||
    function (PlotLineBuffer) {
 | 
			
		||||
 | 
			
		||||
        var TEST_INITIAL_SIZE = 10,
 | 
			
		||||
            TEST_MAX_SIZE = 40,
 | 
			
		||||
            TEST_DOMAIN_OFFSET = 42;
 | 
			
		||||
 | 
			
		||||
        describe("A plot line buffer", function () {
 | 
			
		||||
            var mockSeries,
 | 
			
		||||
                testDomainValues,
 | 
			
		||||
                testRangeValues,
 | 
			
		||||
                buffer;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                testDomainValues = [1, 3, 7, 9, 14, 15];
 | 
			
		||||
                testRangeValues = [8, 0, 3, 9, 8, 11];
 | 
			
		||||
                mockSeries = jasmine.createSpyObj(
 | 
			
		||||
                    "series",
 | 
			
		||||
                    ['getPointCount', 'getDomainValue', 'getRangeValue']
 | 
			
		||||
                );
 | 
			
		||||
                mockSeries.getPointCount.andCallFake(function () {
 | 
			
		||||
                    return testDomainValues.length;
 | 
			
		||||
                });
 | 
			
		||||
                mockSeries.getDomainValue.andCallFake(function (i) {
 | 
			
		||||
                    return testDomainValues[i];
 | 
			
		||||
                });
 | 
			
		||||
                mockSeries.getRangeValue.andCallFake(function (i) {
 | 
			
		||||
                    return testRangeValues[i];
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                buffer = new PlotLineBuffer(
 | 
			
		||||
                    TEST_DOMAIN_OFFSET,
 | 
			
		||||
                    TEST_INITIAL_SIZE,
 | 
			
		||||
                    TEST_MAX_SIZE
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                // Start with some data in there
 | 
			
		||||
                buffer.insert(mockSeries, 0);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("allows insertion of series data", function () {
 | 
			
		||||
                // Convert to a regular array for checking.
 | 
			
		||||
                // Verify that domain/ranges were interleaved and
 | 
			
		||||
                // that domain offset was adjusted for.
 | 
			
		||||
                expect(
 | 
			
		||||
                    Array.prototype.slice.call(buffer.getBuffer()).slice(0, 12)
 | 
			
		||||
                ).toEqual([-41, 8, -39, 0, -35, 3, -33, 9, -28, 8, -27, 11]);
 | 
			
		||||
                expect(buffer.getLength()).toEqual(6);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("finds insertion indexes", function () {
 | 
			
		||||
                expect(buffer.findInsertionIndex(0)).toEqual(0);
 | 
			
		||||
                expect(buffer.findInsertionIndex(2)).toEqual(1);
 | 
			
		||||
                expect(buffer.findInsertionIndex(5)).toEqual(2);
 | 
			
		||||
                expect(buffer.findInsertionIndex(10)).toEqual(4);
 | 
			
		||||
                expect(buffer.findInsertionIndex(14.5)).toEqual(5);
 | 
			
		||||
                expect(buffer.findInsertionIndex(20)).toEqual(6);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("allows insertion in the middle", function () {
 | 
			
		||||
                var head = [-41, 8, -39, 0, -35, 3],
 | 
			
		||||
                    tail = [-33, 9, -28, 8, -27, 11];
 | 
			
		||||
                buffer.insert(mockSeries, 3);
 | 
			
		||||
                expect(
 | 
			
		||||
                    Array.prototype.slice.call(buffer.getBuffer()).slice(0, 24)
 | 
			
		||||
                ).toEqual(head.concat(head).concat(tail).concat(tail));
 | 
			
		||||
                expect(buffer.getLength()).toEqual(12);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("allows values to be trimmed from the start", function () {
 | 
			
		||||
                buffer.trim(2);
 | 
			
		||||
                expect(buffer.getLength()).toEqual(4);
 | 
			
		||||
                expect(
 | 
			
		||||
                    Array.prototype.slice.call(buffer.getBuffer()).slice(0, 8)
 | 
			
		||||
                ).toEqual([-35, 3, -33, 9, -28, 8, -27, 11]);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("expands buffer when needed to accommodate more data", function () {
 | 
			
		||||
                var i;
 | 
			
		||||
 | 
			
		||||
                // Initial underlying buffer should be twice initial size...
 | 
			
		||||
                // (Since each pair will take up two elements)
 | 
			
		||||
                expect(buffer.getBuffer().length).toEqual(20);
 | 
			
		||||
 | 
			
		||||
                // Should be able to insert 6 series of 6 points each
 | 
			
		||||
                // (After that, we'll hit the test max of 40)
 | 
			
		||||
                for (i = 1; i < 15; i += 1) {
 | 
			
		||||
                    expect(buffer.insertPoint(i * 10, Math.sin(i), i))
 | 
			
		||||
                        .toBeTruthy();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Buffer should have expanded in the process
 | 
			
		||||
                expect(buffer.getBuffer().length).toEqual(40);
 | 
			
		||||
 | 
			
		||||
                // Push to maximum size just to make sure...
 | 
			
		||||
                for (i = 1; i < 150; i += 1) {
 | 
			
		||||
                    buffer.insertPoint(i * 10, Math.sin(i), i);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                expect(buffer.getBuffer().length).toEqual(80);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("ensures a maximum size", function () {
 | 
			
		||||
                var i;
 | 
			
		||||
 | 
			
		||||
                // Should be able to insert 6 series of 6 points each
 | 
			
		||||
                // (After that, we'll hit the test max of 40)
 | 
			
		||||
                for (i = 1; i < 6; i += 1) {
 | 
			
		||||
                    expect(buffer.getLength()).toEqual(6 * i);
 | 
			
		||||
                    expect(buffer.insert(mockSeries, Number.POSITIVE_INFINITY))
 | 
			
		||||
                        .toBeTruthy();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Should be maxed out now
 | 
			
		||||
                expect(buffer.getLength()).toEqual(36);
 | 
			
		||||
                expect(buffer.insert(mockSeries, Number.POSITIVE_INFINITY))
 | 
			
		||||
                    .toBeFalsy();
 | 
			
		||||
                expect(buffer.getLength()).toEqual(36);
 | 
			
		||||
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("reduces buffer size when space is no longer needed", function () {
 | 
			
		||||
                // Check that actual buffer is sized to the initial size
 | 
			
		||||
                // (double TEST_INITIAL_SIZE, since two elements are needed per
 | 
			
		||||
                // point; one for domain, one for range)
 | 
			
		||||
                expect(buffer.getBuffer().length).toEqual(20);
 | 
			
		||||
                // Should have 6 elements now... grow to 24
 | 
			
		||||
                buffer.insert(mockSeries, Number.POSITIVE_INFINITY);
 | 
			
		||||
                buffer.insert(mockSeries, Number.POSITIVE_INFINITY);
 | 
			
		||||
                buffer.insert(mockSeries, Number.POSITIVE_INFINITY);
 | 
			
		||||
                // This should have doubled the actual buffer size
 | 
			
		||||
                expect(buffer.getBuffer().length).toEqual(80);
 | 
			
		||||
                // Remove some values
 | 
			
		||||
                buffer.trim(20);
 | 
			
		||||
                // Actual buffer size should have been reduced accordingly
 | 
			
		||||
                expect(buffer.getBuffer().length).toBeLessThan(80);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,133 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    ["../../src/elements/PlotLine"],
 | 
			
		||||
    function (PlotLine) {
 | 
			
		||||
 | 
			
		||||
        describe("A plot line", function () {
 | 
			
		||||
            var mockBuffer,
 | 
			
		||||
                mockSeries,
 | 
			
		||||
                testDomainBuffer,
 | 
			
		||||
                testRangeBuffer,
 | 
			
		||||
                testSeries,
 | 
			
		||||
                line;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                testDomainBuffer = [];
 | 
			
		||||
                testRangeBuffer = [];
 | 
			
		||||
                testSeries = [];
 | 
			
		||||
 | 
			
		||||
                mockBuffer = jasmine.createSpyObj(
 | 
			
		||||
                    'buffer',
 | 
			
		||||
                    ['findInsertionIndex', 'insert', 'insertPoint', 'trim']
 | 
			
		||||
                );
 | 
			
		||||
                mockSeries = jasmine.createSpyObj(
 | 
			
		||||
                    'series',
 | 
			
		||||
                    ['getPointCount', 'getDomainValue', 'getRangeValue']
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                mockSeries.getPointCount.andCallFake(function () {
 | 
			
		||||
                    return testSeries.length;
 | 
			
		||||
                });
 | 
			
		||||
                mockSeries.getDomainValue.andCallFake(function (i) {
 | 
			
		||||
                    return (testSeries[i] || [])[0];
 | 
			
		||||
                });
 | 
			
		||||
                mockSeries.getRangeValue.andCallFake(function (i) {
 | 
			
		||||
                    return (testSeries[i] || [])[1];
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Function like PlotLineBuffer, to aid in testability
 | 
			
		||||
                mockBuffer.findInsertionIndex.andCallFake(function (v) {
 | 
			
		||||
                    var index = 0;
 | 
			
		||||
                    if (testDomainBuffer.indexOf(v) !== -1) {
 | 
			
		||||
                        return -1;
 | 
			
		||||
                    }
 | 
			
		||||
                    while ((index < testDomainBuffer.length) &&
 | 
			
		||||
                            (testDomainBuffer[index] < v)) {
 | 
			
		||||
                        index += 1;
 | 
			
		||||
                    }
 | 
			
		||||
                    return index;
 | 
			
		||||
                });
 | 
			
		||||
                mockBuffer.insert.andCallFake(function (series, index) {
 | 
			
		||||
                    var domains = [], ranges = [], i;
 | 
			
		||||
                    for (i = 0; i < series.getPointCount(); i += 1) {
 | 
			
		||||
                        domains.push(series.getDomainValue(i));
 | 
			
		||||
                        ranges.push(series.getRangeValue(i));
 | 
			
		||||
                    }
 | 
			
		||||
                    testDomainBuffer = testDomainBuffer.slice(0, index)
 | 
			
		||||
                        .concat(domains)
 | 
			
		||||
                        .concat(testDomainBuffer.slice(index));
 | 
			
		||||
                    testRangeBuffer = testRangeBuffer.slice(0, index)
 | 
			
		||||
                        .concat(ranges)
 | 
			
		||||
                        .concat(testRangeBuffer.slice(index));
 | 
			
		||||
                    return true;
 | 
			
		||||
                });
 | 
			
		||||
                mockBuffer.insertPoint.andCallFake(function (dv, rv, index) {
 | 
			
		||||
                    testDomainBuffer.splice(index, 0, dv);
 | 
			
		||||
                    testRangeBuffer.splice(index, 0, rv);
 | 
			
		||||
                    return true;
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                line = new PlotLine(mockBuffer);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("allows single point insertion", function () {
 | 
			
		||||
                line.addPoint(100, 200);
 | 
			
		||||
                line.addPoint(50, 42);
 | 
			
		||||
                line.addPoint(150, 12321);
 | 
			
		||||
                // Should have managed insertion index choices to get to...
 | 
			
		||||
                expect(testDomainBuffer).toEqual([50, 100, 150]);
 | 
			
		||||
                expect(testRangeBuffer).toEqual([42, 200, 12321]);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("allows series insertion", function () {
 | 
			
		||||
                testSeries = [[50, 42], [100, 200], [150, 12321]];
 | 
			
		||||
                line.addSeries(mockSeries);
 | 
			
		||||
                // Should have managed insertion index choices to get to...
 | 
			
		||||
                expect(testDomainBuffer).toEqual([50, 100, 150]);
 | 
			
		||||
                expect(testRangeBuffer).toEqual([42, 200, 12321]);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("splits series insertion when necessary", function () {
 | 
			
		||||
                testSeries = [[50, 42], [100, 200], [150, 12321]];
 | 
			
		||||
                line.addPoint(75, 1);
 | 
			
		||||
                line.addSeries(mockSeries);
 | 
			
		||||
                // Should have managed insertion index choices to get to...
 | 
			
		||||
                expect(testDomainBuffer).toEqual([50, 75, 100, 150]);
 | 
			
		||||
                expect(testRangeBuffer).toEqual([42, 1, 200, 12321]);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("attempts to remove points when insertion fails", function () {
 | 
			
		||||
                // Verify precondition - normally doesn't try to trim
 | 
			
		||||
                line.addPoint(1, 2);
 | 
			
		||||
                expect(mockBuffer.trim).not.toHaveBeenCalled();
 | 
			
		||||
 | 
			
		||||
                // But if insertPoint fails, it should trim
 | 
			
		||||
                mockBuffer.insertPoint.andReturn(false);
 | 
			
		||||
                line.addPoint(2, 3);
 | 
			
		||||
                expect(mockBuffer.trim).toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,123 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MergeModelsSpec. Created by vwoeltje on 11/6/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ["../../src/elements/PlotPalette"],
 | 
			
		||||
    function (PlotPalette) {
 | 
			
		||||
 | 
			
		||||
        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)
 | 
			
		||||
                        );
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,126 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MergeModelsSpec. Created by vwoeltje on 11/6/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ["../../src/elements/PlotPanZoomStackGroup"],
 | 
			
		||||
    function (PlotPanZoomStackGroup) {
 | 
			
		||||
 | 
			
		||||
        var COUNT = 8;
 | 
			
		||||
 | 
			
		||||
        describe("A plot pan-zoom stack group", function () {
 | 
			
		||||
            var stacks,
 | 
			
		||||
                group;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                group = new PlotPanZoomStackGroup(COUNT);
 | 
			
		||||
                stacks = [];
 | 
			
		||||
                while (stacks.length < COUNT) {
 | 
			
		||||
                    stacks.push(group.getPanZoomStack(stacks.length));
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("creates a number of separate stacks", function () {
 | 
			
		||||
                expect(group.getPanZoomStack(0)).toBeDefined();
 | 
			
		||||
                expect(group.getPanZoomStack(COUNT - 1)).toBeDefined();
 | 
			
		||||
                expect(group.getPanZoomStack(COUNT)).toBeUndefined();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("synchronizes pan-zoom stack depth", function () {
 | 
			
		||||
                expect(group.getDepth()).toEqual(1);
 | 
			
		||||
                group.getPanZoomStack(1).pushPanZoom([10, 20], [30, 40]);
 | 
			
		||||
                stacks.forEach(function (stack) {
 | 
			
		||||
                    expect(stack.getDepth()).toEqual(2);
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("synchronizes domain but not range", function () {
 | 
			
		||||
                // Set up different initial states
 | 
			
		||||
                stacks.forEach(function (stack, i) {
 | 
			
		||||
                    stack.pushPanZoom([i, i], [i, i]);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Push a new pan-zoom state onto one of the stacks
 | 
			
		||||
                group.getPanZoomStack(1).pushPanZoom([99, 99], [42, 42]);
 | 
			
		||||
 | 
			
		||||
                // Should changed domain values for all stacks, but
 | 
			
		||||
                // only changed range values for stack 1
 | 
			
		||||
                stacks.forEach(function (stack, i) {
 | 
			
		||||
                    expect(stack.getOrigin())
 | 
			
		||||
                        .toEqual([99, i === 1 ? 99 : i]);
 | 
			
		||||
                    expect(stack.getDimensions())
 | 
			
		||||
                        .toEqual([42, i === 1 ? 42 : i]);
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("synchronizes base pan-zoom", function () {
 | 
			
		||||
                group.setBasePanZoom([10, 9], [8, 7]);
 | 
			
		||||
                stacks.forEach(function (stack) {
 | 
			
		||||
                    expect(stack.getOrigin()).toEqual([10, 9]);
 | 
			
		||||
                    expect(stack.getDimensions()).toEqual([8, 7]);
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("clears pan-zoom on request", function () {
 | 
			
		||||
                // Set up different initial states
 | 
			
		||||
                stacks.forEach(function (stack, i) {
 | 
			
		||||
                    stack.pushPanZoom([i, i], [i, i]);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Verify that we have a greater depth
 | 
			
		||||
                expect(group.getDepth() > 1).toBeTruthy();
 | 
			
		||||
 | 
			
		||||
                // Clear the pan-zoom state
 | 
			
		||||
                group.clearPanZoom();
 | 
			
		||||
 | 
			
		||||
                // Should be back down to our initial state
 | 
			
		||||
                expect(group.getDepth()).toEqual(1);
 | 
			
		||||
                stacks.forEach(function (stack) {
 | 
			
		||||
                    expect(stack.getDepth()).toEqual(1);
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("pops pan-zoom on request", function () {
 | 
			
		||||
                // Set up different initial states
 | 
			
		||||
                stacks.forEach(function (stack, i) {
 | 
			
		||||
                    stack.pushPanZoom([i, i], [i, i]);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Verify that we have a greater depth
 | 
			
		||||
                expect(group.getDepth()).toEqual(COUNT + 1);
 | 
			
		||||
 | 
			
		||||
                // Clear the pan-zoom state
 | 
			
		||||
                group.popPanZoom();
 | 
			
		||||
 | 
			
		||||
                // Should be back down to our initial state
 | 
			
		||||
                expect(group.getDepth()).toEqual(COUNT);
 | 
			
		||||
                stacks.forEach(function (stack) {
 | 
			
		||||
                    expect(stack.getDepth()).toEqual(COUNT);
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,99 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MergeModelsSpec. Created by vwoeltje on 11/6/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ["../../src/elements/PlotPanZoomStack"],
 | 
			
		||||
    function (PlotPanZoomStack) {
 | 
			
		||||
 | 
			
		||||
        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]);
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,67 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MergeModelsSpec. Created by vwoeltje on 11/6/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ["../../src/elements/PlotPosition"],
 | 
			
		||||
    function (PlotPosition) {
 | 
			
		||||
 | 
			
		||||
        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([]);
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,93 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MergeModelsSpec. Created by vwoeltje on 11/6/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ["../../src/elements/PlotPreparer"],
 | 
			
		||||
    function (PlotPreparer) {
 | 
			
		||||
 | 
			
		||||
        var START = 123456;
 | 
			
		||||
 | 
			
		||||
        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(preparer).toBeDefined();
 | 
			
		||||
 | 
			
		||||
                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);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("provides buffers", function () {
 | 
			
		||||
                var datas = [makeMockData(0)],
 | 
			
		||||
                    preparer = new PlotPreparer(datas);
 | 
			
		||||
                expect(preparer.getBuffers()[0] instanceof Float32Array)
 | 
			
		||||
                    .toBeTruthy();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,93 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    ["../../src/elements/PlotSeriesWindow"],
 | 
			
		||||
    function (PlotSeriesWindow) {
 | 
			
		||||
 | 
			
		||||
        describe("A plot's window on a telemetry series", function () {
 | 
			
		||||
            var mockSeries,
 | 
			
		||||
                testSeries,
 | 
			
		||||
                window;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                testSeries = [
 | 
			
		||||
                    [0, 42],
 | 
			
		||||
                    [10, 1],
 | 
			
		||||
                    [20, 4],
 | 
			
		||||
                    [30, 9],
 | 
			
		||||
                    [40, 3]
 | 
			
		||||
                ];
 | 
			
		||||
 | 
			
		||||
                mockSeries = jasmine.createSpyObj(
 | 
			
		||||
                    'series',
 | 
			
		||||
                    ['getPointCount', 'getDomainValue', 'getRangeValue']
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                mockSeries.getPointCount.andCallFake(function () {
 | 
			
		||||
                    return testSeries.length;
 | 
			
		||||
                });
 | 
			
		||||
                mockSeries.getDomainValue.andCallFake(function (i) {
 | 
			
		||||
                    return testSeries[i][0];
 | 
			
		||||
                });
 | 
			
		||||
                mockSeries.getRangeValue.andCallFake(function (i) {
 | 
			
		||||
                    return testSeries[i][1];
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                window = new PlotSeriesWindow(
 | 
			
		||||
                    mockSeries,
 | 
			
		||||
                    "testDomain",
 | 
			
		||||
                    "testRange",
 | 
			
		||||
                    1,
 | 
			
		||||
                    testSeries.length
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("provides a window upon a data series", function () {
 | 
			
		||||
                expect(window.getPointCount()).toEqual(4);
 | 
			
		||||
                expect(window.getDomainValue(0)).toEqual(10);
 | 
			
		||||
                expect(window.getRangeValue(0)).toEqual(1);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("looks up using specific domain/range keys", function () {
 | 
			
		||||
                window.getDomainValue(0);
 | 
			
		||||
                window.getRangeValue(0);
 | 
			
		||||
                expect(mockSeries.getDomainValue)
 | 
			
		||||
                    .toHaveBeenCalledWith(1, 'testDomain');
 | 
			
		||||
                expect(mockSeries.getRangeValue)
 | 
			
		||||
                    .toHaveBeenCalledWith(1, 'testRange');
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("can be split into smaller windows", function () {
 | 
			
		||||
                var windows = window.split();
 | 
			
		||||
                expect(windows.length).toEqual(2);
 | 
			
		||||
                expect(windows[0].getPointCount()).toEqual(2);
 | 
			
		||||
                expect(windows[1].getPointCount()).toEqual(2);
 | 
			
		||||
                expect(windows[0].getDomainValue(0)).toEqual(10);
 | 
			
		||||
                expect(windows[1].getDomainValue(0)).toEqual(30);
 | 
			
		||||
                expect(windows[0].getRangeValue(0)).toEqual(1);
 | 
			
		||||
                expect(windows[1].getRangeValue(0)).toEqual(9);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,71 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    ["../../src/elements/PlotTelemetryFormatter"],
 | 
			
		||||
    function (PlotTelemetryFormatter) {
 | 
			
		||||
 | 
			
		||||
        describe("The PlotTelemetryFormatter", function () {
 | 
			
		||||
            var mockFormatter,
 | 
			
		||||
                formatter;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockFormatter = jasmine.createSpyObj(
 | 
			
		||||
                    'telemetryFormatter',
 | 
			
		||||
                    ['formatDomainValue', 'formatRangeValue']
 | 
			
		||||
                );
 | 
			
		||||
                formatter = new PlotTelemetryFormatter(mockFormatter);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            describe("using domain & range format keys", function () {
 | 
			
		||||
                var rangeFormat = "someRangeFormat",
 | 
			
		||||
                    domainFormat = "someDomainFormat";
 | 
			
		||||
 | 
			
		||||
                beforeEach(function () {
 | 
			
		||||
                    formatter.setRangeFormat(rangeFormat);
 | 
			
		||||
                    formatter.setDomainFormat(domainFormat);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                it("includes format in formatDomainValue calls", function () {
 | 
			
		||||
                    mockFormatter.formatDomainValue.andReturn("formatted!");
 | 
			
		||||
                    expect(formatter.formatDomainValue(12321))
 | 
			
		||||
                        .toEqual("formatted!");
 | 
			
		||||
                    expect(mockFormatter.formatDomainValue)
 | 
			
		||||
                        .toHaveBeenCalledWith(12321, domainFormat);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                it("includes format in formatRangeValue calls for strings", function () {
 | 
			
		||||
                    mockFormatter.formatRangeValue.andReturn("formatted!");
 | 
			
		||||
                    expect(formatter.formatRangeValue('foo'))
 | 
			
		||||
                        .toEqual("formatted!");
 | 
			
		||||
                    expect(mockFormatter.formatRangeValue)
 | 
			
		||||
                        .toHaveBeenCalledWith('foo', rangeFormat);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                it("formats numeric values with three fixed digits", function () {
 | 
			
		||||
                    expect(formatter.formatRangeValue(10)).toEqual("10.000");
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,73 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MergeModelsSpec. Created by vwoeltje on 11/6/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ["../../src/elements/PlotTickGenerator"],
 | 
			
		||||
    function (PlotTickGenerator) {
 | 
			
		||||
 | 
			
		||||
        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();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,237 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MergeModelsSpec. Created by vwoeltje on 11/6/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ["../../src/elements/PlotUpdater"],
 | 
			
		||||
    function (PlotUpdater) {
 | 
			
		||||
 | 
			
		||||
        describe("A plot updater", function () {
 | 
			
		||||
            var mockSubscription,
 | 
			
		||||
                testDomain,
 | 
			
		||||
                testRange,
 | 
			
		||||
                testDomainValues,
 | 
			
		||||
                testRangeValues,
 | 
			
		||||
                mockSeries,
 | 
			
		||||
                updater;
 | 
			
		||||
 | 
			
		||||
            function makeMockDomainObject(id) {
 | 
			
		||||
                var mockDomainObject = jasmine.createSpyObj(
 | 
			
		||||
                    "object-" + id,
 | 
			
		||||
                    ["getId", "getCapability", "getModel"]
 | 
			
		||||
                );
 | 
			
		||||
                mockDomainObject.getId.andReturn(id);
 | 
			
		||||
                return mockDomainObject;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                var ids = ['a', 'b', 'c'],
 | 
			
		||||
                    mockObjects = ids.map(makeMockDomainObject);
 | 
			
		||||
 | 
			
		||||
                mockSubscription = jasmine.createSpyObj(
 | 
			
		||||
                    "subscription",
 | 
			
		||||
                    ["getDomainValue", "getRangeValue", "getTelemetryObjects"]
 | 
			
		||||
                );
 | 
			
		||||
                mockSeries = jasmine.createSpyObj(
 | 
			
		||||
                    'series',
 | 
			
		||||
                    ['getPointCount', 'getDomainValue', 'getRangeValue']
 | 
			
		||||
                );
 | 
			
		||||
                testDomain = "testDomain";
 | 
			
		||||
                testRange = "testRange";
 | 
			
		||||
                testDomainValues = { a: 3, b: 7, c: 13 };
 | 
			
		||||
                testRangeValues = { a: 123, b: 456, c: 789 };
 | 
			
		||||
 | 
			
		||||
                mockSubscription.getTelemetryObjects.andReturn(mockObjects);
 | 
			
		||||
                mockSubscription.getDomainValue.andCallFake(function (mockObject) {
 | 
			
		||||
                    return testDomainValues[mockObject.getId()];
 | 
			
		||||
                });
 | 
			
		||||
                mockSubscription.getRangeValue.andCallFake(function (mockObject) {
 | 
			
		||||
                    return testRangeValues[mockObject.getId()];
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                updater = new PlotUpdater(
 | 
			
		||||
                    mockSubscription,
 | 
			
		||||
                    testDomain,
 | 
			
		||||
                    testRange,
 | 
			
		||||
                    1350 // Smaller max size for easier testing
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("provides one buffer per telemetry object", function () {
 | 
			
		||||
                expect(updater.getLineBuffers().length).toEqual(3);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("changes buffer count if telemetry object counts change", function () {
 | 
			
		||||
                mockSubscription.getTelemetryObjects
 | 
			
		||||
                    .andReturn([makeMockDomainObject('a')]);
 | 
			
		||||
                updater.update();
 | 
			
		||||
                expect(updater.getLineBuffers().length).toEqual(1);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("can handle delayed telemetry object availability", function () {
 | 
			
		||||
                // The case can occur where getTelemetryObjects() returns an
 | 
			
		||||
                // empty array - specifically, while objects are still being
 | 
			
		||||
                // loaded. The updater needs to be able to cope with that
 | 
			
		||||
                // case.
 | 
			
		||||
                var tmp = mockSubscription.getTelemetryObjects();
 | 
			
		||||
                mockSubscription.getTelemetryObjects.andReturn([]);
 | 
			
		||||
 | 
			
		||||
                // Reinstantiate with the empty subscription
 | 
			
		||||
                updater = new PlotUpdater(
 | 
			
		||||
                    mockSubscription,
 | 
			
		||||
                    testDomain,
 | 
			
		||||
                    testRange
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                // Should have 0 buffers for 0 objects
 | 
			
		||||
                expect(updater.getLineBuffers().length).toEqual(0);
 | 
			
		||||
 | 
			
		||||
                // Restore the three objects the test subscription would
 | 
			
		||||
                // normally have.
 | 
			
		||||
                mockSubscription.getTelemetryObjects.andReturn(tmp);
 | 
			
		||||
                updater.update();
 | 
			
		||||
 | 
			
		||||
                // Should have 3 buffers for 3 objects
 | 
			
		||||
                expect(updater.getLineBuffers().length).toEqual(3);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("accepts historical telemetry updates", function () {
 | 
			
		||||
                var mockObject = mockSubscription.getTelemetryObjects()[0];
 | 
			
		||||
 | 
			
		||||
                mockSeries.getPointCount.andReturn(3);
 | 
			
		||||
                mockSeries.getDomainValue.andCallFake(function (i) {
 | 
			
		||||
                    return 1000 + i * 1000;
 | 
			
		||||
                });
 | 
			
		||||
                mockSeries.getRangeValue.andReturn(10);
 | 
			
		||||
 | 
			
		||||
                // PlotLine & PlotLineBuffer are tested for most of the
 | 
			
		||||
                // details here, so just check for some expected side
 | 
			
		||||
                // effect; in this case, should see more points in the buffer
 | 
			
		||||
                expect(updater.getLineBuffers()[0].getLength()).toEqual(1);
 | 
			
		||||
                updater.addHistorical(mockObject, mockSeries);
 | 
			
		||||
                expect(updater.getLineBuffers()[0].getLength()).toEqual(4);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("clears the domain offset if no objects are present", function () {
 | 
			
		||||
                mockSubscription.getTelemetryObjects.andReturn([]);
 | 
			
		||||
                updater.update();
 | 
			
		||||
                expect(updater.getDomainOffset()).toBeUndefined();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("handles empty historical telemetry updates", function () {
 | 
			
		||||
                // General robustness check for when a series is empty
 | 
			
		||||
                var mockObject = mockSubscription.getTelemetryObjects()[0];
 | 
			
		||||
 | 
			
		||||
                mockSeries.getPointCount.andReturn(0);
 | 
			
		||||
                mockSeries.getDomainValue.andCallFake(function (i) {
 | 
			
		||||
                    return 1000 + i * 1000;
 | 
			
		||||
                });
 | 
			
		||||
                mockSeries.getRangeValue.andReturn(10);
 | 
			
		||||
 | 
			
		||||
                // PlotLine & PlotLineBuffer are tested for most of the
 | 
			
		||||
                // details here, so just check for some expected side
 | 
			
		||||
                // effect; in this case, should see more points in the buffer
 | 
			
		||||
                expect(updater.getLineBuffers()[0].getLength()).toEqual(1);
 | 
			
		||||
                updater.addHistorical(mockObject, mockSeries);
 | 
			
		||||
                expect(updater.getLineBuffers()[0].getLength()).toEqual(1);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("can initialize domain offset from historical telemetry", function () {
 | 
			
		||||
                var tmp = mockSubscription.getTelemetryObjects();
 | 
			
		||||
 | 
			
		||||
                mockSubscription.getTelemetryObjects.andReturn([]);
 | 
			
		||||
 | 
			
		||||
                // Reinstantiate with the empty subscription
 | 
			
		||||
                updater = new PlotUpdater(
 | 
			
		||||
                    mockSubscription,
 | 
			
		||||
                    testDomain,
 | 
			
		||||
                    testRange
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                // Restore subscription, provide some historical data
 | 
			
		||||
                mockSubscription.getTelemetryObjects.andReturn(tmp);
 | 
			
		||||
                mockSeries.getPointCount.andReturn(3);
 | 
			
		||||
                mockSeries.getDomainValue.andCallFake(function (i) {
 | 
			
		||||
                    return 1000 + i * 1000;
 | 
			
		||||
                });
 | 
			
		||||
                mockSeries.getRangeValue.andReturn(10);
 | 
			
		||||
 | 
			
		||||
                // PlotLine & PlotLineBuffer are tested for most of the
 | 
			
		||||
                // details here, so just check for some expected side
 | 
			
		||||
                // effect; in this case, should see more points in the buffer
 | 
			
		||||
                expect(updater.getDomainOffset()).toBeUndefined();
 | 
			
		||||
                updater.addHistorical(tmp[0], mockSeries);
 | 
			
		||||
                expect(updater.getDomainOffset()).toBeDefined();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("provides some margin for the range", function () {
 | 
			
		||||
                var mockObject = mockSubscription.getTelemetryObjects()[0];
 | 
			
		||||
 | 
			
		||||
                mockSeries.getPointCount.andReturn(3);
 | 
			
		||||
                mockSeries.getDomainValue.andCallFake(function (i) {
 | 
			
		||||
                    return 1000 + i * 1000;
 | 
			
		||||
                });
 | 
			
		||||
                mockSeries.getRangeValue.andCallFake(function (i) {
 | 
			
		||||
                    return 10 + i; // 10, 20, 30
 | 
			
		||||
                });
 | 
			
		||||
                updater.addHistorical(mockObject, mockSeries);
 | 
			
		||||
                expect(updater.getOrigin()[1]).toBeLessThan(10);
 | 
			
		||||
                expect(updater.getDimensions()[1]).toBeGreaterThan(20);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            describe("when no data is initially available", function () {
 | 
			
		||||
                beforeEach(function () {
 | 
			
		||||
                    testDomainValues = {};
 | 
			
		||||
                    testRangeValues = {};
 | 
			
		||||
                    updater = new PlotUpdater(
 | 
			
		||||
                        mockSubscription,
 | 
			
		||||
                        testDomain,
 | 
			
		||||
                        testRange,
 | 
			
		||||
                        1350 // Smaller max size for easier testing
 | 
			
		||||
                    );
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                it("has no line data", function () {
 | 
			
		||||
                    // Either no lines, or empty lines are fine
 | 
			
		||||
                    expect(updater.getLineBuffers().map(function (lineBuffer) {
 | 
			
		||||
                        return lineBuffer.getLength();
 | 
			
		||||
                    }).reduce(function (a, b) {
 | 
			
		||||
                        return a + b;
 | 
			
		||||
                    }, 0)).toEqual(0);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                it("determines initial domain bounds from first available data", function () {
 | 
			
		||||
                    testDomainValues.a = 123;
 | 
			
		||||
                    testRangeValues.a = 456;
 | 
			
		||||
                    updater.update();
 | 
			
		||||
                    expect(updater.getOrigin()[0]).toEqual(jasmine.any(Number));
 | 
			
		||||
                    expect(updater.getOrigin()[1]).toEqual(jasmine.any(Number));
 | 
			
		||||
                    expect(isNaN(updater.getOrigin()[0])).toBeFalsy();
 | 
			
		||||
                    expect(isNaN(updater.getOrigin()[1])).toBeFalsy();
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,87 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MergeModelsSpec. Created by vwoeltje on 11/6/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ["../../src/modes/PlotModeOptions"],
 | 
			
		||||
    function (PlotModeOptions) {
 | 
			
		||||
 | 
			
		||||
        describe("Plot mode options", function () {
 | 
			
		||||
            var mockDomainObject,
 | 
			
		||||
                mockSubPlotFactory;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockDomainObject = jasmine.createSpyObj(
 | 
			
		||||
                    "domainObject",
 | 
			
		||||
                    ["getId", "getModel", "getCapability"]
 | 
			
		||||
                );
 | 
			
		||||
                mockSubPlotFactory = jasmine.createSpyObj(
 | 
			
		||||
                    "subPlotFactory",
 | 
			
		||||
                    ["createSubPlot"]
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("offers only one option when one object is present", function () {
 | 
			
		||||
                expect(
 | 
			
		||||
                    new PlotModeOptions([mockDomainObject], mockSubPlotFactory)
 | 
			
		||||
                            .getModeOptions().length
 | 
			
		||||
                ).toEqual(1);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("offers two options when multiple objects are present", function () {
 | 
			
		||||
                var objects = [
 | 
			
		||||
                        mockDomainObject,
 | 
			
		||||
                        mockDomainObject,
 | 
			
		||||
                        mockDomainObject,
 | 
			
		||||
                        mockDomainObject
 | 
			
		||||
                    ];
 | 
			
		||||
                expect(
 | 
			
		||||
                    new PlotModeOptions(objects, mockSubPlotFactory)
 | 
			
		||||
                            .getModeOptions().length
 | 
			
		||||
                ).toEqual(2);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("allows modes to be changed", function () {
 | 
			
		||||
                var plotModeOptions = new PlotModeOptions([
 | 
			
		||||
                        mockDomainObject,
 | 
			
		||||
                        mockDomainObject,
 | 
			
		||||
                        mockDomainObject,
 | 
			
		||||
                        mockDomainObject
 | 
			
		||||
                    ], mockSubPlotFactory),
 | 
			
		||||
                    initialHandler = plotModeOptions.getModeHandler();
 | 
			
		||||
 | 
			
		||||
                // Change the mode
 | 
			
		||||
                plotModeOptions.getModeOptions().forEach(function (option) {
 | 
			
		||||
                    if (option !== plotModeOptions.getMode()) {
 | 
			
		||||
                        plotModeOptions.setMode(option);
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Mode should be different now
 | 
			
		||||
                expect(plotModeOptions.getModeHandler())
 | 
			
		||||
                    .not.toBe(initialHandler);
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,184 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MergeModelsSpec. Created by vwoeltje on 11/6/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ["../../src/modes/PlotOverlayMode"],
 | 
			
		||||
    function (PlotOverlayMode) {
 | 
			
		||||
 | 
			
		||||
        describe("Overlaid plot mode", function () {
 | 
			
		||||
            var mockDomainObject,
 | 
			
		||||
                mockSubPlotFactory,
 | 
			
		||||
                mockPrepared,
 | 
			
		||||
                testBuffers,
 | 
			
		||||
                testDrawingObjects,
 | 
			
		||||
                mode;
 | 
			
		||||
 | 
			
		||||
            function createMockSubPlot() {
 | 
			
		||||
                var mockSubPlot = jasmine.createSpyObj(
 | 
			
		||||
                        "subPlot",
 | 
			
		||||
                        [
 | 
			
		||||
                            "setDomainOffset",
 | 
			
		||||
                            "hover",
 | 
			
		||||
                            "startMarquee",
 | 
			
		||||
                            "endMarquee",
 | 
			
		||||
                            "getDrawingObject",
 | 
			
		||||
                            "update"
 | 
			
		||||
                        ]
 | 
			
		||||
                    ),
 | 
			
		||||
                    testDrawingObject = {};
 | 
			
		||||
 | 
			
		||||
                // Track drawing objects in order of creation
 | 
			
		||||
                testDrawingObjects.push(testDrawingObject);
 | 
			
		||||
                mockSubPlot.getDrawingObject.andReturn(testDrawingObject);
 | 
			
		||||
                return mockSubPlot;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockDomainObject = jasmine.createSpyObj(
 | 
			
		||||
                    "domainObject",
 | 
			
		||||
                    ["getId", "getModel", "getCapability"]
 | 
			
		||||
                );
 | 
			
		||||
                mockSubPlotFactory = jasmine.createSpyObj(
 | 
			
		||||
                    "subPlotFactory",
 | 
			
		||||
                    ["createSubPlot"]
 | 
			
		||||
                );
 | 
			
		||||
                // Prepared telemetry data
 | 
			
		||||
                mockPrepared = jasmine.createSpyObj(
 | 
			
		||||
                    "prepared",
 | 
			
		||||
                    [
 | 
			
		||||
                        "getDomainOffset",
 | 
			
		||||
                        "getOrigin",
 | 
			
		||||
                        "getDimensions",
 | 
			
		||||
                        "getLineBuffers"
 | 
			
		||||
                    ]
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                mockSubPlotFactory.createSubPlot.andCallFake(createMockSubPlot);
 | 
			
		||||
 | 
			
		||||
                // Act as if we have three buffers full of data
 | 
			
		||||
                testBuffers = ['a', 'b', 'c'].map(function (id) {
 | 
			
		||||
                    var mockBuffer = jasmine.createSpyObj(
 | 
			
		||||
                        'buffer-' + id,
 | 
			
		||||
                        ['getBuffer', 'getLength']
 | 
			
		||||
                    );
 | 
			
		||||
                    mockBuffer.getBuffer.andReturn([id]);
 | 
			
		||||
                    mockBuffer.getLength.andReturn(3);
 | 
			
		||||
                    return mockBuffer;
 | 
			
		||||
                });
 | 
			
		||||
                mockPrepared.getLineBuffers.andReturn(testBuffers);
 | 
			
		||||
                mockPrepared.getDomainOffset.andReturn(1234);
 | 
			
		||||
                mockPrepared.getOrigin.andReturn([10, 10]);
 | 
			
		||||
                mockPrepared.getDimensions.andReturn([500, 500]);
 | 
			
		||||
 | 
			
		||||
                // Clear out drawing objects
 | 
			
		||||
                testDrawingObjects = [];
 | 
			
		||||
 | 
			
		||||
                mode = new PlotOverlayMode([
 | 
			
		||||
                    mockDomainObject,
 | 
			
		||||
                    mockDomainObject,
 | 
			
		||||
                    mockDomainObject
 | 
			
		||||
                ], mockSubPlotFactory);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("creates one sub-plot for all domain objects", function () {
 | 
			
		||||
                expect(mode.getSubPlots().length).toEqual(1);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("draws telemetry to subplots", function () {
 | 
			
		||||
                // Verify precondition
 | 
			
		||||
                mode.getSubPlots().forEach(function (subplot) {
 | 
			
		||||
                    // Either empty list or undefined is fine;
 | 
			
		||||
                    // just want to make sure there are no lines.
 | 
			
		||||
                    expect(subplot.getDrawingObject().lines || [])
 | 
			
		||||
                        .toEqual([]);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                mode.plotTelemetry(mockPrepared);
 | 
			
		||||
 | 
			
		||||
                // Should have one sub-plot with three lines
 | 
			
		||||
                testDrawingObjects.forEach(function (testDrawingObject) {
 | 
			
		||||
                    // Either empty list or undefined is fine;
 | 
			
		||||
                    // just want to make sure there are no lines.
 | 
			
		||||
                    expect(testDrawingObject.lines.length)
 | 
			
		||||
                        .toEqual(3);
 | 
			
		||||
                    // Make sure the right buffer was drawn to the
 | 
			
		||||
                    // right subplot.
 | 
			
		||||
                    testDrawingObject.lines.forEach(function (line, j) {
 | 
			
		||||
                        expect(line.buffer).toEqual(testBuffers[j].getBuffer());
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("tracks zoomed state of subplots", function () {
 | 
			
		||||
                // Should start out unzoomed
 | 
			
		||||
                expect(mode.isZoomed()).toBeFalsy();
 | 
			
		||||
 | 
			
		||||
                // Trigger some zoom changes
 | 
			
		||||
                mockSubPlotFactory.createSubPlot.calls.forEach(function (c) {
 | 
			
		||||
                    // Second argument to the factory was pan-zoom stack
 | 
			
		||||
                    c.args[1].pushPanZoom([1, 2], [3, 4]);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Should start out unzoomed
 | 
			
		||||
                expect(mode.isZoomed()).toBeTruthy();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("supports unzooming", function () {
 | 
			
		||||
                // Trigger some zoom changes
 | 
			
		||||
                mockSubPlotFactory.createSubPlot.calls.forEach(function (c) {
 | 
			
		||||
                    // Second argument to the factory was pan-zoom stack
 | 
			
		||||
                    c.args[1].pushPanZoom([1, 2], [3, 4]);
 | 
			
		||||
                });
 | 
			
		||||
                // Verify that we are indeed zoomed now
 | 
			
		||||
                expect(mode.isZoomed()).toBeTruthy();
 | 
			
		||||
 | 
			
		||||
                // Unzoom
 | 
			
		||||
                mode.unzoom();
 | 
			
		||||
 | 
			
		||||
                // Should no longer be zoomed
 | 
			
		||||
                expect(mode.isZoomed()).toBeFalsy();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("supports stepping back through zoom states", function () {
 | 
			
		||||
                // Trigger some zoom changes
 | 
			
		||||
                mockSubPlotFactory.createSubPlot.calls.forEach(function (c) {
 | 
			
		||||
                    // Second argument to the factory was pan-zoom stack
 | 
			
		||||
                    c.args[1].pushPanZoom([1, 2], [3, 4]);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Step back the same number of zoom changes
 | 
			
		||||
                mockSubPlotFactory.createSubPlot.calls.forEach(function () {
 | 
			
		||||
                    // Should still be zoomed at start of each iteration
 | 
			
		||||
                    expect(mode.isZoomed()).toBeTruthy();
 | 
			
		||||
                    // Step back one of the zoom changes.
 | 
			
		||||
                    mode.stepBackPanZoom();
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Should no longer be zoomed
 | 
			
		||||
                expect(mode.isZoomed()).toBeFalsy();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,179 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * MergeModelsSpec. Created by vwoeltje on 11/6/14.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ["../../src/modes/PlotStackMode"],
 | 
			
		||||
    function (PlotStackMode) {
 | 
			
		||||
 | 
			
		||||
        describe("Stacked plot mode", function () {
 | 
			
		||||
            var mockDomainObject,
 | 
			
		||||
                mockSubPlotFactory,
 | 
			
		||||
                mockPrepared,
 | 
			
		||||
                testBuffers,
 | 
			
		||||
                testDrawingObjects,
 | 
			
		||||
                mode;
 | 
			
		||||
 | 
			
		||||
            function createMockSubPlot() {
 | 
			
		||||
                var mockSubPlot = jasmine.createSpyObj(
 | 
			
		||||
                        "subPlot",
 | 
			
		||||
                        [
 | 
			
		||||
                            "setDomainOffset",
 | 
			
		||||
                            "hover",
 | 
			
		||||
                            "startMarquee",
 | 
			
		||||
                            "endMarquee",
 | 
			
		||||
                            "getDrawingObject",
 | 
			
		||||
                            "update"
 | 
			
		||||
                        ]
 | 
			
		||||
                    ),
 | 
			
		||||
                    testDrawingObject = {};
 | 
			
		||||
 | 
			
		||||
                // Track drawing objects in order of creation
 | 
			
		||||
                testDrawingObjects.push(testDrawingObject);
 | 
			
		||||
                mockSubPlot.getDrawingObject.andReturn(testDrawingObject);
 | 
			
		||||
                return mockSubPlot;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockDomainObject = jasmine.createSpyObj(
 | 
			
		||||
                    "domainObject",
 | 
			
		||||
                    ["getId", "getModel", "getCapability"]
 | 
			
		||||
                );
 | 
			
		||||
                mockSubPlotFactory = jasmine.createSpyObj(
 | 
			
		||||
                    "subPlotFactory",
 | 
			
		||||
                    ["createSubPlot"]
 | 
			
		||||
                );
 | 
			
		||||
                // Prepared telemetry data
 | 
			
		||||
                mockPrepared = jasmine.createSpyObj(
 | 
			
		||||
                    "prepared",
 | 
			
		||||
                    ["getDomainOffset", "getOrigin", "getDimensions", "getLineBuffers"]
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                mockSubPlotFactory.createSubPlot.andCallFake(createMockSubPlot);
 | 
			
		||||
 | 
			
		||||
                // Act as if we have three buffers full of data
 | 
			
		||||
                testBuffers = ['a', 'b', 'c'].map(function (id) {
 | 
			
		||||
                    var mockBuffer = jasmine.createSpyObj(
 | 
			
		||||
                        'buffer-' + id,
 | 
			
		||||
                        ['getBuffer', 'getLength']
 | 
			
		||||
                    );
 | 
			
		||||
                    mockBuffer.getBuffer.andReturn([id]);
 | 
			
		||||
                    mockBuffer.getLength.andReturn(3);
 | 
			
		||||
                    return mockBuffer;
 | 
			
		||||
                });
 | 
			
		||||
                mockPrepared.getLineBuffers.andReturn(testBuffers);
 | 
			
		||||
                mockPrepared.getDomainOffset.andReturn(1234);
 | 
			
		||||
                mockPrepared.getOrigin.andReturn([10, 10]);
 | 
			
		||||
                mockPrepared.getDimensions.andReturn([500, 500]);
 | 
			
		||||
 | 
			
		||||
                // Objects that will be drawn to in sub-plots
 | 
			
		||||
                testDrawingObjects = [];
 | 
			
		||||
 | 
			
		||||
                mode = new PlotStackMode([
 | 
			
		||||
                    mockDomainObject,
 | 
			
		||||
                    mockDomainObject,
 | 
			
		||||
                    mockDomainObject
 | 
			
		||||
                ], mockSubPlotFactory);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("creates one sub-plot per domain object", function () {
 | 
			
		||||
                expect(mode.getSubPlots().length).toEqual(3);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("draws telemetry to subplots", function () {
 | 
			
		||||
                // Verify precondition
 | 
			
		||||
                mode.getSubPlots().forEach(function (subplot) {
 | 
			
		||||
                    // Either empty list or undefined is fine;
 | 
			
		||||
                    // just want to make sure there are no lines.
 | 
			
		||||
                    expect(subplot.getDrawingObject().lines || [])
 | 
			
		||||
                        .toEqual([]);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                mode.plotTelemetry(mockPrepared);
 | 
			
		||||
 | 
			
		||||
                // Should all each have one line
 | 
			
		||||
                testDrawingObjects.forEach(function (testDrawingObject, i) {
 | 
			
		||||
                    // Either empty list or undefined is fine;
 | 
			
		||||
                    // just want to make sure there are no lines.
 | 
			
		||||
                    expect(testDrawingObject.lines.length)
 | 
			
		||||
                        .toEqual(1);
 | 
			
		||||
                    // Make sure the right buffer was drawn to the
 | 
			
		||||
                    // right subplot.
 | 
			
		||||
                    expect(testDrawingObject.lines[0].buffer)
 | 
			
		||||
                        .toEqual(testBuffers[i].getBuffer());
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("tracks zoomed state of subplots", function () {
 | 
			
		||||
                // Should start out unzoomed
 | 
			
		||||
                expect(mode.isZoomed()).toBeFalsy();
 | 
			
		||||
 | 
			
		||||
                // Trigger some zoom changes
 | 
			
		||||
                mockSubPlotFactory.createSubPlot.calls.forEach(function (c) {
 | 
			
		||||
                    // Second argument to the factory was pan-zoom stack
 | 
			
		||||
                    c.args[1].pushPanZoom([1, 2], [3, 4]);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Should start out unzoomed
 | 
			
		||||
                expect(mode.isZoomed()).toBeTruthy();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("supports unzooming", function () {
 | 
			
		||||
                // Trigger some zoom changes
 | 
			
		||||
                mockSubPlotFactory.createSubPlot.calls.forEach(function (c) {
 | 
			
		||||
                    // Second argument to the factory was pan-zoom stack
 | 
			
		||||
                    c.args[1].pushPanZoom([1, 2], [3, 4]);
 | 
			
		||||
                });
 | 
			
		||||
                // Verify that we are indeed zoomed now
 | 
			
		||||
                expect(mode.isZoomed()).toBeTruthy();
 | 
			
		||||
 | 
			
		||||
                // Unzoom
 | 
			
		||||
                mode.unzoom();
 | 
			
		||||
 | 
			
		||||
                // Should no longer be zoomed
 | 
			
		||||
                expect(mode.isZoomed()).toBeFalsy();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("supports stepping back through zoom states", function () {
 | 
			
		||||
                // Trigger some zoom changes
 | 
			
		||||
                mockSubPlotFactory.createSubPlot.calls.forEach(function (c) {
 | 
			
		||||
                    // Second argument to the factory was pan-zoom stack
 | 
			
		||||
                    c.args[1].pushPanZoom([1, 2], [3, 4]);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Step back the same number of zoom changes
 | 
			
		||||
                mockSubPlotFactory.createSubPlot.calls.forEach(function () {
 | 
			
		||||
                    // Should still be zoomed at start of each iteration
 | 
			
		||||
                    expect(mode.isZoomed()).toBeTruthy();
 | 
			
		||||
                    // Step back
 | 
			
		||||
                    mode.stepBackPanZoom();
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                // Should no longer be zoomed
 | 
			
		||||
                expect(mode.isZoomed()).toBeFalsy();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,123 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define(
 | 
			
		||||
    ["../../src/policies/PlotViewPolicy"],
 | 
			
		||||
    function (PlotViewPolicy) {
 | 
			
		||||
 | 
			
		||||
        describe("Plot view policy", function () {
 | 
			
		||||
            var testView,
 | 
			
		||||
                mockDomainObject,
 | 
			
		||||
                testAdaptedObject,
 | 
			
		||||
                openmct,
 | 
			
		||||
                telemetryMetadata,
 | 
			
		||||
                policy;
 | 
			
		||||
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                testView = { key: "plot" };
 | 
			
		||||
                testAdaptedObject = { telemetry: {} };
 | 
			
		||||
                mockDomainObject = jasmine.createSpyObj(
 | 
			
		||||
                    'domainObject',
 | 
			
		||||
                    ['useCapability', 'hasCapability', 'getCapability']
 | 
			
		||||
                );
 | 
			
		||||
                mockDomainObject.useCapability.andReturn(testAdaptedObject);
 | 
			
		||||
                openmct = {
 | 
			
		||||
                    telemetry: jasmine.createSpyObj('telemetryAPI', [
 | 
			
		||||
                        'getMetadata'
 | 
			
		||||
                    ])
 | 
			
		||||
                };
 | 
			
		||||
                telemetryMetadata = jasmine.createSpyObj('telemetryMetadata', [
 | 
			
		||||
                    'valuesForHints'
 | 
			
		||||
                ]);
 | 
			
		||||
                telemetryMetadata.valuesForHints.andReturn([]);
 | 
			
		||||
                openmct.telemetry.getMetadata.andReturn(telemetryMetadata);
 | 
			
		||||
                policy = new PlotViewPolicy(openmct);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('fetches metadata from telem api', function () {
 | 
			
		||||
                policy.allow(testView, mockDomainObject);
 | 
			
		||||
                expect(mockDomainObject.useCapability)
 | 
			
		||||
                    .toHaveBeenCalledWith('adapter');
 | 
			
		||||
                expect(openmct.telemetry.getMetadata)
 | 
			
		||||
                    .toHaveBeenCalledWith(testAdaptedObject);
 | 
			
		||||
                expect(telemetryMetadata.valuesForHints)
 | 
			
		||||
                    .toHaveBeenCalledWith(['range']);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('returns false if no ranges exist', function () {
 | 
			
		||||
                telemetryMetadata.valuesForHints.andReturn([]);
 | 
			
		||||
                expect(policy.allow(testView, mockDomainObject)).toBe(false);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('returns true if any ranges exist', function () {
 | 
			
		||||
                telemetryMetadata.valuesForHints.andReturn([{}]);
 | 
			
		||||
                expect(policy.allow(testView, mockDomainObject)).toBe(true);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('returns false if all ranges are strings', function () {
 | 
			
		||||
                telemetryMetadata.valuesForHints.andReturn([{
 | 
			
		||||
                    format: 'string'
 | 
			
		||||
                }, {
 | 
			
		||||
                    format: 'string'
 | 
			
		||||
                }]);
 | 
			
		||||
                expect(policy.allow(testView, mockDomainObject)).toBe(false);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('returns true if only some ranges are strings', function () {
 | 
			
		||||
                telemetryMetadata.valuesForHints.andReturn([{
 | 
			
		||||
                    format: 'string'
 | 
			
		||||
                }, {}]);
 | 
			
		||||
                expect(policy.allow(testView, mockDomainObject)).toBe(true);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('returns true for telemetry delegators', function () {
 | 
			
		||||
                delete testAdaptedObject.telemetry;
 | 
			
		||||
                mockDomainObject.hasCapability.andCallFake(function (c) {
 | 
			
		||||
                    return c === 'delegation';
 | 
			
		||||
                });
 | 
			
		||||
                mockDomainObject.getCapability.andReturn(
 | 
			
		||||
                    jasmine.createSpyObj('delegation', [
 | 
			
		||||
                        'doesDelegateCapability'
 | 
			
		||||
                    ])
 | 
			
		||||
                );
 | 
			
		||||
                mockDomainObject.getCapability('delegation')
 | 
			
		||||
                    .doesDelegateCapability.andCallFake(function (c) {
 | 
			
		||||
                        return c === 'telemetry';
 | 
			
		||||
                    });
 | 
			
		||||
                expect(policy.allow(testView, mockDomainObject)).toBe(true);
 | 
			
		||||
                expect(openmct.telemetry.getMetadata).not.toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('returns true for non-telemetry non-delegators', function () {
 | 
			
		||||
                delete testAdaptedObject.telemetry;
 | 
			
		||||
                mockDomainObject.hasCapability.andReturn(false);
 | 
			
		||||
                expect(policy.allow(testView, mockDomainObject)).toBe(false);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("allows other views", function () {
 | 
			
		||||
                testView.key = "somethingElse";
 | 
			
		||||
                expect(policy.allow(testView, mockDomainObject)).toBe(true);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -1,120 +0,0 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT, Copyright (c) 2014-2017, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ExportImageServiceSpec. Created by hudsonfoo on 09/03/16.
 | 
			
		||||
 */
 | 
			
		||||
define(
 | 
			
		||||
    ["../../src/services/ExportImageService"],
 | 
			
		||||
    function (ExportImageService) {
 | 
			
		||||
        var mockQ,
 | 
			
		||||
            mockDeferred,
 | 
			
		||||
            mockPromise,
 | 
			
		||||
            mockTimeout,
 | 
			
		||||
            mockLog,
 | 
			
		||||
            mockHtml2Canvas,
 | 
			
		||||
            mockCanvas,
 | 
			
		||||
            mockSaveAs,
 | 
			
		||||
            mockFileReader,
 | 
			
		||||
            mockExportTimeoutConstant,
 | 
			
		||||
            testElement,
 | 
			
		||||
            exportImageService;
 | 
			
		||||
 | 
			
		||||
        describe("ExportImageService", function () {
 | 
			
		||||
            beforeEach(function () {
 | 
			
		||||
                mockDeferred = jasmine.createSpyObj(
 | 
			
		||||
                    "deferred",
 | 
			
		||||
                    ["reject", "resolve"]
 | 
			
		||||
                );
 | 
			
		||||
                mockPromise = jasmine.createSpyObj(
 | 
			
		||||
                    "promise",
 | 
			
		||||
                    ["then", "finally"]
 | 
			
		||||
                );
 | 
			
		||||
                mockPromise.then = function (callback) {
 | 
			
		||||
                    callback();
 | 
			
		||||
                };
 | 
			
		||||
                mockQ = {
 | 
			
		||||
                    "defer": function () {
 | 
			
		||||
                        return {
 | 
			
		||||
                            "resolve": mockDeferred.resolve,
 | 
			
		||||
                            "reject": mockDeferred.reject,
 | 
			
		||||
                            "promise": mockPromise
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
                mockTimeout = function (fn, time) {
 | 
			
		||||
                    return {
 | 
			
		||||
                        "cancel": function () {}
 | 
			
		||||
                    };
 | 
			
		||||
                };
 | 
			
		||||
                mockLog = jasmine.createSpyObj(
 | 
			
		||||
                    "$log",
 | 
			
		||||
                    ["warn"]
 | 
			
		||||
                );
 | 
			
		||||
                mockHtml2Canvas = jasmine.createSpy("html2canvas").andCallFake(function (element, opts) {
 | 
			
		||||
                    opts.onrendered(mockCanvas);
 | 
			
		||||
                });
 | 
			
		||||
                mockCanvas = jasmine.createSpyObj(
 | 
			
		||||
                    "canvas",
 | 
			
		||||
                    ["toBlob"]
 | 
			
		||||
                );
 | 
			
		||||
                mockSaveAs = jasmine.createSpy("saveAs");
 | 
			
		||||
                mockFileReader = jasmine.createSpyObj(
 | 
			
		||||
                    "FileReader",
 | 
			
		||||
                    ["readAsDataURL", "onloadend"]
 | 
			
		||||
                );
 | 
			
		||||
                mockExportTimeoutConstant = 0;
 | 
			
		||||
                testElement = {};
 | 
			
		||||
 | 
			
		||||
                exportImageService = new ExportImageService(
 | 
			
		||||
                    mockQ,
 | 
			
		||||
                    mockTimeout,
 | 
			
		||||
                    mockLog,
 | 
			
		||||
                    mockExportTimeoutConstant,
 | 
			
		||||
                    mockHtml2Canvas,
 | 
			
		||||
                    mockSaveAs,
 | 
			
		||||
                    mockFileReader
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("runs html2canvas and tries to save a png", function () {
 | 
			
		||||
                exportImageService.exportPNG(testElement, "plot.png");
 | 
			
		||||
 | 
			
		||||
                expect(mockHtml2Canvas).toHaveBeenCalledWith(testElement, { onrendered: jasmine.any(Function) });
 | 
			
		||||
                expect(mockCanvas.toBlob).toHaveBeenCalledWith(mockDeferred.resolve, "image/png");
 | 
			
		||||
                expect(mockDeferred.reject).not.toHaveBeenCalled();
 | 
			
		||||
                expect(mockSaveAs).toHaveBeenCalled();
 | 
			
		||||
                expect(mockPromise.finally).toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it("runs html2canvas and tries to save a jpg", function () {
 | 
			
		||||
                exportImageService.exportJPG(testElement, "plot.png");
 | 
			
		||||
 | 
			
		||||
                expect(mockHtml2Canvas).toHaveBeenCalledWith(testElement, { onrendered: jasmine.any(Function) });
 | 
			
		||||
                expect(mockCanvas.toBlob).toHaveBeenCalledWith(mockDeferred.resolve, "image/jpeg");
 | 
			
		||||
                expect(mockDeferred.reject).not.toHaveBeenCalled();
 | 
			
		||||
                expect(mockSaveAs).toHaveBeenCalled();
 | 
			
		||||
                expect(mockPromise.finally).toHaveBeenCalled();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -205,6 +205,9 @@ define(
 | 
			
		||||
                },
 | 
			
		||||
                getPointCount: function () {
 | 
			
		||||
                    return telemetry.length;
 | 
			
		||||
                },
 | 
			
		||||
                getData: function () {
 | 
			
		||||
                    return telemetry;
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -268,6 +268,7 @@ define([
 | 
			
		||||
 | 
			
		||||
        legacyRegistry.register('adapter', this.legacyBundle);
 | 
			
		||||
        legacyRegistry.enable('adapter');
 | 
			
		||||
        this.install(this.plugins.Plot());
 | 
			
		||||
        /**
 | 
			
		||||
         * Fired by [MCT]{@link module:openmct.MCT} when the application
 | 
			
		||||
         * is started.
 | 
			
		||||
 
 | 
			
		||||
@@ -148,7 +148,9 @@ define([
 | 
			
		||||
        var limitEvaluator = oldObject.getCapability("limit");
 | 
			
		||||
 | 
			
		||||
        if (!limitEvaluator) {
 | 
			
		||||
            return;
 | 
			
		||||
            return {
 | 
			
		||||
                evaluate: function () {}
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
 
 | 
			
		||||
@@ -100,6 +100,18 @@ define([
 | 
			
		||||
            delete valueMetadata.hints.y;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (valueMetadata.format == 'enum') {
 | 
			
		||||
            if (!valueMetadata.values) {
 | 
			
		||||
                valueMetadata.values = _.pluck(valueMetadata.enumerations, 'value');
 | 
			
		||||
            }
 | 
			
		||||
            if (!valueMetadata.hasOwnProperty('max')) {
 | 
			
		||||
                valueMetadata.max = _.max(valueMetadata.values) + 1;
 | 
			
		||||
            }
 | 
			
		||||
            if (!valueMetadata.hasOwnProperty('min')) {
 | 
			
		||||
                valueMetadata.min = _.min(valueMetadata.values) - 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!valueMetadata.hints.hasOwnProperty('priority')) {
 | 
			
		||||
            valueMetadata.hints.priority = index;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -21,9 +21,11 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    'lodash'
 | 
			
		||||
    'lodash',
 | 
			
		||||
    'printj'
 | 
			
		||||
], function (
 | 
			
		||||
    _
 | 
			
		||||
    _,
 | 
			
		||||
    printj
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    // TODO: needs reference to formatService;
 | 
			
		||||
@@ -49,7 +51,7 @@ define([
 | 
			
		||||
            this.formatter = numberFormatter;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (valueMetadata.type === 'enum') {
 | 
			
		||||
        if (valueMetadata.format === 'enum') {
 | 
			
		||||
            this.formatter = {};
 | 
			
		||||
            this.enumerations = valueMetadata.enumerations.reduce(function (vm, e) {
 | 
			
		||||
                vm.byValue[e.value] = e.string;
 | 
			
		||||
@@ -57,15 +59,26 @@ define([
 | 
			
		||||
                return vm;
 | 
			
		||||
            }, {byValue: {}, byString: {}});
 | 
			
		||||
            this.formatter.format = function (value) {
 | 
			
		||||
                return this.enumerations.byValue[value];
 | 
			
		||||
                if (typeof value === "number") {
 | 
			
		||||
                    return this.enumerations.byValue[value] || value;
 | 
			
		||||
                }
 | 
			
		||||
                return value;
 | 
			
		||||
            }.bind(this);
 | 
			
		||||
            this.formatter.parse = function (string) {
 | 
			
		||||
                if (typeof string === "string" && this.enumerations.hasOwnProperty(string)) {
 | 
			
		||||
                    return this.enumerations.byString[string];
 | 
			
		||||
                if (typeof string === "string") {
 | 
			
		||||
                    if (this.enumerations.byString.hasOwnProperty(string)) {
 | 
			
		||||
                        return this.enumerations.byString[string]
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                return Number(string);
 | 
			
		||||
            }.bind(this);
 | 
			
		||||
        }
 | 
			
		||||
        if (valueMetadata.sprintf) {
 | 
			
		||||
            this.formatter = numberFormatter;
 | 
			
		||||
            this.formatter.format = function (value) {
 | 
			
		||||
                return printj.sprintf(valueMetadata.sprintf, value);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    TelemetryValueFormatter.prototype.parse = function (datum) {
 | 
			
		||||
 
 | 
			
		||||
@@ -73,7 +73,6 @@ define([
 | 
			
		||||
    '../platform/features/my-items/bundle',
 | 
			
		||||
    '../platform/features/pages/bundle',
 | 
			
		||||
    '../platform/features/hyperlink/bundle',
 | 
			
		||||
    '../platform/features/plot/bundle',
 | 
			
		||||
    '../platform/features/static-markup/bundle',
 | 
			
		||||
    '../platform/features/table/bundle',
 | 
			
		||||
    '../platform/features/timeline/bundle',
 | 
			
		||||
@@ -120,7 +119,6 @@ define([
 | 
			
		||||
        'platform/features/listview',
 | 
			
		||||
        'platform/features/pages',
 | 
			
		||||
        'platform/features/hyperlink',
 | 
			
		||||
        'platform/features/plot',
 | 
			
		||||
        'platform/features/timeline',
 | 
			
		||||
        'platform/features/table',
 | 
			
		||||
        'platform/forms',
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										114
									
								
								src/plugins/plot/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								src/plugins/plot/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,114 @@
 | 
			
		||||
# plot
 | 
			
		||||
 | 
			
		||||
# One more time-- celebration.
 | 
			
		||||
 | 
			
		||||
PlotConfigurationModel -- backed by Plot Object model.
 | 
			
		||||
    PlotSeries[]
 | 
			
		||||
        PlotSeries
 | 
			
		||||
    XAxis
 | 
			
		||||
    YAxis
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
PlotStateModel
 | 
			
		||||
    PlotSeries[]
 | 
			
		||||
        PlotSeries -- handles loading of data, data, etc.
 | 
			
		||||
    XAxis
 | 
			
		||||
    YAxis
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
TelemetryPointPlot
 | 
			
		||||
    Creates a placeholder PlotConfigurationModel each time.
 | 
			
		||||
 | 
			
		||||
OverlayPlot
 | 
			
		||||
 | 
			
		||||
StackedPlot -- has an array of subplots.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
The `plot-reborn` bundle provides directives for composing plot based views.
 | 
			
		||||
It also exposes domain objects for plotting telemetry points.
 | 
			
		||||
 | 
			
		||||
## chart
 | 
			
		||||
Chart defines a directive for charting data.  It is the main interface between 
 | 
			
		||||
the drawing API and a plot controller.
 | 
			
		||||
 | 
			
		||||
##  plot
 | 
			
		||||
Plot defines a directive for plotting data, and provides some types it 
 | 
			
		||||
uses to do so: the PlotAxis and the PlotSeries.
 | 
			
		||||
 | 
			
		||||
## TelemetryPlot
 | 
			
		||||
Telemetry plot includes controllers needed to connect to telemetry providers.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
MCTChart is a directive for charting data.  
 | 
			
		||||
 | 
			
		||||
## Types
 | 
			
		||||
 | 
			
		||||
* OverlayPlot: can be used on any domain object that has or delegates a 
 | 
			
		||||
    telemetry capability.
 | 
			
		||||
    
 | 
			
		||||
    -> View: OverlayPlot
 | 
			
		||||
 | 
			
		||||
* StackedPlot: can be used on any domain object that delegates telemetry or 
 | 
			
		||||
    delegates composition of elements that have telemetry.
 | 
			
		||||
    
 | 
			
		||||
    -> View: StackedPlot
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Series
 | 
			
		||||
* label
 | 
			
		||||
* data
 | 
			
		||||
* color
 | 
			
		||||
* markers (yes/no)
 | 
			
		||||
* scale
 | 
			
		||||
    - maps 
 | 
			
		||||
 | 
			
		||||
## Directives
 | 
			
		||||
 | 
			
		||||
* `mct-chart`: an element that takes `series`, `viewport`, and
 | 
			
		||||
    `rectangles` and plots the data.  Adding points to a series after it has 
 | 
			
		||||
    been initially plotted can be done either by recreating the series object
 | 
			
		||||
    or by broadcasting "series:data:add" with arguments `event`, `seriesIndex`, 
 | 
			
		||||
    `points`.  This will append `points` to the `series` at index `seriesIndex`.
 | 
			
		||||
 | 
			
		||||
* `mct-plot`: A directive that wraps a mct-chart and handles user interactions
 | 
			
		||||
    with that plot.  It emits events that a parent view can use for coordinating
 | 
			
		||||
    functionality:
 | 
			
		||||
    * emits a `user:viewport:change:start` event when the viewport begins being
 | 
			
		||||
        changed by a user, to allow any parent controller to prevent viewport 
 | 
			
		||||
        modifications while the user is interacting with the plot.
 | 
			
		||||
    * emits a `user:viewport:change:end` event when the user has finished
 | 
			
		||||
        changing the viewport.  This allows a controller on a parent scope to
 | 
			
		||||
        track viewport history and provide any necessary functionality
 | 
			
		||||
        around viewport changes, e.g. viewport history.
 | 
			
		||||
 | 
			
		||||
* `mct-overlay-plot`: A directive that takes `domainObject` and plots either a
 | 
			
		||||
    single series of data (in the case of a single telemetry object) or multiple
 | 
			
		||||
    series of data (in the case of a object which delegates telemetry).
 | 
			
		||||
 | 
			
		||||
## Controllers
 | 
			
		||||
 | 
			
		||||
NOTE: this section not accurate.  Essentially, these controllers format data for
 | 
			
		||||
the mct-chart directive.  They also handle live viewport updating, as well as
 | 
			
		||||
managing all transformations from domain objects to views.
 | 
			
		||||
 | 
			
		||||
* StackPlotController: Uses the composition capability of a StackPlot domain 
 | 
			
		||||
    object to retrieve SubPlots and render them with individual PlotControllers.
 | 
			
		||||
* PlotController: Uses either a domain object that delegates telemetry or a 
 | 
			
		||||
    domain object with telemetry to and feeds that data to the mct-chart 
 | 
			
		||||
    directive.
 | 
			
		||||
 | 
			
		||||
## TODOS:
 | 
			
		||||
 | 
			
		||||
* [ ] Re-implement history stack.
 | 
			
		||||
* [ ] Re-implement plot pallette.
 | 
			
		||||
* [ ] Re-implement stacked plot viewport synchronization (share viewport object)
 | 
			
		||||
* [ ] Other things?
 | 
			
		||||
* [ ] Handle edge cases with marquee zoom/panning.
 | 
			
		||||
* [ ] Tidy code.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										249
									
								
								src/plugins/plot/plugin.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								src/plugins/plot/plugin.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,249 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 * as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 * Administration. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 * "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 * License for the specific language governing permissions and limitations
 | 
			
		||||
 * under the License.
 | 
			
		||||
 *
 | 
			
		||||
 * Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * at runtime from the About dialog for additional information.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
/*global define*/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    "./src/chart/MCTChartDirective",
 | 
			
		||||
    "./src/plot/MCTPlotDirective",
 | 
			
		||||
    './src/plot/MCTTicksDirective',
 | 
			
		||||
    "./src/telemetry/MCTOverlayPlot",
 | 
			
		||||
    "./src/telemetry/PlotController",
 | 
			
		||||
    "./src/telemetry/StackedPlotController",
 | 
			
		||||
    "./src/inspector/PlotInspector",
 | 
			
		||||
    "./src/inspector/PlotOptionsController",
 | 
			
		||||
    "./src/inspector/HideElementPoolDirective",
 | 
			
		||||
    "./src/services/ExportImageService",
 | 
			
		||||
    './src/PlotViewPolicy',
 | 
			
		||||
    "text!./res/templates/plot-options.html",
 | 
			
		||||
    "text!./res/templates/plot-options-browse.html",
 | 
			
		||||
    "text!./res/templates/plot-options-edit.html",
 | 
			
		||||
    "text!./res/templates/stacked-plot.html",
 | 
			
		||||
    "text!./res/templates/plot.html"
 | 
			
		||||
], function (
 | 
			
		||||
    MCTChartDirective,
 | 
			
		||||
    MCTPlotDirective,
 | 
			
		||||
    MCTTicksDirective,
 | 
			
		||||
    MCTOverlayPlot,
 | 
			
		||||
    PlotController,
 | 
			
		||||
    StackedPlotController,
 | 
			
		||||
    PlotInspector,
 | 
			
		||||
    PlotOptionsController,
 | 
			
		||||
    HideElementPool,
 | 
			
		||||
    ExportImageService,
 | 
			
		||||
    PlotViewPolicy,
 | 
			
		||||
    plotOptionsTemplate,
 | 
			
		||||
    plotOptionsBrowseTemplate,
 | 
			
		||||
    plotOptionsEditTemplate,
 | 
			
		||||
    StackedPlotTemplate,
 | 
			
		||||
    PlotTemplate
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    var installed = false;
 | 
			
		||||
 | 
			
		||||
    function PlotPlugin() {
 | 
			
		||||
        return function install(openmct) {
 | 
			
		||||
            if (installed) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            installed = true;
 | 
			
		||||
 | 
			
		||||
            openmct.legacyRegistry.register("openmct/plot", {
 | 
			
		||||
                "name": "Plot view for telemetry, reborn",
 | 
			
		||||
                "extensions": {
 | 
			
		||||
                    "policies": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "category": "view",
 | 
			
		||||
                            "implementation": PlotViewPolicy,
 | 
			
		||||
                            "depends": [
 | 
			
		||||
                                "openmct"
 | 
			
		||||
                            ]
 | 
			
		||||
                        }
 | 
			
		||||
                    ],
 | 
			
		||||
                    "views": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "name": "Plot",
 | 
			
		||||
                            "key": "plot-single",
 | 
			
		||||
                            "cssClass": "icon-telemetry",
 | 
			
		||||
                            "template": PlotTemplate,
 | 
			
		||||
                            "needs": [
 | 
			
		||||
                                "telemetry"
 | 
			
		||||
                            ],
 | 
			
		||||
                            "delegation": false,
 | 
			
		||||
                            "priority": "mandatory"
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            "name": "Overlay Plot",
 | 
			
		||||
                            "key": "overlayPlot",
 | 
			
		||||
                            "cssClass": "icon-plot-overlay",
 | 
			
		||||
                            "type": "telemetry.plot.overlay",
 | 
			
		||||
                            "template": PlotTemplate,
 | 
			
		||||
                            "editable": true
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            "name": "Stacked Plot",
 | 
			
		||||
                            "key": "stackedPlot",
 | 
			
		||||
                            "cssClass": "icon-plot-stacked",
 | 
			
		||||
                            "type": "telemetry.plot.stacked",
 | 
			
		||||
                            "template": StackedPlotTemplate,
 | 
			
		||||
                            "editable": true
 | 
			
		||||
                        }
 | 
			
		||||
                    ],
 | 
			
		||||
                    "directives": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "key": "mctTicks",
 | 
			
		||||
                            "implementation": MCTTicksDirective,
 | 
			
		||||
                            "depends": []
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            "key": "mctChart",
 | 
			
		||||
                            "implementation": MCTChartDirective,
 | 
			
		||||
                            "depends": [
 | 
			
		||||
                                "$interval",
 | 
			
		||||
                                "$log"
 | 
			
		||||
                            ]
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            "key": "mctPlot",
 | 
			
		||||
                            "implementation": MCTPlotDirective,
 | 
			
		||||
                            "depends": [],
 | 
			
		||||
                            "templateUrl": "templates/mct-plot.html"
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            "key": "mctOverlayPlot",
 | 
			
		||||
                            "implementation": MCTOverlayPlot,
 | 
			
		||||
                            "depends": []
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            "key": "hideElementPool",
 | 
			
		||||
                            "implementation": HideElementPool,
 | 
			
		||||
                            "depends": []
 | 
			
		||||
                        }
 | 
			
		||||
                    ],
 | 
			
		||||
                    "controllers": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "key": "PlotController",
 | 
			
		||||
                            "implementation": PlotController,
 | 
			
		||||
                            "depends": [
 | 
			
		||||
                                "$scope",
 | 
			
		||||
                                "$element",
 | 
			
		||||
                                "formatService",
 | 
			
		||||
                                "openmct",
 | 
			
		||||
                                "objectService",
 | 
			
		||||
                                "exportImageService"
 | 
			
		||||
                            ]
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            "key": "StackedPlotController",
 | 
			
		||||
                            "implementation": StackedPlotController,
 | 
			
		||||
                            "depends": [
 | 
			
		||||
                                "$scope",
 | 
			
		||||
                                "openmct",
 | 
			
		||||
                                "objectService",
 | 
			
		||||
                                "$element",
 | 
			
		||||
                                "exportImageService"
 | 
			
		||||
                            ]
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            "key": "PlotOptionsController",
 | 
			
		||||
                            "implementation": PlotOptionsController,
 | 
			
		||||
                            "depends": [
 | 
			
		||||
                                "$scope",
 | 
			
		||||
                                "openmct",
 | 
			
		||||
                                "$timeout"
 | 
			
		||||
                            ]
 | 
			
		||||
                        }
 | 
			
		||||
                    ],
 | 
			
		||||
                    "services": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "key": "exportImageService",
 | 
			
		||||
                            "implementation": ExportImageService,
 | 
			
		||||
                            "depends": [
 | 
			
		||||
                                "$q",
 | 
			
		||||
                                "$timeout",
 | 
			
		||||
                                "$log"
 | 
			
		||||
                            ]
 | 
			
		||||
                        }
 | 
			
		||||
                    ],
 | 
			
		||||
                    "types": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "key": "telemetry.plot.overlay",
 | 
			
		||||
                            "name": "Overlay Plot",
 | 
			
		||||
                            "cssClass": "icon-plot-overlay",
 | 
			
		||||
                            "description": "Combine multiple telemetry elements and view them together as a plot with common X and Y axes. Can be added to Display Layouts.",
 | 
			
		||||
                            "features": "creation",
 | 
			
		||||
                            "contains": [
 | 
			
		||||
                                {
 | 
			
		||||
                                    "has": "telemetry"
 | 
			
		||||
                                }
 | 
			
		||||
                            ],
 | 
			
		||||
                            "model": {
 | 
			
		||||
                                composition: [],
 | 
			
		||||
                                configuration: {
 | 
			
		||||
                                    series: [],
 | 
			
		||||
                                    yAxis: {},
 | 
			
		||||
                                    xAxis: {}
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            "properties": [],
 | 
			
		||||
                            "inspector": "plot-options",
 | 
			
		||||
                            "priority": 891
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            "key": "telemetry.plot.stacked",
 | 
			
		||||
                            "name": "Stacked Plot",
 | 
			
		||||
                            "cssClass": "icon-plot-stacked",
 | 
			
		||||
                            "description": "Combine multiple telemetry elements and view them together as a plot with a common X axis and individual Y axes. Can be added to Display Layouts.",
 | 
			
		||||
                            "features": "creation",
 | 
			
		||||
                            "contains": [
 | 
			
		||||
                                "telemetry.plot.overlay",
 | 
			
		||||
                                {"has": "telemetry"},
 | 
			
		||||
                            ],
 | 
			
		||||
                            "model": {
 | 
			
		||||
                                "composition": []
 | 
			
		||||
                            },
 | 
			
		||||
                            "properties": [],
 | 
			
		||||
                            "priority": 890
 | 
			
		||||
                        }
 | 
			
		||||
                    ],
 | 
			
		||||
                    "representations": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "key": "plot-options",
 | 
			
		||||
                            "template": plotOptionsTemplate
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            "key": "plot-options-browse",
 | 
			
		||||
                            "template": plotOptionsBrowseTemplate
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            "key": "plot-options-edit",
 | 
			
		||||
                            "template": plotOptionsEditTemplate
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            openmct.legacyRegistry.enable("openmct/plot");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return PlotPlugin
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										189
									
								
								src/plugins/plot/res/templates/mct-plot.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								src/plugins/plot/res/templates/mct-plot.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,189 @@
 | 
			
		||||
<div class="gl-plot plot-legend-{{legend.get('position')}} {{legend.get('expanded')? 'plot-legend-expanded' : 'plot-legend-collapsed'}}">
 | 
			
		||||
    <div class="gl-plot-legend flex-elem l-flex-row"
 | 
			
		||||
         ng-class="{ 'hover-on-plot': !!highlights.length }"
 | 
			
		||||
         ng-show="legend.get('position') !== 'hidden'">
 | 
			
		||||
        <span class="view-control flex-elem"
 | 
			
		||||
            ng-class="{ expanded: legend.get('expanded') }"
 | 
			
		||||
            ng-click="legend.set('expanded', !legend.get('expanded'));">
 | 
			
		||||
        </span>
 | 
			
		||||
 | 
			
		||||
        <!-- COLLAPSED PLOT LEGEND -->
 | 
			
		||||
        <div class="plot-wrapper-collapsed-legend">
 | 
			
		||||
            <div class="plot-legend-item"
 | 
			
		||||
                  ng-repeat="series in series track by $index">
 | 
			
		||||
                <div class="plot-series-swatch-and-name">
 | 
			
		||||
                    <span class="plot-series-color-swatch"
 | 
			
		||||
                          ng-style="{ 'background-color': series.get('color').asHexString() }">
 | 
			
		||||
                    </span>
 | 
			
		||||
                    <span class="plot-series-name">{{ series.get('name') }}</span>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="plot-series-value hover-value-enabled value-to-display-{{ legend.get('valueToShowWhenCollapsed') }} {{ series.closest._limit.cssClass }}"
 | 
			
		||||
                     ng-class="{ 'cursor-hover': (legend.get('valueToShowWhenCollapsed').indexOf('nearest') != -1) }"
 | 
			
		||||
                     ng-show="!!highlights.length && legend.get('valueToShowWhenCollapsed') !== 'none'">
 | 
			
		||||
                    {{ legend.get('valueToShowWhenCollapsed') === 'nearestValue' ?
 | 
			
		||||
                        series.formatY(series.closest) :
 | 
			
		||||
                        legend.get('valueToShowWhenCollapsed') === 'nearestTimestamp' ?
 | 
			
		||||
                             series.closest && series.formatX(series.closest) :
 | 
			
		||||
                             series.formatY(series.get('stats')[legend.get('valueToShowWhenCollapsed') + 'Point']);
 | 
			
		||||
                    }}
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <!-- EXPANDED PLOT LEGEND -->
 | 
			
		||||
        <div class="plot-wrapper-expanded-legend flex-elem grows">
 | 
			
		||||
            <table>
 | 
			
		||||
                <thead>
 | 
			
		||||
                    <tr>
 | 
			
		||||
                        <th>Name</th>
 | 
			
		||||
                        <th ng-if="legend.get('showTimestampWhenExpanded')">
 | 
			
		||||
                            Timestamp
 | 
			
		||||
                        </th>
 | 
			
		||||
                        <th ng-if="legend.get('showValueWhenExpanded')">
 | 
			
		||||
                            Value
 | 
			
		||||
                        </th>
 | 
			
		||||
                        <th ng-if="legend.get('showMinimumWhenExpanded')"
 | 
			
		||||
                            class="mobile-hide">
 | 
			
		||||
                            Min
 | 
			
		||||
                        </th>
 | 
			
		||||
                        <th ng-if="legend.get('showMaximumWhenExpanded')"
 | 
			
		||||
                            class="mobile-hide">
 | 
			
		||||
                            Max
 | 
			
		||||
                        </th>
 | 
			
		||||
                    </tr>
 | 
			
		||||
                </thead>
 | 
			
		||||
                <tr ng-repeat="series in series" class="plot-legend-item">
 | 
			
		||||
                    <td class="plot-series-swatch-and-name">
 | 
			
		||||
                        <span class="plot-series-color-swatch"
 | 
			
		||||
                              ng-style="{ 'background-color': series.get('color').asHexString() }">
 | 
			
		||||
                        </span>
 | 
			
		||||
                        <span class="plot-series-name">{{ series.get('name') }}</span>
 | 
			
		||||
                    </td>
 | 
			
		||||
 | 
			
		||||
                    <td ng-if="legend.get('showTimestampWhenExpanded')">
 | 
			
		||||
                        <span class="plot-series-value cursor-hover hover-value-enabled">
 | 
			
		||||
                            {{ series.closest && series.formatX(series.closest) }}
 | 
			
		||||
                        </span>
 | 
			
		||||
                    </td>
 | 
			
		||||
                    <td ng-if="legend.get('showValueWhenExpanded')">
 | 
			
		||||
                        <span class="plot-series-value cursor-hover hover-value-enabled"
 | 
			
		||||
                              ng-class="series.closest._limit.cssClass">
 | 
			
		||||
                            {{ series.formatY(series.closest) }}
 | 
			
		||||
                        </span>
 | 
			
		||||
                    </td>
 | 
			
		||||
                    <td ng-if="legend.get('showMinimumWhenExpanded')"
 | 
			
		||||
                        class="mobile-hide">
 | 
			
		||||
                        <span class="plot-series-value">
 | 
			
		||||
                            {{ series.formatY(series.get('stats').minPoint) }}
 | 
			
		||||
                        </span>
 | 
			
		||||
                    </td>
 | 
			
		||||
                    <td ng-if="legend.get('showMaximumWhenExpanded')"
 | 
			
		||||
                        class="mobile-hide">
 | 
			
		||||
                        <span class="plot-series-value">
 | 
			
		||||
                            {{ series.formatY(series.get('stats').maxPoint) }}
 | 
			
		||||
                        </span>
 | 
			
		||||
                    </td>
 | 
			
		||||
                </tr>
 | 
			
		||||
            </table>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="plot-wrapper-axis-and-display-area flex-elem grows">
 | 
			
		||||
        <div class="gl-plot-axis-area gl-plot-y"
 | 
			
		||||
             ng-style="{
 | 
			
		||||
                 width: (tickWidth + 30) + 'px'
 | 
			
		||||
             }">
 | 
			
		||||
 | 
			
		||||
            <div class="gl-plot-label gl-plot-y-label">
 | 
			
		||||
                {{ yAxis.get('label') }}
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <mct-ticks axis="yAxis">
 | 
			
		||||
                <div ng-repeat="tick in ticks track by tick.text"
 | 
			
		||||
                     class="gl-plot-tick gl-plot-y-tick-label"
 | 
			
		||||
                     ng-style="{ top: (100 * (max - tick.value) / interval) + '%' }"
 | 
			
		||||
                     title="{{:: tick.fullText || tick.text }}"
 | 
			
		||||
                     style="margin-top: -0.50em; direction: ltr;">
 | 
			
		||||
                    <span>{{:: tick.text}}</span>
 | 
			
		||||
                </div>
 | 
			
		||||
            </mct-ticks>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="gl-plot-wrapper-display-area-and-x-axis"
 | 
			
		||||
             ng-style="{
 | 
			
		||||
                     left: (tickWidth + 30) + 'px'
 | 
			
		||||
                 }">
 | 
			
		||||
            <span class="t-object-alert t-alert-unsynced" title="This plot is not currently displaying the latest data. Reset Pan/zoom to return to view latest data."></span>
 | 
			
		||||
            <div class="gl-plot-display-area">
 | 
			
		||||
                <mct-ticks axis="xAxis">
 | 
			
		||||
                    <div class="gl-plot-hash hash-v"
 | 
			
		||||
                         ng-repeat="tick in ticks track by tick.value"
 | 
			
		||||
                         ng-style="{
 | 
			
		||||
                             right: (100 * (max - tick.value) / interval) + '%',
 | 
			
		||||
                             height: '100%'
 | 
			
		||||
                         }">
 | 
			
		||||
                     </div>
 | 
			
		||||
                </mct-ticks>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                <mct-ticks axis="yAxis">
 | 
			
		||||
                     <div class="gl-plot-hash hash-h"
 | 
			
		||||
                          ng-repeat="tick in ticks track by tick.value"
 | 
			
		||||
                          ng-style="{ bottom: (100 * (tick.value - min) / interval) + '%', width: '100%' }">
 | 
			
		||||
                     </div>
 | 
			
		||||
                </mct-ticks>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                <mct-chart config="config"
 | 
			
		||||
                           series="series"
 | 
			
		||||
                           rectangles="rectangles"
 | 
			
		||||
                           highlights="highlights"
 | 
			
		||||
                           the-x-axis="xAxis"
 | 
			
		||||
                           the-y-axis="yAxis">
 | 
			
		||||
                </mct-chart>
 | 
			
		||||
 | 
			
		||||
                <div class="l-local-controls gl-plot-local-controls"
 | 
			
		||||
                     ng-show="plotHistory.length"
 | 
			
		||||
                     style="position: absolute; top: 8px; right: 8px;">
 | 
			
		||||
 | 
			
		||||
                    <a class="s-button icon-arrow-left"
 | 
			
		||||
                       ng-click="plot.back()"
 | 
			
		||||
                       title="Restore previous pan/zoom">
 | 
			
		||||
                    </a>
 | 
			
		||||
 | 
			
		||||
                    <a class="s-button icon-arrows-out"
 | 
			
		||||
                       ng-click="plot.clear()"
 | 
			
		||||
                       title="Reset pan/zoom">
 | 
			
		||||
                    </a>
 | 
			
		||||
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                <span class="t-wait-spinner loading" ng-show="plot.isRequestPending()">
 | 
			
		||||
                </span>
 | 
			
		||||
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="gl-plot-axis-area gl-plot-x"
 | 
			
		||||
                 ng-style="{
 | 
			
		||||
                     left: (tickWidth - 30) + 'px'
 | 
			
		||||
                 }">
 | 
			
		||||
 | 
			
		||||
                <mct-ticks axis="xAxis">
 | 
			
		||||
                     <div ng-repeat="tick in ticks track by tick.text"
 | 
			
		||||
                          class="gl-plot-tick gl-plot-x-tick-label"
 | 
			
		||||
                          ng-style="{
 | 
			
		||||
                              left: (100 * (tick.value - min) / interval) + '%'
 | 
			
		||||
                          }"
 | 
			
		||||
                          ng-title=":: tick.fullText || tick.text">
 | 
			
		||||
                         {{:: tick.text | reverse}}
 | 
			
		||||
                     </div>
 | 
			
		||||
                </mct-ticks>
 | 
			
		||||
 | 
			
		||||
                <div class="gl-plot-label gl-plot-x-label">
 | 
			
		||||
                    {{ xAxis.get('label') }}
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										130
									
								
								src/plugins/plot/res/templates/plot-options-browse.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								src/plugins/plot/res/templates/plot-options-browse.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,130 @@
 | 
			
		||||
<!--
 | 
			
		||||
 Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 Administration. All rights reserved.
 | 
			
		||||
 | 
			
		||||
 Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 You may obtain a copy of the License at
 | 
			
		||||
 http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 | 
			
		||||
 Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 License for the specific language governing permissions and limitations
 | 
			
		||||
 under the License.
 | 
			
		||||
 | 
			
		||||
 Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 this source code distribution or the Licensing information page available
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
<div ng-controller="PlotOptionsController"
 | 
			
		||||
     class="flex-elem grows l-inspector-part">
 | 
			
		||||
     <ul class="flex-elem grows l-inspector-part"><li>
 | 
			
		||||
         <em class="t-inspector-part-header">Plot Series</em>
 | 
			
		||||
         <ul class="first flex-elem grows vscroll">
 | 
			
		||||
             <ul class="tree">
 | 
			
		||||
                 <li ng-repeat="series in config.series.models">
 | 
			
		||||
                         <span class="tree-item menus-to-left">
 | 
			
		||||
                             <span
 | 
			
		||||
                                 class='ui-symbol view-control flex-elem'
 | 
			
		||||
                                 ng-class="{ expanded: series.expanded }"
 | 
			
		||||
                                 ng-click="series.expanded = !series.expanded">
 | 
			
		||||
                             </span>
 | 
			
		||||
                             <mct-representation
 | 
			
		||||
                                 class="rep-object-label"
 | 
			
		||||
                                 key="'label'"
 | 
			
		||||
                                 mct-object="series.oldObject">
 | 
			
		||||
                             </mct-representation>
 | 
			
		||||
                         </span>
 | 
			
		||||
                         <div class="l-flex-col inspector-config" ng-show="series.expanded">
 | 
			
		||||
                             <div class="inspector-properties">
 | 
			
		||||
                                 <div class="label">Line Style</div>
 | 
			
		||||
                                 <div class="value">{{ {
 | 
			
		||||
                                     'none': 'None',
 | 
			
		||||
                                     'linear': 'Linear interpolation',
 | 
			
		||||
                                     'stepAfter': 'Step After'
 | 
			
		||||
                                     }[series.get('interpolate')] }}</div>
 | 
			
		||||
                             </div>
 | 
			
		||||
                             <div class="inspector-properties">
 | 
			
		||||
                                 <div class="label">Markers</div>
 | 
			
		||||
                                 <div class="value">
 | 
			
		||||
                                     {{series.get('markers') ? "On, " + series.get('markerSize') + "px" : "Off"}}
 | 
			
		||||
                                 </div>
 | 
			
		||||
                             </div>
 | 
			
		||||
 | 
			
		||||
                             <div class="inspector-properties">
 | 
			
		||||
                                 <div class="label">Color</div>
 | 
			
		||||
                                 <div class="value">
 | 
			
		||||
                                     <span class="color-swatch"
 | 
			
		||||
                                           ng-style="{
 | 
			
		||||
                                              'background': series.get('color').asHexString(),
 | 
			
		||||
                                              'display': 'inline-block',
 | 
			
		||||
                                              'border': '1px solid rgba(255, 255, 255, 0.2)',
 | 
			
		||||
                                              'height': '10px',
 | 
			
		||||
                                              'width': '10px',
 | 
			
		||||
                                              'vertical-align': 'middle',
 | 
			
		||||
                                              'margin-left': '3px',
 | 
			
		||||
                                              'margin-top': -'2px'
 | 
			
		||||
                                           }">
 | 
			
		||||
                                     </span>
 | 
			
		||||
                                 </div>
 | 
			
		||||
                             </div>
 | 
			
		||||
                         </div>
 | 
			
		||||
                 </li>
 | 
			
		||||
             </ul>
 | 
			
		||||
         </ul>
 | 
			
		||||
     </li>
 | 
			
		||||
         <li>
 | 
			
		||||
             <em class="t-inspector-part-header">Y Axis</em>
 | 
			
		||||
             <div class="inspector-properties first">
 | 
			
		||||
                 <div class="label">Label</div>
 | 
			
		||||
                 <div class="value">{{ config.yAxis.get('label') }}</div>
 | 
			
		||||
             </div>
 | 
			
		||||
             <div class="inspector-properties">
 | 
			
		||||
                 <div class="label">Autoscale</div>
 | 
			
		||||
                 <div class="value">
 | 
			
		||||
                    {{ config.yAxis.get('autoscale') ? "On" : "Off" }}
 | 
			
		||||
                    {{ config.yAxis.get('autoscale') ? (config.yAxis.get('autoscalePadding') * 100) + "%" : ""}}
 | 
			
		||||
                </div>
 | 
			
		||||
             </div>
 | 
			
		||||
             <div class="inspector-properties"
 | 
			
		||||
                  ng-if="!form.yAxis.autoscale">
 | 
			
		||||
                 <div class="label">Min</div>
 | 
			
		||||
                 <div class="value">{{ config.yAxis.get('range').min }}</div>
 | 
			
		||||
             </div>
 | 
			
		||||
             <div class="inspector-properties"
 | 
			
		||||
                  ng-if="!form.yAxis.autoscale">
 | 
			
		||||
                 <div class="label">Max</div>
 | 
			
		||||
                 <div class="value">{{ config.yAxis.get('range').max }}</div>
 | 
			
		||||
             </div>
 | 
			
		||||
         </li>
 | 
			
		||||
         <li>
 | 
			
		||||
             <em class="t-inspector-part-header">Legend</em>
 | 
			
		||||
             <div class="inspector-properties first">
 | 
			
		||||
                 <div class="label">Position</div>
 | 
			
		||||
                 <div class="value">{{ config.legend.get('position') }}</div>
 | 
			
		||||
             </div>
 | 
			
		||||
             <div class="inspector-properties">
 | 
			
		||||
                 <div class="label">Expand by Default</div>
 | 
			
		||||
                 <div class="value">{{ config.legend.get('expandByDefault') ? "Yes" : "No" }}</div>
 | 
			
		||||
             </div>
 | 
			
		||||
             <div class="inspector-properties">
 | 
			
		||||
                 <div class="label">Show when collapsed:</div>
 | 
			
		||||
                 <div class="value">{{
 | 
			
		||||
                   config.legend.get('valueToShowWhenCollapsed').replace('nearest', '')
 | 
			
		||||
                 }}</div>
 | 
			
		||||
             </div>
 | 
			
		||||
             <div class="inspector-properties">
 | 
			
		||||
                 <div class="label">Show when expanded:</div>
 | 
			
		||||
                 <div class="value comma-list">
 | 
			
		||||
                     <span ng-if="config.legend.get('showTimestampWhenExpanded')">Timestamp</span>
 | 
			
		||||
                     <span ng-if="config.legend.get('showValueWhenExpanded')">Value</span>
 | 
			
		||||
                     <span ng-if="config.legend.get('showMinimumWhenExpanded')">Min</span>
 | 
			
		||||
                     <span ng-if="config.legend.get('showMaximumWhenExpanded')">Max</span>
 | 
			
		||||
                 </div>
 | 
			
		||||
             </div>
 | 
			
		||||
         </li>
 | 
			
		||||
    </ul>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										229
									
								
								src/plugins/plot/res/templates/plot-options-edit.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										229
									
								
								src/plugins/plot/res/templates/plot-options-edit.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,229 @@
 | 
			
		||||
<!--
 | 
			
		||||
 Open MCT Web, Copyright (c) 2014-2015, United States Government
 | 
			
		||||
 as represented by the Administrator of the National Aeronautics and Space
 | 
			
		||||
 Administration. All rights reserved.
 | 
			
		||||
 | 
			
		||||
 Open MCT Web is licensed under the Apache License, Version 2.0 (the
 | 
			
		||||
 "License"); you may not use this file except in compliance with the License.
 | 
			
		||||
 You may obtain a copy of the License at
 | 
			
		||||
 http://www.apache.org/licenses/LICENSE-2.0.
 | 
			
		||||
 | 
			
		||||
 Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
			
		||||
 WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
			
		||||
 License for the specific language governing permissions and limitations
 | 
			
		||||
 under the License.
 | 
			
		||||
 | 
			
		||||
 Open MCT Web includes source code licensed under additional open source
 | 
			
		||||
 licenses. See the Open Source Licenses file (LICENSES.md) included with
 | 
			
		||||
 this source code distribution or the Licensing information page available
 | 
			
		||||
 at runtime from the About dialog for additional information.
 | 
			
		||||
-->
 | 
			
		||||
<div ng-controller="PlotOptionsController"
 | 
			
		||||
     class="flex-elem grows l-inspector-part">
 | 
			
		||||
    <em class="t-inspector-part-header"
 | 
			
		||||
        title="Display properties for this object">
 | 
			
		||||
        Series Options
 | 
			
		||||
    </em>
 | 
			
		||||
    <ul class="first flex-elem grows vscroll">
 | 
			
		||||
        <ul class="tree">
 | 
			
		||||
            <li ng-repeat="series in config.series.models">
 | 
			
		||||
                <span class="tree-item menus-to-left">
 | 
			
		||||
                    <span
 | 
			
		||||
                        class='ui-symbol view-control flex-elem'
 | 
			
		||||
                        ng-class="{ expanded: series.expanded }"
 | 
			
		||||
                        ng-click="series.expanded = !series.expanded">
 | 
			
		||||
                    </span>
 | 
			
		||||
                    <mct-representation
 | 
			
		||||
                        class="rep-object-label"
 | 
			
		||||
                        key="'label'"
 | 
			
		||||
                        mct-object="series.oldObject">
 | 
			
		||||
                    </mct-representation>
 | 
			
		||||
                </span>
 | 
			
		||||
                <div class="inspector-config" ng-show="series.expanded">
 | 
			
		||||
                    <ul>
 | 
			
		||||
                        <li>
 | 
			
		||||
                            <label>Value:</label>
 | 
			
		||||
                            <span class="control">
 | 
			
		||||
                                <div class="select">
 | 
			
		||||
                                    <select ng-model="form.series[$index].yKey">
 | 
			
		||||
                                        <option ng-repeat="option in form.series[$index].yAxisOptions"
 | 
			
		||||
                                                value="{{option.value}}"
 | 
			
		||||
                                                ng-selected="option.value == form.series[$index].yKey">
 | 
			
		||||
                                            {{option.name}}
 | 
			
		||||
                                        </option>
 | 
			
		||||
                                    </select>
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </span>
 | 
			
		||||
                        </li>
 | 
			
		||||
                        <li>
 | 
			
		||||
                            <label>Line Style:</label>
 | 
			
		||||
                            <span class="control">
 | 
			
		||||
                                <div class="select">
 | 
			
		||||
                                    <select ng-model="form.series[$index].interpolate">
 | 
			
		||||
                                        <option value="none">None</option>
 | 
			
		||||
                                        <option value="linear">Linear interpolate</option>
 | 
			
		||||
                                        <option value="stepAfter">Step After</option>
 | 
			
		||||
                                    </select>
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </span>
 | 
			
		||||
                        </li>
 | 
			
		||||
                        <li class="controls-first">
 | 
			
		||||
                            <label>Show Markers</label>
 | 
			
		||||
                            <span class="control"><input type="checkbox" ng-model="form.series[$index].markers"/></span>
 | 
			
		||||
                        </li>
 | 
			
		||||
                        <li class="controls-first">
 | 
			
		||||
                            <label>Show Alarm Markers</label>
 | 
			
		||||
                            <span class="control"><input type="checkbox" ng-model="form.series[$index].alarmMarkers"/></span>
 | 
			
		||||
                        </li>
 | 
			
		||||
                        <li ng-show="form.series[$index].markers || form.series[$index].alarmMarkers">
 | 
			
		||||
                            <label>Marker Size:</label>
 | 
			
		||||
                            <span class="control"><input class="sm" type="text" ng-model="form.series[$index].markerSize"/></span>
 | 
			
		||||
                        </li>
 | 
			
		||||
                        <ul ng-controller="ClickAwayController as toggle" ng-show="form.series[$index].interpolate !== 'none' || form.series[$index].markers">
 | 
			
		||||
                            <li>
 | 
			
		||||
                                <label>Color:</label>
 | 
			
		||||
                                <span class="control">
 | 
			
		||||
                                <div class="s-menu-button" ng-click="toggle.toggle()">
 | 
			
		||||
                                    <span class="color-swatch" ng-style="{ background: series.get('color').asHexString() }">
 | 
			
		||||
                                    </span>
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </span>
 | 
			
		||||
                            </li>
 | 
			
		||||
                            <li class="connects-to-previous l-inline-palette" ng-show="toggle.isActive()">
 | 
			
		||||
                                <div class="l-palette-row" ng-repeat="group in config.series.palette.groups()">
 | 
			
		||||
                                    <div class="l-palette-item s-palette-item"
 | 
			
		||||
                                         ng-repeat="color in group"
 | 
			
		||||
                                         xng-class="{ 'icon-check': series.get('color') === color }"
 | 
			
		||||
                                         ng-style="{ background: color.asHexString() }"
 | 
			
		||||
                                         ng-click="setColor(series, color, config.series.models.indexOf(series))">
 | 
			
		||||
                                    </div>
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </li>
 | 
			
		||||
 | 
			
		||||
                        </ul>
 | 
			
		||||
                    </ul>
 | 
			
		||||
                </div>
 | 
			
		||||
            </li>
 | 
			
		||||
        </ul>
 | 
			
		||||
    </ul>
 | 
			
		||||
    <form class="inspector-config"
 | 
			
		||||
          ng-show="!!config.series.models.length">
 | 
			
		||||
        <em class="t-inspector-part-header"
 | 
			
		||||
            title="Options for plot axes display">
 | 
			
		||||
            Y Axis
 | 
			
		||||
        </em>
 | 
			
		||||
        <ul>
 | 
			
		||||
            <li>
 | 
			
		||||
                <label>Label:</label>
 | 
			
		||||
                <input class="control" type="text" ng-model="form.yAxis.label"/>
 | 
			
		||||
            </li>
 | 
			
		||||
        </ul>
 | 
			
		||||
        <ul ng-show="!(form.yAxis.key == 'enum')">
 | 
			
		||||
            <li class="section-header">Scaling</li>
 | 
			
		||||
            <li class="controls-first">
 | 
			
		||||
                <label>Autoscale</label>
 | 
			
		||||
                <span class="control">
 | 
			
		||||
                    <input type="checkbox" ng-model="form.yAxis.autoscale"/>
 | 
			
		||||
                </span>
 | 
			
		||||
            </li>
 | 
			
		||||
            <li class="form-error"
 | 
			
		||||
                ng-show="!(form.yAxis.key == 'enum') && !form.yAxis.autoscale && validation['form.yAxis.range']">
 | 
			
		||||
                {{ validation['form.yAxis.range'] }}
 | 
			
		||||
            </li>
 | 
			
		||||
            <li ng-show="!form.yAxis.autoscale">
 | 
			
		||||
                <label>Minimum:</label>
 | 
			
		||||
                <span class="control">
 | 
			
		||||
                        <input class="sm" type="text" ng-model="form.yAxis.range.min"/>
 | 
			
		||||
                    </span>
 | 
			
		||||
            </li>
 | 
			
		||||
            <li ng-show="!form.yAxis.autoscale">
 | 
			
		||||
                <label>Maximum:</label>
 | 
			
		||||
                <span class="control">
 | 
			
		||||
                        <input class="sm" type="text" ng-model="form.yAxis.range.max"/>
 | 
			
		||||
                    </span>
 | 
			
		||||
            </li>
 | 
			
		||||
            <li ng-show="form.yAxis.autoscale">
 | 
			
		||||
                <label>Padding:</label>
 | 
			
		||||
                <span class="control">
 | 
			
		||||
                    <input class="sm" type="text" ng-model="form.yAxis.autoscalePadding"/>
 | 
			
		||||
                </span>
 | 
			
		||||
            </li>
 | 
			
		||||
        </ul>
 | 
			
		||||
 | 
			
		||||
        <em class="t-inspector-part-header"
 | 
			
		||||
            title="Options for legend display">
 | 
			
		||||
            Legend
 | 
			
		||||
        </em>
 | 
			
		||||
 | 
			
		||||
        <ul>
 | 
			
		||||
            <li>
 | 
			
		||||
                <label>Position:</label>
 | 
			
		||||
                <span class="control">
 | 
			
		||||
                    <div class="select">
 | 
			
		||||
                        <select ng-model="form.legend.position">
 | 
			
		||||
                            <option value="hidden">Hidden</option>
 | 
			
		||||
                            <option value="top">Top</option>
 | 
			
		||||
                            <option value="right">Right</option>
 | 
			
		||||
                            <option value="bottom">Bottom</option>
 | 
			
		||||
                            <option value="left">Left</option>
 | 
			
		||||
                        </select>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </span>
 | 
			
		||||
            </li>
 | 
			
		||||
            <li class="controls-first">
 | 
			
		||||
                <label>Expand by default</label>
 | 
			
		||||
                <span class="control">
 | 
			
		||||
                    <input type="checkbox" ng-model="form.legend.expandByDefault"/>
 | 
			
		||||
                </span>
 | 
			
		||||
            </li>
 | 
			
		||||
            <li class="controls-under">
 | 
			
		||||
                <label>Show when collapsed:</label>
 | 
			
		||||
                <span class="control">
 | 
			
		||||
                    <div class="select">
 | 
			
		||||
                        <select ng-model="form.legend.valueToShowWhenCollapsed">
 | 
			
		||||
                            <option value="none">None</option>
 | 
			
		||||
                            <option value="nearestTimestamp">Nearest Timestamp</option>
 | 
			
		||||
                            <option value="nearestValue">Nearest Value</option>
 | 
			
		||||
                            <option value="min">Minimum</option>
 | 
			
		||||
                            <option value="max">Maximum</option>
 | 
			
		||||
                        </select>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </span>
 | 
			
		||||
            </li>
 | 
			
		||||
            <li class="controls-under">
 | 
			
		||||
                <ul>
 | 
			
		||||
                    <li><label>Show when expanded:</label></li>
 | 
			
		||||
                    <li class="controls-first">
 | 
			
		||||
                      <label>Nearest Timestamp</label>
 | 
			
		||||
                      <span class="control">
 | 
			
		||||
                        <input type="checkbox"
 | 
			
		||||
                          ng-model="form.legend.showTimestampWhenExpanded"/>
 | 
			
		||||
                      </span>
 | 
			
		||||
                    </li>
 | 
			
		||||
                    <li class="controls-first">
 | 
			
		||||
                      <label>Nearest Value</label>
 | 
			
		||||
                      <span class="control">
 | 
			
		||||
                        <input type="checkbox"
 | 
			
		||||
                               ng-model="form.legend.showValueWhenExpanded"/>
 | 
			
		||||
                      </span>
 | 
			
		||||
                    </li>
 | 
			
		||||
                    <li class="controls-first">
 | 
			
		||||
                      <label>Minimum</label>
 | 
			
		||||
                      <span class="control">
 | 
			
		||||
                        <input type="checkbox"
 | 
			
		||||
                               ng-model="form.legend.showMinimumWhenExpanded"/>
 | 
			
		||||
                      </span>
 | 
			
		||||
                    </li>
 | 
			
		||||
                    <li class="controls-first">
 | 
			
		||||
                      <label>Maximum</label>
 | 
			
		||||
                      <span class="control">
 | 
			
		||||
                        <input type="checkbox"
 | 
			
		||||
                               ng-model="form.legend.showMaximumWhenExpanded"/>
 | 
			
		||||
                      </span>
 | 
			
		||||
                    </li>
 | 
			
		||||
                </ul>
 | 
			
		||||
            </li>
 | 
			
		||||
        </ul>
 | 
			
		||||
    </form>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										10
									
								
								src/plugins/plot/res/templates/plot-options.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/plugins/plot/res/templates/plot-options.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
<div ng-if="domainObject.getCapability('editor').inEditContext()">
 | 
			
		||||
    <mct-representation key="'plot-options-edit'"
 | 
			
		||||
        mct-object="domainObject">
 | 
			
		||||
    </mct-representation>
 | 
			
		||||
</div>
 | 
			
		||||
<div ng-if="!domainObject.getCapability('editor').inEditContext()">
 | 
			
		||||
    <mct-representation key="'plot-options-browse'"
 | 
			
		||||
        mct-object="domainObject">
 | 
			
		||||
    </mct-representation>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										29
									
								
								src/plugins/plot/res/templates/plot.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/plugins/plot/res/templates/plot.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
<span ng-controller="PlotController as controller"
 | 
			
		||||
    class="abs holder holder-plot has-control-bar"
 | 
			
		||||
    ng-class="{
 | 
			
		||||
        'loading': !!pending
 | 
			
		||||
    }"
 | 
			
		||||
    >
 | 
			
		||||
    <div class="l-control-bar" ng-show="!controller.hideExportButtons">
 | 
			
		||||
         <span class="l-btn-set">
 | 
			
		||||
            <a class="s-button t-export labeled icon-download"
 | 
			
		||||
               ng-click="controller.exportPNG()"
 | 
			
		||||
               title="Export This View's Data as PNG">
 | 
			
		||||
                PNG
 | 
			
		||||
            </a>
 | 
			
		||||
            <a class="s-button t-export labeled"
 | 
			
		||||
               ng-click="controller.exportJPG()"
 | 
			
		||||
               title="Export This View's Data as JPG">
 | 
			
		||||
                JPG
 | 
			
		||||
            </a>
 | 
			
		||||
        </span>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="l-view-section">
 | 
			
		||||
        <mct-plot config="controller.config"
 | 
			
		||||
                  series="series"
 | 
			
		||||
                  the-y-axis="yAxis"
 | 
			
		||||
                  the-x-axis="xAxis">
 | 
			
		||||
                  </mct-plot>
 | 
			
		||||
    </div>
 | 
			
		||||
</span>
 | 
			
		||||
							
								
								
									
										32
									
								
								src/plugins/plot/res/templates/stacked-plot.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/plugins/plot/res/templates/stacked-plot.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
<span ng-controller="StackedPlotController as stackedPlot"
 | 
			
		||||
      class="abs holder holder-plot has-control-bar t-plot-stacked"
 | 
			
		||||
      ng-class="{
 | 
			
		||||
          'loading': !!currentRequest.pending
 | 
			
		||||
      }">
 | 
			
		||||
 | 
			
		||||
    <div class="l-control-bar" ng-show="!stackedPlot.hideExportButtons">
 | 
			
		||||
       <span class="l-btn-set">
 | 
			
		||||
          <a class="s-button t-export labeled icon-download"
 | 
			
		||||
             ng-click="stackedPlot.exportPNG()"
 | 
			
		||||
             title="Export This View's Data as PNG">
 | 
			
		||||
              PNG
 | 
			
		||||
          </a>
 | 
			
		||||
          <a class="s-button t-export labeled"
 | 
			
		||||
             ng-click="stackedPlot.exportJPG()"
 | 
			
		||||
             title="Export This View's Data as JPG">
 | 
			
		||||
              JPG
 | 
			
		||||
          </a>
 | 
			
		||||
      </span>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="l-view-section">
 | 
			
		||||
        <div class="gl-plot child-frame"
 | 
			
		||||
            ng-repeat="telemetryObject in telemetryObjects"
 | 
			
		||||
            ng-class="{
 | 
			
		||||
                's-status-timeconductor-unsynced': telemetryObject
 | 
			
		||||
                    .getCapability('status')
 | 
			
		||||
                    .get('timeconductor-unsynced')
 | 
			
		||||
            }">
 | 
			
		||||
            <mct-overlay-plot domain-object="telemetryObject"></mct-overlay-plot>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</span>
 | 
			
		||||
@@ -54,7 +54,7 @@ define(
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        PlotViewPolicy.prototype.allow = function (view, domainObject) {
 | 
			
		||||
            if (view.key === 'plot') {
 | 
			
		||||
            if (view.key === 'plot-single') {
 | 
			
		||||
                return this.hasNumericTelemetry(domainObject);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										57
									
								
								src/plugins/plot/src/chart/MCTChartAlarmPointSet.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/plugins/plot/src/chart/MCTChartAlarmPointSet.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
/*global define,Float32Array*/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    '../lib/extend',
 | 
			
		||||
    '../lib/eventHelpers'
 | 
			
		||||
], function (
 | 
			
		||||
    extend,
 | 
			
		||||
    eventHelpers
 | 
			
		||||
) {
 | 
			
		||||
    'use strict';
 | 
			
		||||
 | 
			
		||||
    function MCTChartAlarmPointSet(series, chart, offset) {
 | 
			
		||||
        this.series = series;
 | 
			
		||||
        this.chart = chart;
 | 
			
		||||
        this.offset = offset;
 | 
			
		||||
        this.points = [];
 | 
			
		||||
 | 
			
		||||
        this.listenTo(series, 'add', this.append, this);
 | 
			
		||||
        this.listenTo(series, 'remove', this.remove, this);
 | 
			
		||||
        this.listenTo(series, 'reset', this.reset, this);
 | 
			
		||||
        this.listenTo(series, 'destroy', this.destroy, this);
 | 
			
		||||
        series.data.forEach(function (point, index) {
 | 
			
		||||
            this.append(point, index, series)
 | 
			
		||||
        }, this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    MCTChartAlarmPointSet.prototype.append = function (datum) {
 | 
			
		||||
        if (datum._limit) {
 | 
			
		||||
            this.points.push({
 | 
			
		||||
                x: this.offset.xVal(datum, this.series),
 | 
			
		||||
                y: this.offset.yVal(datum, this.series),
 | 
			
		||||
                datum: datum
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartAlarmPointSet.prototype.remove = function (datum) {
 | 
			
		||||
        this.points = this.points.filter(function (p) {
 | 
			
		||||
            return p.datum !== datum;
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartAlarmPointSet.prototype.reset = function () {
 | 
			
		||||
        this.points = [];
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartAlarmPointSet.prototype.destroy = function () {
 | 
			
		||||
        this.stopListening();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    eventHelpers.extend(MCTChartAlarmPointSet.prototype);
 | 
			
		||||
 | 
			
		||||
    return MCTChartAlarmPointSet;
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										381
									
								
								src/plugins/plot/src/chart/MCTChartController.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										381
									
								
								src/plugins/plot/src/chart/MCTChartController.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,381 @@
 | 
			
		||||
/*global define,requestAnimationFrame,Float32Array*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Module defining MCTChart. Created by vwoeltje on 11/12/14.
 | 
			
		||||
 */
 | 
			
		||||
define([
 | 
			
		||||
    './MCTChartLineLinear',
 | 
			
		||||
    './MCTChartLineStepAfter',
 | 
			
		||||
    './MCTChartPointSet',
 | 
			
		||||
    './MCTChartAlarmPointSet',
 | 
			
		||||
    '../draw/DrawLoader',
 | 
			
		||||
    '../lib/eventHelpers',
 | 
			
		||||
    'lodash'
 | 
			
		||||
],
 | 
			
		||||
function (
 | 
			
		||||
    MCTChartLineLinear,
 | 
			
		||||
    MCTChartLineStepAfter,
 | 
			
		||||
    MCTChartPointSet,
 | 
			
		||||
    MCTChartAlarmPointSet,
 | 
			
		||||
    DrawLoader,
 | 
			
		||||
    eventHelpers,
 | 
			
		||||
    _
 | 
			
		||||
) {
 | 
			
		||||
    'use strict';
 | 
			
		||||
 | 
			
		||||
    var MARKER_SIZE = 6.0,
 | 
			
		||||
        HIGHLIGHT_SIZE = MARKER_SIZE * 2.0;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Offsetter adjusts x and y values by a fixed amount,
 | 
			
		||||
     * generally increasing the precision of the 32 bit float representation
 | 
			
		||||
     * required for plotting.
 | 
			
		||||
     *
 | 
			
		||||
     * @constructor
 | 
			
		||||
     */
 | 
			
		||||
    function MCTChartController($scope) {
 | 
			
		||||
        this.$scope = $scope;
 | 
			
		||||
        this.isDestroyed = false;
 | 
			
		||||
        this.lines = [];
 | 
			
		||||
        this.pointSets = [];
 | 
			
		||||
        this.alarmSets = [];
 | 
			
		||||
        this.offset = {};
 | 
			
		||||
        this.config = $scope.config;
 | 
			
		||||
        this.listenTo(this.$scope, '$destoy', this.destroy, this);
 | 
			
		||||
        this.draw = this.draw.bind(this);
 | 
			
		||||
        this.scheduleDraw = this.scheduleDraw.bind(this);
 | 
			
		||||
        this.seriesElements = new WeakMap();
 | 
			
		||||
 | 
			
		||||
        this.listenTo(this.config.series, 'add', this.onSeriesAdd, this);
 | 
			
		||||
        this.listenTo(this.config.series, 'remove', this.onSeriesRemove, this);
 | 
			
		||||
        this.listenTo(this.config.yAxis, 'change:key', this.clearOffset, this);
 | 
			
		||||
        this.listenTo(this.config.xAxis, 'change:key', this.clearOffset, this);
 | 
			
		||||
        this.listenTo(this.config.yAxis, 'change', this.scheduleDraw);
 | 
			
		||||
        this.listenTo(this.config.xAxis, 'change', this.scheduleDraw);
 | 
			
		||||
        this.$scope.$watch('highlights', this.scheduleDraw);
 | 
			
		||||
        this.$scope.$watch('rectangles', this.scheduleDraw);
 | 
			
		||||
        this.config.series.forEach(this.onSeriesAdd, this);
 | 
			
		||||
        window.chart = this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    eventHelpers.extend(MCTChartController.prototype);
 | 
			
		||||
 | 
			
		||||
    MCTChartController.$inject = ['$scope'];
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.onSeriesAdd = function (series) {
 | 
			
		||||
        this.listenTo(series, 'change:interpolate', this.changeInterpolate, this);
 | 
			
		||||
        this.listenTo(series, 'change:markers', this.changeMarkers, this);
 | 
			
		||||
        this.listenTo(series, 'change:alarmMarkers', this.changeAlarmMarkers, this);
 | 
			
		||||
        this.listenTo(series, 'change', this.scheduleDraw);
 | 
			
		||||
        this.listenTo(series, 'add', this.scheduleDraw);
 | 
			
		||||
        this.makeChartElement(series);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.changeInterpolate = function (mode, o, series) {
 | 
			
		||||
        if (mode === o) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        var elements = this.seriesElements.get(series);
 | 
			
		||||
        elements.lines.forEach(function (line) {
 | 
			
		||||
            this.lines.splice(this.lines.indexOf(line), 1);
 | 
			
		||||
            line.destroy();
 | 
			
		||||
        }, this);
 | 
			
		||||
        elements.lines = [];
 | 
			
		||||
 | 
			
		||||
        var newLine = this.lineForSeries(series);
 | 
			
		||||
        if (newLine) {
 | 
			
		||||
            elements.lines.push(newLine);
 | 
			
		||||
            this.lines.push(newLine);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.changeAlarmMarkers = function (mode, o, series) {
 | 
			
		||||
        if (mode === o) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        var elements = this.seriesElements.get(series);
 | 
			
		||||
        if (elements.alarmSet) {
 | 
			
		||||
            elements.alarmSet.destroy();
 | 
			
		||||
            this.alarmSets.splice(this.alarmSets.indexOf(elements.alarmSet), 1);
 | 
			
		||||
        }
 | 
			
		||||
        elements.alarmSet = this.alarmPointSetForSeries(series);
 | 
			
		||||
        if (elements.alarmSet) {
 | 
			
		||||
            this.alarmSets.push(elements.alarmSet);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.changeMarkers = function (mode, o, series) {
 | 
			
		||||
        if (mode === o) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        var elements = this.seriesElements.get(series);
 | 
			
		||||
        elements.pointSets.forEach(function (pointSet) {
 | 
			
		||||
            this.pointSets.splice(this.pointSets.indexOf(pointSet), 1);
 | 
			
		||||
            pointSet.destroy();
 | 
			
		||||
        }, this);
 | 
			
		||||
        elements.pointSets = [];
 | 
			
		||||
 | 
			
		||||
        var pointSet = this.pointSetForSeries(series);
 | 
			
		||||
        if (pointSet) {
 | 
			
		||||
            elements.pointSets.push(pointSet);
 | 
			
		||||
            this.pointSets.push(pointSet);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.onSeriesRemove = function (series) {
 | 
			
		||||
        this.stopListening(series);
 | 
			
		||||
        this.removeChartElement(series);
 | 
			
		||||
        this.scheduleDraw();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.destroy = function () {
 | 
			
		||||
        this.isDestroyed = true;
 | 
			
		||||
        this.stopListening();
 | 
			
		||||
        _.invoke(this.lines, 'destroy');
 | 
			
		||||
        DrawLoader.releaseDrawAPI(this.drawAPI);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.clearOffset = function () {
 | 
			
		||||
        delete this.offset.x;
 | 
			
		||||
        delete this.offset.y;
 | 
			
		||||
        delete this.offset.xVal;
 | 
			
		||||
        delete this.offset.yVal;
 | 
			
		||||
        delete this.offset.xKey;
 | 
			
		||||
        delete this.offset.yKey;
 | 
			
		||||
        this.lines.forEach(function (line) {
 | 
			
		||||
            line.reset();
 | 
			
		||||
        });
 | 
			
		||||
        this.pointSets.forEach(function (pointSet) {
 | 
			
		||||
            pointSet.reset();
 | 
			
		||||
        })
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.setOffset = function (point, index, series) {
 | 
			
		||||
        if (this.offset.x && this.offset.y) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var offsets = {
 | 
			
		||||
            x: series.getXVal(point),
 | 
			
		||||
            y: series.getYVal(point)
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        this.offset.x = function (x) {
 | 
			
		||||
            return x - offsets.x;
 | 
			
		||||
        }.bind(this);
 | 
			
		||||
        this.offset.y = function (y) {
 | 
			
		||||
            return y - offsets.y;
 | 
			
		||||
        }.bind(this);
 | 
			
		||||
        this.offset.xVal = function (point, pSeries) {
 | 
			
		||||
            return this.offset.x(pSeries.getXVal(point));
 | 
			
		||||
        }.bind(this);
 | 
			
		||||
        this.offset.yVal = function (point, pSeries) {
 | 
			
		||||
            return this.offset.y(pSeries.getYVal(point));
 | 
			
		||||
        }.bind(this);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.initializeCanvas = function (canvas, overlay) {
 | 
			
		||||
        this.canvas = canvas;
 | 
			
		||||
        this.overlay = overlay;
 | 
			
		||||
        this.drawAPI = DrawLoader.getDrawAPI(canvas, overlay);
 | 
			
		||||
        return !!this.drawAPI;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.removeChartElement = function (series) {
 | 
			
		||||
        var elements = this.seriesElements.get(series);
 | 
			
		||||
 | 
			
		||||
        elements.lines.forEach(function (line) {
 | 
			
		||||
            this.lines.splice(this.lines.indexOf(line), 1);
 | 
			
		||||
            line.destroy();
 | 
			
		||||
        }, this);
 | 
			
		||||
        elements.pointSets.forEach(function (pointSet) {
 | 
			
		||||
            this.pointSets.splice(this.pointSets.indexOf(pointSet), 1);
 | 
			
		||||
            pointSet.destroy();
 | 
			
		||||
        }, this);
 | 
			
		||||
        this.seriesElements.delete(series);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.lineForSeries = function (series) {
 | 
			
		||||
        if (series.get('interpolate') === 'linear') {
 | 
			
		||||
            return new MCTChartLineLinear(
 | 
			
		||||
                series,
 | 
			
		||||
                this,
 | 
			
		||||
                this.offset
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        if (series.get('interpolate') === 'stepAfter') {
 | 
			
		||||
            return new MCTChartLineStepAfter(
 | 
			
		||||
                series,
 | 
			
		||||
                this,
 | 
			
		||||
                this.offset
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.pointSetForSeries = function (series) {
 | 
			
		||||
        if (series.get('markers')) {
 | 
			
		||||
            return new MCTChartPointSet(
 | 
			
		||||
                series,
 | 
			
		||||
                this,
 | 
			
		||||
                this.offset
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.alarmPointSetForSeries = function (series) {
 | 
			
		||||
        if (series.get('alarmMarkers')) {
 | 
			
		||||
            return new MCTChartAlarmPointSet(
 | 
			
		||||
                series,
 | 
			
		||||
                this,
 | 
			
		||||
                this.offset
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.makeChartElement = function (series) {
 | 
			
		||||
        var elements = {
 | 
			
		||||
            lines: [],
 | 
			
		||||
            pointSets: []
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        var line = this.lineForSeries(series);
 | 
			
		||||
        if (line) {
 | 
			
		||||
            elements.lines.push(line);
 | 
			
		||||
            this.lines.push(line);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var pointSet = this.pointSetForSeries(series);
 | 
			
		||||
        if (pointSet) {
 | 
			
		||||
            elements.pointSets.push(pointSet);
 | 
			
		||||
            this.pointSets.push(pointSet);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        elements.alarmSet = this.alarmPointSetForSeries(series);
 | 
			
		||||
        if (elements.alarmSet) {
 | 
			
		||||
            this.alarmSets.push(elements.alarmSet);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.seriesElements.set(series, elements);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.canDraw = function () {
 | 
			
		||||
        if (!this.offset.x || !this.offset.y) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.scheduleDraw = function () {
 | 
			
		||||
        if (!this.drawScheduled) {
 | 
			
		||||
            requestAnimationFrame(this.draw);
 | 
			
		||||
            this.drawScheduled = true;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.draw = function () {
 | 
			
		||||
        this.drawScheduled = false;
 | 
			
		||||
        if (this.isDestroyed) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        this.drawAPI.clear();
 | 
			
		||||
        if (this.canDraw()) {
 | 
			
		||||
            this.updateViewport();
 | 
			
		||||
            this.drawSeries();
 | 
			
		||||
            this.drawRectangles();
 | 
			
		||||
            this.drawHighlights();
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.updateViewport = function () {
 | 
			
		||||
        var xRange = this.config.xAxis.get('displayRange'),
 | 
			
		||||
            yRange = this.config.yAxis.get('displayRange');
 | 
			
		||||
 | 
			
		||||
        if (!xRange || !yRange) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var dimensions = [
 | 
			
		||||
                xRange.max - xRange.min,
 | 
			
		||||
                yRange.max - yRange.min
 | 
			
		||||
            ],
 | 
			
		||||
            origin = [
 | 
			
		||||
                this.offset.x(xRange.min),
 | 
			
		||||
                this.offset.y(yRange.min)
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
        this.drawAPI.setDimensions(
 | 
			
		||||
            dimensions,
 | 
			
		||||
            origin
 | 
			
		||||
        );
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.drawSeries = function () {
 | 
			
		||||
        this.lines.forEach(this.drawLine, this);
 | 
			
		||||
        this.pointSets.forEach(this.drawPoints, this);
 | 
			
		||||
        this.alarmSets.forEach(this.drawAlarmPoints, this);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.drawAlarmPoints = function (alarmSet) {
 | 
			
		||||
        this.drawAPI.drawLimitPoints(
 | 
			
		||||
            alarmSet.points,
 | 
			
		||||
            alarmSet.series.get('color').asRGBAArray(),
 | 
			
		||||
            alarmSet.series.get('markerSize')
 | 
			
		||||
        );
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.drawPoints = function (chartElement) {
 | 
			
		||||
        this.drawAPI.drawPoints(
 | 
			
		||||
            chartElement.getBuffer(),
 | 
			
		||||
            chartElement.color().asRGBAArray(),
 | 
			
		||||
            chartElement.count,
 | 
			
		||||
            chartElement.series.get('markerSize')
 | 
			
		||||
        );
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.drawLine = function (chartElement) {
 | 
			
		||||
        this.drawAPI.drawLine(
 | 
			
		||||
            chartElement.getBuffer(),
 | 
			
		||||
            chartElement.color().asRGBAArray(),
 | 
			
		||||
            chartElement.count
 | 
			
		||||
        );
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.drawHighlights = function () {
 | 
			
		||||
        if (this.$scope.highlights && this.$scope.highlights.length) {
 | 
			
		||||
            this.$scope.highlights.forEach(this.drawHighlight, this);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.drawHighlight = function (highlight) {
 | 
			
		||||
        var points = new Float32Array([
 | 
			
		||||
                this.offset.xVal(highlight.point, highlight.series),
 | 
			
		||||
                this.offset.yVal(highlight.point, highlight.series)
 | 
			
		||||
            ]),
 | 
			
		||||
            color = highlight.series.get('color').asRGBAArray(),
 | 
			
		||||
            pointCount = 1;
 | 
			
		||||
 | 
			
		||||
        this.drawAPI.drawPoints(points, color, pointCount, HIGHLIGHT_SIZE);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.drawRectangles = function () {
 | 
			
		||||
        if (this.$scope.rectangles) {
 | 
			
		||||
            this.$scope.rectangles.forEach(this.drawRectangle, this);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MCTChartController.prototype.drawRectangle = function (rect) {
 | 
			
		||||
        this.drawAPI.drawSquare(
 | 
			
		||||
            [
 | 
			
		||||
                this.offset.x(rect.start.x),
 | 
			
		||||
                this.offset.y(rect.start.y)
 | 
			
		||||
            ],
 | 
			
		||||
            [
 | 
			
		||||
                this.offset.x(rect.end.x),
 | 
			
		||||
                this.offset.y(rect.end.y)
 | 
			
		||||
            ],
 | 
			
		||||
            rect.color
 | 
			
		||||
        );
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return MCTChartController;
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										47
									
								
								src/plugins/plot/src/chart/MCTChartDirective.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/plugins/plot/src/chart/MCTChartDirective.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
/*global define,requestAnimationFrame,Float32Array*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Module defining MCTChart. Created by vwoeltje on 11/12/14.
 | 
			
		||||
 */
 | 
			
		||||
define([
 | 
			
		||||
    './MCTChartController'
 | 
			
		||||
], function (
 | 
			
		||||
    MCTChartController
 | 
			
		||||
) {
 | 
			
		||||
    'use strict';
 | 
			
		||||
 | 
			
		||||
    var TEMPLATE = "<canvas style='position: absolute; background: none; width: 100%; height: 100%;'></canvas>";
 | 
			
		||||
    TEMPLATE += TEMPLATE;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * MCTChart draws charts utilizing a drawAPI.
 | 
			
		||||
     *
 | 
			
		||||
     * @constructor
 | 
			
		||||
     */
 | 
			
		||||
    function MCTChart() {
 | 
			
		||||
        return {
 | 
			
		||||
            restrict: "E",
 | 
			
		||||
            template: TEMPLATE,
 | 
			
		||||
            link: function ($scope, $element, attrs, ctrl) {
 | 
			
		||||
                var mainCanvas = $element.find("canvas")[1];
 | 
			
		||||
                var overlayCanvas = $element.find("canvas")[0];
 | 
			
		||||
 | 
			
		||||
                if (ctrl.initializeCanvas(mainCanvas, overlayCanvas)) {
 | 
			
		||||
                    ctrl.draw();
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            controller: MCTChartController,
 | 
			
		||||
            scope: {
 | 
			
		||||
                config: "=",
 | 
			
		||||
                draw: "=" ,
 | 
			
		||||
                rectangles: "=",
 | 
			
		||||
                series: "=",
 | 
			
		||||
                xAxis: "=theXAxis",
 | 
			
		||||
                yAxis: "=theYAxis",
 | 
			
		||||
                highlights: "=?"
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return MCTChart;
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										20
									
								
								src/plugins/plot/src/chart/MCTChartLineLinear.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/plugins/plot/src/chart/MCTChartLineLinear.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
/*global define*/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    './MCTChartSeriesElement'
 | 
			
		||||
], function (
 | 
			
		||||
    MCTChartSeriesElement
 | 
			
		||||
) {
 | 
			
		||||
    'use strict';
 | 
			
		||||
 | 
			
		||||
    var MCTChartLineLinear = MCTChartSeriesElement.extend({
 | 
			
		||||
        addPoint: function (point, start, count) {
 | 
			
		||||
            this.buffer[start] = point.x;
 | 
			
		||||
            this.buffer[start + 1] = point.y;
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return MCTChartLineLinear;
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										58
									
								
								src/plugins/plot/src/chart/MCTChartLineStepAfter.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/plugins/plot/src/chart/MCTChartLineStepAfter.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
/*global define*/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    './MCTChartSeriesElement'
 | 
			
		||||
], function (
 | 
			
		||||
    MCTChartSeriesElement
 | 
			
		||||
) {
 | 
			
		||||
    'use strict';
 | 
			
		||||
 | 
			
		||||
    var MCTChartLineStepAfter = MCTChartSeriesElement.extend({
 | 
			
		||||
        removePoint: function (point, index, count) {
 | 
			
		||||
            if (index > 0 && index / 2 < this.count) {
 | 
			
		||||
                this.buffer[index + 1] = this.buffer[index - 1];
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        vertexCountForPointAtIndex: function (index) {
 | 
			
		||||
            if (index === 0 && this.count === 0) {
 | 
			
		||||
                return 2;
 | 
			
		||||
            }
 | 
			
		||||
            return 4;
 | 
			
		||||
        },
 | 
			
		||||
        startIndexForPointAtIndex: function (index) {
 | 
			
		||||
            if (index === 0) {
 | 
			
		||||
                return 0;
 | 
			
		||||
            }
 | 
			
		||||
            return 2 + ((index - 1) * 4);
 | 
			
		||||
        },
 | 
			
		||||
        addPoint: function (point, start, count) {
 | 
			
		||||
            if (start === 0 && this.count === 0) {
 | 
			
		||||
                // First point is easy.
 | 
			
		||||
                this.buffer[start] = point.x;
 | 
			
		||||
                this.buffer[start + 1] = point.y; // one point
 | 
			
		||||
            } else if (start === 0 && this.count > 0) {
 | 
			
		||||
                // Unshifting requires adding an extra point.
 | 
			
		||||
                this.buffer[start] = point.x;
 | 
			
		||||
                this.buffer[start + 1] = point.y;
 | 
			
		||||
                this.buffer[start + 2] = this.buffer[start + 4];
 | 
			
		||||
                this.buffer[start + 3] = point.y;
 | 
			
		||||
            } else {
 | 
			
		||||
                // Appending anywhere in line, insert standard two points.
 | 
			
		||||
                this.buffer[start] = point.x;
 | 
			
		||||
                this.buffer[start + 1] = this.buffer[start - 1];
 | 
			
		||||
                this.buffer[start + 2] = point.x;
 | 
			
		||||
                this.buffer[start + 3] = point.y;
 | 
			
		||||
 | 
			
		||||
                if (start < this.count * 2) {
 | 
			
		||||
                    // Insert into the middle, need to update the following
 | 
			
		||||
                    // point.
 | 
			
		||||
                    this.buffer[start + 5] = point.y;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return MCTChartLineStepAfter;
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										20
									
								
								src/plugins/plot/src/chart/MCTChartPointSet.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/plugins/plot/src/chart/MCTChartPointSet.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
/*global define*/
 | 
			
		||||
 | 
			
		||||
define([
 | 
			
		||||
    './MCTChartSeriesElement'
 | 
			
		||||
], function (
 | 
			
		||||
    MCTChartSeriesElement
 | 
			
		||||
) {
 | 
			
		||||
    'use strict';
 | 
			
		||||
 | 
			
		||||
    var MCTChartPointSet = MCTChartSeriesElement.extend({
 | 
			
		||||
        addPoint: function (point, start, count) {
 | 
			
		||||
            this.buffer[start] = point.x;
 | 
			
		||||
            this.buffer[start + 1] = point.y;
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return MCTChartPointSet;
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user