block by wboykinm 1a2806d828cb3fa64c4d

One-handled #d3js brush, as magnitude selector on a data distribution

Full Screen

index.html

<!DOCTYPE html>
<meta charset="utf-8">
<head>
<link href="roc.css" rel="stylesheet"/>
<link href='//fonts.googleapis.com/css?family=Rajdhani' rel='stylesheet' type='text/css'>
</head>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="roc.js"></script>

</body>
</html>

roc.css

body {
  font-family: 'Rajdhani', sans-serif;
}
.rocChart {
  position: relative;
  font-size: 1.1rem;
  width: 100%; 
}
.rocChart .roc {
  fill: #87CEFF;
  stroke-width: 0px;
  fill-opacity: 1; 
}
.rocChart .baseline {
  fill: none;
  stroke: #333;
  stroke-width: 0; 
}
.rocChart .brush .extent {
  fill-opacity: 1;
  fill: #49ada6;
  shape-rendering: crispEdges;
}
.rocChart .brush .resize {
  stroke: transparent;
  stroke-width: 20;
  fill: #666; 
}

roc.js

    // Default roc curve
    var rocData = {"roc":[[0,0,0],[0.011360850020433183,0.1520501138952164,14344],[0.029015120555782592,0.2667995444191344,28413],[0.04675112382509195,0.3604783599088838,42773],[0.07592970984879444,0.45074031890660593,57789],[0.12071924805884757,0.5472665148063781,73212],[0.18422558234572947,0.6463553530751709,88373],[0.2804250102165917,0.7428815489749431,103470],[0.43261136085002044,0.8288724373576309,118368],[0.639967306906416,0.9245444191343963,133392],[1.0,1.0,148430]],"campaign_id":null};

    // Dimensions
    var margin = {top: 20, right: 10, bottom: 10, left: 10},
      width = 380,
      chartRatio = 1,
      height = width * chartRatio;

    // Normalize x and y scales as 0-1
    var x = d3.scale.linear()
      .domain([0, d3.max(rocData.roc, function(d){
        return d[1] - d[0];
      })])
      .range([0, width/3]);
    var y = d3.scale.linear()
      .domain([0, 1])
      .range([0, height - margin.top - margin.bottom]);
    
    // Define dimensions and place svg
    var svg = d3.select("body").append("svg")
      .attr("class","rocChart")
      .attr("width", width)
      .attr("height", height + margin.top + margin.bottom);

    // Define the area
    var area = d3.svg.area()
      .y(function(d) { return y(d[0]); })
      .x1(function(d) { return x(d[1] - d[0]); })
      .interpolate("basis");

    // Add the area to the chart, populated with the data
    svg.append("path")
      .datum(rocData.roc)
      .attr("class", "roc")
      .attr("d", area)
      .attr("transform", "translate(" + (width/3 + margin.left) + "," + margin.top + ")");

    // Add the brush to the Y axis, set to 10% of the extent
    var brush = d3.svg.brush()
      .y(y)
      .extent([0,0.1])
      .on("brushend", function(){
        brushg.selectAll(".resize.s")
          .style("display","inline")
      });

    // Tack the brush onto a group element
    var brushg = svg.append("g")
      .attr('class', 'brush')
      .attr('height', height)
      .attr("transform", "translate(" + (width/3) + "," + margin.top + ")")
      .call(brush);

    // Set the brush to non-clickable
    brushg.selectAll("rect")
      .style("pointer-events","none");

    // Disable the top brush handle
    brushg.selectAll(".resize.n")
      .style("pointer-events","none");

    // Add a circle to the bottom of the brush
    brushg.selectAll(".resize.s")
      .append('circle')
        .attr("cx", -19)
        .attr("cy", 0)
        .attr("r", 4);

    // Move everything over 20 pixels from the ROC curve area
    brushg.selectAll("rect")
      .attr("width", 2)
      .attr({transform: 'translate(-20,0)'}); 

    // Add a "sliding track" line to the brush
    var yLine = brushg.append("line")
      .attr("y1", 0)
      .attr("y2", height - margin.top - margin.bottom)
      .attr("stroke-width", 0.5)
      .attr("stroke", "#666")
      .attr("transform", "translate(-19,0)");

    // Add a horizonal line to the lower brush end to show curve intersection
    brushg.selectAll(".resize.s")
      .append("line")
        .attr("x1", -width/3)
        .attr("x2", width/3*2)
        .attr("stroke-width", 0.5)
        .attr("stroke", "#999");

    // Add guidance text to right side of chart
    svg.append('foreignObject')
      .attr("x", width - 100)
      .attr("y", margin.top/2)
      .attr('width', 100 - margin.right)
      .attr('height', 100)
      .append("xhtml:div")
        .attr('class', 'labelContainer')
        .html('<p class="rocLabel right">Taller</p>');
    svg.append('foreignObject')
      .attr("x", width - 100)
      .attr("y", height - margin.bottom)
      .attr('width', 100 - margin.right)
      .attr('height', 100)
      .append("xhtml:div")
        .attr('class', 'labelContainer')
        .html('<p class="rocLabel right">Shorter</p>');

    // Add range text to left side of chart
    svg.append('text')
      .attr("x", margin.left)
      .attr("y", margin.top)
      .style("text-anchor", "left")
      .attr('class', 'rocLabel')
      .text("0 Buildings");
    svg.append('text')
      .attr("x", margin.left)
      .attr("y", height + margin.bottom)
      .style("text-anchor", "left")
      .attr('class', 'rocLabel maxTargets')
      .text("1000 Buildings");