Atualmente no d3, se você tiver um objeto geoJSON que você irá desenhar, precisará escalá-lo e traduzi-lo para obter o tamanho desejado e convertê-lo para centralizá-lo. Esta é uma tarefa muito tediosa de tentativa e erro, e eu queria saber se alguém sabia uma maneira melhor de obter esses valores?
Então, por exemplo, se eu tiver esse 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");
});
Como diabos obtenho .scale (8500) e .translate ([0, -1200]) sem ir aos poucos?
Respostas:
O seguinte parece fazer aproximadamente o que você deseja. A escala parece estar correta. Ao aplicá-lo ao meu mapa, há um pequeno deslocamento. Esse pequeno deslocamento provavelmente é causado porque eu uso o comando translate para centralizar o mapa, enquanto eu provavelmente deveria usar o comando center.
Em código:
fonte
projection.fitSize([width, height], geojson)
( API docs ) - consulte a resposta de @dnltsk abaixo.Minha resposta está próxima da de Jan van der Laan, mas você pode simplificar um pouco as coisas porque não precisa calcular o centróide geográfico; você só precisa da caixa delimitadora. E, usando uma projeção de unidade não dimensionada e não traduzida, você pode simplificar a matemática.
A parte importante do código é esta:
Após compilar a caixa delimitadora do recurso na projeção unitária, é possível calcular a escala apropriada comparando a proporção da caixa delimitadora (
b[1][0] - b[0][0]
eb[1][1] - b[0][1]
) com a proporção da tela (width
eheight
). Nesse caso, também dimensionei a caixa delimitadora para 95% da tela, em vez de 100%, para que haja um pouco de espaço extra nas bordas para traços e recursos ou preenchimento ao redor.Em seguida, você pode calcular a conversão usando o centro da caixa delimitadora (
(b[1][0] + b[0][0]) / 2
e(b[1][1] + b[0][1]) / 2
) e o centro da tela (width / 2
eheight / 2
). Observe que, como a caixa delimitadora está nas coordenadas da projeção da unidade, ela deve ser multiplicada pela escala (s
).Por exemplo, bl.ocks.org/4707858 :
Há uma pergunta relacionada sobre qual é o zoom para um recurso específico em uma coleção sem ajustar a projeção, ou seja , combinando a projeção com uma transformação geométrica para aumentar e diminuir o zoom. Isso usa os mesmos princípios acima, mas a matemática é um pouco diferente porque a transformação geométrica (o atributo "transformação" do SVG) é combinada com a projeção geográfica.
Por exemplo, bl.ocks.org/4699541 :
fonte
* 500
aqui é estranho ... tambémb[1][1] - b[0][0]
deve estarb[1][1] - b[0][1]
no cálculo da 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));
Com d3 v4 ou v5, fica muito mais fácil!
e finalmente
Aproveite, Felicidades
fonte
d3v4
há um tempo e acaba de descobrir esse método.g
vem? Esse é o contêiner svg?g
deve ser<g></g>
tagEu sou novo no d3 - tentarei explicar como eu o entendo, mas não tenho certeza se entendi tudo direito.
O segredo é saber que alguns métodos irão operar no espaço cartográfico (latitude, longitude) e outros no espaço cartesiano (x, y na tela). O espaço cartográfico (nosso planeta) é (quase) esférico, o espaço cartesiano (tela) é plano - para mapear um sobre o outro, você precisa de um algoritmo, chamado de projeção . Esse espaço é muito curto para aprofundar o assunto fascinante das projeções e como elas distorcem as características geográficas para transformar esféricas em plano; alguns são projetados para conservar ângulos, outros conservam distâncias e assim por diante - sempre há um compromisso (Mike Bostock tem uma enorme coleção de exemplos ).
Em d3, o objeto de projeção possui uma propriedade / setter central, dada em unidades de mapa:
Há também a tradução, dada em pixels - onde o centro da projeção fica em relação à tela:
Quando quero centralizar um recurso na tela, gosto de definir o centro de projeção no centro da caixa delimitadora de recursos - isso funciona para mim ao usar o mercator (WGS 84, usado no google maps) para o meu país (Brasil), nunca testado usando outras projeções e hemisférios. Pode ser necessário fazer ajustes para outras situações, mas se você seguir esses princípios básicos, ficará bem.
Por exemplo, dada uma projeção e caminho:
O
bounds
método frompath
retorna a caixa delimitadora em pixels . Use-o para encontrar a escala correta, comparando o tamanho em pixels com o tamanho nas unidades do mapa (0,95 fornece uma margem de 5% sobre o melhor ajuste para largura ou altura). Geometria básica aqui, calculando a largura / altura do retângulo, dada os cantos opostos na diagonal:Use o
d3.geo.bounds
método para encontrar a caixa delimitadora nas unidades de mapa:Defina o centro da projeção no centro da caixa delimitadora:
Use o
translate
método para mover o centro do mapa para o centro da tela:Até agora você deve ter o recurso no centro do mapa ampliado com uma margem de 5%.
fonte
Existe um método center () que você pode usar que aceita um par lat / lon.
Pelo que entendi, translate () é usado apenas para mover literalmente os pixels do mapa. Não sei como determinar o que é escala.
fonte
Além Centro um mapa em d3 dado um objeto GeoJSON , nota que você pode preferir
fitExtent()
maisfitSize()
se você quiser especificar um preenchimento ao redor dos limites do seu objeto.fitSize()
define automaticamente este preenchimento como 0.fonte
Eu estava procurando na Internet uma maneira fácil de centralizar meu mapa e fui inspirado pela resposta de Jan van der Laan e mbostock. Aqui está uma maneira mais fácil de usar o jQuery se você estiver usando um contêiner para o svg. Criei uma borda de 95% para estofamento / bordas etc.
Se você estiver procurando por escala exata, esta resposta não funcionará para você. Mas, como eu, você deseja exibir um mapa centralizado em um contêiner, isso deve ser suficiente. Eu estava tentando exibir o mapa mercator e descobri que esse método era útil para centralizar meu mapa, e eu poderia facilmente cortar a parte da Antártica, pois não precisava dele.
fonte
Para deslocar / ampliar o mapa, você deve sobrepor o SVG no Leaflet. Isso será muito mais fácil do que transformar o SVG. Veja este exemplo http://bost.ocks.org/mike/leaflet/ e, em seguida, Como alterar o centro do mapa no folheto
fonte
Com a resposta da mbostocks e o comentário de Herb Caudill, comecei a ter problemas com o Alasca desde que usava uma projeção mercator. Devo observar que, para meus próprios propósitos, estou tentando projetar e centralizar os Estados Unidos. Eu descobri que tinha que me casar com as duas respostas com a resposta de Jan van der Laan, com a seguinte exceção para polígonos que se sobrepõem aos hemisférios (polígonos que acabam com um valor absoluto para Leste-Oeste maior que 1):
configure uma projeção simples no mercator:
projeção = d3.geo.mercator (). scale (1) .translate ([0,0]);
crie o caminho:
caminho = d3.geo.path (). projeção (projeção);
3. configurar meus limites:
4. Adicione uma exceção ao Alasca e aos estados que se sobrepõem aos hemisférios:
Eu espero que isso ajude.
fonte
Para as pessoas que desejam ajustar verticalmente e horizontalmente, eis a solução:
fonte
Como eu centralizei um Topojson, onde eu precisava extrair o recurso:
fonte