2013-02-28 10 views
6

Może to być klasyczny przypadek "robisz to źle", ale wszystkie moje dotychczasowe poszukiwania nie uzasadniają żadnej pomocy.Jak dostosować rozmiar powiększenia dla punktu w D3?

Oto mój scenariusz:

Używam mapę projekcję albersUSA w połączeniu z plikami krajowych i powiatu GeoJSON wyciągnąć wszystko.

Mam również utworzony przez siebie plik "miast" zawierający główne miasta dla każdego stanu. Współrzędne są dokładne i wszystko wygląda dobrze.

enter image description here

Gdy użytkownik kliknie na dany stan, chowam wszystkie kształty państwowe, a następnie obliczyć transformaty potrzebne, aby dostać kształty hrabstwo za taki stan aby zmieścić wewnątrz mojego widoku. Następnie stosuję tę transformację do wszystkich potrzebnych kształtów hrabstwa, aby uzyskać widok "powiększony". Mój kod wygląda następująco:

function CalculateTransform(objectPath) 
{ 
    var results = ''; 

    // Define bounds/points of viewport 
    var mapDimensions = getMapViewportDimensions(); 
    var baseWidth = mapDimensions[0]; 
    var baseHeight = mapDimensions[1]; 

    var centerX = baseWidth/2; 
    var centerY = baseHeight/2; 

    // Get bounding box of object path and calculate centroid and zoom factor 
    // based on viewport. 
    var bbox = objectPath.getBBox(); 
    var centroid = [bbox.x + bbox.width/2, bbox.y + bbox.height/2]; 
    var zoomScaleFactor = baseHeight/bbox.height; 
    var zoomX = -centroid[0]; 
    var zoomY = -centroid[1]; 

    // If the width of the state is greater than the height, scale by 
    // that property instead so that state will still fit in viewport. 
    if (bbox.width > bbox.height) { 
     zoomScaleFactor = baseHeight/bbox.width; 
    } 

    // Calculate how far to move the object path from it's current position to 
    // the center of the viewport. 
    var augmentX = -(centroid[0] - centerX); 
    var augmentY = -(centroid[1] - centerY); 

    // Our transform logic consists of: 
    // 1. Move the state to the center of the screen. 
    // 2. Move the state based on our anticipated scale. 
    // 3. Scale the state. 
    // 4. Move the state back to accomodate for the scaling. 
    var transform = "translate(" + (augmentX) + "," + (augmentY) + ")" + 
       "translate(" + (-zoomX) + "," + (-zoomY) + ")" + 
       "scale(" + zoomScaleFactor + ")" + 
       "translate(" + (zoomX) + "," + (zoomY) + ")"; 

    return results; 
} 

... a funkcja wiążąca

// Load county data for the state specified. 
d3.json(jsonUrl, function (json) { 
    if (json === undefined || json == null || json.features.length == 0) 
    { 
     logging.error("Failed to retrieve county structure data."); 
     showMapErrorMessage("Unable to retrieve county structure data."); 
     return false; 
    } 
    else 
    { 
     counties.selectAll("path") 
       .data(json.features) 
       .enter() 
        .append("path") 
         .attr("id", function (d, i) { 
         return "county_" + d.properties.GEO_ID 
         }) 
         .attr("data-id", function (d, i) { return d.properties.GEO_ID }) 
         .attr("data-name", function (d, i) { return countyLookup[d.properties.GEO_ID] }) 
         .attr("data-stateid", function (d, i) { return d.properties.STATE }) 
         .attr("d", path); 

     // Show all counties for state specified and apply zoom transform. 
     d3.selectAll(countySelector).attr("visibility", "visible"); 
     d3.selectAll(countySelector).attr("transform", stateTransform); 

     // Show all cities for the state specified and apply zoom transform 
     d3.selectAll(citySelector).attr("visibility", "visible"); 
     d3.selectAll(citySelector).attr("transform", stateTransform); 
    } 
}); 

enter image description here

Działa to dobrze tutaj, z wyjątkiem bardzo małych państw, współczynnik zoom jest znacznie większa, a kręgi się zacierają.

enter image description here

Czy istnieje sposób zmusić wielkości punktami być stałym rozmiarze (słownie promieniu 15px), nawet po transformacji występuje?

Odpowiedz

5

Dzieje się tak, ponieważ ustawiasz przeliczanie skali zamiast skalowania pozycji. Widać różnicę here W zasadzie to jest różnica pomiędzy:

// Thick lines because they are scaled too 
var bottom = svg.append('g').attr('transform', 'scale('+scale+','+scale+')'); 
bottom.selectAll('circle') 
    .data(data) 
    .enter().append('circle') 
    .attr('cx', function(d) { return d.x; }) 
    .attr('cy', function(d) { return d.y; }); 

i

// line thicknesses are nice and thin 
var top = svg.append('g'); 
top.selectAll('circle') 
    .data(data) 
    .enter().append('circle') 
    .attr('cx', function(d) { return d.x * scale; }) 
    .attr('cy', function(d) { return d.y * scale; }); 

z mapowaniem Prawdopodobnie najlepszym rozwiązaniem jest, aby obliczyć swój offsetu i skalę, jak to zrobić, a następnie dodać je do funkcja projekcji - chcesz bezpośrednio zmodyfikować wartości X i Y po projekcji. Jeśli zaktualizujesz poprawnie funkcję projekcji, nie powinieneś robić nic więcej, aby zastosować odpowiedni zoom do swojej mapy.

+0

To ma sens! Zajrzę do skrzypiec, który dostarczyłeś, i sprawię, że zadziała dla mojego rozwiązania. –

5

W przypadku rzeczy, których nie chcesz przeskalować, po prostu podziel je według "skali". W moim przypadku:

var zoom = d3.behavior.zoom() 
    .on("zoom",function() { 
     g.attr("transform","translate("+d3.event.translate.join(",")+")scale("+d3.event.scale+")"); 

     g.selectAll(".mapmarker") 
     .attr("r",6/d3.event.scale) 
     .attr("stroke-width",1/d3.event.scale); 

}); 
Powiązane problemy