Skip to content

Instantly share code, notes, and snippets.

@mbostock
Last active October 25, 2020 21:12

Revisions

  1. mbostock revised this gist Jan 14, 2020. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions .block
    Original file line number Diff line number Diff line change
    @@ -1 +1,2 @@
    license: gpl-3.0
    redirect: https://observablehq.com/@d3/zoomable-area-chart
  2. mbostock revised this gist Jan 25, 2017. 2 changed files with 50 additions and 136 deletions.
    File renamed without changes.
    186 changes: 50 additions & 136 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -1,164 +1,78 @@

    <!DOCTYPE html>
    <meta charset="utf-8">
    <script src="//d3js.org/d3.v3.min.js"></script>
    <style>

    svg {
    font: 10px sans-serif;
    }

    .axis {
    shape-rendering: crispEdges;
    }

    .axis path, .axis line {
    fill: none;
    stroke-width: .5px;
    }

    .x.axis path {
    stroke: #000;
    }

    .x.axis line {
    stroke: #fff;
    stroke-opacity: .5;
    }

    .y.axis line {
    stroke: #ddd;
    }

    path.line {
    fill: none;
    stroke: #000;
    stroke-width: .5px;
    }

    rect.pane {
    cursor: move;
    fill: none;
    pointer-events: all;
    }

    </style>
    <body>
    <svg width="960" height="500"></svg>
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <script>

    var margin = {top: 20, right: 60, bottom: 30, left: 20},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;
    var svg = d3.select("svg"),
    margin = {top: 20, right: 20, bottom: 30, left: 60},
    width = +svg.attr("width") - margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom,
    g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    var parseDate = d3.time.format("%Y-%m-%d").parse,
    formatDate = d3.time.format("%Y");
    var parseDate = d3.timeParse("%Y-%m-%d"),
    formatDate = d3.timeFormat("%Y");

    var x = d3.time.scale()
    var x = d3.scaleTime()
    .domain([new Date(1999, 0, 1), new Date(2003, 0, 0)])
    .range([0, width]);

    var y = d3.scale.linear()
    var y = d3.scaleLinear()
    .range([height, 0]);

    var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom")
    .tickSize(-height, 0)
    .tickPadding(6);

    var yAxis = d3.svg.axis()
    .scale(y)
    .orient("right")
    .tickSize(-width)
    .tickPadding(6);

    var area = d3.svg.area()
    .interpolate("step-after")
    .x(function(d) { return x(d.date); })
    .y0(y(0))
    .y1(function(d) { return y(d.value); });

    var line = d3.svg.line()
    .interpolate("step-after")
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.value); });

    var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    var zoom = d3.behavior.zoom()
    .on("zoom", draw);

    var gradient = svg.append("defs").append("linearGradient")
    .attr("id", "gradient")
    .attr("x2", "0%")
    .attr("y2", "100%");
    var xAxis = d3.axisBottom(x);

    gradient.append("stop")
    .attr("offset", "0%")
    .attr("stop-color", "#fff")
    .attr("stop-opacity", .5);
    var yAxis = d3.axisLeft(y);

    gradient.append("stop")
    .attr("offset", "100%")
    .attr("stop-color", "#999")
    .attr("stop-opacity", 1);

    svg.append("clipPath")
    .attr("id", "clip")
    .append("rect")
    .attr("x", x(0))
    .attr("y", y(1))
    .attr("width", x(1) - x(0))
    .attr("height", y(0) - y(1));

    svg.append("g")
    .attr("class", "y axis")
    .attr("transform", "translate(" + width + ",0)");
    var area = d3.area()
    .curve(d3.curveStepAfter)
    .y0(y(0))
    .y1(function(d) { return y(d.value); });

    svg.append("path")
    .attr("class", "area")
    var areaPath = g.append("path")
    .attr("clip-path", "url(#clip)")
    .style("fill", "url(#gradient)");
    .attr("fill", "steelblue");

    var yGroup = g.append("g");

    svg.append("g")
    .attr("class", "x axis")
    var xGroup = g.append("g")
    .attr("transform", "translate(0," + height + ")");

    svg.append("path")
    .attr("class", "line")
    .attr("clip-path", "url(#clip)");
    var zoom = d3.zoom()
    .scaleExtent([1 / 4, 8])
    .translateExtent([[-width, -Infinity], [2 * width, Infinity]])
    .on("zoom", zoomed);

    svg.append("rect")
    .attr("class", "pane")
    var zoomRect = svg.append("rect")
    .attr("width", width)
    .attr("height", height)
    .attr("fill", "none")
    .attr("pointer-events", "all")
    .call(zoom);

    d3.csv("readme-flights.csv", function(error, data) {
    if (error) throw error;

    data.forEach(function(d) {
    d.date = parseDate(d.date);
    d.value = +d.value;
    });
    g.append("clipPath")
    .attr("id", "clip")
    .append("rect")
    .attr("width", width)
    .attr("height", height);

    x.domain([new Date(1999, 0, 1), new Date(2003, 0, 0)]);
    d3.csv("flights.csv", function(d) {
    d.date = parseDate(d.date);
    d.value = +d.value;
    return d;
    }, function(error, data) {
    if (error) throw error;
    var xExtent = d3.extent(data, function(d) { return d.date; });
    zoom.translateExtent([[x(xExtent[0]), -Infinity], [x(xExtent[1]), Infinity]])
    y.domain([0, d3.max(data, function(d) { return d.value; })]);
    zoom.x(x);

    svg.select("path.area").data([data]);
    svg.select("path.line").data([data]);
    draw();
    yGroup.call(yAxis).select(".domain").remove();
    areaPath.datum(data);
    zoomRect.call(zoom.transform, d3.zoomIdentity);
    });

    function draw() {
    svg.select("g.x.axis").call(xAxis);
    svg.select("g.y.axis").call(yAxis);
    svg.select("path.area").attr("d", area);
    svg.select("path.line").attr("d", line);
    function zoomed() {
    var xz = d3.event.transform.rescaleX(x);
    xGroup.call(xAxis.scale(xz));
    areaPath.attr("d", area.x(function(d) { return xz(d.date); }));
    }

    </script>
  3. mbostock revised this gist Feb 9, 2016. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions .block
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    license: gpl-3.0
  4. mbostock revised this gist Oct 31, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion index.html
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,7 @@

    <!DOCTYPE html>
    <meta charset="utf-8">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
    <script src="//d3js.org/d3.v3.min.js"></script>
    <style>

    svg {
  5. mbostock revised this gist Jun 11, 2015. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion index.html
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,7 @@

    <!DOCTYPE html>
    <meta charset="utf-8">
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
    <style>

    svg {
    @@ -138,6 +138,8 @@
    .call(zoom);

    d3.csv("readme-flights.csv", function(error, data) {
    if (error) throw error;

    data.forEach(function(d) {
    d.date = parseDate(d.date);
    d.value = +d.value;
  6. mbostock revised this gist Nov 13, 2012. 1 changed file with 0 additions and 0 deletions.
    Binary file added thumbnail.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
  7. mbostock created this gist Nov 5, 2012.
    162 changes: 162 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,162 @@

    <!DOCTYPE html>
    <meta charset="utf-8">
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <style>

    svg {
    font: 10px sans-serif;
    }

    .axis {
    shape-rendering: crispEdges;
    }

    .axis path, .axis line {
    fill: none;
    stroke-width: .5px;
    }

    .x.axis path {
    stroke: #000;
    }

    .x.axis line {
    stroke: #fff;
    stroke-opacity: .5;
    }

    .y.axis line {
    stroke: #ddd;
    }

    path.line {
    fill: none;
    stroke: #000;
    stroke-width: .5px;
    }

    rect.pane {
    cursor: move;
    fill: none;
    pointer-events: all;
    }

    </style>
    <body>
    <script>

    var margin = {top: 20, right: 60, bottom: 30, left: 20},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

    var parseDate = d3.time.format("%Y-%m-%d").parse,
    formatDate = d3.time.format("%Y");

    var x = d3.time.scale()
    .range([0, width]);

    var y = d3.scale.linear()
    .range([height, 0]);

    var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom")
    .tickSize(-height, 0)
    .tickPadding(6);

    var yAxis = d3.svg.axis()
    .scale(y)
    .orient("right")
    .tickSize(-width)
    .tickPadding(6);

    var area = d3.svg.area()
    .interpolate("step-after")
    .x(function(d) { return x(d.date); })
    .y0(y(0))
    .y1(function(d) { return y(d.value); });

    var line = d3.svg.line()
    .interpolate("step-after")
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.value); });

    var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    var zoom = d3.behavior.zoom()
    .on("zoom", draw);

    var gradient = svg.append("defs").append("linearGradient")
    .attr("id", "gradient")
    .attr("x2", "0%")
    .attr("y2", "100%");

    gradient.append("stop")
    .attr("offset", "0%")
    .attr("stop-color", "#fff")
    .attr("stop-opacity", .5);

    gradient.append("stop")
    .attr("offset", "100%")
    .attr("stop-color", "#999")
    .attr("stop-opacity", 1);

    svg.append("clipPath")
    .attr("id", "clip")
    .append("rect")
    .attr("x", x(0))
    .attr("y", y(1))
    .attr("width", x(1) - x(0))
    .attr("height", y(0) - y(1));

    svg.append("g")
    .attr("class", "y axis")
    .attr("transform", "translate(" + width + ",0)");

    svg.append("path")
    .attr("class", "area")
    .attr("clip-path", "url(#clip)")
    .style("fill", "url(#gradient)");

    svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")");

    svg.append("path")
    .attr("class", "line")
    .attr("clip-path", "url(#clip)");

    svg.append("rect")
    .attr("class", "pane")
    .attr("width", width)
    .attr("height", height)
    .call(zoom);

    d3.csv("readme-flights.csv", function(error, data) {
    data.forEach(function(d) {
    d.date = parseDate(d.date);
    d.value = +d.value;
    });

    x.domain([new Date(1999, 0, 1), new Date(2003, 0, 0)]);
    y.domain([0, d3.max(data, function(d) { return d.value; })]);
    zoom.x(x);

    svg.select("path.area").data([data]);
    svg.select("path.line").data([data]);
    draw();
    });

    function draw() {
    svg.select("g.x.axis").call(xAxis);
    svg.select("g.y.axis").call(yAxis);
    svg.select("path.area").attr("d", area);
    svg.select("path.line").attr("d", line);
    }

    </script>
    7,672 changes: 7,672 additions & 0 deletions readme-flights.csv
    7,672 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.