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
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
import { Component, viewChild, signal } from '@angular/core';
import { Component, viewChild, signal, computed } from '@angular/core';
import { PinchZoomComponent } from '@brianpooe/ngx-pinch-zoom';
@Component({
@ -265,10 +265,10 @@ import { PinchZoomComponent } from '@brianpooe/ngx-pinch-zoom';
</pinch-zoom>
<div class="custom-controls">
<button (click)="zoomOut()">Zoom -</button>
<button (click)="zoomIn()">Zoom +</button>
<button (click)="brightnessOut()">Brightness -</button>
<button (click)="brightnessIn()">Brightness +</button>
<button [disabled]="isZoomAtMin()" (click)="handleZoomOut()">Zoom -</button>
<button (click)="handleZoomIn()">Zoom +</button>
<button [disabled]="isBrightnessAtMin()" (click)="handleBrightnessOut()">Brightness -</button>
<button (click)="handleBrightnessIn()">Brightness +</button>
</div>
<p>Zoom: {{ zoomLevel() }} | Brightness: {{ brightnessLevel() }}</p>
@ -280,20 +280,51 @@ export class CustomControlsComponent {
zoomLevel = signal(1);
brightnessLevel = signal(1.0);
zoomIn() {
this.pinchZoom()?.zoomIn(0.5);
// Min/max constants
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() {
this.pinchZoom()?.zoomOut(0.5);
handleZoomOut() {
const pinch = this.pinchZoom();
if (!pinch || this.isZoomAtMin()) return;
pinch.zoomOut(0.5);
}
brightnessIn() {
this.pinchZoom()?.brightnessIn();
handleBrightnessIn() {
const pinch = this.pinchZoom();
if (!pinch) return;
if (this.brightnessLevel() >= this.MAX_BRIGHTNESS) {
// At max, reset to normal
pinch.resetBrightness();
} else {
pinch.brightnessIn();
}
}
brightnessOut() {
this.pinchZoom()?.brightnessOut();
handleBrightnessOut() {
const pinch = this.pinchZoom();
if (!pinch || this.isBrightnessAtMin()) return;
pinch.brightnessOut();
}
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
| Input | Type | Default | Description |

View file

@ -371,8 +371,9 @@
<div class="demo">
<h2>Custom Zoom & Brightness Controls</h2>
<p>
Build your own custom control UI using the component's public methods. This example demonstrates plus/minus buttons for both zoom
and brightness, with default controls disabled. Perfect for integrating controls into your own toolbar or UI layout.
Build your own custom control UI using the component's public methods. This example demonstrates plus/minus buttons with smart
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>Zoom State: {{ zoomstate() }} | Brightness State: {{ brightnessstate().toFixed(2) }}</p>
<pinch-zoom
@ -389,10 +390,12 @@
/>
</pinch-zoom>
<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" (click)="customPinch.zoomIn(0.5)">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" (click)="customPinch.brightnessIn()">Brightness +</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)="handleZoomIn()">Zoom +</button>
<button class="btn btn-small btn-green btn-rounded" [disabled]="isBrightnessAtMin()" (click)="handleBrightnessOut()">
Brightness -
</button>
<button class="btn btn-small btn-green btn-rounded" (click)="handleBrightnessIn()">Brightness +</button>
</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';
/**
@ -19,6 +19,19 @@ export class AppComponent {
zoomstate = signal(1);
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 {
this.zoomstate.set(zoom);
}
@ -26,4 +39,46 @@ export class AppComponent {
onBrightnessChanged(brightness: number): void {
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();
}
}