Using d3-brush to create an interactive minimap.
Last active
August 14, 2017 21:47
-
-
Save tlfrd/5efbd1639276d58c904fd1f74508335f to your computer and use it in GitHub Desktop.
Brush Minimap
This file contains 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 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> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script src="https://d3js.org/topojson.v2.min.js"></script> | |
<style> | |
body { margin: 0; position: fixed; top: 0; right: 0; bottom: 0; left: 0; } | |
.minimap { | |
fill: white; | |
stroke: black; | |
} | |
.land { | |
fill: green; | |
fill-opacity: 0.5; | |
} | |
.minimap-land { | |
fill: white; | |
stroke: black; | |
stroke-width: 0.5; | |
} | |
.exterior { | |
fill: none; | |
stroke: black; | |
stroke-width: 0.5; | |
} | |
.interior { | |
fill: none; | |
stroke: black; | |
stroke-opacity: 0.5; | |
stroke-width: 0.5; | |
} | |
.border { | |
fill: none; | |
stroke: black; | |
} | |
g.brush > .handle { | |
display: none; | |
} | |
.overlay { | |
pointer-events: none; | |
} | |
</style> | |
</head> | |
<body> | |
<script> | |
var margin = {top: 0, right: 0, bottom: 0, left: 0}; | |
var width = 960 - margin.left - margin.right, | |
height = 500 - margin.top - margin.bottom; | |
var minimapMargin = {right: 20, bottom: 20}; | |
var minimapWidth = width / 4, | |
minimapHeight = height / 4; | |
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 minimap = svg.append("g") | |
.attr("transform", "translate(" + (width - minimapWidth - minimapMargin.right) + "," + (height - minimapHeight- minimapMargin.bottom) + ")"); | |
minimap.append("rect") | |
.attr("class", "minimap") | |
.attr("width", minimapWidth) | |
.attr("height", minimapHeight); | |
var brush = d3.brush() | |
.extent([[0, 0], [minimapWidth, minimapHeight]]) | |
.on("start brush", brushed); | |
var projection = d3.geoEquirectangular(); | |
var path = d3.geoPath().projection(projection); | |
var miniProjection = d3.geoEquirectangular(); | |
var miniPath = d3.geoPath().projection(miniProjection); | |
var mapSource = "https://unpkg.com/world-atlas@1/world/110m.json" | |
d3.json(mapSource, function(error, world) { | |
if (error) throw error; | |
var land = topojson.feature(world, world.objects.land); | |
var exteriors = topojson.mesh(world, world.objects.countries, function(a, b) { return a == b; }); | |
var interiors = topojson.mesh(world, world.objects.countries, function(a, b) { return a !== b; }); | |
projection.fitSize([width, height], land); | |
miniProjection.fitSize([minimapWidth, minimapHeight], land); | |
var landMap = svg.append("g") | |
.append("path") | |
.datum(land) | |
.attr("class", "land") | |
.attr("d", path); | |
var exteriors = svg.append("g") | |
.append("path") | |
.datum(exteriors) | |
.attr("class", "exterior") | |
.attr("d", path); | |
var interiors = svg.append("g") | |
.append("path") | |
.datum(interiors) | |
.attr("class", "interior") | |
.attr("d", path); | |
minimap.raise(); | |
minimap.append("g") | |
.append("path") | |
.datum(land) | |
.attr("class", "minimap-land") | |
.attr("d", miniPath); | |
minimap.append("g") | |
.attr("class", "brush") | |
.call(brush) | |
.call(brush.move, [[0, 0], [minimapWidth / 2, minimapHeight / 2]]); | |
}); | |
function brushed() { | |
var s = d3.event.selection, | |
c0 = s[0], | |
c1 = s[1]; | |
// convert to lat long | |
var mpc0 = miniProjection.invert(c0); | |
var mpc1 = miniProjection.invert(c1); | |
// convert to larger pixels | |
var pc0 = projection(mpc0); | |
var pc1 = projection(mpc1); | |
projection.center(mpc1); | |
svg.select(".land").attr("d", path); | |
svg.select(".interior").attr("d", path); | |
svg.select(".exterior").attr("d", path); | |
svg.select(".land").attr("transform", "scale(2)") | |
svg.select(".interior").attr("transform", "scale(2)") | |
svg.select(".exterior").attr("transform", "scale(2)") | |
} | |
</script> | |
</body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment