2023-05-16 20:00:53 +03:00
|
|
|
///
|
|
|
|
|
/// Copyright © 2016-2023 The Thingsboard Authors
|
|
|
|
|
///
|
|
|
|
|
/// 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.
|
|
|
|
|
///
|
|
|
|
|
|
|
|
|
|
import { Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core';
|
|
|
|
|
import { WidgetContext } from '@home/models/widget-component.models';
|
|
|
|
|
import { ChartType, TbFlotSettings } from '@home/components/widget/lib/flot-widget.models';
|
|
|
|
|
import { TbFlot } from '@home/components/widget/lib/flot-widget';
|
|
|
|
|
import {
|
|
|
|
|
defaultLegendConfig,
|
|
|
|
|
LegendConfig,
|
|
|
|
|
LegendData,
|
|
|
|
|
LegendPosition,
|
|
|
|
|
widgetType
|
|
|
|
|
} from '@shared/models/widget.models';
|
|
|
|
|
import { isDefinedAndNotNull } from '@core/utils';
|
|
|
|
|
|
|
|
|
|
@Component({
|
|
|
|
|
selector: 'tb-flot-widget',
|
|
|
|
|
templateUrl: './flot-widget.component.html',
|
2023-12-20 15:55:38 +02:00
|
|
|
styleUrls: ['./flot-widget.component.scss']
|
2023-05-16 20:00:53 +03:00
|
|
|
})
|
|
|
|
|
export class FlotWidgetComponent implements OnInit {
|
|
|
|
|
|
|
|
|
|
@ViewChild('flotElement', {static: true}) flotElement: ElementRef;
|
|
|
|
|
|
|
|
|
|
@Input()
|
|
|
|
|
ctx: WidgetContext;
|
|
|
|
|
|
|
|
|
|
@Input()
|
|
|
|
|
chartType: ChartType;
|
|
|
|
|
|
|
|
|
|
displayLegend: boolean;
|
|
|
|
|
legendConfig: LegendConfig;
|
|
|
|
|
legendData: LegendData;
|
|
|
|
|
isLegendFirst: boolean;
|
|
|
|
|
legendContainerLayoutType: string;
|
|
|
|
|
legendStyle: {[klass: string]: any};
|
|
|
|
|
|
|
|
|
|
public settings: TbFlotSettings;
|
|
|
|
|
private flot: TbFlot;
|
|
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ngOnInit(): void {
|
|
|
|
|
this.ctx.$scope.flotWidget = this;
|
|
|
|
|
this.settings = this.ctx.settings;
|
|
|
|
|
this.chartType = this.chartType || 'line';
|
|
|
|
|
this.configureLegend();
|
2023-10-18 12:59:28 +03:00
|
|
|
if (this.ctx.datasources?.length) {
|
|
|
|
|
this.flot = new TbFlot(this.ctx, this.chartType, $(this.flotElement.nativeElement));
|
|
|
|
|
}
|
2023-05-16 20:00:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private configureLegend(): void {
|
|
|
|
|
|
|
|
|
|
this.displayLegend = isDefinedAndNotNull(this.settings.showLegend) ? this.settings.showLegend
|
|
|
|
|
: false;
|
|
|
|
|
|
|
|
|
|
this.legendContainerLayoutType = 'column';
|
|
|
|
|
|
|
|
|
|
if (this.displayLegend) {
|
|
|
|
|
this.legendConfig = this.settings.legendConfig || defaultLegendConfig(widgetType.timeseries);
|
|
|
|
|
if (this.ctx.defaultSubscription) {
|
|
|
|
|
this.legendData = this.ctx.defaultSubscription.legendData;
|
|
|
|
|
} else {
|
|
|
|
|
this.legendData = {
|
|
|
|
|
keys: [],
|
|
|
|
|
data: []
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
if (this.legendConfig.position === LegendPosition.top ||
|
|
|
|
|
this.legendConfig.position === LegendPosition.bottom) {
|
|
|
|
|
this.legendContainerLayoutType = 'column';
|
|
|
|
|
this.isLegendFirst = this.legendConfig.position === LegendPosition.top;
|
|
|
|
|
} else {
|
|
|
|
|
this.legendContainerLayoutType = 'row';
|
|
|
|
|
this.isLegendFirst = this.legendConfig.position === LegendPosition.left;
|
|
|
|
|
}
|
|
|
|
|
switch (this.legendConfig.position) {
|
|
|
|
|
case LegendPosition.top:
|
|
|
|
|
this.legendStyle = {
|
|
|
|
|
paddingBottom: '8px',
|
|
|
|
|
maxHeight: '50%',
|
|
|
|
|
overflowY: 'auto'
|
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
case LegendPosition.bottom:
|
|
|
|
|
this.legendStyle = {
|
|
|
|
|
paddingTop: '8px',
|
|
|
|
|
maxHeight: '50%',
|
|
|
|
|
overflowY: 'auto'
|
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
case LegendPosition.left:
|
|
|
|
|
this.legendStyle = {
|
|
|
|
|
paddingRight: '0px',
|
|
|
|
|
maxWidth: '50%',
|
|
|
|
|
overflowY: 'auto'
|
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
case LegendPosition.right:
|
|
|
|
|
this.legendStyle = {
|
|
|
|
|
paddingLeft: '0px',
|
|
|
|
|
maxWidth: '50%',
|
|
|
|
|
overflowY: 'auto'
|
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public onLegendKeyHiddenChange(index: number) {
|
|
|
|
|
for (const id of Object.keys(this.ctx.subscriptions)) {
|
|
|
|
|
const subscription = this.ctx.subscriptions[id];
|
|
|
|
|
subscription.updateDataVisibility(index);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public onDataUpdated() {
|
|
|
|
|
this.flot.update();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public onLatestDataUpdated() {
|
|
|
|
|
this.flot.latestDataUpdate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public onResize() {
|
|
|
|
|
this.flot.resize();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public onEditModeChanged() {
|
|
|
|
|
this.flot.checkMouseEvents();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public onDestroy() {
|
|
|
|
|
this.flot.destroy();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|