d3.js中SVG元素的集群会产生意外的结果
因此,我正在尝试为一个使用d3.js、polymaps和Coffeescript的项目进行一些地图标记聚类 我基于底层数据计算集群,然后将集群数组作为.data(集群)传递到d3中 集群的位置似乎还可以。在初始缩放级别上的聚类似乎是可以的,并且据我所知是100%准确的。当我更改缩放级别时,乍一看一切都正常,但当我将鼠标悬停在圆圈上时,描述似乎与它们所在的位置不匹配,路线以前所在的位置似乎与它们现在所在的位置不匹配 我准备了一个包含完整代码的示例 我看到了两个主要的失败点:集群和更新SVG 集群的代码相当简单,并且基于来自的代码,但是使用coffeescript而不是phpd3.js中SVG元素的集群会产生意外的结果,svg,coffeescript,d3.js,Svg,Coffeescript,D3.js,因此,我正在尝试为一个使用d3.js、polymaps和Coffeescript的项目进行一些地图标记聚类 我基于底层数据计算集群,然后将集群数组作为.data(集群)传递到d3中 集群的位置似乎还可以。在初始缩放级别上的聚类似乎是可以的,并且据我所知是100%准确的。当我更改缩放级别时,乍一看一切都正常,但当我将鼠标悬停在圆圈上时,描述似乎与它们所在的位置不匹配,路线以前所在的位置似乎与它们现在所在的位置不匹配 我准备了一个包含完整代码的示例 我看到了两个主要的失败点:集群和更新SVG 集群的
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
cluster:(元素,距离)->
currentElements=elements.slice(0)
pixelDistance=@pixelDistance()
distLat=距离*像素距离.lat
distLon=距离*像素距离.lon
集群=[]
而currentElements.length>0
stop=currentElements.shift()
集群=[]
按钮停止
i=0
而我
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]
)
更新:->
如果不是,停止
@停止=[]
如果不是@prevNumStops
@prevNumStops=0
如果不是@prevZoom
@prevZoom=0
如果@zoomLevel()!=@prevZoom或@prevNumStops!=@长度
@prevZoom=@zoomLevel()
@prevNumStops=@stops.length
开始=新日期()
@集群=@cluster(@stops,10)
console.log@clusters
console.log“集群:”+((新日期())-start)
开始=新日期()
marker=@selector.selectAll(“g”).data(@clusters)
marker.enter().append(“g”)
.附加(“圆圈”)
.attr(“类”,“停止,无提示”)
marker.exit().remove()
@选择器。全选(“g”)。全选(“圆圈”)
.attr('r',(cluster)->如果cluster.length>1,则为5,否则为3.5)
.attr(“文本”,(集群)->“”+(((“- ”+路由+“
”)表示站点中的路由。join(“”)表示集群中的站点。join(“+”
”)
@selector.selectAll(“g”).attr(“转换”,(群集)=>
@变换簇[0]
)
我觉得这里可能缺少一些简单的东西,但我对d3还是相当陌生。当数据更改时,现有标记中的“圆”元素不会更新(d3使用每个默认值的索引来确定是添加(输入)、删除(退出)还是更新(默认值))。这将使文本成为该缩放级别上已存在的所有元素的上一缩放级别的旧文本 它应使用以下代码:
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()