2015-12-16 12 views
5

Utworzyłem mapę d3 ze stanów USA, zgodnie z następującym przykładem:d3 Mapa USA stan z markerów, powiększanie przekształcić problemy

http://bl.ocks.org/mbostock/4699541

i dodaje znaczniki po tym SO pytanie:

Put markers to a map generated with topoJSON and d3.js

Problem polega na tym, że znaczniki mapy pozostają na swoim miejscu. Uważam, że muszę przetłumaczyć je na nowe stanowisko, ale nie wiem, jak to zrobić.

enter image description here

var width = 900, 
    height = 500, 
    active = d3.select(null); 

var projection = d3.geo.albersUsa() 
    .scale(1000) 
    .translate([width/2, height/2]); 

var path = d3.geo.path() 
    .projection(projection); 

var svg = d3.select(".rebates").append("svg") 
    .attr("width", width) 
    .attr("height", height); 

svg.append("rect") 
    .attr("class", "background") 
    .attr("width", width) 
    .attr("height", height) 
    .on("click", reset); 

var g = svg.append("g") 
    .style("stroke-width", "1.5px"); 

d3.json("/files/d3-geo/us.json", function(error, us) { 
    if (error) { throw error; } 

    g.selectAll("path") 
    .data(topojson.feature(us, us.objects.states).features) 
    .enter().append("path") 
    .attr("d", path) 
    .attr("class", function(item) { 
     return window.US_STATES[item.id].water_authorities > 0 ? 'avail' : 'unavail'; 
    }) 
    .on("click", clicked); 

    g.append("path") 
    .datum(topojson.mesh(us, us.objects.states, function(a, b) { return a !== b; })) 
    .attr("class", "mesh") 
    .attr("d", path); 
}); 

d3.json('/files/coordinates.json', function(error, coords) { 
    if (error) { throw error; } 

    svg.selectAll(".mark") 
    .data(coords) 
    .enter() 
    .append("image") 
    .attr('class','mark') 
    .attr('width', 20) 
    .attr('height', 20) 
    .attr("xlink:href",'assets/gmap_red.png') 
    .attr("transform", function(d) { 
     return "translate(" + projection([d[1],d[0]]) + ")"; 
    }); 
}); 

function clicked(d) { 
    if (active.node() === this) { return reset(); } 
    if (window.US_STATES[d.id].water_authorities === 0) { return; } 

    active.classed("active", false); 
    active = d3.select(this).classed("active", true); 

    var bounds = path.bounds(d), 
    dx = bounds[1][0] - bounds[0][0], 
    dy = bounds[1][1] - bounds[0][1], 
    x = (bounds[0][0] + bounds[1][0])/2, 
    y = (bounds[0][1] + bounds[1][1])/2, 
    scale = .9/Math.max(dx/width, dy/height), 
    translate = [width/2 - scale * x, height/2 - scale * y]; 

    g.transition() 
    .duration(750) 
    .style("stroke-width", 1.5/scale + "px") 
    .attr("transform", "translate(" + translate + ")scale(" + scale + ")"); 
} 

function reset() { 
    active.classed("active", false); 
    active = d3.select(null); 

    rebatesTable.clear().draw(); 

    g.transition() 
    .duration(750) 
    .style("stroke-width", "1.5px") 
    .attr("transform", ""); 
} 
+0

Zmieniłbym projekcję na zoom, a następnie ponownie obliczono pozycje znaczników ze zmienioną projekcją. –

Odpowiedz

6

Etap 1

dodać wszystkie punkty w grupie, a nie w SVG. Zapewni to, że punkty znacznika będą tłumaczyć z główną grupą.

g.selectAll(".mark")//adding mark in the group 
    .data(marks) 
    .enter() 
    .append("image") 
    .attr('class', 'mark') 
    .attr('width', 20) 
    .attr('height', 20) 
    .attr("xlink:href", 'https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/24x24/DrawingPin1_Blue.png') 
    .attr("transform", function(d) { 
     return "translate(" + projection([d.long, d.lat]) + ")"; 
    }); 

Krok 2

neguje efekt skalowania głównej grupy. w przeciwnym razie znaczniki zostaną powiększone.

g.selectAll(".mark") 
    .transition() 
    .duration(750) 
    .attr("transform", function(d) { 
     var t = d3.transform(d3.select(this).attr("transform")).translate;//maintain aold marker translate 
     return "translate(" + t[0] +","+ t[1] + ")scale("+1/scale+")";//inverse the scale of parent 
    });   

Step3

Na zoom out zrobić skalę znacznik z powrotem do 1.

g.selectAll(".mark") 
    .attr("transform", function(d) { 
     var t = d3.transform(d3.select(this).attr("transform")).translate; 
     console.log(t) 
     return "translate(" + t[0] +","+ t[1] + ")scale("+1+")"; 
    }); 

kod roboczych here

nadzieję, że to pomaga!

+1

Naprawdę doskonała odpowiedź, dziękuję! Wprowadziłem niewielką poprawę do kroku 3, dodając funkcję .transform(). Duration (750) (przed .attr (...)), która dodaje ten sam rodzaj łagodzenia w przypadku pomniejszania, jak przy powiększaniu. – Troy

+0

Jak mogę zachować względną pozycję znaczników podczas powiększania, zamiast przesuwać je na środek wybranej ścieżki stanu? – Nathan

+0

Wewnątrz funkcji "klikniętej" obliczany jest przelicznik, który trzeba będzie odpowiednio zaktualizować ... aby utworzyć znacznik w centrum – Cyril