Skip to content

NumberSpinner

NumberSpinner (from scenerystack/sun) pairs a NumberDisplay with increment/decrement ArrowButtons, bound to an integer-valued Property<number> and a TReadOnlyProperty<Range> for the allowed bounds. Use it instead of HSlider when discrete, one-at-a-time steps make more sense than continuous dragging — a "number of particles" or "index of item" control is the typical case.

ts
import { NumberSpinner } from 'scenerystack/sun';
import { NumberProperty, Property } from 'scenerystack/axon';
import { Range } from 'scenerystack/dot';
import { Tandem } from 'scenerystack/tandem';

const countProperty = new NumberProperty( 3, {
  numberType: 'Integer',
  range: new Range( 0, 10 )
} );

const countRangeProperty = new Property( new Range( 0, 10 ) );

const countSpinner = new NumberSpinner(
  countProperty,
  countRangeProperty,
  { tandem: Tandem.REQUIRED }
);

The range argument is a Property<Range> (not a plain Range) so the spinner can respond if the allowed bounds change dynamically — e.g. disabling further increments once a dependent quantity runs out. Both numberProperty.value and the range's min/max must be integers; NumberSpinner asserts on construction if the initial value falls outside the initial range.

Options

OptionDefaultEffect
arrowsPosition'bothRight'Layout of the two arrow buttons: 'leftRight', 'topBottom', 'bothRight', or 'bothBottom'
deltaValue1Amount each press changes the value by (ignored if incrementFunction/decrementFunction are supplied)
incrementFunction / decrementFunctionv => v + deltaValue / v => v - deltaValueCustom step logic, e.g. non-uniform steps
xSpacing / ySpacing5 / 3Spacing between the arrow buttons and the number display
numberDisplayOptions{ cornerRadius: 5, backgroundStroke: 'black' }Options forwarded to the internal NumberDisplay
arrowButtonOptionsOptions forwarded to both ArrowButtons (color, stroke, etc.)
touchAreaXDilation / touchAreaYDilation0 / 0Expand the arrow buttons' touch hit areas

Methods

MethodEffect
setNumberFill( fill: TPaint )Sets the color of the displayed number text

The arrow buttons disable themselves automatically at the range's edges

NumberSpinner links to both the value and the range Property internally and keeps each arrow button's enabled in sync — the increment button disables itself when incrementFunction(value) > range.max, and correspondingly for decrement. You don't need to wire this up yourself, even if the range changes dynamically.