Internal topoJSON borders used .mesh vs .merge
(function() { | |
var root = this; | |
// create a new SVG element | |
var elasticSVG = function(selector, opts) { | |
opts = opts || {}; | |
// containing DOM element, which defaults to body | |
var parent = document.querySelectorAll(selector || "body"); | |
if (!parent || !parent.length) { | |
console.log("Couldn't find a parent for elasticSVG making the selector '" + selector + "'"); | |
return; | |
} | |
parent = parent[0]; | |
// you can specify a width if you like, or we'll snap to size of container | |
var base = { | |
width: typeof opts.width !== "undefined" ? opts.width : parent.clientWidth, | |
scale: 1 | |
}; | |
// we need to remember the original width for scaling purposes | |
base.original_width = base.width; | |
// you can either specify the height or the aspect ratio. If neither is specified, refaults to roughly the golden ratio | |
if (typeof opts.height !== "undefined") { | |
base.height = opts.height; | |
opts.aspect = base.height / base.width; | |
} else { | |
opts.aspect = typeof opts.aspect !== "undefined" ? opts.aspect : 0.618; | |
base.height = base.width * opts.aspect; | |
} | |
var xmlns = "http://www.w3.org/2000/svg"; | |
var svg = document.createElementNS(xmlns, "svg"); | |
svg.setAttributeNS(null, "width", base.width); | |
svg.setAttributeNS(null, "height", base.height); | |
parent.appendChild(svg); | |
// setting resize to "auto" sets the viewport to the original width and height so that the SVG always scales | |
if (opts.resize && opts.resize == "auto") { | |
svg.setAttributeNS(null, "viewBox", "0 0 " + base.width + " " + base.height); | |
} | |
function resize() { | |
console.log(parent) | |
base.width = parent.clientWidth; | |
base.height = base.width * opts.aspect; | |
base.scale = base.width / base.original_width; | |
svg.setAttributeNS(null, "width", base.width); | |
svg.setAttributeNS(null, "height", base.height); | |
// optional callback | |
if (opts.onResize) { | |
opts.onResize(base.width, base.height, base.scale); | |
} | |
} | |
var resizeTimer; | |
// http://stackoverflow.com/questions/3339825/what-is-the-best-practise-to-not-to-override-other-bound-functions-to-window-onr | |
function addResizeEvent(func, dur) { | |
var oldResize = window.onresize, | |
resizeTimer, | |
dur = typeof dur === "undefined" ? 250 : parseInt(dur, 10); | |
window.onresize = function () { | |
clearTimeout(resizeTimer); | |
if (typeof oldResize === 'function') { | |
oldResize(); | |
} | |
resizeTimer = setTimeout(function() { | |
func(); | |
}, dur); | |
} | |
} | |
addResizeEvent(resize, 250); | |
if (opts.resize && opts.resize === "auto") { | |
resize(); // call this on load since sometimes the initial conditions are wider than container | |
} | |
base.setResize = function(f) { | |
opts.onResize = f; | |
} | |
base.svg = svg; | |
return base; | |
} | |
// support various modular environments | |
if (typeof define === "function" && define.amd) { // RequireJS | |
define(elasticSVG); | |
} else if (typeof module === "object" && module.exports) { // browserify | |
module.exports = elasticSVG; | |
} else { | |
root.elasticSVG = elasticSVG; // directly included | |
} | |
}()); |
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0"> | |
<title>TopoJSON Counties With Organic Borders</title> | |
<style> | |
path.county { | |
fill: #eee; | |
stroke: #fff; | |
stroke-width: .5px; | |
} | |
path.state { | |
fill: none; | |
stroke: #404040; | |
stroke-width: 1px; | |
} | |
.Example { | |
max-width: 900px; | |
width: 100%; | |
height: 1500px; | |
} | |
.title { | |
font-size: 24px; | |
font-family: Arial; | |
text-align: center; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="Example"> | |
<div class="title">Merged</div> | |
<div id="map_merged"></div> | |
<div class="title">Meshed</div> | |
<div id="map_meshed"></div> | |
</div> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/1.6.19/topojson.min.js"></script> | |
<script src="elasticSVG.js"></script> | |
<script> | |
var projection = d3.geo.albersUsa() | |
.scale(1200) | |
.translate([450, 275]); | |
var path = d3.geo.path().projection(projection); | |
d3.json("us.json", function(error, topology) { | |
if (error) throw error; | |
// MESHED | |
// make the SVG responsive | |
var el_meshed = elasticSVG("#map_meshed", { | |
width: 900, | |
aspect: 0.65, | |
resize: "auto" | |
}); | |
var svg_meshed = d3.select(el_meshed.svg).append("g"); | |
//meshed | |
var counties = topojson.feature(topology, topology.objects.counties).features; | |
svg_meshed.selectAll("path") | |
.data(counties) | |
.enter().append("path") | |
.attr("class", "county") | |
.attr("d", path) | |
.on("click", function(d) { | |
console.log(d); | |
}); | |
svg_meshed.append("path") | |
.datum(topojson.mesh(topology, topology.objects.counties, function(a, b) { return a.id - a.id % 1000 !== b.id - b.id % 1000; })) | |
.attr("class", "state") | |
.attr("d", path); | |
// MERGED | |
// make the SVG responsive | |
var el_meshed = elasticSVG("#map_merged", { | |
width: 900, | |
aspect: 0.65, | |
resize: "auto" | |
}); | |
var svg_merged = d3.select(el_meshed.svg).append("g"); | |
//meshed | |
svg_merged.selectAll("path") | |
.data(counties) | |
.enter().append("path") | |
.attr("class", "county") | |
.attr("d", path); | |
// let's get an organic list of fips | |
var fips = {}; | |
counties.forEach(function(county) { fips[county.id - county.id % 1000] = 1; }); | |
var states = []; | |
// and merge by fips | |
Object.keys(fips).forEach(function(fip) { | |
var state = topojson.merge(topology, topology.objects.counties.geometries.filter(function(d) { return d.id - d.id % 1000 == fip; })); | |
states.push(state); | |
}); | |
svg_merged.append("g").attr("id", "states").selectAll(".state").append("path") | |
.data(states) | |
.enter() | |
.append("path") | |
.attr("class", "state") | |
.attr("d", function(d) { | |
return path(d); | |
}); | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment