Obecnie w d3, jeśli masz obiekt geoJSON, który zamierzasz narysować, musisz go przeskalować i przetłumaczyć, aby uzyskać żądany rozmiar i przetłumaczyć, aby go wyśrodkować. Jest to bardzo żmudne zadanie metodą prób i błędów i zastanawiałem się, czy ktoś zna lepszy sposób uzyskania tych wartości?
Na przykład, jeśli mam ten kod
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");
});
Jak do cholery mam uzyskać .scale (8500) i .translate ([0, -1200]) bez przechodzenia po trochu?
Odpowiedzi:
Poniższe wydaje się robić mniej więcej to, co chcesz. Skalowanie wydaje się być w porządku. Podczas nakładania go na moją mapę występuje małe przesunięcie. To małe przesunięcie jest prawdopodobnie spowodowane tym, że używam polecenia translate, aby wyśrodkować mapę, podczas gdy powinienem prawdopodobnie użyć polecenia center.
W kodzie:
źródło
projection.fitSize([width, height], geojson)
( dokumentacja API ) - zobacz odpowiedź @dnltsk poniżej.Moja odpowiedź jest podobna do odpowiedzi Jana van der Laana, ale możesz nieco uprościć sprawę, ponieważ nie musisz obliczać geograficznego centroidu; potrzebujesz tylko obwiedni. Używając nieskalowanej, nieprzetłumaczonej projekcji jednostek, możesz uprościć obliczenia.
Ważną częścią kodu jest to:
Po obliczeniu obwiedni obiektu w rzucie jednostkowym można obliczyć odpowiednią skalę , porównując współczynnik kształtu obwiedni (
b[1][0] - b[0][0]
ib[1][1] - b[0][1]
) ze współczynnikiem kształtu obszaru roboczego (width
iheight
). W tym przypadku przeskalowałem również obwiednię do 95% płótna, a nie 100%, więc na krawędziach jest trochę więcej miejsca na pociągnięcia i otaczające elementy lub wypełnienie.Następnie możesz obliczyć tłumaczenie, używając środka obwiedni (
(b[1][0] + b[0][0]) / 2
i(b[1][1] + b[0][1]) / 2
) i środka płótna (width / 2
iheight / 2
). Zwróć uwagę, że skoro obwiednia znajduje się we współrzędnych odwzorowania jednostek, musi zostać pomnożona przez skalę (s
).Na przykład bl.ocks.org/4707858 :
Istnieje pokrewne pytanie, w jaki sposób powiększyć określoną funkcję w kolekcji bez dostosowywania odwzorowania, tj. Połączyć rzutowanie z transformacją geometryczną w celu powiększenia i zmniejszenia. Wykorzystuje to te same zasady co powyżej, ale matematyka jest nieco inna, ponieważ transformacja geometryczna (atrybut SVG „transform”) jest połączona z odwzorowaniem geograficznym.
Na przykład bl.ocks.org/4699541 :
źródło
* 500
to, że jest tu obcy ... równieżb[1][1] - b[0][0]
powinien być uwzględnionyb[1][1] - b[0][1]
w obliczeniach skali.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));
Z d3 v4 lub v5 staje się o wiele łatwiejsze!
i w końcu
Ciesz się, na zdrowie
źródło
d3v4
przez jakiś czas i właśnie odkryłem tę metodę.g
bierze? Czy to jest kontener SVG?g
powinna być<g></g>
tagiemJestem nowy w d3 - spróbuję wyjaśnić, jak to rozumiem, ale nie jestem pewien, czy wszystko jest w porządku.
Sekret tkwi w świadomości, że niektóre metody będą działać na przestrzeni kartograficznej (szerokość, długość), a inne na przestrzeni kartezjańskiej (x, y na ekranie). Przestrzeń kartograficzna (nasza planeta) jest (prawie) sferyczna, przestrzeń kartezjańska (ekran) jest płaska - do odwzorowania jednej na drugiej potrzebny jest algorytm, który nazywa się projekcją . Przestrzeń ta jest zbyt krótka, aby zagłębić się w fascynujący temat projekcji i tego, jak zniekształcają one cechy geograficzne, aby zmienić sferę w płaszczyznę; niektóre mają na celu zachowanie kątów, inne zachowanie odległości itd. - zawsze istnieje kompromis (Mike Bostock ma ogromny zbiór przykładów ).
W d3 rzutowany obiekt ma właściwość środkową / ustawiającą, podaną w jednostkach mapy:
Jest też tłumaczenie, podane w pikselach - gdzie środek projekcji stoi względem płótna:
Kiedy chcę wyśrodkować obiekt na płótnie, lubię ustawić środek projekcji na środek obwiedni obiektu - to działa, gdy używam mercator (WGS 84, używany w Google Maps) dla mojego kraju (Brazylia), nigdy nie testowano przy użyciu innych wypustów i półkul. Być może będziesz musiał wprowadzić poprawki w innych sytuacjach, ale jeśli zastosujesz się do tych podstawowych zasad, wszystko będzie dobrze.
Na przykład, biorąc pod uwagę rzut i ścieżkę:
bounds
Metoda odpath
zwrotów obwiedni w pikselach . Użyj go, aby znaleźć odpowiednią skalę, porównując rozmiar w pikselach z rozmiarem w jednostkach mapy (0,95 daje 5% margines nad najlepszym dopasowaniem szerokości lub wysokości). Tutaj podstawowa geometria, obliczająca szerokość / wysokość prostokąta dla przeciwległych narożników po przekątnej:Użyj
d3.geo.bounds
metody, aby znaleźć obwiednię w jednostkach mapy:Ustaw środek rzutowania na środek obwiedni:
Użyj tej
translate
metody, aby przenieść środek mapy na środek obszaru roboczego:Do tej pory powinieneś mieć powiększoną funkcję w środku mapy z 5% marginesem.
źródło
Istnieje metoda center () , której możesz użyć, która akceptuje parę lat / lon.
Z tego, co rozumiem, translate () służy tylko do dosłownego przesuwania pikseli mapy. Nie wiem, jak określić, jaka to skala.
źródło
Poza Centrum mapa w d3 podany obiekt GeoJSON pamiętać, że może wolisz
fitExtent()
ponadfitSize()
jeśli chcesz określić wyściółkę wokół granicach swojego przedmiotu.fitSize()
automatycznie ustawia to wypełnienie na 0.źródło
Szukałem w Internecie bezproblemowego sposobu na wyśrodkowanie mapy i zainspirowała mnie odpowiedź Jana van der Laana i mbostocka. Oto łatwiejszy sposób korzystania z jQuery, jeśli używasz kontenera na svg. Utworzyłem granicę 95% dla dopełnienia / obramowania itp.
Jeśli szukasz dokładnego skalowania, ta odpowiedź nie zadziała. Ale jeśli tak jak ja chcesz wyświetlić mapę, która jest centralizowana w kontenerze, to powinno wystarczyć. Próbowałem wyświetlić mapę mercator i odkryłem, że ta metoda była przydatna w centralizacji mojej mapy i mogłem łatwo odciąć część Antarktydy, ponieważ jej nie potrzebowałem.
źródło
Aby przesunąć / powiększyć mapę, należy spojrzeć na nakładkę SVG na Leaflet. To będzie o wiele łatwiejsze niż przekształcenie SVG. Zobacz ten przykład http://bost.ocks.org/mike/leaflet/, a następnie Jak zmienić środek mapy w ulotce
źródło
Po odpowiedzi mbostocks i komentarzu Herba Caudilla zacząłem mieć problemy z Alaską, odkąd użyłem projekcji mercator. Powinienem zauważyć, że dla własnych celów staram się projektować i skupiać Stany Zjednoczone. Okazało się, że muszę poślubić te dwie odpowiedzi z odpowiedzią Jana van der Laana z następującym wyjątkiem dla wielokątów, które nakładają się na półkule (wielokąty, które kończą się wartością bezwzględną dla Wschodu - Zachodu większą niż 1):
ustaw prostą projekcję w mercator:
projection = d3.geo.mercator (). scale (1) .translate ([0,0]);
utwórz ścieżkę:
path = d3.geo.path (). projection (projection);
3. ustaw moje granice:
4. Dodaj wyjątek dla Alaski i stwierdza, że półkule pokrywają się:
Mam nadzieję, że to pomoże.
źródło
Dla osób, które chcą wyregulować w pionie i poziomie, oto rozwiązanie:
źródło
Jak wyśrodkowałem Topojson, z którego musiałem wyciągnąć tę funkcję:
źródło