Commit 0dde6233b130601d55d785f8164e0771e91ec77e

Authored by Igor Kulikov
1 parent 06477895

Improve dashboard image dialog - ability to set crop rectangle for dashboard screenshot

... ... @@ -28,10 +28,32 @@
28 28 <mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
29 29 </mat-progress-bar>
30 30 <div mat-dialog-content style="position: relative;">
31   - <fieldset [disabled]="(isLoading$ | async) || (takingScreenshot$ | async)" fxLayout="column" fxLayoutAlign="center center" fxLayoutGap="16px">
32   - <div class="tb-image-preview-container">
33   - <div *ngIf="!safeImageUrl; else elseBlock">{{ 'dashboard.no-image' | translate }}</div>
34   - <ng-template #elseBlock><img class="tb-image-preview" [src]="safeImageUrl" /></ng-template>
  31 + <fieldset [disabled]="(isLoading$ | async) || (takingScreenshot$ | async)" fxLayout="column" fxLayoutAlign="center center" fxLayoutGap="8px">
  32 + <div [formGroup]="dashboardRectFormGroup" fxLayout="column" fxLayoutGap="8px" fxLayoutAlign="center center">
  33 + <mat-form-field class="rect-field">
  34 + <mat-label>Top %</mat-label>
  35 + <input matInput formControlName="top" type="number" step="1" min="0" max="100">
  36 + </mat-form-field>
  37 + <div fxLayout="row" fxLayoutGap="8px" fxLayoutAlign="center center">
  38 + <mat-form-field class="rect-field">
  39 + <mat-label>Left %</mat-label>
  40 + <input matInput formControlName="left" type="number" step="1" min="0" max="100">
  41 + </mat-form-field>
  42 + <div class="tb-image-preview-container">
  43 + <div *ngIf="!safeImageUrl; else elseBlock">{{ 'dashboard.no-image' | translate }}</div>
  44 + <ng-template #elseBlock><img class="tb-image-preview" [src]="safeImageUrl" /></ng-template>
  45 + </div>
  46 + <mat-form-field class="rect-field">
  47 + <mat-label>Right %</mat-label>
  48 + <input matInput formControlName="right" type="number" step="1" min="0" max="100">
  49 + </mat-form-field>
  50 + </div>
  51 + <mat-form-field class="rect-field">
  52 + <mat-label>Bottom %</mat-label>
  53 + <input matInput formControlName="bottom" type="number" step="1" min="0" max="100">
  54 + </mat-form-field>
  55 + </div>
  56 + <div [formGroup]="dashboardRectFormGroup" fxFlex fxLayout="row" fxLayoutGap="8px">
35 57 </div>
36 58 <button mat-raised-button color="accent"
37 59 type="button"
... ...
... ... @@ -17,6 +17,11 @@
17 17 $previewSize: 300px !default;
18 18
19 19 :host {
  20 +
  21 + mat-form-field.rect-field {
  22 + max-width: 60px;
  23 + }
  24 +
20 25 .tb-image-preview {
21 26 width: auto;
22 27 max-width: $previewSize - 2;
... ...
... ... @@ -18,7 +18,7 @@ import { Component, Inject } from '@angular/core';
18 18 import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
19 19 import { Store } from '@ngrx/store';
20 20 import { AppState } from '@core/core.state';
21   -import { FormBuilder, FormGroup } from '@angular/forms';
  21 +import { FormBuilder, FormGroup, Validators } from '@angular/forms';
22 22 import { Router } from '@angular/router';
23 23 import { DialogComponent } from '@app/shared/components/dialog.component';
24 24 import { DashboardId } from '@shared/models/id/dashboard-id';
... ... @@ -27,6 +27,7 @@ import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
27 27 import html2canvas from 'html2canvas';
28 28 import { map, share } from 'rxjs/operators';
29 29 import { BehaviorSubject, from } from 'rxjs';
  30 +import { isNumber } from '@core/utils';
30 31
31 32 export interface DashboardImageDialogData {
32 33 dashboardId: DashboardId;
... ... @@ -55,6 +56,7 @@ export class DashboardImageDialogComponent extends DialogComponent<DashboardImag
55 56 safeImageUrl?: SafeUrl;
56 57 dashboardElement: HTMLElement;
57 58
  59 + dashboardRectFormGroup: FormGroup;
58 60 dashboardImageFormGroup: FormGroup;
59 61
60 62 constructor(protected store: Store<AppState>,
... ... @@ -69,6 +71,14 @@ export class DashboardImageDialogComponent extends DialogComponent<DashboardImag
69 71 this.dashboardId = this.data.dashboardId;
70 72 this.updateImage(this.data.currentImage);
71 73 this.dashboardElement = this.data.dashboardElement;
  74 + const clientRect = this.dashboardElement.getBoundingClientRect();
  75 +
  76 + this.dashboardRectFormGroup = this.fb.group({
  77 + left: [0, [Validators.min(0), Validators.max(100)]],
  78 + top: [0, [Validators.min(0), Validators.max(100)]],
  79 + right: [100, [Validators.min(0), Validators.max(100)]],
  80 + bottom: [100, [Validators.min(0), Validators.max(100)]]
  81 + });
72 82
73 83 this.dashboardImageFormGroup = this.fb.group({
74 84 dashboardImage: [this.data.currentImage]
... ... @@ -81,13 +91,45 @@ export class DashboardImageDialogComponent extends DialogComponent<DashboardImag
81 91 );
82 92 }
83 93
  94 + private convertUserPercent(percent: any, defaultValue: number): number {
  95 + let result: number;
  96 + if (isNumber(percent)) {
  97 + result = Math.max(0, Math.min(100, percent)) / 100;
  98 + } else {
  99 + result = defaultValue;
  100 + }
  101 + return result;
  102 + }
  103 +
84 104 takeScreenShot() {
85 105 this.takingScreenshotSubject.next(true);
  106 + const rect = this.dashboardElement.getBoundingClientRect();
  107 +
  108 + const leftVal = this.convertUserPercent(this.dashboardRectFormGroup.get('left').value, 0);
  109 + const topVal = this.convertUserPercent(this.dashboardRectFormGroup.get('top').value, 0);
  110 + const rightVal = this.convertUserPercent(this.dashboardRectFormGroup.get('right').value, 100);
  111 + const bottomVal = this.convertUserPercent(this.dashboardRectFormGroup.get('bottom').value, 100);
  112 +
  113 + const left = leftVal * rect.width;
  114 + const top = topVal * rect.height;
  115 + const right = rightVal * rect.width;
  116 + const bottom = bottomVal * rect.height;
  117 +
  118 + const x = rect.left + left;
  119 + const y = rect.top + top;
  120 + let width = right - left;
  121 + let height = bottom - top;
  122 + width = Math.max(1, width);
  123 + height = Math.max(1, height);
86 124 from(html2canvas(this.dashboardElement, {
87 125 logging: false,
88 126 useCORS: true,
89 127 foreignObjectRendering: false,
90   - scale: 512 / this.dashboardElement.clientWidth
  128 + scale: 512 / width,
  129 + x,
  130 + y,
  131 + width,
  132 + height
91 133 })).pipe(
92 134 map(canvas => canvas.toDataURL())).subscribe(
93 135 (image) => {
... ...