tile-stencil
Version:
Load a MapLibre style document and parse it into Javascript functions
71 lines (53 loc) • 2.08 kB
JavaScript
import { color, rgb } from "d3-color";
export function buildInterpolator(stops, base = 1) {
if (!stops || stops.length < 2 || stops[0].length !== 2) return;
// Confirm stops are all the same type, and convert colors to arrays
const type = getType(stops[0][1]);
if (!stops.every(s => getType(s[1]) === type)) return;
stops = stops.map(([x, y]) => [x, convertIfColor(y)]);
const izm = stops.length - 1;
const scale = getScale(base);
const interpolate = getInterpolator(type);
return function(x) {
const iz = stops.findIndex(stop => stop[0] > x);
if (iz === 0) return stops[0][1]; // x is below first stop
if (iz < 0) return stops[izm][1]; // x is above last stop
const [x0, y0] = stops[iz - 1];
const [x1, y1] = stops[iz];
return interpolate(y0, scale(x0, x, x1), y1);
};
}
function getType(v) {
return color(v) ? "color" : typeof v;
}
export function convertIfColor(val) {
// Convert CSS color strings to clamped RGBA arrays for WebGL
if (!color(val)) return val;
const c = rgb(val);
return [c.r / 255, c.g / 255, c.b / 255, c.opacity];
}
function getScale(base) {
// Return a function to find the relative position of x between a and b
// Exponential scale follows mapbox-gl-js, style-spec/function/index.js
// NOTE: https://github.com/mapbox/mapbox-gl-js/issues/2698 not addressed!
const scale = (base === 1)
? (a, x, b) => (x - a) / (b - a) // Linear scale
: (a, x, b) => (Math.pow(base, x - a) - 1) / (Math.pow(base, b - a) - 1);
// Add check for zero range
return (a, x, b) => (a === b)
? 0
: scale(a, x, b);
}
function getInterpolator(type) {
// Return a function to find an interpolated value between end values v1, v2,
// given relative position t between the two end positions
switch (type) {
case "number": // Linear interpolator
return (v1, t, v2) => v1 + t * (v2 - v1);
case "color": // Interpolate RGBA
return (v1, t, v2) =>
v1.map((v, i) => v + t * (v2[i] - v));
default: // Assume step function
return (v1) => v1;
}
}