D3地图+图形协调可视化:选择错误的国家/地图更改属性

时间:2018-08-07 20:25:38

标签: javascript d3.js topojson

这是我的问题:我有一个地图SVG和一个条形图SVG。我想创建一个协调的选择。例如,用户突出显示图形中的条形图,并且地图上与该数据相对应的国家/地区也被突出显示,反之亦然。

现在,我可以突出显示地图上的任何国家,并且相应的相应栏也会突出显示。但是,对于酒吧不一样。当我突出显示一个条时,突出显示一个随机的国家,然后,如工具提示中所显示的,这些国家名称都是混乱的和错误的。

这是地图->条形图突出显示:

<select class="custom-select my-1 mr-sm-2" id="Style" [appAutoFocus]>
  <option selected>Choose...</option>
  <option value="1">One</option>
  <option value="2">Two</option>
  <option value="3">Three</option>
</select>

...

这是条形图->地图突出显示。这是我无法正常运行的功能。

...
           map.selectAll("countries")
                .data(b.features)
                .enter()
                .append("path")
                .attr("d", path)
                //.style("stroke", "black")
                .on("mouseover", function(d) { 
                    activeDistrict = d.properties.ADMIN,
                    chart.selectAll("rect")
                    .each(function(d) {
                        if(d){

                            if (d.Country == activeDistrict){
                                console.log("confirmed" + d.Country)
                                d3.select(this).style("stroke", "blue").style("stroke-width", "3");

                            }
                        }
                    })

这是我的整个JS:

            var bars = chart.selectAll(".bars")
                .data(data)
                .enter()
                .append("rect")
                .on("mouseover", function(d) {
                    activeDistrict = d.Country,
                    //console.log(activeDistrict),
                    map.selectAll("path")
                    .data(b.features)
                    .each(function(d) {
                        if (d){
                            //console.log("activeDistrict = " + activeDistrict)
                            if (d.properties.ADMIN == activeDistrict){
                                d3.select(this).style("stroke", "blue").style("stroke-width", "3");
                                console.log(d.properties.ADMIN + "=" + activeDistrict)

                            }
                        }
                    });

2 个答案:

答案 0 :(得分:2)

最初绘制国家/地区时,您使用:

map.selectAll("countries")
  .data(b.features)
  .enter()
  .append("path")

由于页面上没有标签为countries的元素,因此初始选择为空,并且.enter().append("path")为数据数组中的每个项目创建了一个路径。

但是,当您将鼠标悬停在条形图上时,会按selectAll().data()顺序重新分配数据,但操作方式有所不同:

map.selectAll("path")
  .data(b.features)
  ...

您的地图中有不是国家/地区的路径:标线和轮廓。现在,我们选择了所有路径并为其分配了新数据。由于选择中的前两个项目是刻度线和轮廓线,因此它们现在具有数据数组中前两个项目的数据。在数据数组中,所有国家/地区都将拥有一个国家的绑定数据,该国家/地区与它们相距两个。这就是为什么将鼠标悬停在条形图上时会突出显示错误数据的原因,以及随后导致国家工具提示错误的原因。

目前尚不清楚为什么更新数据(我看不到它在变化),您可以这样附加国家/地区:

var countries = map.selectAll("countries")
  .data(b.features)
  .enter()
  .append("path")
  ... continue as before

map.selectAll("countries")
  .data(b.features)
  .enter()
  .append("path")
  .attr("class","country")
  ... continue as before

然后在条形图的鼠标悬停功能中使用:

countries.each(....

map.selectAll(".country").each(...

如果需要,无论哪种方式,您都可以使用.data()更新数据。


我会注意到each方法不是必需的,但在某些情况下可能更可取,因为可以使用它的外观:

var bars = chart.selectAll(".bars")
  .data(data)
  .enter()
  .append("rect")
  .on("mouseover", function(d) {
     activeDistrict = d.Country,       
     map.selectAll(".country")
       .data(b.features)
       .style("stroke", function(d) { 
         if (d.properties.ADMIN == activeDistrict) return "blue"; else return color(d.properties[currentFood]) 
       })
       .style("stroke-width", function(d) { 
         if (d.properties.ADMIN == activeDistrict) return "3" else return 0; 
       });
  })                          
  ...

答案 1 :(得分:-1)

您可以尝试使以下内容在创建内容和选择内容方面更加一致。

地图:

  • 按类别选择,因为您的svg中有更多path
  • 在栏中添加一个类以突出显示,而不是设置样式

       map.selectAll(".countries")
            .data(b.features)
            .enter()
            .append("path")
            .attr("class", "countries")
            .attr("d", path)
            //.style("stroke", "black")
            .on("mouseover", function(d) { 
                activeDistrict = d.properties.ADMIN,
                chart.selectAll(".bars")
                     .classed("highlight", function(d) {
                         return d && d.Country === activeDistrict;
                      });
                tooltip.transition()    //(this.parentNode.appendChild(this))
                .duration(200)    
                .style("opacity", .9)
                .style("stroke-opacity", 1.0);    
                tooltip.html(d.properties.ADMIN + "<br/>"  + d.properties[currentFood] + "(kg/CO2/Person/Year)")  
                .style("left", (d3.event.pageX) + "px")   
                .style("top", (d3.event.pageY - 28) + "px");
              })          
              .on("mouseout", function(d) {
                activeDistrict = d.properties.ADMIN,
                chart.selectAll(".bars")
                     .classed("highlight", false);
                tooltip.transition()    
                .duration(500)    
                .style("opacity", 0)
                .style("stroke-opacity", 0); 
              })
            .style("fill", function(d) { return color(d.properties[currentFood]) });
    };
    

条形图

  • 修复该类,在barscountry之间添加空格
  • 请勿在鼠标悬停和鼠标移出时将新数据绑定到地图路径
  • 按类别而不是按类型选择地图路径
  • 将一个类添加到地图路径中以突出显示,而不是设置样式

        var bars = chart.selectAll(".bars")
            .data(data)
            .enter()
            .append("rect")
            .on("mouseover", function(d) {
                activeDistrict = d.Country;
                //console.log(activeDistrict),
                map.selectAll(".countries")
                    .classed("highlight", function(d) {
                        return d && d.properties.ADMIN === activeDistrict;
                     });
                tooltip.transition()    //(this.parentNode.appendChild(this))
                .duration(200)    
                .style("opacity", .9)
                .style("stroke-opacity", 1.0);    
                tooltip.html(d.Country + "<br/>"  + d[currentFood] + "(kg/CO2/Person/Year)")  
                .style("left", (d3.event.pageX) + "px")   
                .style("top", (d3.event.pageY - 28) + "px");  
              })          
              .on("mouseout", function(d) {  
                map.selectAll(".countries")
                   .classed("highlight", false);
                tooltip.transition()    
                .duration(500)    
                .style("opacity", 0)
                .style("stroke-opacity", 0); 
              })
            .sort(function(a, b){
            return a[currentFood]-b[currentFood]
            })
            .transition() //add animation
                .delay(function(d, i){
                    return i * 5
                })
                .duration(1)
            .attr("class", function(d){
                return "bars " + d.Country;
            })
            .attr("width", chartWidth / data.length - 1)
            .attr("x", function(d, i){
                return i * (chartWidth / data.length);
            })
            .attr("height", function(d){
                return yScale(parseFloat(d[currentFood]));
            })
            .attr("y", function(d){
                return chartHeight - yScale(parseFloat(d[currentFood]));
            })
            .style("fill", function(d){ return color(d[currentFood]); });