const parseTimeslot = timeslot => {
const [start, end] = timeslot.split('-').map(ts => ts.trim());
const [startHour, startMin] = start.split(':').map(s => parseInt(s));
const [endHour, endMin] = end.split(':').map(s => parseInt(s));
return [startHour * 60 + startMin, endHour * 60 + endMin];
};
const formatTimeslot = minute => {
const hourStart = (Math.floor(minute / 60) + '').padStart(2, '0');
const minuteStart = ((minute % 60) + '').padStart(2, '0');
return `${hourStart}:${minuteStart}`;
};
const load = function () {
const mins = Array.from(new Array(48), (x, i) => i * 30);
const capacityData = window._data;
const allData = [];
capacityData.forEach((capacity, i) => {
mins.forEach((min, j) => {
const quotainfo = capacity.quotainfo.filter(quota => {
const [start, end] = parseTimeslot(quota.timeslot);
return start <= min && end > min;
});
allData.push({
x: j,
y: i,
quotainfo,
min
});
});
});
const svg = d3.select('#chart')
.append('svg')
.attr('width', 1400).attr('height', 800)
.append('g')
.attr('transform', 'translate(30, 50)');
const offset = 15;
svg.selectAll('.hours')
.data(mins).enter().append('text')
.attr('x', (d, i) => 75 + i * 25)
.attr('y', offset - 5)
.attr('transform', function() {
return `rotate(-75, ${d3.select(this).attr('x')}, ${d3.select(this).attr('y')})`;
})
.text(formatTimeslot);
svg.selectAll('.store-name')
.data(capacityData).enter().append('text')
.attr('x', () => 5)
.attr('y', (d, i) => 30 + i * 25)
.text(d => d.store);
const tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// console.log(allData);
svg.selectAll('.cell')
.data(allData).enter().append('rect')
.attr('x', d => 70 + d.x * 25)
.attr('y', d => offset + d.y * 25)
.attr('width', d => {
const { quotainfo } = d;
if (quotainfo.length > 1) {
throw new Error('found more than one matching slot', d);
}
if (quotainfo.length === 0) {
return 20;
}
const [start, end] = parseTimeslot(quotainfo[0].timeslot);
return end === d.min + 30 ? 20 : 25;
})
.attr('height', 20)
.attr('class', d => {
const { quotainfo } = d;
if (quotainfo.length > 1) {
throw new Error('found more than one matching slot', d);
}
if (quotainfo.length === 0) {
return;
}
const fullness = quotainfo[0].filled / quotainfo[0].capacity;
return fullness < 0.80 ? 'capacity-normal' : (fullness < 0.96 ? 'capacity-danger' : 'capacity-full');
})
.on('mouseover', function(d) {
const { quotainfo } = d;
if (quotainfo.length) {
tooltip.transition().duration(200).style('opacity', .9);
tooltip.html(`${quotainfo[0].timeslot}
Kapasite:${quotainfo[0].capacity}
Dolu:${quotainfo[0].filled}`)
.style('left', `${d3.event.pageX}px`)
.style('top', `${d3.event.pageY - 28}px`);
}
d3.select(this).classed('selected-timeslot', true);
})
.on('mouseout', function() {
tooltip.transition().duration(300).style('opacity', 0);
d3.select(this).classed('selected-timeslot', false);
});
}
load();