2012-07-22 39 views
2

因此,我正在嘗試爲使用d3.js,polymaps和Coffeescript的項目做一些地圖標記聚類。d3.js中SVG元素的聚類產生意想不到的結果

我計算基於所述基礎數據的簇,然後羣集陣列傳遞到D3爲。數據(簇狀物)

簇的放置似乎是確定。初始縮放級別上的聚類似乎沒問題,根據我的知識是100%準確的。當我改變縮放級別時,乍看起來一切似乎都很好,但是當我將鼠標懸停在圈子上時,說明似乎與它們的位置以及路線之前的位置相匹配,看起來並不匹配現在。

我在http://bl.ocks.org/3161013上準備了一個包含完整代碼的例子。

我看到兩個主要的失敗點:集羣和更新SVG。

聚類的代碼相當簡單,並基於Mark Tuupola,但在coffeescript而不是php。

cluster: (elements, distance) -> 
    currentElements = elements.slice(0) 
    pixelDistance = @pixelDistance() 
    distLat = distance * pixelDistance.lat 
    distLon = distance * pixelDistance.lon 

    clustered = [] 
    while currentElements.length > 0 
     stop = currentElements.shift() 

     cluster = [] 
     cluster.push stop 

     i = 0 
     while i < currentElements.length 
     if Math.abs(currentElements[i].lat - stop.lat) < distLat and Math.abs(currentElements[i].lon - stop.lon) < distLon 
      aStop = currentElements.splice i,1 
      cluster.push aStop[0] 
      i-- 
     i++ 
     clustered.push cluster 
    clustered 

SVG更新代碼看起來像是相當直接的d3代碼。當地圖移動時,這個更新方法被調用。如果縮放已經改變,或者預聚集的數據已經改變,我們重新聚類和佈局,否則我們只是翻譯現有的點。

update: -> 
    if not @stops 
     @stops = [] 

    if not @prevNumStops 
     @prevNumStops = 0 

    if not @prevZoom 
     @prevZoom = 0 


    if @zoomLevel() != @prevZoom or @prevNumStops != @stops.length 
     @prevZoom = @zoomLevel() 
     @prevNumStops = @stops.length 

     start = new Date() 
     @clusters = @cluster(@stops,10) 
     console.log @clusters 
     console.log "clustering: " + ((new Date()) - start) 

     start = new Date() 
     marker = @selector.selectAll("g").data(@clusters) 
     marker.enter().append("g") 
     .append("circle") 
     .attr("class", "stop no-tip") 
     marker.exit().remove() 
     @selector.selectAll("g").selectAll("circle") 
     .attr('r', (cluster) -> if cluster.length > 1 then 5 else 3.5) 
     .attr("text", (cluster) -> "<ul>" + ((("<li>" + route + "</li>") for route in stop.routes).join("") for stop in cluster).join("") + "</ul>") 

    @selector.selectAll("g").attr("transform", (cluster) => 
     @transform cluster[0] 
    ) 

我覺得這裏可能有些簡單的東西我很想念,但是我對d3還是比較新的。

回答

1

當數據發生變化時(d3使用默認索引來確定是否添加新元素(輸入),刪除(退出)或更新(默認)),現有標記內的'circle'元素不會更新。這會使文本成爲之前縮放級別的舊文本,用於該縮放級別上已存在的所有元素。

應該用下面的代碼工作:

marker = @selector.selectAll("g").data(@clusters) 

# update existing 'g' elements 
marker.select('circle') 
.attr('r', your_cluster_size_function) 
.attr("text", your_text_function) 


# add new 'g' elements 
marker.enter().append("g") 
.append("circle") 
.attr("class", "stop no-tip") 
.attr('r', your_cluster_size_function) 
.attr("text", your_text_function) 

# remove 'g' elements if there are too many 
marker.exit().remove() 
相關問題