How to sell coworkers on FRP\Highland?
- Dominant language
- JavaScript
- Stars
- 3.4k
- Forks
- 145
- PR merge metrics
- No merged PRs in 30d
Description
So at work I've been trying to sell the rest of the tech team on FRP & libraries like Highland to make it easier to accomplish harder tasks.
I found the perfect problem: If an event date is set in the future, how can we gradate the color between set intervals until then? For example we may want a teal-ish color when there are 48 hours or more until the event. Or a mix between teal & yellow when between 48 hours and 6 hours, and a mix between red & yellow when the time is less than 6 hours from the event date which is red.
Fortunately I was able to get it done in highland but looking at a comparison against one a coworker wrote in vanilla ES6 js, it feels like mine is a lot more verbose & makes less sense. Would anyone here have modeled it differently or is it that my grasp of FRP concepts is severely lacking?
Coworker's solution:
```js
const COLORS = [
{ stop: 0, rgb: [35, 198, 161] },
{ stop: 6, rgb: [245, 235, 73] },
{ stop: 48, rgb: [245, 51, 0] },
];
function getRGBColor (hours) {
let min, max, normalizationFactor;
for (let i = 0; i < COLORS.length; i++) {
if (hours <= COLORS[i].stop && hours >= COLORS[i-1].stop) {
max = COLORS[i];
min = COLORS[i-1];
break;
}
}
normalizationFactor = (hours - min.stop) / (max.stop - min.stop);
return min.rgb.map((c, i) => {
let rgb1 = min.rgb[i],
rgb2 = max.rgb[i],
normalizedDiff = (rgb2 - rgb1) * normalizationFactor,
rawValue = parseInt(rgb1 + normalizedDiff, 10);
if (rawValue > 255) return 255;
else if (rawValue < 0) return 0;
return rawValue;
});
}
```
My highland\FRP solution:
```js
const COLOR_TABLE = [
{
rgb: [245, 51, 0], // red
stop: 0,
},
{
rgb: [248, 235, 73], // yellow
stop: 6,
},
{
rgb: [44, 163, 178], // turk-like colors
stop: 48,
},
];
function calcGradient (input) {
return _([ input ])
// Calculate the duration & hours of the time between now & the event
.map((data) => {
data.duration = data.eventDate - data.now;
data.hours = Math.ceil(data.duration / 1000 / 60 / 60);
return data;
})
// Get the two colors we need to switch to
.flatMap((data) => {
return _(COLOR_TABLE)
// Takes colors until we no longer match their stop
.reduce({ done: false, colors: [] }, (reduction, color) => {
// A very cheap way to not use an if statement :D
!reduction.done && reduction.colors.push(color);
reduction.done = data.hours < color.stop;
return reduction;
})
// grab the colors property from the data object
.pluck('colors')
// Ensures there are always at least 2 colors in the event we're still
// before 48 hours or after the event has occurred
.map((colors) => [colors[0]].concat(colors))
// Only use the last two items.
.map((colors) => colors.slice(-2))
// Merge in our colors back into mainstream's our data
.map(([colorA, colorB]) => Object.assign(data, {
colors: {
prev: colorB,
next: colorA,
},
}));
})
// Get our progress factor to so we know where to transition between the
// two colors
.map((data) => {
let { hours, colors: { prev, next } } = data;
let normalProgress = (hours - prev.stop) / (next.stop - prev.stop);
return Object.assign(data, {
progress: Math.min(Math.max(normalProgress, 0), 1),
});
})
// Find a color that is transitional between the two colors
.flatMap((data) => {
let { colors: { prev, next }, progress } = data;
return _(( prev.rgb ))
.zip(next.rgb)
.map(([ start, end ]) => start + ((end - start) * progress))
.map(Math.floor)
.collect()
.map((gradient) => ({
gradient,
hours: data.hours,
time: data.now,
}));
})
}
```
Contributor guide
Assessment
This issue has not been assessed yet.