【问题标题】:How do I replace a node with an image using D3 and CoffeeScript for a network visualization?如何使用 D3 和 CoffeeScript 将节点替换为图像以进行网络可视化?
【发布时间】:2013-06-29 09:41:36
【问题描述】:

我已经尝试解决这个问题好几天了,完全被难住了。

我正在使用此网络实施演练: http://flowingdata.com/2012/08/02/how-to-make-an-interactive-network-visualization/

我已通过此演练成功创建了我的可视化,现在想根据节点的值用小图片替换节点。

这是一个很好的代码示例,其中每个节点都替换为图像。 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 到 CoffeeScript 工具 http://js2coffee.org/ 将代码从 JavaScript 转换为 CoffeeScript,但是我对 CoffeeScript 的熟悉程度不足以将代码添加到正确的位置......我觉得我已经试过了每个地方都没有运气。

我真正想做的是根据节点包含的数据将特定图片放在节点的位置。我希望在 CoffeeScript 本身中有一个 if 语句,以根据所选节点插入图片(可以是名称或组或其他任何内容。)我还希望每个节点都有文本标签,显示,说“数量”,但是我仍然需要更多地研究如何做到这一点。

示例节点:

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

谢谢!任何帮助将不胜感激!

编辑:(使用我的代码)

谢谢 Lars,我不知道无法将图像与 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

【问题讨论】:

    标签: javascript html d3.js coffeescript force-layout


    【解决方案1】:

    为什么不用你的图片替换圆圈:

    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')...
    

    【讨论】:

      【解决方案2】:

      您不能直接在 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)
      

      您可能需要设置patterns 和images 的尺寸。然后稍后您可以执行以下操作

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

      您可能需要调整模式 ID 的生成方式,尤其是在您开始使用绝对 URL 时。

      【讨论】:

      • 感谢 Lars,我已经用我的一些代码更新了我的任务,并试图弄清楚如何在 defs 部分中为每个图像附加一个模式。感谢您为我指明正确的方向!你已经为我节省了很多时间。这是我第一次发帖,长期潜伏在 StackOverflow 上,所以请让我知道是否有任何我可以做的事情来帮助澄清我的问题、代码或其他任何事情。我已将 代码添加到我的 html 部分,并带有图像 xlink 到图像,但是我完全卡在那里。
      • 谢谢拉斯!我更新了我尝试的实现,但是,我缺乏使用 CoffeeScript 的经验真的让我很受伤。我一定是把代码放错地方了。
      • 在这一点上,如果你能提供一个完整的例子来说明你在jsfiddle 这样的事情上要做什么,那将是非常有帮助的。我对您发布的各种代码如何组合在一起感到有些困惑。
      • 嗨 Lars,我试图在 jsfiddle 中插入我的进度,但是在显示它时遇到了重大问题。该代码与flowingdata.com/2012/08/02/… 基本相同,因为所做的唯一重大更改是在文件中获取我自己的数据,我无法上传这些数据。 :/ 好消息,我发现作者的 cmets 他已经看到了在此链接上为节点隐含图像的尝试,但我仍在努力隐含。 apike.ca/prog_svg_images.html 糟糕的 JS Fiddle 尝试。 jsfiddle.net/seadata/5nLX8 感谢您的帮助。
      • 我希望我可以使问题更简单直接,并且可以在 jsfiddle 中为您提供更好的代码库以供您使用。感谢您的帮助拉斯,我意识到这是一个非常复杂的信息混乱,所以如果我没有给你正确的信息继续,我道歉。有一个好男人。
      猜你喜欢
      • 1970-01-01
      • 2022-12-06
      • 2019-08-14
      • 2019-08-10
      • 1970-01-01
      • 2018-02-07
      • 2019-08-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多