2013-07-02 28 views
2

我一直试图解决这个问题几天,并完全难住。如何使用D3和CoffeeScript将图像替换为网络可视化图像?

我使用这个网络实现步行通过: http://flowingdata.com/2012/08/02/how-to-make-an-interactive-network-visualization/

enter image description here

我已经成功地通过这次演练创造了我的可视化,现在想用一个小图片替换节点,根据节点的值。

这是一个很好的代码示例,其中每个节点都被替换为图像。 HTTP://bl.ocks .ORG/mbostock/950642

具体做法是:

node.append("image") 
.attr("xlink:href", "https://github.com/favicon.ico") 
.attr("x", -8) 
.attr("y", -8) 
.attr("width", 16) 
.attr("height", 16); 

唯一的问题是,这个代码是在JavaScript中,我实现了网络图的是写在CoffeeScript的。

我试着用上面的代码创建我自己的JavaScript文件并链接到它,但是这对我没有用,坦率地说我不知道​​这是否是最好的方法。

我试着通过这个JS将代码从JavaScript转换成CoffeeScript到CoffeeScript工具,http://js2coffee.org/,但是我不熟悉CoffeeScript足以将代码添加到正确的位置......我觉得我已经试过了没有运气的现货。

我正在尝试做的事情是根据节点包含的数据放置一个特定的图片来代替节点。我更希望在CoffeeScript本身中有一个if语句来插入基于所选节点的图片(可以是名称或组等)。我还希望每个节点都有文本标签,比如说“金额”,但是我仍然需要更多地研究如何做到这一点。

样本节点:

"nodes" : [{ 
"match" : "1.0", 
"name" : "Airplane", 
"virtualAmount" : "1000", 
"artist" : "Airplane", 
"amount" : "999.99", 
"id" : "a1234", 
"playcount" : "500", 
"group" : "airplanePic.jpg" 
}, { 

谢谢!任何帮助将非常感谢!

编辑:(我的代码)

谢谢拉尔斯,我不知道了无法使用的图像与SVG的。这里是我正在使用的代码:

这是CoffeeScript部分,我相信我需要编辑以获取我想要的SVG文件来替换当前节点的圆。

# enter/exit display for nodes 
updateNodes =() -> 
    node = nodesG.selectAll("circle.node") 
    .data(curNodesData, (d) -> d.id) 

node.enter().append("circle") 
    .attr("class", "node") 
    .attr("cx", (d) -> d.x) 
    .attr("cy", (d) -> d.y) 
    .attr("r", (d) -> d.radius) 
    .style("fill", (d) -> nodeColors(d.artist)) 
    .style("stroke", (d) -> strokeFor(d)) 
    .style("stroke-width", 1.0) 

我一直在尝试使用if语句,就像这样,但我是CoffeeScript的新手,所以要温柔。

if d.group is "airplane"  #comment: or whatever group name I'm looking for 
.attr("src", "tinyWhale.jpg") 

但是,我现在意识到这是行不通的,因为我无法将图像导入SVG。即使在阅读Lar的评论和链接问题之后,我仍然对如何用SVG替换节点仍然感到困惑。

我能创建一个if语句,并用一个Google搜索的svg文件替换圆圈吗?

再次感谢您的帮助。

更新2: 非常感谢Lars,我试图将其添加到vis.coffee文件中,但是当我添加任何代码时它会中断。以下是我如何添加代码:

第4个.attr是添加的代码。

node.enter().append("circle") 
    .attr("class", "node") 
    .attr("cx", (d) -> d.x) 
    .attr("cy", (d) -> d.y) 
    .attr("r", (d) -> d.radius) #this is the code added 
    .attr("fill", (d) -> "url(#" + d.group + ")") 
    .style("fill", (d) -> nodeColors(d.artist)) 
    .style("stroke", (d) -> strokeFor(d)) 
    .style("stroke-width", 1.0) 

我在这里添加了这个,这也打破了代码。我是否把这个放在完全错误的地方?

# Starting point for network visualization 
# Initializes visualization and starts force layout 
network = (selection, data) -> 
# format our data 
allData = setupData(data) 

# create our svg and groups 
vis = d3.select(selection).append("svg") 
    .attr("width", width) 
    .attr("height", height) 
linksG = vis.append("g").attr("id", "links") 
nodesG = vis.append("g").attr("id", "nodes") 

defs = svg.append("defs") 

defs.selectAll("pattern") 
    .data(curNodesData) 
    .append("pattern") 
    .attr("id", (d) -> d.group) 
    .append("image") 
    .attr("xlink:href", (d) -> d.group) 

感谢您的帮助和耐心!

这里是我的vis.coffee文件: https://开头dl.dropboxusercontent的.com/U/18496047/vis.coffee 加空格,因为它不会让我对这个问题不止一个链接。

编辑3: 使用此来结束,我希望能帮助我找出CoffeeScript节点的实现。

# create node objects from original data 
# that will serve as the data behind each 
# bubble in the vis, then add each node 
# to @nodes to be used later 
create_nodes:() => 
    @data.forEach (d) => 
    node = { 
     id: d.id 
     radius: @radius_scale(d.total_amount) 
     value: d.total_amount 
     name: d.tweet_rate 
     org: d.organization 
     group: d.tweet_amount 
     top_conv: d.top_conv 
     x: Math.random() * 900 
     y: Math.random() * 800 
    } 
    @nodes.push node 

    @nodes.sort (a,b) -> b.value - a.value 


# create svg at #vis and then 
# create circle representation for each node 
create_vis:() => 
    @vis = d3.select("#vis").append("svg") 
    .attr("width", @width) 
    .attr("height", @height) 
    .attr("id", "svg_vis") 

    @circles = @vis.selectAll("circle") 
    .data(@nodes, (d) -> d.id) 

    # used because we need 'this' in the 
    # mouse callbacks 
    that = this 

    # radius will be set to 0 initially. 
    # see transition below 
    @circles.enter().append("circle") 
    .attr("r", 0) 
    .attr("fill", (d) => @fill_color(d.group)) 
    .attr("stroke-width", 2) 
    .attr("stroke", (d) => d3.rgb(@fill_color(d.group)).brighter(5)) 
    .attr("id", (d) -> "bubble_#{d.id}") 
    .on("mouseover", (d,i) -> that.show_details(d,i,this)) 
    .on("mouseout", (d,i) -> that.hide_details(d,i,this)) 

    # Fancy transition to make bubbles appear, ending with the 
    # correct radius 
    @circles.transition().duration(2000).attr("r", (d) -> d.radius) 

编辑4:

我转换CoffeeSctipt为JavaScript的可读性和我自己的舒适性。

任何答案都可以通过JS或CoffeeScript提供。

谢谢...这个问题正在杀死我。

谁想要帮助: plnkr.co/edit/DeI4a0gjg0p8ypRS2HUn?p=preview

回答

0

您不能直接在SVG使用这样的图像,则需要将它们定义为图案。有关更多信息,请参阅this question。您没有向我们展示您的代码,但我怀疑这是您问题的根源。

您需要做的是在SVG的defs部分为每个需要的图像添加一个模式,然后在添加节点时引用这些模式。代码看起来像这样。

defs = svg.append("defs") 
defs.selectAll("pattern") 
    .data(curNodesData) 
    .append("pattern") 
    .attr("id", (d) -> d.group) 
    .append("image") 
    .attr("xlink:href", (d) -> d.group) 

您可能需要设置尺寸为pattern S和image秒。再后来,你可以做以下

node.enter().append("circle") 
    .attr("fill", (d) -> "url(#" + d.group + ")") 

您可能需要调整产生模式ID的方式,特别是当你开始使用绝对URL。

+0

感谢拉尔斯,我已经更新了我的追问我的一些代码,我试图找出如何为defs部分中的每个图像添加一个模式。感谢您指点我正确的方向!你已经为我节省了很多时间。这是我第一次发布,很长一段时间潜伏在StackOverflow上,所以请让我知道是否有任何事情可以帮助我澄清我的问题,代码或其他任何内容。我已将代码添加到我的html部分,并且图像链接到图像,但是我完全停留在那里。 – SeaData

+0

查看我更新的答案。 –

+0

谢谢拉尔斯!我更新了我尝试的实现,但是,我对CoffeeScript的经验不足真的让我受到伤害。我必须把代码放在错误的地方。 – SeaData

2

为什么不更换的圈子与你的形象:

node.enter().append("image") 
    .attr("class", "node") 
    .attr("href", "tinyWhale.jpg") 
    .attr("x", function(d) { return d.x;}) 
    .attr("y", function(d) { return d.y;}) 
    .attr("width", function(d) { return d.radius;}) 
    .attr("height", function(d) { return d.radius;}) 

代替:

node.enter().append('circle')...