From 490ef6386c3145412dba7abd40a7545fc75db95f Mon Sep 17 00:00:00 2001 From: "mathias.chouet" <mathias.chouet@irstea.fr> Date: Thu, 11 Jul 2019 10:32:13 +0200 Subject: [PATCH 1/4] Add zoom feature on PAB profile graph --- angular.json | 4 ++- package-lock.json | 8 ++++++ package.json | 1 + .../pab-profile-graph.component.html | 5 +++- .../pab-profile-graph.component.ts | 27 ++++++++++++++++++- src/main.ts | 2 ++ 6 files changed, 44 insertions(+), 3 deletions(-) diff --git a/angular.json b/angular.json index daa02deb9..5482a7544 100644 --- a/angular.json +++ b/angular.json @@ -32,7 +32,9 @@ "node_modules/primeng/resources/primeng.min.css", "node_modules/primeng/resources/themes/nova-light/theme.css" ], - "scripts": [], + "scripts": [ + "node_modules/chartjs-plugin-zoom/chartjs-plugin-zoom.min.js" + ], "showCircularDependencies": false }, "configurations": { diff --git a/package-lock.json b/package-lock.json index 72d12202a..23fc51a46 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3417,6 +3417,14 @@ "color-name": "^1.0.0" } }, + "chartjs-plugin-zoom": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/chartjs-plugin-zoom/-/chartjs-plugin-zoom-0.7.2.tgz", + "integrity": "sha512-5AtMCjlBlRsA/vxlvcBsAYKbkk0tVYE6+XX9M9LE6aSqbjqGR5NUQwYH0YvvvpmJjTZfB+HDhHaaGxJ/8aGaaw==", + "requires": { + "hammerjs": "^2.0.8" + } + }, "cheerio": { "version": "1.0.0-rc.2", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.2.tgz", diff --git a/package.json b/package.json index e39372066..d3fda3c44 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "@types/pako": "^1.0.1", "@types/sprintf-js": "^1.1.2", "angular2-chartjs": "^0.5.1", + "chartjs-plugin-zoom": "^0.7.2", "cordova-android": "^8.0.0", "cordova-plugin-device": "^2.0.2", "core-js": "^2.6.5", diff --git a/src/app/components/pab-profile-graph/pab-profile-graph.component.html b/src/app/components/pab-profile-graph/pab-profile-graph.component.html index bfbe7c551..954f059c1 100644 --- a/src/app/components/pab-profile-graph/pab-profile-graph.component.html +++ b/src/app/components/pab-profile-graph/pab-profile-graph.component.html @@ -1,6 +1,9 @@ <div class="graph-results-container" #graphProfile fxLayout="row wrap" fxLayoutAlign="center center"> <div fxFlex="1 1 100%"> <div class="graph-profile-buttons"> + <button mat-icon-button (click)="resetZoom()"> + <mat-icon color="primary">replay</mat-icon> + </button> <button mat-icon-button (click)="exportAsImage(graphProfile)"> <mat-icon color="primary">image</mat-icon> </button> @@ -15,4 +18,4 @@ <chart type="scatter" [data]="graph_data" [options]="graph_options" #graphChart> </chart> </div> -</div> +</div> \ No newline at end of file diff --git a/src/app/components/pab-profile-graph/pab-profile-graph.component.ts b/src/app/components/pab-profile-graph/pab-profile-graph.component.ts index 9c61cf609..526b2d9fd 100644 --- a/src/app/components/pab-profile-graph/pab-profile-graph.component.ts +++ b/src/app/components/pab-profile-graph/pab-profile-graph.component.ts @@ -1,4 +1,6 @@ -import { Component } from "@angular/core"; +import { Component, ViewChild } from "@angular/core"; + +import { ChartComponent } from "angular2-chartjs"; import { ApplicationSetupService } from "../../services/app-setup/app-setup.service"; import { I18nService } from "../../services/internationalisation/internationalisation.service"; @@ -14,6 +16,9 @@ import { PabResults } from "../../results/pab-results"; }) export class PabProfileGraphComponent extends ResultsComponent { + @ViewChild(ChartComponent) + private chartComponent; + private _results: PabResults; /** size of the longest variable value */ @@ -79,6 +84,22 @@ export class PabProfileGraphComponent extends ResultsComponent { } }] }; + // enable zoom and pan (using "chartjs-plugin-zoom" package) + this.graph_options["plugins"] = { + zoom: { + pan: { + enabled: true, + mode: "xy", + }, + zoom: { + enabled: true, + drag: false, // conflicts with pan; set to false to enable mouse wheel zoom + mode: "xy", + // percentage of zoom on a wheel event + speed: 0.1, + } + } + }; } public set results(r: PabResults) { @@ -170,6 +191,10 @@ export class PabProfileGraphComponent extends ResultsComponent { }); // defaults to image/png } + public resetZoom() { + this.chartComponent.chart.resetZoom(); + } + private getXSeries(): string[] { const data: string[] = []; const nDigits = this.appSetupService.displayDigits; diff --git a/src/main.ts b/src/main.ts index 9b8fff7b9..018a6f867 100644 --- a/src/main.ts +++ b/src/main.ts @@ -5,6 +5,8 @@ import { platformBrowserDynamic } from "@angular/platform-browser-dynamic"; import { AppModule } from "./app/app.module"; import { environment } from "./environments/environment"; +import "chartjs-plugin-zoom"; + if (environment.production) { enableProdMode(); } -- GitLab From 153f000614d67f4a5384109fbe8710ef7e90a5cb Mon Sep 17 00:00:00 2001 From: "mathias.chouet" <mathias.chouet@irstea.fr> Date: Thu, 11 Jul 2019 10:37:17 +0200 Subject: [PATCH 2/4] Improve PAB profile zoom; remove debug message --- .../pab-profile-graph/pab-profile-graph.component.ts | 4 ++-- src/app/formulaire/definition/concrete/form-pab.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/components/pab-profile-graph/pab-profile-graph.component.ts b/src/app/components/pab-profile-graph/pab-profile-graph.component.ts index 526b2d9fd..4eb60ec9a 100644 --- a/src/app/components/pab-profile-graph/pab-profile-graph.component.ts +++ b/src/app/components/pab-profile-graph/pab-profile-graph.component.ts @@ -88,12 +88,12 @@ export class PabProfileGraphComponent extends ResultsComponent { this.graph_options["plugins"] = { zoom: { pan: { - enabled: true, + enabled: false, // conflicts with drag zoom mode: "xy", }, zoom: { enabled: true, - drag: false, // conflicts with pan; set to false to enable mouse wheel zoom + drag: true, // conflicts with pan; set to false to enable mouse wheel zoom mode: "xy", // percentage of zoom on a wheel event speed: 0.1, diff --git a/src/app/formulaire/definition/concrete/form-pab.ts b/src/app/formulaire/definition/concrete/form-pab.ts index 898f54217..aa5bac686 100644 --- a/src/app/formulaire/definition/concrete/form-pab.ts +++ b/src/app/formulaire/definition/concrete/form-pab.ts @@ -23,10 +23,10 @@ export class FormulairePab extends FormulaireBase { return this.currentNub as Pab; } - public doCompute() { + /* public doCompute() { this.dumpPabStructure(this.pabNub); super.doCompute(); - } + } */ // debug method private dumpPabStructure(pab: Pab) { -- GitLab From 965270935ed465e7f6c00e5098116902a162d945 Mon Sep 17 00:00:00 2001 From: "mathias.chouet" <mathias.chouet@irstea.fr> Date: Fri, 12 Jul 2019 11:28:54 +0200 Subject: [PATCH 3/4] PAB profile graph: enable resetZoom button only when zoom changed; add "title" to graph buttons --- .../pab-profile-graph.component.html | 8 ++-- .../pab-profile-graph.component.scss | 6 +++ .../pab-profile-graph.component.ts | 38 +++++++++++++++++-- src/locale/messages.en.json | 4 ++ src/locale/messages.fr.json | 4 ++ 5 files changed, 53 insertions(+), 7 deletions(-) diff --git a/src/app/components/pab-profile-graph/pab-profile-graph.component.html b/src/app/components/pab-profile-graph/pab-profile-graph.component.html index 954f059c1..28b4288fd 100644 --- a/src/app/components/pab-profile-graph/pab-profile-graph.component.html +++ b/src/app/components/pab-profile-graph/pab-profile-graph.component.html @@ -1,16 +1,16 @@ <div class="graph-results-container" #graphProfile fxLayout="row wrap" fxLayoutAlign="center center"> <div fxFlex="1 1 100%"> <div class="graph-profile-buttons"> - <button mat-icon-button (click)="resetZoom()"> + <button mat-icon-button (click)="resetZoom()" [disabled]="! zoomWasChanged" [title]="uitextResetZoomTitle"> <mat-icon color="primary">replay</mat-icon> </button> - <button mat-icon-button (click)="exportAsImage(graphProfile)"> + <button mat-icon-button (click)="exportAsImage(graphProfile)" [title]="uitextExportImageTitle"> <mat-icon color="primary">image</mat-icon> </button> - <button mat-icon-button *ngIf="! isFullscreen" (click)="setFullscreen(graphProfile)"> + <button mat-icon-button *ngIf="! isFullscreen" (click)="setFullscreen(graphProfile)" [title]="uitextEnterFSTitle"> <mat-icon color="primary" class="scaled12">fullscreen</mat-icon> </button> - <button mat-icon-button *ngIf="isFullscreen" (click)="exitFullscreen()"> + <button mat-icon-button *ngIf="isFullscreen" (click)="exitFullscreen()" [title]="uitextExitFSTitle"> <mat-icon color="primary" class="scaled12">fullscreen_exit</mat-icon> </button> </div> diff --git a/src/app/components/pab-profile-graph/pab-profile-graph.component.scss b/src/app/components/pab-profile-graph/pab-profile-graph.component.scss index 6382f8a70..465866a6c 100644 --- a/src/app/components/pab-profile-graph/pab-profile-graph.component.scss +++ b/src/app/components/pab-profile-graph/pab-profile-graph.component.scss @@ -19,5 +19,11 @@ transform: scale(1.2); } } + + &:disabled { + mat-icon { + color: #bfbfbf; + } + } } } diff --git a/src/app/components/pab-profile-graph/pab-profile-graph.component.ts b/src/app/components/pab-profile-graph/pab-profile-graph.component.ts index 4eb60ec9a..9cc7da3ae 100644 --- a/src/app/components/pab-profile-graph/pab-profile-graph.component.ts +++ b/src/app/components/pab-profile-graph/pab-profile-graph.component.ts @@ -1,4 +1,4 @@ -import { Component, ViewChild } from "@angular/core"; +import { Component, ViewChild, ChangeDetectorRef } from "@angular/core"; import { ChartComponent } from "angular2-chartjs"; @@ -27,6 +27,8 @@ export class PabProfileGraphComponent extends ResultsComponent { /** inferred extended values list for each variating parameter */ private varValues = []; + private _zoomWasChanged = false; + /* * config du graphe */ @@ -55,7 +57,8 @@ export class PabProfileGraphComponent extends ResultsComponent { public constructor( private appSetupService: ApplicationSetupService, - private intlService: I18nService + private intlService: I18nService, + private cd: ChangeDetectorRef ) { super(); const nDigits = this.appSetupService.displayDigits; @@ -85,6 +88,7 @@ export class PabProfileGraphComponent extends ResultsComponent { }] }; // enable zoom and pan (using "chartjs-plugin-zoom" package) + const that = this; this.graph_options["plugins"] = { zoom: { pan: { @@ -96,7 +100,8 @@ export class PabProfileGraphComponent extends ResultsComponent { drag: true, // conflicts with pan; set to false to enable mouse wheel zoom mode: "xy", // percentage of zoom on a wheel event - speed: 0.1, + // speed: 0.1, + onZoomComplete: function(t: any) { return function() { t.zoomComplete(); }; }(that) } } }; @@ -130,6 +135,16 @@ export class PabProfileGraphComponent extends ResultsComponent { } } + private zoomComplete() { + console.log("zoom complete du Q !"); + this._zoomWasChanged = true; + this.cd.detectChanges(); + } + + public get zoomWasChanged(): boolean { + return this._zoomWasChanged; + } + public updateView() { this.generateScatterGraph(); } @@ -193,6 +208,23 @@ export class PabProfileGraphComponent extends ResultsComponent { public resetZoom() { this.chartComponent.chart.resetZoom(); + this._zoomWasChanged = false; + } + + public get uitextResetZoomTitle() { + return this.intlService.localizeText("INFO_GRAPH_BUTTON_TITLE_RESET_ZOOM"); + } + + public get uitextExportImageTitle() { + return this.intlService.localizeText("INFO_GRAPH_BUTTON_TITLE_EXPORT_IMAGE"); + } + + public get uitextEnterFSTitle() { + return this.intlService.localizeText("INFO_GRAPH_BUTTON_TITLE_ENTER_FS"); + } + + public get uitextExitFSTitle() { + return this.intlService.localizeText("INFO_GRAPH_BUTTON_TITLE_EXIT_FS"); } private getXSeries(): string[] { diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json index 5e07c524b..1fce8bfcd 100644 --- a/src/locale/messages.en.json +++ b/src/locale/messages.en.json @@ -101,6 +101,10 @@ "INFO_EXTRARES_ENUM_STRUCTUREFLOWREGIME_1": "Partially submerged", "INFO_EXTRARES_ENUM_STRUCTUREFLOWREGIME_2": "Submerged", "INFO_EXTRARES_ENUM_STRUCTUREFLOWREGIME_3": "Zero flow", + "INFO_GRAPH_BUTTON_TITLE_RESET_ZOOM": "Restore default zoom", + "INFO_GRAPH_BUTTON_TITLE_EXPORT_IMAGE": "Save picture", + "INFO_GRAPH_BUTTON_TITLE_ENTER_FS": "Display fullscreen", + "INFO_GRAPH_BUTTON_TITLE_EXIT_FS": "Exis fullscreen mode", "INFO_DEVICE_ADDED": "1 device added", "INFO_DEVICE_ADDED_N_TIMES": "%s devices added", "INFO_DEVICE_COPIED": "Device #%s copied", diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json index 8b97db895..1c4ace04c 100644 --- a/src/locale/messages.fr.json +++ b/src/locale/messages.fr.json @@ -101,6 +101,10 @@ "INFO_EXTRARES_ENUM_STRUCTUREFLOWREGIME_1": "Partiellement noyé", "INFO_EXTRARES_ENUM_STRUCTUREFLOWREGIME_2": "Noyé", "INFO_EXTRARES_ENUM_STRUCTUREFLOWREGIME_3": "Débit nul", + "INFO_GRAPH_BUTTON_TITLE_RESET_ZOOM": "Réinitialiser le zoom", + "INFO_GRAPH_BUTTON_TITLE_EXPORT_IMAGE": "Enregistrer l'image", + "INFO_GRAPH_BUTTON_TITLE_ENTER_FS": "Afficher en plein écran", + "INFO_GRAPH_BUTTON_TITLE_EXIT_FS": "Sortir du mode plein écran", "INFO_DEVICE_ADDED": "1 ouvrage ajouté", "INFO_DEVICE_ADDED_N_TIMES": "%s ouvrages ajoutés", "INFO_DEVICE_COPIED": "Ouvrage n°%s copié", -- GitLab From 2f9d4519b4f6ed85bf0e6b65424f346f9e1c2a7f Mon Sep 17 00:00:00 2001 From: "mathias.chouet" <mathias.chouet@irstea.fr> Date: Fri, 12 Jul 2019 11:36:03 +0200 Subject: [PATCH 4/4] Added zoom functionality on every graph --- .../pab-profile-graph.component.ts | 28 --------- .../results-graph.component.html | 9 ++- .../results-graph.component.scss | 6 ++ .../results-graph/results-graph.component.ts | 61 ++++++++++++++++++- 4 files changed, 71 insertions(+), 33 deletions(-) diff --git a/src/app/components/pab-profile-graph/pab-profile-graph.component.ts b/src/app/components/pab-profile-graph/pab-profile-graph.component.ts index 9cc7da3ae..de364b5e3 100644 --- a/src/app/components/pab-profile-graph/pab-profile-graph.component.ts +++ b/src/app/components/pab-profile-graph/pab-profile-graph.component.ts @@ -136,7 +136,6 @@ export class PabProfileGraphComponent extends ResultsComponent { } private zoomComplete() { - console.log("zoom complete du Q !"); this._zoomWasChanged = true; this.cd.detectChanges(); } @@ -170,33 +169,6 @@ export class PabProfileGraphComponent extends ResultsComponent { showLine: "true" }); } - - /* 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[] = []; - const nbLines = that._results.getVariatingParametersSymbols().length; - 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) { - if (nbLines > 1) { - lines.unshift(""); - } - lines.unshift(line); - } else { - lines.push(line); - } - } - return lines; - } - } - }; */ } public exportAsImage(element: HTMLDivElement) { diff --git a/src/app/components/results-graph/results-graph.component.html b/src/app/components/results-graph/results-graph.component.html index c30eebd7b..1c15bdcc2 100644 --- a/src/app/components/results-graph/results-graph.component.html +++ b/src/app/components/results-graph/results-graph.component.html @@ -1,13 +1,16 @@ <div class="graph-results-container" #graphResults fxLayout="row wrap" fxLayoutAlign="center center"> <div fxFlex="1 1 100%"> <div class="graph-results-buttons"> - <button mat-icon-button (click)="exportAsImage(graphResults)"> + <button mat-icon-button (click)="resetZoom()" [disabled]="! zoomWasChanged" [title]="uitextResetZoomTitle"> + <mat-icon color="primary">replay</mat-icon> + </button> + <button mat-icon-button (click)="exportAsImage(graphResults)" [title]="uitextExportImageTitle"> <mat-icon color="primary">image</mat-icon> </button> - <button mat-icon-button *ngIf="! isFullscreen" (click)="setFullscreen(graphResults)"> + <button mat-icon-button *ngIf="! isFullscreen" (click)="setFullscreen(graphResults)" [title]="uitextEnterFSTitle"> <mat-icon color="primary" class="scaled12">fullscreen</mat-icon> </button> - <button mat-icon-button *ngIf="isFullscreen" (click)="exitFullscreen()"> + <button mat-icon-button *ngIf="isFullscreen" (click)="exitFullscreen()" [title]="uitextExitFSTitle"> <mat-icon color="primary" class="scaled12">fullscreen_exit</mat-icon> </button> </div> diff --git a/src/app/components/results-graph/results-graph.component.scss b/src/app/components/results-graph/results-graph.component.scss index c50b430fd..4eab50fee 100644 --- a/src/app/components/results-graph/results-graph.component.scss +++ b/src/app/components/results-graph/results-graph.component.scss @@ -19,6 +19,12 @@ transform: scale(1.2); } } + + &:disabled { + mat-icon { + color: #bfbfbf; + } + } } } diff --git a/src/app/components/results-graph/results-graph.component.ts b/src/app/components/results-graph/results-graph.component.ts index 7e775c89a..abda1f85a 100644 --- a/src/app/components/results-graph/results-graph.component.ts +++ b/src/app/components/results-graph/results-graph.component.ts @@ -1,4 +1,6 @@ -import { Component, ViewChild, AfterContentInit, OnInit } from "@angular/core"; +import { Component, ViewChild, AfterContentInit, ChangeDetectorRef } from "@angular/core"; + +import { ChartComponent } from "angular2-chartjs"; import { Observer } from "jalhyd"; @@ -17,11 +19,17 @@ import { ResultsComponent } from "../fixedvar-results/results.component"; ] }) export class ResultsGraphComponent extends ResultsComponent implements AfterContentInit, Observer { + + @ViewChild(ChartComponent) + private chartComponent; + private _results: PlottableData; /** used to briefly destroy/rebuild the chart component, to refresh axis labels (@see bug #137) */ public displayChart = true; + private _zoomWasChanged = false; + @ViewChild(GraphTypeSelectComponent) private _graphTypeComponent: GraphTypeSelectComponent; @@ -52,9 +60,28 @@ export class ResultsGraphComponent extends ResultsComponent implements AfterCont public constructor( private appSetup: ApplicationSetupService, - private intlService: I18nService + private intlService: I18nService, + private cd: ChangeDetectorRef ) { super(); + // enable zoom and pan (using "chartjs-plugin-zoom" package) + const that = this; + this.graph_options["plugins"] = { + zoom: { + pan: { + enabled: false, // conflicts with drag zoom + mode: "xy", + }, + zoom: { + enabled: true, + drag: true, // conflicts with pan; set to false to enable mouse wheel zoom + mode: "xy", + // percentage of zoom on a wheel event + // speed: 0.1, + onZoomComplete: function(t: any) { return function() { t.zoomComplete(); }; }(that) + } + } + }; } public set results(r: PlottableData) { @@ -116,6 +143,15 @@ export class ResultsGraphComponent extends ResultsComponent implements AfterCont return this.intlService.localizeText("INFO_PARAMFIELD_GRAPH_SELECT_Y_AXIS"); } + private zoomComplete() { + this._zoomWasChanged = true; + this.cd.detectChanges(); + } + + public get zoomWasChanged(): boolean { + return this._zoomWasChanged; + } + public updateView() { // (re)generate chart switch (this._graphTypeComponent.selectedValue) { @@ -316,6 +352,27 @@ export class ResultsGraphComponent extends ResultsComponent implements AfterCont }); // defaults to image/png } + public resetZoom() { + this.chartComponent.chart.resetZoom(); + this._zoomWasChanged = false; + } + + public get uitextResetZoomTitle() { + return this.intlService.localizeText("INFO_GRAPH_BUTTON_TITLE_RESET_ZOOM"); + } + + public get uitextExportImageTitle() { + return this.intlService.localizeText("INFO_GRAPH_BUTTON_TITLE_EXPORT_IMAGE"); + } + + public get uitextEnterFSTitle() { + return this.intlService.localizeText("INFO_GRAPH_BUTTON_TITLE_ENTER_FS"); + } + + public get uitextExitFSTitle() { + return this.intlService.localizeText("INFO_GRAPH_BUTTON_TITLE_EXIT_FS"); + } + // interface Observer update(sender: any, data: any) { -- GitLab