primeng
Version:
PrimeNG is a premium UI library for Angular featuring a rich set of 90+ components, a theme designer, various theme alternatives such as Material, Bootstrap, Tailwind, premium templates and professional support. In addition, it integrates with PrimeBlock,
468 lines (463 loc) • 23 kB
JavaScript
import * as i0 from '@angular/core';
import { Injectable, InjectionToken, forwardRef, inject, input, numberAttribute, booleanAttribute, output, signal, computed, ViewEncapsulation, ChangeDetectionStrategy, Component, NgModule } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { $dt } from '@primeuix/styled';
import { SharedModule } from 'primeng/api';
import { PARENT_INSTANCE } from 'primeng/basecomponent';
import { BaseEditableHolder } from 'primeng/baseeditableholder';
import * as i1 from 'primeng/bind';
import { Bind, BindModule } from 'primeng/bind';
import { style } from '@primeuix/styles/knob';
import { BaseStyle } from 'primeng/base';
const classes = {
root: ({ instance }) => ['p-knob p-component', { 'p-disabled': instance.$disabled() }],
range: 'p-knob-range',
value: 'p-knob-value',
text: 'p-knob-text'
};
class KnobStyle extends BaseStyle {
name = 'knob';
style = style;
classes = classes;
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: KnobStyle, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: KnobStyle });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: KnobStyle, decorators: [{
type: Injectable
}] });
/**
*
* Knob is a form component to define number inputs with a dial.
*
* [Live Demo](https://www.primeng.org/knob/)
*
* @module knobstyle
*
*/
var KnobClasses;
(function (KnobClasses) {
/**
* Class name of the root element
*/
KnobClasses["root"] = "p-knob";
/**
* Class name of the range element
*/
KnobClasses["range"] = "p-knob-range";
/**
* Class name of the value element
*/
KnobClasses["value"] = "p-knob-value";
/**
* Class name of the text element
*/
KnobClasses["text"] = "p-knob-text";
})(KnobClasses || (KnobClasses = {}));
const KNOB_INSTANCE = new InjectionToken('KNOB_INSTANCE');
const KNOB_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => Knob),
multi: true
};
/**
* Knob is a form component to define number inputs with a dial.
* @group Components
*/
class Knob extends BaseEditableHolder {
componentName = 'Knob';
$pcKnob = inject(KNOB_INSTANCE, { optional: true, skipSelf: true }) ?? undefined;
bindDirectiveInstance = inject(Bind, { self: true });
onAfterViewChecked() {
this.bindDirectiveInstance.setAttrs(this.ptms(['host', 'root']));
}
/**
* Defines a string that labels the input for accessibility.
* @group Props
*/
ariaLabel = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
/**
* Specifies one or more IDs in the DOM that labels the input field.
* @group Props
*/
ariaLabelledBy = input(/* @ts-ignore */
...(ngDevMode ? [undefined, { debugName: "ariaLabelledBy" }] : /* istanbul ignore next */ []));
/**
* Index of the element in tabbing order.
* @group Props
*/
tabindex = input(0, { ...(ngDevMode ? { debugName: "tabindex" } : /* istanbul ignore next */ {}), transform: numberAttribute });
/**
* Background of the value.
* @group Props
*/
valueColor = input($dt('knob.value.background').variable, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "valueColor" }] : /* istanbul ignore next */ []));
/**
* Background color of the range.
* @group Props
*/
rangeColor = input($dt('knob.range.background').variable, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "rangeColor" }] : /* istanbul ignore next */ []));
/**
* Color of the value text.
* @group Props
*/
textColor = input($dt('knob.text.color').variable, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "textColor" }] : /* istanbul ignore next */ []));
/**
* Template string of the value.
* @group Props
*/
valueTemplate = input('{value}', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "valueTemplate" }] : /* istanbul ignore next */ []));
/**
* Size of the component in pixels.
* @group Props
*/
size = input(100, { ...(ngDevMode ? { debugName: "size" } : /* istanbul ignore next */ {}), transform: numberAttribute });
/**
* Mininum boundary value.
* @group Props
*/
min = input(0, { ...(ngDevMode ? { debugName: "min" } : /* istanbul ignore next */ {}), transform: numberAttribute });
/**
* Maximum boundary value.
* @group Props
*/
max = input(100, { ...(ngDevMode ? { debugName: "max" } : /* istanbul ignore next */ {}), transform: numberAttribute });
/**
* Step factor to increment/decrement the value.
* @group Props
*/
step = input(1, { ...(ngDevMode ? { debugName: "step" } : /* istanbul ignore next */ {}), transform: numberAttribute });
/**
* Width of the knob stroke.
* @group Props
*/
strokeWidth = input(14, { ...(ngDevMode ? { debugName: "strokeWidth" } : /* istanbul ignore next */ {}), transform: numberAttribute });
/**
* Whether the show the value inside the knob.
* @group Props
*/
showValue = input(true, { ...(ngDevMode ? { debugName: "showValue" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
/**
* When present, it specifies that the component value cannot be edited.
* @group Props
*/
readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
/**
* Callback to invoke on value change.
* @param {number} value - New value.
* @group Emits
*/
onChange = output();
radius = 40;
midX = 50;
midY = 50;
minRadians = (4 * Math.PI) / 3;
maxRadians = -Math.PI / 3;
value = signal(0, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
windowMouseMoveListener;
windowMouseUpListener;
windowTouchMoveListener;
windowTouchEndListener;
_componentStyle = inject(KnobStyle);
attrTabindex = computed(() => (this.readonly() || this.$disabled() ? -1 : this.tabindex()), /* @ts-ignore */
...(ngDevMode ? [{ debugName: "attrTabindex" }] : /* istanbul ignore next */ []));
attrRequired = computed(() => (this.required() ? '' : undefined), /* @ts-ignore */
...(ngDevMode ? [{ debugName: "attrRequired" }] : /* istanbul ignore next */ []));
svgSize = computed(() => this.size() + 'px', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "svgSize" }] : /* istanbul ignore next */ []));
_value = computed(() => (this.value() != null ? this.value() : this.min()), /* @ts-ignore */
...(ngDevMode ? [{ debugName: "_value" }] : /* istanbul ignore next */ []));
mapRange(x, inMin, inMax, outMin, outMax) {
return ((x - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin;
}
onClick(event) {
if (!this.$disabled() && !this.readonly()) {
this.updateValue(event.offsetX, event.offsetY);
}
}
updateValue(offsetX, offsetY) {
let dx = offsetX - this.size() / 2;
let dy = this.size() / 2 - offsetY;
let angle = Math.atan2(dy, dx);
let start = -Math.PI / 2 - Math.PI / 6;
this.updateModel(angle, start);
}
updateModel(angle, start) {
let mappedValue;
if (angle > this.maxRadians)
mappedValue = this.mapRange(angle, this.minRadians, this.maxRadians, this.min(), this.max());
else if (angle < start)
mappedValue = this.mapRange(angle + 2 * Math.PI, this.minRadians, this.maxRadians, this.min(), this.max());
else
return;
let newValue = Math.round((mappedValue - this.min()) / this.step()) * this.step() + this.min();
this.value.set(newValue);
this.writeModelValue(this.value());
this.onModelChange(this.value());
this.onChange.emit(this.value());
}
onMouseDown(event) {
if (!this.$disabled() && !this.readonly()) {
const window = this.document.defaultView || 'window';
this.windowMouseMoveListener = this.renderer.listen(window, 'mousemove', this.onMouseMove.bind(this));
this.windowMouseUpListener = this.renderer.listen(window, 'mouseup', this.onMouseUp.bind(this));
event.preventDefault();
}
}
onMouseUp(event) {
if (!this.$disabled() && !this.readonly()) {
if (this.windowMouseMoveListener) {
this.windowMouseMoveListener();
this.windowMouseUpListener = null;
}
if (this.windowMouseUpListener) {
this.windowMouseUpListener();
this.windowMouseMoveListener = null;
}
event.preventDefault();
}
}
onTouchStart(event) {
if (!this.$disabled() && !this.readonly()) {
const window = this.document.defaultView || 'window';
this.windowTouchMoveListener = this.renderer.listen(window, 'touchmove', this.onTouchMove.bind(this));
this.windowTouchEndListener = this.renderer.listen(window, 'touchend', this.onTouchEnd.bind(this));
event.preventDefault();
}
}
onTouchEnd(event) {
if (!this.$disabled() && !this.readonly()) {
if (this.windowTouchMoveListener) {
this.windowTouchMoveListener();
}
if (this.windowTouchEndListener) {
this.windowTouchEndListener();
}
this.windowTouchMoveListener = null;
this.windowTouchEndListener = null;
event.preventDefault();
}
}
onMouseMove(event) {
if (!this.$disabled() && !this.readonly()) {
this.updateValue(event.offsetX, event.offsetY);
event.preventDefault();
}
}
onTouchMove(event) {
if (!this.$disabled() && !this.readonly() && event instanceof TouchEvent && event.touches.length === 1) {
const rect = this.el.nativeElement.children[0].getBoundingClientRect();
const touch = event.targetTouches.item(0);
if (touch) {
const offsetX = touch.clientX - rect.left;
const offsetY = touch.clientY - rect.top;
this.updateValue(offsetX, offsetY);
}
}
}
updateModelValue(newValue) {
if (newValue > this.max())
this.value.set(this.max());
else if (newValue < this.min())
this.value.set(this.min());
else
this.value.set(newValue);
this.writeModelValue(this.value());
this.onModelChange(this.value());
this.onChange.emit(this.value());
}
onKeyDown(event) {
if (!this.$disabled() && !this.readonly()) {
switch (event.code) {
case 'ArrowRight':
case 'ArrowUp': {
event.preventDefault();
this.updateModelValue(this._value() + 1);
break;
}
case 'ArrowLeft':
case 'ArrowDown': {
event.preventDefault();
this.updateModelValue(this._value() - 1);
break;
}
case 'Home': {
event.preventDefault();
this.updateModelValue(this.min());
break;
}
case 'End': {
event.preventDefault();
this.updateModelValue(this.max());
break;
}
case 'PageUp': {
event.preventDefault();
this.updateModelValue(this._value() + 10);
break;
}
case 'PageDown': {
event.preventDefault();
this.updateModelValue(this._value() - 10);
break;
}
}
}
}
rangePath() {
return `M ${this.minX()} ${this.minY()} A ${this.radius} ${this.radius} 0 1 1 ${this.maxX()} ${this.maxY()}`;
}
valuePath() {
return `M ${this.zeroX()} ${this.zeroY()} A ${this.radius} ${this.radius} 0 ${this.largeArc()} ${this.sweep()} ${this.valueX()} ${this.valueY()}`;
}
zeroRadians() {
if (this.min() > 0 && this.max() > 0)
return this.mapRange(this.min(), this.min(), this.max(), this.minRadians, this.maxRadians);
else
return this.mapRange(0, this.min(), this.max(), this.minRadians, this.maxRadians);
}
valueRadians() {
return this.mapRange(this._value(), this.min(), this.max(), this.minRadians, this.maxRadians);
}
minX() {
return this.midX + Math.cos(this.minRadians) * this.radius;
}
minY() {
return this.midY - Math.sin(this.minRadians) * this.radius;
}
maxX() {
return this.midX + Math.cos(this.maxRadians) * this.radius;
}
maxY() {
return this.midY - Math.sin(this.maxRadians) * this.radius;
}
zeroX() {
return this.midX + Math.cos(this.zeroRadians()) * this.radius;
}
zeroY() {
return this.midY - Math.sin(this.zeroRadians()) * this.radius;
}
valueX() {
return this.midX + Math.cos(this.valueRadians()) * this.radius;
}
valueY() {
return this.midY - Math.sin(this.valueRadians()) * this.radius;
}
largeArc() {
return Math.abs(this.zeroRadians() - this.valueRadians()) < Math.PI ? 0 : 1;
}
sweep() {
return this.valueRadians() > this.zeroRadians() ? 0 : 1;
}
valueToDisplay() {
return this.valueTemplate().replace('{value}', this._value().toString());
}
/**
* @override
*
* @see {@link BaseEditableHolder.writeControlValue}
* Writes the value to the control.
*/
writeControlValue(value, setModelValue) {
this.value.set(value);
setModelValue(this.value());
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: Knob, deps: null, target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.6", type: Knob, isStandalone: true, selector: "p-knob", inputs: { ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledBy: { classPropertyName: "ariaLabelledBy", publicName: "ariaLabelledBy", isSignal: true, isRequired: false, transformFunction: null }, tabindex: { classPropertyName: "tabindex", publicName: "tabindex", isSignal: true, isRequired: false, transformFunction: null }, valueColor: { classPropertyName: "valueColor", publicName: "valueColor", isSignal: true, isRequired: false, transformFunction: null }, rangeColor: { classPropertyName: "rangeColor", publicName: "rangeColor", isSignal: true, isRequired: false, transformFunction: null }, textColor: { classPropertyName: "textColor", publicName: "textColor", isSignal: true, isRequired: false, transformFunction: null }, valueTemplate: { classPropertyName: "valueTemplate", publicName: "valueTemplate", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, strokeWidth: { classPropertyName: "strokeWidth", publicName: "strokeWidth", isSignal: true, isRequired: false, transformFunction: null }, showValue: { classPropertyName: "showValue", publicName: "showValue", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onChange: "onChange" }, host: { properties: { "class": "cx('root')" } }, providers: [KNOB_VALUE_ACCESSOR, KnobStyle, { provide: KNOB_INSTANCE, useExisting: Knob }, { provide: PARENT_INSTANCE, useExisting: Knob }], usesInheritance: true, hostDirectives: [{ directive: i1.Bind }], ngImport: i0, template: `
<svg
viewBox="0 0 100 100"
role="slider"
[style.width]="svgSize()"
[style.height]="svgSize()"
(click)="onClick($event)"
(keydown)="onKeyDown($event)"
(mousedown)="onMouseDown($event)"
(mouseup)="onMouseUp($event)"
(touchstart)="onTouchStart($event)"
(touchend)="onTouchEnd($event)"
[attr.aria-valuemin]="min()"
[attr.aria-valuemax]="max()"
[attr.required]="attrRequired()"
[attr.aria-valuenow]="_value()"
[attr.aria-labelledby]="ariaLabelledBy()"
[attr.aria-label]="ariaLabel()"
[attr.tabindex]="attrTabindex()"
[pBind]="ptm('svg')"
>
<path [attr.d]="rangePath()" [attr.stroke-width]="strokeWidth()" [attr.stroke]="rangeColor()" [class]="cx('range')" [pBind]="ptm('range')"></path>
<path [attr.d]="valuePath()" [attr.stroke-width]="strokeWidth()" [attr.stroke]="valueColor()" [class]="cx('value')" [pBind]="ptm('value')"></path>
(showValue()) {
<text [attr.x]="50" [attr.y]="57" text-anchor="middle" [attr.fill]="textColor()" [class]="cx('text')" [attr.name]="name()" [pBind]="ptm('text')">
{{ valueToDisplay() }}
</text>
}
</svg>
`, isInline: true, dependencies: [{ kind: "ngmodule", type: SharedModule }, { kind: "ngmodule", type: BindModule }, { kind: "directive", type: i1.Bind, selector: "[pBind]", inputs: ["pBind"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: Knob, decorators: [{
type: Component,
args: [{
selector: 'p-knob',
standalone: true,
imports: [SharedModule, BindModule],
template: `
<svg
viewBox="0 0 100 100"
role="slider"
[style.width]="svgSize()"
[style.height]="svgSize()"
(click)="onClick($event)"
(keydown)="onKeyDown($event)"
(mousedown)="onMouseDown($event)"
(mouseup)="onMouseUp($event)"
(touchstart)="onTouchStart($event)"
(touchend)="onTouchEnd($event)"
[attr.aria-valuemin]="min()"
[attr.aria-valuemax]="max()"
[attr.required]="attrRequired()"
[attr.aria-valuenow]="_value()"
[attr.aria-labelledby]="ariaLabelledBy()"
[attr.aria-label]="ariaLabel()"
[attr.tabindex]="attrTabindex()"
[pBind]="ptm('svg')"
>
<path [attr.d]="rangePath()" [attr.stroke-width]="strokeWidth()" [attr.stroke]="rangeColor()" [class]="cx('range')" [pBind]="ptm('range')"></path>
<path [attr.d]="valuePath()" [attr.stroke-width]="strokeWidth()" [attr.stroke]="valueColor()" [class]="cx('value')" [pBind]="ptm('value')"></path>
(showValue()) {
<text [attr.x]="50" [attr.y]="57" text-anchor="middle" [attr.fill]="textColor()" [class]="cx('text')" [attr.name]="name()" [pBind]="ptm('text')">
{{ valueToDisplay() }}
</text>
}
</svg>
`,
providers: [KNOB_VALUE_ACCESSOR, KnobStyle, { provide: KNOB_INSTANCE, useExisting: Knob }, { provide: PARENT_INSTANCE, useExisting: Knob }],
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
host: {
'[class]': "cx('root')"
},
hostDirectives: [Bind]
}]
}], propDecorators: { ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], ariaLabelledBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabelledBy", required: false }] }], tabindex: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabindex", required: false }] }], valueColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueColor", required: false }] }], rangeColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "rangeColor", required: false }] }], textColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "textColor", required: false }] }], valueTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueTemplate", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], strokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "strokeWidth", required: false }] }], showValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "showValue", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], onChange: [{ type: i0.Output, args: ["onChange"] }] } });
class KnobModule {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: KnobModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.6", ngImport: i0, type: KnobModule, imports: [Knob, SharedModule], exports: [Knob, SharedModule] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: KnobModule, imports: [Knob, SharedModule, SharedModule] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: KnobModule, decorators: [{
type: NgModule,
args: [{
imports: [Knob, SharedModule],
exports: [Knob, SharedModule]
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { KNOB_VALUE_ACCESSOR, Knob, KnobClasses, KnobModule, KnobStyle };
//# sourceMappingURL=primeng-knob.mjs.map