| /******************************************************************************** |
| * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation |
| * |
| * See the NOTICE file(s) distributed with this work for additional |
| * information regarding copyright ownership. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| ********************************************************************************/ |
| |
| import { Component, OnInit, OnDestroy } from '@angular/core'; |
| import { NavigatorService } from 'src/app/navigator/navigator.service'; |
| import { MDMNotificationService } from 'src/app/core/mdm-notification.service'; |
| import { Node } from '../../../navigator/node'; |
| import { TYPE_CHANNEL, TYPE_CHANNELGROUP, TYPE_MEASUREMENT } from '../../model/constants'; |
| import { Subscription, forkJoin } from 'rxjs'; |
| import { NodeService } from 'src/app/navigator/node.service'; |
| import { map, tap } from 'rxjs/operators'; |
| import { MDMItem } from 'src/app/core/mdm-item'; |
| import { ChartViewerService } from '../../services/chart-viewer.service'; |
| |
| @Component({ |
| selector: 'app-xy-chart-viewer-nav-card', |
| templateUrl: './xy-chart-viewer-nav-card.component.html' |
| }) |
| export class XyChartViewerNavCardComponent implements OnInit, OnDestroy { |
| |
| public channels = new Map<string, Node[]>(); |
| public channelGroups: Node[]; |
| public measurement: Node; |
| |
| private selectedNode: Node; |
| |
| // Subscriptions |
| private selectedNodeSub: Subscription; |
| |
| constructor( |
| private navigatorService: NavigatorService, |
| private notificationService: MDMNotificationService, |
| private nodeService: NodeService, |
| private chartViewerService: ChartViewerService) {} |
| |
| ngOnInit() { |
| this.selectedNodeChanged(this.navigatorService.getSelectedNode()); |
| this.selectedNodeSub = this.navigatorService.selectedNodeChanged.subscribe( |
| node => this.selectedNodeChanged(node), |
| error => this.notificationService.notifyError('details.mdm-detail-view.cannot-update-node', error) |
| ); |
| } |
| |
| ngOnDestroy() { |
| this.selectedNodeSub.unsubscribe(); |
| } |
| |
| /** |
| * Handle node selection in navigation tree. |
| * Loads necessary data for xy chart, if not present: |
| * - Measurement: |
| * + Loaded if a channel or channelgroup is selected that is not present. |
| * + Also loads all channels and channelgroups for that measurement. |
| * - Channelgroups: |
| * + Loaded if a measurement is selected/loaded that is not present. |
| * + Also loads all channels for all newly loaded channelgroups. |
| * - Channels: |
| * + Allways loaded if some node is not present. |
| * |
| * @param node the selected node |
| */ |
| private selectedNodeChanged(node: Node) { |
| this.selectedNode = node; |
| if (node != undefined) { |
| switch (node.type) { |
| case TYPE_MEASUREMENT: |
| this.selectedMeasurement(node); |
| break; |
| case TYPE_CHANNELGROUP: |
| this.selectedChannelGroup(node); |
| break; |
| case TYPE_CHANNEL: |
| this.selectedChannel(node); |
| break; |
| } |
| } |
| } |
| |
| // reload all, if channel is not present yet. |
| private selectedChannel(node: Node) { |
| if (!this.isChannelPresent(node)) { |
| this.loadMeasurement(node); |
| } else { |
| this.chartViewerService.sendNodeMeta(this.selectedNode); |
| } |
| } |
| |
| private selectedChannelGroup(node: Node) { |
| if (!this.isChannelGroupPresent(node)) { |
| this.loadMeasurement(node); |
| } else { |
| this.chartViewerService.sendNodeMeta(this.selectedNode); |
| } |
| } |
| |
| private selectedMeasurement(node: Node) { |
| if (this.measurement == undefined || this.measurement.id !== node.id) { |
| this.measurement = node; |
| this.loadChannelGroups(node); |
| } else { |
| this.chartViewerService.sendNodeMeta(this.selectedNode); |
| } |
| } |
| |
| private isChannelPresent(node: Node) { |
| if (this.channels != undefined) { |
| /** |
| * @TODO more readable code, but got the impression that performance is bad. Read up on performance topic in depth. |
| */ |
| // Array.from(this.channels.values()) |
| // .reduce((a,b) => a.concat(b), []) |
| // .findIndex(c => c.id === node.id); |
| let index = -1; |
| const iterator = this.channels.values(); |
| let res = iterator.next(); |
| while (index === -1 && !res.done) { |
| index = res.value.findIndex(c => c.id === node.id); |
| res = iterator.next(); |
| } |
| return index > -1; |
| } |
| return false; |
| } |
| |
| private isChannelGroupPresent(node: Node) { |
| if (this.channelGroups != undefined) { |
| return this.channelGroups.findIndex(channelGroup => channelGroup.id === node.id) > -1; |
| } |
| return false; |
| } |
| |
| private loadMeasurement(node: Node) { |
| this.searchNodes(node, TYPE_MEASUREMENT) |
| .pipe( |
| /** @TODO in general true? */ |
| // parent measurement must be distinct |
| map(measurements => measurements[0]), |
| ).subscribe(measurement => { |
| this.measurement = measurement; |
| this.loadChannelGroups(this.measurement); |
| }); |
| } |
| |
| private loadChannelGroups(measurement: Node) { |
| this.searchNodes(measurement, TYPE_CHANNELGROUP) |
| .subscribe(channelGroups => { |
| this.channelGroups = channelGroups; |
| if (this.channelGroups != undefined) { |
| this.loadChannels(channelGroups); |
| } |
| }); |
| } |
| |
| private loadChannels(channelGroups: Node[]) { |
| this.channels.clear(); |
| let obsArray = channelGroups.map(channelGroup => this.searchNodes(channelGroup, TYPE_CHANNEL)); |
| forkJoin(obsArray).pipe( |
| tap(array => array.forEach((channels, index) => this.channels.set(channelGroups[index].id, channels))) |
| ).subscribe(datasets => this.chartViewerService.sendNodeMeta(this.selectedNode)); |
| } |
| |
| private searchNodes(node: Node, targetType: string) { |
| const filter = 'filter=' + node.type + '.Id eq \"' + node.id + '\"'; |
| return this.nodeService.searchNodes(filter, node.sourceName, targetType); |
| } |
| |
| } |