Skip to content

Instantly share code, notes, and snippets.

@praveenuics
Last active June 24, 2020 14:29
Show Gist options
  • Save praveenuics/bd80f7bf9e915d0f4085fbca4d7c6b01 to your computer and use it in GitHub Desktop.
Save praveenuics/bd80f7bf9e915d0f4085fbca4d7c6b01 to your computer and use it in GitHub Desktop.
6/19 D3v5 mouse move multi line chart with json data
license: mit
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v5.min.js"></script>
<style>
body {
margin:auto;
width: 885px;
font: 10px arial;
padding: 25px;
}
.y-axis line {
opacity:.2;
}
.y-axis path {
display:none;
}
.line {
fill: none;
stroke-width: 1.5px;
opacity:.75;
}
.overlay {
fill: none;
pointer-events: all;
}
.lineHoverText {
text-shadow:
-2px -2px 0 #fff,
2px -2px 0 #fff,
-2px 2px 0 #fff,
2px 2px 0 #fff;
}
.hoverCircle {
opacity: .75;
}
</style>
</head>
<body>
<svg id="chart" width="850" height="410"></svg>
<script>
// Feel free to change or delete any of the code you see in this editor!
var data = [
{
type: 'A',
values: [
{
"$id": "8",
"name": 1592490990000,
"value": 99.475
},
{
"$id": "9",
"name": 1592491020000,
"value": 0
},
{
"$id": "10",
"name": 1592491050000,
"value": 0
},
{
"$id": "11",
"name": 1592491080000,
"value": 98.87500000000001
},
{
"$id": "12",
"name": 1592491110000,
"value": 99.975
},
{
"$id": "13",
"name": 1592491140000,
"value": 99.075
},
{
"$id": "14",
"name": 1592491170000,
"value": 99.625
},
{
"$id": "15",
"name": 1592491200000,
"value": 98.47500000000001
},
{
"$id": "16",
"name": 1592491230000,
"value": 99.72500000000001
},
{
"$id": "17",
"name": 1592491260000,
"value": 98.825
},
]
},
{
type: 'B',
values: [
{
"$id": "8",
"name": 1592490990000,
"value": 19.475
},
{
"$id": "9",
"name": 1592491020000,
"value": 20
},
{
"$id": "10",
"name": 1592491050000,
"value": 40
},
{
"$id": "11",
"name": 1592491080000,
"value": 28.87500000000001
},
{
"$id": "12",
"name": 1592491110000,
"value": 79.975
},
{
"$id": "494",
"name": 1592491140000,
"value": 88.6
},
{
"$id": "495",
"name": 1592491170000,
"value": 89
},
{
"$id": "496",
"name": 1592491200000,
"value": 88.3
},
{
"$id": "497",
"name": 1592491230000,
"value": 89.3
},
{
"$id": "498",
"name": 1592491260000,
"value": 88.5
},
]
}
];
var focus, svg, x, y, color, trendLine;
var bisectDate = d3.bisector(d => d.name).left,
parseTime = d3.timeParse("%Y%m%d"),
formatDate = d3.timeFormat("%Y-%m-%d"),
formatValue = d3.format(",.0f");
function drawChart(data){
svg = d3.select("#chart"),
margin = {top: 15, right: 35, bottom: 15, left: 35},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
x = d3.scaleTime()
.rangeRound([margin.left, width - margin.right])
.domain([data[0].values[0].name, data[0].values[data[0].values.length-1].name]);
y = d3.scaleLinear()
.rangeRound([height - margin.bottom, margin.top]).domain([0,100]).nice();
color = d3.scaleOrdinal(d3.schemeCategory10);
trendLine = d3.line()
.curve(d3.curveBasis)
.x(d => x(d.name))
.y(d => y(d.value));
svg.append("g")
.attr("class","x-axis")
.attr("transform", "translate(0," + (height - margin.bottom) + ")")
.call(d3.axisBottom(x));
svg.append("g")
.attr("class", "y-axis")
.attr("transform", "translate(" + margin.left + ",0)")
.call(d3.axisLeft(y));
focus = svg.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("line").attr("class", "lineHover")
.style("stroke", "#999")
.attr("stroke-width", 1)
.style("shape-rendering", "crispEdges")
.style("opacity", 0.5)
.attr("y1", -height)
.attr("y2",0);
focus.append("text").attr("class", "lineHoverDate")
.attr("text-anchor", "middle")
.attr("font-size", 12);
var overlay = svg.append("rect")
.attr("class", "overlay")
.attr("x", margin.left)
.attr("width", width - margin.right - margin.left)
.attr("height", height)
svg.selectAll(".y-axis").transition()
.duration(300)
.call(d3.axisLeft(y).tickSize(-width + margin.right + margin.left))
var line = svg.selectAll(".lines")
.data(data);
line.exit().remove();
line.enter().insert("g", ".focus").append("path")
.attr("class", "line lines")
.style("stroke", d => color(d.id))
.merge(line)
.transition().duration(300)
.attr("d", d => trendLine(d.values))
tooltip(data.values);
}
function tooltip(copy) {
var labels = focus.selectAll(".lineHoverText")
.data(copy)
labels.enter().append("text")
.attr("class", "lineHoverText")
.style("fill", d => color(d.type))
.attr("text-anchor", "start")
.attr("font-size",12)
.attr("dy", (_, i) => 1 + i * 2 + "em")
.merge(labels);
var circles = focus.selectAll(".hoverCircle")
.data(copy)
circles.enter().append("circle")
.attr("class", "hoverCircle")
.style("fill", d => color(d))
.attr("r", 2.5)
.merge(circles);
svg.selectAll(".overlay")
.on("mouseover", function() { focus.style("display", null); })
.on("mouseout", function() { focus.style("display", "none"); })
.on("mousemove", mousemove);
function mousemove() {
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(data.values, x0, 1),
d0 = data[i - 1].values[i-1],
d1 = data[i].values[i],
d = x0 - d0.name > d1.name - x0 ? d1 : d0;
focus.select(".lineHover")
.attr("transform", "translate(" + x(d.name) + "," + height + ")");
focus.select(".lineHoverDate")
.attr("transform",
"translate(" + x(d.name) + "," + (height + margin.bottom) + ")")
.text(d.name);
focus.selectAll(".hoverCircle")
.attr("cy", e => y(d[e]))
.attr("cx", x(d.name));
focus.selectAll(".lineHoverText")
.attr("transform",
"translate(" + (x(d.name)) + "," + height / 2.5 + ")")
.text(e => e + " " + "º" + formatValue(d[e]));
x(d.name) > (width - width / 4)
? focus.selectAll("text.lineHoverText")
.attr("text-anchor", "end")
.attr("dx", -10)
: focus.selectAll("text.lineHoverText")
.attr("text-anchor", "start")
.attr("dx", 10)
}
}
drawChart(data);
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment