implement metrics tracking
This commit is contained in:
1 parent
ca8d4e31da
commit
9446e3b2de
12 files changed
+846
-467
No files matched your search
+50
-29
@@ -1,71 +1,92 @@
|
||||
<div class="w-full h-full relative">
|
||||
<model-viewer
|
||||
#modelViewer
|
||||
class="absolute inset-0 w-full h-full"
|
||||
src="https://modelviewer.dev/shared-assets/models/Astronaut.glb"
|
||||
ar
|
||||
ar-modes="webxr"
|
||||
ar-placement="ceiling"
|
||||
reveal="manual"
|
||||
camera-orbit="0deg 75deg 2m">
|
||||
<model-viewer #modelViewer class="absolute inset-0 w-full h-full"
|
||||
src="https://modelviewer.dev/shared-assets/models/Astronaut.glb" ar ar-modes="webxr" ar-placement="ceiling"
|
||||
reveal="manual" camera-orbit="0deg 75deg 2m">
|
||||
|
||||
<button
|
||||
slot="ar-button"
|
||||
<button slot="ar-button" id="ar-button-legibility" (click)="logInteraction($event)"
|
||||
class="text-xl absolute top-4 left-1/2 -translate-x-1/2 bg-blue-500 text-white py-2 px-4 rounded-lg z-10">
|
||||
WebXR Umgebung laden
|
||||
</button>
|
||||
|
||||
<button slot="hotspot-text" class="hotspot ar-hotspot" data-position="-0.1 0.93 0.1" data-normal="0 1 0">
|
||||
<div class="annotation" [ngStyle]="{'font-size.px': currentSize}"
|
||||
style="background:rgba(255,255,255,0.9);padding:8px;border-radius:4px;color:black;">
|
||||
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
|
||||
style="background:rgba(255,255,255,0.9);padding:8px;border-radius:4px;color:black;">
|
||||
Lorem ipsum dolor sit amet...
|
||||
</div>
|
||||
</button>
|
||||
<div class="ar-controls absolute bottom-24 left-1/2 -translate-x-1/2 bg-black bg-opacity-70 p-4 rounded-xl space-y-4 text-white z-10">
|
||||
|
||||
|
||||
<div
|
||||
class="ar-controls absolute bottom-24 left-1/2 -translate-x-1/2 bg-black bg-opacity-70 p-4 rounded-xl space-y-4 text-white z-10">
|
||||
|
||||
<!-- Phase: Min -->
|
||||
<ng-container *ngIf="phase==='min'">
|
||||
<div>Minimum setzen</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
<button (click)="decrease()" class="w-10 h-10 bg-gray-600 rounded-full">–</button>
|
||||
<button id="min-decrease-btn" (click)="decrease(); logInteraction($event)"
|
||||
class="w-10 h-10 bg-gray-600 rounded-full">–</button>
|
||||
<span>{{ currentSize }}px</span>
|
||||
<button (click)="increase()" class="w-10 h-10 bg-gray-600 rounded-full">+</button>
|
||||
<button id="min-increase-btn" (click)="increase(); logInteraction($event)"
|
||||
class="w-10 h-10 bg-gray-600 rounded-full">+</button>
|
||||
</div>
|
||||
<button (click)="nextPhase()" class="bg-green-600 py-2 px-6 rounded-lg">Minimum bestätigen</button>
|
||||
<button id="min-confirm-btn" (click)="nextPhase(); logInteraction($event)"
|
||||
class="bg-green-600 py-2 px-6 rounded-lg">Minimum bestätigen</button>
|
||||
</ng-container>
|
||||
|
||||
<!-- Phase: Confirmed Min -->
|
||||
<ng-container *ngIf="phase==='confirmedMin'">
|
||||
<div>Minimum bestätigt: {{ currentSize }}px</div>
|
||||
<button (click)="resetToMid()" class="bg-gray-600 py-2 px-4 rounded-lg">Reset</button>
|
||||
<button (click)="nextPhase()" class="bg-blue-600 py-2 px-6 rounded-lg">Weiter zu Maximum</button>
|
||||
<div>Minimum bestätigt: {{ minSizeResult }}px</div>
|
||||
<button id="confirmed-min-reset-btn" (click)="resetToMid(); logInteraction($event)"
|
||||
class="bg-gray-600 py-2 px-4 rounded-lg">Reset</button>
|
||||
<button id="confirmed-min-continue-btn" (click)="nextPhase(); logInteraction($event)"
|
||||
class="bg-blue-600 py-2 px-6 rounded-lg">Weiter zu Maximum</button>
|
||||
</ng-container>
|
||||
|
||||
<!-- Phase: Max -->
|
||||
<ng-container *ngIf="phase==='max'">
|
||||
<div>Maximum setzen</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
<button (click)="decrease()" class="w-10 h-10 bg-gray-600 rounded-full">–</button>
|
||||
<button id="max-decrease-btn" (click)="decrease(); logInteraction($event)"
|
||||
class="w-10 h-10 bg-gray-600 rounded-full">–</button>
|
||||
<span>{{ currentSize }}px</span>
|
||||
<button (click)="increase()" class="w-10 h-10 bg-gray-600 rounded-full">+</button>
|
||||
<button id="max-increase-btn" (click)="increase(); logInteraction($event)"
|
||||
class="w-10 h-10 bg-gray-600 rounded-full">+</button>
|
||||
</div>
|
||||
<button (click)="nextPhase()" class="bg-green-600 py-2 px-6 rounded-lg">Maximum bestätigen</button>
|
||||
<button id="max-confirm-btn" (click)="nextPhase(); logInteraction($event)"
|
||||
class="bg-green-600 py-2 px-6 rounded-lg">Maximum bestätigen</button>
|
||||
</ng-container>
|
||||
|
||||
<!-- Phase: Confirmed Max -->
|
||||
<ng-container *ngIf="phase==='confirmedMax'">
|
||||
<div>Maximum bestätigt: {{ currentSize }}px</div>
|
||||
<button (click)="nextPhase()" class="bg-blue-600 py-2 px-6 rounded-lg">Weiter zu optiomal</button>
|
||||
<div>Maximum bestätigt: {{ maxSizeResult }}px</div>
|
||||
<button id="confirmed-max-continue-btn" (click)="nextPhase(); logInteraction($event)"
|
||||
class="bg-blue-600 py-2 px-6 rounded-lg">Weiter zu optiomal</button>
|
||||
</ng-container>
|
||||
|
||||
<!-- Phase: Comfortable -->
|
||||
<ng-container *ngIf="phase==='comfortable'">
|
||||
<div>Optimale Größe setzen</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
<button (click)="decrease()" class="w-10 h-10 bg-gray-600 rounded-full">–</button>
|
||||
<button id="comfort-decrease-btn" (click)="decrease(); logInteraction($event)"
|
||||
class="w-10 h-10 bg-gray-600 rounded-full">–</button>
|
||||
<span>{{ currentSize }}px</span>
|
||||
<button (click)="increase()" class="w-10 h-10 bg-gray-600 rounded-full">+</button>
|
||||
<button id="comfort-increase-btn" (click)="increase(); logInteraction($event)"
|
||||
class="w-10 h-10 bg-gray-600 rounded-full">+</button>
|
||||
</div>
|
||||
<button (click)="finishAssessment()" class="bg-green-600 py-2 px-6 rounded-lg">Optimale Größe setzen</button>
|
||||
<button id="comfort-confirm-btn" (click)="nextPhase(); logInteraction($event)"
|
||||
class="bg-green-600 py-2 px-6 rounded-lg">Optimale Größe setzen</button>
|
||||
</ng-container>
|
||||
|
||||
<!-- Phase: Confirmed Comfortable -->
|
||||
<ng-container *ngIf="phase==='confirmedComfort'">
|
||||
<div>Optimale Größe bestätigt: {{ comfortableSizeResult }}px</div>
|
||||
<button id="finish-assessment-btn" (click)="finishAssessment(); logInteraction($event)"
|
||||
class="bg-blue-600 py-2 px-6 rounded-lg">Test beenden</button>
|
||||
</ng-container>
|
||||
|
||||
<!-- Phase: Finished -->
|
||||
<ng-container *ngIf="phase==='finished'">
|
||||
<div class="font-semibold text-lg">Vielen Dank!</div>
|
||||
<p>Ergebnisse werden für die finale Übermittlung gespeichert...</p>
|
||||
</ng-container>
|
||||
|
||||
</div>
|
||||
|
||||
+55
-48
@@ -1,16 +1,18 @@
|
||||
import {
|
||||
Component,
|
||||
AfterViewInit,
|
||||
OnDestroy,
|
||||
ViewChild,
|
||||
ElementRef,
|
||||
ChangeDetectorRef,
|
||||
CUSTOM_ELEMENTS_SCHEMA,
|
||||
EventEmitter,
|
||||
Output
|
||||
Output,
|
||||
inject
|
||||
} from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { MetricsTrackerService } from '../../../../services/metrics-tracker.service';
|
||||
import '../../../../../assets/scripts/model-viewer';
|
||||
|
||||
@Component({
|
||||
@@ -21,97 +23,80 @@ import '../../../../../assets/scripts/model-viewer';
|
||||
styleUrls: ['./text-legibility-assessment.component.css'],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
})
|
||||
export class TextLegibilityAssessmentComponent implements AfterViewInit {
|
||||
export class TextLegibilityAssessmentComponent implements AfterViewInit, OnDestroy {
|
||||
@ViewChild('modelViewer') modelViewerRef!: ElementRef<any>;
|
||||
@Output() testComplete = new EventEmitter<void>();
|
||||
@Output() redoTest = new EventEmitter<number>();
|
||||
@Output() redoTest = new EventEmitter<number>();
|
||||
|
||||
private metricsService = inject(MetricsTrackerService);
|
||||
|
||||
// --- Component State (Restored) ---
|
||||
minSize = 2;
|
||||
maxSize = 64;
|
||||
currentSize = 16;
|
||||
comfortableSize = 16;
|
||||
|
||||
phase:
|
||||
| 'min'
|
||||
| 'confirmedMin'
|
||||
| 'max'
|
||||
| 'confirmedMax'
|
||||
| 'comfortable'
|
||||
| 'confirmedComfort'
|
||||
| 'finished' = 'min';
|
||||
minSizeResult: number | null = null;
|
||||
maxSizeResult: number | null = null;
|
||||
comfortableSizeResult: number | null = null;
|
||||
|
||||
phase: 'min' | 'confirmedMin' | 'max' | 'confirmedMax' | 'comfortable' | 'confirmedComfort' | 'finished' = 'min';
|
||||
|
||||
private offsetApplied = false;
|
||||
|
||||
constructor(private cdr: ChangeDetectorRef) {}
|
||||
constructor(private cdr: ChangeDetectorRef) {
|
||||
this.logInteraction = this.logInteraction.bind(this);
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
const mv = this.modelViewerRef.nativeElement;
|
||||
mv.setAttribute('scale', '0.25 0.25 0.25');
|
||||
this.metricsService.startDeviceOrientationTracking();
|
||||
this.metricsService.startArTracking(this.modelViewerRef.nativeElement);
|
||||
}
|
||||
|
||||
mv.addEventListener('ar-status', async (e: any) => {
|
||||
if (e.detail.status === 'session-started' && !this.offsetApplied) {
|
||||
await mv.updateComplete;
|
||||
const anchor = mv.getAnchor();
|
||||
if (!anchor.includes('not placed')) {
|
||||
const [x, y, z] = anchor.split(' ').map(parseFloat);
|
||||
mv.setAttribute('ar-anchor', `${x} ${y + 3.0} ${z}`);
|
||||
this.offsetApplied = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
public logInteraction(event: Event) {
|
||||
this.metricsService.logInteraction(event);
|
||||
}
|
||||
|
||||
decrease() {
|
||||
if (this.currentSize > this.minSize) {
|
||||
this.currentSize--;
|
||||
this.syncComfortable();
|
||||
}
|
||||
if (this.currentSize > this.minSize) this.currentSize--;
|
||||
}
|
||||
|
||||
increase() {
|
||||
if (this.currentSize < this.maxSize) {
|
||||
this.currentSize++;
|
||||
this.syncComfortable();
|
||||
}
|
||||
}
|
||||
|
||||
private syncComfortable() {
|
||||
if (this.phase === 'comfortable') {
|
||||
this.comfortableSize = this.currentSize;
|
||||
}
|
||||
if (this.currentSize < this.maxSize) this.currentSize++;
|
||||
}
|
||||
|
||||
nextPhase() {
|
||||
switch (this.phase) {
|
||||
case 'min':
|
||||
this.minSizeResult = this.currentSize;
|
||||
this.phase = 'confirmedMin';
|
||||
break;
|
||||
case 'confirmedMin':
|
||||
this.phase = 'max';
|
||||
this.currentSize = this.maxSize;
|
||||
this.phase = 'max';
|
||||
break;
|
||||
case 'max':
|
||||
this.maxSizeResult = this.currentSize;
|
||||
this.phase = 'confirmedMax';
|
||||
break;
|
||||
case 'confirmedMax':
|
||||
this.currentSize = Math.floor((this.minSizeResult! + this.maxSizeResult!) / 2);
|
||||
this.phase = 'comfortable';
|
||||
this.currentSize = Math.floor((this.minSize + this.maxSize) / 2);
|
||||
this.comfortableSize = this.currentSize;
|
||||
break;
|
||||
case 'comfortable':
|
||||
this.comfortableSizeResult = this.currentSize;
|
||||
this.phase = 'confirmedComfort';
|
||||
this.comfortableSize = this.currentSize;
|
||||
break;
|
||||
case 'confirmedComfort':
|
||||
this.phase = 'finished';
|
||||
this.testComplete.emit();
|
||||
this.finishAssessment();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
resetToMid() {
|
||||
this.currentSize = Math.floor((this.minSize + this.maxSize) / 2);
|
||||
this.phase = 'min';
|
||||
this.minSizeResult = null;
|
||||
this.maxSizeResult = null;
|
||||
this.comfortableSizeResult = null;
|
||||
}
|
||||
|
||||
retry() {
|
||||
@@ -119,6 +104,28 @@ export class TextLegibilityAssessmentComponent implements AfterViewInit {
|
||||
}
|
||||
|
||||
finishAssessment() {
|
||||
this.phase = 'finished';
|
||||
|
||||
const finalResults = {
|
||||
minReadableSize: this.minSizeResult,
|
||||
maxReadableSize: this.maxSizeResult,
|
||||
comfortableReadableSize: this.comfortableSizeResult
|
||||
};
|
||||
|
||||
this.metricsService.logInteraction(new CustomEvent('test-results', {
|
||||
detail: {
|
||||
testName: 'TextLegibility',
|
||||
results: finalResults
|
||||
}
|
||||
}));
|
||||
|
||||
console.log(finalResults);
|
||||
|
||||
this.testComplete.emit();
|
||||
}
|
||||
|
||||
|
||||
ngOnDestroy() {
|
||||
this.metricsService.cleanup();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user