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:
parent
757197fe26
commit
3991058265
3 changed files with 115 additions and 21 deletions
64
README.md
64
README.md
|
|
@ -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 |
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue