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); });