Skip to content

Instantly share code, notes, and snippets.

@grdw
Last active May 30, 2023 07:45
Show Gist options
  • Save grdw/a24145d6339d60a6f391ac03246c3e64 to your computer and use it in GitHub Desktop.
Save grdw/a24145d6339d60a6f391ac03246c3e64 to your computer and use it in GitHub Desktop.
A maze minesweeper date of birth UI
<!DOCTYPE html>
<html>
<head>
<title>Date Of Birth</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<form>
<label>Date of birth</label>
<input value="0" id="day" disabled="disabled" maxlength="2" name="date-of-birth-day"/>
<input value="0" id="month" disabled="disabled" maxlength="2" name="date-of-birth-month"/>
<input value="0" id="year" disabled="disabled" maxlength="4" name="date-of-birth-year"/>
</form>
<style>
input { width: 20px; }
input[name="date-of-birth-year"] { width: 40px; }
body{ font-size: 1.2em; font-family: "Times new roman"; }
form { margin-bottom: 12px; }
rect.mine { fill: #FFCCCC; }
rect.selected { fill: #CCFFCC; }
text { text-anchor: middle; }
</style>
<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="600" height="600">
</svg>
<script>
const svg = document.getElementById("svg");
const day = document.getElementById("day");
const month = document.getElementById("month");
const year = document.getElementById("year");
const size = 50;
const mazeWidth = 12;
const colors = ["#d8140e", "#d84f0e", "#6da016"];
const colorIndexes = ["year", "month", "day"];
let yearValue = ["0", "0", "0", "0"];
let yearIndex = 0;
let active = false;
let data = [
{ value: "1", display: "Jan", input: "month" },
{ value: "2", display: "Feb", input: "month" },
{ value: "3", display: "Mar", input: "month" },
{ value: "4", display: "Apr", input: "month" },
{ value: "5", display: "May", input: "month" },
{ value: "6", display: "Jun", input: "month" },
{ value: "7", display: "Jul", input: "month" },
{ value: "8", display: "Aug", input: "month" },
{ value: "9", display: "Sep", input: "month" },
{ value: "10", display: "Oct", input: "month" },
{ value: "11", display: "Nov", input: "month" },
{ value: "12", display: "Dec", input: "month" },
];
for (let i = 1; i <= 31; i++) {
data.push({
value: i.toString(),
display: i.toString(),
input: "day"
});
}
for (let i = 0; i <= 9; i++) {
data.push({
value: i.toString(),
display: i.toString(),
input: "year"
});
}
const blanks = (mazeWidth * mazeWidth) - data.length;
for (let i = 0; i < blanks ; i++) {
data.push({
value: 0,
display: "",
input: null
});
}
function reposition() {
for (const i in data) {
data[i].x = (i % mazeWidth) * size;
data[i].y = Math.floor(i / mazeWidth) * size;
}
}
d3.shuffle(data);
reposition();
d3.shuffle(colorIndexes);
d3.selectAll("input").style("color", function() {
return colors[colorIndexes.indexOf(this.id)]
});
const groups = d3.select("svg")
.selectAll("g")
.data(data)
.enter()
.append("g")
.attr("data-input", function(d) { return d.input; })
.attr("data-value", function(d) { return d.value; })
.attr("transform", function(d, i) {
return "translate(" + d.x + "," + d.y + ")"
})
.on("mouseenter", onMouseEnter);
groups
.append("rect")
.attr("width", size)
.attr("height", size)
.attr("fill", "#EEE")
.attr("stroke", "#DDD");
groups
.append("text")
.attr("dy", "1.6em")
.attr("dx", "1.3em")
.attr('fill', function(d) {
return colors[colorIndexes.indexOf(d.input)];
})
.text(function(d) { return d.display });
function onMouseEnter(evt) {
const d = this.dataset;
if (d.input !== undefined) {
const r = d3.select(this).select("rect");
const c = r.attr("class");
if (c == "mine") {
cancel();
return;
}
switch(d.input) {
case "year":
yearValue[yearIndex % yearValue.length] = d.value;
yearIndex += 1;
year.value = yearValue.join("");
break;
default:
document.getElementById(d.input).value = d.value;
d3
.selectAll("g[data-input=\"" + d.input + "\"] rect")
.attr("class", "mine");
break;
}
r.attr("class", "selected");
}
}
function cancel() {
year.value = day.value = month.value = "0";
groups.on("mouseenter", null);
d3.shuffle(data);
d3.shuffle(colorIndexes);
d3.select("svg")
.selectAll("g")
.data(data)
.join("g")
.transition()
.duration(1000)
.attr("transform", function(d, i) {
return "translate(" + d.x + "," + d.y + ")"
})
.on("end", function() {
groups.on("mouseenter", onMouseEnter);
});
d3.selectAll("input").style("color", function() {
return colors[colorIndexes.indexOf(this.id)]
});
d3.selectAll("g text").attr("fill", function () {
return colors[colorIndexes.indexOf(this.parentNode.dataset.input)];
});
d3.selectAll("g rect").attr("class", "");
}
function confirmDate() {
svg.removeEventListener("mouseleave", cancel, false);
groups.on("mouseenter", null);
d3.selectAll("g rect.mine").attr("class", "");
}
svg.addEventListener("mouseleave", cancel, false);
svg.addEventListener("click", confirmDate, false);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment