createTimelineSharp = function(selection, xGrid, height, category, histHeight, yPosLine) {
const rectHeight = 20;
const rectWidth = 10;
const stripeWidth = 3;
const dayThresholds = d3.timeDay.every(1).range(dateStart, dateEnd)
const dependentDates = ['pre', 'post']
.map(step => eventData[category].stepData[step].data.filter(d => d.type === category ? false : true))
.flat().map(d => d.date);
console.log(dependentDates.map(d => dateToString(d)))
const binData = d3.histogram()
.domain([dateStart, dateEnd])
.thresholds(dayThresholds)
.value(d => d)
(dependentDates);
const tScale = d3.scaleTime()
.domain([shiftHours(dateStart, -12), shiftHours(dateEnd, 12)])
.range([xGrid('pre'), xGrid('post') + xGrid.bandwidth()]);
const binWidth = (tScale.range()[1] - tScale.range()[0]) / (2 * temporalWindowSize);
const stripeData = [];
binData.forEach((binArray, binNr) => {
// Calculate the actual x-position where the bin will start -> shifted to the left by half the bin width
const binStartX = tScale(binArray.x0) - binWidth/2;
const nrBinEvents = binArray.length;
if (nrBinEvents > 0) {
// How large the step is between each stripe
let step;
if (binNr == (temporalWindowSize - 1)) {
// Treat intervention bin differently: Distribute dependent event stripes only across first half of the bin, in front of the intervention event
step = (binWidth - stripeWidth) / (nrBinEvents + 1);
}
else {
// Distribute dependent event stripes across entire bin
step = binWidth / (nrBinEvents + 1);
}
// Push the x-position for each stripe to the data array
binArray.forEach((d, j) => stripeData.push({
// Move the first stripe in by one step
x: binStartX + j * step + step
}));
};
});
const g = selection.append('g').attr('class', 'timeline-g');
const gStripeDep = selection.append('g').attr('class', 'dependent-stripe-g');
const gStripeInt = selection.append('g').attr('class', 'intervention-stripe-g');
gStripeDep.selectAll('.dependent-stripe')
.data(stripeData)
.join('line')
.attr('class', 'dependent-stripe')
.attr('x1', d => d.x)
.attr('x2', d => d.x)
.attr('y1', yPosLine - histHeight)
.attr('y2', yPosLine)
.attr('stroke', d => {
// If the stripe lies outside of the updated temporal window, color it light grey
if(d.x >= tScale(shiftHours(dateBase, - temporalWindowSizeUpdated * 24 + 12)) &&
d.x <= tScale(shiftHours(dateBase, temporalWindowSizeUpdated * 24 + 12))) {
return fillScale('dependent');
}
else return 'lightgrey';
})
.attr('stroke-width', stripeWidth);
// Intervention event (placed first in actual code)
gStripeInt.selectAll('.intervention-stripe-' + category)
.data([{x: tScale(dateBase) + binWidth/2 - stripeWidth/2}])
.join('line')
.attr('class', 'intervention-stripe-' + category)
.attr('x1', d => d.x)
.attr('x2', d => d.x)
.attr('y1', yPosLine - histHeight) // * 1.3)
.attr('y2', yPosLine)
.attr('stroke', fillScale(category))
.attr('stroke-width', stripeWidth);
// Create ticks for the beginning/end of each day
const gTick = g.append('g').attr('class', 'tick-g');
const tickHeight = 3;
// Get all days that should be ticked
const dayTickData = [...dayThresholds, dateEnd, shiftHours(dateEnd, 24)];
gTick.selectAll('.day-tick')
.data(dayTickData)
.join('line')
.attr('class', 'day-tick')
.attr('x1', d => tScale(d) - binWidth/2)
.attr('x2', d => tScale(d) - binWidth/2)
.attr('y1', yPosLine - tickHeight)
.attr('y2', yPosLine)
.attr('stroke', 'grey')
.attr('stroke-width', 1);
// Create brackets for the labelled day bins
const gBracket = g.append('g').attr('class', 'bracket-g');
const bracketHeight = 5;
gBracket.selectAll('.bracket')
.data([dateStart, dateBase, dateEnd])
.join('path')
.attr('class', 'bracket')
.attr('d', d => {
const cx = tScale(d);
const path = d3.path();
path.moveTo(cx - binWidth/2, yPosLine + tickHeight)
path.lineTo(cx - binWidth/2, yPosLine + tickHeight + bracketHeight)
path.lineTo(cx - binWidth/8, yPosLine + tickHeight + bracketHeight)
path.lineTo(cx, yPosLine + tickHeight + bracketHeight + tickHeight)
path.lineTo(cx + binWidth/8, yPosLine + tickHeight + bracketHeight)
path.lineTo(cx + binWidth/2, yPosLine + tickHeight + bracketHeight)
path.lineTo(cx + binWidth/2, yPosLine + tickHeight)
return path;
})
.attr('fill', 'none')
.attr('stroke', 'grey');
// Create x-axis function
const xAxis = d3.axisBottom().scale(tScale)
.tickValues([dateStart, dateBase, dateEnd])
.tickSize(0)
.tickFormat(d3.timeFormat("%d %b %Y"));
g.selectAll(`#${category}-x-axis-g`)
.data([0])
.join(
enter => enter.append('g')
.attr('class', `${category}-x-axis-g`)
.call(xAxis)
.attr('transform', `translate(0, ${yPosLine})`)
)
.selectAll("text")
.attr("dy", "2em");
//appendAxisTicks(g, tScale, category);
}