Derzeit müssen Sie in d3 ein geoJSON-Objekt, das Sie zeichnen möchten, skalieren und übersetzen, um es auf die gewünschte Größe zu bringen, und es übersetzen, um es zu zentrieren. Dies ist eine sehr mühsame Aufgabe des Versuchs und Irrtums, und ich habe mich gefragt, ob jemand einen besseren Weg kennt, um diese Werte zu erhalten?
Also zum Beispiel, wenn ich diesen Code habe
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");
});
Wie zum Teufel erhalte ich .scale (8500) und .translate ([0, -1200]), ohne nach und nach zu gehen?
Antworten:
Das Folgende scheint ungefähr das zu tun, was Sie wollen. Die Skalierung scheint in Ordnung zu sein. Beim Anwenden auf meine Karte gibt es einen kleinen Versatz. Dieser kleine Versatz wird wahrscheinlich verursacht, weil ich den Befehl translate verwende, um die Karte zu zentrieren, während ich wahrscheinlich den Befehl center verwenden sollte.
In Code:
quelle
projection.fitSize([width, height], geojson)
( API-Dokumente ) - siehe die Antwort von @dnltsk unten.Meine Antwort ist nahe an der von Jan van der Laan, aber Sie können die Dinge leicht vereinfachen, da Sie den geografischen Schwerpunkt nicht berechnen müssen. Sie brauchen nur den Begrenzungsrahmen. Mithilfe einer nicht skalierten, nicht übersetzten Einheitenprojektion können Sie die Mathematik vereinfachen.
Der wichtige Teil des Codes ist folgender:
Nachdem Sie den Begrenzungsrahmen des Features in der Einheitenprojektion berechnet haben, können Sie den entsprechenden Maßstab berechnen, indem Sie das Seitenverhältnis des Begrenzungsrahmens (
b[1][0] - b[0][0]
undb[1][1] - b[0][1]
) mit dem Seitenverhältnis der Leinwand (width
undheight
) vergleichen. In diesem Fall habe ich den Begrenzungsrahmen auch auf 95% der Leinwand anstatt auf 100% skaliert, sodass an den Rändern etwas mehr Platz für Striche und umgebende Merkmale oder Polsterungen vorhanden ist.Anschließend können Sie die Übersetzung anhand der Mitte des Begrenzungsrahmens (
(b[1][0] + b[0][0]) / 2
und(b[1][1] + b[0][1]) / 2
) und der Mitte der Leinwand (width / 2
undheight / 2
) berechnen . Da sich der Begrenzungsrahmen in den Koordinaten der Einheitsprojektion befindet, muss er mit der Skala (s
) multipliziert werden .Zum Beispiel bl.ocks.org/4707858 :
Es gibt eine verwandte Frage, wo man auf ein bestimmtes Feature in einer Sammlung zoomen kann, ohne die Projektion anzupassen, dh die Projektion mit einer geometrischen Transformation zu kombinieren, um hinein- und herauszuzoomen. Dies verwendet die gleichen Prinzipien wie oben, aber die Mathematik unterscheidet sich geringfügig, da die geometrische Transformation (das SVG-Attribut "transform") mit der geografischen Projektion kombiniert wird.
Zum Beispiel bl.ocks.org/4699541 :
quelle
* 500
hier irrelevant ...b[1][1] - b[0][0]
sollte auchb[1][1] - b[0][1]
in der Skalenberechnung sein.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));
Mit d3 v4 oder v5 wird es viel einfacher!
und schlussendlich
Viel Spaß, Prost
quelle
d3v4
eine Weile mit und habe gerade diese Methode entdeckt.g
das? Ist das der SVG-Container?g
sollte<g></g>
tagIch bin neu in d3 - werde versuchen zu erklären, wie ich es verstehe, aber ich bin nicht sicher, ob ich alles richtig gemacht habe.
Das Geheimnis ist zu wissen, dass einige Methoden im kartografischen Raum (Breite, Länge) und andere im kartesischen Raum (x, y auf dem Bildschirm) funktionieren. Der kartografische Raum (unser Planet) ist (fast) sphärisch, der kartesische Raum (Bildschirm) ist flach - um einen übereinander abzubilden, benötigen Sie einen Algorithmus, der als Projektion bezeichnet wird . Dieser Raum ist zu kurz, um tief in das faszinierende Thema der Projektionen einzudringen und wie sie geografische Merkmale verzerren, um sphärisch in eben zu verwandeln. Einige sind so konzipiert, dass Winkel erhalten bleiben, andere Entfernungen usw. - es gibt immer einen Kompromiss (Mike Bostock hat eine riesige Sammlung von Beispielen ).
In d3 hat das Projektionsobjekt eine Center-Eigenschaft / einen Setter, die in Karteneinheiten angegeben ist:
Es gibt auch die Übersetzung in Pixel - wobei das Projektionszentrum relativ zur Leinwand steht:
Wenn ich ein Feature auf der Leinwand zentrieren möchte, möchte ich das Projektionszentrum auf die Mitte des Feature-Begrenzungsrahmens setzen. Dies funktioniert bei Verwendung von mercator (WGS 84, in Google Maps verwendet) für mein Land (Brasilien). nie mit anderen Vorsprüngen und Halbkugeln getestet. Möglicherweise müssen Sie Anpassungen für andere Situationen vornehmen, aber wenn Sie diese Grundprinzipien festlegen, wird es Ihnen gut gehen.
Beispiel: Projektion und Pfad:
Die
bounds
Methode vonpath
gibt den Begrenzungsrahmen in Pixel zurück . Verwenden Sie diese Option, um den richtigen Maßstab zu finden, indem Sie die Größe in Pixel mit der Größe in Karteneinheiten vergleichen (0,95 ergibt einen Rand von 5% gegenüber der besten Anpassung für Breite oder Höhe). Grundlegende Geometrie hier, Berechnung der Rechteckbreite / -höhe bei diagonal gegenüberliegenden Ecken:Verwenden Sie die
d3.geo.bounds
Methode, um den Begrenzungsrahmen in Karteneinheiten zu finden:Stellen Sie die Mitte der Projektion auf die Mitte des Begrenzungsrahmens ein:
Verwenden Sie die
translate
Methode, um die Mitte der Karte in die Mitte der Leinwand zu verschieben:Inzwischen sollte die Funktion in der Mitte der Karte mit einem Rand von 5% gezoomt sein.
quelle
Es gibt eine center () -Methode, die ein Lat / Lon-Paar akzeptiert.
Soweit ich weiß, wird translate () nur verwendet, um die Pixel der Karte buchstäblich zu verschieben. Ich bin mir nicht sicher, wie ich den Maßstab bestimmen soll.
quelle
Neben Zentrum eine Karte in d3 ein GeoJSON Objekt gegeben , beachten Sie, dass Sie es vorziehen , können
fitExtent()
über ,fitSize()
wenn Sie eine Polsterung um die Grenzen des Objekts angeben möchten.fitSize()
setzt diese Auffüllung automatisch auf 0.quelle
Ich habe mich im Internet nach einer unkomplizierten Möglichkeit umgesehen, meine Karte zu zentrieren, und mich von Jan van der Laan und der Antwort von mbostock inspirieren lassen. Hier ist eine einfachere Möglichkeit, jQuery zu verwenden, wenn Sie einen Container für das SVG verwenden. Ich habe einen Rand von 95% für Polsterung / Ränder usw. erstellt.
Wenn Sie nach einer genauen Skalierung suchen, funktioniert diese Antwort bei Ihnen nicht. Wenn Sie jedoch wie ich eine Karte anzeigen möchten, die in einem Container zentralisiert ist, sollte dies ausreichen. Ich habe versucht, die Mercator-Karte anzuzeigen, und festgestellt, dass diese Methode bei der Zentralisierung meiner Karte hilfreich ist und ich den antarktischen Teil leicht abschneiden kann, da ich ihn nicht benötige.
quelle
Um die Karte zu schwenken / zu zoomen, sollten Sie die SVG-Datei auf der Broschüre überlagern. Das ist viel einfacher als die Transformation der SVG. Sehen Sie sich dieses Beispiel an: http://bost.ocks.org/mike/leaflet/ und dann So ändern Sie das Kartenzentrum in der Broschüre
quelle
Mit der Antwort von mbostocks und dem Kommentar von Herb Caudill stieß ich auf Probleme mit Alaska, da ich eine Mercator-Projektion verwendete. Ich sollte beachten, dass ich für meine eigenen Zwecke versuche, US-Staaten zu projizieren und zu zentrieren. Ich stellte fest, dass ich die beiden Antworten mit der Antwort von Jan van der Laan heiraten musste, mit der folgenden Ausnahme für Polygone, die Hemisphären überlappen (Polygone, die einen absoluten Wert für Ost - West haben, der größer als 1 ist):
Richten Sie eine einfache Projektion in mercator ein:
Projektion = d3.geo.mercator (). scale (1) .translate ([0,0]);
Erstellen Sie den Pfad:
path = d3.geo.path (). Projektion (Projektion);
3. Richten Sie meine Grenzen ein:
4. Fügen Sie eine Ausnahme für Alaska und Staaten hinzu, die die Hemisphären überlappen:
Ich hoffe das hilft.
quelle
Für Leute, die vertikal und horizontal einstellen möchten, ist hier die Lösung:
quelle
Wie ich einen Topojson zentriert habe, wo ich das Feature herausziehen musste:
quelle