使用D3

时间:2017-01-04 17:57:36

标签: javascript angularjs d3.js svg

我们有一个静态SVG图像,我们试图在AngularJS应用程序的上下文中使用d3.js动态添加工具提示来说明SVG图像中对象上的悬停事件。

SVG图像是一个平面图并且相当复杂,但是我们在POC过程中开始时非常小。以下是一个部分的小代表性片段:

<g id="f3s362c12">
  <g>
    <rect x="75.2" y="92.4" pointer-events="visible" fill="none" 
    width="64.7" height="57.8" />
    <polyline fill="none" stroke="#CDDDED" stroke-width="0.5" 
     stroke-miterlimit="10" points="118.4,149.9 140.3,149.9 140.3,92.4
     75.2,92.4 75.2,128.7" />
  </g>
  <g>
    <text transform="matrix(1 0 0 1 87.8719 144.8836)" fill="#010101" 
     font-family="arial, sans-serif" font-size="13.4182">362.12</text>
  </g>
</g>

D3.js对我们来说是新的,但是从我们的研究来看,它似乎能够做我们需要它做的事情,因为它似乎被设计为与SVG一起工作并在SVG中表示数据,但是所有的我们发现的例子是动态创建SVG(主要是图表)但不操纵现有的SVG图像。

简而言之,我们需要做的是:

  1. 找到ID以“f3”开头的g标签,如上面的g id =“f3s362c12”
  2. 对于与g标记关联的每个rect,添加工具提示悬停事件(可能是标签?)
  3. 当用户将鼠标悬停在说g id =“f3s362c12”时,选择rect并获取f3s362c12的相应数据记录,即我从.csv文件中加载,IE:
  4.   

    ({ “地板”: “3”, “位置”: “的 f3s362c12 ”, “名称”:“大卫   Byrne的”, “OCC”: “歌手”, “IMG”: “IMG / davidAvatar.jpg \ R”})

    1. 将此信息添加到工具提示/标签中,这样当您将鼠标悬停在g id = f3s362c12上时,您会看到David Byrne的工具提示,其职业是歌手和他的头像。
    2. 我创建了一个Plunk

      1. 在HTML
      2. 中加载SVG
      3. 加载.csv文件。
      4. 我们遇到的问题是d3.js. 例如,在我们的Plunk中,在script.js中,我们这样做是为了找到我们的g标签:

         var svg = d3.select("#svgFP");
         var allG = svg.selectAll("g").each(function (d,i) {}
        

        然而,由于我们试图使用“this”关键字在allG上找到一个矩形,所以我们就此碰到了。

          if (this.id.indexOf("f3") > -1)
            {
                //1. Add label/div/hover
                //2. Find corresponding record from array object.
                //3. Inject respective name, occupation and image into label/div along with mouseover/mouseout event.
            }
        

        我们一直在使用Firebug来尝试查找要使用的属性,但至少可以说它非常令人沮丧且毫无结果,因此我们认为在SO中可能会有一个或两个d3 /角度大师可能向我们展示道路。

        提前致谢。

1 个答案:

答案 0 :(得分:3)

您在plunker中遇到的第一个问题是您的CSV:CSV的第一行必须是标题,它定义了每列的内容。因此,我将您的CSV修改为:

floor,location,name,surname,role,image
3,f3s362c12,David ,Byrne,Singer,img/davidAvatar.jpg
3,f3s362c11,Tina,Weymouth,Bassist,img/tinaAvatar.jpg
3,f3s362c2,Jerry,Harrison,Keyboards,img/jerryAvatar.jpg
3,f3s362c1,Chris,Frantz,Drums,img/chrisAvatar.jpg

现在出现了你的实际问题。

D3代码的最佳解决方案是将数据绑定到DOM元素(在本例中为SVG)。但是,既然你已经有了一个静态的SVG,而不是用D3制作而没有任何绑定数据,那么这就是一个解决方案。

首先,选择所有相关的组元素:

var groups = d3.selectAll("g[id^='f3']");

并将mouseover代码添加到该选择中。

mouseover代码中出现了此解决方案中最重要的部分:我们获取了光标所在元素的ID ...

var groupId = this.id

...然后,根据此ID,我们会过滤先前加载的CSV:

var thisData = data.filter(function(d) {
    return d.location === groupId
});

以上代码的作用如下:我们将CSV加载到名为data的变量中。该变量是一个对象数组,每个对象都有一个location属性(查看我创建的CSV标题)。然后,我们将每个对象的locationd.location)与组的ID(groupId)进行比较。

现在,您有一个名为thisData的变量,您可以使用它来填充工具提示。

以下是包含 MCVE 版本代码的演示:

&#13;
&#13;
var tooltip = d3.select("body")
            .append("div")
            .style("position", "absolute")
            .style("background-color", "gainsboro")
            .style("border", "1px solid black")
            .style("padding", "20px")
            .style("pointer-events", "none")
            .style("font-size", "12px");

        var data = d3.csvParse(d3.select("#csv").text());

        var groups = d3.selectAll("g[id^='f3']");

        groups.on("mousemove", function() {
            var groupId = this.id
            var thisData = data.filter(function(d) {
                return d.location === groupId
            });
            tooltip.html("Name: " + thisData[0].name + " " + thisData[0].surname + "<br>Role: " + thisData[0].role)
                .style("top", (d3.event.pageY - 2) + "px").style("left", (d3.event.pageX + 2) + "px")
                .style("visibility", "visible");
        }).on("mouseout", function() {
            tooltip.style("visibility", "hidden");
        });
&#13;
pre {
	display: none;
}
&#13;
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300" height="100%">
    <g id="background">
        <rect x="1.5" y="0.3" fill="#5A8CC9" width="298.7" height="300.4" />
    </g>
    <g id="f3s362c12">
        <g>
            <rect x="75.2" y="92.4" pointer-events="visible" fill="none" width="64.7" height="57.8" />
            <polyline fill="none" stroke="#CDDDED" stroke-width="0.5" stroke-miterlimit="10" points="118.4,149.9 140.3,149.9 140.3,92.4
                75.2,92.4 75.2,128.7        " />
        </g>
        <g>
            <text transform="matrix(1 0 0 1 87.8719 144.8836)" fill="#010101" font-family="arial, sans-serif" font-size="13.4182">362.12</text>
        </g>
    </g>
    <g id="f3s362c11">
        <g>
            <rect x="75.2" y="149.9" pointer-events="visible" fill="none" width="64.7" height="57.8" />
            <polyline fill="none" stroke="#CDDDED" stroke-width="0.5" stroke-miterlimit="10" points="118.4,207.8 140.3,207.8 140.3,149.9
                75.2,149.9 75.2,186.2       " />
        </g>
        <g>
            <text transform="matrix(1 0 0 1 87.8719 201.6532)" fill="#010101" font-family="arial, sans-serif" font-size="13.4182">362.11</text>
        </g>
    </g>
    <g id="f3s362c2">
        <g>
            <rect x="140.3" y="149.9" pointer-events="visible" fill="none" width="68.8" height="57.8" />
            <polyline fill="none" stroke="#CDDDED" stroke-width="0.5" stroke-miterlimit="10" points="208.7,183.5 208.7,149.9 140.3,149.9
                140.3,207.8 185.8,207.8         " />
        </g>
        <g>
            <text transform="matrix(1 0 0 1 163.782 201.6532)" fill="#010101" font-family="arial, sans-serif" font-size="13.4182">362.2</text>
        </g>
    </g>
    <g id="f3s362c1">
        <g>
            <rect x="140.3" y="92.4" pointer-events="visible" fill="none" width="68.8" height="57.8" />
            <polyline fill="none" stroke="#CDDDED" stroke-width="0.5" stroke-miterlimit="10" points="208.7,126 208.7,92.4 140.3,92.4
                140.3,149.9 185.8,149.9         " />
        </g>
        <g>
            <text transform="matrix(1 0 0 1 163.782 144.8836)" fill="#010101" font-family="arial, sans-serif" font-size="13.4182">362.1</text>
        </g>
    </g>
</svg>
<pre id="csv">floor,location,name,surname,role,image
3,f3s362c12,David ,Byrne,Singer,img/davidAvatar.jpg
3,f3s362c11,Tina,Weymouth,Bassist,img/tinaAvatar.jpg
3,f3s362c2,Jerry,Harrison,Keyboards,img/jerryAvatar.jpg
3,f3s362c1,Chris,Frantz,Drums,img/chrisAvatar.jpg</pre>
&#13;
&#13;
&#13;

总结一下,这些是步骤:

  1. 创建选择以获取鼠标事件;
  2. 加载并解析您的CSV;
  3. 当用户将鼠标悬停在<g>上时,请根据<g>的ID过滤您的数据阵列;
  4. 使用已过滤的数组创建工具提示html
  5. PS:在此代码段中,我使用<pre>元素存储您的CSV。我只是这样做,因为与Plunker不同,我无法使用S.O.加载CSV。片段。