block by emeeks 66a38345f12cbe3452ec

Topojson Merged Feature Clustering - d3.carto

Full Screen

Zoom in and zoom out to see dynamically clustered and merged features. Quadtree-based feature clustering in d3.carto.map that takes advantage of topojson’s built-in merging functionality.

In contrast to feature clustering with GeoJSON features, which create multipolygons from the clustered features, topojson layers create merged polygons from clustered features.

This also demonstrates map.clusteringTolerance() which allows you to increase or decrease the degree of clustering.

See also simple point clustering and more advanced point clustering that leverages circle-packing.

index.html

<html xmlns="//www.w3.org/1999/xhtml">
<head>
  <title>Quadtree-based Feature Clustering with TopoJSON Merging- d3.carto</title>
  <meta charset="utf-8" />
    <link type="text/css" rel="stylesheet" href="d3map.css" />
    <link type="text/css" rel="stylesheet" href="https://raw.githubusercontent.com/emeeks/d3-carto-map/master/examples/example.css" />
</head>
<style>
  html,body {
    height: 100%;
    width: 100%;
    margin: 0;
  }

  #map {
    height: 100%;
    width: 100%;
    position: absolute;
  }
  
  .country {
    stroke: white;
  }
  
  .clustered {
    stroke: red;
    fill: orange;
  }
  
</style>
<script>

  function makeSomeMaps() {
    pathSource = 0;

    map = d3.carto.map();

    d3.select("#map").call(map);

    map.centerOn([-88,39],"latlong").setScale(2).clusteringTolerance(1);

    regionLayer = d3.carto.layer.topojson();
    regionLayer
    .path("world.topojson")
    .label("Countries")
    .cssClass("country")
    .renderMode("svg")
    .on("recluster", recolorClusters)
    .specificFeature("countries")
    .cluster(true);
    
    map.addCartoLayer(regionLayer);

    map.refresh();
    
    function recolorClusters() {
        var clusterColor = d3.scale.category20b();

    regionLayer.clusterLayer().g()
    .selectAll("path")
    .style("fill", function(d,i) {return !d.properties.node.leaf ? clusterColor(i%19) : "lightgray"})
    .style("stroke", function(d,i) {return !d.properties.node.leaf ? "black" : "white"})
    .style("stroke-width", function(d,i) {return !d.properties.node.leaf ? "2px" : "1px"})

    d3.selectAll("g.marker").style("pointer-events", "none")
    }

  }
  
  
  

</script>
<body onload="makeSomeMaps()">
<div id="map">
</div>
<footer>
<script src="//d3js.org/d3.v3.min.js" charset="utf-8" type="text/javascript"></script>
<script src="//d3js.org/topojson.v1.min.js" type="text/javascript">
</script>
<script src="//d3js.org/d3.geo.projection.v0.min.js" type="text/javascript">
</script>
<script src="//bl.ocks.org/emeeks/raw/f3105fda25ff785dc5ed/tile.js" type="text/javascript">
</script>
<script src="//bl.ocks.org/emeeks/raw/f3105fda25ff785dc5ed/d3.quadtiles.js" type="text/javascript">
</script>
<script src="//bl.ocks.org/emeeks/raw/f3105fda25ff785dc5ed/d3.geo.raster.js" type="text/javascript">
</script>
<script src="https://rawgit.com/emeeks/d3-carto-map/master/d3.carto.map.js" type="text/javascript">
</script>
</footer>
</body>
</html>

d3map.css

path,circle,rect,polygon,ellipse,line {
    vector-effect: non-scaling-stroke;
}
svg, canvas {
    top: 0;
}
#d3MapZoomBox {
    position: absolute;
    z-index: 10;
    height: 100px;
    width: 25px;
    top: 10px;
    right: 50px;
}

#d3MapZoomBox > button {
    height:25px;
    width: 25px;
    line-height: 25px;
}


.d3MapControlsBox > button {
  font-size:22px;
  font-weight:900;
  border: none;
  height:25px;
  width:25px;
  background: rgba(35,31,32,.85);
  color: white;
  padding: 0;
  cursor: pointer;
}

.d3MapControlsBox > button:hover {
  background: black;
}

#d3MapPanBox {
    position: absolute;
    z-index: 10;
    height: 100px;
    width: 25px;
    top: 60px;
    right: 50px;
}
#d3MapPanBox > button {
    height:25px;
    width: 25px;
    line-height: 25px;
}

#d3MapPanBox > button#left {
  position: absolute;
  left: -25px;
  top: 10px;
}

#d3MapPanBox > button#right {
  position: absolute;
  right: -25px;
  top: 10px;
}

#d3MapLayerBox {
    position: relative;
    z-index: 10;
    height: 100px;
    width: 120px;
    top: 10px;
    left: 10px;
    overflow: auto;
    color: white;
    background: rgba(35,31,32,.85);
}

#d3MapLayerBox > div {
    margin: 5px;
    border: none;
}

#d3MapLayerBox ul {
    list-style: none;
    padding: 0;
    margin: 0;
    cursor: pointer;
}
#d3MapLayerBox li {
    list-style: none;
    padding: 0;
}

#d3MapLayerBox li:hover {
    font-weight:700;
}

#d3MapLayerBox li input {
    cursor: pointer;
}

div.d3MapModal {
    position: absolute;
    z-index: 11;
    background: rgba(35,31,32,.90);
    top: 50px;
    left: 50px;
    color: white;
    max-width: 400px;
}

div.d3MapModalContent {
    width:100%;
    height: 100%;
    overflow: auto;
}

div.d3MapModalContent > p {
    padding: 0px 20px;
    margin: 5px 0;
}

div.d3MapModalContent > h1 {
    padding: 0px 20px;
    font-size: 20px;
}

div.d3MapModalArrow {
    content: "";
	width: 0; 
	height: 0; 
	border-left: 20px solid transparent;
	border-right: 20px solid transparent;
	border-top: 20px solid rgba(35,31,32,.90);
        position: absolute;
        bottom: -20px;
        left: 33px;
}


#d3MapSVG {

}

rect.minimap-extent {
    fill: rgba(200,255,255,0.35);
    stroke: black;
    stroke-width: 2px;
    stroke-dasharray: 5 5;
}

circle.newpoints {
    fill: black;
    stroke: red;
    stroke-width: 2px;
}

path.newfeatures {
    fill: steelblue;
    fill-opacity: .5;
    stroke: pink;
    stroke-width: 2px;
}