merge display layout view config with components, add line view.

* Hacky WIP

* WIP

* check for 'domainobject' in data transfer

* Metadata manager can return default display value

* Refactor subobject and telemetry views to use layout frame

* Use data domainObject

* Get metadata for selected object.

* Don't inject lodash via vue

* move selection to specific layout types

* restore toolbar functionality

* Support creating line

* Add controls for setting x, y, x2 and y2 for lines from the toolbar.

* Initial attempt at resizing lines

* Check for duplicate panel

* line resize handles working

* Get Text and Box elements working.

* Refactor image view to use layout frame

* Fix drill in

* Check for object before accessing the identifier to avoid type error.

* Add inspectable class if item is subobject or telemetry view.

* Delete unused files

* remove unused imports

* Fix typos

* Fix cssClass and objectPath

* object can be undefined so check for it not being undefined before adding a listener.

* Set cssClass when domain object is available

* Get user input for text and image in the toolbar when adding element.
This commit is contained in:
Pegah Sarram 2018-12-11 11:28:16 -08:00 committed by Pete Richards
parent c6a181a2e7
commit c1ef701eb2
18 changed files with 787 additions and 974 deletions

View File

@ -124,6 +124,22 @@ define([
return sortedMetadata;
};
TelemetryMetadataManager.prototype.getDefaultDisplayValue = function () {
let valueMetadata = this.valuesForHints(['range'])[0];
if (valueMetadata === undefined) {
valueMetadata = this.values().filter(values => {
return !(values.hints.domain);
})[0];
}
if (valueMetadata === undefined) {
valueMetadata = this.values()[0];
}
return valueMetadata.key;
};
return TelemetryMetadataManager;

View File

@ -35,9 +35,48 @@ define([], function () {
(selection[0].context.item && selection[0].context.item.type === 'layout')));
},
toolbar: function (selection) {
const DIALOG_FORM = {
'text': {
name: "Text Element Properties",
sections: [
{
rows: [
{
key: "text",
control: "textfield",
name: "Text",
required: true
}
]
}
]
},
'image': {
name: "Image Properties",
sections: [
{
rows: [
{
key: "url",
control: "textfield",
name: "Image URL",
"cssClass": "l-input-lg",
required: true
}
]
}
]
}
};
function getUserInput(form) {
return openmct.$injector.get('dialogService').getUserInput(form, {});
}
let selectedParent = selection[1] && selection[1].context.item,
selectedObject = selection[0].context.item,
layoutItem = selection[0].context.layoutItem,
layoutItemIndex = selection[0].context.index,
toolbar = [];
if (selectedObject && selectedObject.type === 'layout') {
@ -45,7 +84,14 @@ define([], function () {
control: "menu",
domainObject: selectedObject,
method: function (option) {
selection[0].context.addElement(option.name.toLowerCase());
let name = option.name.toLowerCase();
let form = DIALOG_FORM[name];
if (form) {
getUserInput(form)
.then(element => selection[0].context.addElement(name, element));
} else {
selection[0].context.addElement(name);
}
},
key: "add",
icon: "icon-plus",
@ -75,16 +121,19 @@ define([], function () {
return toolbar;
}
let path = `configuration.items[${layoutItemIndex}]`;
let separator = {
control: "separator"
};
if (layoutItem.type === 'subobject-view') {
if (toolbar.length > 0) {
toolbar.push({
control: "separator"
});
toolbar.push(separator);
}
toolbar.push({
control: "toggle-button",
domainObject: selectedParent,
property: "configuration.panels[" + layoutItem.id + "].hasFrame",
property: path + ".hasFrame",
options: [
{
value: false,
@ -100,19 +149,7 @@ define([], function () {
});
} else {
const TEXT_SIZE = [9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 30, 36, 48, 72, 96];
let path;
// TODO: get the path from the view configuration
// let path = layoutItem.config.path();
if (layoutItem.type === 'telemetry-view') {
path = "configuration.alphanumerics[" + layoutItem.config.alphanumeric.index + "]";
} else {
path = "configuration.elements[" + layoutItem.config.element.index + "]";
}
let separator = {
control: "separator"
},
fill = {
let fill = {
control: "color-picker",
domainObject: selectedParent,
property: path + ".fill",
@ -180,9 +217,7 @@ define([], function () {
};
if (layoutItem.type === 'telemetry-view') {
// TODO: add "remove", "order", "useGrid"
let metadata = openmct.telemetry.getMetadata(layoutItem.domainObject),
displayMode = {
let displayMode = {
control: "select-menu",
domainObject: selectedParent,
property: path + ".displayMode",
@ -207,7 +242,7 @@ define([], function () {
domainObject: selectedParent,
property: path + ".value",
title: "Set value",
options: metadata.values().map(value => {
options: openmct.telemetry.getMetadata(selectedObject).values().map(value => {
return {
name: value.name,
value: value.key
@ -231,28 +266,13 @@ define([], function () {
width
];
} else if (layoutItem.type === 'text-view' ) {
// TODO: Add "remove", "order", "useGrid"
let text = {
control: "button",
domainObject: selectedParent,
property: path,
icon: "icon-gear",
title: "Edit text properties",
dialog: {
name: "Text Element Properties",
sections: [
{
rows: [
{
key: "text",
control: "textfield",
name: "Text",
required: true
}
]
}
]
}
dialog: DIALOG_FORM['text']
};
toolbar = [
fill,
@ -269,7 +289,6 @@ define([], function () {
text
];
} else if (layoutItem.type === 'box-view') {
// TODO: Add "remove", "order", "useGrid"
toolbar = [
fill,
stroke,
@ -280,30 +299,14 @@ define([], function () {
width
];
} else if (layoutItem.type === 'image-view') {
// TODO: Add "remove", "order", "useGrid"
let url = {
control: "button",
domainObject: selectedParent,
property: path,
icon: "icon-image",
title: "Edit image properties",
dialog: {
name: "Image Properties",
sections: [
{
rows: [
{
key: "url",
control: "textfield",
name: "Image URL",
"cssClass": "l-input-lg",
required: true
}
]
}
]
}
};
dialog: DIALOG_FORM['image']
};
toolbar = [
stroke,
separator,
@ -315,8 +318,30 @@ define([], function () {
url
];
} else if (layoutItem.type === 'line-view') {
// TODO: Add "remove", "order", "useGrid", "x1", "y1", x2", "y2"
toolbar = [stroke];
let x2 = {
control: "input",
type: "number",
domainObject: selectedParent,
property: path + ".x2",
label: "X2:",
title: "X2 position"
},
y2 = {
control: "input",
type: "number",
domainObject: selectedParent,
property: path + ".y2",
label: "Y2:",
title: "Y2 position",
};
toolbar = [
stroke,
separator,
x,
y,
x2,
y2
];
}
}

View File

@ -29,13 +29,12 @@ define(function () {
initialize(domainObject) {
domainObject.composition = [];
domainObject.configuration = {
panels: {},
alphanumerics: [],
elements: []
items: [],
layoutGrid: [10, 10],
};
}
}
}
return DisplayLayoutType;
});
});

View File

@ -1,171 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
['./ViewConfiguration'],
function (ViewConfiguration) {
class ElementViewConfiguration extends ViewConfiguration {
static create(type, openmct) {
const DEFAULT_WIDTH = 10,
DEFAULT_HEIGHT = 5,
DEFAULT_X = 1,
DEFAULT_Y = 1;
const INITIAL_STATES = {
"image": {
stroke: "transparent"
},
"box": {
fill: "#717171",
stroke: "transparent"
},
"line": {
x: 5,
y: 3,
x2: 6,
y2: 6,
stroke: "#717171"
},
"text": {
fill: "transparent",
stroke: "transparent",
size: "13px",
color: ""
}
};
const DIALOGS = {
"image": {
name: "Image Properties",
sections: [
{
rows: [
{
key: "url",
control: "textfield",
name: "Image URL",
"cssClass": "l-input-lg",
required: true
}
]
}
]
},
"text": {
name: "Text Element Properties",
sections: [
{
rows: [
{
key: "text",
control: "textfield",
name: "Text",
required: true
}
]
}
]
}
};
let element = INITIAL_STATES[type] || {};
element = JSON.parse(JSON.stringify(element));
element.x = element.x || DEFAULT_X;
element.y = element.y || DEFAULT_Y;
element.width = DEFAULT_WIDTH;
element.height = DEFAULT_HEIGHT;
element.type = type;
return DIALOGS[type] ?
openmct.$injector.get('dialogService').getUserInput(DIALOGS[type], element) :
element;
}
/**
* @param {Object} configuration the element (line, box, text or image) view configuration
* @param {Object} configuration.element
* @param {Object} configuration.domainObject the telemetry domain object
* @param {Object} configuration.openmct the openmct object
*/
constructor({element, ...rest}) {
super(rest);
this.element = element;
this.updateStyle(this.position());
}
path() {
return "configuration.elements[" + this.element.index + "]";
}
x() {
return this.element.x;
}
y() {
return this.element.y;
}
width() {
return this.element.width;
}
height() {
return this.element.height;
}
observeProperties() {
[
"width",
"height",
"stroke",
"fill",
"x",
"y",
"x1",
"y1",
"x2",
"y2",
"color",
"size",
"text",
"url"
].forEach(property => {
this.attachListener(property, newValue => {
this.element[property] = newValue;
if (property === 'width' || property === 'height' ||
property === 'x' || property === 'y') {
this.updateStyle();
}
});
});
// TODO: attach listener for useGrid
}
inspectable() {
return false;
}
}
return ElementViewConfiguration;
}
);

View File

@ -1,122 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
['./ViewConfiguration'],
function (ViewConfiguration) {
class SubobjectViewConfiguration extends ViewConfiguration {
static create(domainObject, gridSize, position) {
const MINIMUM_FRAME_SIZE = [320, 180],
DEFAULT_DIMENSIONS = [10, 10],
DEFAULT_POSITION = [0, 0],
DEFAULT_HIDDEN_FRAME_TYPES = ['hyperlink', 'summary-widget'];
function getDefaultDimensions() {
return MINIMUM_FRAME_SIZE.map((min, index) => {
return Math.max(
Math.ceil(min / gridSize[index]),
DEFAULT_DIMENSIONS[index]
);
});
}
function hasFrameByDefault(type) {
return DEFAULT_HIDDEN_FRAME_TYPES.indexOf(type) === -1;
}
position = position || DEFAULT_POSITION;
let defaultDimensions = getDefaultDimensions();
let panel = {
width: defaultDimensions[0],
height: defaultDimensions[1],
x: position[0],
y: position[1],
hasFrame: hasFrameByDefault(domainObject.type)
};
return panel;
}
/**
*
* @param {Object} configuration the subobject view configuration
* @param {String} configuration.id the domain object keystring identifier
* @param {Boolean} configuration.panel
* @param {Object} configuration.domainObject the domain object to observe the changes on
* @param {Object} configuration.openmct the openmct object
*/
constructor({panel, id, ...rest}) {
super(rest);
this.id = id;
this.panel = panel;
this.hasFrame = this.hasFrame.bind(this);
this.updateStyle(this.position());
}
path() {
return "configuration.panels[" + this.id + "]";
}
x() {
return this.panel.x;
}
y() {
return this.panel.y;
}
width() {
return this.panel.width;
}
height() {
return this.panel.height;
}
hasFrame() {
return this.panel.hasFrame;
}
observeProperties() {
[
'hasFrame',
'x',
'y',
'width',
'height'
].forEach(property => {
this.attachListener(property, newValue => {
this.panel[property] = newValue;
if (property === 'width' || property === 'height' ||
property === 'x' || property === 'y') {
this.updateStyle();
}
});
});
}
}
return SubobjectViewConfiguration;
}
);

View File

@ -1,124 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
['./ViewConfiguration'],
function (ViewConfiguration) {
class TelemetryViewConfiguration extends ViewConfiguration {
static create(domainObject, position, openmct) {
const DEFAULT_TELEMETRY_DIMENSIONS = [10, 5];
function getDefaultTelemetryValue(domainObject, openmct) {
let metadata = openmct.telemetry.getMetadata(domainObject);
let valueMetadata = metadata.valuesForHints(['range'])[0];
if (valueMetadata === undefined) {
valueMetadata = metadata.values().filter(values => {
return !(values.hints.domain);
})[0];
}
if (valueMetadata === undefined) {
valueMetadata = metadata.values()[0];
}
return valueMetadata.key;
}
let alphanumeric = {
identifier: domainObject.identifier,
x: position[0],
y: position[1],
width: DEFAULT_TELEMETRY_DIMENSIONS[0],
height: DEFAULT_TELEMETRY_DIMENSIONS[1],
displayMode: 'all',
value: getDefaultTelemetryValue(domainObject, openmct),
stroke: "transparent",
fill: "",
color: "",
size: "13px",
};
return alphanumeric;
}
/**
* @param {Object} configuration the telemetry object view configuration
* @param {Object} configuration.alphanumeric
* @param {Object} configuration.domainObject the domain object to observe the changes on
* @param {Object} configuration.openmct the openmct object
*/
constructor({alphanumeric, ...rest}) {
super(rest);
this.alphanumeric = alphanumeric;
this.updateStyle(this.position());
}
path() {
return "configuration.alphanumerics[" + this.alphanumeric.index + "]";
}
x() {
return this.alphanumeric.x;
}
y() {
return this.alphanumeric.y;
}
width() {
return this.alphanumeric.width;
}
height() {
return this.alphanumeric.height;
}
observeProperties() {
[
'displayMode',
'value',
'fill',
'stroke',
'color',
'size',
'x',
'y',
'width',
'height'
].forEach(property => {
this.attachListener(property, newValue => {
this.alphanumeric[property] = newValue;
if (property === 'width' || property === 'height' ||
property === 'x' || property === 'y') {
this.updateStyle();
}
});
});
}
}
return TelemetryViewConfiguration;
}
);

View File

@ -1,121 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([],
function () {
class ViewConfiguration {
constructor({domainObject, openmct, gridSize}) {
this.domainObject = domainObject;
this.gridSize = gridSize;
this.mutatePosition = this.mutatePosition.bind(this);
this.listeners = [];
this.observe = openmct.objects.observe.bind(openmct.objects);
this.mutate = function (path, value) {
openmct.objects.mutate(this.domainObject, path, value);
}.bind(this);
this.newPosition = {};
}
mutatePosition() {
this.mutate(this.path() + ".x", this.newPosition.position[0]);
this.mutate(this.path() + ".y", this.newPosition.position[1]);
this.mutate(this.path() + ".width", this.newPosition.dimensions[0]);
this.mutate(this.path() + ".height", this.newPosition.dimensions[1]);
}
attachListener(property, callback) {
this.listeners.push(this.observe(this.domainObject, this.path() + "." + property, callback));
}
attachListeners() {
this.observeProperties();
this.listeners.push(this.observe(this.domainObject, '*', function (obj) {
this.domainObject = JSON.parse(JSON.stringify(obj));
}.bind(this)));
}
removeListeners() {
this.listeners.forEach(listener => {
listener();
});
this.listeners = [];
}
position() {
return {
position: [this.x(), this.y()],
dimensions: [this.width(), this.height()]
};
}
path() {
throw "NOT IMPLEMENTED;"
}
inspectable() {
return true;
}
updateStyle(raw) {
if (!raw) {
raw = this.position();
}
this.style = {
left: (this.gridSize[0] * raw.position[0]) + 'px',
top: (this.gridSize[1] * raw.position[1]) + 'px',
width: (this.gridSize[0] * raw.dimensions[0]) + 'px',
height: (this.gridSize[1] * raw.dimensions[1]) + 'px',
minWidth: (this.gridSize[0] * raw.dimensions[0]) + 'px',
minHeight: (this.gridSize[1] * raw.dimensions[1]) + 'px'
};
}
observeProperties() {
// Not implemented
}
x() {
// Not implemented
}
y() {
// Not implemented
}
width() {
// Not implemented
}
height() {
// Not implemented
}
hasFrame() {
// Not implemented
}
}
return ViewConfiguration;
}
);

View File

@ -21,9 +21,13 @@
*****************************************************************************/
<template>
<div class="c-box-view"
:style="styleObject">
</div>
<layout-frame :item="item"
:grid-size="gridSize"
@endDrag="(item, updates) => $emit('endDrag', item, updates)">
<div class="c-box-view"
:style="style">
</div>
</layout-frame>
</template>
<style lang="scss">
@ -40,24 +44,53 @@
</style>
<script>
import LayoutFrame from './LayoutFrame.vue'
export default {
makeDefinition() {
return {
fill: '#717171',
stroke: 'transparent',
x: 1,
y: 1,
width: 10,
height: 5
};
},
inject: ['openmct'],
components: {
LayoutFrame
},
props: {
item: Object
item: Object,
gridSize: Array,
index: Number,
initSelect: Boolean
},
computed: {
styleObject() {
let element = this.item.config.element;
style() {
return {
backgroundColor: element.fill,
border: '1px solid ' + element.stroke
}
backgroundColor: this.item.fill,
border: '1px solid ' + this.item.stroke
};
}
},
mounted() {
this.item.config.attachListeners();
let context = {
layoutItem: this.item,
index: this.index
};
this.removeSelectable = this.openmct.selection.selectable(
this.$el,
context,
this.initSelect
);
},
destroyed() {
this.item.config.removeListeners();
if (this.removeSelectable) {
this.removeSelectable();
}
}
}
</script>
</script>

View File

@ -37,15 +37,16 @@
v-if="gridSize[1] >= 3"
:style="[{ backgroundSize: '100%' + gridSize[1] + 'px' }]"></div>
</div>
<layout-item v-for="(item, index) in layoutItems"
class="l-layout__frame"
:key="index"
:item="item"
:gridSize="gridSize"
@drilledIn="updateDrilledInState"
@dragInProgress="updatePosition"
@endDrag="endDrag">
</layout-item>
<component v-for="(item, index) in layoutItems"
:is="item.type"
:item="item"
:gridSize="gridSize"
:initSelect="initSelectIndex === index"
:index="index"
@drilledIn="updateDrilledIn"
@endDrag="endDrag"
>
</component>
</div>
</div>
</template>
@ -85,112 +86,74 @@
<script>
import LayoutItem from './LayoutItem.vue';
import TelemetryViewConfiguration from './../TelemetryViewConfiguration.js'
import SubobjectViewConfiguration from './../SubobjectViewConfiguration.js'
import ElementViewConfiguration from './../ElementViewConfiguration.js'
import uuid from 'uuid';
const DEFAULT_GRID_SIZE = [10, 10];
import SubobjectView from './SubobjectView.vue'
import TelemetryView from './TelemetryView.vue'
import BoxView from './BoxView.vue'
import TextView from './TextView.vue'
import LineView from './LineView.vue'
import ImageView from './ImageView.vue'
const ITEM_TYPE_VIEW_MAP = {
'subobject-view': SubobjectView,
'telemetry-view': TelemetryView,
'box-view': BoxView,
'line-view': LineView,
'text-view': TextView,
'image-view': ImageView
};
function getItemDefinition(itemType, ...options) {
let itemView = ITEM_TYPE_VIEW_MAP[itemType];
if (!itemView) {
throw `Invalid itemType: ${itemType}`;
}
return itemView.makeDefinition(...options);
}
export default {
data() {
let domainObject = JSON.parse(JSON.stringify(this.domainObject));
return {
gridSize: [],
layoutItems: [],
drilledIn: undefined
drilledIn: undefined,
internalDomainObject: domainObject,
initSelectIndex: undefined
};
},
computed: {
gridSize() {
return this.internalDomainObject.configuration.layoutGrid;
},
layoutItems() {
return this.internalDomainObject.configuration.items;
}
},
},
inject: ['openmct'],
props: ['domainObject'],
components: {
LayoutItem
},
components: ITEM_TYPE_VIEW_MAP,
methods: {
getAlphanumerics() {
let alphanumerics = this.newDomainObject.configuration.alphanumerics || [];
alphanumerics.forEach((alphanumeric, index) => {
alphanumeric.index = index;
this.makeTelemetryItem(alphanumeric, false);
});
},
getElements() {
let elements = this.newDomainObject.configuration.elements || [];
elements.forEach((element, index) => {
element.index = index;
this.makeElementItem(element, false);
});
},
makeSubobjectItem(panel, initSelect) {
let id = this.openmct.objects.makeKeyString(panel.domainObject.identifier);
let config = new SubobjectViewConfiguration({
domainObject: this.newDomainObject,
panel: panel,
id: id,
openmct: openmct,
gridSize: this.gridSize
});
this.layoutItems.push({
id: id,
domainObject: panel.domainObject,
drilledIn: this.isItemDrilledIn(id),
initSelect: initSelect,
type: 'subobject-view',
config: config
});
},
makeTelemetryItem(alphanumeric, initSelect) {
let id = this.openmct.objects.makeKeyString(alphanumeric.identifier);
this.openmct.objects.get(id).then(domainObject => {
let config = new TelemetryViewConfiguration({
domainObject: this.newDomainObject,
alphanumeric: alphanumeric,
openmct: openmct,
gridSize: this.gridSize
});
this.layoutItems.push({
id: id,
domainObject: domainObject,
initSelect: initSelect,
type: 'telemetry-view',
config: config
});
});
},
makeElementItem(element, initSelect) {
let config = new ElementViewConfiguration({
domainObject: this.newDomainObject,
element: element,
openmct: openmct,
gridSize: this.gridSize
});
this.layoutItems.push({
initSelect: initSelect,
type: element.type + '-view',
config: config
});
addElement(itemType, element) {
this.addItem(itemType + '-view', element);
},
setSelection(selection) {
if (selection.length === 0) {
return;
}
this.updateDrilledInState();
this.updateDrilledIn();
},
updateDrilledInState(id) {
this.drilledIn = id;
this.layoutItems.forEach(function (item) {
updateDrilledIn(drilledInItem) {
let identifier = drilledInItem && this.openmct.objects.makeKeyString(drilledInItem.identifier);
this.drilledIn = identifier;
this.layoutItems.forEach(item => {
if (item.type === 'subobject-view') {
item.drilledIn = item.id === id;
item.drilledIn = this.openmct.objects.makeKeyString(item.identifier) === identifier;
}
});
},
isItemDrilledIn(id) {
return this.drilledIn === id;
},
updatePosition(item, newPosition) {
item.config.newPosition = newPosition;
item.config.updateStyle(newPosition);
},
bypassSelection($event) {
if (this.dragInProgress) {
if ($event) {
@ -199,59 +162,56 @@
return;
}
},
endDrag(item) {
endDrag(item, updates) {
this.dragInProgress = true;
setTimeout(function () {
this.dragInProgress = false;
}.bind(this), 0);
// TODO: emit "finishResizing" for view components to mutate position?
item.config.mutatePosition();
let index = this.layoutItems.indexOf(item);
Object.assign(item, updates);
this.mutate(`configuration.items[${index}]`, item);
},
mutate(path, value) {
this.openmct.objects.mutate(this.newDomainObject, path, value);
this.openmct.objects.mutate(this.internalDomainObject, path, value);
},
handleDrop($event) {
if (!$event.dataTransfer.types.includes('domainobject')) {
return;
}
$event.preventDefault();
let domainObject = JSON.parse($event.dataTransfer.getData('domainObject'));
let domainObject = JSON.parse($event.dataTransfer.getData('domainobject'));
let elementRect = this.$el.getBoundingClientRect();
this.droppedObjectPosition = [
let droppedObjectPosition = [
Math.floor(($event.pageX - elementRect.left) / this.gridSize[0]),
Math.floor(($event.pageY - elementRect.top) / this.gridSize[1])
];
if (this.isTelemetry(domainObject)) {
this.addAlphanumeric(domainObject, this.droppedObjectPosition);
this.addItem('telemetry-view', domainObject, droppedObjectPosition);
} else {
this.checkForDuplicatePanel(domainObject);
}
},
checkForDuplicatePanel(domainObject) {
let id = this.openmct.objects.makeKeyString(domainObject.identifier);
let panels = this.newDomainObject.configuration.panels;
let identifier = this.openmct.objects.makeKeyString(domainObject.identifier);
if (panels && panels[id]) {
let prompt = this.openmct.overlays.dialog({
iconClass: 'alert',
message: "This item is already in layout and will not be added again.",
buttons: [
{
label: 'OK',
callback: function () {
prompt.dismiss();
if (!this.objectViewMap[identifier]) {
this.addItem('subobject-view', domainObject, droppedObjectPosition);
} else {
let prompt = this.openmct.overlays.dialog({
iconClass: 'alert',
message: "This item is already in layout and will not be added again.",
buttons: [
{
label: 'OK',
callback: function () {
prompt.dismiss();
}
}
}
]
});
]
});
}
}
},
addAlphanumeric(domainObject, position) {
let alphanumerics = this.newDomainObject.configuration.alphanumerics || [];
let alphanumeric = TelemetryViewConfiguration.create(domainObject, position, this.openmct);
alphanumeric.index = alphanumerics.push(alphanumeric) - 1;
this.mutate("configuration.alphanumerics", alphanumerics);
this.makeTelemetryItem(alphanumeric, true);
},
handleDragOver($event){
$event.preventDefault();
},
@ -263,63 +223,58 @@
return false;
}
},
addSubobject(domainObject) {
if (!this.isTelemetry(domainObject)) {
let panels = this.newDomainObject.configuration.panels,
id = this.openmct.objects.makeKeyString(domainObject.identifier),
panel = panels[id],
mutateObject = false,
initSelect = false;
// If the panel doesn't exist, create one and mutate the configuration
if (!panel) {
panel = SubobjectViewConfiguration.create(domainObject, this.gridSize, this.droppedObjectPosition);
initSelect = true;
this.mutate("configuration.panels[" + id + "]", panel);
delete this.droppedObjectPosition;
}
panel.domainObject = domainObject;
this.makeSubobjectItem(panel, initSelect);
addItem(itemType, ...options) {
let item = getItemDefinition(itemType, this.openmct, this.gridSize, ...options);
item.type = itemType;
this.trackItem(item);
this.layoutItems.push(item);
this.openmct.objects.mutate(this.internalDomainObject, "configuration.items", this.layoutItems);
this.initSelectIndex = this.layoutItems.length - 1;
},
trackItem(item) {
if (item.type === "telemetry-view") {
this.telemetryViewMap[this.openmct.objects.makeKeyString(item.identifier)] = true;
} else if (item.type === "subobject-view") {
this.objectViewMap[this.openmct.objects.makeKeyString(item.identifier)] = true;
}
},
removeSubobject() {
// Not yet implemented
initializeItems() {
this.telemetryViewMap = {};
this.objectViewMap = {};
this.layoutItems.forEach(this.trackItem);
},
addElement(type) {
let elements = this.newDomainObject.configuration.elements || [];
Promise.resolve(ElementViewConfiguration.create(type, this.openmct))
.then(element => {
element.index = elements.push(element) - 1;
this.mutate("configuration.elements", elements);
this.makeElementItem(element, true);
});
addChild(child) {
let identifier = this.openmct.objects.makeKeyString(child.identifier);
if (this.isTelemetry(child)) {
if (!this.telemetryViewMap[identifier]) {
this.addItem('telemetry-view', child);
}
} else if (!this.objectViewMap[identifier]) {
this.addItem('subobject-view', child);
}
},
removeChild(identifier) {
// TODO: implement
}
},
mounted() {
this.newDomainObject = this.domainObject;
this.gridSize = this.newDomainObject.layoutGrid || DEFAULT_GRID_SIZE;
this.unlisten = this.openmct.objects.observe(this.newDomainObject, '*', function (obj) {
this.newDomainObject = JSON.parse(JSON.stringify(obj));
this.gridSize = this.newDomainObject.layoutGrid || DEFAULT_GRID_SIZE;;
this.unlisten = this.openmct.objects.observe(this.internalDomainObject, '*', function (obj) {
this.internalDomainObject = JSON.parse(JSON.stringify(obj));
}.bind(this));
this.openmct.selection.on('change', this.setSelection);
this.composition = this.openmct.composition.get(this.newDomainObject);
this.composition.on('add', this.addSubobject);
this.composition.on('remove', this.removeSubobject);
this.initializeItems();
this.composition = this.openmct.composition.get(this.internalDomainObject);
this.composition.on('add', this.addChild);
this.composition.on('remove', this.removeChild);
this.composition.load();
this.getAlphanumerics();
this.getElements();
},
destroyed: function () {
this.openmct.off('change', this.setSelection);
this.composition.off('add', this.addSubobject);
this.composition.off('remove', this.removeSubobject);
this.composition.off('add', this.addChild);
this.composition.off('remove', this.removeChild);
this.unlisten();
}
}
</script>
</script>

View File

@ -21,9 +21,13 @@
*****************************************************************************/
<template>
<div class="c-image-view"
:style="styleObject">
</div>
<layout-frame :item="item"
:grid-size="gridSize"
@endDrag="(item, updates) => $emit('endDrag', item, updates)">
<div class="c-image-view"
:style="style">
</div>
</layout-frame>
</template>
<style lang="scss">
@ -42,24 +46,49 @@
</style>
<script>
import LayoutFrame from './LayoutFrame.vue'
export default {
makeDefinition(openmct, gridSize, element) {
return {
stroke: 'transparent',
x: 1,
y: 1,
width: 10,
height: 5,
url: element.url
};
},
inject: ['openmct'],
props: {
item: Object
item: Object,
gridSize: Array,
index: Number,
initSelect: Boolean
},
components: {
LayoutFrame
},
computed: {
styleObject() {
let element = this.item.config.element;
style() {
return {
backgroundImage: 'url(' + element.url + ')',
border: '1px solid ' + element.stroke
backgroundImage: 'url(' + this.item.url + ')',
border: '1px solid ' + this.item.stroke
}
}
},
mounted() {
this.item.config.attachListeners();
let context = {
layoutItem: this.item,
index: this.index
};
this.removeSelectable = this.openmct.selection.selectable(
this.$el, context, this.initSelect);
},
destroyed() {
this.item.config.removeListeners();
if (this.removeSelectable) {
this.removeSelectable();
}
}
}
</script>

View File

@ -21,14 +21,16 @@
*****************************************************************************/
<template>
<div class="c-frame has-local-controls"
:style="item.config.style"
:class="[classObject, {
'u-inspectable': item.config.inspectable()
}]"
@dblclick="drill(item.id, $event)">
<div class="l-layout__frame c-frame has-local-controls"
:class="{
'no-frame': !item.hasFrame,
'u-inspectable': inspectable,
'is-drilled-in': item.drilledIn
}"
:style="style"
@dblclick="drill($event)">
<component :is="item.type" :item="item" :gridSize="gridSize"></component>
<slot></slot>
<!-- Drag handles -->
<div class="c-frame-edit">
@ -72,12 +74,6 @@
<script>
import SubobjectView from './SubobjectView.vue'
import TelemetryView from './TelemetryView.vue'
import BoxView from './BoxView.vue'
import TextView from './TextView.vue'
import LineView from './LineView.vue'
import ImageView from './ImageView.vue'
import LayoutDrag from './../LayoutDrag'
export default {
@ -86,46 +82,51 @@
item: Object,
gridSize: Array
},
components: {
SubobjectView,
TelemetryView,
BoxView,
TextView,
LineView,
ImageView
data() {
return {
dragPosition: undefined
}
},
computed: {
classObject: function () {
return {
'is-drilled-in': this.item.drilledIn,
'no-frame': !this.item.config.hasFrame()
style() {
let {x, y, width, height} = this.item;
if (this.dragPosition) {
[x, y] = this.dragPosition.position;
[width, height] = this.dragPosition.dimensions;
}
return {
left: (this.gridSize[0] * x) + 'px',
top: (this.gridSize[1] * y) + 'px',
width: (this.gridSize[0] * width) + 'px',
height: (this.gridSize[1] * height) + 'px',
minWidth: (this.gridSize[0] * width) + 'px',
minHeight: (this.gridSize[1] * height) + 'px'
};
},
inspectable() {
return this.item.type === 'subobject-view' || this.item.type === 'telemetry-view';
}
},
methods: {
drill(id, $event) {
drill($event) {
if ($event) {
$event.stopPropagation();
}
if (!this.openmct.editor.isEditing()) {
if (!this.openmct.editor.isEditing() || !this.item.identifier) {
return;
}
if (!this.item.domainObject) {
return;
}
this.openmct.objects.get(this.item.identifier)
.then(domainObject => {
if (this.openmct.composition.get(domainObject) === undefined) {
return;
}
if (this.openmct.composition.get(this.item.domainObject) === undefined) {
return;
}
// Disable for fixed position.
if (this.item.domainObject.type === 'telemetry.fixed') {
return;
}
this.$emit('drilledIn', id);
this.$emit('drilledIn', this.item);
});
},
updatePosition(event) {
let currentPosition = [event.pageX, event.pageY];
@ -138,51 +139,31 @@
document.body.addEventListener('mousemove', this.continueDrag);
document.body.addEventListener('mouseup', this.endDrag);
this.dragPosition = {
position: [this.item.x, this.item.y],
dimensions: [this.item.width, this.item.height]
};
this.updatePosition(event);
this.activeDrag = new LayoutDrag(
this.item.config.position(),
posFactor,
dimFactor,
this.gridSize
);
this.activeDrag = new LayoutDrag(this.dragPosition, posFactor, dimFactor, this.gridSize);
event.preventDefault();
},
continueDrag(event) {
event.preventDefault();
this.updatePosition(event);
if (this.activeDrag) {
this.$emit(
'dragInProgress',
this.item,
this.activeDrag.getAdjustedPosition(this.delta)
);
}
this.dragPosition = this.activeDrag.getAdjustedPosition(this.delta);
},
endDrag(event) {
document.body.removeEventListener('mousemove', this.continueDrag);
document.body.removeEventListener('mouseup', this.endDrag);
this.continueDrag(event);
this.$emit('endDrag', this.item);
let [x, y] = this.dragPosition.position;
let [width, height] = this.dragPosition.dimensions;
this.$emit('endDrag', this.item, {x, y, width, height});
this.dragPosition = undefined;
this.initialPosition = undefined;
this.delta = undefined;
event.preventDefault();
}
},
mounted() {
let context = {
item: this.item.domainObject,
layoutItem: this.item,
addElement: this.$parent.addElement
};
this.removeSelectable = this.openmct.selection.selectable(
this.$el,
context,
this.item.initSelect
);
},
destroyed() {
this.removeSelectable();
}
}
</script>
</script>

View File

@ -20,37 +20,212 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<div>
<svg :width="gridSize[0] * element.width"
:height=" gridSize[1] * element.height">
<line :x1=" gridSize[0] * element.x1 + 1"
:y1="gridSize[1] * element.y1 + 1 "
:x2="gridSize[0] * element.x2 + 1"
:y2=" gridSize[1] * element.y2 + 1 "
:stroke="element.stroke"
stroke-width="2">
</line>
</svg>
</div>
</template>
<template>
<div class="l-layout__frame c-frame has-local-controls no-frame"
:style="style">
<svg width="100%"
height="100%">
<line v-bind="linePosition"
:stroke="item.stroke"
stroke-width="2">
</line>
</svg>
<div class="c-frame-edit">
<div class="c-frame-edit__move"
@mousedown="startDrag($event)"></div>
<div class="c-frame-edit__handle"
:class="startHandleClass"
@mousedown="startDrag($event, 'start')"></div>
<div class="c-frame-edit__handle"
:class="endHandleClass"
@mousedown="startDrag($event, 'end')"></div>
</div>
</div>
</template>
<script>
const START_HANDLE_QUADRANTS = {
1: 'c-frame-edit__handle--sw',
2: 'c-frame-edit__handle--se',
3: 'c-frame-edit__handle--ne',
4: 'c-frame-edit__handle--nw'
};
const END_HANDLE_QUADRANTS = {
1: 'c-frame-edit__handle--ne',
2: 'c-frame-edit__handle--nw',
3: 'c-frame-edit__handle--sw',
4: 'c-frame-edit__handle--se'
};
export default {
makeDefinition() {
return {
x: 5,
y: 10,
x2: 10,
y2: 5,
stroke: '#717171'
};
},
inject: ['openmct'],
props: {
item: Object,
gridSize: Array
gridSize: Array,
initSelect: Boolean,
index: Number,
},
data() {
return {
dragPosition: undefined
};
},
computed: {
element() {
return this.item.config.element;
position() {
let {x, y, x2, y2} = this.item;
if (this.dragPosition) {
({x, y, x2, y2} = this.dragPosition);
}
return {x, y, x2, y2};
},
style() {
let {x, y, x2, y2} = this.position;
let width = this.gridSize[0] * Math.abs(x - x2);
let height = this.gridSize[1] * Math.abs(y - y2);
let left = this.gridSize[0] * Math.min(x, x2);
let top = this.gridSize[1] * Math.min(y, y2);
return {
left: `${left}px`,
top: `${top}px`,
width: `${width}px`,
height: `${height}px`,
minWidth: `${width}px`,
minHeight: `${height}px`,
position: 'absolute'
};
},
startHandleClass() {
return START_HANDLE_QUADRANTS[this.vectorQuadrant];
},
endHandleClass() {
return END_HANDLE_QUADRANTS[this.vectorQuadrant];
},
vectorQuadrant() {
let {x, y, x2, y2} = this.position;
if (x2 > x) {
if (y2 < y) {
return 1;
}
return 4;
}
if (y2 < y) {
return 2;
}
return 3;
},
linePosition() {
if (this.vectorQuadrant === 1) {
return {
x1: '0%',
y1: '100%',
x2: '100%',
y2: '0%'
};
}
if (this.vectorQuadrant === 4) {
return {
x1: '0%',
y1: '0%',
x2: '100%',
y2: '100%'
};
}
if (this.vectorQuadrant === 2) {
return {
x1: '0%',
y1: '0%',
x2: '100%',
y2: '100%'
};
}
if (this.vectorQuadrant === 3) {
return {
x1: '100%',
y1: '0%',
x2: '0%',
y2: '100%'
};
}
}
},
methods: {
startDrag(event, position) {
this.dragging = position;
document.body.addEventListener('mousemove', this.continueDrag);
document.body.addEventListener('mouseup', this.endDrag);
this.startPosition = [event.pageX, event.pageY];
this.dragPosition = {
x: this.item.x,
y: this.item.y,
x2: this.item.x2,
y2: this.item.y2
};
event.preventDefault();
},
continueDrag(event) {
event.preventDefault();
let pxDeltaX = this.startPosition[0] - event.pageX;
let pxDeltaY = this.startPosition[1] - event.pageY;
this.dragPosition = this.calculateDragPosition(pxDeltaX, pxDeltaY);
},
endDrag(event) {
document.body.removeEventListener('mousemove', this.continueDrag);
document.body.removeEventListener('mouseup', this.endDrag);
let {x, y, x2, y2} = this.dragPosition;
this.$emit('endDrag', this.item, {x, y, x2, y2});
this.dragPosition = undefined;
this.dragging = undefined;
event.preventDefault();
},
calculateDragPosition(pxDeltaX, pxDeltaY) {
let gridDeltaX = Math.round(pxDeltaX / this.gridSize[0]);
let gridDeltaY = Math.round(pxDeltaY / this.gridSize[0]); // TODO: should this be gridSize[1]?
let {x, y, x2, y2} = this.item;
let dragPosition = {x, y, x2, y2};
if (this.dragging === 'start') {
dragPosition.x -= gridDeltaX;
dragPosition.y -= gridDeltaY;
} else if (this.dragging === 'end') {
dragPosition.x2 -= gridDeltaX;
dragPosition.y2 -= gridDeltaY;
} else {
// dragging entire line.
dragPosition.x -= gridDeltaX;
dragPosition.y -= gridDeltaY;
dragPosition.x2 -= gridDeltaX;
dragPosition.y2 -= gridDeltaY;
}
return dragPosition;
}
},
mounted() {
this.item.config.attachListeners();
let context = {
layoutItem: this.item,
index: this.index
};
this.removeSelectable = this.openmct.selection.selectable(
this.$el,
context,
this.initSelect
);
},
destroyed() {
this.item.config.removeListeners();
if (this.removeSelectable) {
this.removeSelectable();
}
}
}
</script>
</script>

View File

@ -20,24 +20,29 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
<template>
<div class="u-contents">
<div class="c-so-view__header">
<div class="c-so-view__header__start">
<div class="c-so-view__header__name"
:class="cssClass">
{{ item.domainObject.name }}
<layout-frame :item="item"
:grid-size="gridSize"
@endDrag="(item, updates) => $emit('endDrag', item, updates)"
@drilledIn="item => $emit('drilledIn', item)">
<div class="u-contents">
<div class="c-so-view__header">
<div class="c-so-view__header__start">
<div class="c-so-view__header__name"
:class="cssClass">
{{ domainObject && domainObject.name }}
</div>
<context-menu-drop-down
:object-path="objectPath">
</context-menu-drop-down>
</div>
<div class="c-so-view__header__end">
<div class="c-button icon-expand local-controls--hidden"></div>
</div>
<context-menu-drop-down
:object-path="objectPath">
</context-menu-drop-down>
</div>
<div class="c-so-view__header__end">
<div class="c-button icon-expand local-controls--hidden"></div>
</div>
<object-view class="c-so-view__object-view"
:object="domainObject"></object-view>
</div>
<object-view class="c-so-view__object-view"
:object="item.domainObject"></object-view>
</div>
</layout-frame>
</template>
<style lang="scss">
@ -101,34 +106,82 @@
</style>
<script>
import ObjectView from '../../../ui/components/layout/ObjectView.vue';
import contextMenuDropDown from './contextMenuDropDown.vue';
import ObjectView from '../../../ui/components/layout/ObjectView.vue'
import ContextMenuDropDown from './contextMenuDropDown.vue';
import LayoutFrame from './LayoutFrame.vue'
const MINIMUM_FRAME_SIZE = [320, 180],
DEFAULT_DIMENSIONS = [10, 10],
DEFAULT_POSITION = [1, 1],
DEFAULT_HIDDEN_FRAME_TYPES = ['hyperlink', 'summary-widget'];
function getDefaultDimensions(gridSize) {
return MINIMUM_FRAME_SIZE.map((min, index) => {
return Math.max(
Math.ceil(min / gridSize[index]),
DEFAULT_DIMENSIONS[index]
);
});
}
function hasFrameByDefault(type) {
return DEFAULT_HIDDEN_FRAME_TYPES.indexOf(type) === -1;
}
export default {
makeDefinition(openmct, gridSize, domainObject, position) {
let defaultDimensions = getDefaultDimensions(gridSize);
position = position || DEFAULT_POSITION;
return {
width: defaultDimensions[0],
height: defaultDimensions[1],
x: position[0],
y: position[1],
identifier: domainObject.identifier,
hasFrame: hasFrameByDefault(domainObject.type)
};
},
inject: ['openmct'],
props: {
item: Object
item: Object,
gridSize: Array,
initSelect: Boolean,
index: Number
},
data() {
return {
domainObject: undefined,
cssClass: undefined,
objectPath: []
}
},
components: {
ObjectView,
contextMenuDropDown
ContextMenuDropDown,
LayoutFrame
},
data() {
let type = this.openmct.types.get(this.item.domainObject.type);
return {
cssClass: type.definition.cssClass,
objectPath: [this.item.domainObject].concat(this.openmct.router.path)
methods: {
setObject(domainObject) {
this.domainObject = domainObject;
this.objectPath = [this.domainObject].concat(this.openmct.router.path);
this.cssClass = this.openmct.types.get(this.domainObject.type).definition.cssClass;
let context = {
item: domainObject,
layoutItem: this.item,
index: this.index
};
this.removeSelectable = this.openmct.selection.selectable(
this.$el, context, this.initSelect);
}
},
mounted() {
if (this.item.config) {
this.item.config.attachListeners();
}
this.openmct.objects.get(this.item.identifier)
.then(this.setObject);
},
destroyed() {
if (this.item.config) {
this.item.config.removeListeners();
if (this.removeSelectable) {
this.removeSelectable();
}
}
}

View File

@ -21,20 +21,25 @@
*****************************************************************************/
<template>
<div class="c-telemetry-view"
:style="styleObject">
<div v-if="showLabel"
class="c-telemetry-view__label">
<div class="c-telemetry-view__label-text">{{ item.domainObject.name }}</div>
</div>
<layout-frame :item="item"
:grid-size="gridSize"
@endDrag="(item, updates) => $emit('endDrag', item, updates)">
<div class="c-telemetry-view"
:style="styleObject"
v-if="domainObject">
<div v-if="showLabel"
class="c-telemetry-view__label">
<div class="c-telemetry-view__label-text">{{ domainObject.name }}</div>
</div>
<div v-if="showValue"
:title="fieldName"
class="c-telemetry-view__value"
:class="[telemetryClass]">
<div class="c-telemetry-view__value-text">{{ telemetryValue }}</div>
<div v-if="showValue"
:title="fieldName"
class="c-telemetry-view__value"
:class="[telemetryClass]">
<div class="c-telemetry-view__value-text">{{ telemetryValue }}</div>
</div>
</div>
</div>
</layout-frame>
</template>
<style lang="scss">
@ -72,37 +77,65 @@
</style>
<script>
import LayoutFrame from './LayoutFrame.vue'
const DEFAULT_TELEMETRY_DIMENSIONS = [10, 5],
DEFAULT_POSITION = [1, 1];
export default {
makeDefinition(openmct, gridSize, domainObject, position) {
let metadata = openmct.telemetry.getMetadata(domainObject);
position = position || DEFAULT_POSITION;
return {
identifier: domainObject.identifier,
x: position[0],
y: position[1],
width: DEFAULT_TELEMETRY_DIMENSIONS[0],
height: DEFAULT_TELEMETRY_DIMENSIONS[1],
displayMode: 'all',
value: metadata.getDefaultDisplayValue(),
stroke: "transparent",
fill: "",
color: "",
size: "13px",
};
},
inject: ['openmct'],
props: {
item: Object
item: Object,
gridSize: Array,
initSelect: Boolean,
index: Number
},
components: {
LayoutFrame
},
computed: {
showLabel() {
let displayMode = this.item.config.alphanumeric.displayMode;
let displayMode = this.item.displayMode;
return displayMode === 'all' || displayMode === 'label';
},
showValue() {
let displayMode = this.item.config.alphanumeric.displayMode;
let displayMode = this.item.displayMode;
return displayMode === 'all' || displayMode === 'value';
},
styleObject() {
let alphanumeric = this.item.config.alphanumeric;
return {
backgroundColor: alphanumeric.fill,
borderColor: alphanumeric.stroke,
color: alphanumeric.color,
fontSize: alphanumeric.size
backgroundColor: this.item.fill,
borderColor: this.item.stroke,
color: this.item.color,
fontSize: this.item.size
}
},
fieldName() {
return this.valueMetadata.name;
return this.valueMetadata && this.valueMetadata.name;
},
valueMetadata() {
return this.metadata.value(this.item.config.alphanumeric.value);
return this.datum && this.metadata.value(this.item.value);
},
valueFormatter() {
return this.formats[this.item.config.alphanumeric.value];
return this.formats[this.item.value];
},
telemetryValue() {
if (!this.datum) {
@ -122,8 +155,9 @@
},
data() {
return {
datum: {},
formats: {}
datum: undefined,
formats: undefined,
domainObject: undefined
}
},
methods: {
@ -134,7 +168,7 @@
end: bounds.end,
size: 1
};
this.openmct.telemetry.request(this.item.domainObject, options)
this.openmct.telemetry.request(this.domainObject, options)
.then(data => {
if (data.length > 0) {
this.updateView(data[data.length - 1]);
@ -142,7 +176,7 @@
});
},
subscribeToObject() {
this.subscription = this.openmct.telemetry.subscribe(this.item.domainObject, function (datum) {
this.subscription = this.openmct.telemetry.subscribe(this.domainObject, function (datum) {
if (this.openmct.time.clock() !== undefined) {
this.updateView(datum);
}
@ -160,28 +194,40 @@
refreshData(bounds, isTick) {
if (!isTick) {
this.datum = undefined;
this.requestHistoricalData(this.item.domainObject);
this.requestHistoricalData(this.domainObject);
}
},
setObject(domainObject) {
this.domainObject = domainObject;
this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
this.limitEvaluator = this.openmct.telemetry.limitEvaluator(this.domainObject);
this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
this.requestHistoricalData();
this.subscribeToObject();
let context = {
item: domainObject,
layoutItem: this.item,
index: this.index
};
this.removeSelectable = this.openmct.selection.selectable(
this.$el, context, this.initSelect);
}
},
created() {
this.metadata = this.openmct.telemetry.getMetadata(this.item.domainObject);
},
mounted() {
this.limitEvaluator = this.openmct.telemetry.limitEvaluator(this.item.domainObject);
this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
this.requestHistoricalData();
this.subscribeToObject();
this.item.config.attachListeners();
this.openmct.objects.get(this.item.identifier)
.then(this.setObject);
this.openmct.time.on("bounds", this.refreshData);
},
destroyed() {
this.removeSubscription();
this.item.config.removeListeners();
if (this.removeSelectable) {
this.removeSelectable();
}
this.openmct.time.off("bounds", this.refreshData);
}
}
</script>
</script>

View File

@ -21,10 +21,14 @@
*****************************************************************************/
<template>
<div class="c-text-view"
:style="styleObject">
{{ item.config.element.text }}
</div>
<layout-frame :item="item"
:grid-size="gridSize"
@endDrag="(item, updates) => $emit('endDrag', item, updates)">
<div class="c-text-view"
:style="style">
{{ item.text }}
</div>
</layout-frame>
</template>
<style lang="scss">
@ -42,26 +46,55 @@
</style>
<script>
import LayoutFrame from './LayoutFrame.vue'
export default {
makeDefinition(openmct, gridSize, element) {
return {
fill: 'transparent',
stroke: 'transparent',
size: '13px',
color: '',
x: 1,
y: 1,
width: 10,
height: 5,
text: element.text
};
},
inject: ['openmct'],
props: {
item: Object
item: Object,
gridSize: Array,
index: Number,
initSelect: Boolean
},
components: {
LayoutFrame
},
computed: {
styleObject() {
let element = this.item.config.element;
style() {
return {
backgroundColor: element.fill,
borderColor: element.stroke,
color: element.color,
fontSize: element.size
}
backgroundColor: this.item.fill,
borderColor: this.item.stroke,
color: this.item.color,
fontSize: this.item.size
};
}
},
mounted() {
this.item.config.attachListeners();
let context = {
layoutItem: this.item,
index: this.index
};
this.removeSelectable = this.openmct.selection.selectable(
this.$el, context, this.initSelect);
},
destroyed() {
this.item.config.removeListeners();
if (this.removeSelectable) {
this.removeSelectable();
}
}
}
</script>
</script>

View File

@ -16,8 +16,12 @@ export default {
Object.assign(oldObject, newObject);
}
this.objectPath.forEach(object => this.$once('hook:destroy',
this.openmct.objects.observe(object, '*', updateObject.bind(this, object)))
this.objectPath.forEach(object => {
if (object) {
this.$once('hook:destroy',
this.openmct.objects.observe(object, '*', updateObject.bind(this, object)))
}
}
);
},
destroyed() {

View File

@ -14,7 +14,7 @@ export default {
return;
}
return '#/browse/' + this.objectPath
.map(o => this.openmct.objects.makeKeyString(o.identifier))
.map(o => o && this.openmct.objects.makeKeyString(o.identifier))
.reverse()
.join('/');
}

View File

@ -18,8 +18,10 @@
import toolbarSeparator from './components/toolbar-separator.vue';
import toolbarToggleButton from './components/toolbar-toggle-button.vue';
import _ from 'lodash';
export default {
inject: ['openmct', 'lodash'],
inject: ['openmct'],
components: {
toolbarButton,
toolbarColorPicker,