blob: 079001b875aa0e5a297be32ea42808b01d0ac5c7 [file] [log] [blame]
/********************************************************************************
* 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, ViewChild, Input, OnChanges, SimpleChanges } from '@angular/core';
import { LazyLoadEvent, Column } from 'primeng/primeng';
import { Table } from 'primeng/table';
import { ChartViewerDataService } from '../../services/chart-viewer-data.service';
import { ChannelSelectionRow, MeasuredValues } from '../../model/chartviewer.model';
import { Measurement } from '../../model/types/measurement.class';
import { getDataArray } from '../../model/types/measured-values.class';
import { forkJoin, Observable, of } from 'rxjs';
import { Channel } from '../../model/types/channel.class';
import { map } from 'rxjs/operators';
import { ChannelGroup } from '../../model/types/channelgroup.class';
@Component({
selector: 'mdm5-dataTable',
templateUrl: 'data-table.component.html',
styleUrls: ['./data-table.component.css'],
providers: []
})
export class DataTableComponent implements OnChanges {
@ViewChild('datatable')
private table: Table;
@Input()
measurement: Measurement;
@Input()
selectedChannelRows: ChannelSelectionRow[];
tableLoading = false;
cols: Column[] = [];
totalRecords = 0;
recordsPerPage = 10;
datapoints = [];
constructor(private chartviewerService: ChartViewerDataService) {
}
ngOnChanges(changes: SimpleChanges) {
for (const propName in changes) {
if (propName === 'measurement') {
this.table.reset();
this.cols = [];
this.datapoints = [];
}
if (propName === 'selectedChannelRows') {
this.table.reset();
this.cols = [];
this.datapoints = [];
}
}
}
load(mv: MeasuredValues[]) {
const zip = (rows => rows[0].map((_, c) => rows.map(row => row[c])));
// combine the columns of multiple data requests
this.cols = this.cols.concat(mv.filter((m, i) => {
for (let j = 0; j < this.cols.length; j++) {
if (this.cols[j].header === m.name) {
return false;
}
}
return true;
}).map((m, i) => Object.assign(new Column(), { header: m.name, field: i })));
return zip(mv.map(m => getDataArray(m).values));
}
loadLazy(event: LazyLoadEvent) {
if (!this.measurement) {
return;
}
if (this.selectedChannelRows) {
const channelsByGroup = this.groupChannelRowsByChannelGroup(this.selectedChannelRows);
forkJoin(
of(this.selectedChannelRows.map(x => x.channelGroup.numberOfRows).reduce((prev, curr) => Math.max(prev, curr), 0)),
this.requestMeasuredValues(channelsByGroup, event.first, event.rows))
.subscribe(res => {
this.totalRecords = res[0];
this.datapoints = this.load(res[1].map(x => x.measuredValues));
});
}
}
/**
* Group the ChannelSelectionRows by ChannelGroup, e.g. the returned record has the ID of the
* channelGroup as key and the list of corresponding Channels (X and Y Channels) as value.
* @param channelRows
*/
private groupChannelRowsByChannelGroup(channelRows: ChannelSelectionRow[]) {
return channelRows.reduce((previous, currentItem) => {
const group = currentItem.channelGroup.id;
if (group != null) {
if (!previous[group]) {
previous[group] = { channelGroup: currentItem.channelGroup, channels: [] };
}
if (currentItem.xChannel != undefined
&& previous[group].channels.findIndex(c => c.id === currentItem.xChannel.id) == -1) {
previous[group].channels.push(currentItem.xChannel);
}
if (currentItem.yChannel != undefined
&& previous[group].channels.findIndex(c => c.id === currentItem.yChannel.id) == -1) {
previous[group].channels.push(currentItem.yChannel);
}
}
return previous;
}, {} as Record<string, {channelGroup: ChannelGroup, channels: Channel[]}>);
}
/**
* Requests the values of all Channels for all ChannelGroups. Returns an Observable containing
* all Channels together with their MeasuredValues
* @param channelsByGroup
*/
private requestMeasuredValues(channelsByGroup: Record<string, {channelGroup: ChannelGroup, channels: Channel[]}>, startIndex: number, requestSize: number) {
let measuredValues : Observable<{ channel: Channel, measuredValues: MeasuredValues}[]>[] = []
for (const channelGroupId in channelsByGroup) {
const channelGroup = this.selectedChannelRows.find(row => row.channelGroup.id == channelGroupId).channelGroup;
let rowCount = channelsByGroup[channelGroupId].channelGroup.numberOfRows;
if (startIndex < rowCount) {
let obs = this.chartviewerService.loadValues(channelGroup, channelsByGroup[channelGroupId].channels,
startIndex, Math.min(requestSize, rowCount - startIndex), 0).pipe(
map(mv => this.mergeMeasuredValuesByName(channelsByGroup[channelGroupId].channels, mv))
)
measuredValues.push(obs);
}
}
return forkJoin(measuredValues).pipe(map(mv => [].concat(...mv) as { channel: Channel, measuredValues: MeasuredValues}[]));
}
/**
* Merge list of Channels with MeasuredValues by channel name. Only channels of one ChannelGroup
* are allowed, because names of Channels within a ChannelGroup are unique.
* @param channels
* @param measuredValues
*/
private mergeMeasuredValuesByName(channels: Channel[], measuredValues: MeasuredValues[]) {
return channels.map(c => { return { channel: c, measuredValues: measuredValues.find(mv => mv.name === c.name)}; });
}
}