所以我正在尝试为使用 d3.js、polymaps 和 Coffeescript 的项目做一些地图标记聚类。
我根据基础数据计算集群,然后将集群数组作为 .data(clusters) 传递到 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 还是很陌生。