From aa67f45f78e6f725c58c2a2e87b8291a58f7a0cc Mon Sep 17 00:00:00 2001
From: jojohoch <joachim.hoch@iqb.hu-berlin.de>
Date: Mon, 8 Nov 2021 08:28:01 +0100
Subject: [PATCH] Enable and extend magnifier for images

* Add magnifier properties to `ImageElement`
* Set used value at `UnitStateService`
* Bypass parsing error of distpacker
---
 .../element-components/image.component.ts     | 21 ++++---
 .../element-components/magnifier.component.ts | 56 ++++++++++++-------
 projects/common/models/image-element.ts       |  4 ++
 .../element-container.component.ts            | 14 +++++
 4 files changed, 67 insertions(+), 28 deletions(-)

diff --git a/projects/common/element-components/image.component.ts b/projects/common/element-components/image.component.ts
index cf57db12c..d3ba88932 100644
--- a/projects/common/element-components/image.component.ts
+++ b/projects/common/element-components/image.component.ts
@@ -1,6 +1,7 @@
-import { Component } from '@angular/core';
+import { Component, EventEmitter, Output } from '@angular/core';
 import { ElementComponent } from '../element-component.directive';
 import { ImageElement } from '../models/image-element';
+import { ValueChangeElement } from '../models/uI-element';
 
 @Component({
   selector: 'app-image',
@@ -13,18 +14,24 @@ import { ImageElement } from '../models/image-element';
              [src]="elementModel.src | safeResourceUrl"
              [alt]="'imageNotFound' | translate"
              [class]="elementModel.dynamicPositioning? 'dynamic-image' : 'static-image'">
-<!--        <app-magnifier-->
-<!--            [image]=image>-->
-<!--        </app-magnifier>-->
+        <app-magnifier *ngIf="elementModel.magnifier"
+                       [imageId]="elementModel.id"
+                       [size]="elementModel.magnifierSize"
+                       [zoom]="elementModel.magnifierZoom"
+                       [used]="elementModel.magnifierUsed"
+                       [image]=image
+                       (magnifierUsed)="magnifierUsed.emit($event)">
+        </app-magnifier>
       </div>
     </div>
   `,
   styles: [
-    '.image-container{ width: fit-content; height: fit-content; margin: auto; position: relative}',
-    '.dynamic-image{width: 100%; height: fit-content}',
-    '.static-image{ width: 100%; height: 100%; object-fit: contain}'
+    '.image-container{ width: fit-content; height: fit-content; margin: auto; position: relative }',
+    '.dynamic-image{ width: 100%; height: fit-content }',
+    '.static-image{ width: 100%; height: 100%; object-fit: contain }'
   ]
 })
 export class ImageComponent extends ElementComponent {
+  @Output() magnifierUsed = new EventEmitter<ValueChangeElement>();
   elementModel!: ImageElement;
 }
diff --git a/projects/common/element-components/magnifier.component.ts b/projects/common/element-components/magnifier.component.ts
index f319cd0ce..43910aade 100644
--- a/projects/common/element-components/magnifier.component.ts
+++ b/projects/common/element-components/magnifier.component.ts
@@ -1,50 +1,64 @@
-import { Component, HostListener, Input } from '@angular/core';
+import {
+  Component, EventEmitter, HostListener, Input, Output
+} from '@angular/core';
+import { ValueChangeElement } from '../models/uI-element';
 
 @Component({
   selector: 'app-magnifier',
   template: `
-    <div *ngIf="image && image.width && image.height"
-         class="hide-cursor">
-<!--      <div class="magnifier-glass"-->
-<!--           [style.backgroundImage] = "'url('+ (image.src) + ')'"-->
-<!--           [style.backgroundPosition] = "backgroundPosition"-->
-<!--           [style.left.px]="left"-->
-<!--           [style.top.px]="top"-->
-<!--           [style.width.px]="glassRadius * 2"-->
-<!--           [style.height.px]="glassRadius * 2"-->
-<!--           [style.backgroundSize] = "(image.width * zoom) + 'px ' + (image.height * zoom) + 'px'"-->
-<!--           [style.backgroundRepeat] = "'no-repeat'">-->
-<!--      </div>-->
+    <div class="hide-cursor">
+      <div class="magnifier-glass"
+           [style.backgroundImage]="url + '(' + image.src + ')'"
+           [style.backgroundPosition]="backgroundPosition"
+           [style.left.px]="left"
+           [style.top.px]="top"
+           [style.width.px]="size"
+           [style.height.px]="size"
+           [style.backgroundSize]="(image.width * zoom) + 'px ' + (image.height * zoom) + 'px'"
+           [style.backgroundRepeat]="'no-repeat'">
+      </div>
     </div>
   `,
   styles: [
     ':host { position: absolute; top: 0; bottom: 0; right: 0; left: 0; }',
-    '.magnifier-glass{ position: absolute; outline: 1px solid #000; pointer-events: none;}',
+    '.magnifier-glass{ position: absolute; border: 1px solid #000; pointer-events: none;}',
     '.hide-cursor{ width: 100%; height: 100%; cursor: none }'
   ]
 })
 export class Magnifier {
   @Input() image!: HTMLImageElement;
+  @Input() imageId!: string;
+  @Input() zoom!: number;
+  @Input() size!: number;
+  @Input() used!: boolean;
+  @Output() magnifierUsed = new EventEmitter<ValueChangeElement>();
 
-  glassRadius = 50;
-  zoom: number = 2;
   left!: number;
-  top!:number;
+  top!: number;
   backgroundPosition!: string;
+  url: string = 'url';
 
   @HostListener('mousemove', ['$event'])
   onMousemove(event: MouseEvent): void {
+    if (!this.used) {
+      this.used = true;
+      this.magnifierUsed.emit({ id: this.imageId, values: [false, true] });
+    }
     this.left = this.calculateGlassPosition(this.image.width, event.offsetX);
     this.top = this.calculateGlassPosition(this.image.height, event.offsetY);
     this.backgroundPosition =
-      `-${this.calculateBackgroundPosition(event.offsetX)}px -${this.calculateBackgroundPosition(event.offsetY)}px`;
+      `-${
+        this.calculateBackgroundPosition(this.image.width, event.offsetX)
+      }px -${
+        this.calculateBackgroundPosition(this.image.height, event.offsetY)
+      }px`;
   }
 
   private calculateGlassPosition(max: number, value: number): number {
-    return ((max - 2 * this.glassRadius) / (max)) * value;
+    return ((max - this.size) / (max)) * value;
   }
 
-  private calculateBackgroundPosition(value: number): number {
-    return (value * this.zoom) < this.glassRadius ? 0 : (value * this.zoom - this.glassRadius);
+  private calculateBackgroundPosition(max: number, value: number): number {
+    return value * this.zoom - (value / max) * this.size;
   }
 }
diff --git a/projects/common/models/image-element.ts b/projects/common/models/image-element.ts
index 06e8fb9fa..2c6ee045a 100644
--- a/projects/common/models/image-element.ts
+++ b/projects/common/models/image-element.ts
@@ -2,6 +2,10 @@ import { UIElement } from './uI-element';
 
 export class ImageElement extends UIElement {
   src: string = '';
+  magnifier: boolean = false;
+  magnifierSize: number = 100;
+  magnifierZoom: number = 1.5;
+  magnifierUsed: boolean = false;
   constructor(serializedElement: UIElement) {
     super(serializedElement);
     Object.assign(this, serializedElement);
diff --git a/projects/player/src/app/components/element-container/element-container.component.ts b/projects/player/src/app/components/element-container/element-container.component.ts
index ef013bd0f..b72132b7c 100644
--- a/projects/player/src/app/components/element-container/element-container.component.ts
+++ b/projects/player/src/app/components/element-container/element-container.component.ts
@@ -26,6 +26,7 @@ import { CompoundElementComponent }
 import { TextElement } from '../../../../../common/models/text-element';
 import { VideoElement } from '../../../../../common/models/video-element';
 import { AudioElement } from '../../../../../common/models/audio-element';
+import { ImageElement } from '../../../../../common/models/image-element';
 
 @Component({
   selector: 'app-element-container',
@@ -105,6 +106,14 @@ export class ElementContainerComponent implements OnInit {
         });
     }
 
+    if (elementComponent.magnifierUsed) {
+      elementComponent.magnifierUsed
+        .pipe(takeUntil(this.ngUnsubscribe))
+        .subscribe((magnifierUsed: ValueChangeElement) => {
+          this.unitStateService.changeElementValue(magnifierUsed);
+        });
+    }
+
     if (elementComponent.formValueChanged) {
       elementComponent.formValueChanged
         .pipe(takeUntil(this.ngUnsubscribe))
@@ -165,6 +174,9 @@ export class ElementContainerComponent implements OnInit {
         case 'text':
           elementModel.text = unitStateElementCode.value;
           break;
+        case 'image':
+          elementModel.magnifierUsed = unitStateElementCode.value;
+          break;
         case 'video':
         case 'audio':
           elementModel.playbackTime = unitStateElementCode.value;
@@ -180,6 +192,8 @@ export class ElementContainerComponent implements OnInit {
     switch (elementModel.type) {
       case 'text':
         return { id: elementModel.id, value: (elementModel as TextElement).text };
+      case 'image':
+        return { id: elementModel.id, value: (elementModel as ImageElement).magnifierUsed };
       case 'video':
         return { id: elementModel.id, value: (elementModel as VideoElement).playbackTime };
       case 'audio':
-- 
GitLab