【问题标题】:SVG D3.js append element to SVG g:circle on text mouseoverSVG D3.js 在文本鼠标悬停时将元素附加到 SVG g:circle
【发布时间】:2014-07-22 13:55:36
【问题描述】:

在这个问题上摸不着头脑。

我们在页面左侧有一个文本列表。列表中的每个项目都有一个 data-id 属性,可以轻松匹配 SVG 地图中的相应学校。此 SVG 地图是美国地图,学校位置从 CSV excel 表中输入并存储在“学校”中以供访问。

                circles.selectAll("circles")
            .data(schools)
            .enter().append("svg:a")
            .attr("xlink:href", function(d) { return d.url; })
            .append("svg:circle")
            .attr("school", function(d, i) { return d.name; })
            .attr("id", function(d, i) { return d.id; })
            .attr("cx", function(d,i) { return d.longitude; })
            .attr("cy", function(d,i) { return d.latitude; })
            .attr("r", function(d,i) { return 6; })
            .attr("i", function(d,i) { return i; })
            .attr("class", "icon")

所以当用户将鼠标悬停在我之前提到的这个文本列表上时,我使用这个函数:

                mapSearch = function(id) {
                  d3.selectAll("circle")
                    .filter(function(d) {
                      if (d.id == id) {
                          return show_bubble_2(d);
                       }
                    })
               }

调用者:

show_bubble_2 = function(school_data) {
                var school_info = school_data,
                    latitude = school_info.latitude,
                    longitude = school_info.longitude;


                        bubble.css({
                            "left": (longitude - 75)+"px",
                            "top": (latitude - 67)+"px"
                        });

                bubble.html("<h1>" + school_info.name + "</h1>" + "<p>" + school_info.city + ", " + school_info.state + "</p>")
                                        .attr("class", function(d) { return school_info.letter; });
                bubble.addClass("active");
            }

除非我们开始调整地图大小以适应不同的屏幕尺寸,或者除非我们在地图上执行特殊的缩放功能,否则此方法有效。然后离西海岸更近的气泡是它们应该在的地方,但东海岸的那些离得很远。简而言之,这是一场彻头彻尾的噩梦,根本无法扩展。

我的问题:如何将此 DIV 附加到相应的圆圈 ID 而不是使用绝对定位的 DIV,以便无论地图大小,气泡始终会在该圆圈的顶部弹出.

我已经尝试在 if (d.id == id) { } 中附加,但它总是返回错误,到目前为止我还没有弄清楚。我会继续沿着这些思路尝试一些东西,因为我觉得这就是这样做的方式。如果您有更好的解决方案或可以为我指明正确的方向,我将不胜感激。

谢谢,祝你好运!

【问题讨论】:

    标签: svg d3.js


    【解决方案1】:

    即使使用Element.getBoundingClientRect 应用了变换,您也可以找到圆的位置。

    您可以使用过滤后的选择,获取.node() 并找到它的边界矩形。然后通过调整滚动位置,你可以找到topleft 的值来给你的气泡。

    这意味着气泡的位置基于圆圈出现在页面上的实际位置,而不是基于其数据,这需要您考虑转换。试试这样的:

    mapSearch = function(id) {
    
      // get the selection for the single element that matches id
      var c = d3.selectAll("circle")
        .filter(function(d) {
          if (d.id == id) {
            return show_bubble_2(d);
          }
        });
    
      // get the bounding rect for that selection's node (the actual circle element)
      var bcr = c.node().getBoundingClientRect();
    
      // calculate the top/left based on bcr and scroll position
      var bubbleTop = bcr.top + document.body.scrollTop + 'px',
          bubbleLeft = bcr.left + document.body.scrollLeft + 'px';
    
      // set the top and left positions
      bubble.css({
        'top': bubbleTop,
        'left': bubbleLeft
      });
    
    }
    

    当然,如果您正在缩放或平移并希望气泡保持在圆圈上,则需要在缩放和平移函数中重新计算这些值,但过程是相同的。

    HERE 是一个演示,它使用随机放置在 g 元素中的圆圈,该元素应用了平移和缩放。单击列表中的一个项目,将气泡放置在相应的圆圈上。

    【讨论】:

    • 这很好用。我遇到的唯一奇怪的事情是放大地图时,气泡向左稍微太远了。不过,很容易修复。非常感谢!
    【解决方案2】:

    &lt;div&gt; 是 HTML。 &lt;circle&gt; 是 SVG。您不能(轻松)将 HTML 元素放入 SVG 中。你必须使用&lt;foreignobject&gt; 元素来做到这一点。 (有关详细信息,请参阅 this question。)或者,您可以使用原生 SVG 元素,例如 &lt;tspan&gt; 而不是 &lt;div&gt;

    【讨论】:

    • 您也可以使用css使div看起来像圆圈或在圆圈上使用.text()方法添加文字。
    • 感谢您的回答,斯蒂芬。很高兴知道您不能真正将 div 添加到 SVG。不过,我不打算使用 div。无论地图大小如何,我都更担心让气泡在它们应该出现的地方弹出。如果这意味着报废 div,那很好
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-03
    • 2018-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-30
    相关资源
    最近更新 更多