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> |