diff --git a/Guide.md b/Guide.md index 1076e08..546b0d8 100644 --- a/Guide.md +++ b/Guide.md @@ -150,6 +150,24 @@ gui.addColor( obj, 'colorObject', 255 ); gui.addColor( obj, 'colorArray', 255 ); ``` +### Custom Color Spaces + +lil-gui allows you to work with colors outside of the typical sRGB color space, so long as they provide conversion methods to and from sRGB hex integers. + +```js +class MyColor { + + // convert this color to hex int (0xff00aa) + getHex() { return hexInt; } + + // parse int and convert to this color space + setHex( hexInt ) {} + +} +``` + +If present, lil-gui will use these methods instead of reading or writing the `{ r, g, b }` components directly. + ## Folders You can organize controllers in collapsible groups using `addFolder()`. The method returns a new GUI diff --git a/Migrating.md b/Migrating.md index d38e1c2..b399b07 100644 --- a/Migrating.md +++ b/Migrating.md @@ -51,6 +51,8 @@ params = { color }; lil_gui.addColor( params, 'color' ); ``` +_Note: lil-gui is automatically converting color spaces under the hood since THREE.Color provides getHex/setHex methods._ + The other differences in color handling are fairly minor: - lil-gui always writes to `#rrggbb` format for strings, even those defined as `rgb()` or `#RGB`. diff --git a/examples/custom-color/custom-color.js b/examples/custom-color/custom-color.js new file mode 100644 index 0000000..c149bc9 --- /dev/null +++ b/examples/custom-color/custom-color.js @@ -0,0 +1,36 @@ +import * as THREE from 'https://cdn.jsdelivr.net/npm/three/build/three.module.js'; +import GUI from '../../dist/lil-gui.esm.js'; + +const debugDiv = document.getElementById( 'debug-div' ); + +const scene = new THREE.Scene(); + +const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); +camera.position.z = 2; + +const renderer = new THREE.WebGLRenderer(); +renderer.setSize( window.innerWidth, window.innerHeight ); +document.body.appendChild( renderer.domElement ); + +const geometry = new THREE.BoxGeometry(); +const material = new THREE.MeshBasicMaterial( { color: 0x00aaff } ); +const cube = new THREE.Mesh( geometry, material ); + +scene.add( cube ); +const gui = new GUI(); +const ctrl = gui.addColor( material, 'color' ); + +function animate() { + + requestAnimationFrame( animate ); + + cube.rotation.x += 0.01; + cube.rotation.y += 0.01; + + debugDiv.style.backgroundColor = '#' + ctrl.$text.value; + + renderer.render( scene, camera ); + +} + +animate(); diff --git a/examples/custom-color/index.html b/examples/custom-color/index.html new file mode 100644 index 0000000..0f90d9f --- /dev/null +++ b/examples/custom-color/index.html @@ -0,0 +1,28 @@ + + + + + + + + + +
+ + + diff --git a/homepage/guide-examples.js b/homepage/guide-examples.js index e6e92e7..2474d33 100644 --- a/homepage/guide-examples.js +++ b/homepage/guide-examples.js @@ -122,7 +122,7 @@ example( 12, ( gui, code ) => { } ); -example( 13, gui => { +example( 14, gui => { const params = { scale: 1, @@ -139,7 +139,7 @@ example( 13, gui => { } ); -example( 17, gui => { +example( 18, gui => { const params = { feedback: 0 }; @@ -154,7 +154,7 @@ example( 17, gui => { } ); -example( 18, gui => { +example( 19, gui => { let saved = {}; diff --git a/src/utils/getColorFormat.js b/src/utils/getColorFormat.js index f170576..5fb4c87 100644 --- a/src/utils/getColorFormat.js +++ b/src/utils/getColorFormat.js @@ -43,6 +43,25 @@ const ARRAY = { } }; +// When getHex/setHex methods are available, prefer them over modifying RGB +// components directly. In some software (e.g. three.js and Blender), hex +// triplets are sRGB by convention, like the color picker's input and display, +// while RGB components are Linear sRGB. +const CUSTOM = { + isPrimitive: false, + match: v => Object( v ) === v && v.getHex && v.setHex, + fromHexString( string, target ) { + + target.setHex( INT.fromHexString( string ) ); + + }, + toHexString( target ) { + + return INT.toHexString( target.getHex() ); + + } +}; + const OBJECT = { isPrimitive: false, match: v => Object( v ) === v, @@ -68,7 +87,7 @@ const OBJECT = { } }; -const FORMATS = [ STRING, INT, ARRAY, OBJECT ]; +const FORMATS = [ STRING, INT, ARRAY, CUSTOM, OBJECT ]; export default function( value ) { return FORMATS.find( format => format.match( value ) ); diff --git a/tests/color-parsing.js b/tests/color-parsing.js index 4ed0773..eef56c2 100644 --- a/tests/color-parsing.js +++ b/tests/color-parsing.js @@ -1,6 +1,8 @@ import assert from 'assert'; import GUI from '../dist/lil-gui.esm.min.js'; +import CallTracker from './utils/CallTracker.js'; + export default () => { const gui = new GUI(); @@ -21,6 +23,32 @@ export default () => { assert.strictEqual( gui.addColor( { int }, 'int' ).$input.value, string ); assert.strictEqual( gui.addColor( { string }, 'string' ).$input.value, string ); + // custom getHex/setHex methods + + const getHexTracker = new CallTracker(); + const setHexTracker = new CallTracker(); + + class CustomColorFormat { + _hex = 0x7a26ab; + getHex() { + getHexTracker.handler(); + return this._hex; + } + setHex( hex ) { + setHexTracker.handler(); + this._hex = hex; + } + } + + const custom = new CustomColorFormat(); + const customColorController = gui.addColor( { custom }, 'custom' ); + + assert.strictEqual( customColorController.$input.value, string ); + assert( getHexTracker.numCalls > 0 ); + + customColorController._setValueFromHexString( '#334455' ); + assert.strictEqual( setHexTracker.numCalls, 1 ); + // todo: it doesn't get hit with any edge cases or malformed colors };