2015-12-16 41 views
5

Ho creato una mappa d3 con gli Stati Uniti d'America, seguendo questo esempio:d3 mappa di stato degli Stati Uniti con i marcatori, zoom trasformare problemi

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

e marcatori aggiunto seguendo questo SO domanda:

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

Il problema è che sullo zoom, i marcatori di mappa rimangono sul posto. Credo di aver bisogno di tradurli in una nuova posizione, ma non sono sicuro di come farlo accadere.

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

Vorrei cambiare la proiezione per ingrandire e quindi ricalcolare le posizioni dei marcatori con la proiezione modificata. –

risposta

6

Fase 1

aggiungere tutti i punti nel gruppo e non nel svg. Ciò assicurerà che i punti marker vengano tradotti con il gruppo principale.

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]) + ")"; 
    }); 

Step2

annulla l'effetto di scala del gruppo principale. altrimenti i marcatori verranno ingranditi.

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 
    });   

Fase 3

Su zoom out rendono la scala marcatore torna a 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+")"; 
    }); 

codice di lavoro here

Spero che questo aiuti!

+1

Risposta davvero eccellente, grazie! Ho apportato un piccolo miglioramento al passaggio 3 aggiungendo .transform(). Duration (750) (before .attr (...)) che aggiunge lo stesso tipo di easing allo zoom-out come per lo zoom-in. – Troy

+0

Come posso mantenere la posizione relativa dei marcatori durante lo zoom, anziché spostarlo al centro del percorso di stato selezionato? – Nathan

+0

All'interno della funzione 'cliccata' la traduzione viene calcolata dovrai aggiornarla di conseguenza..per rendere il marcatore al centro – Cyril