diff --git a/e2e/tests/performance/tagging.perf.spec.js b/e2e/tests/performance/tagging.perf.spec.js index 8f20b078fcf..8c527e45541 100644 --- a/e2e/tests/performance/tagging.perf.spec.js +++ b/e2e/tests/performance/tagging.perf.spec.js @@ -32,7 +32,7 @@ const { waitForPlotsToRender } = require('../../appActions'); -test.describe.fixme('Plot Tagging Performance', () => { +test.describe('Plot Tagging Performance', () => { /** * Given a canvas and a set of points, tags the points on the canvas. * @param {import('@playwright/test').Page} page diff --git a/src/plugins/plot/MctPlot.vue b/src/plugins/plot/MctPlot.vue index 8e98ad7c7d5..7557946c44e 100644 --- a/src/plugins/plot/MctPlot.vue +++ b/src/plugins/plot/MctPlot.vue @@ -78,8 +78,8 @@ :rectangles="rectangles" :highlights="highlights" :show-limit-line-labels="limitLineLabels" - :annotated-points="annotatedPoints" - :annotation-selections="annotationSelections" + :annotated-points-by-series="annotatedPointsBySeries" + :annotation-selections-by-series="annotationSelectionsBySeries" :hidden-y-axis-ids="hiddenYAxisIds" :annotation-viewing-and-editing-allowed="annotationViewingAndEditingAllowed" @plotReinitializeCanvas="initCanvas" @@ -245,9 +245,9 @@ export default { data() { return { altPressed: false, + annotatedPointsBySeries: {}, highlights: [], - annotatedPoints: [], - annotationSelections: [], + annotationSelectionsBySeries: {}, annotationsEverLoaded: false, lockHighlightPoint: false, yKeyOptions: [], @@ -256,8 +256,6 @@ export default { plotHistory: [], selectedXKeyOption: {}, xKeyOptions: [], - seriesModels: [], - legend: {}, pending: 0, isRealTime: this.openmct.time.isRealTime(), loaded: false, @@ -346,6 +344,8 @@ export default { this.abortController = new AbortController(); }, mounted() { + this.seriesModels = []; + this.config = {}; this.yAxisIdVisibility = {}; this.offsetWidth = 0; @@ -357,7 +357,6 @@ export default { this.setTimeContext = this.setTimeContext.bind(this); this.config = this.getConfig(); - this.legend = this.config.legend; this.yAxes = [ { id: this.config.yAxis.id, @@ -455,7 +454,7 @@ export default { const clickedOption = event.target.closest('.js-autocomplete-options') !== null; if (!clickedInsidePlot && !clickedInsideInspector && !clickedOption) { this.rectangles = []; - this.annotationSelections = []; + this.annotationSelectionsBySeries = {}; this.selectPlot(); document.body.removeEventListener('click', this.cancelSelection); } @@ -639,7 +638,7 @@ export default { }) ); if (rawAnnotationsForPlot) { - this.annotatedPoints = this.findAnnotationPoints(rawAnnotationsForPlot); + this.annotatedPointsBySeries = this.findAnnotationPoints(rawAnnotationsForPlot); } this.annotationsEverLoaded = true; }, @@ -795,7 +794,7 @@ export default { }; this.config.xAxis.set('range', newRange); if (!isTick) { - this.annotatedPoints = []; + this.annotatedPointsBySeries = {}; this.clearPanZoomHistory(); this.synchronizeIfBoundsMatch(); this.loadMoreData(newRange, true); @@ -1157,7 +1156,7 @@ export default { series.closest = series.nearestPoint(point); return { - series: series, + seriesKeyString: series.keyString, point: series.closest }; }); @@ -1245,7 +1244,7 @@ export default { startMarquee(event, annotationEvent) { this.rectangles = []; - this.annotationSelections = []; + this.annotationSelectionsBySeries = {}; this.canvas.classList.remove('plot-drag'); this.canvas.classList.add('plot-marquee'); @@ -1273,7 +1272,10 @@ export default { const nearbyAnnotations = this.gatherNearbyAnnotations(); - if (this.annotationViewingAndEditingAllowed && this.annotationSelections.length) { + if ( + this.annotationViewingAndEditingAllowed && + Object.keys(this.annotationSelectionsBySeries).length + ) { //no annotations were found, but we are adding some now return; } @@ -1353,20 +1355,18 @@ export default { document.body.addEventListener('click', this.cancelSelection); }, - selectNewPlotAnnotations(boundingBoxPerYAxis, pointsInBox, event) { + selectNewPlotAnnotations(boundingBoxPerYAxis, pointsInBoxBySeries, event) { let targetDomainObjects = {}; let targetDetails = {}; let annotations = []; - pointsInBox.forEach((pointInBox) => { - if (pointInBox.length) { - const seriesID = pointInBox[0].series.keyString; - const boundingBoxWithId = boundingBoxPerYAxis.find( - (box) => box.id === pointInBox[0].series.get('yAxisId') - ); - targetDetails[seriesID] = boundingBoxWithId?.boundingBox; + Object.keys(pointsInBoxBySeries).forEach((seriesKey) => { + const seriesModel = this.getSeries(seriesKey); + const boundingBoxWithId = boundingBoxPerYAxis.find( + (box) => box.id === seriesModel.get('yAxisId') + ); + targetDetails[seriesKey] = boundingBoxWithId?.boundingBox; - targetDomainObjects[seriesID] = pointInBox[0].series.domainObject; - } + targetDomainObjects[seriesKey] = seriesModel.domainObject; }); this.selectPlotAnnotations({ targetDetails, @@ -1375,7 +1375,7 @@ export default { }); }, findAnnotationPoints(rawAnnotations) { - const annotationsByPoints = []; + const annotationsBySeries = {}; rawAnnotations.forEach((rawAnnotation) => { if (rawAnnotation.targets) { const targetValues = Object.values(rawAnnotation.targets); @@ -1390,6 +1390,9 @@ export default { if (!series) { return; } + if (!annotationsBySeries[seriesId]) { + annotationsBySeries[seriesId] = []; + } boundingBoxPerYAxis.push({ id: series.get('yAxisId'), @@ -1397,15 +1400,23 @@ export default { }); }); - const pointsInBox = this.getPointsInBox(boundingBoxPerYAxis, rawAnnotation); - if (pointsInBox && pointsInBox.length) { - annotationsByPoints.push(pointsInBox.flat()); + const pointsInBoxBySeries = this.getPointsInBoxBySeries( + boundingBoxPerYAxis, + rawAnnotation + ); + if (pointsInBoxBySeries && Object.values(pointsInBoxBySeries).length) { + Object.keys(pointsInBoxBySeries).forEach((seriesKeyString) => { + const pointsInBox = pointsInBoxBySeries[seriesKeyString]; + if (pointsInBox && pointsInBox.length) { + annotationsBySeries[seriesKeyString].push(...pointsInBox); + } + }); } } } }); - return annotationsByPoints.flat(); + return annotationsBySeries; }, searchWithFlatbush(seriesData, seriesModel, boundingBox) { const flatbush = new Flatbush(seriesData.length); @@ -1425,9 +1436,15 @@ export default { return rangeResults; }, - getPointsInBox(boundingBoxPerYAxis, rawAnnotation) { + getSeries(keyStringToFind) { + const foundSeries = this.seriesModels.find((series) => { + return series.keyString === keyStringToFind; + }); + return foundSeries; + }, + getPointsInBoxBySeries(boundingBoxPerYAxis, rawAnnotation) { // load series models in KD-Trees - const seriesKDTrees = []; + const searchResultsBySeries = {}; this.seriesModels.forEach((seriesModel) => { const boundingBoxWithId = boundingBoxPerYAxis.find( (box) => box.id === seriesModel.get('yAxisId') @@ -1440,16 +1457,15 @@ export default { const seriesData = seriesModel.getSeriesData(); if (seriesData && seriesData.length) { - const searchResults = []; + searchResultsBySeries[seriesModel.keyString] = []; const rangeResults = this.searchWithFlatbush(seriesData, seriesModel, boundingBox); rangeResults.forEach((id) => { const seriesDatum = seriesData[id]; if (seriesDatum) { const result = { - series: seriesModel, point: seriesDatum }; - searchResults.push(result); + searchResultsBySeries[seriesModel.keyString].push(result); } if (rawAnnotation) { @@ -1463,13 +1479,10 @@ export default { seriesDatum.annotationsById[annotationKeyString] = rawAnnotation; } }); - if (searchResults.length) { - seriesKDTrees.push(searchResults); - } } }); - return seriesKDTrees; + return searchResultsBySeries; }, endAnnotationMarquee(event) { const boundingBoxPerYAxis = []; @@ -1490,13 +1503,13 @@ export default { }); }); - const pointsInBox = this.getPointsInBox(boundingBoxPerYAxis); - if (!pointsInBox) { + const pointsInBoxBySeries = this.getPointsInBoxBySeries(boundingBoxPerYAxis); + if (!pointsInBoxBySeries || Object.values(pointsInBoxBySeries).length === 0) { return; } - this.annotationSelections = pointsInBox.flat(); - this.selectNewPlotAnnotations(boundingBoxPerYAxis, pointsInBox, event); + this.annotationSelectionsBySeries = pointsInBoxBySeries; + this.selectNewPlotAnnotations(boundingBoxPerYAxis, this.annotationSelectionsBySeries, event); }, endZoomMarquee() { const startPixels = this.marquee.startPixels; diff --git a/src/plugins/plot/chart/MctChart.vue b/src/plugins/plot/chart/MctChart.vue index 1521dd975c8..968556b674e 100644 --- a/src/plugins/plot/chart/MctChart.vue +++ b/src/plugins/plot/chart/MctChart.vue @@ -101,16 +101,16 @@ export default { return []; } }, - annotatedPoints: { - type: Array, + annotatedPointsBySeries: { + type: Object, default() { - return []; + return {}; } }, - annotationSelections: { - type: Array, + annotationSelectionsBySeries: { + type: Object, default() { - return []; + return {}; } }, showLimitLineLabels: { @@ -143,17 +143,15 @@ export default { }, deep: true }, - annotatedPoints: { + annotatedPointsBySeries: { handler() { this.scheduleDraw(); - }, - deep: true + } }, - annotationSelections: { + annotationSelectionsBySeries: { handler() { this.scheduleDraw(); - }, - deep: true + } }, rectangles: { handler() { @@ -177,6 +175,7 @@ export default { }, mounted() { eventHelpers.extend(this); + this.seriesModels = []; this.config = this.getConfig(); this.isDestroyed = false; this.lines = []; @@ -256,7 +255,8 @@ export default { this.changeAlarmMarkers(newXKey, oldXKey, series); this.changeLimitLines(newXKey, oldXKey, series); }, - onSeriesAdd(series) { + onSeriesAdd(series, index) { + this.seriesModels[index] = series; this.listenTo(series, `change:${HANDLED_ATTRIBUTES.xKey}`, this.reDraw, this); this.listenTo( series, @@ -280,10 +280,15 @@ export default { this.makeChartElement(series); this.makeLimitLines(series); }, - onSeriesRemove(series) { - this.stopListening(series); - this.removeChartElement(series); + onSeriesRemove(seriesToRemove) { + this.stopListening(seriesToRemove); + this.removeChartElement(seriesToRemove); this.scheduleDraw(); + + const seriesIndexToRemove = this.seriesModels.findIndex( + (series) => series.keyString === seriesToRemove.keyString + ); + this.seriesModels.splice(seriesIndexToRemove, 1); }, onAddPoint(point, insertIndex, series) { const mainYAxisId = this.config.yAxis.get('id'); @@ -642,8 +647,8 @@ export default { this.drawHighlights(id); // only draw these in fixed time mode or plot is paused if (this.annotationViewingAndEditingAllowed) { - this.drawAnnotatedPoints(id); - this.drawAnnotationSelections(id); + this.prepareToDrawAnnotatedPoints(id); + this.prepareToDrawAnnotationSelections(id); } }); }, @@ -698,6 +703,7 @@ export default { pointSets.forEach(this.drawPoints, this); const alarmSets = this.alarmSets.filter(this.matchByYAxisId.bind(this, id)); alarmSets.forEach(this.drawAlarmPoints, this); + //console.timeEnd('📈 drawSeries'); }, updateLimitLines() { Array.from(this.$refs.limitArea.children).forEach((el) => el.remove()); @@ -827,82 +833,110 @@ export default { ); } }, - drawAnnotatedPoints(yAxisId) { - // we should do this by series, and then plot all the points at once instead - // of doing it one by one - if (this.annotatedPoints && this.annotatedPoints.length) { - const uniquePointsToDraw = []; + prepareToDrawAnnotatedPoints(yAxisId) { + if (this.annotatedPointsBySeries && Object.values(this.annotatedPointsBySeries).length) { + const uniquePointsToDraw = new Set(); - const annotatedPoints = this.annotatedPoints.filter( - this.matchByYAxisId.bind(this, yAxisId) - ); - annotatedPoints.forEach((annotatedPoint) => { + Object.keys(this.annotatedPointsBySeries).forEach((seriesKeyString) => { + const seriesModel = this.getSeries(seriesKeyString); + const matchesYAxis = this.matchByYAxisId(yAxisId, { series: seriesModel }); + if (!matchesYAxis) { + return; + } // annotation points are all within range (checked in MctPlot with FlatBush), so we don't need to check - const canvasXValue = this.offset[yAxisId].xVal( - annotatedPoint.point, - annotatedPoint.series + const annotatedPointBuffer = new Float32Array( + this.annotatedPointsBySeries[seriesKeyString].length * 2 ); - const canvasYValue = this.offset[yAxisId].yVal( - annotatedPoint.point, - annotatedPoint.series + Object.values(this.annotatedPointsBySeries[seriesKeyString]).forEach( + (annotatedPoint, index) => { + const canvasXValue = this.offset[yAxisId].xVal(annotatedPoint.point, seriesModel); + const canvasYValue = this.offset[yAxisId].yVal(annotatedPoint.point, seriesModel); + const drawnPointKey = `${canvasXValue}|${canvasYValue}`; + if (!uniquePointsToDraw.has(drawnPointKey)) { + annotatedPointBuffer[index * 2] = canvasXValue; + annotatedPointBuffer[index * 2 + 1] = canvasYValue; + uniquePointsToDraw.add(drawnPointKey); + } + } ); - const pointToDraw = new Float32Array([canvasXValue, canvasYValue]); - const drawnPoint = uniquePointsToDraw.some((rawPoint) => { - return rawPoint[0] === pointToDraw[0] && rawPoint[1] === pointToDraw[1]; - }); - if (!drawnPoint) { - uniquePointsToDraw.push(pointToDraw); - this.drawAnnotatedPoint(annotatedPoint, pointToDraw); - } + this.drawAnnotatedPoints(seriesModel, annotatedPointBuffer); }); } }, - drawAnnotatedPoint(annotatedPoint, pointToDraw) { - if (annotatedPoint.point && annotatedPoint.series) { - const color = annotatedPoint.series.get('color').asRGBAArray(); + drawAnnotatedPoints(seriesModel, annotatedPointBuffer) { + if (annotatedPointBuffer && seriesModel) { + const color = seriesModel.get('color').asRGBAArray(); // set transparency color[3] = 0.15; - const pointCount = 1; - const shape = annotatedPoint.series.get('markerShape'); + const pointCount = annotatedPointBuffer.length / 2; + const shape = seriesModel.get('markerShape'); - this.drawAPI.drawPoints(pointToDraw, color, pointCount, ANNOTATION_SIZE, shape); + this.drawAPI.drawPoints(annotatedPointBuffer, color, pointCount, ANNOTATION_SIZE, shape); } }, - drawAnnotationSelections(yAxisId) { - if (this.annotationSelections && this.annotationSelections.length) { - const annotationSelections = this.annotationSelections.filter( - this.matchByYAxisId.bind(this, yAxisId) - ); - annotationSelections.forEach(this.drawAnnotationSelection.bind(this, yAxisId), this); + prepareToDrawAnnotationSelections(yAxisId) { + if ( + this.annotationSelectionsBySeries && + Object.keys(this.annotationSelectionsBySeries).length + ) { + Object.keys(this.annotationSelectionsBySeries).forEach((seriesKeyString) => { + const seriesModel = this.getSeries(seriesKeyString); + const matchesYAxis = this.matchByYAxisId(yAxisId, { series: seriesModel }); + if (matchesYAxis) { + const annotationSelectionBuffer = new Float32Array( + this.annotationSelectionsBySeries[seriesKeyString].length * 2 + ); + Object.values(this.annotationSelectionsBySeries[seriesKeyString]).forEach( + (annotatedSelectedPoint, index) => { + const canvasXValue = this.offset[yAxisId].xVal( + annotatedSelectedPoint.point, + seriesModel + ); + const canvasYValue = this.offset[yAxisId].yVal( + annotatedSelectedPoint.point, + seriesModel + ); + annotationSelectionBuffer[index * 2] = canvasXValue; + annotationSelectionBuffer[index * 2 + 1] = canvasYValue; + } + ); + this.drawAnnotationSelections(seriesModel, annotationSelectionBuffer); + } + }); } }, - drawAnnotationSelection(yAxisId, annotationSelection) { - const points = new Float32Array([ - this.offset[yAxisId].xVal(annotationSelection.point, annotationSelection.series), - this.offset[yAxisId].yVal(annotationSelection.point, annotationSelection.series) - ]); - + drawAnnotationSelections(seriesModel, annotationSelectionBuffer) { const color = [255, 255, 255, 1]; // white - const pointCount = 1; - const shape = annotationSelection.series.get('markerShape'); + const pointCount = annotationSelectionBuffer.length / 2; + const shape = seriesModel.get('markerShape'); - this.drawAPI.drawPoints(points, color, pointCount, ANNOTATION_SIZE, shape); + this.drawAPI.drawPoints(annotationSelectionBuffer, color, pointCount, ANNOTATION_SIZE, shape); }, drawHighlights(yAxisId) { if (this.highlights && this.highlights.length) { - const highlights = this.highlights.filter(this.matchByYAxisId.bind(this, yAxisId)); + const highlights = this.highlights.filter((highlight) => { + const series = this.getSeries(highlight.seriesKeyString); + return this.matchByYAxisId.bind(yAxisId, { series }); + }); highlights.forEach(this.drawHighlight.bind(this, yAxisId), this); } }, + getSeries(keyStringToFind) { + const foundSeries = this.seriesModels.find((series) => { + return series.keyString === keyStringToFind; + }); + return foundSeries; + }, drawHighlight(yAxisId, highlight) { + const series = this.getSeries(highlight.seriesKeyString); const points = new Float32Array([ - this.offset[yAxisId].xVal(highlight.point, highlight.series), - this.offset[yAxisId].yVal(highlight.point, highlight.series) + this.offset[yAxisId].xVal(highlight.point, series), + this.offset[yAxisId].yVal(highlight.point, series) ]); - const color = highlight.series.get('color').asRGBAArray(); + const color = series.get('color').asRGBAArray(); const pointCount = 1; - const shape = highlight.series.get('markerShape'); + const shape = series.get('markerShape'); this.drawAPI.drawPoints(points, color, pointCount, HIGHLIGHT_SIZE, shape); }, diff --git a/src/plugins/plot/legend/PlotLegend.vue b/src/plugins/plot/legend/PlotLegend.vue index ca57c20e1be..3465314e5bf 100644 --- a/src/plugins/plot/legend/PlotLegend.vue +++ b/src/plugins/plot/legend/PlotLegend.vue @@ -45,7 +45,7 @@ :key="`${seriesObject.keyString}-${seriesIndex}-collapsed`" :highlights="highlights" :value-to-show-when-collapsed="valueToShowWhenCollapsed" - :series-object="seriesObject" + :series-key-string="seriesObject.keyString" @legendHoverChanged="legendHoverChanged" /> @@ -72,7 +72,7 @@ diff --git a/src/plugins/plot/legend/PlotLegendItemCollapsed.vue b/src/plugins/plot/legend/PlotLegendItemCollapsed.vue index e3e814d74dc..5aacba8fab7 100644 --- a/src/plugins/plot/legend/PlotLegendItemCollapsed.vue +++ b/src/plugins/plot/legend/PlotLegendItemCollapsed.vue @@ -71,12 +71,9 @@ export default { mixins: [stalenessMixin, tooltipHelpers], inject: ['openmct', 'domainObject'], props: { - seriesObject: { - type: Object, - required: true, - default() { - return {}; - } + seriesKeyString: { + type: String, + required: true }, highlights: { type: Array, @@ -112,7 +109,7 @@ export default { highlights: { handler(newHighlights) { const highlightedObject = newHighlights.find( - (highlight) => highlight.series.keyString === this.seriesObject.keyString + (highlight) => highlight.seriesKeyString === this.seriesKeyString ); if (newHighlights.length === 0 || highlightedObject) { this.initialize(highlightedObject); @@ -122,28 +119,14 @@ export default { } }, mounted() { + this.seriesModels = []; eventHelpers.extend(this); this.config = this.getConfig(); + this.listenTo(this.config.series, 'add', this.onSeriesAdd, this); + this.listenTo(this.config.series, 'remove', this.onSeriesRemove, this); + this.config.series.forEach(this.onSeriesAdd, this); this.legend = this.config.legend; this.loaded = true; - this.listenTo( - this.seriesObject, - 'change:color', - (newColor) => { - this.updateColor(newColor); - }, - this - ); - this.listenTo( - this.seriesObject, - 'change:name', - () => { - this.updateName(); - }, - this - ); - this.subscribeToStaleness(this.seriesObject.domainObject); - this.initialize(); }, beforeUnmount() { this.stopListening(); @@ -154,8 +137,44 @@ export default { return configStore.get(configId); }, + onSeriesAdd(series, index) { + this.seriesModels[index] = series; + if (series.keyString === this.seriesKeyString) { + this.listenTo( + series, + 'change:color', + (newColor) => { + this.updateColor(newColor); + }, + this + ); + this.listenTo( + series, + 'change:name', + () => { + this.updateName(); + }, + this + ); + this.subscribeToStaleness(series.domainObject); + this.initialize(); + } + }, + onSeriesRemove(seriesToRemove) { + const seriesIndexToRemove = this.seriesModels.findIndex( + (series) => series.keyString === seriesToRemove.keyString + ); + this.seriesModels.splice(seriesIndexToRemove, 1); + }, + getSeries(keyStringToFind) { + const foundSeries = this.seriesModels.find((series) => { + return series.keyString === keyStringToFind; + }); + return foundSeries; + }, initialize(highlightedObject) { - const seriesObject = highlightedObject?.series || this.seriesObject; + const seriesKeyStringToUse = highlightedObject?.seriesKeyString || this.seriesKeyString; + const seriesObject = this.getSeries(seriesKeyStringToUse); this.isMissing = seriesObject.domainObject.status === 'missing'; this.colorAsHexString = seriesObject.get('color').asHexString(); @@ -187,7 +206,8 @@ export default { this.colorAsHexString = newColor.asHexString(); }, updateName() { - this.nameWithUnit = this.seriesObject.nameWithUnit(); + const seriesObject = this.getSeries(this.seriesKeyString); + this.nameWithUnit = seriesObject.nameWithUnit(); }, toggleHover(hover) { this.hover = hover; @@ -195,15 +215,16 @@ export default { 'legendHoverChanged', this.hover ? { - seriesKey: this.seriesObject.keyString + seriesKey: this.seriesKeyString } : undefined ); }, async showToolTip() { + const seriesObject = this.getSeries(this.seriesKeyString); const { BELOW } = this.openmct.tooltips.TOOLTIP_LOCATIONS; this.buildToolTip( - await this.getTelemetryPathString(this.seriesObject.domainObject.identifier), + await this.getTelemetryPathString(seriesObject.domainObject.identifier), BELOW, 'series' ); diff --git a/src/plugins/plot/legend/PlotLegendItemExpanded.vue b/src/plugins/plot/legend/PlotLegendItemExpanded.vue index a5ef0923ec9..590506768aa 100644 --- a/src/plugins/plot/legend/PlotLegendItemExpanded.vue +++ b/src/plugins/plot/legend/PlotLegendItemExpanded.vue @@ -86,12 +86,9 @@ export default { mixins: [stalenessMixin, tooltipHelpers], inject: ['openmct', 'domainObject'], props: { - seriesObject: { - type: Object, - required: true, - default() { - return {}; - } + seriesKeyString: { + type: String, + required: true }, highlights: { type: Array, @@ -135,7 +132,7 @@ export default { highlights: { handler(newHighlights) { const highlightedObject = newHighlights.find( - (highlight) => highlight.series.keyString === this.seriesObject.keyString + (highlight) => highlight.seriesKeyString === this.seriesKeyString ); if (newHighlights.length === 0 || highlightedObject) { this.initialize(highlightedObject); @@ -145,40 +142,62 @@ export default { } }, mounted() { + this.seriesModels = []; eventHelpers.extend(this); this.config = this.getConfig(); + this.listenTo(this.config.series, 'add', this.onSeriesAdd, this); + this.listenTo(this.config.series, 'remove', this.onSeriesRemove, this); + this.config.series.forEach(this.onSeriesAdd, this); this.legend = this.config.legend; this.loaded = true; - this.listenTo( - this.seriesObject, - 'change:color', - (newColor) => { - this.updateColor(newColor); - }, - this - ); - this.listenTo( - this.seriesObject, - 'change:name', - () => { - this.updateName(); - }, - this - ); - this.subscribeToStaleness(this.seriesObject.domainObject); - this.initialize(); }, beforeUnmount() { this.stopListening(); }, methods: { + onSeriesAdd(series, index) { + this.seriesModels[index] = series; + if (series.keyString === this.seriesKeyString) { + this.listenTo( + series, + 'change:color', + (newColor) => { + this.updateColor(newColor); + }, + this + ); + this.listenTo( + series, + 'change:name', + () => { + this.updateName(); + }, + this + ); + this.subscribeToStaleness(series.domainObject); + this.initialize(); + } + }, + onSeriesRemove(seriesToRemove) { + const seriesIndexToRemove = this.seriesModels.findIndex( + (series) => series.keyString === seriesToRemove.keyString + ); + this.seriesModels.splice(seriesIndexToRemove, 1); + }, + getSeries(keyStringToFind) { + const foundSeries = this.seriesModels.find((series) => { + return series.keyString === keyStringToFind; + }); + return foundSeries; + }, getConfig() { const configId = this.openmct.objects.makeKeyString(this.domainObject.identifier); return configStore.get(configId); }, initialize(highlightedObject) { - const seriesObject = highlightedObject?.series || this.seriesObject; + const seriesKeyStringToUse = highlightedObject?.seriesKeyString || this.seriesKeyString; + const seriesObject = this.getSeries(seriesKeyStringToUse); this.isMissing = seriesObject.domainObject.status === 'missing'; this.colorAsHexString = seriesObject.get('color').asHexString(); @@ -209,22 +228,20 @@ export default { updateColor(newColor) { this.colorAsHexString = newColor.asHexString(); }, - updateName(newName) { - this.nameWithUnit = this.seriesObject.nameWithUnit(); + updateName() { + const seriesObject = this.getSeries(this.seriesKeyString); + this.nameWithUnit = seriesObject.nameWithUnit(); }, toggleHover(hover) { this.hover = hover; this.$emit('legendHoverChanged', { - seriesKey: this.hover ? this.seriesObject.keyString : '' + seriesKey: this.hover ? this.seriesKeyString : '' }); }, async showToolTip() { const { BELOW } = this.openmct.tooltips.TOOLTIP_LOCATIONS; - this.buildToolTip( - await this.getTelemetryPathString(this.seriesObject.domainObject.identifier), - BELOW, - 'seriesName' - ); + const seriesIdentifier = this.openmct.objects.parseKeyString(this.seriesKeyString); + this.buildToolTip(await this.getTelemetryPathString(seriesIdentifier), BELOW, 'seriesName'); } } };