;(function() { var map; function Map(topology) { // Convert the topojson to geojson var geojson = topojson.feature(topology, topology.objects.towns), // Since we're using projected TopoJSON, we use a null projection here. path = d3.geo.path().projection(null), // Use topojson.mesh to create a path representing county outlines. countyMesh = topojson.mesh(topology, topology.objects.towns, function(a, b) { return a.properties.fips !== b.properties.fips; }), svg = d3.select("#map").append("svg") .attr({ width: 615, height: 375 }), g = svg.append("g").attr({"class": "g-town"}), colorScale = d3.scale.category20b(), // Add town paths town = g.selectAll("path.town").data(geojson.features) .enter().append("path") .attr({ "class": "town", d: path }) .style({ fill: function(d, i) { return colorScale(Math.floor(Math.random()*1000)); }, stroke: "white" }), // Add county path and set its opacity to 0, // since we don't want to show it initially. county = g.append("path").datum(countyMesh) .attr({ "class": "county", d: path }) .style({ opacity: 0, stroke: "white", "stroke-width": 2, fill: "none" }), currentState = "town"; // To show the county outlines, we // transition the town shapes to have // a consistent stroke, and fill, in effect hiding // them. We also transition the county // path to be visible. this.showCounties = function() { var countyColors = {}; // Since we're using a mesh for the county outlines, // it doesn't work well to add the fill to the county // path. Instead, we'll set a consistent fill on all // the towns in each county, to give the effect of // filling in the county. town.transition() .duration(600) .style({ fill: function(d, i) { if (!countyColors[d.properties.fips]) { countyColors[d.properties.fips] = colorScale(Math.floor(Math.random()*1000)); } return countyColors[d.properties.fips]; }, stroke: function(d, i) { return countyColors[d.properties.fips]; } }); county.transition() .duration(600) .style({ opacity: 1 }) }; // To show the town outlines, we transition // back to our original state. this.showTowns = function() { town.transition() .duration(600) .style({ stroke: "white", fill: function(d, i) { return colorScale(Math.floor(Math.random()*1000)); } }); county.transition() .duration(600) .style({ opacity: 0 }) }; this.toggle = function() { if (currentState === "town") { this.showCounties(); currentState = "county"; } else { this.showTowns(); currentState = "town"; } }; } d3.json("ma-towns.topojson", function(err, topology) { map = new Map(topology); }); d3.select("#toggle").on("click", function() { map.toggle(); }); }());