2016-03-31 15 views
5

Sto cercando di ottimizzare un po 'l'SVG che sto generando utilizzando il fantastico modulo geografico D3js.Semplificando la stringa generata dal percorso SVG di D3js

Sto usando d3.geo.path come il generatore di attributo d per i percorsi SVG:

path = d3.geo.path().projection(config.projection); // projection is initialized somewhere else 

e poi usarlo per rendere i percorsi come questo:

svg.selectAll(".country") 
    .data(countries) 
    .enter() 
    .insert("path", ".graticule") 
    .attr({ 
     class: "country", 
     d: path 
    }) 

e il tipo di percorso corde che sto ottenendo sono come questo:

M713.601085,459.8780053259876L714.7443994399441,460.08170562468473L715.0310281028103,460.5903728431771L715.0310281028103... 

Come si può vedere, alcuni i numeri sono estremamente lunghi con troppi decimali e non sono veramente utili alla mia attuale risoluzione, che ostruisce un po 'il DOM e rende pigro il debug di questi percorsi (ce ne sono anche molti, dato che è una mappa del mondo con un sacco di paesi disegnati su di esso).

Quindi il mio primo approccio è stato la creazione di questo pathSimplified wrapper per path:

// Path simplified: take some decimals out of the 'd' string 
pathSimplified = function (d) { 
     return path(d).replace(/(\.\d{4})\d+/g, '$1'); 
    }; 

e poi usarlo al posto del path:

//... 
    .attr({ 
     class: "country", 
     d: pathSimplified 
    }) 

che funziona e ora ho solo 4 cifre decimali per ogni valore sulla stringa del percorso. Mi piace questo:

M713.6010,459.8780L714.7443,460.0817L715.0310,460.5903L715.0310... 

La mia domanda è: può essere fatto in un modo migliore, meno hackerato? Non sembra giusto modificare la stringa dopo che è stata sputata dalla funzione path di D3js e sarebbe bello specificare l'arrotondamento a un certo punto del percorso stesso o della proiezione ...

+0

Nel mio caso ho scelto una larghezza SVG virtuale (viewBox) abbastanza grande da mostrare tutti i dettagli di cui ho bisogno e quindi ho rimosso completamente i decimali: 'const path_trunc = d => percorso (d) .replace (/ \. \ d +/g, '') 'Ma mi stavo chiedendo anche se geo.path avesse questa funzionalità nascosta da qualche parte. – Tobia

risposta

2

La tua idea è buona, semplificando una polilinea aiuta, ma puoi certamente farlo meglio di troncare le coordinate: algoritmi per la polilinea Esistono e potrebbero dare risultati più belli.

Ad esempio, dare un'occhiata allo Ramer-Douglas-Peucker algorithm. È implementato in librerie come Simplify.js (controlla la demo su quella pagina), che ti permette anche di regolarlo con tolleranza. Dovrai passare la linea come una matrice di x/y coords, ma credo che non sia troppo complicato da fare.

Ho anche notato che le proiezioni geografiche d3 consentono un parametro di precisione (come here), forse c'è qualcosa di simile a cui si è trascurato? In ogni caso, semplificare le coordinate da solo con semplify.js è sempre possibile.

+0

Grazie per le informazioni, esaminerò il parametro di precisione in d3.geo. Ad ogni modo, si noti che ciò di cui ho bisogno non sta semplificando il poligono reale, poiché questo è già risolto usando l'utilità 'topojson' (Tutte le informazioni qui: https://bost.ocks.org/mike/map/). La mia intenzione è semplicemente il taglio delle cifre decimali per la verbosità di DOM. Quindi la necessità di controllare l'output della funzione 'path'. –

+1

@ ÓscarGómezAlcañiz Bene, idealmente ci sono algoritmi [adattamento adattativo] (http://bl.ocks.org/mbostock/3795544) che ridurranno anche il numero di punti, senza perdere troppi dettagli.Se hai solo bisogno di troncare, allora la tua soluzione è già a posto, l'unica cosa che può renderlo migliore è se d3.geo permette effettivamente di ridurre la precisione dell'output. – Sosdoc