93 lines
2.7 KiB
JavaScript
93 lines
2.7 KiB
JavaScript
export const gradient = (node, config = {}) => {
|
|
const defaultConfig = {
|
|
points: 12,
|
|
saturation: 0.85,
|
|
lightness: 0.7,
|
|
softness: 0.9,
|
|
seed: null,
|
|
version: null,
|
|
}
|
|
|
|
// Applies a gradient background
|
|
const createGradient = config => {
|
|
config = {
|
|
...defaultConfig,
|
|
...config,
|
|
}
|
|
const { saturation, lightness, softness, points } = config
|
|
const seed = config.seed || Math.random().toString(32).substring(2)
|
|
const version = config.version ?? 0
|
|
|
|
// Hash function which returns a fixed hash between specified limits
|
|
// for a given seed and a given version
|
|
const rangeHash = (seed, min = 0, max = 100, version = 0) => {
|
|
const range = max - min
|
|
let hash = range + version
|
|
for (let i = 0; i < seed.length * 2 + version; i++) {
|
|
hash = (hash << 5) - hash + seed.charCodeAt(i % seed.length)
|
|
hash = ((hash & hash) % range) + version
|
|
}
|
|
return min + (hash % range)
|
|
}
|
|
|
|
// Generates a random HSL colour using the options specified
|
|
const randomHSL = (seed, version, alpha = 1) => {
|
|
const lowerSaturation = Math.min(100, saturation * 100)
|
|
const upperSaturation = Math.min(100, (saturation + 0.2) * 100)
|
|
const lowerLightness = Math.min(100, lightness * 100)
|
|
const upperLightness = Math.min(100, (lightness + 0.2) * 100)
|
|
const hue = rangeHash(seed, 0, 360, version)
|
|
const sat = `${rangeHash(
|
|
seed,
|
|
lowerSaturation,
|
|
upperSaturation,
|
|
version
|
|
)}%`
|
|
const light = `${rangeHash(
|
|
seed,
|
|
lowerLightness,
|
|
upperLightness,
|
|
version
|
|
)}%`
|
|
return `hsla(${hue},${sat},${light},${alpha})`
|
|
}
|
|
|
|
// Generates a radial gradient stop point
|
|
const randomGradientPoint = (seed, version) => {
|
|
const lowerTransparency = Math.min(100, softness * 100)
|
|
const upperTransparency = Math.min(100, (softness + 0.2) * 100)
|
|
const transparency = rangeHash(
|
|
seed,
|
|
lowerTransparency,
|
|
upperTransparency,
|
|
version
|
|
)
|
|
return (
|
|
`radial-gradient(at ` +
|
|
`${rangeHash(seed, 0, 100, version)}% ` +
|
|
`${rangeHash(seed, 0, 100, version + 1)}%,` +
|
|
`${randomHSL(seed, version, saturation)} 0,` +
|
|
`transparent ${transparency}%)`
|
|
)
|
|
}
|
|
|
|
let css = `opacity:0.9;background:${randomHSL(seed, version, 0.7)};`
|
|
css += "background-image:"
|
|
for (let i = 0; i < points - 1; i++) {
|
|
css += `${randomGradientPoint(seed, version + i)},`
|
|
}
|
|
css += `${randomGradientPoint(seed, points)};`
|
|
node.style = css
|
|
}
|
|
|
|
// Apply the initial gradient
|
|
createGradient(config)
|
|
|
|
return {
|
|
// Apply a new gradient
|
|
update: config => {
|
|
createGradient(config)
|
|
},
|
|
}
|
|
}
|