【问题标题】:associating a javascript object to an SVG element将 javascript 对象关联到 SVG 元素
【发布时间】:2014-07-15 04:30:39
【问题描述】:

目标

我想将 d3.js 创建的 SVG 元素与 javascript 对象相关联 - 这样,当 SVG 元素在事件侦听器上可用时,我可以直接从它追溯到 javascript 对象。然而,这在我的情况下似乎并不奏效,如下所述。

(动机)

我有很多 SVG 元素,每个元素在逻辑上都与一个对象相关联,该对象包含与之相关的结构化数据。该数据决定了当任何 SVG 元素触发事件时要执行的操作,并且每个元素都不同

我的尝试

我只是将对象添加为 SVG 元素的新属性。我可以看到它已经添加好了。 然后我使用 d3 的 .on 函数附加事件侦听器。 我获得了我认为是d3.select(this) 触发事件的SVG 元素。实际上,我可以通过这种方式修改它的 SVG 属性,正如您在下面给出的代码笔中将小矩形悬停时看到的那样。

问题

虽然我可以确认我的对象已添加到 SVG 对象中,但当我在事件处理程序中检索 SVG 元素时,它具有除了该对象引用的所有内容。

我将此问题简化为 codepen 中的代码 - 日志记录演示了问题 - 将矩形悬停以检查它。

我做错了什么导致添加的对象引用不可用? 我应该如何正确地在 SVG 元素中使用对象引用,或者解决这个问题?

问题代码描述:

rectangle = main.append('rect')
                           .style('fill', '#0000FF')   
                           .style('stroke-width', '0px')
                           .style('fill-opacity', '1')
                           .attr('height',30)
                           .attr('width',30)
                           .attr('id', '1')

rectangle.__test__ = 'test'



rectangle.on('mouseover', function(){
  console.dir(d3.select(this))
  /* __test__ is absent.... */
  })

【问题讨论】:

  • 您不能在 DOM 中存储对象引用——保存的将是序列化为字符串。听起来您需要一个查找表来检索具有特定 ID 的元素的 Javascript 对象。
  • 我不完全确定最后的说法。请注意此处的矩形 - codepen.io/matanster/pen/ujiJq?editors=001。 svg 元素包含一个完全可用的对象。我认为 svg 是 DOM 的一部分,因为 SVG 是 DOM 命名空间。你怎么看?
  • 在您的示例中它可以工作,因为该对象可以被序列化(成 JSON)和反序列化。它一般不起作用(例如,你不能用函数来做到这一点)。
  • D3 已经对数据做了完全相同的事情(在安全的地方)。您不能在 DOM 中存储行为(即函数)。
  • 你能解释一下为什么不使用 d3 的数据对象将对象与元素关联起来,然后在事件处理程序中检索它吗?

标签: javascript html dom svg d3.js


【解决方案1】:

您的示例代码无法按预期工作的原因是因为rectangle 不是 对矩形元素的引用,它是对 d3 选择的引用,它只是碰巧包含单个元素。稍后为同一元素创建不同的选择不会让您访问初始选择的属性。

(想一想:把实际的 SVGRectElement 对象想象成图书馆的书。那本书在你的背包里(rectangle 引用的 d3 选择)。你创建了一些关于这本书的注释(@ 987654327@),也把它们加到你的背包里。然后你做其他事情,后来有人把同一个图书馆的书拿出来放在不同的背包里。对于很多用途,效果是一样的:一个背包里有一个特定的书。如果您想阅读这本书或将其带到特定的班级,那么它在哪个背包里都没有关系。但是,那个人将无法神奇地找到你的笔记在他们的背包里!)

如果你这样做了

rectangle.node().__test__ = "test";  
//use .node() to extract the first element from the d3 selection
//and then assign a new property value to it

然后

console.dir(this.__test__);
//`this` directly references the rectangle element,  
// which has the test property added above

在事件处理程序中,它会起作用。

但是您可以更轻松地做到这一点,方法是使用 d3 数据函数将数据对象与每个元素相关联,然后将其作为事件处理函数的第一个参数直接访问。 花点时间与the tutorials 交流,了解如何充分利用 d3。

【讨论】:

  • 谢谢。这是演示答案的幼稚部分的代码笔。 codepen.io/matanster/pen/eDdlF?editors=001。我没有直接使用数据对象的原因是,在 d3 蜂蜜中,我只使用 d3 转换。我不可视化数据,只使用 d3 来控制用户界面资产
  • 让我补充一点,我从数据中应用逻辑,而不是为我希望根据数据按比例更改的硬连线属性或样式制造值。我的程序逻辑意味着我应该一次更改一些样式/属性,然后再更改一些其他的。逻辑不适合缩放数据的属性,而是根据表示逻辑的数据进行操作。因此,这似乎并不是 d3 方式的数据绑定所提供的真正模式。我将尝试绑定我的控制数据,以便我可以在 d3 主持的事件侦听器中检索它,并查看它是否感觉不太复杂。应该没问题:)
  • @matt 我不确定我是否完全遵循,但您当然可以根据您的程序随意使用尽可能多或尽可能少的 d3!如果您只操作现有元素(而不是创建一组元素来匹配数据集),您可能会发现使用.datum() 函数来设置和检索数据对象更容易。如果您的元素出于其他原因在 d3 选择范围内,它通常比提取节点并在其上设置属性更短且更整洁。
猜你喜欢
  • 2011-11-14
  • 2014-01-02
  • 1970-01-01
  • 1970-01-01
  • 2012-12-12
  • 1970-01-01
  • 2015-11-12
  • 1970-01-01
  • 2014-04-26
相关资源
最近更新 更多