fix(algorithms): render sliders only after first browser render
ngx-slider throws during prerender (no layout APIs on the server). Its ngOnDestroy then calls disconnect() on null, so about 1 in 10 prerender builds failed. Gate fractal and pendulum sliders on a signal set by afterNextRender.
This commit is contained in:
1 parent
82228e9141
commit
1cff9e6eb2
4 files changed
+55
-33
No files matched your search
@@ -31,7 +31,11 @@
|
||||
</div>
|
||||
<div 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>
|
||||
@if (sliderReady()) {
|
||||
<ngx-slider [(value)]="sliderValue" [options]="options" (valueChange)="onSliderChange($event)" ></ngx-slider>
|
||||
} @else {
|
||||
<div class="grow h-[60px]"></div>
|
||||
}
|
||||
<mat-icon>zoom_in</mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Component, OnInit, signal} from '@angular/core';
|
||||
import {afterNextRender, Component, OnInit, signal} from '@angular/core';
|
||||
import {Information} from '../information/information';
|
||||
import {MatCard, MatCardContent, MatCardHeader, MatCardTitle} from '@angular/material/card';
|
||||
import {TranslatePipe} from '@ngx-translate/core';
|
||||
@@ -39,6 +39,13 @@ import {clampZoom, initialView, iterationsForZoom, zoomAroundPoint} from './frac
|
||||
styleUrl: './fractal.component.scss',
|
||||
})
|
||||
export class FractalComponent implements OnInit {
|
||||
// ngx-slider throws on the server (no layout APIs), so render it in the browser only
|
||||
readonly sliderReady = signal(false);
|
||||
|
||||
constructor() {
|
||||
afterNextRender(() => this.sliderReady.set(true));
|
||||
}
|
||||
|
||||
algoInformation: AlgorithmInformation = {
|
||||
title: 'FRACTAL.EXPLANATION.TITLE',
|
||||
entries: [
|
||||
|
||||
@@ -5,39 +5,43 @@
|
||||
<mat-card-content>
|
||||
<app-information [algorithmInformation]="algoInformation"/>
|
||||
<div class="flex flex-col mb-4">
|
||||
<div class="grid grid-cols-2 tablet:grid-cols-1 tablet:gap-4 mb-6">
|
||||
<div class="flex items-center gap-4 mr-4">
|
||||
<p class="w-[100px] shrink-0 m-0 text-sm">{{ 'PENDULUM.TRAIL_DECAY_TIME' | translate }}</p>
|
||||
<ngx-slider class="grow" [(value)]="trailDecay" [options]="trailDecayOptions" ></ngx-slider>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 mr-4">
|
||||
<p class="w-[100px] shrink-0 m-0 text-sm">{{ 'PENDULUM.ATTRACTION' | translate }}</p>
|
||||
<ngx-slider class="grow" [(value)]="g" [options]="gravityOptions" ></ngx-slider>
|
||||
</div>
|
||||
@if (sliderReady()) {
|
||||
<div class="grid grid-cols-2 tablet:grid-cols-1 tablet:gap-4 mb-6">
|
||||
<div class="flex items-center gap-4 mr-4">
|
||||
<p class="w-[100px] shrink-0 m-0 text-sm">{{ 'PENDULUM.TRAIL_DECAY_TIME' | translate }}</p>
|
||||
<ngx-slider class="grow" [(value)]="trailDecay" [options]="trailDecayOptions" ></ngx-slider>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 mr-4">
|
||||
<p class="w-[100px] shrink-0 m-0 text-sm">{{ 'PENDULUM.ATTRACTION' | translate }}</p>
|
||||
<ngx-slider class="grow" [(value)]="g" [options]="gravityOptions" ></ngx-slider>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4 mr-4">
|
||||
<p class="w-[100px] shrink-0 m-0 text-sm">{{ 'PENDULUM.L1_LENGTH' | translate }}</p>
|
||||
<ngx-slider class="grow" [(value)]="l1" [options]="lengthOptions" ></ngx-slider>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 mr-4">
|
||||
<p class="w-[100px] shrink-0 m-0 text-sm">{{ 'PENDULUM.L2_LENGTH' | translate }}</p>
|
||||
<ngx-slider class="grow" [(value)]="l2" [options]="lengthOptions" ></ngx-slider>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 mr-4">
|
||||
<p class="w-[100px] shrink-0 m-0 text-sm">{{ 'PENDULUM.L1_LENGTH' | translate }}</p>
|
||||
<ngx-slider class="grow" [(value)]="l1" [options]="lengthOptions" ></ngx-slider>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 mr-4">
|
||||
<p class="w-[100px] shrink-0 m-0 text-sm">{{ 'PENDULUM.L2_LENGTH' | translate }}</p>
|
||||
<ngx-slider class="grow" [(value)]="l2" [options]="lengthOptions" ></ngx-slider>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4 mr-4">
|
||||
<p class="w-[100px] shrink-0 m-0 text-sm">{{ 'PENDULUM.M1_MASS' | translate }}</p>
|
||||
<ngx-slider class="grow" [(value)]="m1" [options]="massOptions" ></ngx-slider>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 mr-4">
|
||||
<p class="w-[100px] shrink-0 m-0 text-sm">{{ 'PENDULUM.M2_MASS' | translate }}</p>
|
||||
<ngx-slider class="grow" [(value)]="m2" [options]="massOptions" ></ngx-slider>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 mr-4">
|
||||
<p class="w-[100px] shrink-0 m-0 text-sm">{{ 'PENDULUM.M1_MASS' | translate }}</p>
|
||||
<ngx-slider class="grow" [(value)]="m1" [options]="massOptions" ></ngx-slider>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 mr-4">
|
||||
<p class="w-[100px] shrink-0 m-0 text-sm">{{ 'PENDULUM.M2_MASS' | translate }}</p>
|
||||
<ngx-slider class="grow" [(value)]="m2" [options]="massOptions" ></ngx-slider>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4 mr-4 col-span-full">
|
||||
<p class="w-[100px] shrink-0 m-0 text-sm">{{ 'PENDULUM.DAMPING' | translate }}</p>
|
||||
<ngx-slider class="grow" [(value)]="damping" [options]="dampingOptions" ></ngx-slider>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 mr-4 col-span-full">
|
||||
<p class="w-[100px] shrink-0 m-0 text-sm">{{ 'PENDULUM.DAMPING' | translate }}</p>
|
||||
<ngx-slider class="grow" [(value)]="damping" [options]="dampingOptions" ></ngx-slider>
|
||||
</div>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="mb-6 h-[200px]"></div>
|
||||
}
|
||||
|
||||
<div class="flex flex-wrap gap-3 mb-4">
|
||||
<button mat-raised-button color="primary" (click)="pushPendulum(true)">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Component, signal} from '@angular/core';
|
||||
import {afterNextRender, Component, signal} from '@angular/core';
|
||||
import {BabylonCanvas, RenderConfig, SceneEventData} from '../../../shared/components/render-canvas/babylon-canvas.component';
|
||||
import {MatCard, MatCardContent, MatCardHeader, MatCardTitle} from '@angular/material/card';
|
||||
|
||||
@@ -33,6 +33,13 @@ import {PendulumCpuStrategy} from './strategies/pendulum-cpu.strategy';
|
||||
})
|
||||
class PendulumComponent {
|
||||
|
||||
// ngx-slider throws on the server (no layout APIs), so render it in the browser only
|
||||
readonly sliderReady = signal(false);
|
||||
|
||||
constructor() {
|
||||
afterNextRender(() => this.sliderReady.set(true));
|
||||
}
|
||||
|
||||
algoInformation: AlgorithmInformation = {
|
||||
title: 'PENDULUM.EXPLANATION.TITLE',
|
||||
entries: [
|
||||
|
||||
Reference in new issue
Block a user