nb12345
nb12345

Reputation: 145

Initiate d3 map over certain area given latitude and longitude

I am building a map in d3 and basing it off of this codepen by Andy Barefoot: https://codepen.io/nb123456/pen/zLdqvM?editors=0010. I want to modify the initiateZoom() function so that if I set the lat/lon coordinates for a box surrounding say Ohio, the map will initialize its panning to be over Ohio.

function initiateZoom() {
  minZoom = Math.max($("#map-holder").width() / w, $("#map-holder").height() / h);
  maxZoom = 20 * minZoom;

  zoom
    .scaleExtent([minZoom, maxZoom])
    .translateExtent([[0, 0], [w, h]])
  ;

  midX = ($("#map-holder").width() - minZoom * w) / 2;
  midY = ($("#map-holder").height() - minZoom * h) / 2;//These are the original values
  var swlat = 32;
  var swlon = -82;
  var nelat = 42;
  var nelon = -72;
  var projectCoordinates = projection([(swlat+nelat)/2, (swlon+nelon)/2]);

  /*This did not work
  var midX =  minZoom*(w-(swlat+nelat)/2) - ($("#map-holder").width()-(swlat+nelat)/2);
  var midY = minZoom*(h-(swlon+nelon)/2) - ($("#map-holder").height()-(swlon+nelon)/2);*/
  /*Neither did this
  var midX = minZoom*(w-projectCoordinates[0])-($("#map-holder").width()-projectCoordinates[0]);
  var midY = minZoom*(h-projectCoordinates[1])-($("#map-holder").height()-projectCoordinates[1]);*/

  svg.call(zoom.transform, d3.zoomIdentity.translate(midX, midY).scale(minZoom));
}  

The idea behind the original approach was to:

1: Get the current pixel display of the map
2: Get the new pixel distance from the map corner to the map point after zoom has been applied 
3: The pixel distance of the center of the container to the top of the container
4: subtract the values from 2 and 3

The original post was trying to translate the map so that it would initialize the zoom and pan over the center of the map. I tried to modify this approach first by directly substituting the lat/lon values into the above equations. I also tried first transforming the lat/lon values using the projection and then substituting those values in, with little success. What do I need to do in order to get my desired result?

Upvotes: 1

Views: 108

Answers (1)

rioV8
rioV8

Reputation: 28673

Setting a translateExtent could be a bad idea because it depends on the zoom scale.

The following replacement works.

function initiateZoom() {
  // Define a "minzoom" whereby the "Countries" is as small possible without leaving white space at top/bottom or sides
  minZoom = Math.max($("#map-holder").width() / w, $("#map-holder").height() / h);
  // set max zoom to a suitable factor of this value
  maxZoom = 20 * minZoom;
  // set extent of zoom to chosen values
  // set translate extent so that panning can't cause map to move out of viewport
  zoom
    .scaleExtent([minZoom, maxZoom])
    .translateExtent([[0, 0], [w, h]])
  ;

  var swlat = 32;
  var swlon = -82;
  var nelat = 42;
  var nelon = -72;
  var nwXY = projection([swlon, nelat]);
  var seXY = projection([nelon, swlat]);
  var zoomScale = Math.min($("#map-holder").width()/(seXY[0]-nwXY[0]), $("#map-holder").height()/(seXY[1]-nwXY[1]))
  var projectCoordinates = projection([(swlon+nelon)/2, (swlat+nelat)/2]);

  svg.call(zoom.transform, d3.zoomIdentity.translate($("#map-holder").width()*0.5-zoomScale*projectCoordinates[0], $("#map-holder").height()*0.5-zoomScale*projectCoordinates[1]).scale(zoomScale));
}

Upvotes: 1

Related Questions