Skip to content

Commit

Permalink
Refactor to improve a number of bugs with ranges
Browse files Browse the repository at this point in the history
  • Loading branch information
LeaVerou committed May 24, 2024
1 parent 0f70067 commit 669d985
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 57 deletions.
115 changes: 68 additions & 47 deletions src/Format.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,53 +34,32 @@ export default class Format {

let spaceCoords = Object.values(space.coords);

if (this.coords) {
// Format has a coord specification
this.coords = format.coords.map(coordGrammar => {
return coordGrammar.split("|").map(type => {
return Type.get(type);
});
});
}
else {
// Generate coord grammar from color space metadata
if (!this.coords) {
this.coords = spaceCoords.map(coordMeta => {
let {range, refRange} = coordMeta;
let ret = [
{type: "<number>", range},
{type: "<percentage>", range: range ?? refRange ?? [0, 1]},
];
let ret = ["<number>", "<percentage>"];

if (coordMeta.type === "angle") {
ret.push("<angle>");
}

return ret.map(Type.get);
});
return ret;
})
}

this.coordFormats = spaceCoords.map((coordMeta, i) => {
// Preferred format for each coord is the first one
let outputType = this.coords[i][0];

let fromRange = coordMeta.range || coordMeta.refRange;
this.coords = this.coords.map((types, i) => {
let coordMeta = spaceCoords[i];

let {toRange, suffix} = outputByType[outputType.type] || {toRange: outputType.range, suffix: ""};
if (typeof types === "string") {
types = types.trim().split(/\s*\|\s*/);
}

return {fromRange, toRange, suffix};
return types.map(type => Type.get(type, coordMeta));
});

}

serializeCoords (coords, precision) {
return coords.map((c, i) => {
let {fromRange, toRange, suffix} = this.coordFormats[i];

c = mapRange(fromRange, toRange, c);
c = serializeNumber(c, {precision, unit: suffix});

return c;
});
serializeCoords (coords, precision, types) {
types = coords.map((_, i) => Type.get(types?.[i] ?? this.coords[i][0]));
return coords.map((c, i) => types[i].serialize(c, precision));
}

/**
Expand All @@ -95,7 +74,7 @@ export default class Format {
return Object.entries(this.space.coords).map(([id, coordMeta], i) => {
let arg = coords[i];

if (isNone(arg)) {
if (isNone(arg) || isNaN(arg)) {
// Nothing to do here
return arg;
}
Expand All @@ -112,12 +91,7 @@ export default class Format {
throw new TypeError(`${ providedType ?? arg?.raw ?? arg } not allowed for ${coordName} in ${this.name}()`);
}

let fromRange = type.range;
let toRange = coordMeta.range || coordMeta.refRange;

if (fromRange && toRange) {
return mapRange(fromRange, toRange, arg);
}
arg = type.resolve(arg);

return arg;
});
Expand All @@ -137,7 +111,15 @@ export default class Format {
}

class Type {
constructor (type) {
constructor (type, coordMeta) {
if (typeof type === "object") {
this.coordMeta = type;
}

if (coordMeta) {
this.coordRange = coordMeta.range ?? coordMeta.refRange;
}

if (typeof type === "string") {
let params = type.trim().match(/^(?<type><[a-z]+>)(\[(?<min>-?[.\d]+),\s*(?<max>-?[.\d]+)\])?$/);

Expand All @@ -151,21 +133,60 @@ class Type {
if (min || max) {
this.range = [+min, +max];
}
else if (this.type === "<percentage>") {
}

if (!this.range) {
if (this.type === "<percentage>") {
this.range = [0, 1];
}
else if (this.type === "<angle>") {
this.range = [0, 360];
}
}
}

get toRange () {
if (this.type === "<percentage>") {
return [0, 100];
}
else if (this.type === "<angle>") {
return [0, 360];
}

return null;
}

get unit () {
if (this.type === "<percentage>") {
return "%";
}
else {
Object.assign(this, type);
else if (this.type === "<angle>") {
return "deg";
}

return "";
}

resolve (arg) {
let fromRange = this.range;
let toRange = this.coordRange;

return mapRange(fromRange, toRange, arg);
}

serialize (number, precision) {
let {toRange, unit} = this;
number = mapRange(this.coordRange, toRange, number);
number = serializeNumber(number, {unit, precision});

return number;
}

static get (type) {
static get (type, ...args) {
if (type instanceof Type) {
return type;
}

return new Type(type);
return new Type(type, ...args);
}
}
2 changes: 1 addition & 1 deletion src/parse.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { mapRange, isNone, clamp } from "./util.js";
import { isNone, clamp } from "./util.js";
import hooks from "./hooks.js";
import ColorSpace from "./space.js";
import defaults from "./defaults.js";
Expand Down
4 changes: 3 additions & 1 deletion src/serialize.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export default function serialize (color, {
precision = defaults.precision,
format = "default",
inGamut = true,
coordTypes,
alphaType,
...customOptions
} = {}) {
let ret;
Expand Down Expand Up @@ -54,7 +56,7 @@ export default function serialize (color, {
// Functional syntax
let name = format.name || "color";

let args = format.serializeCoords(coords, precision);
let args = format.serializeCoords(coords, precision, coordTypes);

if (name === "color") {
// If output is a color() function, add colorspace id as first argument
Expand Down
27 changes: 19 additions & 8 deletions src/space.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,17 +137,22 @@ export default class ColorSpace {
}

getFormat (format) {
let ret;
if (!(typeof format === "object")) {
let name = format === "default" ? Object.keys(this.formats)[0] : format;
format = this.formats[name];
}

if (typeof format === "object") {
ret = format;
if (!format) {
return null;
}
else {
let name = format === "default" ? Object.keys(this.formats)[0] : format;
ret = this.formats[name];

let ret = Format.get(format, this);

if (ret !== format && format.name in this.formats) {
this.formats[format.name] = ret;
}

return ret ? Format.get(ret, this) : null;
return ret;
}

/**
Expand Down Expand Up @@ -328,7 +333,13 @@ export default class ColorSpace {
}

if (matches) {
return Format.get(format, space);
let ret = Format.get(format, space);

if (ret !== format) {
space.formats[format.name] = ret;
}

return ret;
}
}
}
Expand Down

0 comments on commit 669d985

Please sign in to comment.