Cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Continuous Color Picker

I'm trying to build a watch face and came up against what I assume is a common problem of allowing users to select colours in settings.

I wanted to allow users to pick any possible HSL colour using the hsl() CSS function, rather than an arbitrarily short list of colours. I figured a nice way to do this would be to have 3 Sliders for Hue, Saturation and Lightness and store each value in a separate settingsKey - which kind of works (more on that later). 

 

The next challenge I came up against was finding a way to show the colour produced by the user's selection; which is difficult since the only component available in Settings for which the API allows programmatically controlling colour is the colour picker (we just "picked" the colour with the sliders).

 

Ideally it would be nice to be able to control the backgroundColor of some other element, like Text, for conveying a user's selection. For the time being I've chosen to use a Color Picker with a single option, which also kind of works except clicking the color picker with one option gets an error:

[6:22:50 PM]TypeError: Invalid attempt to destructure non-iterable instance
[6:22:50 PM]Uncaught TypeError: Invalid attempt to destructure non-iterable instance

The issue I have is that the Sliders are almost completely unresponsive. Trying to drag them on both the simulator and iOS app is like pulling a refridgerator with an oily rope, the sliders just barely move and then get "dropped". I assume it's something to do with rerendering the page when a value changes? 

 

/common/HSLPicker.js

import { toHSLString } from './utils';

export default (props) => {
  const { settingsKey, settings, settingsStorage } = props
  
  console.log(JSON.stringify(settings))
  
  return (
    <Text>
      <Slider 
        label="Hue"
        value={settings[settingsKey+".h"]}        
        onChange={value => settingsStorage.setItem(settingsKey+".h", value)}
        min="0"
        max="360"
      />  
      <Slider 
        label="Saturation"
        value={settings[settingsKey+".s"]}
        onChange={value => settingsStorage.setItem(settingsKey+".s", value)}
        min="0"
        max="100"
      />  
      <Slider 
        label="Lightness"
        value={settings[settingsKey+".l"]}
        onChange={value => settingsStorage.setItem(settingsKey+".l", value)}
        min="0"
        max="100"
      />    
      <ColorSelect        
        colors={[
          {color: toHSLString(settings, settingsKey)}
        ]}
      />
    </Text>
  );
}

/common/utils.js:

export function withSettings (Component, settings, settingsStorage) {
  return (props) => {
    return (<Component settings={settings} settingsStorage={settingsStorage} {...props} />);
  };
}
            
export function toHSLString(settings, settingsKey) {
  if (!settings[settingsKey+".h"] || !settings[settingsKey+".s"] || !settings[settingsKey+".l"]) {
      return 'hsl(0,0%,0%)'
  }
      
  return "hsl("+ 
   settings[settingsKey+".h"] + "," + 
   settings[settingsKey+".s"] + "%," + 
   settings[settingsKey+".l"] + "%" +
   ")";
}

/settings/index.js

import { withSettings } from '../common/utils'
import hslPicker from '../common/HSLPicker'

const SettingsMain = (props) => {
  const HSLPicker = withSettings(hslPicker, props.settings, props.settingsStorage);
  
  return (<Page>
    <Section
      title={<Text bold align="center">Demo Settings</Text>}
    >
      <HSLPicker        
        settingsKey="backgroundColor"
      />
    </Section>
  </Page>)
}

registerSettingsPage(SettingsMain)

Hopefully I'm not missing anything obvious, I guess this may become a feature request.

 

Cheers!

Kev

Best Answer
0 Votes
1 REPLY 1

I wonder if you should allow users to change the sliders, but the color is only applied when a button is pressed, instead of for each value onchange?

Best Answer
0 Votes