{
const viewWidth = 696;
const maxWidth = viewWidth;
const viewHeight = 396;
const margin = { top: 48, bottom: 60, left: 12, right: 12 };
return state.doses;
const caffeineStreams = dosesToCaffeineStreams(state.doses, {
totalHours,
caffeinePerCupMg
}).sort((l, r) => l[0][0] - r[0][0]);
return caffeineStreams;
const stackedStreams = stackStreams(caffeineStreams);
let streamsToPlot = stackedStreams.map((curStream) => {
return curStream
.filter(([x]) => x <= 30)
.map(([x, y0, y]) => ({ x, y0, y }));
});
let streamCountByTime = new Map();
streamsToPlot.forEach((curStream) => {
const countForTime = streamCountByTime.get(curStream[0].x) || 0;
streamCountByTime.set(curStream[0].x, countForTime + 1);
curStream.id = `${curStream[0].x}_${countForTime}`;
});
const streamIDs = new Set(streamsToPlot.map((ds) => ds.id));
const enteredStreamIDs = new Set(
[...streamIDs].filter((x) => !visibleStreamIDs.has(x))
);
const exitedStreamIDs = new Set(
[...visibleStreamIDs].filter((x) => !streamIDs.has(x))
);
if (0 !== enteredStreamIDs.size || 0 !== exitedStreamIDs.size) {
console.log("Entered: " + Array.from(enteredStreamIDs));
console.log("Exited: " + Array.from(exitedStreamIDs));
new Promise(async () => {
await Promises.delay(500);
mutable visibleStreamIDs = new Set(
[...visibleStreamIDs, ...enteredStreamIDs].filter(
(x) => !exitedStreamIDs.has(x)
)
);
});
}
streamsToPlot.forEach((curStream) => {
curStream.entered = enteredStreamIDs.has(curStream.id);
curStream.exited = exitedStreamIDs.has(curStream.id);
});
const maxCaffeine = d3.max(
streamsToPlot.flat().map((d) => caffeineSleepThreshold <= d.y)
);
const caffeineBelowSleepThreshold = maxCaffeine <= caffeineSleepThreshold;
const sleepTime = calculateSleepTime(streamsToPlot);
const description = getDescriptionText(streamsToPlot);
const descriptionParts = description.split("\n");
const colors = d3.quantize(
d3.interpolateRgb("#E6762A", "#F3E500"),
Math.max(2, streamsToPlot.length)
);
const grid = null;
const renderedCaffeineChart = caffeineChart(streamsToPlot, {
colors,
width: viewWidth - margin.left - margin.right,
height: viewHeight - margin.top - margin.bottom,
domain: [6, 30]
});
return svg`
<svg width="${Math.min(maxWidth, width)}"
height="${viewHeight * (Math.min(maxWidth, width) / viewWidth)}"
viewBox="0 0 ${viewWidth} ${viewHeight}"
style="max-width: ${maxWidth}px;">
<style>
text {
fill: #1B1A4B;
/* font-family: "Helvetica Neue", helvetica, arial, san-serif;*/
}
.title-text {
font-size: 1.5em;
font-weight: bold;
}
.description-text {
font-size: 0.9em;
}
.title-text text,
.description-text text {
alignment-baseline: bottom;
}
.background-rect {
fill: #FEFCF9;
}
.y-axis > path {
display: none;
}
.y-axis text {
alignment-baseline: bottom;
}
.x-axis > path {
display: none;
/*stroke-width: 3px;
stroke-color: #1B1A4B;*/
}
.tick line {
display: none;
}
.sleep-line {
fill: #238BCD;
}
.sleep-line-border {
stroke: #FFFDF7;
stroke-width: 7;
}
@keyframes fadein {
from { opacity: 0.2; }
to { opacity: 1; }
}
.stream.entered {
animation: fadein 0.5s;
}
</style>
<rect class="background-rect" width="${viewWidth}" height="${viewHeight}"/>
<g transform="translate(${margin.left + 48}, ${margin.top})">
<text>
<tspan class="title-text" x="0">Caffeine Levels by Hour</tspan>
<tspan class="description-text" x="0" dy="24">
${descriptionParts[0]}
</tspan>
<tspan class="description-text" x="0" dy="24">
${descriptionParts[1] || ""}
</tspan>
</text>
</g>
<g transform="translate(${margin.left}, ${margin.top + 72})">
${renderedCaffeineChart}
</g>
${grid}
</svg>
`;
}