Voronoi plots over aerial photos, my oh my!
Scroll down to add a custom image.
Inspired by Rod Bogart's tweet
Photo by Lance Asper on Unsplash
Built with blockbuilder.org
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.css" />
<style>
body {
width: 100%;
margin: 0;
}
.container {
margin: 0 auto 6px;
position: relative;
width: 960px;
}
svg {
position: absolute;
left: 0;
top: 0;
}
.voronoi {
fill: none;
stroke: rgba(255, 255, 255, 0.4);
stroke-width: 4;
}
.actions-bar {
opacity: 0.8;
background-color: white;
padding: 12px;
position: absolute;
top: 0;
right: 0;
left: 0;
z-index: 2;
text-align: right;
}
.actions-bar button {
margin-bottom: 0;
}
.actions {
margin: 12px;
}
.points {
fill: none;
stroke: rgba(248, 231, 28, 0.95);
stroke-width: 3;
}
</style>
</head>
<body>
<div class="container">
</div>
<div class="actions-bar">
<button onClick='reset()'>Reset</button>
<button onClick='undo()'>Undo</button>
<button onClick='togglePoints()'>Toggle Points</button>
</div>
<div class="actions row">
<div class="six columns">
<label for="exampleEmailInput">Replace image</label>
<input class="u-full-width" type="url" id="src_url" placeholder="Image URL">
<button onClick='changeBg()'>Change</button>
</div>
</div>
<script>
var SRC_IMAGE = "https://gist.githubusercontent.com/samhogg/ddec8105ac38c24b69a120596c9b41d9/raw/74c7e598e84838fa7acda331ceef37554fee5a77/overhead.jpg",
width = 960,
height = 500,
pointsOn = false,
points = [[532, 386], [621, 445], [706, 384], [589, 278], [483, 200], [501, 297], [278, 294], [278, 246], [293, 139], [152, 229], [443, 406], [446, 473], [580, 20], [750, 145], [805, 31]],
canvas = d3.select(".container")
.append('canvas')
.attr('width', width)
.attr('height', height)
.node(),
context = canvas.getContext("2d"),
voronoi = d3.voronoi().extent([[0, 0], [width, height]]),
img = new Image();
function draw() {
context.drawImage(img, 0, 0, width, height);
d3.select('svg').remove();
svg = d3.select('.container')
.append('svg')
.attr('width', width)
.attr('height', height)
.on('click', svgClick);
// Draw Polygons
svg.append("g")
.attr("class", "voronoi")
.selectAll("path")
.data(voronoi.polygons(points))
.enter().append("path")
.call(drawVoronoi);
// Draw points
if (pointsOn) {
svg.append("g")
.attr("class", "points")
.selectAll("circle")
.data(points)
.enter().append("circle")
.attr("r", 2.5)
.call(drawPoint);
}
};
function reset() {
points = [];
draw();
};
function undo() {
points.pop();
draw();
};
function togglePoints() {
pointsOn = !pointsOn;
draw();
};
function drawPoint(p) {
p.attr("cx", function (d) { return d[0]; })
.attr("cy", function (d) { return d[1]; });
}
function drawVoronoi(p) {
p
.attr("d", function (d) { return d ? "M" + d.join("L") + "Z" : null; });
}
function svgClick() {
points.push(d3.mouse(this));
draw();
};
function changeBg() {
var src = document.getElementById('src_url').value
src.length > 0 ? img.src = src : null;
points = [];
};
img.onload = draw;
img.src = SRC_IMAGE;
</script>
</body>
https://d3js.org/d3.v4.min.js