Compare commits
	
		
			29 Commits
		
	
	
		
			v1.2-RC5
			...
			feature/ti
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					a6ac54383d | ||
| 
						 | 
					490f25add8 | ||
| 
						 | 
					694255db6b | ||
| 
						 | 
					6910ae0a2b | ||
| 
						 | 
					b3bf7f2db1 | ||
| 
						 | 
					348ba9085b | ||
| 
						 | 
					9d6a5e2e17 | ||
| 
						 | 
					5cb0e2e885 | ||
| 
						 | 
					ee277f3547 | ||
| 
						 | 
					bf77d240c7 | ||
| 
						 | 
					684a3d2807 | ||
| 
						 | 
					27e01ef13f | ||
| 
						 | 
					4a2b1640e9 | ||
| 
						 | 
					38cb92b203 | ||
| 
						 | 
					0792ae0ae4 | ||
| 
						 | 
					d462f5d763 | ||
| 
						 | 
					cb8e97dc1c | ||
| 
						 | 
					aed3c19edd | ||
| 
						 | 
					a19c5cfd52 | ||
| 
						 | 
					03e5241041 | ||
| 
						 | 
					29ed251685 | ||
| 
						 | 
					60433a12b8 | ||
| 
						 | 
					69b8dd6c37 | ||
| 
						 | 
					e6c78c1826 | ||
| 
						 | 
					a1657817dc | ||
| 
						 | 
					29538e6e78 | ||
| 
						 | 
					68e9152d6a | ||
| 
						 | 
					02b2b47411 | ||
| 
						 | 
					70624c2c5c | 
							
								
								
									
										20
									
								
								index.html
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								index.html
									
									
									
									
									
								
							@@ -48,6 +48,7 @@
 | 
			
		||||
        openmct.install(openmct.plugins.Generator());
 | 
			
		||||
        openmct.install(openmct.plugins.ExampleImagery());
 | 
			
		||||
        openmct.install(openmct.plugins.UTCTimeSystem());
 | 
			
		||||
        openmct.install(openmct.plugins.LocalTimeSystem());
 | 
			
		||||
        openmct.install(openmct.plugins.AutoflowView({
 | 
			
		||||
            type: "telemetry.panel"
 | 
			
		||||
        }));
 | 
			
		||||
@@ -72,7 +73,24 @@
 | 
			
		||||
                        start: - THIRTY_MINUTES,
 | 
			
		||||
                        end: FIVE_MINUTES
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    name: "Fixed",
 | 
			
		||||
                    timeSystem: 'local',
 | 
			
		||||
                    bounds: {
 | 
			
		||||
                        start: Date.now() - THIRTY_MINUTES,
 | 
			
		||||
                        end: Date.now()
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    name: "Realtime",
 | 
			
		||||
                    timeSystem: 'local',
 | 
			
		||||
                    clock: 'local',
 | 
			
		||||
                    clockOffsets: {
 | 
			
		||||
                        start: - THIRTY_MINUTES,
 | 
			
		||||
                        end: FIVE_MINUTES
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
            ]
 | 
			
		||||
        }));
 | 
			
		||||
        openmct.install(openmct.plugins.SummaryWidget());
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,7 @@
 | 
			
		||||
    "css-loader": "^1.0.0",
 | 
			
		||||
    "d3-array": "1.2.x",
 | 
			
		||||
    "d3-axis": "1.0.x",
 | 
			
		||||
    "d3-brush": "^1.1.3",
 | 
			
		||||
    "d3-collection": "1.0.x",
 | 
			
		||||
    "d3-color": "1.0.x",
 | 
			
		||||
    "d3-format": "1.2.x",
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@ define([], function () {
 | 
			
		||||
        this.timeFormat = 'local-format';
 | 
			
		||||
        this.durationFormat = 'duration';
 | 
			
		||||
 | 
			
		||||
        this.isUTCBased = false;
 | 
			
		||||
        this.isUTCBased = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return LocalTimeSystem;
 | 
			
		||||
 
 | 
			
		||||
@@ -88,15 +88,24 @@
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
                <conductor-axis
 | 
			
		||||
                        class="c-conductor__ticks"
 | 
			
		||||
                        :bounds="rawBounds"
 | 
			
		||||
                        @panAxis="setViewFromBounds"></conductor-axis>
 | 
			
		||||
                    class="c-conductor__ticks"
 | 
			
		||||
                    :bounds="rawBounds"
 | 
			
		||||
                    :isFixed="isFixed"
 | 
			
		||||
                    @panAxis="setViewFromBounds"
 | 
			
		||||
                    @zoomAxis="setViewFromBounds"
 | 
			
		||||
                ></conductor-axis>
 | 
			
		||||
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="c-conductor__controls">
 | 
			
		||||
                <!-- Mode, time system menu buttons and duration slider -->
 | 
			
		||||
                <ConductorMode class="c-conductor__mode-select"></ConductorMode>
 | 
			
		||||
                <ConductorTimeSystem class="c-conductor__time-system-select"></ConductorTimeSystem>
 | 
			
		||||
                <ConductorHistory
 | 
			
		||||
                    v-if="isFixed"
 | 
			
		||||
                    class="c-conductor__history-select"
 | 
			
		||||
                    :bounds="bounds"
 | 
			
		||||
                    :time-system="timeSystem"
 | 
			
		||||
                    @select-timespan="setViewFromBounds"
 | 
			
		||||
                ></ConductorHistory>
 | 
			
		||||
            </div>
 | 
			
		||||
            <input type="submit" class="invisible">
 | 
			
		||||
        </form>
 | 
			
		||||
@@ -294,6 +303,7 @@ import ConductorTimeSystem from './ConductorTimeSystem.vue';
 | 
			
		||||
import DatePicker from './DatePicker.vue';
 | 
			
		||||
import ConductorAxis from './ConductorAxis.vue';
 | 
			
		||||
import ConductorModeIcon from './ConductorModeIcon.vue';
 | 
			
		||||
import ConductorHistory from './ConductorHistory.vue'
 | 
			
		||||
 | 
			
		||||
const DEFAULT_DURATION_FORMATTER = 'duration';
 | 
			
		||||
const SECONDS = 1000;
 | 
			
		||||
@@ -309,7 +319,8 @@ export default {
 | 
			
		||||
        ConductorTimeSystem,
 | 
			
		||||
        DatePicker,
 | 
			
		||||
        ConductorAxis,
 | 
			
		||||
        ConductorModeIcon
 | 
			
		||||
        ConductorModeIcon,
 | 
			
		||||
        ConductorHistory
 | 
			
		||||
    },
 | 
			
		||||
    data() {
 | 
			
		||||
        let bounds = this.openmct.time.bounds();
 | 
			
		||||
@@ -319,6 +330,7 @@ export default {
 | 
			
		||||
        let durationFormatter = this.getFormatter(timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER);
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            timeSystem: timeSystem,
 | 
			
		||||
            timeFormatter: timeFormatter,
 | 
			
		||||
            durationFormatter: durationFormatter,
 | 
			
		||||
            offsets: {
 | 
			
		||||
@@ -329,6 +341,10 @@ export default {
 | 
			
		||||
                start: timeFormatter.format(bounds.start),
 | 
			
		||||
                end: timeFormatter.format(bounds.end)
 | 
			
		||||
            },
 | 
			
		||||
            bounds: {
 | 
			
		||||
                start: bounds.start,
 | 
			
		||||
                end: bounds.end
 | 
			
		||||
            },
 | 
			
		||||
            rawBounds: {
 | 
			
		||||
                start: bounds.start,
 | 
			
		||||
                end: bounds.end
 | 
			
		||||
@@ -340,10 +356,10 @@ export default {
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        setTimeSystem(timeSystem) {
 | 
			
		||||
            this.timeSystem = timeSystem
 | 
			
		||||
            this.timeFormatter = this.getFormatter(timeSystem.timeFormat);
 | 
			
		||||
            this.durationFormatter = this.getFormatter(
 | 
			
		||||
                timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER);
 | 
			
		||||
 | 
			
		||||
            this.isUTCBased = timeSystem.isUTCBased;
 | 
			
		||||
        },
 | 
			
		||||
        setOffsetsFromView($event) {
 | 
			
		||||
@@ -492,11 +508,14 @@ export default {
 | 
			
		||||
            this.validateAllBounds();
 | 
			
		||||
            this.submitForm();
 | 
			
		||||
        },
 | 
			
		||||
        setNewBounds(bounds) {
 | 
			
		||||
            this.bounds.start = bounds.start;
 | 
			
		||||
            this.bounds.end = bounds.end;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
        this.setTimeSystem(JSON.parse(JSON.stringify(this.openmct.time.timeSystem())));
 | 
			
		||||
 | 
			
		||||
        this.openmct.time.on('bounds', this.setViewFromBounds);
 | 
			
		||||
        this.openmct.time.on('bounds', this.setNewBounds);
 | 
			
		||||
        this.openmct.time.on('timeSystem', this.setTimeSystem);
 | 
			
		||||
        this.openmct.time.on('clock', this.setViewFromClock);
 | 
			
		||||
        this.openmct.time.on('clockOffsets', this.setViewFromOffsets)
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,8 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div class="c-conductor-axis"
 | 
			
		||||
         ref="axisHolder"
 | 
			
		||||
         @mousedown="dragStart($event)">
 | 
			
		||||
         @mousedown="dragStart($event)"
 | 
			
		||||
    >
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
@@ -44,7 +45,7 @@
 | 
			
		||||
            text-rendering: geometricPrecision;
 | 
			
		||||
            width: 100%;
 | 
			
		||||
            height: 100%;
 | 
			
		||||
            > g {
 | 
			
		||||
            > g.axis {
 | 
			
		||||
                // Overall Tick holder
 | 
			
		||||
                transform: translateY($tickYPos);
 | 
			
		||||
                path {
 | 
			
		||||
@@ -97,6 +98,7 @@
 | 
			
		||||
                    transition: $transIn;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .is-realtime-mode & {
 | 
			
		||||
@@ -115,6 +117,7 @@
 | 
			
		||||
import * as d3Selection from 'd3-selection';
 | 
			
		||||
import * as d3Axis from 'd3-axis';
 | 
			
		||||
import * as d3Scale from 'd3-scale';
 | 
			
		||||
import * as d3Brush from 'd3-brush';
 | 
			
		||||
import utcMultiTimeFormat from './utcMultiTimeFormat.js';
 | 
			
		||||
 | 
			
		||||
const PADDING = 1;
 | 
			
		||||
@@ -126,7 +129,13 @@ const PIXELS_PER_TICK_WIDE = 200;
 | 
			
		||||
export default {
 | 
			
		||||
    inject: ['openmct'],
 | 
			
		||||
    props: {
 | 
			
		||||
        bounds: Object
 | 
			
		||||
        bounds: Object,
 | 
			
		||||
        isFixed: Boolean
 | 
			
		||||
    },
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
            altPressed: false
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        setScale() {
 | 
			
		||||
@@ -171,9 +180,8 @@ export default {
 | 
			
		||||
        },
 | 
			
		||||
        getActiveFormatter() {
 | 
			
		||||
            let timeSystem = this.openmct.time.timeSystem();
 | 
			
		||||
            let isFixed = this.openmct.time.clock() === undefined;
 | 
			
		||||
 | 
			
		||||
            if (isFixed) {
 | 
			
		||||
            if (this.isFixed) {
 | 
			
		||||
                return this.getFormatter(timeSystem.timeFormat);
 | 
			
		||||
            } else {
 | 
			
		||||
                return this.getFormatter(timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER);
 | 
			
		||||
@@ -185,8 +193,7 @@ export default {
 | 
			
		||||
            }).formatter;
 | 
			
		||||
        },
 | 
			
		||||
        dragStart($event){
 | 
			
		||||
            let isFixed = this.openmct.time.clock() === undefined;
 | 
			
		||||
            if (isFixed){
 | 
			
		||||
            if (this.isFixed){
 | 
			
		||||
                this.dragStartX = $event.clientX;
 | 
			
		||||
 | 
			
		||||
                document.addEventListener('mousemove', this.drag);
 | 
			
		||||
@@ -198,18 +205,20 @@ export default {
 | 
			
		||||
        drag($event) {
 | 
			
		||||
            if (!this.dragging){
 | 
			
		||||
                this.dragging = true;
 | 
			
		||||
                requestAnimationFrame(()=>{
 | 
			
		||||
                    let deltaX = $event.clientX - this.dragStartX;
 | 
			
		||||
                    let percX = deltaX / this.width;
 | 
			
		||||
                    let bounds = this.openmct.time.bounds();
 | 
			
		||||
                    let deltaTime = bounds.end - bounds.start;
 | 
			
		||||
                    let newStart = bounds.start - percX * deltaTime;
 | 
			
		||||
                    this.$emit('panAxis',{
 | 
			
		||||
                        start: newStart,
 | 
			
		||||
                        end: newStart + deltaTime
 | 
			
		||||
                    });
 | 
			
		||||
                    this.dragging = false;
 | 
			
		||||
                })
 | 
			
		||||
                if (this.altPressed) {
 | 
			
		||||
                    requestAnimationFrame(()=>{
 | 
			
		||||
                        let deltaX = $event.clientX - this.dragStartX;
 | 
			
		||||
                        let percX = deltaX / this.width;
 | 
			
		||||
                        let bounds = this.openmct.time.bounds();
 | 
			
		||||
                        let deltaTime = bounds.end - bounds.start;
 | 
			
		||||
                        let newStart = bounds.start - percX * deltaTime;
 | 
			
		||||
                        this.$emit('panAxis',{
 | 
			
		||||
                            start: newStart,
 | 
			
		||||
                            end: newStart + deltaTime
 | 
			
		||||
                        });
 | 
			
		||||
                    })
 | 
			
		||||
                }
 | 
			
		||||
                this.dragging = false;
 | 
			
		||||
            } else {
 | 
			
		||||
                console.log('Rejected drag due to RAF cap');
 | 
			
		||||
            }
 | 
			
		||||
@@ -225,6 +234,55 @@ export default {
 | 
			
		||||
            if (this.$refs.axisHolder.clientWidth !== this.width) {
 | 
			
		||||
                this.width = this.$refs.axisHolder.clientWidth;
 | 
			
		||||
                this.setScale();
 | 
			
		||||
                this.destroyBrush();
 | 
			
		||||
                this.initBrush();
 | 
			
		||||
                this.createBrush();
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        initBrush() {
 | 
			
		||||
            // brush extent y coordinate starts at -1 to prevent underlying layer cursor to show
 | 
			
		||||
            this.brush = d3Brush.brushX()
 | 
			
		||||
                .extent([[0, -1], [this.width, this.height]])
 | 
			
		||||
                .on("end", this.brushEnd);
 | 
			
		||||
        },
 | 
			
		||||
        createBrush() {
 | 
			
		||||
            if (!this.isFixed) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.svg = this.svg || d3Selection.select('svg');
 | 
			
		||||
            if (!this.svg) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.svg.append("g")
 | 
			
		||||
                .attr("class", "brush")
 | 
			
		||||
                .call(this.brush);
 | 
			
		||||
        },
 | 
			
		||||
        brushEnd () {
 | 
			
		||||
            const selection = d3Selection.event.selection;
 | 
			
		||||
            if (!d3Selection.event.sourceEvent || !selection) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // SMELL
 | 
			
		||||
            const [x0, x1] = selection.map(d => this.xScale.invert(d).getTime());
 | 
			
		||||
            this.openmct.time.bounds({
 | 
			
		||||
                start: x0,
 | 
			
		||||
                end: x1
 | 
			
		||||
            });
 | 
			
		||||
            this.$emit('zoomAxis', {
 | 
			
		||||
                start: x0,
 | 
			
		||||
                end: x1
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // clear brush
 | 
			
		||||
            d3Selection.select('g.brush').call(this.brush.move, null);
 | 
			
		||||
        },
 | 
			
		||||
        destroyBrush() {
 | 
			
		||||
            const brush = d3Selection.select('g.brush')
 | 
			
		||||
            if (brush){
 | 
			
		||||
                brush.remove();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
@@ -234,22 +292,40 @@ export default {
 | 
			
		||||
                this.setScale();
 | 
			
		||||
            },
 | 
			
		||||
            deep: true
 | 
			
		||||
        },
 | 
			
		||||
        isFixed: function(value) {
 | 
			
		||||
            value ? this.createBrush() : this.destroyBrush();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    created() {
 | 
			
		||||
        document.addEventListener('keydown', (e) => {
 | 
			
		||||
            if (e.key === 'Alt') {
 | 
			
		||||
                this.altPressed = true;
 | 
			
		||||
                this.destroyBrush();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        document.addEventListener('keyup', (e) => {
 | 
			
		||||
            if (e.key === 'Alt') {
 | 
			
		||||
                this.altPressed = false;
 | 
			
		||||
                this.createBrush();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
        let axisHolder = this.$refs.axisHolder;
 | 
			
		||||
        let height = axisHolder.offsetHeight;
 | 
			
		||||
        this.height = axisHolder.offsetHeight;
 | 
			
		||||
        let vis = d3Selection.select(axisHolder)
 | 
			
		||||
            .append("svg:svg")
 | 
			
		||||
            .attr("width", "100%")
 | 
			
		||||
            .attr("height", height);
 | 
			
		||||
            .attr("height", this.height);
 | 
			
		||||
 | 
			
		||||
        this.width = this.$refs.axisHolder.clientWidth;
 | 
			
		||||
        this.xAxis = d3Axis.axisTop();
 | 
			
		||||
        this.dragging = false;
 | 
			
		||||
 | 
			
		||||
        // draw x axis with labels. CSS is used to position them.
 | 
			
		||||
        this.axisElement = vis.append("g");
 | 
			
		||||
        this.axisElement = vis.append("g")
 | 
			
		||||
            .attr("class", "axis");
 | 
			
		||||
 | 
			
		||||
        this.setViewFromTimeSystem(this.openmct.time.timeSystem());
 | 
			
		||||
        this.setScale();
 | 
			
		||||
@@ -257,6 +333,9 @@ export default {
 | 
			
		||||
        //Respond to changes in conductor
 | 
			
		||||
        this.openmct.time.on("timeSystem", this.setViewFromTimeSystem);
 | 
			
		||||
        setInterval(this.resize, RESIZE_POLL_INTERVAL);
 | 
			
		||||
 | 
			
		||||
        this.initBrush();
 | 
			
		||||
        this.createBrush();
 | 
			
		||||
    },
 | 
			
		||||
    destroyed() {
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										161
									
								
								src/plugins/timeConductor/ConductorHistory.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								src/plugins/timeConductor/ConductorHistory.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,161 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * Open MCT Web, Copyright (c) 2014-2018, 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.
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
<template>
 | 
			
		||||
    <div class="c-ctrl-wrapper c-ctrl-wrapper--menus-up">
 | 
			
		||||
        <button class="c-button--menu c-history-button icon-history"
 | 
			
		||||
             @click.prevent="toggle">
 | 
			
		||||
            <span class="c-button__label">History</span>
 | 
			
		||||
        </button>
 | 
			
		||||
        <div class="c-menu" v-if="open">
 | 
			
		||||
            <ul
 | 
			
		||||
                v-if="isUTCBased"
 | 
			
		||||
            >
 | 
			
		||||
                <li @click="selectHours(24)">Last 24 hours</li>
 | 
			
		||||
                <li @click="selectHours(2)">Last 2 hours</li>
 | 
			
		||||
                <li @click="selectHours(1)">Last hour</li>
 | 
			
		||||
            </ul>
 | 
			
		||||
            <ul>
 | 
			
		||||
                <li
 | 
			
		||||
                    v-for="(timespan, index) in historyForCurrentTimeSystem"
 | 
			
		||||
                    :key="index"
 | 
			
		||||
                    @click="selectTimespan(timespan)"
 | 
			
		||||
                >
 | 
			
		||||
                    {{ formatTime(timespan.start) }} - {{ formatTime(timespan.end) }}
 | 
			
		||||
                </li>
 | 
			
		||||
            </ul>
 | 
			
		||||
        </div>    
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style lang="scss">
 | 
			
		||||
    @import "~styles/sass-base";
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import toggleMixin from '../../ui/mixins/toggle-mixin';
 | 
			
		||||
import utcMultiTimeFormat from './utcMultiTimeFormat.js';
 | 
			
		||||
import _ from 'lodash'
 | 
			
		||||
 | 
			
		||||
const LOCAL_STORAGE_HISTORY_MAX_RECORDS = 20;
 | 
			
		||||
const LOCAL_STORAGE_HISTORY_KEY = 'tcHistory';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    inject: ['openmct'],
 | 
			
		||||
    mixins: [toggleMixin],
 | 
			
		||||
    props: {
 | 
			
		||||
        bounds: {
 | 
			
		||||
            type: Object,
 | 
			
		||||
            required: true
 | 
			
		||||
        },
 | 
			
		||||
        timeSystem: {
 | 
			
		||||
            type: Object,
 | 
			
		||||
            required: true
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
            history: {} // contains arrays of timespans {start, end}, array key is time system key
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
        isUTCBased() {
 | 
			
		||||
            return this.timeSystem.isUTCBased;
 | 
			
		||||
        },
 | 
			
		||||
        historyForCurrentTimeSystem() {
 | 
			
		||||
            return this.history[this.timeSystem.key]
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        getHistoryFromLocalStorage() {
 | 
			
		||||
            if (localStorage.getItem(LOCAL_STORAGE_HISTORY_KEY)) {
 | 
			
		||||
                this.history = JSON.parse(localStorage.getItem(LOCAL_STORAGE_HISTORY_KEY))
 | 
			
		||||
            } else {
 | 
			
		||||
                this.history = {};
 | 
			
		||||
                this.persistHistoryToLocalStorage();
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        persistHistoryToLocalStorage() {
 | 
			
		||||
            localStorage.setItem(LOCAL_STORAGE_HISTORY_KEY, JSON.stringify(this.history));
 | 
			
		||||
        },
 | 
			
		||||
        addTimespan() {
 | 
			
		||||
            const key = this.timeSystem.key;
 | 
			
		||||
            let [...currentHistory] = this.history[key] || [];
 | 
			
		||||
            const timespan = {
 | 
			
		||||
                start: this.bounds.start,
 | 
			
		||||
                end: this.bounds.end,
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            // when choosing an existing entry, remove it and add it back as latest entry
 | 
			
		||||
            currentHistory = currentHistory.filter((entry) => {
 | 
			
		||||
                return !_.isEqual(timespan, entry);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if (currentHistory.length >= LOCAL_STORAGE_HISTORY_MAX_RECORDS) {
 | 
			
		||||
                currentHistory.shift();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            currentHistory.push(timespan);
 | 
			
		||||
            this.history[key] = currentHistory;
 | 
			
		||||
        },
 | 
			
		||||
        selectTimespan(timespan) {
 | 
			
		||||
            this.$emit('select-timespan', timespan);
 | 
			
		||||
        },
 | 
			
		||||
        selectHours(hours) {
 | 
			
		||||
            const now = Date.now();
 | 
			
		||||
            this.selectTimespan({
 | 
			
		||||
                start: now - hours * 60 * 60 * 1000,
 | 
			
		||||
                end: now
 | 
			
		||||
            });
 | 
			
		||||
        },
 | 
			
		||||
        formatTime(time) {
 | 
			
		||||
            const formatter = this.openmct.telemetry.getValueFormatter({
 | 
			
		||||
                format: this.timeSystem.timeFormat
 | 
			
		||||
            }).formatter;
 | 
			
		||||
 | 
			
		||||
            return formatter.format(time);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    watch: {
 | 
			
		||||
        bounds: {
 | 
			
		||||
            handler() {
 | 
			
		||||
                this.addTimespan();
 | 
			
		||||
            },
 | 
			
		||||
            deep: true
 | 
			
		||||
        },
 | 
			
		||||
        timeSystem: {
 | 
			
		||||
            handler() {
 | 
			
		||||
                this.addTimespan();
 | 
			
		||||
            },
 | 
			
		||||
            deep: true
 | 
			
		||||
        },
 | 
			
		||||
        history: {
 | 
			
		||||
            handler() {
 | 
			
		||||
                this.persistHistoryToLocalStorage();
 | 
			
		||||
            },
 | 
			
		||||
            deep: true
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
        this.getHistoryFromLocalStorage();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
@@ -432,6 +432,11 @@ select {
 | 
			
		||||
             content: ''; // Add this element so that menu items without an icon still indent properly
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    ul {
 | 
			
		||||
        &:not(:last-child) {
 | 
			
		||||
            border-bottom: 1px solid $colorInteriorBorder;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.c-menu {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user