feat: Add smart min/max behavior to custom controls

Improve custom controls example with intelligent button behavior:
- Minus buttons disabled when at minimum (initial state)
- Plus buttons reset to minimum when at maximum
- Prevents going below min values
- Provides intuitive UX with disabled states

Implementation:
- Added computed signals: isZoomAtMin, isBrightnessAtMin, isBrightnessAtMax
- Created handler methods: handleZoomIn/Out, handleBrightnessIn/Out
- Handlers check limits and reset when appropriate
- Template binds [disabled] to computed signals

Benefits:
- Users can't accidentally go below minimum
- Easy reset from maximum with single click
- Clear visual feedback via disabled buttons
- Clean pattern for custom toolbar integration
This commit is contained in:
Claude 2025-11-16 15:09:09 +00:00
parent 757197fe26
commit 3991058265
No known key found for this signature in database
3 changed files with 115 additions and 21 deletions

View file

@ -241,10 +241,10 @@ export class BrightnessControlsComponent {
### Custom Controls with Plus/Minus Buttons ### Custom Controls with Plus/Minus Buttons
Build your own custom UI by disabling default controls and using the public methods: Build your own custom UI by disabling default controls and using the public methods with smart min/max behavior:
```typescript ```typescript
import { Component, viewChild, signal } from '@angular/core'; import { Component, viewChild, signal, computed } from '@angular/core';
import { PinchZoomComponent } from '@brianpooe/ngx-pinch-zoom'; import { PinchZoomComponent } from '@brianpooe/ngx-pinch-zoom';
@Component({ @Component({
@ -265,10 +265,10 @@ import { PinchZoomComponent } from '@brianpooe/ngx-pinch-zoom';
</pinch-zoom> </pinch-zoom>
<div class="custom-controls"> <div class="custom-controls">
<button (click)="zoomOut()">Zoom -</button> <button [disabled]="isZoomAtMin()" (click)="handleZoomOut()">Zoom -</button>
<button (click)="zoomIn()">Zoom +</button> <button (click)="handleZoomIn()">Zoom +</button>
<button (click)="brightnessOut()">Brightness -</button> <button [disabled]="isBrightnessAtMin()" (click)="handleBrightnessOut()">Brightness -</button>
<button (click)="brightnessIn()">Brightness +</button> <button (click)="handleBrightnessIn()">Brightness +</button>
</div> </div>
<p>Zoom: {{ zoomLevel() }} | Brightness: {{ brightnessLevel() }}</p> <p>Zoom: {{ zoomLevel() }} | Brightness: {{ brightnessLevel() }}</p>
@ -280,20 +280,51 @@ export class CustomControlsComponent {
zoomLevel = signal(1); zoomLevel = signal(1);
brightnessLevel = signal(1.0); brightnessLevel = signal(1.0);
zoomIn() { // Min/max constants
this.pinchZoom()?.zoomIn(0.5); private readonly MIN_ZOOM = 1;
private readonly MIN_BRIGHTNESS = 1.0;
private readonly MAX_BRIGHTNESS = 2.0;
// Computed signals for button states
isZoomAtMin = computed(() => this.zoomLevel() <= this.MIN_ZOOM);
isBrightnessAtMin = computed(() => this.brightnessLevel() <= this.MIN_BRIGHTNESS);
// Smart handlers with min/max and reset behavior
handleZoomIn() {
const pinch = this.pinchZoom();
if (!pinch) return;
const maxScale = pinch.maxScale();
if (this.zoomLevel() >= maxScale) {
// At max, reset to min
pinch.destroy();
} else {
pinch.zoomIn(0.5);
}
} }
zoomOut() { handleZoomOut() {
this.pinchZoom()?.zoomOut(0.5); const pinch = this.pinchZoom();
if (!pinch || this.isZoomAtMin()) return;
pinch.zoomOut(0.5);
} }
brightnessIn() { handleBrightnessIn() {
this.pinchZoom()?.brightnessIn(); const pinch = this.pinchZoom();
if (!pinch) return;
if (this.brightnessLevel() >= this.MAX_BRIGHTNESS) {
// At max, reset to normal
pinch.resetBrightness();
} else {
pinch.brightnessIn();
}
} }
brightnessOut() { handleBrightnessOut() {
this.pinchZoom()?.brightnessOut(); const pinch = this.pinchZoom();
if (!pinch || this.isBrightnessAtMin()) return;
pinch.brightnessOut();
} }
onZoomChange(scale: number) { onZoomChange(scale: number) {
@ -306,6 +337,11 @@ export class CustomControlsComponent {
} }
``` ```
**Smart Control Behavior:**
- **Minus buttons**: Disabled when at minimum value (initial state), prevent going below min
- **Plus buttons**: When at maximum value, clicking resets to minimum instead of being disabled
- This pattern provides intuitive UX - users can't accidentally go below min, and can easily reset from max
## Configuration Options ## Configuration Options
| Input | Type | Default | Description | | Input | Type | Default | Description |

View file

@ -371,8 +371,9 @@
<div class="demo"> <div class="demo">
<h2>Custom Zoom & Brightness Controls</h2> <h2>Custom Zoom & Brightness Controls</h2>
<p> <p>
Build your own custom control UI using the component's public methods. This example demonstrates plus/minus buttons for both zoom Build your own custom control UI using the component's public methods. This example demonstrates plus/minus buttons with smart
and brightness, with default controls disabled. Perfect for integrating controls into your own toolbar or UI layout. behavior: minus buttons are disabled when at minimum (initial state), plus buttons reset to minimum when at maximum. Perfect for
integrating controls into your own toolbar or UI layout.
</p> </p>
<p>Zoom State: {{ zoomstate() }} | Brightness State: {{ brightnessstate().toFixed(2) }}</p> <p>Zoom State: {{ zoomstate() }} | Brightness State: {{ brightnessstate().toFixed(2) }}</p>
<pinch-zoom <pinch-zoom
@ -389,10 +390,12 @@
/> />
</pinch-zoom> </pinch-zoom>
<div class="actions"> <div class="actions">
<button class="btn btn-small btn-blue btn-rounded" (click)="customPinch.zoomOut(0.5)">Zoom -</button> <button class="btn btn-small btn-blue btn-rounded" [disabled]="isZoomAtMin()" (click)="handleZoomOut()">Zoom -</button>
<button class="btn btn-small btn-blue btn-rounded" (click)="customPinch.zoomIn(0.5)">Zoom +</button> <button class="btn btn-small btn-blue btn-rounded" (click)="handleZoomIn()">Zoom +</button>
<button class="btn btn-small btn-green btn-rounded" (click)="customPinch.brightnessOut()">Brightness -</button> <button class="btn btn-small btn-green btn-rounded" [disabled]="isBrightnessAtMin()" (click)="handleBrightnessOut()">
<button class="btn btn-small btn-green btn-rounded" (click)="customPinch.brightnessIn()">Brightness +</button> Brightness -
</button>
<button class="btn btn-small btn-green btn-rounded" (click)="handleBrightnessIn()">Brightness +</button>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,4 +1,4 @@
import { Component, signal } from '@angular/core'; import { Component, signal, computed, viewChild } from '@angular/core';
import { PinchZoomComponent } from '@brianpooe/ngx-pinch-zoom'; import { PinchZoomComponent } from '@brianpooe/ngx-pinch-zoom';
/** /**
@ -19,6 +19,19 @@ export class AppComponent {
zoomstate = signal(1); zoomstate = signal(1);
brightnessstate = signal(1.0); brightnessstate = signal(1.0);
// Reference to custom controls pinch-zoom instance
customPinch = viewChild<PinchZoomComponent>('customPinch');
// Custom controls configuration
private readonly MIN_ZOOM = 1;
private readonly MIN_BRIGHTNESS = 1.0;
private readonly MAX_BRIGHTNESS = 2.0;
// Computed signals for button states
isZoomAtMin = computed(() => this.zoomstate() <= this.MIN_ZOOM);
isBrightnessAtMin = computed(() => this.brightnessstate() <= this.MIN_BRIGHTNESS);
isBrightnessAtMax = computed(() => this.brightnessstate() >= this.MAX_BRIGHTNESS);
onZoomChanged(zoom: number): void { onZoomChanged(zoom: number): void {
this.zoomstate.set(zoom); this.zoomstate.set(zoom);
} }
@ -26,4 +39,46 @@ export class AppComponent {
onBrightnessChanged(brightness: number): void { onBrightnessChanged(brightness: number): void {
this.brightnessstate.set(brightness); this.brightnessstate.set(brightness);
} }
// Custom control handlers with min/max and reset behavior
handleZoomIn(): void {
const pinch = this.customPinch();
if (!pinch) return;
const maxScale = pinch.maxScale();
const currentScale = this.zoomstate();
if (currentScale >= maxScale) {
// At max, reset to min
pinch.destroy();
} else {
pinch.zoomIn(0.5);
}
}
handleZoomOut(): void {
const pinch = this.customPinch();
if (!pinch || this.isZoomAtMin()) return;
pinch.zoomOut(0.5);
}
handleBrightnessIn(): void {
const pinch = this.customPinch();
if (!pinch) return;
if (this.isBrightnessAtMax()) {
// At max, reset to normal (1.0)
pinch.resetBrightness();
} else {
pinch.brightnessIn();
}
}
handleBrightnessOut(): void {
const pinch = this.customPinch();
if (!pinch || this.isBrightnessAtMin()) return;
pinch.brightnessOut();
}
} }