Skip to content

Instantly share code, notes, and snippets.

@kkdd
Last active September 7, 2022 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kkdd/6235f48385f7a208e0b1956a19bb894f to your computer and use it in GitHub Desktop.
Save kkdd/6235f48385f7a208e0b1956a19bb894f to your computer and use it in GitHub Desktop.
d3.js_lines_multiple (with tooltip)
<!DOCTYPE html>
<!--https://www.goodmarketing.club/guide/d3-js-multiple-lines-chart-w-line-by-line-code-explanations/-->
<html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="https://d3js.org/colorbrewer.v1.min.js"></script>
<style>
.axis path{
stroke:black;
stroke-width:2px ;
}
.axis line{
stroke: black;
stroke-width: 1.5px;
}
.axis text{
fill: black;
font-weight: bold;
font-size: 14px;
font-family:"Arial Black", Gadget, sans-serif;
}
.legend text{
fill: black;
font-family:"Arial Black", Gadget, sans-serif;
}
.tooltip {
position: absolute;
text-align: left;
width: auto;
height: auto;
padding: 2px;
font-size: 9px;
background: white;
-webkit-box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.8);
-moz-box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.8);
box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.8);
visibility: hidden;
}
</style>
</head>
<body>
<svg width="1200" height="750" style="background-image: url('https://etc.usf.edu/presentations/backgrounds/grid/grid_04/1304m.gif');">
</svg>
<script>
const leftMargin=70, topMargin=30;
// DataSource: eMarketer, March 2018
const data = [
{ year: 2016, media: "Digital", spending: 72.2 },
{ year: 2017, media: "Digital", spending: 90.39 },
{ year: 2018, media: "Digital", spending: 107.3 },
{ year: 2019, media: "Digital", spending: 125.75 },
{ year: 2020, media: "Digital", spending: 142.23 },
{ year: 2021, media: "Digital", spending: 156.43 },
{ year: 2022, media: "Digital", spending: 170.48 },
{ year: 2016, media: "TV", spending: 71.29 },
{ year: 2017, media: "TV", spending: 70.22 },
{ year: 2018, media: "TV", spending: 69.87 },
{ year: 2019, media: "TV", spending: 69.17 },
{ year: 2020, media: "TV", spending: 69.52 },
{ year: 2021, media: "TV", spending: 68.82 },
{ year: 2022, media: "TV", spending: 68.13 },
{ year: 2016, media: "Print", spending: 25.49 },
{ year: 2017, media: "Print", spending: 22.81 },
{ year: 2018, media: "Print", spending: 20.05 },
{ year: 2019, media: "Print", spending: 17.29 },
{ year: 2020, media: "Print", spending: 15.19 },
{ year: 2021, media: "Print", spending: 13.56 },
{ year: 2022, media: "Print", spending: 12.38 },
{ year: 2016, media: "Radio", spending: 14.33 },
{ year: 2017, media: "Radio", spending: 14.33 },
{ year: 2018, media: "Radio", spending: 14.41 },
{ year: 2019, media: "Radio", spending: 14.43 },
{ year: 2020, media: "Radio", spending: 14.46 },
{ year: 2021, media: "Radio", spending: 14.49 },
{ year: 2022, media: "Radio", spending: 14.52 },
{ year: 2016, media: "Out-of-home", spending: 7.6 },
{ year: 2017, media: "Out-of-home", spending: 7.75 },
{ year: 2018, media: "Out-of-home", spending: 7.87 },
{ year: 2019, media: "Out-of-home", spending: 7.95 },
{ year: 2020, media: "Out-of-home", spending: 8.03 },
{ year: 2021, media: "Out-of-home", spending: 8.11 },
{ year: 2022, media: "Out-of-home", spending: 8.19 },
{ year: 2016, media: "Directories", spending: 2.35 },
{ year: 2017, media: "Directories", spending: 1.83 },
{ year: 2018, media: "Directories", spending: 1.47 },
{ year: 2019, media: "Directories", spending: 1.19 },
{ year: 2020, media: "Directories", spending: 0.99 },
{ year: 2021, media: "Directories", spending: 0.84 },
{ year: 2022, media: "Directories", spending: 0.74 }
];
// format the year
data.forEach(d => {d.year = d3.timeParse("%Y")(d.year)});
const dataGrouped = d3.group(data, d => d.media); // InternMap
const KEY = 0, VALUE = 1;
//console.log(dataGrouped);
// xAxis
const xExtent = d3.extent(data, d => d.year);
const xScale = d3.scaleTime().domain(xExtent).range([leftMargin, 900]);
const xAxis = d3.axisBottom().scale(xScale);
// yAxis
const yExtent = [0, d3.max(data,d=>d.spending) + topMargin];
const yScale = d3.scaleLinear().domain(yExtent).range([600, 0]);
const yAxis = d3.axisLeft().scale(yScale).ticks(10);
const tooltip = d3.select("body").append("div").attr("class", "tooltip");
d3.select("svg")
.append("g")
.attr("class", "axis")
.attr("transform", "translate(0,620)")
.call(xAxis)
.append("text")
.attr("x", (900+70)/2) //middle of the xAxis
.attr("y", "50") // a little bit below xAxis
.text("Year");
d3.select('svg')
.append("g")
.attr("class", "axis")
.attr("transform", `translate(${leftMargin},20)`) //use variable in translate
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("x", "-150")
.attr("y", "-50")
.attr("text-anchor", "end")
.text("US Media Ad Spending (Billions)");
d3.select("svg")
.selectAll(".line")
.append("g")
.attr("class", "line")
.data(dataGrouped)
.enter()
.append("path")
.attr("fill", "none")
.attr("stroke-width", 2)
.attr("stroke", d => color(d[KEY]))
.attr("d", d => line(d[VALUE]))
.on("mouseover", (e, d) => {
tooltip
.style("visibility", "visible")
.html("media: " + d[KEY]);
})
.on("mousemove", (e, d) => {
tooltip
.style("top", (event.pageY - 20) + "px")
.style("left", (event.pageX + 10) + "px");
})
.on("mouseout", d => {
tooltip.style("visibility", "hidden");
});
function color(d) {return d3.scaleOrdinal().domain([...dataGrouped.keys()]).range(colorbrewer.Set2[6])(d)};
function line(d) {return d3.line()
.x(d => xScale(d.year))
.y(d => yScale(d.spending))
.curve(d3.curveCardinal)(d)};
// curveLinear curveBasis curveCardinal
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment