2013-06-11 12 views
7

Chciałbym zrobić płynne przejście między Alber/ortogonalnego w mini aplikacji buduję, podobnie jak w poniższym przykładzie:Jak zrobić płynne przejście do mapy ponowne odwzorowanie w d3 js

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

It wydaje się, że to płynne przejście jest podzielona w v3 jednak z dość niestabilny przejścia ze ścieżek mAP:

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

kod jest bardzo prosty, zainicjować mapę według Albers, a następnie uruchomić orto() zaktualizować.

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

} 

Mapa zmienia się z albers na ortograficzny, ale przejście nie jest płynne. Wszelkie myśli byłyby świetne.

Odpowiedz

17

Jeśli interpolujesz ścieżkę za pomocą interpretera ciągów naiwnych D3 (d3.interpolateString), liczba współrzędnych w ścieżce początkowej i liczba współrzędnych na ścieżce końcowej muszą być dokładnie takie same, w tym w tej samej kolejności. Ale prawie nigdy tak się nie dzieje z powodu clipping, cutting i resampling. Shape interpolation jest możliwe (przy użyciu multiplestrategies), ale jest to trudny problem do rozwiązania w ogólnym przypadku. Zobacz this explanation (część Path Transitions), dlaczego naiwna interpolacja jest niewystarczająca.

Zamiast interpolować ścieżkę, należy interpolować projekcję. Interpolacja projekcji nie wymaga dokładnej zgodności między współrzędnymi, a zatem unika artefaktów interpolacji. Zobacz te przykłady do demonstracji:

Jak pokazano w pierwszym przykładzie, tutaj jest implementacją można użyć:

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

Utwórz interpolowaną projekcję za pomocą tw o rzuty a i b, a następnie ustaw interpolowaną alfę na wartość między 0 (dla a) a 1 (dla b).

+3

Czy można interpolować clipAngle w ten sposób? Żaden z przykładów tego nie demonstruje - próbuję przejść z ortograficznego/90 do equirectangular/180 i istnieje wiele dziwnych artefaktów – Casey