Last active
January 13, 2017 18:29
-
-
Save jgeryk/5a50c30125a142650c4fa73950cc9701 to your computer and use it in GitHub Desktop.
Date/Hours Prototype Spline w/ Balancing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!doctype html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <title>Volume Control</title> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.4.0/d3.min.js" charset="utf-8"></script> | |
| <style> | |
| body { | |
| font: 13px sans-serif; | |
| position: relative; | |
| width: 960px; | |
| height: 500px; | |
| } | |
| .axis text { | |
| font: 10px sans-serif; | |
| } | |
| .axis path, | |
| .axis line { | |
| fill: none; | |
| stroke: #000; | |
| shape-rendering: crispEdges; | |
| } | |
| path { | |
| stroke: steelblue; | |
| stroke-width: 2; | |
| fill: none; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <script> | |
| var budgetedHours = 50; | |
| var now = new Date | |
| var future = new Date | |
| future = future.setDate(future.getDate() + 7) | |
| // set the dimensions and margins of the graph | |
| var margin = {top: 20, right: 20, bottom: 50, left: 70}, | |
| width = 960 - margin.left - margin.right, | |
| height = 500 - margin.top - margin.bottom; | |
| var x = d3.scaleTime() | |
| .domain([now, future]) | |
| .nice() | |
| .range([0, width]) | |
| var xAxis = d3.axisBottom(x).ticks(8) | |
| var dates = xAxis.scale().ticks(xAxis.ticks()[0]) | |
| var data = dates.map(function(d, i){ return {date: d, hours: budgetedHours/dates.length, percent: 100/dates.length, index: i } }); | |
| var scaleMax = 12 | |
| console.log(data) | |
| var dragged = null, | |
| selected = null | |
| d3.select(window) | |
| .on("mousemove", mousemove) | |
| .on("mouseup", mouseup) | |
| .on("keydown", keydown); | |
| var valueline = d3.line() | |
| .x(function(d) { return x(d.date); }) | |
| .y(function(d) { return y(d.hours); }) | |
| .curve(d3.curveCardinal); | |
| // valueline.interpolate('cardinal-open') | |
| var y = d3.scaleLinear().range([0, height]).domain([scaleMax, 0]) | |
| 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 + ")"); | |
| svg.append("g") | |
| .attr("transform", "translate(0," + height + ")") | |
| // .call(d3.axisLeft(y)) | |
| .call(xAxis) | |
| svg.append("g") | |
| .call(d3.axisLeft(y)) | |
| function redraw(){ | |
| var line = svg.append("path") | |
| .data([data]) | |
| .attr("class", "line") | |
| .attr("d", valueline) | |
| .on("mousedown", function(d){ selected = dragged = d; }); | |
| svg.selectAll("dot") | |
| .data(data) | |
| .enter().append("circle") | |
| .attr("r", 10) | |
| .attr("cx", function(d) { return x(d.date); }) | |
| .attr("cy", function(d) { return y(d.hours); }) | |
| .on("mousedown", function(d){ selected = dragged = d; }); | |
| } | |
| function mousedown() { | |
| console.log('mousedown') | |
| } | |
| function mousemove() { | |
| if(!dragged) return; | |
| else { | |
| var m = d3.mouse(svg.node()); | |
| // getDay(m[0]) | |
| day = dragged | |
| oldPct = day.percent | |
| day.hours = scaleHours(m[1]) | |
| day.percent = 100*day.hours/budgetedHours | |
| balance(data, dragged.index, oldPct) | |
| // dragged[1] = Math.max(0, Math.min(height, m[1])); | |
| svg.select('.line').remove() | |
| svg.selectAll('.dot').remove() | |
| svg.selectAll('circle').remove() | |
| redraw(); | |
| } | |
| } | |
| function mouseup() { | |
| if(!dragged) return; | |
| // mousemove(); | |
| dragged = null; | |
| } | |
| function keydown(){ | |
| console.log('keydown') | |
| } | |
| redraw() | |
| function getDay(xPos){ | |
| dayLength = width / data.length | |
| return data[Math.round((xPos/dayLength) - 0.8)] | |
| } | |
| function scaleHours(yPos){ | |
| var invertedPct = 1-(yPos / height) | |
| var hours = invertedPct * scaleMax | |
| return hours < 0 ? 0 : (hours > scaleMax ? scaleMax : hours) | |
| } | |
| function balance(array, index, oldPct){ | |
| var div = 1 - oldPct / 100 | |
| var balancedPct = array[index].percent | |
| for(var i=0; i<array.length; i++){ | |
| if (i != index){ | |
| array[i].percent = 100 * (((1 - (balancedPct / 100)) * (array[i].percent / 100)) / div); | |
| array[i].hours = budgetedHours * array[i].percent/100 | |
| } | |
| } | |
| return array | |
| } | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment