Published
Edited
Sep 2, 2019
Insert cell
Insert cell
Insert cell
DOM.download(() => serialize(chart), undefined, "Save as SVG")
Insert cell
mobile_width = 650
Insert cell
html`<style>

.team.twins_2019 {
stroke: red
}

</style>`
Insert cell
function hover(svg, path) {
svg
.style("position", "relative");
if ("ontouchstart" in document) svg
.style("-webkit-tap-highlight-color", "transparent")
.on("touchmove", moved)
.on("touchstart", entered)
.on("touchend", left)
else svg
.on("mousemove", moved)
.on("mouseenter", entered)
.on("mouseleave", left);

const dot = svg.append("g")
.attr("display", "none");

dot.append("circle")
.attr("r", 2.5);

dot.append("text")
.style("font", "10px sans-serif")
.attr("text-anchor", "middle")
.attr("y", -25);
dot.append('text')
.attr('class', 'game')
.style('font', '10px sans-serif')
.attr('text-anchor', 'middle')
.attr('y', -15);
dot.append('text')
.attr('class', 'hrs')
.style('font', '10px sans-serif')
.attr('text-anchor', 'middle')
.attr('y', -5);

function moved() {
d3.event.preventDefault();
const ym = y.invert(d3.event.layerY);
const xm = x.invert(d3.event.layerX);
const i1 = d3.bisectLeft(data.games, xm, 1);
const i0 = i1 - 1;
const i = xm - data.games[i0] > data.games[i1] - xm ? i1 : i0;
const s = data.teams.reduce((a, b) => Math.abs(a.values[i] - ym) < Math.abs(b.values[i] - ym) ? a : b);
path.attr("stroke", d => d === s ? line_color(d.id) : "#ddd" ).filter(d => d === s).raise();
dot.attr("transform", `translate(${x(data.games[i])},${y(s.values[i])})`);
dot.select("text").text(s.name);
dot.select('.game').text("Game " + data.games[i])
dot.select('.hrs').text(s.values[i] + " home runs")
}

function entered() {
path.style("mix-blend-mode", null).attr("stroke", "#ddd");
dot.attr("display", null);
}

function left() {
path.style("mix-blend-mode", "multiply").attr("stroke", null).attr('stroke-width', 1.5);
dot.attr("display", "none");
}
}
Insert cell
height = 600
Insert cell
margin = ({top: 20, right: 20, bottom: 30, left: 30})
Insert cell
line_color = d3.scaleOrdinal()
.domain(["twins_2019", "mariners_1999", "mariners_1997", "rangers_2005", "jays_2010", "orioles_1996", "orioles_2016", "astros_2000", "rangers_2001", "yankees_2012", "mariners_1996", "jays_2000", "athletics_1996", "whitesox_2004", "yankees_2018"])
.range(['#D31145', '#002878', '#002878', '#C0111F', '#134A8E', '#DF4601', '#DF4601', '#9A3324', '#C0111F', '#0C2340', '#002878', '#002878', '#134A8E', '#4cbb17', 'black', '#0C2340'])
Insert cell
x = d3.scaleLinear()
.domain([1,163])
.range([margin.left, width - margin.right])
Insert cell
y = d3.scaleLinear()
.domain([0, 330])
.range([height - margin.bottom, margin.top])
Insert cell
xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).ticks(width / 80).tickSizeOuter(0).tickSizeInner(1))
Insert cell
yAxis = g => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y).tickSize(-(width-margin.left), 0, 0))
.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"))
Insert cell
line = d3.line()
.defined(d => !isNaN(d))
.x((d, i) => x(data.games[i]))
.y(d => y(d))
Insert cell
data = d3.json('https://gist.githubusercontent.com/thomasoide/e2a21b2428f41d17c7e33c1919186bf7/raw/ed81570b4e07e7b6a52d6197d0d49c6407d61c22/team_hrs.json')
Insert cell
data.teams[0]
Insert cell
data.teams[1]
Insert cell
record = ({'lineValue': 267, 'label': 'Current MLB HR record'})
Insert cell
d3 = require("d3@5")
Insert cell
import {serialize} from "@mbostock/saving-svg"
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more