class Plotter {
constructor(options) {
this.options = options;
}
draw(buffer, now) {
const {
width,
height,
windowMillis,
delayMillis,
yRange,
margins,
yPadding
} = this.options;
const svg = d3.select(DOM.svg(width, height));
const xRange = [now - (windowMillis + delayMillis), now - delayMillis];
const xScale = d3.scaleTime(xRange, [margins.left, width - margins.right]);
const [minY, maxY] = yRange || buffer.yRange();
const padding = isNaN(yPadding) ? (maxY - minY) / 8 : yPadding;
const yScale = d3.scaleLinear(
[minY - padding, maxY + padding],
[height - margins.bottom, margins.top]
);
const plotLine = d3
.line()
.x(d => xScale(d[0]))
.y(d => yScale(d[1]));
const rightAxis = d3
.axisRight(yScale)
.tickSize(width - (margins.left + margins.right))
.ticks(10, "+f");
const bottomAxis = d3
.axisTop(xScale)
.tickSize(height - (margins.top + margins.bottom));
const dashedAxis = g =>
g
.selectAll(".tick line")
.attr("stroke-opacity", 0.5)
.attr("stroke-dasharray", "2,2");
svg
.append('clipPath')
.attr('id', 'chart-area')
.append('rect')
.attr('x', margins.left - 1)
.attr('y', margins.top)
.attr('width', width - (margins.left + margins.right))
.attr('height', height - (margins.top + margins.bottom));
svg
.append("g")
.attr("transform", `translate(0,${height - margins.bottom})`)
.call(bottomAxis)
.call(dashedAxis);
svg
.append("g")
.attr("transform", `translate(${margins.left},0)`)
.call(rightAxis)
.call(dashedAxis)
.call(g => g.selectAll(".tick text").attr("x", -25));
Object.keys(buffer.dataById).forEach((id, idx) => {
const data = buffer.dataById[id];
svg
.append('path')
.datum(data)
.attr("clip-path", "url(#chart-area)")
.attr('fill', 'none')
.attr('stroke', d3.schemeTableau10[idx % 10])
.attr('stroke-width', 2)
.attr("transform", "translate(0,0)")
.attr('d', plotLine);
});
return svg.node();
}
}