block by enjalot 6641917

d3 workshop

Full Screen

index.html

<!DOCTYPE html>
<meta charset="utf-8">
<html>
  <head>
    <style>
      svg {
        width: 960px;
        height: 500px;
        border: 1px solid gray;
      }
      .table {
        width: 960px;
        height: 500px;
        overflow: scroll;
      }
      .axis {
        font-size: 10px;
      }
      .axis path {
        fill: none;
        stroke: #000000;
      }
      .axis .tick line {
        stroke: #000;
      }
    </style>
  </head>
  <body>
   
    <svg></svg>
    <div id="display"></div>

    <script src="//d3js.org/d3.v3.js"></script>
    <script src="table.js"></script>
    <script src="scatter.js"></script>
    <script src="brush.js"></script>
    <script src="histogram.js"></script>
    <script>
      var display = d3.select("#display");

      d3.json("pics.json", function(err, pics) {
        var data = pics.data.children;
        data.forEach(function(d) {
          d.data.created *= 1000;
        })
        console.log(data);

        var display = d3.select("#display")

        //table
        var tdiv = display.append("div").classed("table", true)
        var table = d3.chart.table()
        table.data(data)
        table(tdiv);

        var svg = d3.select("svg")
        //scatter plot
        var sgroup = svg.append("g")
          .attr("transform", "translate(50, 0)")
        var scatter = d3.chart.scatter()
        scatter.data(data)
        scatter(sgroup)

        //histogram
        var hgroup = svg.append("g")
          .attr("transform", "translate(450, 0)")
        var histogram = d3.chart.histogram()
        histogram.data(data)
        histogram(hgroup)


        //brush
        var bgroup = svg.append("g")
          .attr("transform", "translate(100, 430)")
        var brush = d3.chart.brush()
        brush
          .data(data)
          .width(800)
        brush(bgroup)

        brush.on("filter", function(filtered) {
          console.log("filtered", filtered);

          scatter.data(filtered);
          scatter.update();
          table.data(filtered)
          table.update();
          histogram.data(filtered)
          histogram.update();


        })

        table.on("hover", function(hovered) {
          scatter.highlight(hovered)
          brush.highlight(hovered)
        })
        scatter.on("hover", function(hovered) {
          table.highlight(hovered)
          brush.highlight(hovered)
        })
        histogram.on("hover", function(hovered) {
          table.highlight(hovered)
          scatter.highlight(hovered)
          brush.highlight(hovered)
        })
      
      })

    </script>
  </body>
</html>

brush.js

if(!d3.chart) d3.chart = {};

d3.chart.brush = function() {
  var g;
  var data;
  var width = 600;
  var height = 30;
  var dispatch = d3.dispatch(chart, "filter");

  function chart(container) {
    g = container;
    
    var extent = d3.extent(data, function(d) {
      return d.data.created
    })

    var scale = d3.time.scale()
      .domain(extent)
      .range([0, width])

    var brush = d3.svg.brush()
    brush.x(scale)
    brush(g)
    g.selectAll("rect").attr("height", height)
    g.selectAll(".background")
      .style({fill: "#4B9E9E", visibility: "visible"})
    g.selectAll(".extent")
      .style({fill: "#78C5C5", visibility: "visible"})
    g.selectAll(".resize rect")
      .style({fill: "#276C86", visibility: "visible"})

    var rects = g.selectAll("rect.events")
    .data(data)
    rects.enter()
    .append("rect").classed("events", true)
    rects.attr({
      x: function(d) { return scale(d.data.created);},
      y: 0,
      width: 1,
      height: height
    }).style("pointer-events", "none")

    rects.exit().remove()

    brush.on("brushend", function() {
      var ext = brush.extent()
      var filtered = data.filter(function(d) {
        return (d.data.created > ext[0] && d.data.created < ext[1])
      })
      g.selectAll("rect.events")
      .style("stroke", "")
      
      g.selectAll("rect.events")
      .data(filtered, function(d) { return d.data.id })
      .style({
        stroke: "#fff"
      })

      //emit filtered data
      dispatch.filter(filtered)
    })

    var axis = d3.svg.axis()
    .scale(scale)
    .orient("bottom")
    .tickValues([new Date(extent[0]), new Date(extent[0] + (extent[1] - extent[0])/2) , new Date(extent[1])])
    .tickFormat(d3.time.format("%x %H:%M"))

    var agroup = g.append("g")
    agroup.attr("transform", "translate(" + [0, height] + ")")
    axis(agroup)
    agroup.selectAll("path")
      .style({ fill: "none", stroke: "#000"})
    agroup.selectAll("line")
      .style({ stroke: "#000"})
  }

  chart.highlight = function(data) {
    var rects = g.selectAll("rect.events")
    .style("stroke", "")
    .style("stroke-width", "")

    rects.data(data, function(d) { return d.data.id })
    .style("stroke", "orange")
    .style("stroke-width", 3)
  }

  chart.data = function(value) {
    if(!arguments.length) return data;
    data = value;
    return chart;
  }
  chart.width = function(value) {
    if(!arguments.length) return width;
    width = value;
    return chart;
  }
  chart.height = function(value) {
    if(!arguments.length) return height;
    height = value;
    return chart;
  }

  return d3.rebind(chart, dispatch, "on");
}

histogram.js

if(!d3.chart) d3.chart = {};

d3.chart.histogram = function() {
  var g;
  var data;
  var width = 400;
  var height = 400;
  var cx = 10;
  var numberBins = 5;
  var dispatch = d3.dispatch(chart, "hover");

  function chart(container) {
    g = container;

    update();
  }
  chart.update = update;
  function update() {

    var hist = d3.layout.histogram()
    .value(function(d) { return d.data.score })
    .range([0, d3.max(data, function(d){ return d.data.score }) ])
    .bins(numberBins);
    var layout = hist(data);

    var maxLength = d3.max(layout, function(d) { return d.length });
    var widthScale = d3.scale.linear()
    .domain([0, maxLength])
    .range([0, width])

    var yScale = d3.scale.ordinal()
    .domain(d3.range(numberBins))
    .rangeBands([height, 0], 0.1)

    var colorScale = d3.scale.category20();

    
    var rects = g.selectAll("rect")
    .data(layout)
    
    rects.enter().append("rect")

    rects
    .transition()
    .attr({
      y: function(d,i) {
        return yScale(i)
      },
      x: 50,
      height: yScale.rangeBand(),
      width: function(d,i) {
        return widthScale(d.length)
      },
      fill: function(d, i) { return colorScale(i) }
    })
    rects.exit().transition().remove();


    rects.on("mouseover", function(d) {
      d3.select(this).style("fill", "orange")
      console.log("hist over", d)
      dispatch.hover(d)
    })
    rects.on("mouseout", function(d) {
      d3.select(this).style("fill", "")
      dispatch.hover([])
    })
  }


  chart.data = function(value) {
    if(!arguments.length) return data;
    data = value;
    return chart;
  }
  chart.width = function(value) {
    if(!arguments.length) return width;
    width = value;
    return chart;
  }
  chart.height = function(value) {
    if(!arguments.length) return height;
    height = value;
    return chart;
  }

  return d3.rebind(chart, dispatch, "on");
}

scatter.js

if(!d3.chart) d3.chart = {};

d3.chart.scatter = function() {
  var g;
  var data;
  var width = 400;
  var height = 400;
  var cx = 10;
  var numberBins = 5;
  var dispatch = d3.dispatch(chart, "hover");

  function chart(container) {
    g = container;

    g.append("g")
    .classed("xaxis", true)

    g.append("g")
    .classed("yaxis", true)

    update();
  }
  chart.update = update;
  function update() {
    var maxCreated = d3.max(data, function(d) { return d.data.created });
    var minCreated = d3.min(data, function(d) { return d.data.created });
    var maxScore = d3.max(data, function(d) { return d.data.score })

    var colorScale = d3.scale.category20();
    var createdScale = d3.time.scale()
        .domain([minCreated, maxCreated])
        .range([cx, width])

    var commentScale = d3.scale.linear()
    .domain(d3.extent(data, function(d) { return d.data.num_comments }))
    .range([3, 15])

    var yScale = d3.scale.linear()
      .domain([0, maxScore])
      .range([height, cx])
  
     var xAxis = d3.svg.axis()
    .scale(createdScale)
    .ticks(3)
    .tickFormat(d3.time.format("%x %H:%M"))

    var yAxis = d3.svg.axis()
    .scale(yScale)
    .ticks(3)
    .orient("left")

    var xg = g.select(".xaxis")
      .classed("axis", true)
      .attr("transform", "translate(" + [0,height] + ")")
      .transition()
      .call(xAxis)

    var yg = g.select(".yaxis")
      .classed("axis", true)
      .classed("yaxis", true)
      .attr("transform", "translate(" + [cx - 5,0] + ")")
      .transition()
      .call(yAxis)

    var circles = g.selectAll("circle")
    .data(data, function(d) { return d.data.id })

    circles.enter()
    .append("circle")

    circles
    .transition()
    .attr({
      cx: function(d,i) { return createdScale(d.data.created) },
      cy: function(d,i) { return yScale(d.data.score) },
      r: function(d) { return commentScale(d.data.num_comments)}
    })

    circles.exit().remove()

    circles.on("mouseover", function(d) {
      d3.select(this).style("stroke", "black")
      dispatch.hover([d])
    })
    circles.on("mouseout", function(d) {
      d3.select(this).style("stroke", "")
      dispatch.hover([])
    })

    var hist = d3.layout.histogram()
    .value(function(d) { return d.data.score })
    .range([0, d3.max(data, function(d){ return d.data.score }) ])
    .bins(numberBins);
    var layout = hist(data);

    for(var i = 0; i < layout.length; i++) {
      var bin = layout[i];
      g.selectAll("circle")
      .data(bin, function(d) { return d.data.id })
      .style("fill", function() {  return colorScale(i) })
    }

  }

  chart.highlight = function(data) {
    var circles = g.selectAll("circle")
    .style("stroke", "")

    circles.data(data, function(d) { return d.data.id })
    .style("stroke", "orange")
    .style("stroke-width", 3)
  }

  chart.data = function(value) {
    if(!arguments.length) return data;
    data = value;
    return chart;
  }
  chart.width = function(value) {
    if(!arguments.length) return width;
    width = value;
    return chart;
  }
  chart.height = function(value) {
    if(!arguments.length) return height;
    height = value;
    return chart;
  }

  return d3.rebind(chart, dispatch, "on");
}

table.js

if(!d3.chart) d3.chart = {};

d3.chart.table = function() {
  var div;
  var data;
  var width;
  var dispatch = d3.dispatch(chart, "hover");
  function chart(container) {
    div = container;

    var table = container.append("table")
    update();
  }
  chart.update = update;

  function update() {
    var table = div.select("table")
    var rows = table.selectAll("tr.row")
    .data(data, function(d) { return d.data.id })

    console.log("table data", data)

    rows.exit().remove();
    var rowsEnter = rows.enter()
    .append("tr").classed("row", true)

    rowsEnter.append("td")
    .text(function(d) { return d.data.score })

    rowsEnter.append("td")
    .append("a")
    .attr({
      href: function(d) { return d.data.url }
    })
    .append("img")
    .attr({
      src: function(d) { return d.data.thumbnail }
    })

    rowsEnter.append("td")
    .append("a")
    .attr({
      href: function(d) { return d.data.url }
    }).text(function(d) { return d.data.title })

    rowsEnter.append("td")
    .text(function(d) { return d.data.ups })

    rowsEnter.append("td")
    .text(function(d) { return d.data.downs })

    

    rowsEnter.on("mouseover", function(d) {
      d3.select(this).style("background-color", "orange")
      dispatch.hover([d])
    })
    rowsEnter.on("mouseout", function(d) {
      d3.select(this).style("background-color", "")
      dispatch.hover([])
    })
  }

  chart.highlight = function(data) {
    var trs = div.selectAll("tr")
    .style("background-color", "")

    trs.data(data, function(d) { return d.data.id })
    .style("background-color", "orange")
  }

  chart.data = function(value) {
    if(!arguments.length) return data;
    data = value;
    return chart;
  }
  chart.width = function(value) {
    if(!arguments.length) return width;
    width = value;
    return chart;
  }

  return d3.rebind(chart, dispatch, "on");
}