@pencil.js/slider
Version:
Slider user input for Pencil.js package.
137 lines (122 loc) • 4.07 kB
JavaScript
import BaseEvent from "@pencil.js/base-event";
import Circle from "@pencil.js/circle";
import Component from "@pencil.js/component";
import Container from "@pencil.js/container";
import Input from "@pencil.js/input";
import MouseEvent from "@pencil.js/mouse-event";
import Position from "@pencil.js/position";
import Vector from "@pencil.js/vector";
import { constrain } from "@pencil.js/math";
import "@pencil.js/draggable";
const constrainerKey = Symbol("_constrainer");
const moveHandleKey = Symbol("_moveHandle");
/**
* Slider class
* @class
* @extends Container
*/
export default class Slider extends Input {
/**
* Slider constructor
* @param {PositionDefinition} positionDefinition - Top-left corner
* @param {SliderOptions} [options] - Specific options
*/
constructor (positionDefinition, options) {
super(positionDefinition, options);
this.background.width = this.width;
this.background.height = Slider.HEIGHT;
const container = new Container(new Position(Slider.HEIGHT / 2, Slider.HEIGHT / 2));
this.background.add(container);
this.handle = new Circle(new Position(0, 0), (Slider.HEIGHT - 2) / 2, {
fill: this.options.fill,
cursor: Component.cursors.ewResize,
});
container.add(this.handle);
this[constrainerKey] = new Vector(new Position(0, 0), new Position(this.width - Slider.HEIGHT, 0));
this.handle.draggable({
constrain: this[constrainerKey],
});
this.handle.on(MouseEvent.events.drag, () => this.fire(new BaseEvent(Slider.events.change, this)), true);
}
/**
* @inheritDoc
*/
click (position) {
this.handle.position.set(position.x - (Slider.HEIGHT / 2), 0)
.constrain(this[constrainerKey].start, this[constrainerKey].end);
super.click();
}
/**
* Change this slider's size
* @param {Number} newWidth - A new size in pixels
*/
set width (newWidth) {
if (newWidth < Slider.HEIGHT) {
throw new RangeError(`Slider is too small, minimum is ${Slider.HEIGHT}px.`);
}
this.options.width = newWidth;
this.background.width = newWidth;
this[constrainerKey].end = new Position(this.width - Slider.HEIGHT, 0);
this[moveHandleKey](this.value);
}
/**
* Return this slider's size
* @return {Number}
*/
get width () {
return this.options.width;
}
/**
* Returns this current value
* @return {Number}
*/
get value () {
const range = this.options.max - this.options.min;
const relativePosition = this.handle.position.x / (this.width - Slider.HEIGHT);
return this.options.min + (range * relativePosition);
}
/**
* Change this current value
* @param {Number} newValue - A new value to set
*/
set value (newValue) {
this[moveHandleKey](constrain(newValue, this.options.min, this.options.max));
}
/**
* @typedef {Object} SliderOptions
* @extends InputOptions
* @prop {Number} [min=0] - Minimum value when the slider is at lowest
* @prop {Number} [max=10] - Maximum value when the slider is at highest
* @prop {Number} [value=0] - Initial value
* @prop {Number} [width=200] - Size of the slider
*/
/**
* @return {SliderOptions}
*/
static get defaultOptions () {
return {
...super.defaultOptions,
min: 0,
max: 1,
value: 0,
width: 200,
};
}
/**
* Height of sliders
* @return {Number}
* @constant
*/
static get HEIGHT () {
return 20;
}
}
/**
* Move the handle to a specified value
* @param {Number} value - New value to use
* @memberOf Slider#
*/
Slider.prototype[moveHandleKey] = function moveHandle (value) {
const range = this.options.max - this.options.min;
this.handle.position.x = (this.width - Slider.HEIGHT) * ((value - this.options.min) / range);
};