-
Mathias Chouet authored2cadfcac
import { Component, ViewChild, AfterContentInit, OnInit } from "@angular/core";
import { Observer } from "jalhyd";
import { GraphTypeSelectComponent } from "./graph-type.component";
import { ApplicationSetupService } from "../../services/app-setup/app-setup.service";
import { I18nService } from "../../services/internationalisation/internationalisation.service";
import { PlottableData } from "../../results/plottable-data";
import { GraphType } from "../../results/graph-type";
import { ResultsComponent } from "../fixedvar-results/results.component";
@Component({
selector: "results-graph",
templateUrl: "./results-graph.component.html",
styleUrls: [
"./results-graph.component.scss"
]
})
export class ResultsGraphComponent extends ResultsComponent implements AfterContentInit, Observer {
private _results: PlottableData;
/** used to briefly destroy/rebuild the chart component, to refresh axis labels (@see bug #137) */
public displayChart = true;
@ViewChild(GraphTypeSelectComponent)
private _graphTypeComponent: GraphTypeSelectComponent;
/*
* config du graphe
*/
public graph_type: string;
public graph_data = {};
public graph_options = {
responsive: true,
maintainAspectRatio: true,
animation: {
duration: 0
},
legend: {
display: false
},
title: {
display: true,
text: ""
},
elements: {
line: {
tension: 0
}
}
};
public constructor(
private appSetup: ApplicationSetupService,
private intlService: I18nService
) {
super();
}
public set results(r: PlottableData) {
this.forceRebuild();
this._results = r;
if (this._results && this._graphTypeComponent) {
this._graphTypeComponent.selectedValue = r.graphType;
}
}
public get availableChartAxis() {
if (this._results) {
return this._results.getAvailableChartAxis();
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
}
}
public get chartX() {
if (this._results) {
return this._results.chartX;
}
}
public set chartX(X) {
if (X !== this.chartX) {
this._results.chartX = X;
this.forceRebuild();
// refresh chart
this.updateView();
}
}
public get chartY() {
if (this._results) {
return this._results.chartY;
}
}
public set chartY(Y) {
if (Y !== this.chartY) {
this._results.chartY = Y;
this.forceRebuild();
// refresh chart
this.updateView();
}
}
/**
* Returns a human readable description of any param / result symbol
*/
public getChartAxisLabel(symbol: string): string {
return this._results.getChartAxisLabel(symbol);
}
public get uitextSelectX() {
return this.intlService.localizeText("INFO_PARAMFIELD_GRAPH_SELECT_X_AXIS");
}
public get uitextSelectY() {
return this.intlService.localizeText("INFO_PARAMFIELD_GRAPH_SELECT_Y_AXIS");
}
public updateView() {
// (re)generate chart
switch (this._graphTypeComponent.selectedValue) {
case GraphType.Histogram:
this.graph_type = "bar";
this.generateBarGraph();
break;
default:
this.graph_type = "scatter";
this.generateScatterGraph();
break;
}
}
public ngAfterContentInit() {
this._graphTypeComponent.addObserver(this);
}
/**
* Calls getChartAxisLabel() and removes the symbol prefix
* (cannot rebuild a clean label here)
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
*/
private axisLabelWithoutSymbol(symbol: string) {
let l = this._results.getChartAxisLabel(symbol);
const i = l.indexOf(": ");
if (i !== -1) {
l = l.substring(i + 2);
}
return l;
}
/** forces Angular to rebuild the chart @see bug #137 */
private forceRebuild() {
this.displayChart = false;
const that = this;
setTimeout(() => { // trick
that.displayChart = true;
}, 10);
}
/**
* génère les données d'un graphe de type "bar"
*/
private generateBarGraph() {
const labs = [];
const dat = [];
const xSeries = this._results.getValuesSeries(this.chartX);
const ySeries = this._results.getValuesSeries(this.chartY);
// both series are supposed to be the same length
for (let i = 0; i < xSeries.length; i++) {
labs.push(xSeries[i]);
dat.push(ySeries[i]);
}
const nDigits = this.appSetup.displayDigits;
this.graph_options["scales"] = {
xAxes: [{
gridLines: {
offsetGridLines: true
},
ticks: {
precision: nDigits,
callback: function(value, index, values) {
return Number(value).toFixed(nDigits);
}
},
scaleLabel: {
display: true,
labelString: this.axisLabelWithoutSymbol(this.chartX)
}
}],
yAxes: [{
scaleLabel: {
display: true,
labelString: this.axisLabelWithoutSymbol(this.chartY)
}
}]
};
const that = this;
this.graph_options["tooltips"] = {
displayColors: false,
callbacks: {
title: (tooltipItems, data) => {
return this.chartY + " = " + Number(tooltipItems[0].yLabel).toFixed(nDigits);
},
label: (tooltipItem, data) => {
const lines: string[] = [];
for (const v of that._results.getVariatingParametersSymbols()) {
const series = that._results.getValuesSeries(v);
const line = v + " = " + series[tooltipItem.index].toFixed(nDigits);
if (v === this.chartX) {
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
lines.unshift("");
lines.unshift(line);
} else {
lines.push(line);
}
}
return lines;
}
}
};
this.graph_data = {
labels: labs,
datasets: [{
label: "",
data: dat
}]
};
}
/**
* génère les données d'un graphe de type "scatter"
*/
private generateScatterGraph() {
const dat = [];
const xSeries = this._results.getValuesSeries(this.chartX);
const ySeries = this._results.getValuesSeries(this.chartY);
// both series are supposed to be the same length
for (let i = 0; i < xSeries.length; i++) {
dat.push({
x: xSeries[i],
y: ySeries[i]
});
}
const nDigits = this.appSetup.displayDigits;
this.graph_options["scales"] = {
xAxes: [{
type: "linear",
position: "bottom",
ticks: {
precision: nDigits
},
scaleLabel: {
display: true,
labelString: this.axisLabelWithoutSymbol(this.chartX)
}
}],
yAxes: [{
type: "linear",
position: "left",
ticks: {
precision: nDigits
},
scaleLabel: {
display: true,
labelString: this.axisLabelWithoutSymbol(this.chartY)
}
}]
};
const that = this;
this.graph_options["tooltips"] = {
displayColors: false,
callbacks: {
title: (tooltipItems, data) => {
return this.chartY + " = " + Number(tooltipItems[0].yLabel).toFixed(nDigits);
},
label: (tooltipItem, data) => {
const lines: string[] = [];
for (const v of that._results.getVariatingParametersSymbols()) {
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
const series = that._results.getValuesSeries(v);
const line = v + " = " + series[tooltipItem.index].toFixed(nDigits);
if (v === this.chartX) {
lines.unshift("");
lines.unshift(line);
} else {
lines.push(line);
}
}
return lines;
}
}
};
this.graph_data = {
datasets: [{
label: "",
data: dat,
borderColor: "#808080", // couleur de la ligne
backgroundColor: "rgba(0,0,0,0)", // couleur de remplissage sous la courbe : transparent
showLine: "true"
}]
};
}
public exportAsImage(element: HTMLDivElement) {
const canvas: HTMLCanvasElement = element.querySelector("canvas");
canvas.toBlob((blob) => {
saveAs(blob, "chart.png");
}); // defaults to image/png
}
// interface Observer
update(sender: any, data: any) {
if (sender instanceof GraphTypeSelectComponent) {
if (data.action === "graphTypeChanged") {
this._results.graphType = data.value;
}
}
this.updateView();
}
}