Built with blockbuilder.org
Created
February 7, 2020 12:41
-
-
Save mohamedkhanafer/a3740e7a89c1a6930ce2357a595b6cdb to your computer and use it in GitHub Desktop.
fresh block
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
| license: mit |
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><head> | |
| <style> | |
| /* #Reset & Basics (Inspired by E. Meyers) | |
| ================================================== */ | |
| { | |
| margin: 0; | |
| padding: 0; | |
| border: 0; | |
| font-size: 100%; | |
| font: inherit; | |
| vertical-align: baseline; } | |
| ///CAN REMOVE: | |
| article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { | |
| display: block; } | |
| body { | |
| line-height: 1; } | |
| ol, ul { | |
| list-style: none; } | |
| blockquote, q { | |
| quotes: none; } | |
| blockquote:before, blockquote:after, | |
| q:before, q:after { | |
| content: ''; | |
| content: none; } | |
| table { | |
| border-collapse: collapse; | |
| border-spacing: 0; } | |
| #main-wrapper { | |
| font-family: 'Inconsolata', Monaco, "Lucida Console", Consolas, "Courier New"; | |
| font-size: 15px; | |
| width: 1200px; | |
| } | |
| #sidebar { | |
| width: 250px; | |
| float: left; | |
| margin-right: 30px; | |
| margin-top:50px; | |
| padding-right: 20px; | |
| border-right: 1px solid #ccc; | |
| height: 800px; | |
| text-align: center; | |
| } | |
| #current_time { | |
| font-size: 25px; | |
| color: #666; | |
| text-align: center; | |
| } | |
| #chart { float: left; } | |
| #speed { | |
| font-family: 'Inconsolata', Monaco, "Lucida Console", Consolas, "Courier New"; | |
| font-size: 13px; | |
| text-transform: uppercase; | |
| margin: 15px 0 20px 25px; | |
| } | |
| #speed .togglebutton { | |
| padding: 3px 3px; | |
| text-align: center; | |
| border: 1px solid #ccc; | |
| cursor: pointer; | |
| float: left; | |
| width: 60px; | |
| } | |
| #speed .togglebutton.slow { | |
| border-right: none; | |
| } | |
| #speed .togglebutton.fast { | |
| border-left: none; | |
| } | |
| #speed .togglebutton.current { | |
| color: #fff; | |
| background: #000; | |
| border: 1px solid #000; | |
| } | |
| #note { | |
| position: relative; | |
| color: #fff; | |
| padding-left: 5px; | |
| font-family: "Mercury SSm A", "Mercury SSm B"; | |
| font-style: italic; | |
| font-weight: 400; | |
| font-size: 14px; | |
| line-height: 1.4em; | |
| } | |
| #cite { | |
| position: absolute; | |
| border-top: 1px solid #ccc; | |
| padding-top: 20px; | |
| top: 640px; | |
| font-size: 12px; | |
| line-height: 1.4em; | |
| width: 259px; | |
| } | |
| circle { | |
| /* display: none;*/ | |
| } | |
| .line { | |
| /* fill: none;*/ | |
| /* stroke: #000;*/ | |
| stroke-width: 0.1px; | |
| } | |
| a { | |
| color: #821122; | |
| text-decoration: none; | |
| border-bottom: 1px solid #ccc; | |
| } | |
| a:hover { | |
| border-bottom: 1px solid #821122; | |
| } | |
| .clr { clear: both; } | |
| </style></head> | |
| <body> | |
| <div id="main-wrapper"> | |
| <div id="sidebar"> | |
| <div id="current_time"></div> | |
| <div id="speed"> | |
| <div class="togglebutton slow current" data-val="slow">Slow</div> | |
| <div class="togglebutton medium" data-val="medium">Fast</div> | |
| <div class="togglebutton fast" data-val="fast">Pause</div> | |
| <div class="clr"></div> | |
| </div> | |
| <div id="note" style="top: 20px; color: rgb(0, 0, 0);"></div> | |
| <div id="cite"> | |
| This is an animation for showing the cycle of a pregnant woman</div> | |
| </div> | |
| <div id="chart"><svg width="220" height="50"> | |
| <div class="clr"></div> | |
| </div> | |
| <script src="js/d3-3-5-5.min.js"></script> | |
| <!-- Connecting with D3 library--> | |
| <script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script> | |
| <script> | |
| var USER_SPEED = "slow"; | |
| var width = 800, | |
| height = 800, | |
| padding = 1, | |
| maxRadius = 3; | |
| // color = d3.scale.category10(); | |
| var sched_objs = [], | |
| curr_minute = 0; | |
| var act_codes = [ | |
| {"index": "1", "short": "Sleeping", "desc": "Sleeping"}, | |
| {"index": "2", "short": "Work/Commute", "desc": "Work/Commute"}, | |
| {"index": "3", "short": "Free Time", "desc": "Free Time"}, | |
| {"index": "4", "short": "Nursing / Pumping", "desc": "Nursing / Pumping"}, | |
| {"index": "5", "short": "Take Care of Baby", "desc": "Taking Care of Baby"} | |
| ]; | |
| /// here we are defining how fast are the 3 different options: | |
| var speeds = { "slow": 70, "medium": 30, "fast": 10000 }; | |
| var time_notes = [ | |
| { "start_minute": 1, "stop_minute": 60, "note": "The animation starts with data based on a graph by @beeonaposy." }, | |
| { "start_minute": 90, "stop_minute": 180, "note": "In the pre-baby phase, the routine is normally split between work, sleep, and free time." }, | |
| { "start_minute": 240, "stop_minute": 320, "note": "The baby has arrived!" }, | |
| { "start_minute": 360, "stop_minute": 440, "note": " The typical day activities are now more devoted to the baby." }, | |
| { "start_minute": 480, "stop_minute": 540, "note": "In this month, the baby requires a little less nursing." }, | |
| { "start_minute": 580, "stop_minute": 640, "note": "Do not forget that in Month 1 and 2, the mother is on maternal leave." }, | |
| { "start_minute": 720, "stop_minute": 780, "note": "Time to get back to work." }, | |
| { "start_minute": 850, "stop_minute": 910, "note": "Older baby, a bit more free time." }, | |
| { "start_minute": 960, "stop_minute": 1030, "note": "Back to a routine with a baby in the equation." }, | |
| ]; | |
| var notes_index = 0; | |
| // Activity to put in center of circle arrangement | |
| var center_act = "Sleeping", | |
| center_pt = { "x": 380, "y": 365 }; | |
| // Coordinates for activities | |
| var foci = {}; | |
| act_codes.forEach(function(code, i) { | |
| if (code.desc == center_act) { | |
| foci[code.index] = center_pt; | |
| } else { | |
| var theta = 2 * Math.PI / (act_codes.length-1); | |
| foci[code.index] = {x: 250 * Math.cos(i * theta)+380, y: 250 * Math.sin(i * theta)+365 }; | |
| } | |
| }); | |
| // Start the SVG | |
| var svg = d3.select("#chart").append("svg") | |
| .attr("width", width) | |
| .attr("height", height); | |
| //Data loading | |
| d3.csv('https://gist.githubusercontent.com/mohamedkhanafer/c98be5b6981264a6d8054a0ae0436898/raw/ef9513e446b4f510cf6466fd4083c703987d36fc/gistfile1.txt', function(data) { | |
| data.forEach(function(d) { | |
| var day_array = d.day.split(","); | |
| var activities = []; | |
| for (var i=0; i < day_array.length; i++) { | |
| // Duration | |
| if (i % 2 == 1) { | |
| activities.push({'act': day_array[i-1], 'duration': +day_array[i]}); | |
| } | |
| } | |
| sched_objs.push(activities); | |
| }); | |
| // Used for percentages by minute | |
| var act_counts = {"1": 0, "2": 0, "3": 0, "4": 0, "5": 0}; | |
| // A node for each person's schedule | |
| var nodes = sched_objs.map(function(o,i) { | |
| var act = o[0].act; | |
| act_counts[act] += 1; | |
| var init_x = foci[act].x + Math.random(); | |
| var init_y = foci[act].y + Math.random(); | |
| return { | |
| act: act, | |
| radius: 6, | |
| x: init_x, | |
| y: init_y, | |
| color: color(act), | |
| moves: 0, | |
| next_move_time: o[0].duration, | |
| sched: o, | |
| } | |
| }); | |
| var force = d3.layout.force() | |
| .nodes(nodes) | |
| .size([width, height]) | |
| // .links([]) | |
| .gravity(0) | |
| .charge(0) | |
| .friction(.9) | |
| .on("tick", tick) | |
| .start(); | |
| var circle = svg.selectAll("circle") | |
| .data(nodes) | |
| .enter().append("circle") | |
| .attr("r", function(d) { return d.radius; }) | |
| .style("fill", function(d) { return d.color; }); | |
| // .call(force.drag); | |
| // Activity labels | |
| var label = svg.selectAll("text") | |
| .data(act_codes) | |
| .enter().append("text") | |
| .attr("class", "actlabel") | |
| .attr("x", function(d, i) { | |
| if (d.desc == center_act) { | |
| return center_pt.x; | |
| } else { | |
| var theta = 2 * Math.PI / (act_codes.length-1); | |
| return 340 * Math.cos(i * theta)+380; | |
| } | |
| }) | |
| .attr("y", function(d, i) { | |
| if (d.desc == center_act) { | |
| return center_pt.y; | |
| } else { | |
| var theta = 2 * Math.PI / (act_codes.length-1); | |
| return 340 * Math.sin(i * theta)+365; | |
| } | |
| }); | |
| label.append("tspan") | |
| .attr("x", function() { return d3.select(this.parentNode).attr("x"); }) | |
| // .attr("dy", "1.3em") | |
| .attr("text-anchor", "middle") | |
| .text(function(d) { | |
| return d.short; | |
| }); | |
| label.append("tspan") | |
| .attr("dy", "1.3em") | |
| .attr("x", function() { return d3.select(this.parentNode).attr("x"); }) | |
| .attr("text-anchor", "middle") | |
| .attr("class", "actpct") | |
| .text(function(d) { | |
| return act_counts[d.index] + "%"; | |
| }); | |
| // Update nodes based on activity and duration | |
| function timer() { | |
| d3.range(nodes.length).map(function(i) { | |
| var curr_node = nodes[i], | |
| curr_moves = curr_node.moves; | |
| // Time to go to next activity | |
| if (curr_node.next_move_time == curr_minute) { | |
| if (curr_node.moves == curr_node.sched.length-1) { | |
| curr_moves = 0; | |
| } else { | |
| curr_moves += 1; | |
| } | |
| // Subtract from current activity count | |
| act_counts[curr_node.act] -= 1; | |
| // Move on to next activity | |
| curr_node.act = curr_node.sched[ curr_moves ].act; | |
| // Add to new activity count | |
| act_counts[curr_node.act] += 1; | |
| curr_node.moves = curr_moves; | |
| curr_node.cx = foci[curr_node.act].x; | |
| curr_node.cy = foci[curr_node.act].y; | |
| nodes[i].next_move_time += nodes[i].sched[ curr_node.moves ].duration; | |
| } | |
| }); | |
| force.resume(); | |
| curr_minute += 1; | |
| // Update percentages | |
| label.selectAll("tspan.actpct") | |
| .text(function(d) { | |
| return readablePercent(act_counts[d.index]); | |
| }); | |
| // Update time | |
| var true_minute = curr_minute % 1440; | |
| d3.select("#current_time").text(minutesToTime(true_minute)); | |
| // Update notes | |
| // var true_minute = curr_minute % 1440; | |
| if (true_minute == time_notes[notes_index].start_minute) { | |
| d3.select("#note") | |
| .style("top", "0px") | |
| .transition() | |
| .duration(600) | |
| .style("top", "20px") | |
| .style("color", "#000000") | |
| .text(time_notes[notes_index].note); | |
| } | |
| // Make note disappear at the end. | |
| else if (true_minute == time_notes[notes_index].stop_minute) { | |
| d3.select("#note").transition() | |
| .duration(1000) | |
| .style("top", "300px") | |
| .style("color", "#ffffff"); | |
| notes_index += 1; | |
| if (notes_index == time_notes.length) { | |
| notes_index = 0; | |
| } | |
| } | |
| setTimeout(timer, speeds[USER_SPEED]); | |
| } | |
| setTimeout(timer, speeds[USER_SPEED]); | |
| function tick(e) { | |
| var k = 0.04 * e.alpha; | |
| // Push nodes toward their designated focus. | |
| nodes.forEach(function(o, i) { | |
| var curr_act = o.act; | |
| // Make sleep more sluggish moving. | |
| if (curr_act == "0") { | |
| var damper = 0.6; | |
| } else { | |
| var damper = 0.5; | |
| } | |
| o.color = color(curr_act); | |
| o.y += (foci[curr_act].y - o.y) * k * damper; | |
| o.x += (foci[curr_act].x - o.x) * k * damper; | |
| }); | |
| circle | |
| .each(collide(.5)) | |
| .style("fill", function(d) { return d.color; }) | |
| .attr("cx", function(d) { return d.x; }) | |
| .attr("cy", function(d) { return d.y; }); | |
| } | |
| // Resolve collisions between nodes. | |
| function collide(alpha) { | |
| var quadtree = d3.geom.quadtree(nodes); | |
| return function(d) { | |
| var r = d.radius + maxRadius + padding, | |
| nx1 = d.x - r, | |
| nx2 = d.x + r, | |
| ny1 = d.y - r, | |
| ny2 = d.y + r; | |
| quadtree.visit(function(quad, x1, y1, x2, y2) { | |
| if (quad.point && (quad.point !== d)) { | |
| var x = d.x - quad.point.x, | |
| y = d.y - quad.point.y, | |
| l = Math.sqrt(x * x + y * y), | |
| r = d.radius + quad.point.radius + (d.act !== quad.point.act) * padding; | |
| if (l < r) { | |
| l = (l - r) / l * alpha; | |
| d.x -= x *= l; | |
| d.y -= y *= l; | |
| quad.point.x += x; | |
| quad.point.y += y; | |
| } | |
| } | |
| return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1; | |
| }); | |
| }; | |
| } | |
| // Speed toggle | |
| d3.selectAll(".togglebutton") | |
| .on("click", function() { | |
| if (d3.select(this).attr("data-val") == "slow") { | |
| d3.select(".slow").classed("current", true); | |
| d3.select(".medium").classed("current", false); | |
| d3.select(".fast").classed("current", false); | |
| } else if (d3.select(this).attr("data-val") == "medium") { | |
| d3.select(".slow").classed("current", false); | |
| d3.select(".medium").classed("current", true); | |
| d3.select(".fast").classed("current", false); | |
| } | |
| else { | |
| d3.select(".slow").classed("current", false); | |
| d3.select(".medium").classed("current", false); | |
| d3.select(".fast").classed("current", true); | |
| } | |
| USER_SPEED = d3.select(this).attr("data-val"); | |
| }); | |
| }); // @end d3.tsv | |
| function color(activity) { | |
| var colorByActivity = { | |
| "0": "#e0d400", | |
| "1": "#1c8af9", | |
| "2": "#51BC05", | |
| "3": "#FF7F00", | |
| "4": "#DB32A4", | |
| "5": "#00CDF8", | |
| } | |
| return colorByActivity[activity]; | |
| } | |
| var d3Graph = d3.select('svg') | |
| var dropShadowFilter = d3Graph.append('svg:filter') | |
| .attr('id', 'drop-shadow') | |
| .attr('filterUnits', "userSpaceOnUse") | |
| .attr('width', '250%') | |
| .attr('height', '250%'); | |
| dropShadowFilter.append('svg:feGaussianBlur') | |
| .attr('in', 'SourceGraphic') | |
| .attr('stdDeviation', 2) | |
| .attr('result', 'blur-out'); | |
| dropShadowFilter.append('svg:feColorMatrix') | |
| .attr('in', 'blur-out') | |
| .attr('type', 'hueRotate') | |
| .attr('values', 180) | |
| .attr('result', 'color-out'); | |
| dropShadowFilter.append('svg:feOffset') | |
| .attr('in', 'color-out') | |
| .attr('dx', 3) | |
| .attr('dy', 3) | |
| .attr('result', 'the-shadow'); | |
| dropShadowFilter.append('svg:feBlend') | |
| .attr('in', 'SourceGraphic') | |
| .attr('in2', 'the-shadow') | |
| .attr('mode', 'normal'); | |
| var simpleGradient = d3Graph.append('defs') | |
| .append('radialGradient') | |
| .attr('id', 'fake-shadow'); | |
| simpleGradient.append('stop') | |
| .attr('offset', "80%") | |
| .attr('stop-color', '#01AFAF'); | |
| simpleGradient.append('stop') | |
| .attr('offset', "100%") | |
| .attr('stop-color', "#01AFAF00"); | |
| // Output readable percent based on count. | |
| function readablePercent(n) { | |
| var pct = 100 * n / 100; | |
| if (pct < 1 && pct > 0) { | |
| pct = "<1%"; | |
| } else { | |
| pct = Math.round(pct) + "%"; | |
| } | |
| return pct; | |
| } | |
| // Minutes to time of day. Data is minutes from 4am. | |
| function minutesToTime(m) { | |
| var minutes = (m + 4*60) % 1440; | |
| var hh = Math.floor(minutes / 60); | |
| var ampm; | |
| if (hh > 12) { | |
| hh = hh - 12; | |
| ampm = "pm"; | |
| } else if (hh == 12) { | |
| ampm = "pm"; | |
| } else if (hh == 0) { | |
| hh = 12; | |
| ampm = "am"; | |
| } else { | |
| ampm = "am"; | |
| } | |
| var mm = minutes % 60; | |
| if (mm < 10) { | |
| mm = "0" + mm; | |
| } | |
| run=hh + ampm | |
| if(run=="4am" || run=="5am" || run=="6am"|| run=="7am") | |
| return "Pre-pregnancy" | |
| else if (run=="8am" || run=="9am" || run=="10am" ||run=="11am") | |
| return "1 Month old Baby"; | |
| else if (run=="12pm" || run=="1pm" || run=="2pm" || run=="3pm") | |
| return "2 Months old Baby"; | |
| else if (run=="4pm" || run=="5pm" || run=="6pm" || run=="7pm") | |
| return "3 Months old Baby"; | |
| else if (run=="8pm" || run=="9pm" || run=="10pm" || run=="11pm") | |
| return "4 Months old Baby"; | |
| else if (run=="12am" || run=="1am" || run=="2am" || run=="3am") | |
| return "5-6 Months old Baby" | |
| } | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment