Actualmente en d3 si tiene un objeto geoJSON que va a dibujar, debe escalarlo y traducirlo para obtener el tamaño que desee y traducirlo para centrarlo. Esta es una tarea muy tediosa de prueba y error, y me preguntaba si alguien sabía una mejor manera de obtener estos valores.
Entonces, por ejemplo, si tengo este código
var path, vis, xy;
xy = d3.geo.mercator().scale(8500).translate([0, -1200]);
path = d3.geo.path().projection(xy);
vis = d3.select("#vis").append("svg:svg").attr("width", 960).attr("height", 600);
d3.json("../../data/ireland2.geojson", function(json) {
return vis.append("svg:g")
.attr("class", "tracts")
.selectAll("path")
.data(json.features).enter()
.append("svg:path")
.attr("d", path)
.attr("fill", "#85C3C0")
.attr("stroke", "#222");
});
¿Cómo diablos obtengo .scale (8500) y .translate ([0, -1200]) sin ir poco a poco?
Respuestas:
Lo siguiente parece hacer aproximadamente lo que quieres. La escala parece estar bien. Al aplicarlo a mi mapa hay un pequeño desplazamiento. Este pequeño desplazamiento probablemente se deba a que uso el comando traducir para centrar el mapa, mientras que probablemente debería usar el comando central.
En codigo:
fuente
projection.fitSize([width, height], geojson)
( documentos de API ) - vea la respuesta de @dnltsk a continuación.Mi respuesta es cercana a la de Jan van der Laan, pero puedes simplificar las cosas ligeramente porque no necesitas calcular el centroide geográfico; solo necesitas el cuadro delimitador. Y, al usar una proyección de unidad no traducida y sin escala, puede simplificar las matemáticas.
La parte importante del código es esta:
Después de compilar el cuadro delimitador de la entidad en la proyección de la unidad, puede calcular la escala apropiada comparando la relación de aspecto del cuadro delimitador (
b[1][0] - b[0][0]
yb[1][1] - b[0][1]
) con la relación de aspecto del lienzo (width
yheight
). En este caso, también he escalado el cuadro delimitador al 95% del lienzo, en lugar del 100%, por lo que hay un poco de espacio extra en los bordes para los trazos y las características circundantes o el relleno.Luego, puede calcular la traducción utilizando el centro del cuadro delimitador (
(b[1][0] + b[0][0]) / 2
y(b[1][1] + b[0][1]) / 2
) y el centro del lienzo (width / 2
yheight / 2
). Tenga en cuenta que dado que el cuadro delimitador está en las coordenadas de la proyección de la unidad, debe multiplicarse por la escala (s
).Por ejemplo, bl.ocks.org/4707858 :
Hay una pregunta relacionada sobre cuál es cómo hacer zoom a una característica específica en una colección sin ajustar la proyección, es decir , combinar la proyección con una transformación geométrica para acercar y alejar. Utiliza los mismos principios que el anterior, pero las matemáticas son ligeramente diferentes porque la transformación geométrica (el atributo "transformar" SVG) se combina con la proyección geográfica.
Por ejemplo, bl.ocks.org/4699541 :
fuente
* 500
aquí es extraño ... también,b[1][1] - b[0][0]
debería estarb[1][1] - b[0][1]
en el cálculo de la escala.b.s = b[0][1]; b.n = b[1][1]; b.w = b[0][0]; b.e = b[1][0]; b.height = Math.abs(b.n - b.s); b.width = Math.abs(b.e - b.w); s = .9 / Math.max(b.width / width, (b.height / height));
Con d3 v4 o v5, ¡es mucho más fácil!
y finalmente
Disfruta, salud
fuente
d3v4
durante un tiempo y acabo de descubrir este método.g
viene ¿Es ese el contenedor de svg?g
debería ser<g></g>
etiquetadaSoy nuevo en d3: intentaré explicar cómo lo entiendo, pero no estoy seguro de haberlo entendido bien
El secreto es saber que algunos métodos funcionarán en el espacio cartográfico (latitud, longitud) y otros en el espacio cartesiano (x, y en la pantalla). El espacio cartográfico (nuestro planeta) es (casi) esférico, el espacio cartesiano (pantalla) es plano; para mapear uno sobre el otro necesita un algoritmo, que se llama proyección . Este espacio es demasiado corto para profundizar en el fascinante tema de las proyecciones y en cómo distorsionan las características geográficas para convertir el esférico en plano; algunos están diseñados para conservar ángulos, otros conservan distancias, etc. Siempre hay un compromiso (Mike Bostock tiene una gran colección de ejemplos ).
En d3, el objeto de proyección tiene una propiedad central / setter, dada en unidades de mapa:
También está la traducción, dada en píxeles, donde el centro de proyección se encuentra en relación con el lienzo:
Cuando quiero centrar una característica en el lienzo, me gusta establecer el centro de proyección en el centro del cuadro delimitador de características; esto funciona para mí cuando uso mercator (WGS 84, utilizado en google maps) para mi país (Brasil), nunca probado usando otras proyecciones y hemisferios. Puede que tenga que hacer ajustes para otras situaciones, pero si logra estos principios básicos, estará bien.
Por ejemplo, dada una proyección y ruta:
El
bounds
método depath
devuelve el cuadro delimitador en píxeles . Úselo para encontrar la escala correcta, comparando el tamaño en píxeles con el tamaño en unidades de mapa (0.95 le da un margen de 5% sobre el mejor ajuste para ancho o alto). Geometría básica aquí, calculando el ancho / alto del rectángulo dados las esquinas diagonalmente opuestas:Use el
d3.geo.bounds
método para encontrar el cuadro delimitador en unidades de mapa:Establezca el centro de la proyección en el centro del cuadro delimitador:
Use el
translate
método para mover el centro del mapa al centro del lienzo:En este momento, debería tener la función en el centro del mapa ampliada con un margen del 5%.
fuente
Hay un método center () que puede usar que acepta un par lat / lon.
Por lo que entiendo, translate () solo se usa para mover literalmente los píxeles del mapa. No estoy seguro de cómo determinar qué escala es.
fuente
Además de centrar un mapa en d3 dado un objeto geoJSON , tenga en cuenta que puede preferir
fitExtent()
sobrefitSize()
si desea especificar un relleno alrededor de los límites de su objeto.fitSize()
establece automáticamente este relleno en 0.fuente
Estaba buscando en Internet una manera fácil de centrar mi mapa y me inspiré en la respuesta de Jan van der Laan y mbostock. Aquí hay una manera más fácil de usar jQuery si está utilizando un contenedor para el svg. Creé un borde del 95% para relleno / bordes, etc.
Si busca una escala exacta, esta respuesta no funcionará para usted. Pero si, como yo, desea mostrar un mapa que se centralice en un contenedor, esto debería ser suficiente. Estaba tratando de mostrar el mapa de mercator y descubrí que este método era útil para centralizar mi mapa, y podía cortar fácilmente la porción antártica ya que no lo necesitaba.
fuente
Para desplazar / hacer zoom en el mapa, debe mirar superponer el SVG en el folleto. Eso será mucho más fácil que transformar el SVG. Vea este ejemplo http://bost.ocks.org/mike/leaflet/ y luego Cómo cambiar el centro del mapa en el folleto
fuente
Con la respuesta de mbostocks y el comentario de Herb Caudill, comencé a tener problemas con Alaska ya que estaba usando una proyección de mercator. Debo señalar que, para mis propios fines, estoy tratando de proyectar y centrar los Estados Unidos. Descubrí que tenía que casar las dos respuestas con la respuesta de Jan van der Laan con la siguiente excepción para los polígonos que se superponen a los hemisferios (polígonos que terminan con un valor absoluto para Este - Oeste que es mayor que 1):
configurar una proyección simple en mercator:
proyección = d3.geo.mercator (). scale (1) .translate ([0,0]);
crea el camino:
ruta = d3.geo.path (). proyección (proyección);
3. configurar mis límites:
4. Agregue una excepción para Alaska y estados que se superponen a los hemisferios:
Espero que esto ayude.
fuente
Para las personas que desean ajustar verticalmente y horizontalmente, esta es la solución:
fuente
Cómo centré un Topojson, donde necesitaba sacar la función:
fuente