Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[picker-mavo] First pass in fixing the known issues #186

Merged
merged 1 commit into from
Jun 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 54 additions & 47 deletions apps/picker-mavo/index.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<!DOCTYPE html>
<html lang="en" mv-storage="local" mv-app="genericPicker" mv-autosave
mv-init='data:application/json,{"spaceId":"lch", "coords": [50, 50, 50], "alpha": 100}'
mv-mode="edit">
<html lang="en">
<head>
<meta charset="UTF-8">
<title>LCH Colour picker</title>
Expand All @@ -13,59 +11,68 @@
<script src="https://get.mavo.io/mavo.js" defer></script>
<link rel="icon" id="favicon">
</head>
<body id="app">
<main style="--color: [css_color]">
<header>
<h1>
<select class="autosize" property id="spaceId">
<option mv-multiple="space" mv-value="getColorSpaces()" value="[id]" mv-group>[name]</option>
</select>
<div>Colour Picker <button onclick="CSS_color_to_LCH()">Import color…</button></div>
</h1>
</header>
<body mv-app="genericPicker" mv-storage="local" mv-autosave
mv-expressions-ignore="mv-init" mv-init='data:application/json,{"spaceId":"lch", "coords": [50, 50, 50], "alpha": 100}'
mv-mode="edit">
<main style="--color: [css_color]">
<header>
<h1>
<select class="autosize" property id="spaceId">
<optgroup mv-list mv-value="getColorSpaces()">
<option mv-list-item="space" value="[id]" mv-group>[name]</option>
</optgroup>
</select>
<div>Colour Picker <button mv-action="CSS_color_to_LCH()">Import color…</button></div>
</h1>
</header>

<div hidden property="color">
<meta property="spaceId" content="[genericPicker.spaceId]">
<meta property="coords" content="[value]">
<meta property="alpha" content="[genericPicker.alpha]">
</div>
<div hidden property="color_srgb" mv-value="color_to(genericPicker.color, 'srgb')">
<meta property="spaceId">
<meta property="coords">
<meta property="alpha">
</div>
<div hidden property="color">
<meta property="spaceId" content="[genericPicker.spaceId]">
<meta property="coords" content="[value]">
<meta property="alpha" content="[genericPicker.alpha / 100]">
</div>

<div class="mv-container" mv-list>
<label mv-list-item="coord_meta" mv-value="getCoordMeta(genericPicker.spaceId)" class="color-slider-label">
[name] ([min]-[max])
<!-- style="--stops: [get(getSliderSteps(spaceId, coords, coord_meta, alpha), $index)]" -->
<input class="color-slider" type="range" property="value" mv-default="[valueNumber]" min="[min]" max="[max]" step="[step]" />
<input type="number" property="valueNumber" mv-default="[value]" style="`--percentage: [ value / (max - min) ]`" min="[min]" max="[max]" step="[step]" />
</label>
</div>
<meta property="color_srgb_obj" content="[color_to(color, 'srgb')]">
<div hidden property="color_srgb">
<meta property="spaceId" content="[genericPicker.spaceId]">
<meta property="coords" content="[color_srgb_obj.coords]">
<meta property="alpha" content="[color_srgb_obj.alpha]">
</div>

<label class="color-slider-label">Alpha (0-100)
<!-- style="--stops: [last(getSliderSteps(spaceId, coords, coord_meta, alpha))]" -->
<input class="color-slider" type="range" property="alpha" mv-default="[alphaNumber]"
/>
<input type="number" class="autosize" property="alphaNumber" mv-default="[alpha]" style="--percentage: [alpha / 100]" max="100" />
<div class="mv-container" mv-list mv-value="getCoordMeta(spaceId)" mv-storage="inherit">
<label mv-list-item="coord_meta" class="color-slider-label">
[name] ([min]–[max])
<input class="color-slider" type="range" property="value" mv-default="[valueNumber]" min="[min]" max="[max]" step="[step]"
style="--stops: [get(getSliderSteps(spaceId, color.coords, coord_meta.$all, alpha), $index)]" />
<input type="number" property="valueNumber" mv-value="[value or get(genericPicker.coords, $index)]" style="--percentage: [ value / (max - min) ]" min="[min]" max="[max]" step="[step]" />
</label>
</div>

<label>CSS Color <span class="decimals autosize">(<span property="decimals" mv-mode="edit" mv-editor-type="number" mv-editor-min="0" mv-editor-max="20">3</span> decimals)</span>
<input class="color-css" value="[color_serialize(color, precision: decimals)]" readonly />
<label class="color-slider-label">Alpha (0–100)
<input class="color-slider" type="range" property="alpha" mv-default="[alphaNumber]"
style="--stops: [last(getSliderSteps(spaceId, color.coords, coord_meta.$all, alpha))]" />
<input type="number" class="autosize" property="alphaNumber" mv-default="[alpha]" style="--percentage: [alpha / 100]" max="100" />
</label>

<label>Displayed color</span>
<input property id="css_color" class="color-css" value="[color_serialize(color, group(precision: decimals, fallback: true))]" readonly />
</label>
<fieldset>
<legend>Output
<span class="decimals autosize">(<span property="decimals" mv-mode="edit" mv-editor-type="number" mv-editor-min="0" mv-editor-max="20">3</span> significant digits)</span>
</legend>
<label>Serialized Color
<input class="color-css" value="[color_serialize(color, precision: decimals)]" readonly />
</label>

<label class="[!if(color_inGamut(color, 'srgb', epsilon: .00005), 'out-of-gamut')]" style="--color: [color_serialize(color_srgb)]">
<abbr>sRGB</abbr> Color
<input class="color-srgb" value="[color_serialize(color_srgb, precision: decimals)]" readonly />
<div class="out-of-gamut-warning">Color is actually [color_serialize(color_srgb, group(precision: decimals, inGamut: false))], which is out of sRGB gamut; auto-corrected to sRGB boundary.</div>
</label>
</main>
<label>Displayed color
<input property id="css_color" class="color-css" value="[color_serialize(color, group(precision: decimals, fallback: true))]" readonly />
</label>

<label class="[if(!color_inGamut(color, 'srgb', epsilon: .00005), 'out-of-gamut')]" style="--color: [color_serialize(color_srgb)]">
<abbr>sRGB</abbr> Color
<input class="color-srgb" value="[color_serialize(color_srgb, precision: decimals)]" readonly />
<div class="out-of-gamut-warning">Color is actually [color_serialize(color_srgb, group(precision: decimals, inGamut: false))], which is out of sRGB gamut; auto-corrected to sRGB boundary.</div>
</label>
</fieldset>
</main>

</body>
</html>
139 changes: 47 additions & 92 deletions apps/picker-mavo/index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,32 @@
import Color from "../../color.js";
import {parse, ColorSpace, to, serialize, inGamut, steps} from "../../src/index-fn.js";
import {ColorSpace, to, serialize, inGamut, steps} from "../../src/index-fn.js";

// Expose Color.js functions as globals so we can easily reference them from Mavo
window.ColorSpace = ColorSpace;
window.color_to = to;
window.color_serialize = serialize;
window.color_inGamut = inGamut;
window.color_to = function (...args) {
// Drop proxies
args = args.map(a => Mavo.clone(a));

return to(...args);
};
window.color_serialize = function (...args) {
// Drop proxies
args = args.map(a => Mavo.clone(a));

return serialize(...args);
};
window.color_inGamut = function (...args) {
// Drop proxies
args = args.map(a => Mavo.clone(a));

return inGamut(...args);
};

window.getColorSpaces = () => ColorSpace.all.map(({id, name}) => ({id, name}));
window.getCoordMeta = (spaceId) => {
// Drop proxy
spaceId = Mavo.clone(spaceId);

let space = ColorSpace.get(spaceId);
return Object.entries(space.coords).map(([id, meta]) => {
let {name, range, refRange} = meta;
Expand All @@ -24,16 +42,28 @@ window.getCoordMeta = (spaceId) => {

return { id, name, isHue, min, max, step };
});
};

window.getColorSpace = function (spaceId) {
// Drop proxy
spaceId = Mavo.clone(spaceId);

return ColorSpace.get(spaceId);
}

window.getSliderSteps = function(spaceId, coords, coord_meta, alpha) {
return "";
// Drop proxies
spaceId = Mavo.clone(spaceId);
coords = Mavo.clone(coords);
coord_meta = Mavo.clone(coord_meta);
alpha = Mavo.clone(alpha);

alpha /= 100;

let ret = [];

for (let i=0; i<this.coord_meta.length; i++) {
let {range, isHue, min, max} = coord_meta[i];
for (let i=0; i<coord_meta.length; i++) {
let {isHue, min, max} = coord_meta[i];

let start = coords.slice();
start[i] = min;
Expand All @@ -56,8 +86,8 @@ window.getSliderSteps = function(spaceId, coords, coord_meta, alpha) {
// Push alpha too
let color1 = {spaceId, coords, alpha: 0};
let color2 = {spaceId, coords, alpha: 1};
let steps = steps(color1, color2, {steps: 10}).map(c => serialize(c, {fallback: true})).join(", ");
ret.push(steps);
let colorSteps = steps(color1, color2, {steps: 10}).map(c => serialize(c, {fallback: true})).join(", ");
ret.push(colorSteps);

return ret;
}
Expand All @@ -77,85 +107,6 @@ document.body.addEventListener("mv-change", evt => {
}
});

let app = {
data() {
return {
alpha: 100,
decimals: 3,
spaceId: "lch",
color_spaces: Color.Space.registry,
coords: [50, 50, 50],
};
},
computed: {
space () {
return Color.Space.get(this.spaceId);
},
coord_meta () {

},
color (...args) {
return new Color(this.spaceId, this.coords, this.alpha / 100);
},
css_color () {
let css_color = this.color.toString({fallback: true});



return css_color;
},
color_srgb () {
return this.color.to('srgb');
},
slider_steps () {
let {spaceId, coords, coord_meta, alpha} = this;
alpha /= 100;

let ret = [];

for (let i=0; i<this.coord_meta.length; i++) {
let {range, isHue, min, max} = coord_meta[i];

let start = coords.slice();
start[i] = min;
let color1 = new Color(spaceId, start, alpha);

let end = coords.slice();
end[i] = max;
let color2 = new Color(spaceId, end, alpha);

let interpolationOptions = {space: spaceId, steps: 10};

if (isHue) {
interpolationOptions.hue = "raw";
}

let steps = Color.steps(color1, color2, interpolationOptions);
ret.push(steps.map(c => c.toString({fallback: true})).join(", "));
}

// Push alpha too
let color1 = new Color(spaceId, coords, 0);
let color2 = new Color(spaceId, coords, 1);
let steps = Color.steps(color1, color2, {steps: 10}).map(c => c.toString({fallback: true})).join(", ");
ret.push(steps);

return ret;
}
},
watch: {
spaceId (newSpaceId, oldSpaceId) {
if (newSpaceId != oldSpaceId) {
let newSpace = Color.Space.get(newSpaceId);
let coords = Color.Space.get(oldSpaceId).to(newSpace, this.coords);
this.coords = coords;

document.title = `${newSpace.name} color picker`;
}
},
}
};

window.CSS_color_to_LCH = function CSS_color_to_LCH(str) {
str = str || prompt("Enter any CSS color");

Expand All @@ -166,11 +117,15 @@ window.CSS_color_to_LCH = function CSS_color_to_LCH(str) {
let app = Mavo.all.genericPicker;

try {
let color = parse(str);
let converted = color_to(color, app.root.children.spaceId.value);
let color = new Color(str);
let converted = color_to(color, spaceId.value);

let coord_meta = [];
for (let coords of converted.coords) {
coord_meta.push({value: coords});
}

app.coords = converted.coords;
app.alpha = converted.alpha * 100;
app.render({coord_meta, coords: converted.coords, alpha: converted.alpha * 100});
}
catch (e) {
alert(e.message);
Expand Down
8 changes: 8 additions & 0 deletions apps/picker-mavo/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,15 @@ main {
box-shadow: .05em .05em .1em rgba(0,0,0,.2), 0 0 0 100vmax var(--color);
}

fieldset {
border: 1px solid hsl(220 10% 80%);
border-radius: .3em;
margin: 0;
margin-top: 1em;
}

label,
legend,
details summary {
display: block;
text-transform: uppercase;
Expand Down