spin-wheel
Version:
An easy to use, themeable component for randomising choices and prizes.
241 lines (216 loc) • 6.27 kB
JavaScript
import * as util from './util.js';
import {Defaults} from './constants.js';
export class Item {
constructor(wheel, props = {}) {
// Validate params.
if (!util.isObject(wheel)) throw new Error('wheel must be an instance of Wheel'); // Ideally we would use instanceof, however importing the Wheel class would create a circular ref.
if (!util.isObject(props) && props !== null) throw new Error('props must be an Object or null');
this._wheel = wheel;
// Assign default values.
// This avoids null exceptions when we initalise each property one-by-one in `init()`.
for (const i of Object.keys(Defaults.item)) {
this['_' + i] = Defaults.item[i];
}
if (props) {
this.init(props);
} else {
this.init(Defaults.item);
}
}
/**
* Initialise all properties.
*/
init(props = {}) {
this.backgroundColor = props.backgroundColor;
this.image = props.image;
this.imageOpacity = props.imageOpacity;
this.imageRadius = props.imageRadius;
this.imageRotation = props.imageRotation;
this.imageScale = props.imageScale;
this.label = props.label;
this.labelColor = props.labelColor;
this.value = props.value;
this.weight = props.weight;
}
/**
* The [CSS color](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value) of the item's background.
* When `null`, the color will fall back to `Wheel.itemBackgroundColors`.
* Example: `'#fff'`.
*/
get backgroundColor() {
return this._backgroundColor;
}
set backgroundColor(val) {
if (typeof val === 'string') {
this._backgroundColor = val;
} else {
this._backgroundColor = Defaults.item.backgroundColor;
}
this._wheel.refresh();
}
/**
* The image (HTMLImageElement) to draw on the item.
* Any part of the image that extends outside the item will be clipped.
* The image will be drawn over the top of `Item.backgroundColor`.
*/
get image() {
return this._image;
}
set image(val) {
if (val instanceof HTMLImageElement) {
this._image = val;
} else {
this._image = Defaults.item.image;
}
this._wheel.refresh();
}
/**
* The opacity (as a percent) of `Item.image`.
* Useful if you want to fade the image to make the item's label stand out.
*/
get imageOpacity() {
return this._imageOpacity;
}
set imageOpacity(val) {
if (typeof val === 'number') {
this._imageOpacity = val;
} else {
this._imageOpacity = Defaults.item.imageOpacity;
}
this._wheel.refresh();
}
/**
* The point along the wheel's radius (as a percent, starting from the center) to draw the center of `Item.image`.
*/
get imageRadius() {
return this._imageRadius;
}
set imageRadius(val) {
if (typeof val === 'number') {
this._imageRadius = val;
} else {
this._imageRadius = Defaults.item.imageRadius;
}
this._wheel.refresh();
}
/**
* The rotation (angle in degrees) of `Item.image`.
*/
get imageRotation() {
return this._imageRotation;
}
set imageRotation(val) {
if (typeof val === 'number') {
this._imageRotation = val;
} else {
this._imageRotation = Defaults.item.imageRotation;
}
this._wheel.refresh();
}
/**
* The scale (size as a percent) of `Item.image`.
*/
get imageScale() {
return this._imageScale;
}
set imageScale(val) {
if (typeof val === 'number') {
this._imageScale = val;
} else {
this._imageScale = Defaults.item.imageScale;
}
this._wheel.refresh();
}
/**
* The text that will be drawn on the item.
*/
get label() {
return this._label;
}
set label(val) {
if (typeof val === 'string') {
this._label = val;
} else {
this._label = Defaults.item.label;
}
this._wheel.refresh();
}
/**
* The [CSS color](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value) of the item's label.
* When `null`, the color will fall back to `Wheel.itemLabelColors`.
* Example: `'#000'`.
*/
get labelColor() {
return this._labelColor;
}
set labelColor(val) {
if (typeof val === 'string') {
this._labelColor = val;
} else {
this._labelColor = Defaults.item.labelColor;
}
this._wheel.refresh();
}
/**
* Some value that has meaning to your application.
* For example, a reference to the object representing the item on the wheel, or a database id.
*/
get value() {
return this._value;
}
set value(val) {
if (val !== undefined) {
this._value = val;
} else {
this._value = Defaults.item.value;
}
}
/**
* The proportional size of the item relative to other items on the wheel.
* For example, if you have 2 items where `item[0]` has a weight of `1` and `item[1]` has a weight of `2`,
* then `item[0]` will take up 1/3 of the space on the wheel.
*/
get weight() {
return this._weight;
}
set weight(val) {
if (typeof val === 'number') {
this._weight = val;
} else {
this._weight = Defaults.item.weight;
}
}
/**
* Get the 0-based index of this item.
*/
getIndex() {
const index = this._wheel.items.findIndex(i => i === this);
if (index === -1) throw new Error('Item not found in parent Wheel');
return index;
}
/**
* Get the angle (in degrees) that this item ends at (exclusive), ignoring the current `rotation` of the wheel.
*/
getCenterAngle() {
const angle = this._wheel.getItemAngles()[ this.getIndex() ];
return angle.start + ((angle.end - angle.start) / 2);
}
/**
* Get the angle (in degrees) that this item starts at (inclusive), ignoring the current `rotation` of the wheel.
*/
getStartAngle() {
return this._wheel.getItemAngles()[ this.getIndex() ].start;
}
/**
* Get the angle (in degrees) that this item ends at (inclusive), ignoring the current `rotation` of the wheel.
*/
getEndAngle() {
return this._wheel.getItemAngles()[ this.getIndex() ].end;
}
/**
* Return a random angle (in degrees) between this item's start angle (inclusive) and end angle (inclusive).
*/
getRandomAngle() {
return util.getRandomFloat(this.getStartAngle(), this.getEndAngle());
}
}