← back to Dw Pairs Well
lib/paint.js
60 lines
// Nearest Sherwin-Williams + Dunn-Edwards paint match for any hex.
// Reads from color_reference (already populated with hex + Lab).
const { hexToLab } = require('./color');
// All seven paint brands stocked in color_reference. The frontend picks which
// to display per request via ?brands=sw,de,bm — server always returns all so
// switching is instant (no extra fetch).
const BRANDS = ['sherwin-williams', 'dunn-edwards', 'benjamin-moore', 'behr', 'ppg', 'farrow-ball', 'ral'];
const BRAND_LABELS = {
'sherwin-williams': 'SW',
'dunn-edwards': 'DE',
'benjamin-moore': 'BM',
'behr': 'Behr',
'ppg': 'PPG',
'farrow-ball': 'F&B',
'ral': 'RAL'
};
const cache = new Map(); // hex -> { sherwin-williams: {...}, dunn-edwards: {...} }
async function nearestPaints(pool, hex) {
if (!hex) return null;
var key = String(hex).toLowerCase();
if (cache.has(key)) return cache.get(key);
var lab = hexToLab(hex);
if (!lab) return null;
var sql = `
SELECT DISTINCT ON (brand) brand, code, name, hex,
((lab_l - $1) * (lab_l - $1)
+ (lab_a - $2) * (lab_a - $2)
+ (lab_b - $3) * (lab_b - $3)) AS dist_sq
FROM color_reference
WHERE brand = ANY($4)
ORDER BY brand, dist_sq
`;
var r = await pool.query(sql, [lab.L, lab.a, lab.b, BRANDS]);
var out = {};
for (var i = 0; i < r.rows.length; i++) {
var row = r.rows[i];
out[row.brand] = { code: row.code, name: row.name, hex: row.hex };
}
cache.set(key, out);
return out;
}
// Bulk variant — pass an array of hexes, get back map hex -> paints
async function nearestPaintsBatch(pool, hexes) {
var uniq = Array.from(new Set((hexes || []).filter(Boolean).map(function (h) { return String(h).toLowerCase(); })));
var result = {};
for (var i = 0; i < uniq.length; i++) {
var h = uniq[i];
result[h] = await nearestPaints(pool, h);
}
return result;
}
module.exports = { nearestPaints, nearestPaintsBatch, BRANDS, BRAND_LABELS };