重新定位SVG:使用d3.js创建的rect元素(使用d3或jQuery)

时间:2014-02-15 01:39:39

标签: jquery svg d3.js event-handling mouseover

情况:

我正在使用d3覆盖的谷歌地图上工作。它主要基于迈克博斯托克的这个例子:http://bl.ocks.org/mbostock/899711

我正在使用Rails 4应用程序运行它,并从CDN加载到d3.js库中。因此可以访问d3.js和jQuery库,并且更愿意避免添加更多库。

任务:

数据点(由svg:rect元素表示)有时会模糊谷歌地图上的地名。我想要它,以便用户可以将光标传递到这些数据点上,并且它们会暂时弹出。

我应该注意到我试图让这些点随机重新定位,所以不能真正进入悬停的CSS路线。

因此...

  • 在SVG上放置一个事件监听器(或者取决于实际应该操作哪个元素的矩形)

  • 编写一个回调函数,用于重新定位(偏移?动画?过渡?)触发事件的元素

  • 等待setTimeout(或使用d3 .each("end",function())),然后将元素返回到其先前位置

简单吧?

尝试:

所以,尝试使用d3然后尝试使用jQuery。受jQuery欢迎,因为它似乎没有处理SVG(虽然我可能不得不求助于使用jQuery-SVG库,如果d3.js没有通过商品)

使用d3尝试,事件处理程序分配很好。我已将处理程序分配给svg父元素,而不是rect子元素。

.on('mouseover', scatter)

这会产生事件触发的预期行为,并在鼠标悬停时调用散点函数。

但是,我无法明确表达我正在寻找的行为。

我尝试过更改x,y值。我试过改变顶部和左边的值。值似乎在对象上发生变化,但没有任何动作。我尝试过直接d3风格选择以及d3风格转换。

我在rect子元素上尝试了相同的更改。这会移动rect元素,但不会带SVG,因此不会显示。

相关代码:

将SVG附加到每个数据点,为SVG设置正确的x和y,并为每个数据点添加事件监听器。

var marker = layer.selectAll("svg")
      .data(data)
      .each(transformMarker)
      .enter().append("svg:svg")
      .each(transformMarker)
      .on('mouseover', scatter);

另外,我将SVG父元素设置为包含rect子元素的样式,并设置样式的样式,以便实际显示在屏幕上。

transformMarker函数,您可能需要了解标记的定位方式。

    function transformMarker(d) {
      d = new google.maps.LatLng(J.lat(d), J.lon(d));
      d = projection.fromLatLngToDivPixel(d);
      return d3.select(this)
          .style("left", (d.x) + "px")
          .style("top", (d.y) + "px");

分散功能(使用一大堆console.logs,以便您可以看到正在发生的事情)

function scatter(d){
      console.log("the event has fired")
      d = new google.maps.LatLng(J.lat(d), J.lon(d));
      d = projection.fromLatLngToDivPixel(d);
      console.log(d.x)
      console.log((d.x + 15) + "px")
      console.log(this)
      d3.select(this)
        .attr("x", (d.x + 15))
        .attr("y", (d.y + 15))
      console.log(this)

控制台.logs抽出的内容

the event has fired
602.0032221842557
617.0032221842557px

<svg style=​"left:​ 602.0032221842557px;​ top:​ 230.00228557549417px;​" 
    x="617.0032221842557" y=​"245.00228557549417">​
    <rect height=​"7" width=​"7" fill=​"#138770" stroke=​"#0f0f02" stroke-width=​"0.5">​</rect>​
</svg>​

<svg style=​"left:​ 602.0032221842557px;​ top:​ 230.00228557549417px;​"
    x="617.0032221842557" y=​"245.00228557549417">​
    <rect height=​"7" width=​"7" fill=​"#138770" stroke=​"#0f0f02" stroke-width=​"0.5">​</rect>​
</svg>​

SVG的CSS,因为这可能会在工作中抛出扳手

.overlay, .overlay svg {
  position: absolute;
}

.wrapper, .overlay svg {
  /*border: 1px solid black;*/
  width: 7px;
  height: 7px;

  transform: translateZ(0px);
  -webkit-transform: translateZ(0px);
  -moz-transform: translateZ(0px);
}

我离文明只有几天了,所以希望能够解决这个问题,然后采用Stack Overflow和d3 google小组的一些新方法和一些建议回来。

如果您有任何其他问题或需要更多信息,请与我们联系。

2 个答案:

答案 0 :(得分:0)

回顾一下:

每个数据点矩形都在其自己的单独 <svg>元素中。在left事件中,使用绝对定位(toptransformMarker样式)定位每个svg元素。

显然,如果要移动与数据点关联的svg图形,则需要更改<svg>元素的定位。您尝试使用xy属性进行此操作,但这不是SVG首先定位的方式。仅当<svg>元素嵌入 另一个SVG时,这些属性才有意义。你的是绝对定位在页面上的独立元素。因此,您需要更改绝对定位样式值:

function scatter(d){
      d = new google.maps.LatLng(J.lat(d), J.lon(d));
      d = projection.fromLatLngToDivPixel(d);
      d3.select(this)
        .style("left", (d.x + 15) + "px")
        .style("top", (d.y + 15) + "px")
}

另外,我不确定你为什么要在初始化时调用transformMarker两次;你只需要一次,但要确保你保留的版本是在创建元素之后被称为的版本:

var marker = layer.selectAll("svg")
      .data(data)
      .enter().append("svg:svg")
        .each(transformMarker)
        .on('mouseover', scatter);

答案 1 :(得分:0)

我看看这个漂亮的random function for Sass

module Sass::Script::Functions
  def random(max = Sass::Script::Number.new(100))
    Sass::Script::Number.new(rand(max.value), max.numerator_units, max.denominator_units)
  end
end

将随机函数添加到您的sass中,请查看this guide。如果你想让你的项目在mousever上随机重新定位,我会使用随机函数创建一个具有随机位置的类,并将该类移除/添加到元素中。当然,在我提供的链接中有一些使用随机函数的例子。

当然这很简单,只需将上面的代码添加到sass.rb中的config / initializers中。这是使用它的example rails app

它的一个问题是,如果你在一个类中设置它,它只会生成一次随机数。在刷新和重新加载时,它不会为它生成的css生成新的随机上/下等。我不确定是否有解决方法,或者这是否真的有用。但它很有趣所以我想我还是会发布它。