Links: https://stackoverflow.com/questions/45107825/how-to-use-d3fc-label-label-js-on-a-map https://stackoverflow.com/questions/17425268/d3js-automatic-labels-placement-to-avoid-overlaps-force-repulsion
https://bl.ocks.org/ColinEberhardt/389c76c6a544af9f0cab https://bost.ocks.org/mike/map/ (v3 version)
/pnavarrc/5913636 - label placement using the force layout and multiple foci but v3 https://bl.ocks.org/mbostock/1667139 - force layout in d3v4
/larskotthoff/11406992 - implements automatic label placement using collision detection
Other: https://github.com/migurski/Dymo https://github.com/ShareMap/ShareMap-dymo-js
/ilyabo/2585241 http://jsfiddle.net/s3logic/j789j3xt/
xxxxxxxxxx
<html>
<head>
<meta charset="utf-8" \>
<style>
path {
stroke: white;
stroke-width: 1.5px;
fill: #C4C4C4;
}
text {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
pointer-events: none;
}
.label rect {
fill: transparent;
}
</style>
<script src="https://d3js.org/d3.v4.min.js"></script>
<!--<script src="https://d3js.org/topojson.v2.min.js"></script>-->
<script src="https://unpkg.com/topojson-client@3"></script>
<script src="https://npmcdn.com/d3fc-label-layout@4.0.0/build/d3fc-label-layout.js"></script>
<script src="https://npmcdn.com/d3fc-data-join@2.0.0/build/d3fc-data-join.js"></script>
<script src="https://npmcdn.com/d3fc-rebind@4.0.1/build/d3fc-rebind.js"></script>
<script src="https://d3js.org/queue.v1.min.js"></script>
</head>
<body>
<div id="map"></div>
<script>
const map = d3.select("#map");
const width = map.node().getBoundingClientRect().width;
const height = width / 2;
const projection = d3.geoMercator();
const path = d3.geoPath().projection(projection).pointRadius(2);
const zoom = d3.zoom()
.scaleExtent([1, 40])
.translateExtent([[0,0], [width, height]])
.extent([[0, 0], [width, height]])
.on("zoom", zoomed);
const svg = map.append("svg")
.attr("width", width)
.attr("height", height)
.call(zoom);
const g = svg.append("g");
queue()
.defer(d3.json, "https://cdn.rawgit.com/mbostock/4090846/raw/d534aba169207548a8a3d670c9c2cc719ff05c47/world-50m.json")
.defer(d3.tsv, "https://cdn.rawgit.com/mbostock/4090846/raw/d534aba169207548a8a3d670c9c2cc719ff05c47/world-country-names.tsv")
.await(ready);
function ready(error, world, names) {
if (error) throw error;
var countries = topojson.feature(world, world.objects.countries).features;
//map country names to IDs used on map
var names_arr=[];
names.forEach(function(i){
names_arr[i.id]=i.name;
});
countries.forEach(function(feature) {
//feature.properties.area = d3.geoArea(feature);
//feature.properties.center = projection(d3.geoCentroid(feature));
feature.properties.name = names_arr[feature.id];
});
// "path" instead of ".subunit"
g.selectAll("path")
//.data(map_data.features)
.data(countries)
.enter().append("path")
.attr("d", path)
.attr("class", function(d) { return "label " + d.id})
/*
g.selectAll(".subunit-label")
.data(countries)
.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; });
*/
var labelPadding = 2;
// the component used to render each label
var textLabel = fc.layoutTextLabel()
.padding(labelPadding)
//.value(function(d) { return map_data.properties.iso; });
//.value(function(d) { return d.properties.iso; });
.value(function(d) { return d.properties.name; });
// use simulate annealing to find minimum overlapping text label positions
//https://github.com/d3fc/d3fc-label-layout/blob/master/README.md
var strategy = fc.layoutGreedy();
//var strategy = fc.layoutAnnealing();
// 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 path.centroid(d); })
.component(textLabel);
// render!
g.datum(countries)
.call(labels);
};
function zoomed(){
g.attr("transform", d3.event.transform);
}
</script>
</body>
</html>
https://d3js.org/d3.v4.min.js
https://d3js.org/topojson.v2.min.js
https://unpkg.com/topojson-client@3
https://npmcdn.com/d3fc-label-layout@4.0.0/build/d3fc-label-layout.js
https://npmcdn.com/d3fc-data-join@2.0.0/build/d3fc-data-join.js
https://npmcdn.com/d3fc-rebind@4.0.1/build/d3fc-rebind.js
https://d3js.org/queue.v1.min.js