JSFiddle - React, Tailwind, and code Playground

by rwhal06

HTML

<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<script src="//d3js.org/d3.v4.min.js"></script>
<div class="d3Chart" id="mChart" data-parameter="cm" data-value="30" data-type="bigDollars" data-xAxisLabel="x" data-xAxisFormat="$.2f" data-yAxisLabel="y" data-yAxisFormat="$.2f" data-restrict="Math.max(3e4, Math.min(3e6, d3.round(v < 1000 ? v * 1000 : v, -3)))"
data-scale="d3.scale.log().domain([3e4, 3e6])" data-scale-format="$s" data-height="240">
  
</div>
<h3>
My chart above is on its way to looking and behaving like Bostock's (below) but needs these additional features:
</h3>
<ol>
  <li>handle should move when dragged</li>
  <li>After dragging, input box val should be adjusted and formatted to make sense</li>
  <li>On change of input box value, attr data-value and charts should update</li>
  <li>There should be a y-value tooltip that is dynamically updated</li>
</ol>
<a href="https://www.nytimes.com/interactive/2014/upshot/buy-rent-calculator.html" target="_blank">(link to Bostock's)</a>
<a href="https://www.nytimes.com/interactive/2014/upshot/buy-rent-calculator.html" target="_blank"><img src="http://i.imgur.com/XOCLWJE.png" /></a>

SCSS

.chartTitle{
    font-weight: bold;
    font-size: 14px;
    position: relative;
    top: 100px;
}
.bar {
    fill: steelblue;
    &:hover {
        fill: brown;
    }
}
.axisLabel{
    font-size: 18px;
    font-weight: bold;
}

.ticks {
    font: 10px sans-serif;
}

.track,
.track-inset,
.track-overlay {
    stroke-linecap: round;
}
$trackStroke: 8px;
.track {
    stroke: #000;
    stroke-opacity: 0.3;
    stroke-width: $trackStroke;
}

.track-inset {
    stroke: #ddd;
    stroke-width: $trackStroke - 2;
}

.track-overlay {
    pointer-events: stroke;
    stroke-width: 50px;
    cursor: ew-resize;
}

.handle {
    fill: #fff;
    stroke: #000;
    stroke-opacity: 0.5;
    stroke-width: 1.25px;
    cursor: ew-resize;
    user-select: none;
    pointer-events: none;
}

.line {
    fill: none;
    stroke: black;
    stroke-width: 2px;
}

.grid {
    line {
        stroke: white;
        stroke-opacity: 0.7;
        shape-rendering: crispEdges;
    }
    path {
        stroke-width: 0;
    }
}
.g-parameter-input{
    position: relative;
    left: -230px;
    display: inline;
    min-width: 160px;
    input{
        padding: 4px 0;
        width: 40px;
        margin: auto;

    }
}
.g-parameter-tip {
    z-index: 1;
    pointer-events: none;
    position: absolute;
    left: 50%;
    text-anchor: middle;
    path {
        fill: hsl(69, 91%, 44%);
    }
}

JavaScript

$(document).ready(function() {
   function getData() {
     var a = 0.04;
     var data = [];
     for (var b = 8; b <= 50; b = b + 1) {
       data.push({
         xVar: b,
         yVar: b / a
       });
     }
     return data;
   }

   function drawChart(selector, data) {
     var chartEl = d3.select(selector);
     var xAxisLabel = chartEl.attr("data-xAxisLabel");
     var xAxisFormat = chartEl.attr("data-xAxisFormat");
     var yAxisLabel = chartEl.attr("data-yAxisLabel");
     var yAxisFormat = chartEl.attr("data-yAxisFormat");
     chartEl.selectAll("*").remove();
     var svg = chartEl.append("svg");
     svg.attr('width', 350).attr('height', 300).attr('viewBox', '0 0 350 300');
     var margin = {
       top: 50,
       right: 20,
       bottom: 40,
       left: 70
     };
     var width = +svg.attr("width") - margin.left - margin.right;
     var height = +svg.attr("height") - margin.top - margin.bottom;
     var sliderTop = 0 + height + margin.top;
     var xBandScale = d3.scaleBand().rangeRound([0, width]).padding(0.1);
     var xAxisScale = d3.scaleLinear().rangeRound([0, width]); //TODO: allow log scale via attr
     var yAxisScale = d3.scaleLinear().rangeRound([height, 0]);
     var g = svg.append("g")
       .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
     xBandScale.domain(data.map(function(d) {
       return d.xVar;
     }));
     xAxisScale.domain([d3.min(data, function(d) {
       return d.xVar;
     }), d3.max(data, function(d) {
       return d.xVar;
     })]);
     yAxisScale.domain([d3.min(data, function(d) {
       return d.yVar;
     }), d3.max(data, function(d) {
       return d.yVar;
     })]);
     var yTicks = 6;
     var gX = g.append("g") //add x-axis
       .attr("class", "axis axis--x")
       .attr("transform", "translate(0," + height + ")")
       .call(d3.axisBottom(xAxisScale).ticks(5, xAxisFormat));
     g.append("text") //add x-axis label
       .attr("class", "axisLabel xAxisLabel")
      ...