2013-06-11 10 views
7

Mi piacerebbe fare una transizione graduale tra Alber/ortografica in un mini app sto costruendo, proprio come in questo esempio:Come fare transizione graduale per la mappa riproiezione in d3.js

http://mbostock.github.io/d3/talk/20111018/#27

E ' sembra che questa transizione liscia è rotto in v3 tuttavia, con una transizione piuttosto instabile dei percorsi della mappa:

https://www.evernote.com/shard/s236/sh/46b002bd-9c5b-4e9b-87ef-270c303eb677/2eaeebb267a3fc59df5a8447bbbcc58b/res/37917835-5aad-4509-b534-31a3e3034762/Worst_Tornado_Outbreaks_of_All_Time-20130611-074050.jpg.jpg?resizeSmall&width=832

codice è piuttosto semplice, ho inizializzare la mappa come Albers, quindi eseguire orto() per aggiornarlo.

function ortho() { 
    var self = this, 
    h = 1000, 
    w = document.width; 

    this.projection = d3.geo.orthographic() 
    .scale(500) 
    .translate([ (w - 300)/2, h/2]) 
    .clipAngle(90) 
    .rotate([90, 0, 0]) 
    .precision(.1); 

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

    //update path WITH transition 
    d3.selectAll('path') 
    .transition() 
    .duration(900) 
    .attr('d', app.path); 

} 

La mappa cambia da albers a ortografica, ma la transizione non è regolare. Ogni pensiero sarebbe fantastico.

risposta

17

Se si interpola il percorso utilizzando l'interpolatore di stringa naïve di D3 (d3.interpolateString), il numero di coordinate nel percorso iniziale e il numero delle coordinate nel percorso finale devono corrispondere esattamente, incluso nello stesso ordine. Ma questo è quasi mai il caso a causa di clipping, cutting e resampling. Shape interpolation è possibile (utilizzando multiplestrategies), ma nel caso generale è un problema difficile da risolvere. Vedere this explanation (parte di Path Transitions) per il motivo per cui l'interpolazione ingenua è insufficiente.

Invece di interpolare il percorso, si desidera interpolare la proiezione. L'interpolazione della proiezione non richiede una corrispondenza esatta tra le coordinate e pertanto evita gli artefatti di interpolazione. Vedere questi esempi per una dimostrazione:

Come mostrato nel primo esempio, qui è un'implementazione è possibile utilizzare:

function interpolatedProjection(a, b) { 
    var projection = d3.geo.projection(raw).scale(1), 
     center = projection.center, 
     translate = projection.translate, 
     α; 

    function raw(λ, φ) { 
    var pa = a([λ *= 180/Math.PI, φ *= 180/Math.PI]), pb = b([λ, φ]); 
    return [(1 - α) * pa[0] + α * pb[0], (α - 1) * pa[1] - α * pb[1]]; 
    } 

    projection.alpha = function(_) { 
    if (!arguments.length) return α; 
    α = +_; 
    var ca = a.center(), cb = b.center(), 
     ta = a.translate(), tb = b.translate(); 
    center([(1 - α) * ca[0] + α * cb[0], (1 - α) * ca[1] + α * cb[1]]); 
    translate([(1 - α) * ta[0] + α * tb[0], (1 - α) * ta[1] + α * tb[1]]); 
    return projection; 
    }; 

    delete projection.scale; 
    delete projection.translate; 
    delete projection.center; 
    return projection.alpha(0); 
} 

Creare la proiezione interpolata usando tw o proiezioni a e b, quindi impostare l'alfa interpolato su un valore compreso tra 0 (per a) e 1 (per).

+3

È possibile interpolare la clipAngle in questo modo? Nessuno degli esempi dimostra questo: sto provando a passare da ortografico/90 ad equirettangolare/180 e ci sono molti strani artefatti – Casey