Compare commits
	
		
			17 Commits
		
	
	
		
			code-walkt
			...
			khalid-pre
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					fd1f2fa303 | ||
| 
						 | 
					51d4ad58c7 | ||
| 
						 | 
					36fc4929fc | ||
| 
						 | 
					0f848d9f4c | ||
| 
						 | 
					41b860a547 | ||
| 
						 | 
					254b3db966 | ||
| 
						 | 
					b6cc1924aa | ||
| 
						 | 
					3e97f32dba | ||
| 
						 | 
					558b802228 | ||
| 
						 | 
					de13f67ae5 | ||
| 
						 | 
					0256cc4830 | ||
| 
						 | 
					8422add614 | ||
| 
						 | 
					2114697d6f | ||
| 
						 | 
					412eaf599e | ||
| 
						 | 
					0691a35dab | ||
| 
						 | 
					f57191fd89 | ||
| 
						 | 
					14066b5c4d | 
@@ -49,6 +49,10 @@ define([
 | 
			
		||||
        ];
 | 
			
		||||
        const IMAGE_DELAY = 20000;
 | 
			
		||||
 | 
			
		||||
        function getCompassValues(min, max) {
 | 
			
		||||
            return min + Math.random() * (max - min);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function pointForTimestamp(timestamp, name) {
 | 
			
		||||
            const url = IMAGE_SAMPLES[Math.floor(timestamp / IMAGE_DELAY) % IMAGE_SAMPLES.length];
 | 
			
		||||
            const urlItems = url.split('/');
 | 
			
		||||
@@ -59,6 +63,9 @@ define([
 | 
			
		||||
                utc: Math.floor(timestamp / IMAGE_DELAY) * IMAGE_DELAY,
 | 
			
		||||
                local: Math.floor(timestamp / IMAGE_DELAY) * IMAGE_DELAY,
 | 
			
		||||
                url,
 | 
			
		||||
                sunOrientation: getCompassValues(0, 360),
 | 
			
		||||
                cameraPan: getCompassValues(0, 360),
 | 
			
		||||
                heading: getCompassValues(0, 360),
 | 
			
		||||
                imageDownloadName
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -194,7 +194,6 @@
 | 
			
		||||
            ['table', 'telemetry.plot.overlay', 'telemetry.plot.stacked'],
 | 
			
		||||
            {indicator: true}
 | 
			
		||||
        ));
 | 
			
		||||
        openmct.install(openmct.plugins.CodeWalkthrough);
 | 
			
		||||
        openmct.start();
 | 
			
		||||
    </script>
 | 
			
		||||
</html>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "openmct",
 | 
			
		||||
  "version": "1.7.4",
 | 
			
		||||
  "version": "1.7.5",
 | 
			
		||||
  "description": "The Open MCT core platform",
 | 
			
		||||
  "dependencies": {},
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
@@ -34,7 +34,7 @@
 | 
			
		||||
    "git-rev-sync": "^1.4.0",
 | 
			
		||||
    "glob": ">= 3.0.0",
 | 
			
		||||
    "html-loader": "^0.5.5",
 | 
			
		||||
    "html2canvas": "^1.0.0-alpha.12",
 | 
			
		||||
    "html2canvas": "^1.0.0-rc.7",
 | 
			
		||||
    "imports-loader": "^0.8.0",
 | 
			
		||||
    "istanbul-instrumenter-loader": "^3.0.1",
 | 
			
		||||
    "jasmine-core": "^3.1.0",
 | 
			
		||||
 
 | 
			
		||||
@@ -181,7 +181,7 @@ define([
 | 
			
		||||
                        ],
 | 
			
		||||
                        "category": "contextual",
 | 
			
		||||
                        "name": "Stop",
 | 
			
		||||
                        "cssClass": "icon-box",
 | 
			
		||||
                        "cssClass": "icon-box-round-corners",
 | 
			
		||||
                        "priority": "preferred"
 | 
			
		||||
                    }
 | 
			
		||||
                ],
 | 
			
		||||
 
 | 
			
		||||
@@ -101,7 +101,7 @@ define(
 | 
			
		||||
                    name: "Pause"
 | 
			
		||||
                });
 | 
			
		||||
                mockStop.getMetadata.and.returnValue({
 | 
			
		||||
                    cssClass: "icon-box",
 | 
			
		||||
                    cssClass: "icon-box-round-corners",
 | 
			
		||||
                    name: "Stop"
 | 
			
		||||
                });
 | 
			
		||||
                mockScope.domainObject = mockDomainObject;
 | 
			
		||||
 
 | 
			
		||||
@@ -45,6 +45,7 @@ export default class URLTimeSettingsSynchronizer {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    initialize() {
 | 
			
		||||
        this.updateTimeSettings();
 | 
			
		||||
        this.openmct.router.on('change:params', this.updateTimeSettings);
 | 
			
		||||
 | 
			
		||||
        TIME_EVENTS.forEach(event => {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,71 +0,0 @@
 | 
			
		||||
import Vue from 'Vue';
 | 
			
		||||
 | 
			
		||||
export default function install(openmct) {
 | 
			
		||||
    openmct.objectViews.addProvider({
 | 
			
		||||
        name: "Latest Data Table",
 | 
			
		||||
        key: "latest-table",
 | 
			
		||||
        cssClass: "icon-packet",
 | 
			
		||||
        description: "A tabular view of telemetry contents.",
 | 
			
		||||
        canView: function () {
 | 
			
		||||
            return true;
 | 
			
		||||
        },
 | 
			
		||||
        view: function (domainObject) {
 | 
			
		||||
            let unsubscribe;
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                show: function (element) {
 | 
			
		||||
                    //element.innerText = 'Hello World!';
 | 
			
		||||
                    let telemetryMetadata = openmct.telemetry.getMetadata(domainObject).values();
 | 
			
		||||
                    let tableEl = document.createElement('table');
 | 
			
		||||
                    let tableHeader = document.createElement('thead');
 | 
			
		||||
                    let tableHeaderRow = document.createElement('tr');
 | 
			
		||||
                    let tableBody = document.createElement('tbody');
 | 
			
		||||
 | 
			
		||||
                    element.appendChild(tableEl);
 | 
			
		||||
                    tableHeader.appendChild(tableHeaderRow);
 | 
			
		||||
                    tableEl.appendChild(tableHeader);
 | 
			
		||||
                    tableEl.appendChild(tableBody);
 | 
			
		||||
 | 
			
		||||
                    telemetryMetadata.forEach(metadatum => {
 | 
			
		||||
                        let tableHeader = document.createElement('td');
 | 
			
		||||
                        tableHeader.innerText = metadatum.name;
 | 
			
		||||
                        tableHeaderRow.appendChild(tableHeader);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    openmct.time.on('bounds', (newBounds) => {
 | 
			
		||||
                        tableBody.innerHTML = '';
 | 
			
		||||
                        requestTelemetry(newBounds);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    requestTelemetry();
 | 
			
		||||
 | 
			
		||||
                    // unsubscribe = openmct.telemetry.subscribe(domainObject, (datum) => {
 | 
			
		||||
                    //     addRow(datum);
 | 
			
		||||
                    // });
 | 
			
		||||
 | 
			
		||||
                    function addRow(telemetryDatum) {
 | 
			
		||||
                        let dataRow = document.createElement('tr');
 | 
			
		||||
                        telemetryMetadata.forEach(metadatum => {
 | 
			
		||||
                            let tableCell = document.createElement('td');
 | 
			
		||||
                            let formatter = openmct.telemetry.getValueFormatter(metadatum);
 | 
			
		||||
 | 
			
		||||
                            tableCell.innerText = formatter.format(telemetryDatum[metadatum.key]);
 | 
			
		||||
                            dataRow.appendChild(tableCell);
 | 
			
		||||
                            tableBody.appendChild(dataRow);
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    function requestTelemetry(bounds) {
 | 
			
		||||
                        openmct.telemetry.request(domainObject, {bounds}).then(arrayOfTelemetry => {
 | 
			
		||||
                            arrayOfTelemetry.forEach(addRow);
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                destroy: function (element) {
 | 
			
		||||
                    unsubscribe();
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -138,7 +138,7 @@ export default class Condition extends EventEmitter {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    updateCriteria(criterionConfigurations) {
 | 
			
		||||
        this.destroyCriteria();
 | 
			
		||||
        this.destroyCriteria(true);
 | 
			
		||||
        this.createCriteria(criterionConfigurations);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -204,7 +204,7 @@ export default class Condition extends EventEmitter {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    destroyCriterion(id) {
 | 
			
		||||
    destroyCriterion(id, isRemoved) {
 | 
			
		||||
        let found = this.findCriterion(id);
 | 
			
		||||
        if (found) {
 | 
			
		||||
            let criterion = found.item;
 | 
			
		||||
@@ -216,7 +216,9 @@ export default class Condition extends EventEmitter {
 | 
			
		||||
            });
 | 
			
		||||
            criterion.destroy();
 | 
			
		||||
            this.criteria.splice(found.index, 1);
 | 
			
		||||
            this.updateDescription();
 | 
			
		||||
            if (isRemoved) {
 | 
			
		||||
                this.updateDescription();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
@@ -309,17 +311,17 @@ export default class Condition extends EventEmitter {
 | 
			
		||||
        return this.criteria;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    destroyCriteria() {
 | 
			
		||||
    destroyCriteria(isRemoved) {
 | 
			
		||||
        let success = true;
 | 
			
		||||
        //looping through the array backwards since destroyCriterion modifies the criteria array
 | 
			
		||||
        for (let i = this.criteria.length - 1; i >= 0; i--) {
 | 
			
		||||
            success = success && this.destroyCriterion(this.criteria[i].id);
 | 
			
		||||
            success = success && this.destroyCriterion(this.criteria[i].id, isRemoved);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return success;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    destroy() {
 | 
			
		||||
        this.destroyCriteria();
 | 
			
		||||
    destroy(isRemoved) {
 | 
			
		||||
        this.destroyCriteria(isRemoved);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@ export default class ConditionManager extends EventEmitter {
 | 
			
		||||
        this.subscriptions = {};
 | 
			
		||||
        this.telemetryObjects = {};
 | 
			
		||||
        this.testData = {
 | 
			
		||||
            conditionTestData: [],
 | 
			
		||||
            conditionTestInputs: this.conditionSetDomainObject.configuration.conditionTestData,
 | 
			
		||||
            applied: false
 | 
			
		||||
        };
 | 
			
		||||
        this.initialize();
 | 
			
		||||
@@ -154,8 +154,10 @@ export default class ConditionManager extends EventEmitter {
 | 
			
		||||
 | 
			
		||||
    updateConditionDescription(condition) {
 | 
			
		||||
        const found = this.conditionSetDomainObject.configuration.conditionCollection.find(conditionConfiguration => (conditionConfiguration.id === condition.id));
 | 
			
		||||
        found.summary = condition.description;
 | 
			
		||||
        this.persistConditions();
 | 
			
		||||
        if (found.summary !== condition.description) {
 | 
			
		||||
            found.summary = condition.description;
 | 
			
		||||
            this.persistConditions();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    initCondition(conditionConfiguration, index) {
 | 
			
		||||
@@ -225,7 +227,7 @@ export default class ConditionManager extends EventEmitter {
 | 
			
		||||
    removeCondition(id) {
 | 
			
		||||
        let index = this.conditions.findIndex(item => item.id === id);
 | 
			
		||||
        if (index > -1) {
 | 
			
		||||
            this.conditions[index].destroy();
 | 
			
		||||
            this.conditions[index].destroy(true);
 | 
			
		||||
            this.conditions.splice(index, 1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -414,8 +416,10 @@ export default class ConditionManager extends EventEmitter {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    updateTestData(testData) {
 | 
			
		||||
        this.testData = testData;
 | 
			
		||||
        this.openmct.objects.mutate(this.conditionSetDomainObject, 'configuration.conditionTestData', this.testData.conditionTestInputs);
 | 
			
		||||
        if (!_.isEqual(testData, this.testData)) {
 | 
			
		||||
            this.testData = testData;
 | 
			
		||||
            this.openmct.objects.mutate(this.conditionSetDomainObject, 'configuration.conditionTestData', this.testData.conditionTestInputs);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    persistConditions() {
 | 
			
		||||
@@ -433,7 +437,7 @@ export default class ConditionManager extends EventEmitter {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.conditions.forEach((condition) => {
 | 
			
		||||
            condition.destroy();
 | 
			
		||||
            condition.destroy(false);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@
 | 
			
		||||
<template>
 | 
			
		||||
<div
 | 
			
		||||
    class="c-compass"
 | 
			
		||||
    :style="`width: ${ sizedImageDimensions.width }px; height: ${ sizedImageDimensions.height }px`"
 | 
			
		||||
    :style="`width: 100%; height: 100%`"
 | 
			
		||||
>
 | 
			
		||||
    <CompassHUD
 | 
			
		||||
        v-if="hasCameraFieldOfView"
 | 
			
		||||
@@ -33,13 +33,12 @@
 | 
			
		||||
    />
 | 
			
		||||
    <CompassRose
 | 
			
		||||
        v-if="hasCameraFieldOfView"
 | 
			
		||||
        :heading="heading"
 | 
			
		||||
        :sized-image-width="sizedImageDimensions.width"
 | 
			
		||||
        :sun-heading="sunHeading"
 | 
			
		||||
        :camera-angle-of-view="cameraAngleOfView"
 | 
			
		||||
        :camera-pan="cameraPan"
 | 
			
		||||
        :lock-compass="lockCompass"
 | 
			
		||||
        @toggle-lock-compass="toggleLockCompass"
 | 
			
		||||
        :compass-rose-sizing-classes="compassRoseSizingClasses"
 | 
			
		||||
        :heading="heading"
 | 
			
		||||
        :sized-image-dimensions="sizedImageDimensions"
 | 
			
		||||
        :sun-heading="sunHeading"
 | 
			
		||||
    />
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
@@ -56,42 +55,20 @@ export default {
 | 
			
		||||
        CompassRose
 | 
			
		||||
    },
 | 
			
		||||
    props: {
 | 
			
		||||
        containerWidth: {
 | 
			
		||||
            type: Number,
 | 
			
		||||
            required: true
 | 
			
		||||
        },
 | 
			
		||||
        containerHeight: {
 | 
			
		||||
            type: Number,
 | 
			
		||||
            required: true
 | 
			
		||||
        },
 | 
			
		||||
        naturalAspectRatio: {
 | 
			
		||||
            type: Number,
 | 
			
		||||
        compassRoseSizingClasses: {
 | 
			
		||||
            type: String,
 | 
			
		||||
            required: true
 | 
			
		||||
        },
 | 
			
		||||
        image: {
 | 
			
		||||
            type: Object,
 | 
			
		||||
            required: true
 | 
			
		||||
        },
 | 
			
		||||
        lockCompass: {
 | 
			
		||||
            type: Boolean,
 | 
			
		||||
        sizedImageDimensions: {
 | 
			
		||||
            type: Object,
 | 
			
		||||
            required: true
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
        sizedImageDimensions() {
 | 
			
		||||
            let sizedImageDimensions = {};
 | 
			
		||||
            if ((this.containerWidth / this.containerHeight) > this.naturalAspectRatio) {
 | 
			
		||||
                // container is wider than image
 | 
			
		||||
                sizedImageDimensions.width = this.containerHeight * this.naturalAspectRatio;
 | 
			
		||||
                sizedImageDimensions.height = this.containerHeight;
 | 
			
		||||
            } else {
 | 
			
		||||
                // container is taller than image
 | 
			
		||||
                sizedImageDimensions.width = this.containerWidth;
 | 
			
		||||
                sizedImageDimensions.height = this.containerWidth * this.naturalAspectRatio;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return sizedImageDimensions;
 | 
			
		||||
        },
 | 
			
		||||
        hasCameraFieldOfView() {
 | 
			
		||||
            return this.cameraPan !== undefined && this.cameraAngleOfView > 0;
 | 
			
		||||
        },
 | 
			
		||||
 
 | 
			
		||||
@@ -21,152 +21,203 @@
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
<div
 | 
			
		||||
    class="w-direction-rose"
 | 
			
		||||
    :class="compassRoseSizingClasses"
 | 
			
		||||
<div ref="compassRoseWrapper"
 | 
			
		||||
     class="w-direction-rose"
 | 
			
		||||
     :class="compassRoseSizingClasses"
 | 
			
		||||
     @click="toggleLockCompass"
 | 
			
		||||
>
 | 
			
		||||
    <div
 | 
			
		||||
        class="c-direction-rose"
 | 
			
		||||
        @click="toggleLockCompass"
 | 
			
		||||
    <svg ref="compassRoseSvg"
 | 
			
		||||
         class="c-compass-rose-svg"
 | 
			
		||||
         viewBox="0 0 100 100"
 | 
			
		||||
    >
 | 
			
		||||
        <div
 | 
			
		||||
            class="c-nsew"
 | 
			
		||||
            :style="compassRoseStyle"
 | 
			
		||||
        <mask id="mask0"
 | 
			
		||||
              mask-type="alpha"
 | 
			
		||||
              maskUnits="userSpaceOnUse"
 | 
			
		||||
              x="0"
 | 
			
		||||
              y="0"
 | 
			
		||||
              width="100"
 | 
			
		||||
              height="100"
 | 
			
		||||
        >
 | 
			
		||||
            <svg
 | 
			
		||||
                class="c-nsew__minor-ticks"
 | 
			
		||||
                viewBox="0 0 100 100"
 | 
			
		||||
            <circle cx="50"
 | 
			
		||||
                    cy="50"
 | 
			
		||||
                    r="50"
 | 
			
		||||
                    fill="black"
 | 
			
		||||
            />
 | 
			
		||||
        </mask>
 | 
			
		||||
        <g class="c-cr__compass-wrapper">
 | 
			
		||||
            <g class="c-cr__compass-main"
 | 
			
		||||
               mask="url(#mask0)"
 | 
			
		||||
            >
 | 
			
		||||
                <rect
 | 
			
		||||
                    class="c-nsew__tick c-tick-ne"
 | 
			
		||||
                    x="49"
 | 
			
		||||
                    y="0"
 | 
			
		||||
                    width="2"
 | 
			
		||||
                    height="5"
 | 
			
		||||
                <!-- Background and clipped elements -->
 | 
			
		||||
                <rect class="c-cr__bg"
 | 
			
		||||
                      width="100"
 | 
			
		||||
                      height="100"
 | 
			
		||||
                      fill="black"
 | 
			
		||||
                />
 | 
			
		||||
                <rect
 | 
			
		||||
                    class="c-nsew__tick c-tick-se"
 | 
			
		||||
                    x="95"
 | 
			
		||||
                    y="49"
 | 
			
		||||
                    width="5"
 | 
			
		||||
                    height="2"
 | 
			
		||||
                <rect class="c-cr__edge"
 | 
			
		||||
                      width="100"
 | 
			
		||||
                      height="100"
 | 
			
		||||
                      fill="url(#paint0_radial)"
 | 
			
		||||
                />
 | 
			
		||||
                <rect
 | 
			
		||||
                    class="c-nsew__tick c-tick-sw"
 | 
			
		||||
                    x="49"
 | 
			
		||||
                    y="95"
 | 
			
		||||
                    width="2"
 | 
			
		||||
                    height="5"
 | 
			
		||||
                />
 | 
			
		||||
                <rect
 | 
			
		||||
                    class="c-nsew__tick c-tick-nw"
 | 
			
		||||
                    x="0"
 | 
			
		||||
                    y="49"
 | 
			
		||||
                    width="5"
 | 
			
		||||
                    height="2"
 | 
			
		||||
                <rect v-if="hasSunHeading"
 | 
			
		||||
                      class="c-cr__sun"
 | 
			
		||||
                      width="100"
 | 
			
		||||
                      height="100"
 | 
			
		||||
                      fill="url(#paint1_radial)"
 | 
			
		||||
                      :style="sunHeadingStyle"
 | 
			
		||||
                />
 | 
			
		||||
 | 
			
		||||
            </svg>
 | 
			
		||||
                <!-- Camera FOV -->
 | 
			
		||||
                <mask id="mask2"
 | 
			
		||||
                      class="c-cr__cam-fov-l-mask"
 | 
			
		||||
                      mask-type="alpha"
 | 
			
		||||
                      maskUnits="userSpaceOnUse"
 | 
			
		||||
                      x="0"
 | 
			
		||||
                      y="0"
 | 
			
		||||
                      width="50"
 | 
			
		||||
                      height="100"
 | 
			
		||||
                >
 | 
			
		||||
                    <rect width="51"
 | 
			
		||||
                          height="100"
 | 
			
		||||
                    />
 | 
			
		||||
                </mask>
 | 
			
		||||
                <mask id="mask1"
 | 
			
		||||
                      class="c-cr__cam-fov-r-mask"
 | 
			
		||||
                      mask-type="alpha"
 | 
			
		||||
                      maskUnits="userSpaceOnUse"
 | 
			
		||||
                      x="50"
 | 
			
		||||
                      y="0"
 | 
			
		||||
                      width="50"
 | 
			
		||||
                      height="100"
 | 
			
		||||
                >
 | 
			
		||||
                    <rect x="49"
 | 
			
		||||
                          width="51"
 | 
			
		||||
                          height="100"
 | 
			
		||||
                    />
 | 
			
		||||
                </mask>
 | 
			
		||||
                <g class="c-cr__cam-fov"
 | 
			
		||||
                   :style="cameraPanStyle"
 | 
			
		||||
                >
 | 
			
		||||
                    <g mask="url(#mask2)">
 | 
			
		||||
                        <rect class="c-cr__cam-fov-r"
 | 
			
		||||
                              x="49"
 | 
			
		||||
                              width="51"
 | 
			
		||||
                              height="100"
 | 
			
		||||
                              :style="cameraFOVStyleRightHalf"
 | 
			
		||||
                        />
 | 
			
		||||
                    </g>
 | 
			
		||||
                    <g mask="url(#mask1)">
 | 
			
		||||
                        <rect class="c-cr__cam-fov-l"
 | 
			
		||||
                              width="51"
 | 
			
		||||
                              height="100"
 | 
			
		||||
                              :style="cameraFOVStyleLeftHalf"
 | 
			
		||||
                        />
 | 
			
		||||
                    </g>
 | 
			
		||||
                </g>
 | 
			
		||||
            </g>
 | 
			
		||||
 | 
			
		||||
            <svg
 | 
			
		||||
                class="c-nsew__ticks"
 | 
			
		||||
                viewBox="0 0 100 100"
 | 
			
		||||
            <!-- Spacecraft body -->
 | 
			
		||||
            <path v-if="hasHeading"
 | 
			
		||||
                  class="c-cr__spacecraft-body"
 | 
			
		||||
                  fill-rule="evenodd"
 | 
			
		||||
                  clip-rule="evenodd"
 | 
			
		||||
                  d="M37 49C35.3431 49 34 50.3431 34 52V82C34 83.6569 35.3431 85 37 85H63C64.6569 85 66 83.6569 66 82V52C66 50.3431 64.6569 49 63 49H37ZM50 52L58 60H55V67H45V60H42L50 52Z"
 | 
			
		||||
                  :style="headingStyle"
 | 
			
		||||
            />
 | 
			
		||||
 | 
			
		||||
            <!-- NSEW and ticks -->
 | 
			
		||||
            <g class="c-cr__nsew"
 | 
			
		||||
               :style="compassRoseStyle"
 | 
			
		||||
            >
 | 
			
		||||
                <polygon
 | 
			
		||||
                    class="c-nsew__tick c-tick-n"
 | 
			
		||||
                    points="50,0 60,10 40,10"
 | 
			
		||||
                <g class="c-cr__ticks-major">
 | 
			
		||||
                    <path d="M50 3L43 10H57L50 3Z" />
 | 
			
		||||
                    <path d="M4 51V49H10V51H4Z"
 | 
			
		||||
                          class="--hide-min"
 | 
			
		||||
                    />
 | 
			
		||||
                    <path d="M49 96V90H51V96H49Z"
 | 
			
		||||
                          class="--hide-min"
 | 
			
		||||
                    />
 | 
			
		||||
                    <path d="M90 49V51H96V49H90Z"
 | 
			
		||||
                          class="--hide-min"
 | 
			
		||||
                    />
 | 
			
		||||
                </g>
 | 
			
		||||
                <g class="c-cr__ticks-minor --hide-small">
 | 
			
		||||
                    <path d="M4 51V49H10V51H4Z" />
 | 
			
		||||
                    <path d="M90 51V49H96V51H90Z" />
 | 
			
		||||
                    <path d="M51 96H49V90H51V96Z" />
 | 
			
		||||
                    <path d="M51 10L49 10V4L51 4V10Z" />
 | 
			
		||||
                </g>
 | 
			
		||||
                <g class="c-cr__nsew-text">
 | 
			
		||||
                    <path :style="cardinalTextRotateW"
 | 
			
		||||
                          class="c-cr__nsew-w --hide-small"
 | 
			
		||||
                          d="M56.7418 45.004H54.1378L52.7238 52.312H52.6958L51.2258 45.004H48.7758L47.3058 52.312H47.2778L45.8638 45.004H43.2598L45.9618 55H48.6078L49.9798 48.112H50.0078L51.3798 55H53.9838L56.7418 45.004Z"
 | 
			
		||||
                    />
 | 
			
		||||
                    <path :style="cardinalTextRotateE"
 | 
			
		||||
                          class="c-cr__nsew-e --hide-small"
 | 
			
		||||
                          d="M46.104 55H54.21V52.76H48.708V50.856H53.608V48.84H48.708V47.09H54.07V45.004H46.104V55Z"
 | 
			
		||||
                    />
 | 
			
		||||
                    <path :style="cardinalTextRotateS"
 | 
			
		||||
                          class="c-cr__nsew-s --hide-small"
 | 
			
		||||
                          d="M45.6531 51.64C45.6671 54.202 47.6971 55.21 49.9931 55.21C52.1911 55.21 54.3471 54.398 54.3471 51.864C54.3471 50.058 52.8911 49.386 51.4491 48.98C49.9931 48.574 48.5511 48.434 48.5511 47.664C48.5511 47.006 49.2511 46.81 49.8111 46.81C50.6091 46.81 51.4631 47.104 51.4211 48.014H54.0251C54.0111 45.76 52.0091 44.794 50.0211 44.794C48.1451 44.794 45.9471 45.648 45.9471 47.832C45.9471 49.666 47.4451 50.31 48.8731 50.716C50.3151 51.122 51.7431 51.29 51.7431 52.172C51.7431 52.914 50.9311 53.194 50.1471 53.194C49.0411 53.194 48.3131 52.816 48.2571 51.64H45.6531Z"
 | 
			
		||||
                    />
 | 
			
		||||
                    <path :style="cardinalTextRotateN"
 | 
			
		||||
                          class="c-cr__nsew-n"
 | 
			
		||||
                          d="M42.5935 60H46.7935V49.32H46.8415L52.7935 60H57.3775V42.864H53.1775V53.424H53.1295L47.1775 42.864H42.5935V60Z"
 | 
			
		||||
                    />
 | 
			
		||||
                </g>
 | 
			
		||||
            </g>
 | 
			
		||||
        </g>
 | 
			
		||||
        <defs>
 | 
			
		||||
            <radialGradient id="paint0_radial"
 | 
			
		||||
                            cx="0"
 | 
			
		||||
                            cy="0"
 | 
			
		||||
                            r="1"
 | 
			
		||||
                            gradientUnits="userSpaceOnUse"
 | 
			
		||||
                            gradientTransform="translate(50 50) rotate(90) scale(50)"
 | 
			
		||||
            >
 | 
			
		||||
                <stop offset="0.751387"
 | 
			
		||||
                      stop-opacity="0"
 | 
			
		||||
                />
 | 
			
		||||
                <rect
 | 
			
		||||
                    class="c-nsew__tick c-tick-e"
 | 
			
		||||
                    x="95"
 | 
			
		||||
                    y="49"
 | 
			
		||||
                    width="5"
 | 
			
		||||
                    height="2"
 | 
			
		||||
                <stop offset="1"
 | 
			
		||||
                      stop-color="white"
 | 
			
		||||
                />
 | 
			
		||||
                <rect
 | 
			
		||||
                    class="c-nsew__tick c-tick-w"
 | 
			
		||||
                    x="0"
 | 
			
		||||
                    y="49"
 | 
			
		||||
                    width="5"
 | 
			
		||||
                    height="2"
 | 
			
		||||
            </radialGradient>
 | 
			
		||||
            <radialGradient id="paint1_radial"
 | 
			
		||||
                            cx="0"
 | 
			
		||||
                            cy="0"
 | 
			
		||||
                            r="1"
 | 
			
		||||
                            gradientUnits="userSpaceOnUse"
 | 
			
		||||
                            gradientTransform="translate(50 -7) rotate(-90) scale(18.5)"
 | 
			
		||||
            >
 | 
			
		||||
                <stop offset="0.716377"
 | 
			
		||||
                      stop-color="#FFCC00"
 | 
			
		||||
                />
 | 
			
		||||
                <rect
 | 
			
		||||
                    class="c-nsew__tick c-tick-s"
 | 
			
		||||
                    x="49"
 | 
			
		||||
                    y="95"
 | 
			
		||||
                    width="2"
 | 
			
		||||
                    height="5"
 | 
			
		||||
                <stop offset="1"
 | 
			
		||||
                      stop-color="#FF9900"
 | 
			
		||||
                      stop-opacity="0"
 | 
			
		||||
                />
 | 
			
		||||
 | 
			
		||||
                <text
 | 
			
		||||
                    class="c-nsew__label c-label-n"
 | 
			
		||||
                    text-anchor="middle"
 | 
			
		||||
                    :transform="northTextTransform"
 | 
			
		||||
                >N</text>
 | 
			
		||||
                <text
 | 
			
		||||
                    class="c-nsew__label c-label-e"
 | 
			
		||||
                    text-anchor="middle"
 | 
			
		||||
                    :transform="eastTextTransform"
 | 
			
		||||
                >E</text>
 | 
			
		||||
                <text
 | 
			
		||||
                    class="c-nsew__label c-label-w"
 | 
			
		||||
                    text-anchor="middle"
 | 
			
		||||
                    :transform="southTextTransform"
 | 
			
		||||
                >W</text>
 | 
			
		||||
                <text
 | 
			
		||||
                    class="c-nsew__label c-label-s"
 | 
			
		||||
                    text-anchor="middle"
 | 
			
		||||
                    :transform="westTextTransform"
 | 
			
		||||
                >S</text>
 | 
			
		||||
            </svg>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div
 | 
			
		||||
            v-if="hasHeading"
 | 
			
		||||
            class="c-spacecraft-body"
 | 
			
		||||
            :style="headingStyle"
 | 
			
		||||
        >
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div
 | 
			
		||||
            v-if="hasSunHeading"
 | 
			
		||||
            class="c-sun"
 | 
			
		||||
            :style="sunHeadingStyle"
 | 
			
		||||
        ></div>
 | 
			
		||||
 | 
			
		||||
        <div
 | 
			
		||||
            class="c-cam-field"
 | 
			
		||||
            :style="cameraPanStyle"
 | 
			
		||||
        >
 | 
			
		||||
            <div class="cam-field-half cam-field-half-l">
 | 
			
		||||
                <div
 | 
			
		||||
                    class="cam-field-area"
 | 
			
		||||
                    :style="cameraFOVStyleLeftHalf"
 | 
			
		||||
                ></div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="cam-field-half cam-field-half-r">
 | 
			
		||||
                <div
 | 
			
		||||
                    class="cam-field-area"
 | 
			
		||||
                    :style="cameraFOVStyleRightHalf"
 | 
			
		||||
                ></div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
            </radialGradient>
 | 
			
		||||
        </defs>
 | 
			
		||||
    </svg>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { rotate } from './utils';
 | 
			
		||||
import { throttle } from 'lodash';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    props: {
 | 
			
		||||
        sizedImageWidth: {
 | 
			
		||||
            type: Number,
 | 
			
		||||
        compassRoseSizingClasses: {
 | 
			
		||||
            type: String,
 | 
			
		||||
            required: true
 | 
			
		||||
        },
 | 
			
		||||
        heading: {
 | 
			
		||||
            type: Number,
 | 
			
		||||
            required: true
 | 
			
		||||
            required: true,
 | 
			
		||||
            default() {
 | 
			
		||||
                return 0;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        sunHeading: {
 | 
			
		||||
            type: Number,
 | 
			
		||||
@@ -178,58 +229,39 @@ export default {
 | 
			
		||||
        },
 | 
			
		||||
        cameraPan: {
 | 
			
		||||
            type: Number,
 | 
			
		||||
            required: true
 | 
			
		||||
            required: true,
 | 
			
		||||
            default() {
 | 
			
		||||
                return 0;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        lockCompass: {
 | 
			
		||||
            type: Boolean,
 | 
			
		||||
        sizedImageDimensions: {
 | 
			
		||||
            type: Object,
 | 
			
		||||
            required: true
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    data() {
 | 
			
		||||
        return {
 | 
			
		||||
            lockCompass: true
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
        compassRoseSizingClasses() {
 | 
			
		||||
            let compassRoseSizingClasses = '';
 | 
			
		||||
            if (this.sizedImageWidth < 300) {
 | 
			
		||||
                compassRoseSizingClasses = '--rose-small --rose-min';
 | 
			
		||||
            } else if (this.sizedImageWidth < 500) {
 | 
			
		||||
                compassRoseSizingClasses = '--rose-small';
 | 
			
		||||
            } else if (this.sizedImageWidth > 1000) {
 | 
			
		||||
                compassRoseSizingClasses = '--rose-max';
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return compassRoseSizingClasses;
 | 
			
		||||
        },
 | 
			
		||||
        compassRoseStyle() {
 | 
			
		||||
            return { transform: `rotate(${ this.north }deg)` };
 | 
			
		||||
        },
 | 
			
		||||
        north() {
 | 
			
		||||
            return this.lockCompass ? rotate(-this.cameraPan) : 0;
 | 
			
		||||
        },
 | 
			
		||||
        northTextTransform() {
 | 
			
		||||
            return this.cardinalPointsTextTransform.north;
 | 
			
		||||
        cardinalTextRotateN() {
 | 
			
		||||
            return { transform: `translateY(-27%) rotate(${ -this.north }deg)` };
 | 
			
		||||
        },
 | 
			
		||||
        eastTextTransform() {
 | 
			
		||||
            return this.cardinalPointsTextTransform.east;
 | 
			
		||||
        cardinalTextRotateS() {
 | 
			
		||||
            return { transform: `translateY(30%) rotate(${ -this.north }deg)` };
 | 
			
		||||
        },
 | 
			
		||||
        southTextTransform() {
 | 
			
		||||
            return this.cardinalPointsTextTransform.south;
 | 
			
		||||
        cardinalTextRotateE() {
 | 
			
		||||
            return { transform: `translateX(30%) rotate(${ -this.north }deg)` };
 | 
			
		||||
        },
 | 
			
		||||
        westTextTransform() {
 | 
			
		||||
            return this.cardinalPointsTextTransform.west;
 | 
			
		||||
        },
 | 
			
		||||
        cardinalPointsTextTransform() {
 | 
			
		||||
            /**
 | 
			
		||||
             * cardinal points text must be rotated
 | 
			
		||||
             * in the opposite direction that north is rotated
 | 
			
		||||
             * to keep text vertically oriented
 | 
			
		||||
             */
 | 
			
		||||
            const rotation = `rotate(${ -this.north })`;
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                north: `translate(50,23) ${ rotation }`,
 | 
			
		||||
                east: `translate(82,50) ${ rotation }`,
 | 
			
		||||
                south: `translate(18,50) ${ rotation }`,
 | 
			
		||||
                west: `translate(50,82) ${ rotation }`
 | 
			
		||||
            };
 | 
			
		||||
        cardinalTextRotateW() {
 | 
			
		||||
            return { transform: `translateX(-30%) rotate(${ -this.north }deg)` };
 | 
			
		||||
        },
 | 
			
		||||
        hasHeading() {
 | 
			
		||||
            return this.heading !== undefined;
 | 
			
		||||
@@ -238,7 +270,7 @@ export default {
 | 
			
		||||
            const rotation = rotate(this.north, this.heading);
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                transform: `translateX(-50%) rotate(${ rotation }deg)`
 | 
			
		||||
                transform: `rotate(${ rotation }deg)`
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        hasSunHeading() {
 | 
			
		||||
@@ -262,20 +294,37 @@ export default {
 | 
			
		||||
        // rotated counter-clockwise from camera pan angle
 | 
			
		||||
        cameraFOVStyleLeftHalf() {
 | 
			
		||||
            return {
 | 
			
		||||
                transform: `translateX(50%) rotate(${ -this.cameraAngleOfView / 2 }deg)`
 | 
			
		||||
                transform: `rotate(${ this.cameraAngleOfView / 2 }deg)`
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
        // right half of camera field of view
 | 
			
		||||
        // rotated clockwise from camera pan angle
 | 
			
		||||
        cameraFOVStyleRightHalf() {
 | 
			
		||||
            return {
 | 
			
		||||
                transform: `translateX(-50%) rotate(${ this.cameraAngleOfView / 2 }deg)`
 | 
			
		||||
                transform: `rotate(${ -this.cameraAngleOfView / 2 }deg)`
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    watch: {
 | 
			
		||||
        sizedImageDimensions() {
 | 
			
		||||
            this.debounceResizeSvg();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
        this.debounceResizeSvg = throttle(this.resizeSvg, 100);
 | 
			
		||||
 | 
			
		||||
        this.$nextTick(() => {
 | 
			
		||||
            this.debounceResizeSvg();
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        resizeSvg() {
 | 
			
		||||
            const svg = this.$refs.compassRoseSvg;
 | 
			
		||||
            svg.setAttribute('width', this.$refs.compassRoseWrapper.clientWidth);
 | 
			
		||||
            svg.setAttribute('height', this.$refs.compassRoseWrapper.clientHeight);
 | 
			
		||||
        },
 | 
			
		||||
        toggleLockCompass() {
 | 
			
		||||
            this.$emit('toggle-lock-compass');
 | 
			
		||||
            this.lockCompass = !this.lockCompass;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -12,9 +12,8 @@ $elemBg: rgba(black, 0.7);
 | 
			
		||||
.c-compass {
 | 
			
		||||
    pointer-events: none; // This allows the image element to receive a browser-level context click
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    left: 50%;
 | 
			
		||||
    top: 50%;
 | 
			
		||||
    transform: translate(-50%, -50%);
 | 
			
		||||
    left: 0;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    z-index: 1;
 | 
			
		||||
    @include userSelectNone;
 | 
			
		||||
}
 | 
			
		||||
@@ -81,114 +80,55 @@ $elemBg: rgba(black, 0.7);
 | 
			
		||||
        transform: translateX(-50%);
 | 
			
		||||
        z-index: 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/***************************** COMPASS DIRECTIONS */
 | 
			
		||||
.c-nsew {
 | 
			
		||||
/***************************** COMPASS SVG */
 | 
			
		||||
.c-compass-rose-svg {
 | 
			
		||||
    $color: $interfaceKeyColor;
 | 
			
		||||
    $inset: 5%;
 | 
			
		||||
    $tickHeightPerc: 15%;
 | 
			
		||||
    text-shadow: black 0 0 10px;
 | 
			
		||||
    top: $inset;
 | 
			
		||||
    right: $inset;
 | 
			
		||||
    bottom: $inset;
 | 
			
		||||
    left: $inset;
 | 
			
		||||
    z-index: 3;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    top: 0; left: 0;
 | 
			
		||||
 | 
			
		||||
    &__tick,
 | 
			
		||||
    &__label {
 | 
			
		||||
        fill: $color;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &__minor-ticks {
 | 
			
		||||
        opacity: 0.5;
 | 
			
		||||
    g, path, rect {
 | 
			
		||||
        // In an SVG, rotation occurs about the center of the SVG, not the element
 | 
			
		||||
        transform-origin: center;
 | 
			
		||||
        transform: rotate(45deg);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &__label {
 | 
			
		||||
        dominant-baseline: central;
 | 
			
		||||
        font-size: 1.25em;
 | 
			
		||||
        font-weight: bold;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .c-label-n {
 | 
			
		||||
        font-size: 2em;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/***************************** CAMERA FIELD ANGLE */
 | 
			
		||||
.c-cam-field {
 | 
			
		||||
    $color: white;
 | 
			
		||||
    opacity: 0.3;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    right: 0;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    z-index: 2;
 | 
			
		||||
 | 
			
		||||
    .cam-field-half {
 | 
			
		||||
        top: 0;
 | 
			
		||||
        right: 0;
 | 
			
		||||
        bottom: 0;
 | 
			
		||||
        left: 0;
 | 
			
		||||
 | 
			
		||||
        .cam-field-area {
 | 
			
		||||
            background: $color;
 | 
			
		||||
            top: -30%;
 | 
			
		||||
            right: 0;
 | 
			
		||||
            bottom: -30%;
 | 
			
		||||
            left: 0;
 | 
			
		||||
    .c-cr {
 | 
			
		||||
        &__bg {
 | 
			
		||||
            fill: #000;
 | 
			
		||||
            opacity: 0.8;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // clip-paths overlap a bit to avoid a gap between halves
 | 
			
		||||
        &-l {
 | 
			
		||||
            clip-path: polygon(0 0, 50.5% 0, 50.5% 100%, 0 100%);
 | 
			
		||||
 | 
			
		||||
            .cam-field-area {
 | 
			
		||||
                transform-origin: left center;
 | 
			
		||||
            }
 | 
			
		||||
        &__edge {
 | 
			
		||||
            opacity: 0.1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &-r {
 | 
			
		||||
            clip-path: polygon(49.5% 0, 100% 0, 100% 100%, 49.5% 100%);
 | 
			
		||||
 | 
			
		||||
            .cam-field-area {
 | 
			
		||||
                transform-origin: right center;
 | 
			
		||||
            }
 | 
			
		||||
        &__sun {
 | 
			
		||||
            opacity: 0.7;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/***************************** SPACECRAFT BODY */
 | 
			
		||||
.c-spacecraft-body {
 | 
			
		||||
    $color: $interfaceKeyColor;
 | 
			
		||||
    $s: 30%;
 | 
			
		||||
    background: $color;
 | 
			
		||||
    border-radius: 3px;
 | 
			
		||||
    height: $s;
 | 
			
		||||
    width: $s;
 | 
			
		||||
    left: 50%;
 | 
			
		||||
    top: 50%;
 | 
			
		||||
    opacity: 0.4;
 | 
			
		||||
    transform-origin: center top;
 | 
			
		||||
    transform: translateX(-50%); // center by default, overridden by CompassRose.vue / headingStyle()
 | 
			
		||||
        &__cam-fov-l,
 | 
			
		||||
        &__cam-fov-r {
 | 
			
		||||
            // Cam FOV indication
 | 
			
		||||
            opacity: 0.2;
 | 
			
		||||
            fill: #fff;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    &:before {
 | 
			
		||||
        // Direction arrow
 | 
			
		||||
        $color: rgba(black, 0.5);
 | 
			
		||||
        $arwPointerY: 60%;
 | 
			
		||||
        $arwBodyOffset: 25%;
 | 
			
		||||
        background: $color;
 | 
			
		||||
        content: '';
 | 
			
		||||
        display: block;
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        top: 10%;
 | 
			
		||||
        right: 20%;
 | 
			
		||||
        bottom: 50%;
 | 
			
		||||
        left: 20%;
 | 
			
		||||
        clip-path: polygon(50% 0, 100% $arwPointerY, 100%-$arwBodyOffset $arwPointerY, 100%-$arwBodyOffset 100%, $arwBodyOffset 100%, $arwBodyOffset $arwPointerY, 0 $arwPointerY);
 | 
			
		||||
        &__nsew-text,
 | 
			
		||||
        &__spacecraft-body,
 | 
			
		||||
        &__ticks-major,
 | 
			
		||||
        &__ticks-minor {
 | 
			
		||||
            fill: $color;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &__ticks-minor {
 | 
			
		||||
            opacity: 0.5;
 | 
			
		||||
            transform: rotate(45deg);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &__spacecraft-body {
 | 
			
		||||
            opacity: 0.3;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -196,32 +136,28 @@ $elemBg: rgba(black, 0.7);
 | 
			
		||||
.w-direction-rose {
 | 
			
		||||
    $s: 10%;
 | 
			
		||||
    $m: 2%;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    pointer-events: all;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    bottom: $m;
 | 
			
		||||
    left: $m;
 | 
			
		||||
    width: $s;
 | 
			
		||||
    padding-top: $s;
 | 
			
		||||
    z-index: 2;
 | 
			
		||||
 | 
			
		||||
    &.--rose-min {
 | 
			
		||||
        $s: 30px;
 | 
			
		||||
        width: $s;
 | 
			
		||||
        padding-top: $s;
 | 
			
		||||
        .--hide-min {
 | 
			
		||||
            display: none;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &.--rose-small {
 | 
			
		||||
        .c-nsew__minor-ticks,
 | 
			
		||||
        .c-tick-w,
 | 
			
		||||
        .c-tick-s,
 | 
			
		||||
        .c-tick-e,
 | 
			
		||||
        .c-label-w,
 | 
			
		||||
        .c-label-s,
 | 
			
		||||
        .c-label-e {
 | 
			
		||||
        .--hide-small {
 | 
			
		||||
            display: none;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .c-label-n {
 | 
			
		||||
            font-size: 2.5em;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &.--rose-max {
 | 
			
		||||
@@ -230,44 +166,3 @@ $elemBg: rgba(black, 0.7);
 | 
			
		||||
        padding-top: $s;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.c-direction-rose {
 | 
			
		||||
    $c2: rgba(white, 0.1);
 | 
			
		||||
    background: $elemBg;
 | 
			
		||||
    background-image: radial-gradient(circle closest-side, transparent, transparent 80%, $c2);
 | 
			
		||||
    transform-origin: 0 0;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    right: 0;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    clip-path: circle(50% at 50% 50%);
 | 
			
		||||
    border-radius: 100%;
 | 
			
		||||
    pointer-events: all;
 | 
			
		||||
 | 
			
		||||
    svg, div {
 | 
			
		||||
        position: absolute;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Sun
 | 
			
		||||
    .c-sun {
 | 
			
		||||
        top: 0;
 | 
			
		||||
        right: 0;
 | 
			
		||||
        bottom: 0;
 | 
			
		||||
        left: 0;
 | 
			
		||||
 | 
			
		||||
        &:before {
 | 
			
		||||
            $s: 35%;
 | 
			
		||||
            @include sun();
 | 
			
		||||
            content: '';
 | 
			
		||||
            display: block;
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            opacity: 0.7;
 | 
			
		||||
            top: 0;
 | 
			
		||||
            left: 50%;
 | 
			
		||||
            height: $s;
 | 
			
		||||
            width: $s;
 | 
			
		||||
            transform: translate(-50%, -60%);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -55,28 +55,33 @@
 | 
			
		||||
                ></a>
 | 
			
		||||
            </span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="c-imagery__main-image__bg"
 | 
			
		||||
        <div ref="imageBG"
 | 
			
		||||
             class="c-imagery__main-image__bg"
 | 
			
		||||
             :class="{'paused unnsynced': isPaused,'stale':false }"
 | 
			
		||||
        >
 | 
			
		||||
            <img
 | 
			
		||||
                ref="focusedImage"
 | 
			
		||||
                class="c-imagery__main-image__image js-imageryView-image"
 | 
			
		||||
                :src="imageUrl"
 | 
			
		||||
                :style="{
 | 
			
		||||
                    'filter': `brightness(${filters.brightness}%) contrast(${filters.contrast}%)`
 | 
			
		||||
                }"
 | 
			
		||||
                :data-openmct-image-timestamp="time"
 | 
			
		||||
                :data-openmct-object-keystring="keyString"
 | 
			
		||||
            <div class="image-wrapper"
 | 
			
		||||
                 :style="{
 | 
			
		||||
                     'width': `${sizedImageDimensions.width}px`,
 | 
			
		||||
                     'height': `${sizedImageDimensions.height}px`
 | 
			
		||||
                 }"
 | 
			
		||||
            >
 | 
			
		||||
            <Compass
 | 
			
		||||
                v-if="shouldDisplayCompass"
 | 
			
		||||
                :container-width="imageContainerWidth"
 | 
			
		||||
                :container-height="imageContainerHeight"
 | 
			
		||||
                :natural-aspect-ratio="focusedImageNaturalAspectRatio"
 | 
			
		||||
                :image="focusedImage"
 | 
			
		||||
                :lock-compass="lockCompass"
 | 
			
		||||
                @toggle-lock-compass="toggleLockCompass"
 | 
			
		||||
            />
 | 
			
		||||
                <img ref="focusedImage"
 | 
			
		||||
                     class="c-imagery__main-image__image js-imageryView-image"
 | 
			
		||||
                     :src="imageUrl"
 | 
			
		||||
                     :style="{
 | 
			
		||||
                         'filter': `brightness(${filters.brightness}%) contrast(${filters.contrast}%)`
 | 
			
		||||
                     }"
 | 
			
		||||
                     :data-openmct-image-timestamp="time"
 | 
			
		||||
                     :data-openmct-object-keystring="keyString"
 | 
			
		||||
                >
 | 
			
		||||
                <Compass
 | 
			
		||||
                    v-if="shouldDisplayCompass"
 | 
			
		||||
                    :compass-rose-sizing-classes="compassRoseSizingClasses"
 | 
			
		||||
                    :image="focusedImage"
 | 
			
		||||
                    :natural-aspect-ratio="focusedImageNaturalAspectRatio"
 | 
			
		||||
                    :sized-image-dimensions="sizedImageDimensions"
 | 
			
		||||
                />
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="c-local-controls c-local-controls--show-on-hover c-imagery__prev-next-buttons">
 | 
			
		||||
            <button class="c-nav c-nav--prev"
 | 
			
		||||
@@ -224,6 +229,18 @@ export default {
 | 
			
		||||
        };
 | 
			
		||||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
        compassRoseSizingClasses() {
 | 
			
		||||
            let compassRoseSizingClasses = '';
 | 
			
		||||
            if (this.sizedImageDimensions.width < 300) {
 | 
			
		||||
                compassRoseSizingClasses = '--rose-small --rose-min';
 | 
			
		||||
            } else if (this.sizedImageDimensions.width < 500) {
 | 
			
		||||
                compassRoseSizingClasses = '--rose-small';
 | 
			
		||||
            } else if (this.sizedImageDimensions.width > 1000) {
 | 
			
		||||
                compassRoseSizingClasses = '--rose-max';
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return compassRoseSizingClasses;
 | 
			
		||||
        },
 | 
			
		||||
        time() {
 | 
			
		||||
            return this.formatTime(this.focusedImage);
 | 
			
		||||
        },
 | 
			
		||||
@@ -347,6 +364,20 @@ export default {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return isFresh;
 | 
			
		||||
        },
 | 
			
		||||
        sizedImageDimensions() {
 | 
			
		||||
            let sizedImageDimensions = {};
 | 
			
		||||
            if ((this.imageContainerWidth / this.imageContainerHeight) > this.focusedImageNaturalAspectRatio) {
 | 
			
		||||
                // container is wider than image
 | 
			
		||||
                sizedImageDimensions.width = this.imageContainerHeight * this.focusedImageNaturalAspectRatio;
 | 
			
		||||
                sizedImageDimensions.height = this.imageContainerHeight;
 | 
			
		||||
            } else {
 | 
			
		||||
                // container is taller than image
 | 
			
		||||
                sizedImageDimensions.width = this.imageContainerWidth;
 | 
			
		||||
                sizedImageDimensions.height = this.imageContainerWidth * this.focusedImageNaturalAspectRatio;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return sizedImageDimensions;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    watch: {
 | 
			
		||||
@@ -395,7 +426,7 @@ export default {
 | 
			
		||||
        _.debounce(this.resizeImageContainer, 400);
 | 
			
		||||
 | 
			
		||||
        this.imageContainerResizeObserver = new ResizeObserver(this.resizeImageContainer);
 | 
			
		||||
        this.imageContainerResizeObserver.observe(this.$refs.focusedImage);
 | 
			
		||||
        this.imageContainerResizeObserver.observe(this.$refs.imageBG);
 | 
			
		||||
 | 
			
		||||
        // For adjusting scroll bar size and position when resizing thumbs wrapper
 | 
			
		||||
        this.handleScroll = _.debounce(this.handleScroll, SCROLL_LATENCY);
 | 
			
		||||
@@ -833,12 +864,12 @@ export default {
 | 
			
		||||
            }, { once: true });
 | 
			
		||||
        },
 | 
			
		||||
        resizeImageContainer() {
 | 
			
		||||
            if (this.$refs.focusedImage.clientWidth !== this.imageContainerWidth) {
 | 
			
		||||
                this.imageContainerWidth = this.$refs.focusedImage.clientWidth;
 | 
			
		||||
            if (this.$refs.imageBG.clientWidth !== this.imageContainerWidth) {
 | 
			
		||||
                this.imageContainerWidth = this.$refs.imageBG.clientWidth;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (this.$refs.focusedImage.clientHeight !== this.imageContainerHeight) {
 | 
			
		||||
                this.imageContainerHeight = this.$refs.focusedImage.clientHeight;
 | 
			
		||||
            if (this.$refs.imageBG.clientHeight !== this.imageContainerHeight) {
 | 
			
		||||
                this.imageContainerHeight = this.$refs.imageBG.clientHeight;
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        handleThumbWindowResizeStart() {
 | 
			
		||||
@@ -858,9 +889,6 @@ export default {
 | 
			
		||||
            this.$nextTick(() => {
 | 
			
		||||
                this.resizingWindow = false;
 | 
			
		||||
            });
 | 
			
		||||
        },
 | 
			
		||||
        toggleLockCompass() {
 | 
			
		||||
            this.lockCompass = !this.lockCompass;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,9 @@
 | 
			
		||||
        &__bg {
 | 
			
		||||
            background-color: $colorPlotBg;
 | 
			
		||||
            border: 1px solid transparent;
 | 
			
		||||
            display: flex;
 | 
			
		||||
            align-items: center;
 | 
			
		||||
            justify-content: center;
 | 
			
		||||
            flex: 1 1 auto;
 | 
			
		||||
            height: 0;
 | 
			
		||||
 | 
			
		||||
@@ -33,7 +36,6 @@
 | 
			
		||||
        &__image {
 | 
			
		||||
            height: 100%;
 | 
			
		||||
            width: 100%;
 | 
			
		||||
            object-fit: contain;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -192,6 +194,10 @@
 | 
			
		||||
                margin-right: $interiorMarginSm;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .s-status-taking-snapshot & {
 | 
			
		||||
            display: none;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &__lc {
 | 
			
		||||
@@ -273,6 +279,10 @@
 | 
			
		||||
            content: $glyph-icon-play;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .s-status-taking-snapshot & {
 | 
			
		||||
        display: none;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.c-imagery__prev-next-buttons {
 | 
			
		||||
@@ -287,6 +297,10 @@
 | 
			
		||||
    .c-nav {
 | 
			
		||||
        pointer-events: all;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .s-status-taking-snapshot & {
 | 
			
		||||
        display: none;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.c-nav {
 | 
			
		||||
 
 | 
			
		||||
@@ -101,7 +101,6 @@ export default {
 | 
			
		||||
                buttons: [
 | 
			
		||||
                    {
 | 
			
		||||
                        label: 'Cancel',
 | 
			
		||||
                        emphasis: true,
 | 
			
		||||
                        callback: () => {
 | 
			
		||||
                            painterroInstance.dismiss();
 | 
			
		||||
                            annotateOverlay.dismiss();
 | 
			
		||||
@@ -109,6 +108,7 @@ export default {
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        label: 'Save',
 | 
			
		||||
                        emphasis: true,
 | 
			
		||||
                        callback: () => {
 | 
			
		||||
                            painterroInstance.save((snapshotObject) => {
 | 
			
		||||
                                annotateOverlay.dismiss();
 | 
			
		||||
 
 | 
			
		||||
@@ -7,10 +7,10 @@
 | 
			
		||||
                    <div class="c-object-label__type-icon icon-camera"></div>
 | 
			
		||||
                    <div class="c-object-label__name">
 | 
			
		||||
                        Notebook Snapshots
 | 
			
		||||
                        <span v-if="snapshots.length"
 | 
			
		||||
                              class="l-browse-bar__object-details"
 | 
			
		||||
                        > {{ snapshots.length }} of {{ getNotebookSnapshotMaxCount() }}
 | 
			
		||||
                        </span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div v-if="snapshots.length"
 | 
			
		||||
                         class="l-browse-bar__object-details"
 | 
			
		||||
                    >{{ snapshots.length }} of {{ getNotebookSnapshotMaxCount() }}
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <PopupMenu v-if="snapshots.length > 0"
 | 
			
		||||
 
 | 
			
		||||
@@ -4,8 +4,10 @@
 | 
			
		||||
        <div class="l-browse-bar__start">
 | 
			
		||||
            <div class="l-browse-bar__object-name--w">
 | 
			
		||||
                <span class="c-object-label l-browse-bar__object-name"
 | 
			
		||||
                    v-bind:class="cssClass"
 | 
			
		||||
                >
 | 
			
		||||
                    <span class="c-object-label__type-icon"
 | 
			
		||||
                          v-bind:class="cssClass"
 | 
			
		||||
                    ></span>
 | 
			
		||||
                    <span class="c-object-label__name">{{ name }}</span>
 | 
			
		||||
                </span>
 | 
			
		||||
            </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -49,10 +49,6 @@ describe('the plugin', function () {
 | 
			
		||||
        child.style.height = '480px';
 | 
			
		||||
        element.appendChild(child);
 | 
			
		||||
 | 
			
		||||
        openmct.time.timeSystem('utc', {
 | 
			
		||||
            start: 1597160002854,
 | 
			
		||||
            end: 1597181232854
 | 
			
		||||
        });
 | 
			
		||||
        openmct.on('start', done);
 | 
			
		||||
        openmct.start(appHolder);
 | 
			
		||||
    });
 | 
			
		||||
@@ -105,6 +101,11 @@ describe('the plugin', function () {
 | 
			
		||||
        let planView;
 | 
			
		||||
 | 
			
		||||
        beforeEach(() => {
 | 
			
		||||
            openmct.time.timeSystem('utc', {
 | 
			
		||||
                start: 1597160002854,
 | 
			
		||||
                end: 1597181232854
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            planDomainObject = {
 | 
			
		||||
                identifier: {
 | 
			
		||||
                    key: 'test-object',
 | 
			
		||||
 
 | 
			
		||||
@@ -427,9 +427,12 @@ export default {
 | 
			
		||||
                this.skipReloadOnInteraction = false;
 | 
			
		||||
                this.loadMoreData(newRange, true);
 | 
			
		||||
            } else {
 | 
			
		||||
                // If we're not panning or zooming (time conductor and plot x-axis times are not out of sync)
 | 
			
		||||
                // Drop any data that is more than 1x (max-min) before min.
 | 
			
		||||
                // Limit these purges to once a second.
 | 
			
		||||
                if (!this.nextPurge || this.nextPurge < Date.now()) {
 | 
			
		||||
                const isPanningOrZooming = this.isTimeOutOfSync;
 | 
			
		||||
                const purgeRecords = !isPanningOrZooming && (!this.nextPurge || (this.nextPurge < Date.now()));
 | 
			
		||||
                if (purgeRecords) {
 | 
			
		||||
                    const keepRange = {
 | 
			
		||||
                        min: newRange.min - (newRange.max - newRange.min),
 | 
			
		||||
                        max: newRange.max
 | 
			
		||||
 
 | 
			
		||||
@@ -279,6 +279,10 @@ describe("the plugin", function () {
 | 
			
		||||
        let plotView;
 | 
			
		||||
 | 
			
		||||
        beforeEach(() => {
 | 
			
		||||
            openmct.time.timeSystem("utc", {
 | 
			
		||||
                start: 0,
 | 
			
		||||
                end: 4
 | 
			
		||||
            });
 | 
			
		||||
            const getFunc = openmct.$injector.get;
 | 
			
		||||
            spyOn(openmct.$injector, "get")
 | 
			
		||||
                .withArgs("exportImageService").and.returnValue({
 | 
			
		||||
 
 | 
			
		||||
@@ -65,8 +65,7 @@ define([
 | 
			
		||||
    './interceptors/plugin',
 | 
			
		||||
    './performanceIndicator/plugin',
 | 
			
		||||
    './CouchDBSearchFolder/plugin',
 | 
			
		||||
    './timeline/plugin',
 | 
			
		||||
    './codeWalkthrough/plugin'
 | 
			
		||||
    './timeline/plugin'
 | 
			
		||||
], function (
 | 
			
		||||
    _,
 | 
			
		||||
    UTCTimeSystem,
 | 
			
		||||
@@ -112,8 +111,7 @@ define([
 | 
			
		||||
    ObjectInterceptors,
 | 
			
		||||
    PerformanceIndicator,
 | 
			
		||||
    CouchDBSearchFolder,
 | 
			
		||||
    Timeline,
 | 
			
		||||
    codeWalkthroughPlugin
 | 
			
		||||
    Timeline
 | 
			
		||||
) {
 | 
			
		||||
    const bundleMap = {
 | 
			
		||||
        LocalStorage: 'platform/persistence/local',
 | 
			
		||||
@@ -214,7 +212,6 @@ define([
 | 
			
		||||
    plugins.PerformanceIndicator = PerformanceIndicator.default;
 | 
			
		||||
    plugins.CouchDBSearchFolder = CouchDBSearchFolder.default;
 | 
			
		||||
    plugins.Timeline = Timeline.default;
 | 
			
		||||
    plugins.CodeWalkthrough = codeWalkthroughPlugin.default;
 | 
			
		||||
 | 
			
		||||
    return plugins;
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -121,6 +121,11 @@ describe("the plugin", () => {
 | 
			
		||||
        let tableInstance;
 | 
			
		||||
 | 
			
		||||
        beforeEach(() => {
 | 
			
		||||
            openmct.time.timeSystem('utc', {
 | 
			
		||||
                start: 0,
 | 
			
		||||
                end: 4
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            testTelemetryObject = {
 | 
			
		||||
                identifier: {
 | 
			
		||||
                    namespace: "",
 | 
			
		||||
 
 | 
			
		||||
@@ -85,7 +85,7 @@
 | 
			
		||||
                <button
 | 
			
		||||
                    ref="startOffset"
 | 
			
		||||
                    class="c-button c-conductor__delta-button"
 | 
			
		||||
                    @click="showTimePopupStart"
 | 
			
		||||
                    @click.prevent="showTimePopupStart"
 | 
			
		||||
                >
 | 
			
		||||
                    {{ offsets.start }}
 | 
			
		||||
                </button>
 | 
			
		||||
@@ -133,7 +133,7 @@
 | 
			
		||||
                <button
 | 
			
		||||
                    ref="endOffset"
 | 
			
		||||
                    class="c-button c-conductor__delta-button"
 | 
			
		||||
                    @click="showTimePopupEnd"
 | 
			
		||||
                    @click.prevent="showTimePopupEnd"
 | 
			
		||||
                >
 | 
			
		||||
                    {{ offsets.end }}
 | 
			
		||||
                </button>
 | 
			
		||||
 
 | 
			
		||||
@@ -237,7 +237,6 @@
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Prototype
 | 
			
		||||
[class^='pr-tc-input-menu'] {
 | 
			
		||||
    // Uses ^= here to target both start and end menus
 | 
			
		||||
    background: $colorBodyBg;
 | 
			
		||||
@@ -247,8 +246,7 @@
 | 
			
		||||
    grid-column-gap: 3px;
 | 
			
		||||
    grid-row-gap: 4px;
 | 
			
		||||
    align-items: start;
 | 
			
		||||
 | 
			
		||||
    filter: brightness(1.4);
 | 
			
		||||
    filter: $filterMenu;
 | 
			
		||||
    box-shadow: $shdwMenu;
 | 
			
		||||
    padding: $interiorMargin;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
 
 | 
			
		||||
@@ -237,11 +237,12 @@ $shdwSelect: rgba(black, 0.5) 0 0.5px 3px;
 | 
			
		||||
$controlDisabledOpacity: 0.2;
 | 
			
		||||
 | 
			
		||||
// Menus
 | 
			
		||||
$colorMenuBg: pullForward($colorBodyBg, 15%);
 | 
			
		||||
$colorMenuFg: pullForward($colorBodyFg, 30%);
 | 
			
		||||
$colorMenuIc: pullForward($colorKey, 15%);
 | 
			
		||||
$colorMenuHovBg: $colorMenuIc;
 | 
			
		||||
$colorMenuHovFg: pullForward($colorMenuFg, 10%);
 | 
			
		||||
$colorMenuBg: $colorBodyBg;
 | 
			
		||||
$colorMenuFg: $colorBodyFg;
 | 
			
		||||
$colorMenuIc: $colorKey;
 | 
			
		||||
$filterMenu:  brightness(1.4);
 | 
			
		||||
$colorMenuHovBg: rgba($colorKey, 0.5);
 | 
			
		||||
$colorMenuHovFg: $colorBodyFgEm;
 | 
			
		||||
$colorMenuHovIc: $colorMenuHovFg;
 | 
			
		||||
$colorMenuElementHilite: pullForward($colorMenuBg, 10%);
 | 
			
		||||
$shdwMenu: rgba(black, 0.5) 0 1px 5px;
 | 
			
		||||
 
 | 
			
		||||
@@ -241,11 +241,12 @@ $shdwSelect: rgba(black, 0.5) 0 0.5px 3px;
 | 
			
		||||
$controlDisabledOpacity: 0.2;
 | 
			
		||||
 | 
			
		||||
// Menus
 | 
			
		||||
$colorMenuBg: pullForward($colorBodyBg, 15%);
 | 
			
		||||
$colorMenuFg: pullForward($colorBodyFg, 30%);
 | 
			
		||||
$colorMenuIc: pullForward($colorKey, 15%);
 | 
			
		||||
$colorMenuHovBg: $colorMenuIc;
 | 
			
		||||
$colorMenuHovFg: pullForward($colorMenuFg, 10%);
 | 
			
		||||
$colorMenuBg: $colorBodyBg;
 | 
			
		||||
$colorMenuFg: $colorBodyFg;
 | 
			
		||||
$colorMenuIc: $colorKey;
 | 
			
		||||
$filterMenu:  brightness(1.4);
 | 
			
		||||
$colorMenuHovBg: rgba($colorKey, 0.5);
 | 
			
		||||
$colorMenuHovFg: $colorBodyFgEm;
 | 
			
		||||
$colorMenuHovIc: $colorMenuHovFg;
 | 
			
		||||
$colorMenuElementHilite: pullForward($colorMenuBg, 10%);
 | 
			
		||||
$shdwMenu: rgba(black, 0.5) 0 1px 5px;
 | 
			
		||||
 
 | 
			
		||||
@@ -237,9 +237,10 @@ $shdwSelect: none;
 | 
			
		||||
$controlDisabledOpacity: 0.3;
 | 
			
		||||
 | 
			
		||||
// Menus
 | 
			
		||||
$colorMenuBg: pushBack($colorBodyBg, 10%);
 | 
			
		||||
$colorMenuFg: pullForward($colorMenuBg, 70%);
 | 
			
		||||
$colorMenuBg: $colorBodyBg;
 | 
			
		||||
$colorMenuFg: $colorBodyFg;
 | 
			
		||||
$colorMenuIc: $colorKey;
 | 
			
		||||
$filterMenu: brightness(0.95);
 | 
			
		||||
$colorMenuHovBg: $colorMenuIc;
 | 
			
		||||
$colorMenuHovFg: $colorMenuBg;
 | 
			
		||||
$colorMenuHovIc: $colorMenuBg;
 | 
			
		||||
 
 | 
			
		||||
@@ -458,6 +458,7 @@ select {
 | 
			
		||||
@mixin menuOuter() {
 | 
			
		||||
    border-radius: $basicCr;
 | 
			
		||||
    background: $colorMenuBg;
 | 
			
		||||
    filter: $filterMenu;
 | 
			
		||||
    text-shadow: $shdwMenuText;
 | 
			
		||||
    padding: $interiorMarginSm;
 | 
			
		||||
    box-shadow: $shdwMenu;
 | 
			
		||||
 
 | 
			
		||||
@@ -490,7 +490,7 @@
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#snap-annotation {
 | 
			
		||||
    $m: $interiorMargin;
 | 
			
		||||
    $m: 0; //$interiorMargin;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
@@ -514,21 +514,32 @@
 | 
			
		||||
    // Holds tool buttons, color selectors, etc.
 | 
			
		||||
    $h: 22px;
 | 
			
		||||
    $fs: 0.8rem;
 | 
			
		||||
    $m: $interiorMarginSm;
 | 
			
		||||
 | 
			
		||||
    display: flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    height: $h + ($m * 2) !important;
 | 
			
		||||
    margin-bottom: $interiorMarginLg;
 | 
			
		||||
    order: 1;
 | 
			
		||||
    flex: 0 0 auto;
 | 
			
		||||
    height: auto;
 | 
			
		||||
    background-color: transparent !important;
 | 
			
		||||
    margin-bottom: $interiorMargin;
 | 
			
		||||
    padding: $interiorMarginSm;
 | 
			
		||||
 | 
			
		||||
    > div > span {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        font-size: $fs;
 | 
			
		||||
    > div {
 | 
			
		||||
        display: contents;
 | 
			
		||||
 | 
			
		||||
        > * + * { margin-left: $interiorMargin !important; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .ptro-tool-controls {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        margin-left: $interiorMarginLg !important;
 | 
			
		||||
 | 
			
		||||
        > * + * {
 | 
			
		||||
            margin-left: $interiorMargin !important;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    > div,
 | 
			
		||||
    > div > span,
 | 
			
		||||
    .ptro-icon-btn,
 | 
			
		||||
    .ptro-named-btn,
 | 
			
		||||
    .ptro-color-btn,
 | 
			
		||||
@@ -538,27 +549,18 @@
 | 
			
		||||
    .tool-controls,
 | 
			
		||||
    .ptro-input {
 | 
			
		||||
        // Lot of resets for crappy CSS in Painterro
 | 
			
		||||
        &:first-child {
 | 
			
		||||
            margin-left: 0 !important;
 | 
			
		||||
        }
 | 
			
		||||
        display: inline-block;
 | 
			
		||||
        font-family: inherit;
 | 
			
		||||
        font-size: $fs !important;
 | 
			
		||||
        height: $h !important;
 | 
			
		||||
        margin: 0 0 0 5px;
 | 
			
		||||
        margin: 0;
 | 
			
		||||
        position: relative;
 | 
			
		||||
        width: auto !important;
 | 
			
		||||
        line-height: $h !important;
 | 
			
		||||
        top: auto;
 | 
			
		||||
        right: auto;
 | 
			
		||||
        bottom: auto;
 | 
			
		||||
        left: auto;
 | 
			
		||||
        vertical-align: top;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .ptro-tool-ctl-name {
 | 
			
		||||
        border-radius: 0;
 | 
			
		||||
        background: none;
 | 
			
		||||
        color: $colorBodyFg;
 | 
			
		||||
        top: auto;
 | 
			
		||||
        font-family: inherit;
 | 
			
		||||
        padding: 0;
 | 
			
		||||
@@ -568,13 +570,15 @@
 | 
			
		||||
        width: $h !important;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .ptro-check,
 | 
			
		||||
    .ptro-color-control,
 | 
			
		||||
    .ptro-icon-btn,
 | 
			
		||||
    .ptro-named-btn {
 | 
			
		||||
        // Buttons in toolbar. Why the f* they're named like this is a mystery
 | 
			
		||||
        background-color: $colorBtnBg;
 | 
			
		||||
        color: $colorBtnFg;
 | 
			
		||||
        padding: 0 $interiorMargin;
 | 
			
		||||
        // Buttons in toolbar
 | 
			
		||||
        border-radius: $smallCr;
 | 
			
		||||
        box-shadow: rgba($colorBtnFg, 0.3) 0 0 0 1px;
 | 
			
		||||
        color: $colorBtnFg !important;
 | 
			
		||||
        padding: 1px $interiorMargin;
 | 
			
		||||
 | 
			
		||||
        &:hover {
 | 
			
		||||
            background: $colorBtnBgHov;
 | 
			
		||||
@@ -588,6 +592,13 @@
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .ptro-color-control,
 | 
			
		||||
    .ptro-icon-btn,
 | 
			
		||||
    .ptro-named-btn {
 | 
			
		||||
        // Buttons in toolbar
 | 
			
		||||
        background-color: $colorBtnBg;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .ptro-color-active-control {
 | 
			
		||||
        background: $colorBtnMajorBg  !important;
 | 
			
		||||
        color: $colorBtnMajorFg !important;
 | 
			
		||||
 
 | 
			
		||||
@@ -17,15 +17,7 @@
 | 
			
		||||
        <div v-if="singleSelectNonObject"
 | 
			
		||||
             class="c-inspector__selected c-inspector__selected--non-domain-object  c-object-label"
 | 
			
		||||
        >
 | 
			
		||||
            <span class="c-object-label__type-icon"
 | 
			
		||||
                  :class="typeCssClass"
 | 
			
		||||
            ></span>
 | 
			
		||||
            <span v-if="!activity"
 | 
			
		||||
                  class="c-object-label__name"
 | 
			
		||||
            >Layout Object</span>
 | 
			
		||||
            <span v-else
 | 
			
		||||
                  class="c-object-label__name"
 | 
			
		||||
            >{{ activity.name }}</span>
 | 
			
		||||
            <span class="c-object-label__name">Layout Object</span>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div v-if="multiSelect"
 | 
			
		||||
 
 | 
			
		||||
@@ -32,6 +32,7 @@
 | 
			
		||||
 | 
			
		||||
        &__scrollable {
 | 
			
		||||
            overflow: auto;
 | 
			
		||||
            padding-right: $interiorMargin;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &__item--empty {
 | 
			
		||||
 
 | 
			
		||||
@@ -113,7 +113,7 @@ import search from '../components/search.vue';
 | 
			
		||||
const ITEM_BUFFER = 25;
 | 
			
		||||
const LOCAL_STORAGE_KEY__TREE_EXPANDED = 'mct-tree-expanded';
 | 
			
		||||
const RETURN_ALL_DESCDNDANTS = true;
 | 
			
		||||
const TREE_ITEM_INDENT_PX = 15;
 | 
			
		||||
const TREE_ITEM_INDENT_PX = 18;
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    name: 'MctTree',
 | 
			
		||||
 
 | 
			
		||||
@@ -103,10 +103,16 @@ export default {
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
        if (this.actionCollection) {
 | 
			
		||||
            this.actionCollection.hide(HIDDEN_ACTIONS);
 | 
			
		||||
            this.actionCollection.on('update', this.updateActionItems);
 | 
			
		||||
            this.updateActionItems(this.actionCollection.getActionsObject());
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    destroyed() {
 | 
			
		||||
        if (this.actionCollection) {
 | 
			
		||||
            this.actionCollection.off('update', this.updateActionItems);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
        setView(view) {
 | 
			
		||||
            this.$emit('setView', view);
 | 
			
		||||
@@ -116,7 +122,6 @@ export default {
 | 
			
		||||
            delete this.actionCollection;
 | 
			
		||||
        },
 | 
			
		||||
        updateActionItems() {
 | 
			
		||||
            this.actionCollection.hide(HIDDEN_ACTIONS);
 | 
			
		||||
            this.statusBarItems = this.actionCollection.getStatusBarActions();
 | 
			
		||||
            this.menuActionItems = this.actionCollection.getVisibleActions();
 | 
			
		||||
        },
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@ let resolveFunction;
 | 
			
		||||
 | 
			
		||||
let initialHash = '';
 | 
			
		||||
 | 
			
		||||
describe('Application router utility functions', () => {
 | 
			
		||||
xdescribe('Application router utility functions', () => {
 | 
			
		||||
    beforeAll(done => {
 | 
			
		||||
        appHolder = document.createElement('div');
 | 
			
		||||
        appHolder.style.width = '640px';
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user