Changed slider handling for 2d
All checks were successful
Build, Test & Push Frontend / quality-check (pull_request) Successful in 1m5s
Build, Test & Push Frontend / docker (pull_request) Has been skipped

This commit is contained in:
2026-02-13 14:15:22 +01:00
parent 1e8ba020e2
commit c2ad2ae992
4 changed files with 77 additions and 9 deletions

32
package-lock.json generated
View File

@@ -8,6 +8,7 @@
"name": "playground-frontend", "name": "playground-frontend",
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"@angular-slider/ngx-slider": "^21.0.0",
"@angular/animations": "~21.1.0", "@angular/animations": "~21.1.0",
"@angular/cdk": "~21.1.0", "@angular/cdk": "~21.1.0",
"@angular/common": "~21.1.0", "@angular/common": "~21.1.0",
@@ -464,6 +465,22 @@
"typescript": "*" "typescript": "*"
} }
}, },
"node_modules/@angular-slider/ngx-slider": {
"version": "21.0.0",
"resolved": "https://registry.npmjs.org/@angular-slider/ngx-slider/-/ngx-slider-21.0.0.tgz",
"integrity": "sha512-66mbz9+022VDcquV8RrbD3jF6KXUX28r5YEzBAiv2D2H2wJGZiq6GdxKuCPnIgPs6VL5eCbD7nCO7m02U8kBcw==",
"license": "MIT",
"dependencies": {
"detect-passive-events": "^2.0.3",
"rxjs": "^7.8.2",
"tslib": "^2.3.0"
},
"peerDependencies": {
"@angular/common": "^21.0.0",
"@angular/core": "^21.0.0",
"@angular/forms": "^21.0.0"
}
},
"node_modules/@angular/animations": { "node_modules/@angular/animations": {
"version": "21.1.2", "version": "21.1.2",
"resolved": "https://registry.npmjs.org/@angular/animations/-/animations-21.1.2.tgz", "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-21.1.2.tgz",
@@ -7364,6 +7381,12 @@
"npm": "1.2.8000 || >= 1.4.16" "npm": "1.2.8000 || >= 1.4.16"
} }
}, },
"node_modules/detect-it": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/detect-it/-/detect-it-4.0.1.tgz",
"integrity": "sha512-dg5YBTJYvogK1+dA2mBUDKzOWfYZtHVba89SyZUhc4+e3i2tzgjANFg5lDRCd3UOtRcw00vUTMK8LELcMdicug==",
"license": "MIT"
},
"node_modules/detect-libc": { "node_modules/detect-libc": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
@@ -7375,6 +7398,15 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/detect-passive-events": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/detect-passive-events/-/detect-passive-events-2.0.3.tgz",
"integrity": "sha512-QN/1X65Axis6a9D8qg8Py9cwY/fkWAmAH/edTbmLMcv4m5dboLJ7LcAi8CfaCON2tjk904KwKX/HTdsHC6yeRg==",
"license": "MIT",
"dependencies": {
"detect-it": "^4.0.1"
}
},
"node_modules/devtools-protocol": { "node_modules/devtools-protocol": {
"version": "0.0.1467305", "version": "0.0.1467305",
"resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1467305.tgz", "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1467305.tgz",

View File

@@ -11,6 +11,7 @@
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular-slider/ngx-slider": "^21.0.0",
"@angular/animations": "~21.1.0", "@angular/animations": "~21.1.0",
"@angular/cdk": "~21.1.0", "@angular/cdk": "~21.1.0",
"@angular/common": "~21.1.0", "@angular/common": "~21.1.0",

View File

@@ -29,7 +29,13 @@
<mat-icon>undo</mat-icon> {{ 'FRACTAL.RESET' | translate }} <mat-icon>undo</mat-icon> {{ 'FRACTAL.RESET' | translate }}
</button> </button>
</div> </div>
<div class="zoom-controls" style="display: flex; align-items: center; gap: 10px;">
<mat-icon>zoom_out</mat-icon>
<ngx-slider [(value)]="sliderValue" [options]="options" (valueChange)="onSliderChange($event)" ></ngx-slider>
<mat-icon>zoom_in</mat-icon>
</div> </div>
</div>
<app-babylon-canvas <app-babylon-canvas
[config]="renderConfig" [config]="renderConfig"
[renderCallback]="onRender" [renderCallback]="onRender"

View File

@@ -1,4 +1,4 @@
import {Component, OnInit} from '@angular/core'; import {Component, OnInit, signal} from '@angular/core';
import {Information} from '../information/information'; import {Information} from '../information/information';
import {MatCard, MatCardContent, MatCardHeader, MatCardTitle} from '@angular/material/card'; import {MatCard, MatCardContent, MatCardHeader, MatCardTitle} from '@angular/material/card';
import {TranslatePipe} from '@ngx-translate/core'; import {TranslatePipe} from '@ngx-translate/core';
@@ -13,6 +13,7 @@ import {FRACTAL2D_FRAGMENT, FRACTAL2D_VERTEX} from './fractal.shader';
import {PointerEventTypes, PointerInfo, Scene, ShaderMaterial, Vector2} from '@babylonjs/core'; import {PointerEventTypes, PointerInfo, Scene, ShaderMaterial, Vector2} from '@babylonjs/core';
import {MatButton} from '@angular/material/button'; import {MatButton} from '@angular/material/button';
import {MatIcon} from '@angular/material/icon'; import {MatIcon} from '@angular/material/icon';
import {NgxSliderModule, Options} from '@angular-slider/ngx-slider';
@Component({ @Component({
selector: 'app-fractal', selector: 'app-fractal',
@@ -30,7 +31,8 @@ import {MatIcon} from '@angular/material/icon';
FormsModule, FormsModule,
BabylonCanvas, BabylonCanvas,
MatButton, MatButton,
MatIcon MatIcon,
NgxSliderModule
], ],
templateUrl: './fractal.component.html', templateUrl: './fractal.component.html',
styleUrl: './fractal.component.scss', styleUrl: './fractal.component.scss',
@@ -79,12 +81,24 @@ export class FractalComponent implements OnInit {
}; };
// --- State --- // --- State ---
readonly minZoomValue = 0.2;
readonly maxZoomValue = 64000;
private isDragging = false; private isDragging = false;
private dragStartPoint: { x: number, y: number } | null = null; private dragStartPoint: { x: number, y: number } | null = null;
selectedAlgorithm = 0; selectedAlgorithm = 0;
selectedColorScheme = 0; selectedColorScheme = 0;
sliderValue = signal(0);
options: Options = {
floor: this.minZoomValue,
ceil: this.maxZoomValue,
logScale: true,
step: 0.01,
showTicks: false,
hideLimitLabels: true,
hidePointerLabels: true
};
zoom = 0; zoom = 0;
offsetX = 0; offsetX = 0;
offsetY = 0; offsetY = 0;
@@ -108,14 +122,13 @@ export class FractalComponent implements OnInit {
} }
onAlgorithmChange(algoName: string): void { onAlgorithmChange(algoName: string): void {
this.onReset()
switch(algoName) { switch(algoName) {
case 'Mandelbrot': this.selectedAlgorithm = 0; break; case 'Mandelbrot': this.selectedAlgorithm = 0; break;
case 'Julia': this.selectedAlgorithm = 1; break; case 'Julia': this.selectedAlgorithm = 1; break;
case 'Burning Ship': this.selectedAlgorithm = 2; break; case 'Burning Ship': this.selectedAlgorithm = 2; break;
case 'Newton': this.selectedAlgorithm = 3; break; case 'Newton': this.selectedAlgorithm = 3; break;
} }
this.onReset()
} }
onColorChanged(schemeName: string): void { onColorChanged(schemeName: string): void {
@@ -128,10 +141,18 @@ export class FractalComponent implements OnInit {
} }
onReset(): void { onReset(): void {
this.zoom = 0.2;
this.offsetX = 0.0;
this.offsetY = 0.0; this.offsetY = 0.0;
this.zoom = 0.2
this.maxIterations = 100; this.maxIterations = 100;
switch(this.selectedAlgorithm) {
case 0: this.offsetX = -0.5; break;
case 1: this.offsetX = 0; break;
case 2: this.offsetX = -1.75; this.zoom = 8; this.offsetY = -0.03;break;
case 3: this.offsetX = 0; break;
default: this.offsetX = 0.0;
}
} }
onSceneReady(scene: Scene): void { onSceneReady(scene: Scene): void {
@@ -161,7 +182,6 @@ export class FractalComponent implements OnInit {
if (info.event.button !== 0) { if (info.event.button !== 0) {
return; return;
} }
this.isDragging = true; this.isDragging = true;
this.dragStartPoint = { x: info.event.clientX, y: info.event.clientY }; this.dragStartPoint = { x: info.event.clientX, y: info.event.clientY };
} }
@@ -216,6 +236,8 @@ export class FractalComponent implements OnInit {
this.zoom /= zoomFactor; this.zoom /= zoomFactor;
} }
this.zoom = Math.max(Math.min(this.zoom, this.maxZoomValue), this.minZoomValue);
this.sliderValue.set(this.zoom);
const optimalIterations = this.getIterationsForZoom(this.zoom); const optimalIterations = this.getIterationsForZoom(this.zoom);
this.maxIterations = Math.min(optimalIterations, 3000); this.maxIterations = Math.min(optimalIterations, 3000);
@@ -223,6 +245,13 @@ export class FractalComponent implements OnInit {
this.offsetY = mouseYWorld - mouseYView / this.zoom; this.offsetY = mouseYWorld - mouseYView / this.zoom;
} }
onSliderChange(newValue: number): void {
this.zoom = newValue;
this.zoom = Math.max(Math.min(this.zoom, this.maxZoomValue), this.minZoomValue);
this.maxIterations = this.getIterationsForZoom(this.zoom);
}
private getIterationsForZoom(zoom: number): number { private getIterationsForZoom(zoom: number): number {
const baseIterations = 100; const baseIterations = 100;
const factor = 200; const factor = 200;