This is a demonstration of the d3fc-label-layout component based on Mike Bostock's Let's Make a Map example. The label layout component provides an easy mechanism for labeling charts and maps in such a way that labels are positioned to avoid collisions, and (optionally) overlapping labels are removed.
Last active
October 27, 2019 20:05
-
-
Save ColinEberhardt/389c76c6a544af9f0cab to your computer and use it in GitHub Desktop.
d3fc-label-layout map example
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> | |
<html> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> | |
<meta charset="utf-8"> | |
<style> | |
.subunit.SCT { fill: #ddc; } | |
.subunit.WLS { fill: #cdd; } | |
.subunit.NIR { fill: #cdc; } | |
.subunit.ENG { fill: #dcd; } | |
.subunit.IRL, | |
.subunit-label.IRL { | |
display: none; | |
} | |
.subunit-boundary { | |
fill: none; | |
stroke: #777; | |
stroke-dasharray: 2,2; | |
stroke-linejoin: round; | |
} | |
.subunit-boundary.IRL { | |
stroke: #aaa; | |
} | |
.subunit-label { | |
fill: #777; | |
fill-opacity: .5; | |
font-size: 20px; | |
font-weight: 300; | |
text-anchor: middle; | |
} | |
.place, | |
.place-label { | |
fill: #444; | |
} | |
text { | |
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; | |
font-size: 14px; | |
pointer-events: none; | |
} | |
.label rect { | |
fill: transparent; | |
} | |
</style> | |
</head> | |
<body> | |
<!-- include polyfills for custom event, Symbol and Custom Elements --> | |
<script src="//unpkg.com/babel-polyfill@6.26.0/dist/polyfill.js"></script> | |
<script src="//unpkg.com/custom-event-polyfill@0.3.0/custom-event-polyfill.js"></script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/document-register-element/1.8.0/document-register-element.js"></script> | |
<script src="//unpkg.com/d3@5.5.0"></script> | |
<script src="//unpkg.com/d3fc@14.0.1"></script> | |
<script src="https://npmcdn.com/topojson@1.6.24/build/topojson.min.js"></script> | |
<script src="map.js"></script> | |
</body> | |
</html> |
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
var width = 960, | |
height = 1160; | |
var projection = d3.geoAlbers() | |
.center([0, 55.4]) | |
.rotate([4.4, 0]) | |
.parallels([50, 60]) | |
.scale(1200 * 5) | |
.translate([width / 2, height / 2]); | |
var path = d3.geoPath() | |
.projection(projection) | |
.pointRadius(2); | |
var svg = d3.select("body").append("svg") | |
.attr("width", width) | |
.attr("height", height); | |
d3.json("uk.json").then(uk => { | |
var subunits = topojson.feature(uk, uk.objects.subunits), | |
places = topojson.feature(uk, uk.objects.places); | |
svg.selectAll(".subunit") | |
.data(subunits.features) | |
.enter().append("path") | |
.attr("class", function(d) { return "subunit " + d.id; }) | |
.attr("d", path); | |
svg.append("path") | |
.datum(topojson.mesh(uk, uk.objects.subunits, function(a, b) { return a !== b && a.id !== "IRL"; })) | |
.attr("d", path) | |
.attr("class", "subunit-boundary"); | |
svg.append("path") | |
.datum(topojson.mesh(uk, uk.objects.subunits, function(a, b) { return a === b && a.id === "IRL"; })) | |
.attr("d", path) | |
.attr("class", "subunit-boundary IRL"); | |
svg.selectAll(".subunit-label") | |
.data(subunits.features) | |
.enter().append("text") | |
.attr("class", function(d) { return "subunit-label " + d.id; }) | |
.attr("transform", function(d) { return "translate(" + path.centroid(d) + ")"; }) | |
.attr("dy", ".35em") | |
.text(function(d) { return d.properties.name; }); | |
svg.append("path") | |
.datum(places) | |
.attr("d", path) | |
.attr("class", "place"); | |
var labelPadding = 2; | |
// the component used to render each label | |
var textLabel = fc.layoutTextLabel() | |
.padding(labelPadding) | |
.value(function(d) { return d.properties.name; }); | |
// a strategy that combines simulated annealing with removal | |
// of overlapping labels | |
var strategy = fc.layoutRemoveOverlaps(fc.layoutGreedy()); | |
// create the layout that positions the labels | |
var labels = fc.layoutLabel(strategy) | |
.size(function(_, i, g) { | |
// measure the label and add the required padding | |
var textSize = d3.select(g[i]) | |
.select('text') | |
.node() | |
.getBBox(); | |
return [textSize.width + labelPadding * 2, textSize.height + labelPadding * 2]; | |
}) | |
.position(function(d) { return projection(d.geometry.coordinates); }) | |
.component(textLabel); | |
// render! | |
svg.datum(places.features) | |
.call(labels); | |
}); |
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
�PNG | |