lineChart = (height, data, xAxisColumn, yAxisColumn, dateFormatter, lineColor ) => {
const margin = ({top: 10, right: 40, bottom: 20, left: 40})
const svg = d3.select(DOM.svg(width, height));
const x = d3.scaleTime()
.domain(d3.extent(data, d => d[xAxisColumn]))
.range([margin.left, width - margin.right])
const y = d3.scaleLinear()
.domain( [d3.min(data, d => d[yAxisColumn]), d3.max(data, d => d[yAxisColumn]) ] ).nice()
.range([height - margin.bottom, margin.top])
const xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).ticks(width / 45).tickSizeOuter(0))
const yAxis = g => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y).ticks(8, ".0f"))
.call(g => g.select(".domain").remove())
.call(g => g.select(".tick:last-of-type text").clone()
.attr("x", 3)
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.text(data.y))
const line = d3.line()
.defined(d => !isNaN(d[yAxisColumn] ) )
.x(d => x(d[xAxisColumn]))
.y(d => y(d[yAxisColumn]))
svg.append("text")
.attr("x", (width / 2))
.attr("y", margin.top + 5)
.attr("text-anchor", "middle")
.style("font-size", "12px")
.style("text-decoration", "none")
.style("font-family", "Arial, Helvetica, sans-serif")
.style("text-transform", "lowercase")
.text(yAxisColumn);
svg.append("g")
.call(xAxis);
svg.append("g")
.call(yAxis);
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke",lineColor)
.attr("stroke-width", 1.5)
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("d", line);
///////////////////////////////////////////////////////
var focusColor = "#2874A6"
var focus = svg.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("line")
.attr("class", "x-hover-line hover-line")
.attr("y1", 0)
.attr("y2", height)
.style("stroke", focusColor)
.style("stroke-width", "0.5px")
.style("stroke-dasharray", "3,3");
focus.append("circle")
.attr("r", 3.0)
.attr("fill", focusColor);
focus.append("text")
.attr("x", 10)
.attr("dy", ".45em")
.attr("fill", focusColor)
.style("font-size", "12px")
.style("font-family", "Arial, Helvetica, sans-serif")
.style("text-shadow", "2px 2px 1px #E5E8E8");
svg.append("rect")
.attr("transform", "translate(" +0 + "," + 0+ ")")
.attr("width", width)
.attr("height", height)
.style("fill", "none")
.style("pointer-events", "all")
.on("mouseover", () => { focus.style("display", null); })
.on("mouseout", () => { focus.style("display", "none"); })
.on("mousemove", mousemove);
const bisectDate = d3.bisector(function(d) { return d[xAxisColumn]; }).left
function mousemove() {
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0[xAxisColumn] > d1[xAxisColumn] - x0 ? d1 : d0;
focus.attr("transform", "translate(" + x(d[xAxisColumn]) + "," + y(d[yAxisColumn]) + ")");
focus.select("text").text( () => { return dateFormatter(d1[xAxisColumn]) + " : "+ numberFormat(d[yAxisColumn]) ; });
focus.select(".x-hover-line").attr("y2", height - y(d[yAxisColumn]) - margin.bottom );
}
return svg.node();
}