mirror of
https://github.com/nasa/openmct.git
synced 2025-06-14 21:28:12 +00:00
1.7.8 master (#4373)
* Notebook conflict auto retry 1.7.7 (#4230) * Use timeFormatter.parse to get the timestamp of imagery since the source could be something other than key (#4238) * If there is a pending create request for an id, queue a duplicate request. (#4243) * [Telemetry Tables] Handling Request Loading (#4245) * Fix file selection on pressing enter key (#4246) * starting loading as false, since that makes sense (#4247) * Hide independent time conductor mode if only 1 mode option is available. (#4250) * Fix bargraph color selection (#4253) * snapshot clicked while in edit mode should open in preview mode #4115 (#4257) * Fix missing object handling in several vues (#4259) * Flexible Layouts display Condition Sets as their editing/browsing interface (#4179) * Flexible Layouts display Condition Sets as their editing/browsing interface #4141 * [Telemetry Table] Progress bar tests (#4249) * Remove alert styling and hide pause button if in Fixed Time mode. (#4263) * [Table/Collection Fixes] Clearing correctly, no mutating options, no duplicate requests (#4261) * Condition sets only persist if actively editing (#4262) * Imagery views should follow time context (#4264) * Equal stacked plot y widths for all it's sub-plots (#4267) * Fix Bar Graph related CSS (#4270) * Bar graph review comment fixes (#4232) * Mct4196 - Fixes Conditional Styling not being applied when editing a Condition Widget (#4255) * Fix plot zoom when child of time strip (#4272) * Resume plot if no pan, zoom, or drag action is taken (#4138) (#4256) * [Telemetry Collection] No duplicate requests on load (#4274) * doing the easy thing first (#4278) * Bargraph time metadata should consider 'source' (#4289) * Show clicked image in large view (#4280) * added icon for inspector (#4275) * Bar graph style nullcheck (#4291) * Stacked plots need to align the Y axis (#4286) * Duplicate Request Fixes (#4295) * Add braintree sanitize url lib and sanitize form urls (#4296) * Mct4177 fix for telemetry endpoints with '.' in the key (#4308) * Remove additional request to load plots when mounted. (#4314) * Fix plots dup requests (#4324) * Merging 1.7.8 into master. Co-authored-by: Andrew Henry <akhenry@gmail.com> Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov> Co-authored-by: Nikhil <nikhil.k.mandlik@nasa.gov> Co-authored-by: Khalid Adil <khalidadil29@gmail.com> Co-authored-by: Charles Hacskaylo <charlesh88@gmail.com> Co-authored-by: Scott Bell <scott@traclabs.com> Co-authored-by: Michael Rogers <michael@mhrogers.com>
This commit is contained in:
@ -1,170 +0,0 @@
|
||||
<!--
|
||||
Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
as represented by the Administrator of the National Aeronautics and Space
|
||||
Administration. All rights reserved.
|
||||
|
||||
Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<template>
|
||||
<div class="u-contents">
|
||||
<ul v-if="canEdit"
|
||||
class="l-inspector-part"
|
||||
>
|
||||
<h2 v-if="heading"
|
||||
:title="heading"
|
||||
>{{ heading }}</h2>
|
||||
<li class="grid-row">
|
||||
<div class="grid-cell label"
|
||||
:title="editTitle"
|
||||
>{{ shortLabel }}</div>
|
||||
<div class="grid-cell value">
|
||||
<div class="c-click-swatch c-click-swatch--menu"
|
||||
@click="toggleSwatch()"
|
||||
>
|
||||
<span class="c-color-swatch"
|
||||
:style="{ background: currentColor }"
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
<div class="c-palette c-palette--color">
|
||||
<div v-show="swatchActive"
|
||||
class="c-palette__items"
|
||||
>
|
||||
<div v-for="group in colorPaletteGroups"
|
||||
:key="group.id"
|
||||
class="u-contents"
|
||||
>
|
||||
<div v-for="color in group"
|
||||
:key="color.id"
|
||||
class="c-palette__item"
|
||||
:class="{ 'selected': currentColor === color.hexString }"
|
||||
:style="{ background: color.hexString }"
|
||||
@click="setColor(color)"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<ul v-else
|
||||
class="l-inspector-part"
|
||||
>
|
||||
<h2 v-if="heading"
|
||||
:title="heading"
|
||||
>{{ heading }}</h2>
|
||||
<li class="grid-row">
|
||||
<div class="grid-cell label"
|
||||
:title="viewTitle"
|
||||
>{{ shortLabel }}</div>
|
||||
<div class="grid-cell value">
|
||||
<span class="c-color-swatch"
|
||||
:style="{
|
||||
'background': currentColor
|
||||
}"
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ColorPalette from './lib/ColorPalette';
|
||||
|
||||
export default {
|
||||
inject: ['openmct', 'domainObject'],
|
||||
props: {
|
||||
currentColor: {
|
||||
type: String,
|
||||
default() {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
editTitle: {
|
||||
type: String,
|
||||
default() {
|
||||
return 'Set the color.';
|
||||
}
|
||||
},
|
||||
viewTitle: {
|
||||
type: String,
|
||||
default() {
|
||||
return 'The current color.';
|
||||
}
|
||||
},
|
||||
shortLabel: {
|
||||
type: String,
|
||||
default() {
|
||||
return 'Color';
|
||||
}
|
||||
},
|
||||
heading: {
|
||||
type: String,
|
||||
default() {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
swatchActive: false,
|
||||
colorPaletteGroups: [],
|
||||
isEditing: this.openmct.editor.isEditing()
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
canEdit() {
|
||||
return this.isEditing && !this.domainObject.locked;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.colorPalette = new ColorPalette();
|
||||
this.openmct.editor.on('isEditing', this.setEditState);
|
||||
this.initialize();
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.openmct.editor.off('isEditing', this.setEditState);
|
||||
},
|
||||
methods: {
|
||||
initialize() {
|
||||
const colorPaletteGroups = this.colorPalette.groups();
|
||||
colorPaletteGroups.forEach((group, index) => {
|
||||
let groupId = [];
|
||||
group.forEach(color => {
|
||||
color.hexString = color.asHexString();
|
||||
color.id = `${color.hexString}-${index}`;
|
||||
groupId.push(color.id);
|
||||
});
|
||||
group.id = groupId.join('-');
|
||||
});
|
||||
this.colorPaletteGroups = colorPaletteGroups;
|
||||
},
|
||||
setEditState(isEditing) {
|
||||
this.isEditing = isEditing;
|
||||
},
|
||||
setColor(chosenColor) {
|
||||
this.$emit('colorSet', chosenColor);
|
||||
},
|
||||
toggleSwatch() {
|
||||
this.swatchActive = !this.swatchActive;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
@ -35,12 +35,15 @@
|
||||
:tick-width="tickWidth"
|
||||
:single-series="seriesModels.length === 1"
|
||||
:series-model="seriesModels[0]"
|
||||
:style="{
|
||||
left: (plotWidth - tickWidth) + 'px'
|
||||
}"
|
||||
@yKeyChanged="setYAxisKey"
|
||||
@tickWidthChanged="onTickWidthChange"
|
||||
/>
|
||||
<div class="gl-plot-wrapper-display-area-and-x-axis"
|
||||
:style="{
|
||||
left: (tickWidth + 20) + 'px'
|
||||
left: (plotWidth + 20) + 'px'
|
||||
}"
|
||||
>
|
||||
|
||||
@ -219,7 +222,8 @@ export default {
|
||||
isRealTime: this.openmct.time.clock() !== undefined,
|
||||
loaded: false,
|
||||
isTimeOutOfSync: false,
|
||||
showLimitLineLabels: undefined
|
||||
showLimitLineLabels: undefined,
|
||||
isFrozenOnMouseDown: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -235,11 +239,9 @@ export default {
|
||||
} else {
|
||||
return 'plot-legend-collapsed';
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
plotTickWidth(newTickWidth) {
|
||||
this.onTickWidthChange(newTickWidth, true);
|
||||
},
|
||||
plotWidth() {
|
||||
return this.plotTickWidth || this.tickWidth;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@ -336,6 +338,11 @@ export default {
|
||||
},
|
||||
|
||||
loadSeriesData(series) {
|
||||
//this check ensures that duplicate requests don't happen on load
|
||||
if (!this.timeContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.$parent.$refs.plotWrapper.offsetWidth === 0) {
|
||||
this.scheduleLoad(series);
|
||||
|
||||
@ -345,9 +352,12 @@ export default {
|
||||
this.offsetWidth = this.$parent.$refs.plotWrapper.offsetWidth;
|
||||
|
||||
this.startLoading();
|
||||
const bounds = this.timeContext.bounds();
|
||||
const options = {
|
||||
size: this.$parent.$refs.plotWrapper.offsetWidth,
|
||||
domain: this.config.xAxis.get('key')
|
||||
domain: this.config.xAxis.get('key'),
|
||||
start: bounds.start,
|
||||
end: bounds.end
|
||||
};
|
||||
|
||||
series.load(options)
|
||||
@ -356,9 +366,10 @@ export default {
|
||||
|
||||
loadMoreData(range, purge) {
|
||||
this.config.series.forEach(plotSeries => {
|
||||
this.offsetWidth = this.$parent.$refs.plotWrapper.offsetWidth;
|
||||
this.startLoading();
|
||||
plotSeries.load({
|
||||
size: this.$parent.$refs.plotWrapper.offsetWidth,
|
||||
size: this.offsetWidth,
|
||||
start: range.min,
|
||||
end: range.max,
|
||||
domain: this.config.xAxis.get('key')
|
||||
@ -593,7 +604,8 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
this.$emit('plotTickWidth', this.tickWidth);
|
||||
const id = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||
this.$emit('plotTickWidth', this.tickWidth, id);
|
||||
},
|
||||
|
||||
trackMousePosition(event) {
|
||||
@ -686,6 +698,11 @@ export default {
|
||||
|
||||
this.listenTo(window, 'mouseup', this.onMouseUp, this);
|
||||
this.listenTo(window, 'mousemove', this.trackMousePosition, this);
|
||||
|
||||
// track frozen state on mouseDown to be read on mouseUp
|
||||
const isFrozen = this.config.xAxis.get('frozen') === true && this.config.yAxis.get('frozen') === true;
|
||||
this.isFrozenOnMouseDown = isFrozen;
|
||||
|
||||
if (event.altKey) {
|
||||
return this.startPan(event);
|
||||
} else {
|
||||
@ -706,7 +723,14 @@ export default {
|
||||
}
|
||||
|
||||
if (this.marquee) {
|
||||
return this.endMarquee(event);
|
||||
this.endMarquee(event);
|
||||
}
|
||||
|
||||
// resume the plot if no pan, zoom, or drag action is taken
|
||||
// needs to follow endMarquee so that plotHistory is pruned
|
||||
const isAction = Boolean(this.plotHistory.length);
|
||||
if (!isAction && !this.isFrozenOnMouseDown) {
|
||||
return this.play();
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -44,7 +44,9 @@ export default function PlotViewProvider(openmct) {
|
||||
}
|
||||
|
||||
function isCompactView(objectPath) {
|
||||
return objectPath.find(object => object.type === 'time-strip');
|
||||
let isChildOfTimeStrip = objectPath.find(object => object.type === 'time-strip');
|
||||
|
||||
return isChildOfTimeStrip && !openmct.router.isNavigatedObject(objectPath);
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -1,53 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2021, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
import { BAR_GRAPH_KEY } from './BarGraphConstants';
|
||||
|
||||
export default function BarGraphCompositionPolicy(openmct) {
|
||||
function hasAggregateDomainAndRange(metadata) {
|
||||
const rangeValues = metadata.valuesForHints(['range']);
|
||||
|
||||
return rangeValues.length > 0;
|
||||
}
|
||||
|
||||
function hasBarGraphTelemetry(domainObject) {
|
||||
if (!Object.prototype.hasOwnProperty.call(domainObject, 'telemetry')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let metadata = openmct.telemetry.getMetadata(domainObject);
|
||||
|
||||
return metadata.values().length > 0 && hasAggregateDomainAndRange(metadata);
|
||||
}
|
||||
|
||||
return {
|
||||
allow: function (parent, child) {
|
||||
if ((parent.type === BAR_GRAPH_KEY)
|
||||
&& ((child.type !== 'telemetry.plot.overlay') && (hasBarGraphTelemetry(child) === false))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
@ -1,346 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2021, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
import BarGraphCompositionPolicy from "./BarGraphCompositionPolicy";
|
||||
import { createOpenMct } from "utils/testing";
|
||||
|
||||
describe("The bar graph composition policy", () => {
|
||||
let openmct;
|
||||
const mockMetaDataWithNoRangeHints = {
|
||||
"period": 10,
|
||||
"amplitude": 1,
|
||||
"offset": 0,
|
||||
"dataRateInHz": 1,
|
||||
"phase": 0,
|
||||
"randomness": 0,
|
||||
valuesForHints: () => {
|
||||
return [];
|
||||
},
|
||||
values: [
|
||||
{
|
||||
"key": "name",
|
||||
"name": "Name",
|
||||
"format": "string"
|
||||
},
|
||||
{
|
||||
"key": "utc",
|
||||
"name": "Time",
|
||||
"format": "utc",
|
||||
"hints": {
|
||||
"domain": 1,
|
||||
"priority": 1
|
||||
},
|
||||
"source": "utc"
|
||||
}
|
||||
]
|
||||
};
|
||||
const mockMetaDataWithRangeHints = {
|
||||
"period": 10,
|
||||
"amplitude": 1,
|
||||
"offset": 0,
|
||||
"dataRateInHz": 1,
|
||||
"phase": 0,
|
||||
"randomness": 0,
|
||||
"wavelength": 0,
|
||||
valuesForHints: () => {
|
||||
return [
|
||||
{
|
||||
"key": "sin",
|
||||
"name": "Sine",
|
||||
"unit": "Hz",
|
||||
"formatString": "%0.2f",
|
||||
"hints": {
|
||||
"range": 1,
|
||||
"priority": 4
|
||||
},
|
||||
"source": "sin"
|
||||
},
|
||||
{
|
||||
"key": "cos",
|
||||
"name": "Cosine",
|
||||
"unit": "deg",
|
||||
"formatString": "%0.2f",
|
||||
"hints": {
|
||||
"range": 2,
|
||||
"priority": 5
|
||||
},
|
||||
"source": "cos"
|
||||
}
|
||||
];
|
||||
},
|
||||
values: [
|
||||
{
|
||||
"key": "name",
|
||||
"name": "Name",
|
||||
"format": "string",
|
||||
"source": "name",
|
||||
"hints": {
|
||||
"priority": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": "utc",
|
||||
"name": "Time",
|
||||
"format": "utc",
|
||||
"hints": {
|
||||
"domain": 1,
|
||||
"priority": 1
|
||||
},
|
||||
"source": "utc"
|
||||
},
|
||||
{
|
||||
"key": "yesterday",
|
||||
"name": "Yesterday",
|
||||
"format": "utc",
|
||||
"hints": {
|
||||
"domain": 2,
|
||||
"priority": 2
|
||||
},
|
||||
"source": "yesterday"
|
||||
},
|
||||
{
|
||||
"key": "sin",
|
||||
"name": "Sine",
|
||||
"unit": "Hz",
|
||||
"formatString": "%0.2f",
|
||||
"hints": {
|
||||
"range": 1,
|
||||
"spectralAttribute": true
|
||||
},
|
||||
"source": "sin"
|
||||
},
|
||||
{
|
||||
"key": "cos",
|
||||
"name": "Cosine",
|
||||
"unit": "deg",
|
||||
"formatString": "%0.2f",
|
||||
"hints": {
|
||||
"range": 2,
|
||||
"priority": 5
|
||||
},
|
||||
"source": "cos"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
openmct = createOpenMct();
|
||||
const mockTypeDef = {
|
||||
telemetry: mockMetaDataWithRangeHints
|
||||
};
|
||||
const mockTypeService = {
|
||||
getType: () => {
|
||||
return {
|
||||
typeDef: mockTypeDef
|
||||
};
|
||||
}
|
||||
};
|
||||
openmct.$injector = {
|
||||
get: () => {
|
||||
return mockTypeService;
|
||||
}
|
||||
};
|
||||
|
||||
openmct.telemetry.isTelemetryObject = function (domainObject) {
|
||||
return true;
|
||||
};
|
||||
});
|
||||
|
||||
it("exists", () => {
|
||||
expect(BarGraphCompositionPolicy(openmct).allow).toBeDefined();
|
||||
});
|
||||
|
||||
xit("allow composition for telemetry that provides/supports bar graph meta data", () => {
|
||||
const parent = {
|
||||
"composition": [],
|
||||
"configuration": {},
|
||||
"name": "Some Bar Graph",
|
||||
"type": "telemetry.plot.bar-graph",
|
||||
"location": "mine",
|
||||
"modified": 1631005183584,
|
||||
"persisted": 1631005183502,
|
||||
"identifier": {
|
||||
"namespace": "",
|
||||
"key": "b78e7e23-f2b8-4776-b1f0-3ff778f5c8a9"
|
||||
}
|
||||
};
|
||||
const child = {
|
||||
"telemetry": {
|
||||
"period": 10,
|
||||
"amplitude": 1,
|
||||
"offset": 0,
|
||||
"dataRateInHz": 1,
|
||||
"phase": 0,
|
||||
"randomness": 0
|
||||
},
|
||||
"name": "Unnamed Sine Wave Generator",
|
||||
"type": "generator",
|
||||
"location": "mine",
|
||||
"modified": 1630399715531,
|
||||
"persisted": 1630399715531,
|
||||
"identifier": {
|
||||
"namespace": "",
|
||||
"key": "21d61f2d-6d2d-4bea-8b0a-7f59fd504c6c"
|
||||
}
|
||||
};
|
||||
expect(BarGraphCompositionPolicy(openmct).allow(parent, child)).toEqual(true);
|
||||
});
|
||||
|
||||
it("allows composition for telemetry that contain at least one range", () => {
|
||||
const mockTypeDef = {
|
||||
telemetry: mockMetaDataWithRangeHints
|
||||
};
|
||||
const mockTypeService = {
|
||||
getType: () => {
|
||||
return {
|
||||
typeDef: mockTypeDef
|
||||
};
|
||||
}
|
||||
};
|
||||
openmct.$injector = {
|
||||
get: () => {
|
||||
return mockTypeService;
|
||||
}
|
||||
};
|
||||
const parent = {
|
||||
"composition": [],
|
||||
"configuration": {},
|
||||
"name": "Some Bar Graph",
|
||||
"type": "telemetry.plot.bar-graph",
|
||||
"location": "mine",
|
||||
"modified": 1631005183584,
|
||||
"persisted": 1631005183502,
|
||||
"identifier": {
|
||||
"namespace": "",
|
||||
"key": "b78e7e23-f2b8-4776-b1f0-3ff778f5c8a9"
|
||||
}
|
||||
};
|
||||
const child = {
|
||||
"telemetry": {
|
||||
"period": 10,
|
||||
"amplitude": 1,
|
||||
"offset": 0,
|
||||
"dataRateInHz": 1,
|
||||
"phase": 0,
|
||||
"randomness": 0
|
||||
},
|
||||
"name": "Unnamed Sine Wave Generator",
|
||||
"type": "generator",
|
||||
"location": "mine",
|
||||
"modified": 1630399715531,
|
||||
"persisted": 1630399715531,
|
||||
"identifier": {
|
||||
"namespace": "",
|
||||
"key": "21d61f2d-6d2d-4bea-8b0a-7f59fd504c6c"
|
||||
}
|
||||
};
|
||||
expect(BarGraphCompositionPolicy(openmct).allow(parent, child)).toEqual(true);
|
||||
});
|
||||
|
||||
it("disallows composition for telemetry that don't contain any range hints", () => {
|
||||
const mockTypeDef = {
|
||||
telemetry: mockMetaDataWithNoRangeHints
|
||||
};
|
||||
const mockTypeService = {
|
||||
getType: () => {
|
||||
return {
|
||||
typeDef: mockTypeDef
|
||||
};
|
||||
}
|
||||
};
|
||||
openmct.$injector = {
|
||||
get: () => {
|
||||
return mockTypeService;
|
||||
}
|
||||
};
|
||||
const parent = {
|
||||
"composition": [],
|
||||
"configuration": {},
|
||||
"name": "Some Bar Graph",
|
||||
"type": "telemetry.plot.bar-graph",
|
||||
"location": "mine",
|
||||
"modified": 1631005183584,
|
||||
"persisted": 1631005183502,
|
||||
"identifier": {
|
||||
"namespace": "",
|
||||
"key": "b78e7e23-f2b8-4776-b1f0-3ff778f5c8a9"
|
||||
}
|
||||
};
|
||||
const child = {
|
||||
"telemetry": {
|
||||
"period": 10,
|
||||
"amplitude": 1,
|
||||
"offset": 0,
|
||||
"dataRateInHz": 1,
|
||||
"phase": 0,
|
||||
"randomness": 0
|
||||
},
|
||||
"name": "Unnamed Sine Wave Generator",
|
||||
"type": "generator",
|
||||
"location": "mine",
|
||||
"modified": 1630399715531,
|
||||
"persisted": 1630399715531,
|
||||
"identifier": {
|
||||
"namespace": "",
|
||||
"key": "21d61f2d-6d2d-4bea-8b0a-7f59fd504c6c"
|
||||
}
|
||||
};
|
||||
expect(BarGraphCompositionPolicy(openmct).allow(parent, child)).toEqual(false);
|
||||
});
|
||||
|
||||
it("passthrough for composition for non bar graph plots", () => {
|
||||
const parent = {
|
||||
"composition": [],
|
||||
"configuration": {},
|
||||
"name": "Some Stacked Plot",
|
||||
"type": "telemetry.plot.stacked",
|
||||
"location": "mine",
|
||||
"modified": 1631005183584,
|
||||
"persisted": 1631005183502,
|
||||
"identifier": {
|
||||
"namespace": "",
|
||||
"key": "b78e7e23-f2b8-4776-b1f0-3ff778f5c8a9"
|
||||
}
|
||||
};
|
||||
const child = {
|
||||
"telemetry": {
|
||||
"period": 10,
|
||||
"amplitude": 1,
|
||||
"offset": 0,
|
||||
"dataRateInHz": 1,
|
||||
"phase": 0,
|
||||
"randomness": 0
|
||||
},
|
||||
"name": "Unnamed Sine Wave Generator",
|
||||
"type": "generator",
|
||||
"location": "mine",
|
||||
"modified": 1630399715531,
|
||||
"persisted": 1630399715531,
|
||||
"identifier": {
|
||||
"namespace": "",
|
||||
"key": "21d61f2d-6d2d-4bea-8b0a-7f59fd504c6c"
|
||||
}
|
||||
};
|
||||
expect(BarGraphCompositionPolicy(openmct).allow(parent, child)).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +0,0 @@
|
||||
export const BAR_GRAPH_VIEW = 'bar-graph.view';
|
||||
export const BAR_GRAPH_KEY = 'telemetry.plot.bar-graph';
|
||||
export const BAR_GRAPH_INSPECTOR_KEY = 'telemetry.plot.bar-graph.inspector';
|
||||
export const SUBSCRIBE = 'subscribe';
|
||||
export const UNSUBSCRIBE = 'unsubscribe';
|
@ -1,293 +0,0 @@
|
||||
<template>
|
||||
<div ref="plotWrapper"
|
||||
class="has-local-controls"
|
||||
:class="{ 's-unsynced' : isZoomed }"
|
||||
>
|
||||
<div v-if="isZoomed"
|
||||
class="l-state-indicators"
|
||||
>
|
||||
<span class="l-state-indicators__alert-no-lad t-object-alert t-alert-unsynced icon-alert-triangle"
|
||||
title="This plot is not currently displaying the latest data. Reset pan/zoom to view latest data."
|
||||
></span>
|
||||
</div>
|
||||
<div ref="plot"
|
||||
class="c-bar-chart"
|
||||
></div>
|
||||
<div v-if="false"
|
||||
ref="localControl"
|
||||
class="gl-plot__local-controls h-local-controls h-local-controls--overlay-content c-local-controls--show-on-hover"
|
||||
>
|
||||
<button v-if="data.length"
|
||||
class="c-button icon-reset"
|
||||
:disabled="!isZoomed"
|
||||
title="Reset pan/zoom"
|
||||
@click="reset()"
|
||||
>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Plotly from 'plotly.js-basic-dist';
|
||||
import { SUBSCRIBE, UNSUBSCRIBE } from './BarGraphConstants';
|
||||
|
||||
const MULTI_AXES_X_PADDING_PERCENT = {
|
||||
LEFT: 8,
|
||||
RIGHT: 94
|
||||
};
|
||||
|
||||
export default {
|
||||
inject: ['openmct', 'domainObject'],
|
||||
props: {
|
||||
data: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
plotAxisTitle: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isZoomed: false,
|
||||
primaryYAxisRange: {
|
||||
min: '',
|
||||
max: ''
|
||||
},
|
||||
xAxisRange: {
|
||||
min: '',
|
||||
max: ''
|
||||
}
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
data: {
|
||||
immediate: false,
|
||||
handler: 'updateData'
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
Plotly.newPlot(this.$refs.plot, Array.from(this.data), this.getLayout(), {
|
||||
responsive: true,
|
||||
displayModeBar: false
|
||||
});
|
||||
this.registerListeners();
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$refs.plot.removeAllListeners();
|
||||
|
||||
if (this.plotResizeObserver) {
|
||||
this.plotResizeObserver.unobserve(this.$refs.plotWrapper);
|
||||
clearTimeout(this.resizeTimer);
|
||||
}
|
||||
|
||||
if (this.removeBarColorListener) {
|
||||
this.removeBarColorListener();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getAxisMinMax(axis) {
|
||||
const min = axis.autoSize
|
||||
? ''
|
||||
: axis.min;
|
||||
const max = axis.autoSize
|
||||
? ''
|
||||
: axis.max;
|
||||
|
||||
return {
|
||||
min,
|
||||
max
|
||||
};
|
||||
},
|
||||
getLayout() {
|
||||
const yAxesMeta = this.getYAxisMeta();
|
||||
const primaryYaxis = this.getYaxisLayout(yAxesMeta['1']);
|
||||
const xAxisDomain = this.getXAxisDomain(yAxesMeta);
|
||||
|
||||
return {
|
||||
autosize: true,
|
||||
showlegend: false,
|
||||
textposition: 'auto',
|
||||
font: {
|
||||
family: 'Helvetica Neue, Helvetica, Arial, sans-serif',
|
||||
size: '12px',
|
||||
color: '#666'
|
||||
},
|
||||
xaxis: {
|
||||
domain: xAxisDomain,
|
||||
range: [this.xAxisRange.min, this.xAxisRange.max],
|
||||
title: this.plotAxisTitle.xAxisTitle,
|
||||
automargin: true,
|
||||
fixedrange: true
|
||||
},
|
||||
yaxis: primaryYaxis,
|
||||
margin: {
|
||||
l: 5,
|
||||
r: 5,
|
||||
t: 5,
|
||||
b: 0
|
||||
},
|
||||
paper_bgcolor: 'transparent',
|
||||
plot_bgcolor: 'transparent'
|
||||
};
|
||||
},
|
||||
getYAxisMeta() {
|
||||
const yAxisMeta = {};
|
||||
|
||||
this.data.forEach(d => {
|
||||
const yAxisMetadata = d.yAxisMetadata;
|
||||
const range = '1';
|
||||
const side = 'left';
|
||||
const name = '';
|
||||
const unit = yAxisMetadata.units;
|
||||
|
||||
yAxisMeta[range] = {
|
||||
range,
|
||||
side,
|
||||
name,
|
||||
unit
|
||||
};
|
||||
});
|
||||
|
||||
return yAxisMeta;
|
||||
},
|
||||
getXAxisDomain(yAxisMeta) {
|
||||
let leftPaddingPerc = 0;
|
||||
let rightPaddingPerc = 100;
|
||||
let rightSide = yAxisMeta && Object.values(yAxisMeta).filter((axisMeta => axisMeta.side === 'right'));
|
||||
let leftSide = yAxisMeta && Object.values(yAxisMeta).filter((axisMeta => axisMeta.side === 'left'));
|
||||
if (yAxisMeta && rightSide.length > 1) {
|
||||
rightPaddingPerc = MULTI_AXES_X_PADDING_PERCENT.RIGHT;
|
||||
}
|
||||
|
||||
if (yAxisMeta && leftSide.length > 1) {
|
||||
leftPaddingPerc = MULTI_AXES_X_PADDING_PERCENT.LEFT;
|
||||
}
|
||||
|
||||
return [leftPaddingPerc / 100, rightPaddingPerc / 100];
|
||||
},
|
||||
getYaxisLayout(yAxisMeta) {
|
||||
if (!yAxisMeta) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const { name, range, side = 'left', unit } = yAxisMeta;
|
||||
const title = `${name} ${unit ? '(' + unit + ')' : ''}`;
|
||||
const yaxis = {
|
||||
automargin: true,
|
||||
fixedrange: true,
|
||||
title
|
||||
};
|
||||
|
||||
let yAxistype = this.primaryYAxisRange;
|
||||
if (range === '1') {
|
||||
yaxis.range = [yAxistype.min, yAxistype.max];
|
||||
|
||||
return yaxis;
|
||||
}
|
||||
|
||||
yaxis.range = [yAxistype.min, yAxistype.max];
|
||||
yaxis.anchor = side.toLowerCase() === 'left'
|
||||
? 'free'
|
||||
: 'x';
|
||||
yaxis.showline = side.toLowerCase() === 'left';
|
||||
yaxis.side = side.toLowerCase();
|
||||
yaxis.overlaying = 'y';
|
||||
yaxis.position = 0.01;
|
||||
|
||||
return yaxis;
|
||||
},
|
||||
registerListeners() {
|
||||
this.$refs.plot.on('plotly_relayout', this.zoom);
|
||||
|
||||
this.removeBarColorListener = this.openmct.objects.observe(
|
||||
this.domainObject,
|
||||
'configuration.barStyles',
|
||||
this.barColorChanged
|
||||
);
|
||||
this.resizeTimer = false;
|
||||
if (window.ResizeObserver) {
|
||||
this.plotResizeObserver = new ResizeObserver(() => {
|
||||
// debounce and trigger window resize so that plotly can resize the plot
|
||||
clearTimeout(this.resizeTimer);
|
||||
this.resizeTimer = setTimeout(() => {
|
||||
window.dispatchEvent(new Event('resize'));
|
||||
}, 250);
|
||||
});
|
||||
this.plotResizeObserver.observe(this.$refs.plotWrapper);
|
||||
}
|
||||
},
|
||||
reset() {
|
||||
this.updatePlot();
|
||||
|
||||
this.isZoomed = false;
|
||||
this.$emit(SUBSCRIBE);
|
||||
},
|
||||
barColorChanged() {
|
||||
const colors = [];
|
||||
const indices = [];
|
||||
this.data.forEach((item, index) => {
|
||||
const key = item.key;
|
||||
const color = this.domainObject.configuration.barStyles[key] && this.domainObject.configuration.barStyles[key].color;
|
||||
indices.push(index);
|
||||
if (color) {
|
||||
colors.push();
|
||||
} else {
|
||||
colors.push(item.marker.color);
|
||||
}
|
||||
});
|
||||
const plotUpdate = {
|
||||
'marker.color': colors
|
||||
};
|
||||
Plotly.restyle(this.$refs.plot, plotUpdate, indices);
|
||||
},
|
||||
updateData() {
|
||||
this.updatePlot();
|
||||
},
|
||||
updateLocalControlPosition() {
|
||||
const localControl = this.$refs.localControl;
|
||||
localControl.style.display = 'none';
|
||||
|
||||
const plot = this.$refs.plot;
|
||||
const bgLayer = this.$el.querySelector('.bglayer');
|
||||
|
||||
const plotBoundingRect = plot.getBoundingClientRect();
|
||||
const bgLayerBoundingRect = bgLayer.getBoundingClientRect();
|
||||
|
||||
const top = bgLayerBoundingRect.top - plotBoundingRect.top + 5;
|
||||
const left = bgLayerBoundingRect.left - plotBoundingRect.left + 5;
|
||||
|
||||
localControl.style.top = `${top}px`;
|
||||
localControl.style.left = `${left}px`;
|
||||
localControl.style.display = 'block';
|
||||
},
|
||||
updatePlot() {
|
||||
if (!this.$refs || !this.$refs.plot) {
|
||||
return;
|
||||
}
|
||||
|
||||
Plotly.react(this.$refs.plot, Array.from(this.data), this.getLayout());
|
||||
},
|
||||
zoom(eventData) {
|
||||
const autorange = eventData['xaxis.autorange'];
|
||||
const { autosize } = eventData;
|
||||
|
||||
if (autosize || autorange) {
|
||||
this.isZoomed = false;
|
||||
this.reset();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.isZoomed = true;
|
||||
this.$emit(UNSUBSCRIBE);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
@ -1,286 +0,0 @@
|
||||
<!--
|
||||
Open MCT, Copyright (c) 2014-2021, United States Government
|
||||
as represented by the Administrator of the National Aeronautics and Space
|
||||
Administration. All rights reserved.
|
||||
|
||||
Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
|
||||
<template>
|
||||
<BarGraph ref="barGraph"
|
||||
class="c-plot c-bar-chart-view"
|
||||
:data="trace"
|
||||
:plot-axis-title="plotAxisTitle"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as SPECTRAL_AGGREGATE from './BarGraphConstants';
|
||||
import ColorPalette from '../lib/ColorPalette';
|
||||
import BarGraph from './BarGraphPlot.vue';
|
||||
import Color from "@/plugins/plot/lib/Color";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
BarGraph
|
||||
},
|
||||
inject: ['openmct', 'domainObject'],
|
||||
data() {
|
||||
return {
|
||||
composition: {},
|
||||
currentDomainObject: this.domainObject,
|
||||
subscriptions: [],
|
||||
telemetryObjects: {},
|
||||
trace: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
activeClock() {
|
||||
return this.openmct.time.activeClock;
|
||||
},
|
||||
plotAxisTitle() {
|
||||
const { xAxisMetadata = {}, yAxisMetadata = {} } = this.trace[0] || {};
|
||||
const xAxisUnit = xAxisMetadata.units ? `(${xAxisMetadata.units})` : '';
|
||||
const yAxisUnit = yAxisMetadata.units ? `(${yAxisMetadata.units})` : '';
|
||||
|
||||
return {
|
||||
xAxisTitle: `${xAxisMetadata.name || ''} ${xAxisUnit}`,
|
||||
yAxisTitle: `${yAxisMetadata.name || ''} ${yAxisUnit}`
|
||||
};
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.colorPalette = new ColorPalette();
|
||||
this.loadComposition();
|
||||
|
||||
this.openmct.time.on('bounds', this.refreshData);
|
||||
this.openmct.time.on('clock', this.clockChanged);
|
||||
|
||||
this.$refs.barGraph.$on(SPECTRAL_AGGREGATE.SUBSCRIBE, this.subscribeToAll);
|
||||
this.$refs.barGraph.$on(SPECTRAL_AGGREGATE.UNSUBSCRIBE, this.removeAllSubscriptions);
|
||||
|
||||
this.unobserve = this.openmct.objects.observe(this.currentDomainObject, '*', this.updateDomainObject);
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$refs.barGraph.$off();
|
||||
this.openmct.time.off('bounds', this.refreshData);
|
||||
this.openmct.time.off('clock', this.clockChanged);
|
||||
|
||||
this.removeAllSubscriptions();
|
||||
this.unobserve();
|
||||
|
||||
if (!this.composition) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.composition.off('add', this.addTelemetryObject);
|
||||
this.composition.off('remove', this.removeTelemetryObject);
|
||||
},
|
||||
methods: {
|
||||
addTelemetryObject(telemetryObject) {
|
||||
const key = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||
|
||||
if (!this.domainObject.configuration.barStyles) {
|
||||
this.domainObject.configuration.barStyles = {};
|
||||
}
|
||||
|
||||
// check to see if we've set a bar color
|
||||
if (!this.domainObject.configuration.barStyles[key] || !this.domainObject.configuration.barStyles[key].color) {
|
||||
const color = this.colorPalette.getNextColor().asHexString();
|
||||
this.domainObject.configuration.barStyles[key] = {
|
||||
name: telemetryObject.name,
|
||||
color
|
||||
};
|
||||
this.openmct.objects.mutate(
|
||||
this.domainObject,
|
||||
`configuration.barStyles[${this.key}]`,
|
||||
this.domainObject.configuration.barStyles[key]
|
||||
);
|
||||
} else {
|
||||
let color = this.domainObject.configuration.barStyles[key].color;
|
||||
if (!(color instanceof Color)) {
|
||||
color = Color.fromHexString(color);
|
||||
}
|
||||
|
||||
this.colorPalette.remove(color);
|
||||
}
|
||||
|
||||
this.telemetryObjects[key] = telemetryObject;
|
||||
|
||||
this.requestDataFor(telemetryObject);
|
||||
this.subscribeToObject(telemetryObject);
|
||||
},
|
||||
addTrace(trace, key) {
|
||||
if (!this.trace.length) {
|
||||
this.trace = this.trace.concat([trace]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let isInTrace = false;
|
||||
const newTrace = this.trace.map((currentTrace, index) => {
|
||||
if (currentTrace.key !== key) {
|
||||
return currentTrace;
|
||||
}
|
||||
|
||||
isInTrace = true;
|
||||
|
||||
return trace;
|
||||
});
|
||||
|
||||
this.trace = isInTrace ? newTrace : newTrace.concat([trace]);
|
||||
},
|
||||
clockChanged() {
|
||||
this.removeAllSubscriptions();
|
||||
this.subscribeToAll();
|
||||
},
|
||||
getAxisMetadata(telemetryObject) {
|
||||
const metadata = this.openmct.telemetry.getMetadata(telemetryObject);
|
||||
const yAxisMetadata = metadata.valuesForHints(['range'])[0];
|
||||
//Exclude 'name' and 'time' based metadata specifically, from the x-Axis values by using range hints only
|
||||
const xAxisMetadata = metadata.valuesForHints(['range']);
|
||||
|
||||
return {
|
||||
xAxisMetadata,
|
||||
yAxisMetadata
|
||||
};
|
||||
},
|
||||
getOptions(telemetryObject) {
|
||||
const { start, end } = this.openmct.time.bounds();
|
||||
|
||||
return {
|
||||
end,
|
||||
start,
|
||||
startTime: null,
|
||||
spectra: true
|
||||
};
|
||||
},
|
||||
loadComposition() {
|
||||
this.composition = this.openmct.composition.get(this.currentDomainObject);
|
||||
|
||||
if (!this.composition) {
|
||||
this.addTelemetryObject(this.currentDomainObject);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.composition.on('add', this.addTelemetryObject);
|
||||
this.composition.on('remove', this.removeTelemetryObject);
|
||||
this.composition.load();
|
||||
},
|
||||
refreshData(bounds, isTick) {
|
||||
if (!isTick) {
|
||||
const telemetryObjects = Object.values(this.telemetryObjects);
|
||||
telemetryObjects.forEach(this.requestDataFor);
|
||||
}
|
||||
},
|
||||
removeAllSubscriptions() {
|
||||
this.subscriptions.forEach(subscription => subscription.unsubscribe());
|
||||
this.subscriptions = [];
|
||||
},
|
||||
removeSubscription(key) {
|
||||
const found = this.subscriptions.findIndex(subscription => subscription.key === key);
|
||||
if (found > -1) {
|
||||
this.subscriptions[found].unsubscribe();
|
||||
this.subscriptions.splice(found, 1);
|
||||
}
|
||||
},
|
||||
removeTelemetryObject(identifier) {
|
||||
const key = this.openmct.objects.makeKeyString(identifier);
|
||||
delete this.telemetryObjects[key];
|
||||
if (this.domainObject.configuration.barStyles[key]) {
|
||||
delete this.domainObject.configuration.barStyles[key];
|
||||
}
|
||||
|
||||
this.removeSubscription(key);
|
||||
|
||||
this.trace = this.trace.filter(t => t.key !== key);
|
||||
},
|
||||
processData(telemetryObject, data, axisMetadata) {
|
||||
const key = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||
|
||||
if (data.message) {
|
||||
this.openmct.notifications.alert(data.message);
|
||||
}
|
||||
|
||||
let xValues = [];
|
||||
let yValues = [];
|
||||
|
||||
//populate X and Y values for plotly
|
||||
axisMetadata.xAxisMetadata.forEach((metadata) => {
|
||||
xValues.push(metadata.name);
|
||||
if (data[metadata.key]) {
|
||||
//TODO: Format the data?
|
||||
yValues.push(data[metadata.key]);
|
||||
} else {
|
||||
yValues.push('');
|
||||
}
|
||||
});
|
||||
|
||||
const trace = {
|
||||
key,
|
||||
name: telemetryObject.name,
|
||||
x: xValues,
|
||||
y: yValues,
|
||||
text: yValues.map(String),
|
||||
xAxisMetadata: axisMetadata.xAxisMetadata,
|
||||
yAxisMetadata: axisMetadata.yAxisMetadata,
|
||||
type: 'bar',
|
||||
marker: {
|
||||
color: this.domainObject.configuration.barStyles[key].color
|
||||
},
|
||||
hoverinfo: 'skip'
|
||||
};
|
||||
|
||||
this.addTrace(trace, key);
|
||||
},
|
||||
requestDataFor(telemetryObject) {
|
||||
const axisMetadata = this.getAxisMetadata(telemetryObject);
|
||||
this.openmct.telemetry.request(telemetryObject, this.getOptions(telemetryObject))
|
||||
.then(data => {
|
||||
data.forEach((datum) => {
|
||||
this.processData(telemetryObject, datum, axisMetadata);
|
||||
});
|
||||
});
|
||||
},
|
||||
subscribeToObject(telemetryObject) {
|
||||
const key = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||
|
||||
this.removeSubscription(key);
|
||||
|
||||
const options = this.getOptions(telemetryObject);
|
||||
const axisMetadata = this.getAxisMetadata(telemetryObject);
|
||||
const unsubscribe = this.openmct.telemetry.subscribe(telemetryObject,
|
||||
data => this.processData(telemetryObject, data, axisMetadata)
|
||||
, options);
|
||||
|
||||
this.subscriptions.push({
|
||||
key,
|
||||
unsubscribe
|
||||
});
|
||||
},
|
||||
subscribeToAll() {
|
||||
const telemetryObjects = Object.values(this.telemetryObjects);
|
||||
telemetryObjects.forEach(this.subscribeToObject);
|
||||
},
|
||||
updateDomainObject(newDomainObject) {
|
||||
this.currentDomainObject = newDomainObject;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
@ -1,76 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2021, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
import BarGraphView from './BarGraphView.vue';
|
||||
import { BAR_GRAPH_KEY, BAR_GRAPH_VIEW } from './BarGraphConstants';
|
||||
import Vue from 'vue';
|
||||
|
||||
export default function BarGraphViewProvider(openmct) {
|
||||
function isCompactView(objectPath) {
|
||||
return objectPath.find(object => object.type === 'time-strip');
|
||||
}
|
||||
|
||||
return {
|
||||
key: BAR_GRAPH_VIEW,
|
||||
name: 'Spectral Aggregate Plot',
|
||||
cssClass: 'icon-telemetry',
|
||||
canView(domainObject, objectPath) {
|
||||
return domainObject && domainObject.type === BAR_GRAPH_KEY;
|
||||
},
|
||||
|
||||
canEdit(domainObject, objectPath) {
|
||||
return domainObject && domainObject.type === BAR_GRAPH_KEY;
|
||||
},
|
||||
|
||||
view: function (domainObject, objectPath) {
|
||||
let component;
|
||||
|
||||
return {
|
||||
show: function (element) {
|
||||
let isCompact = isCompactView(objectPath);
|
||||
component = new Vue({
|
||||
el: element,
|
||||
components: {
|
||||
BarGraphView
|
||||
},
|
||||
provide: {
|
||||
openmct,
|
||||
domainObject
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: {
|
||||
compact: isCompact
|
||||
}
|
||||
};
|
||||
},
|
||||
template: '<bar-graph-view :options="options"></bar-graph-view>'
|
||||
});
|
||||
},
|
||||
destroy: function () {
|
||||
component.$destroy();
|
||||
component = undefined;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
import { BAR_GRAPH_INSPECTOR_KEY, BAR_GRAPH_KEY } from '../BarGraphConstants';
|
||||
import Vue from 'vue';
|
||||
import Options from "./Options.vue";
|
||||
|
||||
export default function BarGraphInspectorViewProvider(openmct) {
|
||||
return {
|
||||
key: BAR_GRAPH_INSPECTOR_KEY,
|
||||
name: 'Bar Graph Inspector View',
|
||||
canView: function (selection) {
|
||||
if (selection.length === 0 || selection[0].length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let object = selection[0][0].context.item;
|
||||
|
||||
return object
|
||||
&& object.type === BAR_GRAPH_KEY;
|
||||
},
|
||||
view: function (selection) {
|
||||
let component;
|
||||
|
||||
return {
|
||||
show: function (element) {
|
||||
component = new Vue({
|
||||
el: element,
|
||||
components: {
|
||||
Options
|
||||
},
|
||||
provide: {
|
||||
openmct,
|
||||
domainObject: selection[0][0].context.item
|
||||
},
|
||||
template: '<options></options>'
|
||||
});
|
||||
},
|
||||
destroy: function () {
|
||||
if (component) {
|
||||
component.$destroy();
|
||||
component = undefined;
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
priority: function () {
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
<!--
|
||||
Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
as represented by the Administrator of the National Aeronautics and Space
|
||||
Administration. All rights reserved.
|
||||
|
||||
Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<template>
|
||||
<ul>
|
||||
<li class="c-tree__item menus-to-left">
|
||||
<span class="c-disclosure-triangle is-enabled flex-elem"
|
||||
:class="expandedCssClass"
|
||||
@click="expanded = !expanded"
|
||||
>
|
||||
</span>
|
||||
<div>
|
||||
<div class="c-object-label__name">{{ name }}</div>
|
||||
</div>
|
||||
</li>
|
||||
<ColorSwatch v-if="expanded"
|
||||
:current-color="currentColor"
|
||||
title="Manually set the color for this bar graph."
|
||||
edit-title="Manually set the color for this bar graph"
|
||||
view-title="The color for this bar graph."
|
||||
short-label="Color"
|
||||
class="grid-properties"
|
||||
@colorSet="setColor"
|
||||
/>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ColorSwatch from '../../ColorSwatch.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ColorSwatch
|
||||
},
|
||||
inject: ['openmct', 'domainObject'],
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentColor: undefined,
|
||||
name: '',
|
||||
expanded: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
expandedCssClass() {
|
||||
return this.expanded ? 'c-disclosure-triangle--expanded' : '';
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
item: {
|
||||
handler() {
|
||||
this.initColor();
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.key = this.openmct.objects.makeKeyString(this.item);
|
||||
this.initColor();
|
||||
this.unObserve = this.openmct.objects.observe(this.domainObject, `this.domainObject.configuration.barStyles[${this.key}]`, this.initColor);
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.unObserve) {
|
||||
this.unObserve();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initColor() {
|
||||
if (this.domainObject.configuration.barStyles && this.domainObject.configuration.barStyles[this.key]) {
|
||||
this.currentColor = this.domainObject.configuration.barStyles[this.key].color;
|
||||
this.name = this.domainObject.configuration.barStyles[this.key].name;
|
||||
}
|
||||
},
|
||||
setColor(chosenColor) {
|
||||
this.currentColor = chosenColor.asHexString();
|
||||
this.openmct.objects.mutate(
|
||||
this.domainObject,
|
||||
`configuration.barStyles[${this.key}].color`,
|
||||
this.currentColor
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
@ -1,63 +0,0 @@
|
||||
<!--
|
||||
Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
as represented by the Administrator of the National Aeronautics and Space
|
||||
Administration. All rights reserved.
|
||||
|
||||
Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<template>
|
||||
<div>
|
||||
<ul class="c-tree">
|
||||
<li v-for="series in domainObject.composition"
|
||||
:key="series.key"
|
||||
>
|
||||
<bar-graph-options :item="series" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BarGraphOptions from "./BarGraphOptions.vue";
|
||||
export default {
|
||||
components: {
|
||||
BarGraphOptions
|
||||
},
|
||||
inject: ['openmct', 'domainObject'],
|
||||
data() {
|
||||
return {
|
||||
isEditing: this.openmct.editor.isEditing()
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
canEdit() {
|
||||
return this.isEditing && !this.domainObject.locked;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.openmct.editor.on('isEditing', this.setEditState);
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.openmct.editor.off('isEditing', this.setEditState);
|
||||
},
|
||||
methods: {
|
||||
setEditState(isEditing) {
|
||||
this.isEditing = isEditing;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
@ -82,12 +82,17 @@ export default class PlotSeries extends Model {
|
||||
.openmct
|
||||
.telemetry
|
||||
.getMetadata(options.domainObject);
|
||||
|
||||
this.formats = options
|
||||
.openmct
|
||||
.telemetry
|
||||
.getFormatMap(this.metadata);
|
||||
|
||||
const range = this.metadata.valuesForHints(['range'])[0];
|
||||
//if the object is missing or doesn't have metadata for some reason
|
||||
let range = {};
|
||||
if (this.metadata) {
|
||||
range = this.metadata.valuesForHints(['range'])[0];
|
||||
}
|
||||
|
||||
return {
|
||||
name: options.domainObject.name,
|
||||
@ -191,7 +196,10 @@ export default class PlotSeries extends Model {
|
||||
.uniq(true, point => [this.getXVal(point), this.getYVal(point)].join())
|
||||
.value();
|
||||
this.reset(newPoints);
|
||||
}.bind(this));
|
||||
}.bind(this))
|
||||
.catch((error) => {
|
||||
console.warn('Error fetching data', error);
|
||||
});
|
||||
/* eslint-enable you-dont-need-lodash-underscore/concat */
|
||||
}
|
||||
/**
|
||||
@ -199,7 +207,9 @@ export default class PlotSeries extends Model {
|
||||
*/
|
||||
onXKeyChange(xKey) {
|
||||
const format = this.formats[xKey];
|
||||
this.getXVal = format.parse.bind(format);
|
||||
if (format) {
|
||||
this.getXVal = format.parse.bind(format);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Update y formatter on change, default to stepAfter interpolation if
|
||||
|
@ -23,8 +23,8 @@ import _ from 'lodash';
|
||||
|
||||
import PlotSeries from "./PlotSeries";
|
||||
import Collection from "./Collection";
|
||||
import Color from "../lib/Color";
|
||||
import ColorPalette from "../lib/ColorPalette";
|
||||
import Color from "@/ui/color/Color";
|
||||
import ColorPalette from "@/ui/color/ColorPalette";
|
||||
|
||||
export default class SeriesCollection extends Collection {
|
||||
|
||||
|
@ -184,7 +184,7 @@ export default class YAxisModel extends Model {
|
||||
this.set('values', yMetadata.values);
|
||||
if (!label) {
|
||||
const labelName = series.map(function (s) {
|
||||
return s.metadata.value(s.get('yKey')).name;
|
||||
return s.metadata ? s.metadata.value(s.get('yKey')).name : '';
|
||||
}).reduce(function (a, b) {
|
||||
if (a === undefined) {
|
||||
return b;
|
||||
@ -204,7 +204,7 @@ export default class YAxisModel extends Model {
|
||||
}
|
||||
|
||||
const labelUnits = series.map(function (s) {
|
||||
return s.metadata.value(s.get('yKey')).units;
|
||||
return s.metadata ? s.metadata.value(s.get('yKey')).units : '';
|
||||
}).reduce(function (a, b) {
|
||||
if (a === undefined) {
|
||||
return b;
|
||||
|
@ -79,7 +79,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ColorSwatch from "@/plugins/plot/ColorSwatch.vue";
|
||||
import ColorSwatch from '@/ui/color/ColorSwatch.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
@ -129,7 +129,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ColorSwatch from '../../ColorSwatch.vue';
|
||||
import ColorSwatch from '@/ui/color/ColorSwatch.vue';
|
||||
import { MARKER_SHAPES } from "../../draw/MarkerShapes";
|
||||
import { objectPath, validate, coerce } from "./formUtil";
|
||||
import _ from 'lodash';
|
||||
|
@ -1,98 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2021, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* A representation of a color that allows conversions between different
|
||||
* formats.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
/**
|
||||
* A representation of a color that allows conversions between different
|
||||
* formats.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function Color(integerArray) {
|
||||
this.integerArray = integerArray;
|
||||
}
|
||||
|
||||
Color.fromHexString = function (hexString) {
|
||||
if (!/#([0-9a-fA-F]{2}){2}/.test(hexString)) {
|
||||
throw new Error(
|
||||
'Invalid input "'
|
||||
+ hexString
|
||||
+ '". Hex string must be in CSS format e.g. #00FF00'
|
||||
);
|
||||
}
|
||||
|
||||
return new Color([
|
||||
parseInt(hexString.slice(1, 3), 16),
|
||||
parseInt(hexString.slice(3, 5), 16),
|
||||
parseInt(hexString.slice(5, 7), 16)
|
||||
]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return color as a three element array of RGB values, where each value
|
||||
* is a integer in the range of 0-255.
|
||||
*
|
||||
* @return {number[]} the color, as integer RGB values
|
||||
*/
|
||||
Color.prototype.asIntegerArray = function () {
|
||||
return this.integerArray.map(function (c) {
|
||||
return c;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Return color as a string using #-prefixed six-digit RGB hex notation
|
||||
* (e.g. #FF0000). See http://www.w3.org/TR/css3-color/#rgb-color.
|
||||
*
|
||||
* @return {string} the color, as a style-friendly string
|
||||
*/
|
||||
|
||||
Color.prototype.asHexString = function () {
|
||||
return '#' + this.integerArray.map(function (c) {
|
||||
return (c < 16 ? '0' : '') + c.toString(16);
|
||||
}).join('');
|
||||
};
|
||||
|
||||
/**
|
||||
* Return color as a RGBA float array.
|
||||
*
|
||||
* This format is present specifically to support use with
|
||||
* WebGL, which expects colors of that form.
|
||||
*
|
||||
* @return {number[]} the color, as floating-point RGBA values
|
||||
*/
|
||||
Color.prototype.asRGBAArray = function () {
|
||||
return this.integerArray.map(function (c) {
|
||||
return c / 255.0;
|
||||
}).concat([1]);
|
||||
};
|
||||
|
||||
Color.prototype.equalTo = function (otherColor) {
|
||||
return this.asHexString() === otherColor.asHexString();
|
||||
};
|
||||
|
||||
export default Color;
|
@ -1,62 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2021, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
export const COLOR_PALETTE = [
|
||||
[0x00, 0x37, 0xFF],
|
||||
[0xF0, 0x60, 0x00],
|
||||
[0x00, 0x70, 0x40],
|
||||
[0xFB, 0x49, 0x49],
|
||||
[0xC8, 0x00, 0xCF],
|
||||
[0x55, 0x77, 0xF2],
|
||||
[0xFF, 0xA6, 0x3D],
|
||||
[0x05, 0xA3, 0x00],
|
||||
[0xF0, 0x00, 0x6C],
|
||||
[0x77, 0x17, 0x7A],
|
||||
[0x23, 0xA9, 0xDB],
|
||||
[0xFA, 0xF0, 0x6F],
|
||||
[0x4E, 0xF0, 0x48],
|
||||
[0xAD, 0x50, 0x72],
|
||||
[0x94, 0x25, 0xEA],
|
||||
[0x21, 0x87, 0x82],
|
||||
[0x8F, 0x6E, 0x47],
|
||||
[0xf0, 0x59, 0xcb],
|
||||
[0x34, 0xB6, 0x7D],
|
||||
[0x6A, 0x36, 0xFF],
|
||||
[0x56, 0xF0, 0xE8],
|
||||
[0xA1, 0x8C, 0x1C],
|
||||
[0xCB, 0xE1, 0x44],
|
||||
[0xFF, 0x84, 0x9E],
|
||||
[0xB7, 0x79, 0xE7],
|
||||
[0x8C, 0xC9, 0xFD],
|
||||
[0xDB, 0xAA, 0x6E],
|
||||
[0xB8, 0xDF, 0x97],
|
||||
[0xFF, 0xBC, 0xDA],
|
||||
[0xD3, 0xB6, 0xDE]
|
||||
];
|
||||
|
||||
export function isDefaultColor(color) {
|
||||
const a = color.asIntegerArray();
|
||||
|
||||
return COLOR_PALETTE.some(function (b) {
|
||||
return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
|
||||
});
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2021, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* A color palette stores a set of colors and allows for different
|
||||
* methods of color allocation.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
import { isDefaultColor, COLOR_PALETTE } from './ColorHelper';
|
||||
import Color from './Color';
|
||||
|
||||
/**
|
||||
* A color palette stores a set of colors and allows for different
|
||||
* methods of color allocation.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function ColorPalette() {
|
||||
const allColors = this.allColors = COLOR_PALETTE.map(function (color) {
|
||||
return new Color(color);
|
||||
});
|
||||
this.colorGroups = [[], [], []];
|
||||
for (let i = 0; i < allColors.length; i++) {
|
||||
this.colorGroups[i % 3].push(allColors[i]);
|
||||
}
|
||||
|
||||
this.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
ColorPalette.prototype.groups = function () {
|
||||
return this.colorGroups;
|
||||
};
|
||||
|
||||
ColorPalette.prototype.reset = function () {
|
||||
this.availableColors = this.allColors.slice();
|
||||
};
|
||||
|
||||
ColorPalette.prototype.remove = function (color) {
|
||||
this.availableColors = this.availableColors.filter(function (c) {
|
||||
return !c.equalTo(color);
|
||||
});
|
||||
};
|
||||
|
||||
ColorPalette.prototype.return = function (color) {
|
||||
if (isDefaultColor(color)) {
|
||||
this.availableColors.unshift(color);
|
||||
}
|
||||
};
|
||||
|
||||
ColorPalette.prototype.getByHexString = function (hexString) {
|
||||
const color = Color.fromHexString(hexString);
|
||||
|
||||
return color;
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {Color} the next unused color in the palette. If all colors
|
||||
* have been allocated, it will wrap around.
|
||||
*/
|
||||
ColorPalette.prototype.getNextColor = function () {
|
||||
if (!this.availableColors.length) {
|
||||
console.warn('Color Palette empty, reusing colors!');
|
||||
this.reset();
|
||||
}
|
||||
|
||||
return this.availableColors.shift();
|
||||
};
|
||||
|
||||
export default ColorPalette;
|
@ -25,7 +25,9 @@ import Vue from 'vue';
|
||||
|
||||
export default function OverlayPlotViewProvider(openmct) {
|
||||
function isCompactView(objectPath) {
|
||||
return objectPath.find(object => object.type === 'time-strip');
|
||||
let isChildOfTimeStrip = objectPath.find(object => object.type === 'time-strip');
|
||||
|
||||
return isChildOfTimeStrip && !openmct.router.isNavigatedObject(objectPath);
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -19,18 +19,12 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
import { BAR_GRAPH_KEY } from './barGraph/BarGraphConstants';
|
||||
import PlotViewProvider from './PlotViewProvider';
|
||||
import SpectralPlotViewProvider from './spectralPlot/SpectralPlotViewProvider';
|
||||
import BarGraphViewProvider from './barGraph/BarGraphViewProvider';
|
||||
import OverlayPlotViewProvider from './overlayPlot/OverlayPlotViewProvider';
|
||||
import StackedPlotViewProvider from './stackedPlot/StackedPlotViewProvider';
|
||||
import PlotsInspectorViewProvider from './inspector/PlotsInspectorViewProvider';
|
||||
import BarGraphInspectorViewProvider from './barGraph/inspector/BarGraphInspectorViewProvider';
|
||||
import OverlayPlotCompositionPolicy from './overlayPlot/OverlayPlotCompositionPolicy';
|
||||
import StackedPlotCompositionPolicy from './stackedPlot/StackedPlotCompositionPolicy';
|
||||
import SpectralPlotCompositionPolicy from './spectralPlot/SpectralPlotCompositionPolicy';
|
||||
import BarGraphCompositionPolicy from './barGraph/BarGraphCompositionPolicy';
|
||||
|
||||
export default function () {
|
||||
return function install(openmct) {
|
||||
@ -64,48 +58,15 @@ export default function () {
|
||||
},
|
||||
priority: 890
|
||||
});
|
||||
openmct.types.addType('telemetry.plot.spectral', {
|
||||
key: "telemetry.plot.spectral",
|
||||
name: "Spectral Plot",
|
||||
cssClass: "icon-plot-stacked",
|
||||
description: "View Spectra on Y Axes with non-time domain on the X axis. Can be added to Display Layouts.",
|
||||
//Temporarily disabling spectral plots
|
||||
creatable: false,
|
||||
initialize: function (domainObject) {
|
||||
domainObject.composition = [];
|
||||
domainObject.configuration = {};
|
||||
},
|
||||
priority: 890
|
||||
});
|
||||
|
||||
openmct.types.addType(BAR_GRAPH_KEY, {
|
||||
key: BAR_GRAPH_KEY,
|
||||
name: "Bar Graph",
|
||||
cssClass: "icon-bar-chart",
|
||||
description: "View data as a bar graph. Can be added to Display Layouts.",
|
||||
creatable: true,
|
||||
initialize: function (domainObject) {
|
||||
domainObject.composition = [];
|
||||
domainObject.configuration = {
|
||||
plotType: 'bar'
|
||||
};
|
||||
},
|
||||
priority: 891
|
||||
});
|
||||
|
||||
openmct.objectViews.addProvider(new StackedPlotViewProvider(openmct));
|
||||
openmct.objectViews.addProvider(new OverlayPlotViewProvider(openmct));
|
||||
openmct.objectViews.addProvider(new PlotViewProvider(openmct));
|
||||
openmct.objectViews.addProvider(new SpectralPlotViewProvider(openmct));
|
||||
openmct.objectViews.addProvider(new BarGraphViewProvider(openmct));
|
||||
|
||||
openmct.inspectorViews.addProvider(new PlotsInspectorViewProvider(openmct));
|
||||
openmct.inspectorViews.addProvider(new BarGraphInspectorViewProvider(openmct));
|
||||
|
||||
openmct.composition.addPolicy(new OverlayPlotCompositionPolicy(openmct).allow);
|
||||
openmct.composition.addPolicy(new StackedPlotCompositionPolicy(openmct).allow);
|
||||
openmct.composition.addPolicy(new SpectralPlotCompositionPolicy(openmct).allow);
|
||||
openmct.composition.addPolicy(new BarGraphCompositionPolicy(openmct).allow);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -24,12 +24,10 @@ import {createMouseEvent, createOpenMct, resetApplicationState, spyOnBuiltins} f
|
||||
import PlotVuePlugin from "./plugin";
|
||||
import Vue from "vue";
|
||||
import StackedPlot from "./stackedPlot/StackedPlot.vue";
|
||||
// import SpectralPlot from "./spectralPlot/SpectralPlot.vue";
|
||||
import configStore from "./configuration/ConfigStore";
|
||||
import EventEmitter from "EventEmitter";
|
||||
import PlotOptions from "./inspector/PlotOptions.vue";
|
||||
import PlotConfigurationModel from "./configuration/PlotConfigurationModel";
|
||||
import { BAR_GRAPH_VIEW, BAR_GRAPH_KEY } from './barGraph/BarGraphConstants';
|
||||
|
||||
describe("the plugin", function () {
|
||||
let element;
|
||||
@ -149,6 +147,7 @@ describe("the plugin", function () {
|
||||
|
||||
spyOn(window, 'ResizeObserver').and.returnValue({
|
||||
observe() {},
|
||||
unobserve() {},
|
||||
disconnect() {}
|
||||
});
|
||||
|
||||
@ -305,37 +304,6 @@ describe("the plugin", function () {
|
||||
expect(plotView).toBeDefined();
|
||||
});
|
||||
|
||||
it("provides a spectral plot view for objects with telemetry", () => {
|
||||
const testTelemetryObject = {
|
||||
id: "test-object",
|
||||
type: "telemetry.plot.spectral",
|
||||
telemetry: {
|
||||
values: [{
|
||||
key: "a-very-fine-key"
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
const applicableViews = openmct.objectViews.get(testTelemetryObject, mockObjectPath);
|
||||
let plotView = applicableViews.find((viewProvider) => viewProvider.key === "plot-spectral");
|
||||
expect(plotView).toBeDefined();
|
||||
});
|
||||
|
||||
it("provides a spectral aggregate plot view for objects with telemetry", () => {
|
||||
const testTelemetryObject = {
|
||||
id: "test-object",
|
||||
type: BAR_GRAPH_KEY,
|
||||
telemetry: {
|
||||
values: [{
|
||||
key: "lots-of-aggregate-telemetry"
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
const applicableViews = openmct.objectViews.get(testTelemetryObject, mockObjectPath);
|
||||
let plotView = applicableViews.find((viewProvider) => viewProvider.key === BAR_GRAPH_VIEW);
|
||||
expect(plotView).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("The single plot view", () => {
|
||||
@ -388,6 +356,10 @@ describe("the plugin", function () {
|
||||
return Vue.nextTick();
|
||||
});
|
||||
|
||||
it("Makes only one request for telemetry on load", () => {
|
||||
expect(openmct.telemetry.request).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("Renders a collapsed legend for every telemetry", () => {
|
||||
let legend = element.querySelectorAll(".plot-wrapper-collapsed-legend .plot-series-name");
|
||||
expect(legend.length).toBe(1);
|
||||
@ -473,6 +445,64 @@ describe("the plugin", function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('resume actions on errant click', () => {
|
||||
beforeEach(() => {
|
||||
openmct.time.clock('local', {
|
||||
start: -1000,
|
||||
end: 100
|
||||
});
|
||||
|
||||
return Vue.nextTick();
|
||||
});
|
||||
|
||||
it("clicking the plot view without movement resumes the plot while active", async () => {
|
||||
|
||||
const pauseEl = element.querySelectorAll(".c-button-set .icon-pause");
|
||||
// if the pause button is present, the chart is running
|
||||
expect(pauseEl.length).toBe(1);
|
||||
|
||||
// simulate an errant mouse click
|
||||
// the second item is the canvas we need to use
|
||||
const canvas = element.querySelectorAll("canvas")[1];
|
||||
const mouseDownEvent = new MouseEvent('mousedown');
|
||||
const mouseUpEvent = new MouseEvent('mouseup');
|
||||
canvas.dispatchEvent(mouseDownEvent);
|
||||
// mouseup event is bound to the window
|
||||
window.dispatchEvent(mouseUpEvent);
|
||||
await Vue.nextTick();
|
||||
|
||||
const pauseElAfterClick = element.querySelectorAll(".c-button-set .icon-pause");
|
||||
console.log('pauseElAfterClick', pauseElAfterClick);
|
||||
expect(pauseElAfterClick.length).toBe(1);
|
||||
|
||||
});
|
||||
|
||||
it("clicking the plot view without movement leaves the plot paused", async () => {
|
||||
|
||||
const pauseEl = element.querySelector(".c-button-set .icon-pause");
|
||||
// pause the plot
|
||||
pauseEl.dispatchEvent(createMouseEvent('click'));
|
||||
await Vue.nextTick();
|
||||
|
||||
const playEl = element.querySelectorAll('.c-button-set .is-paused');
|
||||
expect(playEl.length).toBe(1);
|
||||
|
||||
// simulate an errant mouse click
|
||||
// the second item is the canvas we need to use
|
||||
const canvas = element.querySelectorAll("canvas")[1];
|
||||
const mouseDownEvent = new MouseEvent('mousedown');
|
||||
const mouseUpEvent = new MouseEvent('mouseup');
|
||||
canvas.dispatchEvent(mouseDownEvent);
|
||||
// mouseup event is bound to the window
|
||||
window.dispatchEvent(mouseUpEvent);
|
||||
await Vue.nextTick();
|
||||
|
||||
const playElAfterChartClick = element.querySelectorAll(".c-button-set .is-paused");
|
||||
expect(playElAfterChartClick.length).toBe(1);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('controls in time strip view', () => {
|
||||
|
||||
it('zoom controls are hidden', () => {
|
||||
@ -493,146 +523,6 @@ describe("the plugin", function () {
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
* disabling this until we develop the plot view
|
||||
describe("The spectral plot view", () => {
|
||||
let testTelemetryObject;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
let testTelemetryObject2;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
let config;
|
||||
let spectralPlotObject;
|
||||
let component;
|
||||
let mockComposition;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
let plotViewComponentObject;
|
||||
|
||||
beforeEach(() => {
|
||||
const getFunc = openmct.$injector.get;
|
||||
spyOn(openmct.$injector, "get")
|
||||
.withArgs("exportImageService").and.returnValue({
|
||||
exportPNG: () => {},
|
||||
exportJPG: () => {}
|
||||
})
|
||||
.and.callFake(getFunc);
|
||||
|
||||
spectralPlotObject = {
|
||||
identifier: {
|
||||
namespace: "",
|
||||
key: "test-spectral-plot"
|
||||
},
|
||||
type: "telemetry.plot.spectral",
|
||||
name: "Test Spectral Plot"
|
||||
};
|
||||
|
||||
testTelemetryObject = {
|
||||
identifier: {
|
||||
namespace: "",
|
||||
key: "test-object"
|
||||
},
|
||||
type: "test-object",
|
||||
name: "Test Object",
|
||||
telemetry: {
|
||||
values: [{
|
||||
key: "utc",
|
||||
format: "utc",
|
||||
name: "Time",
|
||||
hints: {
|
||||
domain: 1
|
||||
}
|
||||
}, {
|
||||
key: "some-key",
|
||||
name: "Some attribute",
|
||||
hints: {
|
||||
range: 1
|
||||
}
|
||||
}, {
|
||||
key: "some-other-key",
|
||||
name: "Another attribute",
|
||||
hints: {
|
||||
range: 2
|
||||
}
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
testTelemetryObject2 = {
|
||||
identifier: {
|
||||
namespace: "",
|
||||
key: "test-object2"
|
||||
},
|
||||
type: "test-object",
|
||||
name: "Test Object2",
|
||||
telemetry: {
|
||||
values: [{
|
||||
key: "utc",
|
||||
format: "utc",
|
||||
name: "Time",
|
||||
hints: {
|
||||
domain: 1
|
||||
}
|
||||
}, {
|
||||
key: "wavelength",
|
||||
name: "Wavelength",
|
||||
hints: {
|
||||
range: 1
|
||||
}
|
||||
}, {
|
||||
key: "some-other-key2",
|
||||
name: "Another attribute2",
|
||||
hints: {
|
||||
range: 2
|
||||
}
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
mockComposition = new EventEmitter();
|
||||
mockComposition.load = () => {
|
||||
mockComposition.emit('add', testTelemetryObject);
|
||||
|
||||
return [testTelemetryObject];
|
||||
};
|
||||
|
||||
spyOn(openmct.composition, 'get').and.returnValue(mockComposition);
|
||||
|
||||
let viewContainer = document.createElement("div");
|
||||
child.append(viewContainer);
|
||||
component = new Vue({
|
||||
el: viewContainer,
|
||||
components: {
|
||||
SpectralPlot
|
||||
},
|
||||
provide: {
|
||||
openmct: openmct,
|
||||
domainObject: spectralPlotObject,
|
||||
composition: openmct.composition.get(spectralPlotObject)
|
||||
},
|
||||
template: "<spectral-plot></spectral-plot>"
|
||||
});
|
||||
|
||||
cleanupFirst.push(() => {
|
||||
component.$destroy();
|
||||
component = undefined;
|
||||
});
|
||||
|
||||
return telemetryPromise
|
||||
.then(Vue.nextTick())
|
||||
.then(() => {
|
||||
plotViewComponentObject = component.$root.$children[0];
|
||||
const configId = openmct.objects.makeKeyString(testTelemetryObject.identifier);
|
||||
config = configStore.get(configId);
|
||||
});
|
||||
});
|
||||
|
||||
it("Renders a collapsed legend for every telemetry", () => {
|
||||
let legend = element.querySelectorAll(".plot-wrapper-collapsed-legend .plot-series-name");
|
||||
expect(legend.length).toBe(1);
|
||||
expect(legend[0].innerHTML).toEqual("Test Object");
|
||||
});
|
||||
|
||||
}); */
|
||||
|
||||
describe("The stacked plot view", () => {
|
||||
let testTelemetryObject;
|
||||
let testTelemetryObject2;
|
||||
@ -1163,42 +1053,11 @@ describe("the plugin", function () {
|
||||
const yAxisProperties = editOptionsEl.querySelectorAll("div.grid-properties:first-of-type .l-inspector-part");
|
||||
expect(yAxisProperties.length).toEqual(3);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("the spectral plot", () => {
|
||||
const mockObject = {
|
||||
name: 'A Very Nice Spectral Plot',
|
||||
key: 'telemetry.plot.spectral',
|
||||
creatable: true
|
||||
};
|
||||
|
||||
it('defines a spectral plot object type with the correct key', () => {
|
||||
const objectDef = openmct.types.get('telemetry.plot.spectral').definition;
|
||||
expect(objectDef.key).toEqual(mockObject.key);
|
||||
});
|
||||
|
||||
xit('is creatable', () => {
|
||||
const objectDef = openmct.types.get('telemetry.plot.spectral').definition;
|
||||
expect(objectDef.creatable).toEqual(mockObject.creatable);
|
||||
});
|
||||
});
|
||||
|
||||
describe("the aggregate spectral plot", () => {
|
||||
const mockObject = {
|
||||
name: 'An Even Nicer Aggregate Spectral Plot',
|
||||
key: BAR_GRAPH_KEY,
|
||||
creatable: true
|
||||
};
|
||||
|
||||
it('defines a spectral plot object type with the correct key', () => {
|
||||
const objectDef = openmct.types.get(BAR_GRAPH_KEY).definition;
|
||||
expect(objectDef.key).toEqual(mockObject.key);
|
||||
});
|
||||
|
||||
it('is creatable', () => {
|
||||
const objectDef = openmct.types.get(BAR_GRAPH_KEY).definition;
|
||||
expect(objectDef.creatable).toEqual(mockObject.creatable);
|
||||
it('renders color palette options', () => {
|
||||
const colorSwatch = editOptionsEl.querySelector(".c-click-swatch");
|
||||
expect(colorSwatch).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,36 +0,0 @@
|
||||
export default function SpectralPlotCompositionPolicy(openmct) {
|
||||
function hasSpectralDomainAndRange(metadata) {
|
||||
const rangeValues = metadata.valuesForHints(['range']);
|
||||
const domainValues = metadata.valuesForHints(['domain']);
|
||||
const containsSomeSpectralData = domainValues.some(value => {
|
||||
return ((value.key === 'wavelength') || (value.key === 'frequency'));
|
||||
});
|
||||
|
||||
return rangeValues.length > 0
|
||||
&& domainValues.length > 0
|
||||
&& containsSomeSpectralData;
|
||||
}
|
||||
|
||||
function hasSpectralTelemetry(domainObject) {
|
||||
if (!Object.prototype.hasOwnProperty.call(domainObject, 'telemetry')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let metadata = openmct.telemetry.getMetadata(domainObject);
|
||||
|
||||
return metadata.values().length > 0 && hasSpectralDomainAndRange(metadata);
|
||||
}
|
||||
|
||||
return {
|
||||
allow: function (parent, child) {
|
||||
|
||||
if ((parent.type === 'telemetry.plot.spectral')
|
||||
&& ((child.type !== 'telemetry.plot.overlay') && (hasSpectralTelemetry(child) === false))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2021, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
import SpectralView from './SpectralView.vue';
|
||||
import Vue from 'vue';
|
||||
|
||||
export default function SpectralPlotViewProvider(openmct) {
|
||||
function isCompactView(objectPath) {
|
||||
return objectPath.find(object => object.type === 'time-strip');
|
||||
}
|
||||
|
||||
return {
|
||||
key: 'plot-spectral',
|
||||
name: 'Spectral Plot',
|
||||
cssClass: 'icon-telemetry',
|
||||
canView(domainObject, objectPath) {
|
||||
return domainObject && domainObject.type === 'telemetry.plot.spectral';
|
||||
},
|
||||
|
||||
canEdit(domainObject, objectPath) {
|
||||
return domainObject && domainObject.type === 'telemetry.plot.spectral';
|
||||
},
|
||||
|
||||
view: function (domainObject, objectPath) {
|
||||
let component;
|
||||
|
||||
return {
|
||||
show: function (element) {
|
||||
let isCompact = isCompactView(objectPath);
|
||||
component = new Vue({
|
||||
el: element,
|
||||
components: {
|
||||
SpectralView
|
||||
},
|
||||
provide: {
|
||||
openmct,
|
||||
domainObject
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: {
|
||||
compact: isCompact
|
||||
}
|
||||
};
|
||||
},
|
||||
template: '<spectral-view :options="options"></spectral-view>'
|
||||
});
|
||||
},
|
||||
destroy: function () {
|
||||
component.$destroy();
|
||||
component = undefined;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
inject: ['openmct', 'domainObject']
|
||||
};
|
||||
|
||||
</script>
|
@ -92,7 +92,8 @@ export default {
|
||||
cursorGuide: false,
|
||||
gridLines: true,
|
||||
loading: false,
|
||||
compositionObjects: []
|
||||
compositionObjects: [],
|
||||
tickWidthMap: {}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -106,8 +107,6 @@ export default {
|
||||
mounted() {
|
||||
this.imageExporter = new ImageExporter(this.openmct);
|
||||
|
||||
this.tickWidthMap = {};
|
||||
|
||||
this.composition.on('add', this.addChild);
|
||||
this.composition.on('remove', this.removeChild);
|
||||
this.composition.on('reorder', this.compositionReorder);
|
||||
@ -126,13 +125,15 @@ export default {
|
||||
addChild(child) {
|
||||
const id = this.openmct.objects.makeKeyString(child.identifier);
|
||||
|
||||
this.tickWidthMap[id] = 0;
|
||||
this.$set(this.tickWidthMap, id, 0);
|
||||
this.compositionObjects.push(child);
|
||||
},
|
||||
|
||||
removeChild(childIdentifier) {
|
||||
const id = this.openmct.objects.makeKeyString(childIdentifier);
|
||||
delete this.tickWidthMap[id];
|
||||
|
||||
this.$delete(this.tickWidthMap, id);
|
||||
|
||||
const childObj = this.compositionObjects.filter((c) => {
|
||||
const identifier = this.openmct.objects.makeKeyString(c.identifier);
|
||||
|
||||
@ -190,14 +191,7 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
//update the tickWidth for this plotId, the computed max tick width of the stacked plot will be cascaded down
|
||||
//TODO: Might need to do this using $set
|
||||
this.tickWidthMap[plotId] = Math.max(width, this.tickWidthMap[plotId]);
|
||||
// const newTickWidth = Math.max(...Object.values(this.tickWidthMap));
|
||||
// if (newTickWidth !== tickWidth || width !== tickWidth) {
|
||||
// tickWidth = newTickWidth;
|
||||
// $scope.$broadcast('plot:tickWidth', tickWidth);
|
||||
// }
|
||||
this.$set(this.tickWidthMap, plotId, width);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -25,7 +25,9 @@ import Vue from 'vue';
|
||||
|
||||
export default function StackedPlotViewProvider(openmct) {
|
||||
function isCompactView(objectPath) {
|
||||
return objectPath.find(object => object.type === 'time-strip');
|
||||
let isChildOfTimeStrip = objectPath.find(object => object.type === 'time-strip');
|
||||
|
||||
return isChildOfTimeStrip && !openmct.router.isNavigatedObject(objectPath);
|
||||
}
|
||||
|
||||
return {
|
||||
|
Reference in New Issue
Block a user