Warning, /firebird/firebird-ng/src/app/components/object-clipping/object-clipping.component.ts is written in an unsupported language. File is not indexed.
0001 import {
0002 Component,
0003 OnInit,
0004 OnDestroy,
0005 ViewChild,
0006 TemplateRef,
0007 ElementRef,
0008 ViewContainerRef,
0009 ChangeDetectorRef
0010 } from '@angular/core';
0011 import {MatCheckbox, MatCheckboxChange} from '@angular/material/checkbox';
0012 import { Subscription } from 'rxjs';
0013
0014 import { ThreeService } from '../../services/three.service';
0015 import { LocalStorageService } from '../../services/local-storage.service';
0016 import {MatMenuItem} from "@angular/material/menu";
0017 import {MatSlider, MatSliderThumb} from "@angular/material/slider";
0018
0019 import {MatButton, MatIconButton} from "@angular/material/button";
0020
0021 import {MatDialog, MatDialogClose, MatDialogRef} from "@angular/material/dialog";
0022 import {MatIcon} from "@angular/material/icon";
0023 import {MatTooltip} from "@angular/material/tooltip";
0024 import {FormsModule} from "@angular/forms";
0025
0026
0027
0028 @Component({
0029 selector: 'app-custom-object-clipping',
0030 templateUrl: './object-clipping.component.html',
0031 styleUrls: ['./object-clipping.component.scss'],
0032 imports: [
0033 MatSlider,
0034 MatMenuItem,
0035 MatSliderThumb,
0036 MatCheckbox,
0037 MatButton,
0038 MatIcon,
0039 MatDialogClose,
0040 MatIconButton,
0041 MatTooltip,
0042 FormsModule,
0043
0044 ]
0045 })
0046 export class ObjectClippingComponent implements OnInit, OnDestroy {
0047 /** Local copies that reflect the config property values. */
0048 clippingEnabled = false;
0049 startClippingAngle = 0;
0050 openingClippingAngle = 180;
0051
0052 private subscriptions: Subscription[] = [];
0053
0054 @ViewChild('openBtn', { read: ElementRef }) openBtn!: ElementRef;
0055 @ViewChild('dialogTemplate') dialogTemplate!: TemplateRef<any>;
0056 dialogRef: MatDialogRef<any> | null = null;
0057
0058 constructor(
0059 private threeService: ThreeService,
0060 private config: LocalStorageService,
0061 private dialog: MatDialog,
0062 private viewContainerRef: ViewContainerRef,
0063 private cdr: ChangeDetectorRef
0064 ) {}
0065
0066 ngOnInit(): void {
0067 // 1) Initialize local values from the config
0068 this.clippingEnabled = this.config.clippingEnabled.value;
0069 this.startClippingAngle = this.config.clippingStartAngle.value;
0070 this.openingClippingAngle = this.config.clippingOpeningAngle.value;
0071
0072 // 2) Subscribe to config changes so if another component or code updates them,
0073 // this component sees the updated values automatically:
0074 this.subscriptions.push(
0075 this.config.clippingEnabled.changes$.subscribe((enabled) => {
0076 this.clippingEnabled = enabled;
0077 // Also immediately update ThreeService
0078 this.threeService.enableClipping(enabled);
0079 if (enabled) {
0080 this.threeService.setClippingAngle(
0081 this.config.clippingStartAngle.value,
0082 this.config.clippingOpeningAngle.value
0083 );
0084 }
0085 })
0086 );
0087
0088 this.subscriptions.push(
0089 this.config.clippingStartAngle.changes$.subscribe((value) => {
0090 this.startClippingAngle = value;
0091 if (this.config.clippingEnabled.value) {
0092 this.threeService.setClippingAngle(
0093 value,
0094 this.config.clippingOpeningAngle.value
0095 );
0096 }
0097 })
0098 );
0099
0100 this.subscriptions.push(
0101 this.config.clippingOpeningAngle.changes$.subscribe((value) => {
0102 this.openingClippingAngle = value;
0103 if (this.config.clippingEnabled.value) {
0104 this.threeService.setClippingAngle(
0105 this.config.clippingStartAngle.value,
0106 value
0107 );
0108 }
0109 })
0110 );
0111
0112 // 3) Optionally trigger an initial clipping if was enabled:
0113 if (this.clippingEnabled) {
0114 this.threeService.enableClipping(true);
0115 this.threeService.setClippingAngle(this.startClippingAngle, this.openingClippingAngle);
0116 }
0117 }
0118
0119 ngOnDestroy(): void {
0120 // Unsubscribe from config property streams to avoid memory leaks.
0121 for (const sub of this.subscriptions) {
0122 sub.unsubscribe();
0123 }
0124 }
0125
0126 /**
0127 * User toggles clipping in the UI checkbox.
0128 */
0129 toggleClipping(change: MatCheckboxChange): void {
0130 // Update the config property. This automatically saves to localStorage
0131 // and triggers the subscription above, which updates the ThreeService.
0132 this.config.clippingEnabled.value = change.checked;
0133 }
0134
0135 /**
0136 * User changes the start angle. Use the config property setter to persist and update the scene.
0137 */
0138 changeStartClippingAngle(angle: number): void {
0139 this.config.clippingStartAngle.value = angle;
0140 }
0141
0142 /**
0143 * User changes the opening angle. Use the config property setter to persist and update the scene.
0144 */
0145 changeOpeningClippingAngle(angle: number): void {
0146 this.config.clippingOpeningAngle.value = angle;
0147 }
0148
0149
0150 openDialog(): void {
0151 if (this.dialogRef) {
0152 this.dialogRef.close();
0153 return;
0154 }
0155
0156 const rect = this.openBtn.nativeElement.getBoundingClientRect();
0157 const dialogWidth = 320;
0158
0159 const left = Math.max(rect.right - dialogWidth, 8);
0160 const top = rect.bottom + 12;
0161
0162 this.dialogRef = this.dialog.open(this.dialogTemplate, {
0163 position: {
0164 top: `${top}px`,
0165 left: `${left}px`
0166 },
0167 hasBackdrop: false,
0168 panelClass: 'custom-position-dialog',
0169 autoFocus: false,
0170 viewContainerRef: this.viewContainerRef
0171 });
0172
0173 this.dialogRef.afterClosed().subscribe(() => {
0174 this.dialogRef = null;
0175 });
0176 }
0177
0178
0179 /**
0180 * Updates angle value in real-time as any slider moves
0181 * @param event The slider input event
0182 * @param sliderType Identifier for which slider is being updated ('start' or 'opening')
0183 */
0184 onSliderInput(event: any, sliderType: 'start' | 'opening'): void {
0185 // Extract the value safely from the event
0186 let newValue: number | null = null;
0187
0188 // Try different ways to get the value based on Angular Material version
0189 if (event && event.value !== undefined) {
0190 newValue = event.value;
0191 } else if (event && event.source && event.source.value !== undefined) {
0192 newValue = event.source.value;
0193 } else if (event && event.target && event.target.value !== undefined) {
0194 newValue = Number(event.target.value);
0195 }
0196
0197 // Only update if we got a valid number
0198 if (newValue !== null && !isNaN(newValue)) {
0199 // Update the appropriate property based on which slider was moved
0200 if (sliderType === 'start') {
0201 this.startClippingAngle = newValue;
0202 } else if (sliderType === 'opening') {
0203 this.openingClippingAngle = newValue;
0204 }
0205 }
0206 }
0207
0208
0209 }