2

I have a world map that will be placed into popovers/modals (following this tutorial) When used, it needs to zoom into a given country. I made a reference map, hid it, copied its contents, created a new (localized) map. The problem: I'm not able to update the projection.scale on the new map. It works on the original map, following instructions from this answer.

I'm coming here for help as a first time post. Thanks a lot. I'm sure this isn't best practices, but the load time of redrawing a fresh svg was a performance hog.

var width = 280, height = width/2, scale = 50;
var projection, path, svg, g, countries, country, content;

projection = d3.geo.mercator()
  .translate([(width/2), (height/2)])
  .scale( width / 2 / Math.PI);
path = d3.geo.path().projection(projection);

svg = d3.select("#referenceMap").append("svg")
  .attr("width", width)
  .attr("height", height);
g = svg.append("g");

d3.json("data/world-topo-min.json", function(error, world) {
  countries = topojson.feature(world, world.objects.countries).features;
  country = g.selectAll(".country").data(topo);
  country.enter().insert("path")
    .attr("class", "country")
    .attr("d", path)
    .attr("id", function(d,i) { return d.id; })
    .attr("title", function(d,i) { return d.properties.name; })
    .style("fill", function(d, i) { return d.properties.color; });

  content = d3.select('#referenceMap').html(); // -- copy the SVG
});

function copyMap(element, countryName) {
  var countryPath = countries.filter(function(d) {
    return d.properties.name == countryName;
  })[0];

  var div = d3.select(element).html(content); // -- 'paste' the SVG
  g = d3.select(element).select('g');
    .attr("fill", 'rgb(102, 106, 79)'); // -- this works fine as well

  // Issue Area: Update the projection to pan and zoom on the given country 
  var bounds  = path.bounds(countryPath);
  var hscale  = scale*width  / (bounds[1][0] - bounds[0][0]);
  var vscale  = scale*height / (bounds[1][1] - bounds[0][1]);
  scale   = (hscale < vscale) ? hscale : vscale;
  var offset  = [width - (bounds[0][0] + bounds[1][0])/2,
                    height - (bounds[0][1] + bounds[1][1])/2];

  // new projection
  projection = d3.geo.mercator().center(d3.geo.centroid(countryPath))
    .scale(scale).translate(offset);
  path = path.projection(projection);
}
Community
  • 1
  • 1
  • What do you want to do? I mean do you just want to center your map? Or do you actually want to use a complete other projection by selection? – kwoxer Nov 08 '15 at 20:46
  • @kwoxer I want a complete other projection by selection. But even if I'm able to center the original, it works by using: projection.scale(600).center(10,50); but if I use a function to run that one, it does nothing. – Joshua Benson Nov 09 '15 at 06:57
  • Can you show something running maybe? That would help me to understand the issue. Thanks. – kwoxer Nov 09 '15 at 10:47
  • @kwoxer Thanks for your help and attention. I figured it out when typing it into a plunker. After doing `projection.scale(600);`, I needed to add `g.selectAll("path").attr("d", path);`. Unfortunately, this just keeps the load speed too long for my popover. I'll close this question. . . back to the drawing board. – Joshua Benson Nov 09 '15 at 16:44
  • Okay, since you cannot really show the issue. I wanna show you a project of mine http://arda-maps.org . Maybe it uses something that helps you. It's pretty big and I don't switch projections, but e.g. I do many zoomings. Hope it helps somehow. :) – kwoxer Nov 09 '15 at 17:20
  • @kwoxer Really cool project. Great job & this did help! Thanks again. – Joshua Benson Nov 13 '15 at 17:43

1 Answers1

0

After doing projection.scale(600); I needed to add g.selectAll("path").attr("d", path);. Unfortunately, this just keeps the load speed too long for my popover.

// new projection
projection = d3.geo.mercator().center(d3.geo.centroid(countryPath))
.scale(scale).translate(offset);
path = path.projection(projection);
g.selectAll("path").attr("d", path); // <-- Added this line to fix the issue.