UNPKG

pex-gui

Version:
640 lines (474 loc) 23.5 kB
# pex-gui [![npm version](https://img.shields.io/npm/v/pex-gui)](https://www.npmjs.com/package/pex-gui) [![stability-stable](https://img.shields.io/badge/stability-stable-green.svg)](https://www.npmjs.com/package/pex-gui) [![npm minzipped size](https://img.shields.io/bundlephobia/minzip/pex-gui)](https://bundlephobia.com/package/pex-gui) [![dependencies](https://img.shields.io/librariesio/release/npm/pex-gui)](https://github.com/pex-gl/pex-gui/blob/main/package.json) [![types](https://img.shields.io/npm/types/pex-gui)](https://github.com/microsoft/TypeScript) [![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-fa6673.svg)](https://conventionalcommits.org) [![styled with prettier](https://img.shields.io/badge/styled_with-Prettier-f8bc45.svg?logo=prettier)](https://github.com/prettier/prettier) [![linted with eslint](https://img.shields.io/badge/linted_with-ES_Lint-4B32C3.svg?logo=eslint)](https://github.com/eslint/eslint) [![license](https://img.shields.io/github/license/pex-gl/pex-gui)](https://github.com/pex-gl/pex-gui/blob/main/LICENSE.md) GUI controls for [PEX](https://pex.gl). ![](https://raw.githubusercontent.com/pex-gl/pex-gui/main/screenshot.png) ## Installation ```bash npm install pex-gui ``` ## Usage ```js import createGUI from "pex-gui"; import createContext from "pex-context"; import { loadImage } from "pex-io"; const ctx = createContext({ pixelRatio: 2 }); const gui = createGUI(ctx); const res = await load({ palette: { image: `examples/assets/palette.jpg` }, paletteHsl: { image: `examples/assets/palette-hsl.png` }, plask: { image: `examples/assets/plask.png` }, pex: { image: `examples/assets/pex.png` }, noise: { image: `examples/assets/noise.png` }, posx: { image: `examples/assets/pisa/pisa_posx.jpg` }, negx: { image: `examples/assets/pisa/pisa_negx.jpg` }, posy: { image: `examples/assets/pisa/pisa_posy.jpg` }, negy: { image: `examples/assets/pisa/pisa_negy.jpg` }, posz: { image: `examples/assets/pisa/pisa_posz.jpg` }, negz: { image: `examples/assets/pisa/pisa_negz.jpg` }, }); const images = [res.plask, res.pex, res.noise]; const State = { currentRadioListChoice: 0, radioListChoices: ["Choice 1", "Choice 2", "Choice 3"].map((name, value) => ({ name, value, })), checkboxValue: false, message: "Message", range: 0, position: [2, 0], rgb: [0.92, 0.2, 0.2], rgba: [0.2, 0.92, 0.2, 1.0], palette: Float32Array.of(0.2, 0.2, 0.92, 1.0), paletteHsl: Float32Array.of(0.92, 0.2, 0.92, 1.0), cubeTexture: ctx.textureCube({ data: [res.posx, res.negx, res.posy, res.negy, res.posz, res.negz], width: 64, height: 64, }), currentTexture: 0, textures: images.map((image) => ctx.texture2D({ data: image, width: image.width, height: image.height, flipY: true, wrap: ctx.Wrap.Repeat, encoding: ctx.Encoding.SRGB, mipmap: true, min: ctx.Filter.LinearMipmapLinear, aniso: 16, }) ), }; // Controls gui.addTab("Controls"); gui.addColumn("Inputs"); gui.addLabel("Special Parameters"); gui.addLabel("Multiline\nLabel"); gui.addButton("Button", () => { console.log("Called back"); }); gui.addRadioList( "Radio list", State, "currentRadioListChoice", State.radioListChoices ); gui.addSeparator(); gui.addLabel("Smart Parameters"); gui.addParam("Checkbox", State, "checkboxValue"); gui.addParam("Text message", State, "message", {}, (value) => { console.log(value); }); gui.addParam("Slider", State, "range", { min: -Math.PI / 2, max: Math.PI / 2, }); gui.addParam("Multi Slider", State, "position", { min: 0, max: 10, }); gui.addColumn("Colors"); gui.addParam("Color", State, "rgb", { type: "color", }); gui.addParam("Color alpha", State, "rgba", { type: "color", alpha: true, }); gui.addParam("Palette", State, "palette", { type: "color", palette: res.palette, }); gui.addParam("Palette HSL", State, "paletteHsl", { type: "color", palette: res.paletteHsl, }); gui.addColumn("Textures"); gui.addTexture2D("Single", State.textures[0]); gui.addTexture2DList( "List", State, "currentTexture", State.textures.map((texture, value) => ({ texture, value, })) ); gui.addTextureCube("Cube", State.cubeTexture, { level: 2 }); gui.addColumn("Graphs"); gui.addGraph("Sin", { interval: 500, t: 0, update(item) { item.options.t += 0.01; }, redraw(item) { item.values.push(+Math.sin(item.options.t).toFixed(3)); }, }); gui.addFPSMeeter(); gui.addHeader("Stats"); gui.addStats(); gui.addStats("Object stats", { update(item) { Object.assign(item.stats, { r: State.rgb[0], g: State.rgb[1], b: State.rgb[2], }); }, }); ``` ## API <!-- api-start --> ## Modules <dl> <dt><a href="#module_pex-gui">pex-gui</a></dt> <dd></dd> </dl> ## Classes <dl> <dt><a href="#GUI">GUI</a></dt> <dd><p>GUI controls for PEX.</p> </dd> </dl> ## Typedefs <dl> <dt><a href="#GUIControlOptions">GUIControlOptions</a> : <code>object</code></dt> <dd></dd> <dt><a href="#GUIOptions">GUIOptions</a> : <code>object</code></dt> <dd></dd> <dt><a href="#ctx">ctx</a> : <code>module:pex-context~ctx</code></dt> <dd></dd> </dl> <a name="module_pex-gui"></a> ## pex-gui **Summary**: Export a factory function for creating a GUI instance. <a name="module_pex-gui.default"></a> ### pex-gui.default(ctx, opts) ⇒ [<code>GUI</code>](#GUI) **Kind**: static method of [<code>pex-gui</code>](#module_pex-gui) | Param | Type | | ----- | ----------------------------------------------------------------- | | ctx | [<code>ctx</code>](#ctx) \| <code>CanvasRenderingContext2D</code> | | opts | [<code>GUIOptions</code>](#GUIOptions) | <a name="GUI"></a> ## GUI GUI controls for PEX. **Kind**: global class **Properties** | Name | Type | Default | Description | | --------- | -------------------- | ----------------- | ----------------------------------------------- | | [enabled] | <code>boolean</code> | <code>true</code> | Enable/disable pointer interaction and drawing. | - [GUI](#GUI) - [new GUI(ctx, opts)](#new_GUI_new) - [.addTab(title, contextObject, attributeName, [options], onChange)](#GUI+addTab) ⇒ <code>GUIControl</code> - [.addColumn(title, [width])](#GUI+addColumn) ⇒ <code>GUIControl</code> - [.addHeader(title)](#GUI+addHeader) ⇒ <code>GUIControl</code> - [.addSeparator()](#GUI+addSeparator) ⇒ <code>GUIControl</code> - [.addLabel(title, [options])](#GUI+addLabel) ⇒ <code>GUIControl</code> - [.addParam(title, contextObject, attributeName, [options], onChange)](#GUI+addParam) ⇒ <code>GUIControl</code> - [.addButton(title, onClick)](#GUI+addButton) ⇒ <code>GUIControl</code> - [.addRadioList(title, contextObject, attributeName, items, onChange)](#GUI+addRadioList) ⇒ <code>GUIControl</code> - [.addTexture2DList(title, contextObject, attributeName, items, [itemsPerRow], onChange)](#GUI+addTexture2DList) ⇒ <code>GUIControl</code> - [.addTexture2D(title, texture, options)](#GUI+addTexture2D) ⇒ <code>GUIControl</code> - [.addTextureCube(title, texture, options)](#GUI+addTextureCube) ⇒ <code>GUIControl</code> - [.addGraph(title, options)](#GUI+addGraph) ⇒ <code>GUIControl</code> - [.addFPSMeeter()](#GUI+addFPSMeeter) ⇒ <code>GUIControl</code> - [.addStats(title, [options])](#GUI+addStats) ⇒ <code>GUIControl</code> - [.remove(items)](#GUI+remove) - [.moveAfter(item, targetItem)](#GUI+moveAfter) - [.draw()](#GUI+draw) - [.serialize()](#GUI+serialize) ⇒ <code>object</code> - [.deserialize(data)](#GUI+deserialize) - [.dispose()](#GUI+dispose) <a name="new_GUI_new"></a> ### new GUI(ctx, opts) Creates an instance of GUI. | Param | Type | | ----- | ----------------------------------------------------------------- | | ctx | [<code>ctx</code>](#ctx) \| <code>CanvasRenderingContext2D</code> | | opts | [<code>GUIOptions</code>](#GUIOptions) | <a name="GUI+addTab"></a> ### guI.addTab(title, contextObject, attributeName, [options], onChange) ⇒ <code>GUIControl</code> Add a tab control. **Kind**: instance method of [<code>GUI</code>](#GUI) | Param | Type | Default | | ------------- | ---------------------------------------------------- | --------------- | | title | <code>string</code> | | | contextObject | <code>object</code> | | | attributeName | <code>string</code> | | | [options] | [<code>GUIControlOptions</code>](#GUIControlOptions) | <code>{}</code> | | onChange | <code>function</code> | | <a name="GUI+addColumn"></a> ### guI.addColumn(title, [width]) ⇒ <code>GUIControl</code> Add a column control with a header. **Kind**: instance method of [<code>GUI</code>](#GUI) | Param | Type | Default | | ------- | ------------------- | ----------------------------------- | | title | <code>string</code> | | | [width] | <code>number</code> | <code>this.theme.columnWidth</code> | <a name="GUI+addHeader"></a> ### guI.addHeader(title) ⇒ <code>GUIControl</code> Add a header control. **Kind**: instance method of [<code>GUI</code>](#GUI) | Param | Type | | ----- | ------------------- | | title | <code>string</code> | <a name="GUI+addSeparator"></a> ### guI.addSeparator() ⇒ <code>GUIControl</code> Add some breathing space between controls. **Kind**: instance method of [<code>GUI</code>](#GUI) <a name="GUI+addLabel"></a> ### guI.addLabel(title, [options]) ⇒ <code>GUIControl</code> Add a text label. Can be multiple line. **Kind**: instance method of [<code>GUI</code>](#GUI) | Param | Type | Default | | --------- | ---------------------------------------------------- | --------------- | | title | <code>string</code> | | | [options] | [<code>GUIControlOptions</code>](#GUIControlOptions) | <code>{}</code> | **Example** ```js gui.addLabel("Multiline\nLabel"); ``` <a name="GUI+addParam"></a> ### guI.addParam(title, contextObject, attributeName, [options], onChange) ⇒ <code>GUIControl</code> Add a generic parameter control. **Kind**: instance method of [<code>GUI</code>](#GUI) | Param | Type | Default | | ------------- | ---------------------------------------------------- | --------------- | | title | <code>string</code> | | | contextObject | <code>object</code> | | | attributeName | <code>string</code> | | | [options] | [<code>GUIControlOptions</code>](#GUIControlOptions) | <code>{}</code> | | onChange | <code>function</code> | | **Example** ```js gui.addParam("Checkbox", State, "rotate"); gui.addParam("Text message", State, "text", {}, function (value) { console.log(value); }); gui.addParam("Slider", State, "range", { min: -Math.PI / 2, max: Math.PI / 2, }); gui.addParam("Multi Slider", State, "position", { min: 0, max: 10, }); gui.addParam("Color [RGBA]", State, "color"); gui.addParam("Texture", State, "texture"); gui.addParam("Texture Cube", State, "textureCube"); ``` <a name="GUI+addButton"></a> ### guI.addButton(title, onClick) ⇒ <code>GUIControl</code> Add a clickable button. **Kind**: instance method of [<code>GUI</code>](#GUI) | Param | Type | | ------- | --------------------- | | title | <code>string</code> | | onClick | <code>function</code> | **Example** ```js gui.addButton("Button", () => { console.log("Called back"); }); ``` <a name="GUI+addRadioList"></a> ### guI.addRadioList(title, contextObject, attributeName, items, onChange) ⇒ <code>GUIControl</code> Add a radio list with options. **Kind**: instance method of [<code>GUI</code>](#GUI) | Param | Type | | ------------- | -------------------------------------------------------- | | title | <code>string</code> | | contextObject | <code>object</code> | | attributeName | <code>string</code> | | items | <code>Array.&lt;{name: string, value: number}&gt;</code> | | onChange | <code>function</code> | **Example** ```js gui.addRadioList( "Radio list", State, "currentRadioListChoice", ["Choice 1", "Choice 2", "Choice 3"].map((name, value) => ({ name, value, })), ); ``` <a name="GUI+addTexture2DList"></a> ### guI.addTexture2DList(title, contextObject, attributeName, items, [itemsPerRow], onChange) ⇒ <code>GUIControl</code> Add a texture visualiser and selector for multiple textures (from pex-context) or images. **Kind**: instance method of [<code>GUI</code>](#GUI) | Param | Type | Default | | ------------- | ---------------------------------------------------------------------------------------------------- | -------------- | | title | <code>string</code> | | | contextObject | <code>object</code> | | | attributeName | <code>string</code> | | | items | <code>Array.&lt;{texture: (module:pex-context~texture\|CanvasImageSource), value: number}&gt;</code> | | | [itemsPerRow] | <code>number</code> | <code>4</code> | | onChange | <code>function</code> | | **Example** ```js gui.addTexture2DList("List", State, "currentTexture", textures.map((texture, value) = > ({ texture, value }))); ``` <a name="GUI+addTexture2D"></a> ### guI.addTexture2D(title, texture, options) ⇒ <code>GUIControl</code> Add a texture (from pex-context) or image visualiser. Notes: texture cannot be updated once created. **Kind**: instance method of [<code>GUI</code>](#GUI) | Param | Type | | ------- | ------------------------------------------------------------------------- | | title | <code>string</code> | | texture | <code>module:pex-context~texture</code> \| <code>CanvasImageSource</code> | | options | [<code>GUIControlOptions</code>](#GUIControlOptions) | **Example** ```js gui.addTexture2D("Single", image); ``` <a name="GUI+addTextureCube"></a> ### guI.addTextureCube(title, texture, options) ⇒ <code>GUIControl</code> Add a cube texture visualiser (from pex-context). Notes: texture cannot be updated once created. **Kind**: instance method of [<code>GUI</code>](#GUI) | Param | Type | | ------- | ------------------------------------------- | | title | <code>string</code> | | texture | <code>module:pex-context~textureCube</code> | | options | <code>Object</code> | **Example** ```js gui.addTextureCube("Cube", State.cubeTexture, { level: 2 }); ``` <a name="GUI+addGraph"></a> ### guI.addGraph(title, options) ⇒ <code>GUIControl</code> Add a XY graph visualiser from the control values. **Kind**: instance method of [<code>GUI</code>](#GUI) | Param | Type | | ------- | ---------------------------------------------------- | | title | <code>string</code> | | options | [<code>GUIControlOptions</code>](#GUIControlOptions) | **Example** ```js gui.addGraph("Sin", { interval: 500, t: 0, update(item) { item.options.t += 0.01; }, redraw(item) { item.values.push(+Math.sin(item.options.t).toFixed(3)); }, }); ``` <a name="GUI+addFPSMeeter"></a> ### guI.addFPSMeeter() ⇒ <code>GUIControl</code> Add a FPS counter. Need "gui.draw()" to be called on frame. **Kind**: instance method of [<code>GUI</code>](#GUI) <a name="GUI+addStats"></a> ### guI.addStats(title, [options]) ⇒ <code>GUIControl</code> Add an updatable object stats visualiser. **Kind**: instance method of [<code>GUI</code>](#GUI) | Param | Type | Description | | --------- | ------------------- | ------------------------------------------------------------ | | title | <code>string</code> | | | [options] | <code>object</code> | An object with an update() function to update control.stats. | <a name="GUI+remove"></a> ### guI.remove(items) Remove controls **Kind**: instance method of [<code>GUI</code>](#GUI) | Param | Type | | ----- | ---------------------------------------------------------------- | | items | <code>GUIControl</code> \| <code>Array.&lt;GUIControl&gt;</code> | <a name="GUI+moveAfter"></a> ### guI.moveAfter(item, targetItem) Move a control after another **Kind**: instance method of [<code>GUI</code>](#GUI) | Param | Type | | ---------- | ----------------------- | | item | <code>GUIControl</code> | | targetItem | <code>GUIControl</code> | <a name="GUI+draw"></a> ### guI.draw() Renders the GUI. Should be called at the end of the frame. **Kind**: instance method of [<code>GUI</code>](#GUI) <a name="GUI+serialize"></a> ### guI.serialize() ⇒ <code>object</code> Retrieve a serialized value of the current GUI's state. **Kind**: instance method of [<code>GUI</code>](#GUI) <a name="GUI+deserialize"></a> ### guI.deserialize(data) Deserialize a previously serialized data state GUI's state. **Kind**: instance method of [<code>GUI</code>](#GUI) | Param | Type | | ----- | ------------------- | | data | <code>object</code> | <a name="GUI+dispose"></a> ### guI.dispose() Remove events listeners, empty list of controls and dispose of the gui's resources. **Kind**: instance method of [<code>GUI</code>](#GUI) <a name="GUIControlOptions"></a> ## GUIControlOptions : <code>object</code> **Kind**: global typedef **Properties** | Name | Type | Default | Description | | ------------ | ------------------------------ | ----------------- | ----------------------------------------------------------------------------------- | | [min] | <code>number</code> | <code>0</code> | | | [max] | <code>number</code> | <code>0</code> | | | [type] | <code>&quot;color&quot;</code> | | Interpret an array as color. | | [colorSpace] | <code>string</code> | | Display a color as values of a pex-color color space. | | [alpha] | <code>boolean</code> | | Add a 4th slider for colors. | | [palette] | <code>HTMLImageElement</code> | | Draw a palette image as color picker. | | [flipEnvMap] | <code>boolean</code> | | Should be 1 for dynamic cubemaps and -1 for cubemaps from file with X axis flipped. | | [flipY] | <code>boolean</code> | | Flip texture 2D vertically. | | [level] | <code>number</code> | | Level of detail for cube textures. | | [update] | <code>function</code> | | An update(item, now) function to update labels and stats. | | [redraw] | <code>function</code> | | A redraw(item) function to be called when interval has passed. | | [interval] | <code>number</code> | <code>2000</code> | The interval between redraw(item). | <a name="GUIOptions"></a> ## GUIOptions : <code>object</code> **Kind**: global typedef **Properties** | Name | Type | Default | Description | | ------------ | -------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [pixelRatio] | <code>boolean</code> | <code>window.devicePixelRatio</code> | | | [theme] | <code>boolean</code> | <code>{}</code> | See [theme file](https://github.com/pex-gl/pex-gui/blob/main/theme.js) for all options. | | [scale] | <code>number</code> | <code>1</code> | | | [responsive] | <code>boolean</code> | <code>true</code> | Adapts to canvas dimension. | | [overlay] | <code>boolean</code> | <code>false</code> | Sets canvas CSS pointer-events to "none" and adds a DOM div overlay with children sized to interacitve areas. Allows pointer events to pass through non-interactive areas of the GUI. | <a name="ctx"></a> ## ctx : <code>module:pex-context~ctx</code> **Kind**: global typedef <!-- api-end --> ## License MIT. See [license file](https://github.com/pex-gl/pex-gui/blob/main/LICENSE.md).