Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI: chartjs migration from 2.9.4 to 4.4.0 #2392

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion ui/.npmrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Takes care of version constraints strictly.
# For ex: node.js constraint added in package.json is taken strictly and throws errors during compile time if the mentioned version is out of range.
engine-strict=true
engine-strict=true
legacy-peer-deps=true
8 changes: 5 additions & 3 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@
"@ngx-formly/schematics": "^6.1.7",
"@ngx-translate/core": "^14.0.0",
"angular-mydatepicker": "^0.11.5",
"chart.js": "^2.9.4",
"chart.js": "^4.4.0",
"chartjs-adapter-date-fns": "^3.0.0",
"chartjs-plugin-zoom": "^2.0.1",
"classlist.js": "^1.1.20150312",
"compare-versions": "^6.1.0",
"d3": "^7.8.5",
"date-fns": "^2.30.0",
"file-saver-es": "^2.0.5",
"ng2-charts": "^2.4.3",
"ng2-charts": "4.1.1",
"ngx-cookie-service": "^15.0.0",
"ngx-spinner": "^15.0.1",
"roboto-fontface": "^0.10.0",
Expand Down Expand Up @@ -71,4 +73,4 @@
"lint": "ng lint",
"test": "ng test"
}
}
}
3 changes: 1 addition & 2 deletions ui/src/app/edge/history/abstracthistorychart.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<div [style.height.px]="getChartHeight()">
<ngx-spinner [name]="spinnerId"></ngx-spinner>
<ng-container *ngIf="!loading">
<canvas baseChart [datasets]="datasets" [labels]="labels" [options]="options" [colors]="colors"
chartType="line"></canvas>
<canvas baseChart [datasets]="datasets" [labels]="labels" [options]="options" type="line"></canvas>
</ng-container>
</div>
199 changes: 164 additions & 35 deletions ui/src/app/edge/history/abstracthistorychart.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import { Data } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { ChartDataSets } from 'chart.js';
import { differenceInDays, differenceInMonths } from 'date-fns';
import * as Chart from 'chart.js';
import { AbstractHistoryChart as NewAbstractHistoryChart } from 'src/app/shared/genericComponents/chart/abstracthistorychart';
import { JsonrpcResponseError } from 'src/app/shared/jsonrpc/base';
import { QueryHistoricTimeseriesDataRequest } from "src/app/shared/jsonrpc/request/queryHistoricTimeseriesDataRequest";
import { QueryHistoricTimeseriesEnergyPerPeriodRequest } from 'src/app/shared/jsonrpc/request/queryHistoricTimeseriesEnergyPerPeriodRequest';
import { QueryHistoricTimeseriesDataResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse";
import { QueryHistoricTimeseriesEnergyPerPeriodResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyPerPeriodResponse';
import { ChartAxis, HistoryUtils, YAxisTitle } from 'src/app/shared/service/utils';
import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from "src/app/shared/shared";

import { calculateResolution, ChartOptions, DEFAULT_TIME_CHART_OPTIONS, EMPTY_DATASET, Resolution, TooltipItem } from './shared';
import { HistoryUtils } from 'src/app/shared/service/utils';
import { DateUtils } from 'src/app/shared/utils/dateutils/dateutils';

import { calculateResolution, DEFAULT_TIME_CHART_OPTIONS, EMPTY_DATASET, Resolution, setLabelVisible, Unit } from './shared';

// NOTE: Auto-refresh of widgets is currently disabled to reduce server load
export abstract class AbstractHistoryChart {

Expand All @@ -29,12 +28,17 @@
// private ngUnsubscribe: Subject<void> = new Subject<void>();

public labels: Date[] = [];
public datasets: ChartDataSets[] = HistoryUtils.createEmptyDataset(this.translate);
public options: ChartOptions | null = DEFAULT_TIME_CHART_OPTIONS;
public datasets: Chart.ChartDataset[] = [];
public options: Chart.ChartOptions | null = null;
public colors = [];
// prevents subscribing more than once
protected hasSubscribed: boolean = false;

/** @deprecated*/
protected unit: YAxisTitle = YAxisTitle.ENERGY;
/** @deprecated*/
protected formatNumber: string = '1.0-2';

// Colors for Phase 1-3
protected phase1Color = {
backgroundColor: 'rgba(255,127,80,0.05)',
Expand Down Expand Up @@ -151,19 +155,25 @@
}

/**
* Generates a Tooltip Title string from a 'fromDate' and 'toDate'.
*
* @param fromDate the From-Date
* @param toDate the To-Date
* @param date Date from TooltipItem
* @returns period for Tooltip Header
*/
protected toTooltipTitle(fromDate: Date, toDate: Date, date: Date): string {
if (this.service.periodString == 'year') {
* Generates a Tooltip Title string from a 'fromDate' and 'toDate'.
*
* @param fromDate the From-Date
* @param toDate the To-Date
* @param date Date from TooltipItem
* @returns period for Tooltip Header
*/
protected static toTooltipTitle(fromDate: Date, toDate: Date, date: Date, service: Service): string {
let unit = calculateResolution(service, fromDate, toDate).resolution.unit;
if (unit == Unit.MONTHS) {
// Yearly view
return date.toLocaleDateString('default', { month: 'long' });
} else if (this.service.periodString == 'month') {

} else if (unit == Unit.DAYS) {
// Monthly view
return date.toLocaleDateString('default', { day: '2-digit', month: 'long' });

} else {
// Default
return date.toLocaleString('default', { day: '2-digit', month: '2-digit', year: '2-digit' }) + ' ' + date.toLocaleTimeString('default', { hour12: false, hour: '2-digit', minute: '2-digit' });
}
}
Expand All @@ -175,23 +185,8 @@
*
* @returns the ChartOptions
*/
protected createDefaultChartOptions(): ChartOptions {
let options = <ChartOptions>Utils.deepCopy(DEFAULT_TIME_CHART_OPTIONS);

// Overwrite TooltipsTitle
options.tooltips.callbacks.title = (tooltipItems: TooltipItem[], data: Data): string => {
let date = new Date(tooltipItems[0].xLabel);
return this.toTooltipTitle(this.service.historyPeriod.value.from, this.service.historyPeriod.value.to, date);
};

//x-axis
if (differenceInMonths(this.service.historyPeriod.value.to, this.service.historyPeriod.value.from) > 1) {
options.scales.xAxes[0].time.unit = "month";
} else if (differenceInDays(this.service.historyPeriod.value.to, this.service.historyPeriod.value.from) >= 5 && differenceInMonths(this.service.historyPeriod.value.to, this.service.historyPeriod.value.from) <= 1) {
options.scales.xAxes[0].time.unit = "day";
} else {
options.scales.xAxes[0].time.unit = "hour";
}
protected createDefaultChartOptions(): Chart.ChartOptions {
let options = <Chart.ChartOptions>Utils.deepCopy(DEFAULT_TIME_CHART_OPTIONS);
return options;
}

Expand Down Expand Up @@ -292,4 +287,138 @@
this.service.stopSpinner(this.spinnerId);
}

/**
*
* Sets chart options
*
* @deprecated used for charts not using {@link NewAbstractHistoryChart} but {@link AbstractHistoryChart}
*/
public setOptions(options: Chart.ChartOptions) {

const locale = this.service.translate.currentLang;
const yAxis: HistoryUtils.yAxis = { position: 'left', unit: this.unit, yAxisId: ChartAxis.LEFT };
const chartObject: HistoryUtils.ChartData = {
input: [],
output: () => [],
yAxes: [yAxis],
tooltip: {
formatNumber: this.formatNumber

Check failure on line 305 in ui/src/app/edge/history/abstracthistorychart.ts

View workflow job for this annotation

GitHub Actions / build-ui

Missing trailing comma
}

Check failure on line 306 in ui/src/app/edge/history/abstracthistorychart.ts

View workflow job for this annotation

GitHub Actions / build-ui

Missing trailing comma
};
const unit = this.unit;
const formatNumber = this.formatNumber;
const colors = this.colors;
const translate = this.translate;

/** Hide default displayed yAxis */
options.scales['y'] = {
display: false,
};

// Overwrite TooltipsTitle
options.plugins.tooltip.callbacks.title = (tooltipItems: Chart.TooltipItem<any>[]): string => {
let date = new Date(tooltipItems[0].label);
return AbstractHistoryChart.toTooltipTitle(this.service.historyPeriod.value.from, this.service.historyPeriod.value.to, date, this.service);
};

options.plugins.tooltip.callbacks.label = function (tooltipItem: Chart.TooltipItem<any>) {
let label = tooltipItem.dataset.label;
let value = tooltipItem.dataset.data[tooltipItem.dataIndex];

const customUnit = tooltipItem.dataset.unit ?? null;
return label.split(":")[0] + ": " + NewAbstractHistoryChart.getToolTipsSuffix("", value, formatNumber, customUnit ?? unit, 'line', locale, translate);
};

options.plugins.tooltip.callbacks.labelColor = (item: Chart.TooltipItem<any>) => {
const color = colors[item.datasetIndex];

if (!color) {
return;
}

return {
borderColor: color.borderColor,
backgroundColor: color.backgroundColor,
};
};

options.plugins.legend.labels.generateLabels = function (chart: Chart.Chart) {
let chartLegendLabelItems: Chart.LegendItem[] = [];
chart.data.datasets.forEach((dataset, index) => {

const color = colors[index];

if (!color) {
return;
}

// Set colors manually
dataset.backgroundColor = color.backgroundColor ?? dataset.backgroundColor;
dataset.borderColor = color.borderColor ?? dataset.borderColor;

chartLegendLabelItems.push({
text: dataset.label,
datasetIndex: index,
fillStyle: color.backgroundColor,
hidden: !chart.isDatasetVisible(index),
lineWidth: 2,
...(dataset['borderDash'] && { lineDash: dataset['borderDash'] }),
strokeStyle: color.borderColor,
});
});
return chartLegendLabelItems;
};

// Remove duplicates from legend, if legendItem with two or more occurrences in legend, use one legendItem to trigger them both
options.plugins.legend.onClick = function (event: Chart.ChartEvent, legendItem: Chart.LegendItem, legend) {
let chart: Chart.Chart = this.chart;

let legendItems = chart.data.datasets.reduce((arr, ds, i) => {
if (ds.label == legendItem.text) {
arr.push({ label: ds.label, index: i });
}
return arr;
}, []);

legendItems.forEach(item => {
// original.call(this, event, legendItem1);
setLabelVisible(item.label, !chart.isDatasetVisible(legendItem.datasetIndex));
var meta = chart.getDatasetMeta(item.index);
// See controller.isDatasetVisible comment
meta.hidden = meta.hidden === null ? !chart.data.datasets[item.index].hidden : null;
});

// We hid a dataset ... rerender the chart
chart.update();
};

options = NewAbstractHistoryChart.getYAxisOptions(options, yAxis, this.translate, 'line', locale);

const timeFormat = calculateResolution(this.service, this.service.historyPeriod.value.from, this.service.historyPeriod.value.to).timeFormat;
options.scales.x['time'].unit = timeFormat;
switch (timeFormat) {
case 'hour':
options.scales.x.ticks['source'] = 'auto';//labels,auto
options.scales.x.ticks.maxTicksLimit = 31;
break;
case 'day':
case 'month':
options.scales.x.ticks['source'] = 'data';
break;
}

options.scales.x['stacked'] = true;
options.scales[ChartAxis.LEFT]['stacked'] = false;

NewAbstractHistoryChart.applyChartTypeSpecificOptionsChanges('line', options, this.service, chartObject);

/** Overwrite default yAxisId */
this.datasets = this.datasets
.map(el => {
el['yAxisID'] = ChartAxis.LEFT;
return el;
});

this.options = options;
}
}
19 changes: 6 additions & 13 deletions ui/src/app/edge/history/chpsoc/chart.component.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { formatNumber } from '@angular/common';
import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { DefaultTypes } from 'src/app/shared/service/defaulttypes';

import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared';
import { AbstractHistoryChart } from '../abstracthistorychart';
import { Data, TooltipItem } from './../shared';
import { YAxisTitle } from 'src/app/shared/service/utils';

@Component({
selector: 'chpsocchart',
Expand All @@ -29,7 +28,6 @@ export class ChpSocChartComponent extends AbstractHistoryChart implements OnInit
super("chpsoc-chart", service, translate);
}


ngOnInit() {
this.startSpinner();
this.service.setCurrentComponent('', this.route);
Expand Down Expand Up @@ -141,7 +139,10 @@ export class ChpSocChartComponent extends AbstractHistoryChart implements OnInit
console.error(reason); // TODO error message
this.initializeChart();
return;
});
}).finally(() => {
this.unit = YAxisTitle.PERCENTAGE;
this.setOptions(this.options);
});;
}

protected getChannelAddresses(edge: Edge, config: EdgeConfig): Promise<ChannelAddress[]> {
Expand All @@ -159,15 +160,7 @@ export class ChpSocChartComponent extends AbstractHistoryChart implements OnInit
}

protected setLabel() {
let options = this.createDefaultChartOptions();
options.scales.yAxes[0].scaleLabel.labelString = this.translate.instant('General.percentage');
options.tooltips.callbacks.label = function (tooltipItem: TooltipItem, data: Data) {
let label = data.datasets[tooltipItem.datasetIndex].label;
let value = tooltipItem.yLabel;
return label + ": " + formatNumber(value, 'de', '1.0-0') + " %"; // TODO get locale dynamically
};
options.scales.yAxes[0].ticks.max = 100;
this.options = options;
this.options = this.createDefaultChartOptions();
}

public getChartHeight(): number {
Expand Down
2 changes: 0 additions & 2 deletions ui/src/app/edge/history/common/consumption/chart/chart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,6 @@ export class ChartComponent extends AbstractHistoryChart {
},
color: 'rgb(253,197,7)',
stack: 0,
hiddenOnInit: true,
noStrokeThroughLegendIfHidden: false,
});

const evcsComponentColors: string[] = ['rgb(0,223,0)', 'rgb(0,178,0)', 'rgb(0,201,0)', 'rgb(0,134,0)', 'rgb(0,156,0)'];
Expand Down
Loading
Loading