PageSourceSearch

https://libregraphicsmeeting.org/2026/js/culori-4.0.1/src/interpolate/interpolate.js

js libregraphicsmeeting.org collected 2026-10-02 02:40:56 UTC 3,916 bytes, 155 lines download raw bytes

vendor: 3,916 bytes, lines 1-155
1import converter from '../converter.js';
2import { getMode } from '../modes.js';
3import normalizePositions from '../util/normalizePositions.js';
4import easingMidpoint from '../easing/midpoint.js';
5import { mapper, mapAlphaMultiply, mapAlphaDivide } from '../map.js';
6
7const isfn = o => typeof o === 'function';
8const isobj = o => o && typeof o === 'object';
9const isnum = o => typeof o === 'number';
10
11const interpolate_fn = (colors, mode = 'rgb', overrides, premap) => {
12	let def = getMode(mode);
13	let conv = converter(mode);
14
15	let conv_colors = [];
16	let positions = [];
17	let fns = {};
18
19	colors.forEach(val => {
20		if (Array.isArray(val)) {
21			conv_colors.push(conv(val[0]));
22			positions.push(val[1]);
23		} else if (isnum(val) || isfn(val)) {
24			// Color interpolation hint or easing function
25			fns[positions.length] = val;
26		} else {
27			conv_colors.push(conv(val));
28			positions.push(undefined);
29		}
30	});
31
32	normalizePositions(positions);
33
34	// override the default interpolators
35	// from the color space definition with any custom ones
36	let fixed = def.channels.reduce((res, ch) => {
37		let ffn;
38		if (isobj(overrides) && isobj(overrides[ch]) && overrides[ch].fixup) {
39			ffn = overrides[ch].fixup;
40		} else if (isobj(def.interpolate[ch]) && def.interpolate[ch].fixup) {
41			ffn = def.interpolate[ch].fixup;
42		} else {
43			ffn = v => v;
44		}
45		res[ch] = ffn(conv_colors.map(color => color[ch]));
46		return res;
47	}, {});
48
49	if (premap) {
50		let ccolors = conv_colors.map((color, idx) => {
51			return def.channels.reduce(
52				(c, ch) => {
53					c[ch] = fixed[ch][idx];
54					return c;
55				},
56				{ mode }
57			);
58		});
59		fixed = def.channels.reduce((res, ch) => {
60			res[ch] = ccolors.map(c => {
61				let v = premap(c[ch], ch, c, mode);
62				return isNaN(v) ? undefined : v;
63			});
64			return res;
65		}, {});
66	}
67
68	let interpolators = def.channels.reduce((res, ch) => {
69		let ifn;
70		if (isfn(overrides)) {
71			ifn = overrides;
72		} else if (isobj(overrides) && isfn(overrides[ch])) {
73			ifn = overrides[ch];
74		} else if (
75			isobj(overrides) &&
76			isobj(overrides[ch]) &&
77			overrides[ch].use
78		) {
79			ifn = overrides[ch].use;
80		} else if (isfn(def.interpolate[ch])) {
81			ifn = def.interpolate[ch];
82		} else if (isobj(def.interpolate[ch])) {
83			ifn = def.interpolate[ch].use;
84		}
85
86		res[ch] = ifn(fixed[ch]);
87		return res;
88	}, {});
89
90	let n = conv_colors.length - 1;
91
92	return t => {
93		// clamp t to the [0, 1] interval
94		t = Math.min(Math.max(0, t), 1);
95
96		if (t <= positions[0]) {
97			return conv_colors[0];
98		}
99
100		if (t > positions[n]) {
101			return conv_colors[n];
102		}
103
104		// Convert `t` from [0, 1] to `t0` between the appropriate two colors.
105		// First, look for the two colors between which `t` is located.
106		// Note: this can be optimized by searching for the index
107		// through bisection instead of start-to-end.
108		let idx = 0;
109		while (positions[idx] < t) idx++;
110		let start = positions[idx - 1];
111		let delta = positions[idx] - start;
112
113		let P = (t - start) / delta;
114
115		// use either the local easing, or the global easing, if any
116		let fn = fns[idx] || fns[0];
117		if (fn !== undefined) {
118			if (isnum(fn)) {
119				fn = easingMidpoint((fn - start) / delta);
120			}
121			P = fn(P);
122		}
123
124		let t0 = (idx - 1 + P) / n;
125
126		return def.channels.reduce(
127			(res, channel) => {
128				let val = interpolators[channel](t0);
129				if (val !== undefined) {
130					res[channel] = val;
131				}
132				return res;
133			},
134			{ mode }
135		);
136	};
137};
138
139const interpolate = (colors, mode = 'rgb', overrides) =>
140	interpolate_fn(colors, mode, overrides);
141
142const interpolateWith =
143	(premap, postmap) =>
144	(colors, mode = 'rgb', overrides) => {
145		let post = postmap ? mapper(postmap, mode) : undefined;
146		let it = interpolate_fn(colors, mode, overrides, premap);
147		return post ? t => post(it(t)) : it;
148	};
149
150const interpolateWithPremultipliedAlpha = interpolateWith(
151	mapAlphaMultiply,
152	mapAlphaDivide
153);
154
155export { interpolate, interpolateWith, interpolateWithPremultipliedAlpha };

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.