Reputation: 25
I am very new to D3 map, and I have been trying to create a responsive D3 map with drop shadow effect using svg filter.
The example code is adapted from blocks by Mike Bostock (drop shadow) & Darren Jaworski (responsive projection). You can view the example code on Codepen. Following is my JS code:
var width = parseInt(d3.select('#mapContainer').style('width'))
,height = width/960*600;
var svg = d3.select("svg")
.attr("width", width)
.attr("height",height);
var defs = svg.select("defs");
d3.json("https://d3js.org/us-10m.v1.json", function(error, us) {
if (error) throw error;
var path = d3.geoPath();
var projection = d3.geoIdentity()
.scale(width)
.translate([width / 2, height / 2])
.fitSize([width, height],topojson.feature(us, us.objects.states));
defs.append("path")
.attr("id", "nation")
.attr("d", path(topojson.feature(us, us.objects.nation)));
svg.append("use")
.attr("xlink:href", "#nation")
.attr("fill-opacity", 0.2)
.attr("filter", "url(#blur)");
svg.append("use")
.attr("xlink:href", "#nation")
.attr("fill", "#fff");
svg.append("path")
.attr("fill", "none")
.attr("stroke", "#777")
.attr("stroke-width", 0.70)
.attr("d", path(topojson.mesh(us, us.objects.states, function(a, b) { return a !== b; })));
// resize event
d3.select(window)
.on("resize", resize);
// function to resize map
function resize() {
// adjust things when the window size changes
width = parseInt(d3.select('#mapContainer').style('width'));
//console.log(parseInt(d3.select('#mapContainer').style('width')));
height = width/960*600;
svg.attr('width', width).attr('height', height);
// update projection
projection
.scale(width)
.translate([width / 2, height / 2])
.fitSize([width, height],topojson.feature(us, us.objects.states));
// resize the map
svg.selectAll('path').attr('d', path);
svg.select('.land').attr('d', path);
svg.select('.state').attr('d', path);
}
});
In the example, the resize function doesn't seem to work. On window resize, the map would disappear, so would the svg filter appended to it.
Could someone enlighten me on what went wrong? And if someone could provide a fix?
Thank you very much for your help!
I updated the codepen on Responsive US D3 Map with Drop Shadow with @rioV8's great answer.
Upvotes: 0
Views: 737
Reputation: 28868
Have you ever considered to connect your projection and path generator?
var path = d3.geoPath(projection);
Also set the path in the resize method. Label the 2 path elements
svg.select('#nation').attr('d', path(topojson.feature(us, us.objects.nation)));
svg.select('#nation2').attr('d', path(topojson.mesh(us, us.objects.states, function(a, b) { return a !== b; })));
the onload in the body has to go
<body>
there are no tags with class land
or state
//svg.select('.land').attr('d', path);
//svg.select('.state').attr('d', path);
why call projection size
and translate
if you call fitSize
Here is the script code
var width = parseInt(d3.select('#mapContainer').style('width')) - 50
,height = width/960*600;
var svg = d3.select("svg")
.attr("width", width + 50)
.attr("height",height);
var defs = svg.select("defs");
d3.json("https://d3js.org/us-10m.v1.json", function(error, us) {
if (error) throw error;
var topoFeatureStates = topojson.feature(us, us.objects.states);
var projection = d3.geoIdentity()
.fitSize([width, height], topoFeatureStates);
var path = d3.geoPath(projection);
defs.append("path")
.datum(topojson.feature(us, us.objects.nation))
.attr("id", "nation")
.attr("d", path);
svg.append("use")
.attr("xlink:href", "#nation")
.attr("fill-opacity", 0.2)
.attr("filter", "url(#blur)");
svg.append("use")
.attr("xlink:href", "#nation")
.attr("fill", "#fff");
svg.append("path")
.datum(topojson.mesh(us, us.objects.states, function(a, b) { return a !== b; }))
.attr("fill", "none")
.attr("stroke", "#777")
.attr("stroke-width", 0.70)
.attr("d", path);
// function to resize map
function resize() {
// adjust things when the window size changes
width = parseInt(d3.select('#mapContainer').style('width')) - 50;
//console.log(parseInt(d3.select('#mapContainer').style('width')));
height = width/960*600;
svg.attr('width', width + 50).attr('height', height);
// update projection
projection
.fitSize([width, height], topoFeatureStates);
// resize the map
svg.selectAll('path').attr('d', path);
}
// resize event
d3.select(window).on("resize", resize);
});
Edit
Wondering why the path
in the resize did not I work had a second look at the responsive example. It attaches the result of topojson
as datum to the path
.
Modified the code to do the same.
Upvotes: 1