Time in Process Scatter Chart

by Trever Shick

HTML

<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/3.3.1/lodash.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.9.0/moment.js"></script>
<link href='http://fonts.googleapis.com/css?family=Lato&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
    
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script>
    url = "https://s3.amazonaws.com/trevershick-experiments/tip.json"
</script>

<div class="well">
    <div id="chart"></div>
</div>

CSS

body {
    font-family:Lato;
}
#chart {
    width:100%;
    height:400px;
}
svg {
    display:block;
    width:100%;
    height:100%;
}
.axis {
    font-size:10px;
}
.tooltip b {
    font-size:1.1em;
    color:black;
}
.tooltip {
    color:grey;
    background-color:white;
    border-radius:4px;
    border:1px solid;
    padding: 5px;
    margin:3px;
    position :absolute;
    z-index:10;
    opacity:0;
}
.axis path {
    fill: none;
    stroke: #777;
    shape-rendering: crispEdges;
}
.axis text {
    font-size: 13px;
}

JavaScript

function rand(min, max) {
    return parseInt(Math.random() * (max-min+1), 10) + min;
}
function rc() {
    var h = rand(1, 360); // color hue between 1 and 360
    var s = 58; // saturation 30-100%
    var l = 32; // lightness 30-70%
    return 'hsl(' + h + ',' + s + '%,' + l + '%)';
}
var tooltip = d3.select("body")
	.append("div")
    .style("border-color", rc())
    .attr("class","tooltip")
	.text("a simple tooltip");

var template = _.template(
    "<b><%=d.Name%></b><br/>"
    + "Days in Process:  <%=ip%><br/>"
    + "PlanEstimate: <%=d.PlanEstimate%><br/>"
    + "on <%=when%>");

function tooltipFormatter(d) {
    return template({
        d:d,
        ip: d.daysInProcess ? d.daysInProcess : Math.round(d.hoursInProcess/24*10)/10,
        when:moment(d._ValidFrom).format("YYYY-MM-DD")});
}

var svg = d3.select("#chart").append("svg");

var margin= 20;
var margins = { top: 20, right:20, bottom:20, left:20 },
    w = $(svg).parent().width(),
    h = $(svg).parent().height() - (margins.top + margins.bottom);



function onData(data) {
    data.Results.forEach(function(row) {
        var d = new Date(row._ValidFrom);
        row.vf = d.getUTCFullYear() * 10000 + d.getUTCMonth() * 100  + d.getUTCDate();
        
        var dt = new Date(row._ValidTo);
        if (dt.getUTCFullYear() >= 3000) {
            dt = d;
            row._ValidTo = row._ValidFrom;
        }
        row.vt = dt.getUTCFullYear() * 10000 + dt.getUTCMonth() * 100  + dt.getUTCDate();
    });

    var minDate = d3.min(data.Results, function(d) { return d._ValidFrom; });
    var maxDate = d3.max(data.Results, function(d) { return d._ValidTo; });
    

    var grouped = d3.nest()
        .key(function(d) { return d.ObjectID; })
        .entries(data.Results);

    grouped.forEach(function(g) {
        g.ObjectID = g.values[0].ObjectID;
        g._ValidFrom = d3.min(g.values, function(v) { return v._ValidFrom; });
        g._ValidTo = d3.max(g.values, function(v) { return v._ValidTo; });
       ...