首页 > 解决方案 > 如何在气泡图中按状态和在行/列中定位气泡

问题描述

我已经使用以下教程让我​​们制作一个气泡图来创建一个带有矩形而不是圆形的状态图来代表印度的选区。我不想根据选区定位矩形,而是将它放在每个状态上方的行/列中彼此相邻的位置。

svg.selectAll(".state-stroke")
            .data(stateboundary).enter().append("path")
            .attr("d", geoPath)
            .attr("class", "state-stroke")
            .attr('stroke', "#888888")
            .attr('stroke-width', "0.8")
            .attr('fill', "none")
            .attr('stroke-opacity', "1")

svg.selectAll(".name").data(pcCentroid)
            .enter().append("rect")
            .attr("x", function(d){ return d[0]; })
            .attr("y", function (d){ return d[1]; })
            .attr("width", "3")
            .attr("height", "3")
            .attr("class", function(d,i){
                return stateboundary[i]['properties']['ST_CODE']
            });

我在这里包含了完整的代码 https://jsfiddle.net/diviseed/4qhnakwb/2/

现在看起来像下面的地图 在此处输入图像描述

我想要的结果如下 在此处输入图像描述

标签: javascriptd3.jssvg

解决方案


这是从您的代码中分叉的小提琴。

首先让我们遍历选区并按州对它们进行分组。

var constituenciesByState = {};
pathshape.objects.pcboundary.geometries
  .forEach(function(pc){
     var code = pc.properties.ST_CODE;
     if (!constituenciesByState[code]) {
        constituenciesByState[code] = [];
     }
     constituenciesByState[code].push(pc);
  });

然后修改 d3 代码,而不是从pcCentroid数据开始,而是从数据开始,并为每个状态stateCentroid附加一个新元素。svg

svg.selectAll(".name").data(stateCentroid)
  .enter().append("svg") 

然后我们为每个选区生成嵌套数据。首先获取当前状态的代码,并获取相关选区的数组。然后我们计算rowLength,您可以根据您的要求更改此逻辑。然后我们根据行数和列数计算initialX并确定第一个点应该去哪里。initialY然后我们使用、和属性为map每个选区返回一个新对象。和值被修改为根据它们的索引向右和向下移动每个项目。xystateconstituencyxy

.data(function(d, index) { 
  var stateCode = stateboundary[index]['properties']['ST_CODE'];
  var constituencies = constituenciesByState[stateCode];

  var rowLength = Math.ceil(Math.sqrt(constituencies.length));  // rectangles per row
  var offset = 5;  // spacing between start of each rectangle

  var numCols = Math.min(constituencies.length, rowLength);
  var numRows = Math.ceil(constituencies.length/rowLength);

  var initialX = d[0] - (numCols * offset)/2;
  var initialY = d[1] - (numRows * offset)/2;

  return constituencies
    .map(function(c, i) {
    return {
      x : initialX + ((i % rowLength) * offset),
      y : initialY + Math.floor(i / rowLength) * offset,
      constituency: c.properties.PC_CODE,
      state: stateCode
    }
  }); 
 })

然后对每个点的格式进行轻微修改,并在工具提示中显示选区代码:

.attr("x", function(d){ return d.x })
.attr("y", function (d){ return d.y })
.attr("width", "3")
.attr("height", "3")
.attr("class", function(d,i){
    return d.state;
})
.append("title")
.text(function(d) { return d.constituency });

推荐阅读