D3地图上每个SVG圆的不同工具提示

时间:2017-07-26 13:17:46

标签: javascript d3.js svg tooltip

我正在制作与其绩效评级相关联的商家世界地图:因此每个商家都会用一个点来表示,其中包含一个带有性能的工具提示(以及其他信息)。我使用地图示例{ {3}}

地图数据:

pointData = {
    "businessName": businessName,
    "location": location,
    "performance": currperformance
}

pointsData.push(pointData);

因此pointsData JSON对象属于表单     [{"business":"b1","location":[long1, lat1]},{"businessName":"b2","location":[long2, lat2]}...]

工具提示问题:

我可以完美地显示带有点和相同工具提示的地图,直到我尝试使用不同的工具提示。我使用动态工具提示进行研究的许多D3示例仅适用于图表 - 我的目标是在地图上的每个SVG圈上附加工具提示的JSON数据。

这是我到目前为止的尝试,它显示无分数并且没有显示控制台错误(添加.each(function (d, i) {..}不再绘制部分了但是它不是将每个位置与其后续的业务和绩效评级联系起来所必需的。)

d3.json("https://raw.githubusercontent.com/d3/d3.github.com/master/world-110m.v1.json", function (error, topo) {
    if (error) throw error;

    gBackground.append("g")
        .attr("id", "country")
        .selectAll("path")
        .data(topojson.feature(topo, topo.objects.countries).features)
        .enter().append("path")
        .attr("d", path);


    gBackground.append("path")
        .datum(topojson.mesh(topo, topo.objects.countries, function (a, b) { return a !== b; }))
        .attr("id", "country-borders")
        .attr("d", path);


    //Tooltip Implementation
    var tooltip = d3.select("body").append("div")
        .attr("class", "tooltip")
        .style('opacity', 0)
        .style('position', 'absolute')
        .style('padding', '0 10px');


    gPoints.selectAll("circle")
        .each(function (d, i) {
            this.data(pointsData.location).enter()
                .append("circle")
                .attr("cx", function (d, i) { return projection(d)[0]; })
                .attr("cy", function (d, i) { return projection(d)[1]; })
                .attr("r", "10px")
                .style("fill", "yellow")
                .on('mouseover', function (d) {
                    tooltip.transition()
                        .style('opacity', .9)
                        .style('background', 'black')
                        .text("Business" + pointsData.businessName + "performance" + pointsData.performance)
                        .style('left', (d3.event.pageX - 35) + 'px')
                        .style('top', (d3.event.pageY - 30) + 'px')
                })
                .on('mouseout', function (d) {
                    tooltip.transition()
                        .style("visibility", "hidden");
                })
        });
}); 

1 个答案:

答案 0 :(得分:1)

输入选择会在不使用.each()的情况下执行您要执行的操作。 Bostock设计了D3来将数据连接到元素,以便:

  

告诉D3你想要什么,而不是告诉D3如何做某事。您   希望圆形元素对应于数据。你想要一个圆圈   每个数据。然后,告诉D3,而不是指示D3创建圆圈   选择"圈"应该对应数据。这个概念是   称为数据连接(Thinking with Joins)。

我建议您查看输入,更新和退出选择的一些示例。虽然,您可能最初使用普通圆圈(和相同的工具提示)进行此操作:

  svg.selectAll("circle")
      .data([[long,lat],[long,lat]])
      .enter()
      .append("circle")
      .attr("cx", function(d,i) { return projection(d)[0]; })
      .attr("cy", function(d,i) { return projection(d)[1]; })

如果您是,那么只需访问其他属性的数据即可。如果没有,那么就是正确使用输入选择的问题。 无论如何,这是使用输入选择和您指定的数据格式的可能实现:



var pointsData = [
  { "businessName": "Business A",
    "location": [50,100],
    "performance": "100" },
  { "businessName": "Business B",
    "location": [100,50],
    "performance": "75"
  },  
  { "businessName": "Business C",
    "location": [150,150],
    "performance": "50"
  }];
  
var svg = d3.select("body")
  .append("svg")
  .attr("width",300)
  .attr("height",300);
  
var tooltip = d3.select("body").append("div")
  .attr("class", "tooltip")
  .style('opacity', 0)
  .style('position', 'absolute')
  .style('padding', '0 10px');
  
svg.selectAll("circle") // empty selection
  .data(pointsData)     // data to bind to selection
  .enter()              // the enter selection holds new elements in the selection
  .append("circle")     // append a circle for each new element
    // Manage the style of each circle based on its datum:
    .attr("cx",function(d) { return d.location[0]; })
    .attr("cy",function(d) { return d.location[1]; })
    .attr("r",10)
    .on("mouseover", function(d) {
      tooltip.transition()
        .style('opacity', .9)
        .style('background', 'steelblue')
        .text("Business: " + d.businessName + ". performance " + d.performance)
        .style('left', (d3.event.pageX - 35) + 'px')
        .style('top', (d3.event.pageY - 30) + 'px')
        .duration(100);
    })
    .on("mouseout",function(d) {
       tooltip.transition()
         .style("opacity", "0")
         .duration(50);
    })

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.5.0/d3.min.js"></script>
&#13;
&#13;
&#13;

原始选择svg.selectAll("circle")为空。将数据绑定到此空选择时,enter选择将为数据数组中的每个项目保留一个项目,该项目在选择中没有相应的元素(在本例中为圆形,因为没有, enter数组为数据数组中的每个项目都有一个项目。然后,我们在输入选择中为每个项目附加一个元素,并根据每个数据的属性对其进行样式化。

请注意,这需要对原始代码进行一些修改(我还跳过了一个投影,使其更简洁。)

  1. 访问基准属性:
  2. 我想你的初始数据集看起来像这样:[[long,lat], [long,lat], [long,lat]]。从此数据集访问每个数据时,您可以将一个圆圈居中,如:

      .attr("cx", function(d,i) { return projection(d)[0]; })
      .attr("cy", function(d,i) { return projection(d)[1]; })
    

    这些是您在示例中使用的行。但是,您的数据现在看起来像示例代码中的变量pointData,因此您需要将其修改为:

    .attr("cx", function(d,i) { return projection(d.location)[0]; })
    .attr("cy", function(d,i) { return projection(d.location)[1]; })
    

    我还访问了工具提示文本的每个数据的相应属性,而不是访问未绑定到每个元素的数据(即使它来自同一个源)。

    1. 不透明度与可见度:
    2. 您最初将工具提示的不透明度设置为零,然后在鼠标悬停时将其修改为0.9:.style('opacity', .9),而不是切换可见性(只有mouseout函数可以)在mouseout上将不透明度更改为零。