An updated version of Guess The Ratio.
TODO:
- Experiment with voronoi vs. large (hidden) mouseover circles
| license: mit | 
An updated version of Guess The Ratio.
TODO:
| <!DOCTYPE html> | |
| <head> | |
| <meta charset="utf-8"> | |
| <script src="https://d3js.org/d3.v4.min.js"></script> | |
| <style> | |
| body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
| .drag-dot { | |
| cursor: -webkit-grab; | |
| } | |
| .outer-line { | |
| stroke-linecap: round; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <script> | |
| var margin = {top: 50, right: 100, bottom: 50, left: 100}; | |
| var width = 960 - margin.left - margin.right, | |
| height = 500 - margin.top - margin.bottom; | |
| 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 + ")"); | |
| var defs = svg.append("defs"); | |
| var filter = defs.append("filter") | |
| .attr("id", "glow"); | |
| filter.append("feGaussianBlur") | |
| .attr("class", "blur") | |
| .attr("stdDeviation", 0.75) | |
| .attr("result","coloredBlur"); | |
| var feMerge = filter.append("feMerge"); | |
| feMerge.append("feMergeNode") | |
| .attr("in","coloredBlur"); | |
| feMerge.append("feMergeNode") | |
| .attr("in","SourceGraphic"); | |
| var dragbehaviour = d3.drag() | |
| .on("start", dragstarted) | |
| .on("drag", dragged) | |
| .on("end", dragended); | |
| var config = { | |
| radius: 13, | |
| strokeWidth: 4 | |
| }; | |
| var dots = [ | |
| {position: "lowest", x: width / 4, colour: d3.interpolateMagma(0.25)}, | |
| {position: "median", x: width / 2, colour: d3.interpolateMagma(0.5)}, | |
| {position: "highest", x: width * 3 / 4, colour: d3.interpolateMagma(0.75)} | |
| ]; | |
| var outerLine = svg.append("line") | |
| .attr("class", "outer-line") | |
| .attr("x1", 0) | |
| .attr("x2", width) | |
| .attr("y1", height / 2) | |
| .attr("y2", height / 2) | |
| .style("stroke", "#e0e0e0") | |
| .style("stroke-width", config.strokeWidth + 1); | |
| var innerLine = svg.append("line") | |
| .attr("class", "inner-line") | |
| .attr("x1", dots[0].x) | |
| .attr("x2", dots[dots.length - 1].x) | |
| .attr("y1", height / 2) | |
| .attr("y2", height / 2) | |
| .style("stroke", "#ee8476") | |
| .style("stroke-width", config.strokeWidth + 3); | |
| var dotGroup = svg.append("g"); | |
| var bgDots = dotGroup.selectAll("circle") | |
| .data(dots) | |
| .enter().append("circle") | |
| .attr("cx", d => d.x) | |
| .attr("cy", height / 2) | |
| .attr("r", config.radius) | |
| .style("fill", "white"); | |
| var dragDots = dotGroup.selectAll("circle.drag-dot") | |
| .data(dots) | |
| .enter().append("circle") | |
| .attr("class", "drag-dot") | |
| .attr("cx", d => d.x) | |
| .attr("cy", height / 2) | |
| .attr("r", config.radius) | |
| .style("stroke", d => d.colour) | |
| .style("fill", d => d.colour) | |
| .style("fill-opacity", 0.5) | |
| .style("stroke-width", config.strokeWidth) | |
| .call(dragbehaviour) | |
| .on("mouseover", function() { | |
| addGlow(d3.select(this)); | |
| }) | |
| .on("mouseout", function() { | |
| if (!glowing) removeGlow(d3.select(this)); | |
| }); | |
| debugger; | |
| dotGroup.selectAll("circle").sort(function(a, b) { | |
| if (a.x > b.x) return 1; | |
| if (a.x < b.x) return -1; | |
| return 0; | |
| }); | |
| /* Drag functions */ | |
| var glowing = false; | |
| function dragstarted() { | |
| addGlow(d3.select(this)); | |
| glowing = true; | |
| } | |
| function dragged(data, i) { | |
| var minX, maxX; | |
| if (data.position == "lowest") { | |
| minX = 0; | |
| maxX = dots[i + 1].x - config.strokeWidth; | |
| } else if (data.position == "median") { | |
| minX = dots[i - 1].x + config.strokeWidth; | |
| maxX = dots[i + 1].x - config.strokeWidth; | |
| } else { | |
| minX = dots[i - 1].x + config.strokeWidth; | |
| maxX = width; | |
| } | |
| d3.select(this) | |
| .attr("cx", d => d.x = Math.max(minX, Math.min(maxX, d3.event.x))); | |
| bgDots | |
| .attr("cx", d => d.x); | |
| innerLine | |
| .attr("x1", dots[0].x) | |
| .attr("x2", dots[dots.length - 1].x); | |
| } | |
| function dragended() { | |
| removeGlow(d3.select(this)); | |
| glowing = false; | |
| } | |
| /* Glow/change colour functions */ | |
| function addGlow(selection) { | |
| selection | |
| .style("filter", "url(#glow)") | |
| .style("stroke", "black"); | |
| } | |
| function removeGlow(selection) { | |
| selection | |
| .style("filter", "none") | |
| .style("stroke", d => d.colour); | |
| } | |
| </script> | |
| </body> |