diff --git a/src/app/components/section-canvas/section-canvas.component.html b/src/app/components/section-canvas/section-canvas.component.html index da242b966d3d4eb18ed9873ad32e8779fec1ce6b..fc687f76cb6b9420bdf574549d9df16370711eee 100644 --- a/src/app/components/section-canvas/section-canvas.component.html +++ b/src/app/components/section-canvas/section-canvas.component.html @@ -1,2 +1,7 @@ -<canvas #canvas [attr.width]="width" [attr.height]="height"> -</canvas> +<div fxLayout="column" fxLayoutAlign="center center"> + <canvas #canvas [attr.width]="width" [attr.height]="height"> + </canvas> + <mat-checkbox [ngModel]="useRealAspectRatio" (ngModelChange)="setUseRealAspectRatio($event)"> + {{ uitextUseRealRatio }} + </mat-checkbox> +</div> \ No newline at end of file diff --git a/src/app/components/section-canvas/section-canvas.component.ts b/src/app/components/section-canvas/section-canvas.component.ts index 41364eac3afb02d9d0c18364d1494b1460973bdb..be18032faa6581e72fe1ccf3e81b8dc69fb64666 100644 --- a/src/app/components/section-canvas/section-canvas.component.ts +++ b/src/app/components/section-canvas/section-canvas.component.ts @@ -1,4 +1,5 @@ import { Component, ViewChild, Input, OnChanges, AfterViewInit, ElementRef } from "@angular/core"; +import { I18nService } from "app/services/internationalisation.service"; import { acSection, cSnTrapez, ParamsSectionTrapez, cSnRectang, ParamsSectionRectang, cSnCirc, @@ -40,19 +41,44 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements private _result: Result; + /** + * paramètre de taille du canvas en entrée (pixels) + */ private _size: number; + /** + * taille horizontale résultante, suivant le flag de respect de l'échelle (pixels) + */ + private _sizeX: number; + + /** + * taille verticale résultante, suivant le flag de respect de l'échelle (pixels) + */ + private _sizeY: number; + + /** + * taille horizontale de la section (m) + */ + private _sectionWidth: number; + + /** + * taille verticale de la section (m) + */ + private _sectionHeight: number; + // tirants private _levels: Object[] = []; + constructor(private intlService: I18nService) { + super(); + } + public get width(): number { - // return this._calcCanvas.nativeElement.width; - return this._size; + return this._sizeX; } public get height(): number { - // return this._calcCanvas.nativeElement.height; - return this._size; + return this._sizeY; } private _context2d: CanvasRenderingContext2D; @@ -63,6 +89,7 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements @Input() public set section(s: acSection) { this._section = s; + this.computeSectionWidth(); } @Input() @@ -75,6 +102,9 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements this._size = s; } + // respect du rapport abscisses/ordonnées + public useRealAspectRatio: boolean = false; + // redessine le canvas chaque fois qu'une entrée change public ngOnChanges() { setTimeout(() => { @@ -92,7 +122,30 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements this.clear(); } - public addLevel(val: number, label: string, rgb: {}) { + /** + * calcul des tailles horizontale et verticale du canvas (pixels) + */ + private updateCanvasSize() { + if (this.useRealAspectRatio) { + if (this._sectionWidth > this._sectionHeight) { + this._sizeX = this._size; + this._sizeY = this._size * this._sectionHeight / this._sectionWidth; + } + else { + this._sizeX = this._size * this._sectionHeight / this._sectionWidth; + this._sizeY = this._size; + } + } else { + this._sizeX = this._sizeY = this._size; + } + } + + public setUseRealAspectRatio(b: boolean) { + this.useRealAspectRatio = b; + this.draw(); + } + + private addLevel(val: number, label: string, rgb: {}) { this._levels.push({ val, label, rgb }); } @@ -111,6 +164,26 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements return false; } + /** + * calcul des tailles horizontale et verticale de la section (m) + */ + private computeSectionWidth() { + if (this._section instanceof cSnTrapez) { + this.computeSectionWidthTrapez(); + } + else if (this._section instanceof cSnRectang) { + this.computeSectionWidthRect(); + } + else if (this._section instanceof cSnCirc) { + this.computeSectionWidthCirc(); + } + else if (this._section instanceof cSnPuiss) { + this.computeSectionWidthPara(); + } + else + throw new Error("SectionCanvasComponent.computeSectionWidth() : type de section non pris en charge"); + } + public draw() { // console.log(">> redrawing at size", this._size); if (this._context2d && this._section) { @@ -136,10 +209,13 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements const valY = this._result.sourceNub.getParameter("Y").singleValue; this.addLevel(valY, "Y = " + this.formattedValue(valY), SectionCanvasComponent.labelColors["Y"]); - this.sortLevels(); - this.drawFrame(); - const maxWidth = this.drawSection(); - this.drawLevels(maxWidth); + this.computeSectionHeight(); + this.updateCanvasSize(); + setTimeout(() => { // à cause du changement de taille du canvas dans updateCanvasSize() + this.drawFrame(); + this.drawSection(); + this.drawLevels(); + }, 10); } } @@ -157,24 +233,35 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements this.drawSectionLine(xmax, yb, xmax, maxHeight); } - private drawSectionTrapez(): number { + private computeSectionHeight() { + this.sortLevels(); + + // hauteur totale de la section + this._sectionHeight = this.getMaxLevel() * 1.1; + } + + private computeSectionWidthTrapez() { const sect: cSnTrapez = <cSnTrapez>this._section; const prms: ParamsSectionTrapez = <ParamsSectionTrapez>sect.prms; - // cote de berge - const yb: number = prms.YB.v; - // largeur de la partie pentue const lp: number = prms.Fruit.v * prms.YB.v; // largeur totale de la section - const maxWidth: number = lp * 2 + prms.LargeurFond.v; + this._sectionWidth = lp * 2 + prms.LargeurFond.v; + } - // hauteur totale de la section - let maxHeight: number = this.getMaxLevel(); - maxHeight *= 1.1; + private drawSectionTrapez() { + const sect: cSnTrapez = <cSnTrapez>this._section; + const prms: ParamsSectionTrapez = <ParamsSectionTrapez>sect.prms; - this.computeScale(maxWidth, maxHeight); + // cote de berge + const yb: number = prms.YB.v; + + // largeur de la partie pentue + const lp: number = prms.Fruit.v * prms.YB.v; + + this.computeScale(); // dessin de la section @@ -182,13 +269,19 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements this.setLineWidth(5); this.drawSectionLine(0, yb, lp, 0); this.drawSectionLine(lp, 0, lp + prms.LargeurFond.v, 0); - this.drawSectionLine(lp + prms.LargeurFond.v, 0, maxWidth, yb); + this.drawSectionLine(lp + prms.LargeurFond.v, 0, this._sectionWidth, yb); // pointillés du haut - this.drawTopDashLines(0, maxWidth, yb, maxHeight); + this.drawTopDashLines(0, this._sectionWidth, yb, this._sectionHeight); + } + + private computeSectionWidthRect() { + const sect: cSnRectang = <cSnRectang>this._section; + const prms: ParamsSectionRectang = <ParamsSectionRectang>sect.prms; - return maxWidth; + // largeur totale de la section + this._sectionWidth = prms.LargeurBerge.v; } private drawSectionRect() { @@ -198,14 +291,7 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements // cote de berge const yb: number = prms.YB.v; - // largeur totale de la section - const maxWidth: number = prms.LargeurBerge.v; - - // hauteur totale de la section - let maxHeight: number = this.getMaxLevel(); - maxHeight *= 1.1; - - this.computeScale(maxWidth, maxHeight); + this.computeScale(); // dessin de la section @@ -213,13 +299,32 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements this.setLineWidth(5); this.drawSectionLine(0, yb, 0, 0); this.drawSectionLine(0, 0, prms.LargeurBerge.v, 0); - this.drawSectionLine(prms.LargeurBerge.v, 0, maxWidth, yb); + this.drawSectionLine(prms.LargeurBerge.v, 0, this._sectionWidth, yb); // pointillés du haut - this.drawTopDashLines(0, maxWidth, yb, maxHeight); + this.drawTopDashLines(0, this._sectionWidth, yb, this._sectionHeight); + } + + private computeSectionWidthCirc() { + const sect: cSnCirc = <cSnCirc>this._section; + const prms: ParamsSectionCirc = <ParamsSectionCirc>sect.prms; + + // cote de berge + const yb: number = prms.YB.v; + + // diamètre, rayon + const D: number = prms.D.v; + const r: number = D / 2; + + // largeur au miroir + const B: Result = sect.CalcSection("B", yb); + if (!B.ok) { + throw B; + } - return maxWidth; + // largeur totale de la section + this._sectionWidth = yb < r ? B.vCalc : D; } private drawSectionCirc() { @@ -240,21 +345,14 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements throw B; } - // largeur totale de la section - const maxWidth: number = yb < r ? B.vCalc : D; - - // hauteur totale de la section - let maxHeight: number = this.getMaxLevel(); - maxHeight *= 1.1; - - this.computeScale(maxWidth, maxHeight); + this.computeScale(); // dessin de la section this.setStrokeColor(0, 0, 0); this.setLineWidth(5); - const wx: number = maxWidth / 2; + const wx: number = this._sectionWidth / 2; const alpha: Result = sect.CalcSection("Alpha", yb); if (!alpha.ok) { throw alpha; @@ -267,15 +365,24 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements // pointillés du haut const w: number = yb > r ? (D - B.vCalc) / 2 : 0; - this.drawTopDashLines(w, maxWidth - w, yb, maxHeight); - - return maxWidth; + this.drawTopDashLines(w, this._sectionWidth - w, yb, this._sectionHeight); } catch (e) { const res: Result = e as Result; this.drawText("error : " + res.log.toString(), 0, 0); } } + private computeSectionWidthPara() { + const sect: cSnPuiss = <cSnPuiss>this._section; + const prms: ParamsSectionPuiss = <ParamsSectionPuiss>sect.prms; + + // largeur au miroir + const B: number = prms.LargeurBerge.v; + + // largeur totale de la section + this._sectionWidth = B; + } + private drawSectionPara() { const sect: cSnPuiss = <cSnPuiss>this._section; const prms: ParamsSectionPuiss = <ParamsSectionPuiss>sect.prms; @@ -286,14 +393,7 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements // largeur au miroir const B: number = prms.LargeurBerge.v; - // largeur totale de la section - const maxWidth: number = B; - - // hauteur totale de la section - let maxHeight: number = this.getMaxLevel(); - maxHeight *= 1.1; - - this.computeScale(maxWidth, maxHeight); + this.computeScale(); // contour de la section @@ -312,9 +412,7 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements this._context2d.stroke(); // pointillés du haut - this.drawTopDashLines(0, maxWidth, yb, maxHeight); - - return maxWidth; + this.drawTopDashLines(0, this._sectionWidth, yb, this._sectionHeight); } private drawSectionEllipse(x: number, y: number, rX: number, rY: number, rot: number, start: number, end: number) { @@ -333,25 +431,26 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements * dessin de la section * @returns largeur de la section (en m) */ - private drawSection(): number { + private drawSection() { if (this._section instanceof cSnTrapez) { - return this.drawSectionTrapez(); + this.drawSectionTrapez(); } - if (this._section instanceof cSnRectang) { - return this.drawSectionRect(); + else if (this._section instanceof cSnRectang) { + this.drawSectionRect(); } - if (this._section instanceof cSnCirc) { - return this.drawSectionCirc(); + else if (this._section instanceof cSnCirc) { + this.drawSectionCirc(); } - if (this._section instanceof cSnPuiss) { - return this.drawSectionPara(); + else if (this._section instanceof cSnPuiss) { + this.drawSectionPara(); } - throw new Error("SectionCanvasComponent.drawSection() : type de section non pris en charge"); + else + throw new Error("SectionCanvasComponent.drawSection() : type de section non pris en charge"); } - private computeScale(maxWidth: number, maxHeight: number) { - this._scaleX = (this._size - 2 * this._textMargin) / maxWidth; - this._scaleY = (this._size - this._bottomMargin) / maxHeight; + private computeScale() { + this._scaleX = (this._sizeX - 2 * this._textMargin) / this._sectionWidth; + this._scaleY = (this._sizeY - this._bottomMargin) / this._sectionHeight; } /** @@ -365,7 +464,7 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements * convertit une ordonnée en m en pixels */ private Ym2pix(y: number) { - return this._size - this._bottomMargin - y * this._scaleY; + return this._sizeY - this._bottomMargin - y * this._scaleY; } private sortLevels() { @@ -380,7 +479,7 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements }); } - private drawLevels(maxWidth: number) { + private drawLevels() { let left = true; this.resetLineDash(); @@ -390,13 +489,13 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements const y = l["val"]; const col = l["rgb"]; this.setStrokeColor(col["r"], col["g"], col["b"]); - this.drawSectionLine(0, y, maxWidth, y); + this.drawSectionLine(0, y, this._sectionWidth, y); this.setFillColor(col["r"], col["g"], col["b"]); if (left) { this.drawText(l["label"], -0.1, y, "right"); } else { - this.drawText(l["label"], maxWidth + 0.1, y, "left"); + this.drawText(l["label"], this._sectionWidth + 0.1, y, "left"); } left = !left; } @@ -404,15 +503,14 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements // contour du canvas private drawFrame() { - this.clear(); this.resetLineDash(); this.setStrokeColor(128, 128, 128); - this.drawRect(0, 0, this.width, this.height); + this.drawRect(0, 0, this._sizeX, this._sizeY); } public clear() { if (this._context2d) { - this._context2d.clearRect(0, 0, this.width, this.height); + this._context2d.clearRect(0, 0, this._sizeX, this._sizeY); } } @@ -475,4 +573,8 @@ export class SectionCanvasComponent extends ResultsComponentDirective implements this._context2d.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle); this._context2d.stroke(); } + + public get uitextUseRealRatio(): string { + return this.intlService.localizeText("INFO_SECTIONPARAMETREE_REAL_RATIO"); + } } diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json index 56a2f105b8fe381cc8260baac031adecf8349a29..80c1a982ce9683d9fce6e7d7ea56814cdea0a99e 100755 --- a/src/locale/messages.en.json +++ b/src/locale/messages.en.json @@ -584,6 +584,7 @@ "INFO_SECTIONPARAMETREE_DESCRIPTION": "open-channel canal rectangular circular trapezoidal depth head normal critical conjugate corresponding subcritical supercritical Froude", "INFO_SECTIONPARAMETREE_TITRE_COURT": "Param. section", "INFO_SECTIONPARAMETREE_TITRE": "Parametric section", + "INFO_SECTIONPARAMETREE_REAL_RATIO": "Apply 1:1 scale", "INFO_SELECT_MULTIPLE_AND_OTHER": "other", "INFO_SELECT_MULTIPLE_AND_OTHERS": "others", "INFO_SETUP_ENABLE_HOTKEYS": "Enable keyboard shortcuts", diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json index 225b0751e30d7981d2294f75d501e110605f0bed..77a92907f461fbc5f0771b1fbdf5f43f6e28b21a 100755 --- a/src/locale/messages.fr.json +++ b/src/locale/messages.fr.json @@ -585,6 +585,7 @@ "INFO_SECTIONPARAMETREE_DESCRIPTION": "hydraulique à surface libre canal chenal bief rectangulaire circulaire puissance trapézoïdale périmètre charge mouillée rugosité hauteur charge critique normal conjuguée correspondante fluvial torrentiel Froude", "INFO_SECTIONPARAMETREE_TITRE_COURT": "Sec. param.", "INFO_SECTIONPARAMETREE_TITRE": "Section paramétrée", + "INFO_SECTIONPARAMETREE_REAL_RATIO": "Respecter l'échelle", "INFO_SELECT_MULTIPLE_AND_OTHER": "autre", "INFO_SELECT_MULTIPLE_AND_OTHERS": "autres", "INFO_SETUP_ENABLE_HOTKEYS": "Activer les raccourcis clavier",