如何在 D3 TOPOJSON 地图加载后 运行 发挥作用

How to run function after D3 TOPOJSON map loads

我正在尝试 运行 一个基于数据对 TOPOJSON D3 地图的各个状态进行着色的函数。

但是,该函数在 SVG 中的状态 load/appear 之前保持 运行ning。构建地图的函数在文档就绪函数中调用。我已经尝试向状态添加一个事件侦听器,一个 .on 属性调用应该遮蔽状态并使用 window.load 的函数。但是遮蔽状态的函数在状态出现在屏幕上之前保持 运行ning,因此当试图通过它们的 id

找到每个状态时 returns 一个 NULL 值
.background {
  fill: none;
  pointer-events: all;
}

#states {
  fill: #aaa;
}

#states .active {
  fill: orange;
}

#state-borders {
  fill: none;
  stroke: #fff;
  stroke-width: 1.5px;
  stroke-linejoin: round;
  stroke-linecap: round;
  pointer-events: none;
}

</style>

<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script>
function buildmap(){
var width = 960,
    height = 500,
    centered;

var projection = d3.geo.albersUsa()
    .scale(1070)
    .translate([width / 2, height / 2]);

var path = d3.geo.path()
    .projection(projection);

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);

svg.append("rect")
    .attr("class", "background")
    .attr("width", width)
    .attr("height", height)
    .on("click", clicked);

var g = svg.append("g");

d3.json("/mbostock/raw/4090846/us.json", function(error, us) {
  if (error) throw error;

  g.append("g")
      .attr("id", "states")
    .selectAll("path")
      .data(topojson.feature(us, us.objects.states).features)
    .enter().append("path")
      .attr("d", path);

  g.append("path")
      .datum(topojson.mesh(us, us.objects.states, function(a, b) { return a !== b; }))
      .attr("id", "state-borders")
      .attr("d", path);
});
};

function colorstates(){
   var mainstate = document.getElementById("texas")
   mainstate.style.fill="blue"
}



 $(document).ready(function((){
      buildmap()
      colorstates() //I have also used window.load and adding .on attribute to svg/d3

d3.json 是异步的。意思是它后面的所有代码都会运行立即,也就是代码不会等待[=12] =] 完成。

使用$(document).ready()window.load不会有任何区别。只有在 d3.json 获取文件(顺便说一句,一个大文件)并绘制 SVG 之后,路径才会出现在 DOM 中。因此,您必须等待 d3.json 完成,这样您才能 select 这些路径。

解决方法:在d3.json的底部调用你的函数:

d3.json("/mbostock/raw/4090846/us.json", function(error, us) {
    if (error) throw error;

    g.append("g")
        .attr("id", "states")
        .selectAll("path")
        .data(topojson.feature(us, us.objects.states).features)
        .enter().append("path")
        .attr("d", path);

    g.append("path")
        .datum(topojson.mesh(us, us.objects.states, function(a, b) {
            return a !== b;
        }))
        .attr("id", "state-borders")
        .attr("d", path);

    //calling colorstates inside d3.json
    colorstates() 

    function colorstates() {
        var mainstate = document.getElementById("texas")
        mainstate.style.fill = "blue"
    }

});

这样,当您调用 colorstates 函数时,元素就会在那里。

编辑:要通过 ID select 状态(即路径),您必须首先设置路径的 ID(现在,他们没有身份证):

g.append("path")
    .datum(topojson.mesh(us, us.objects.states, function(a, b) {
        return a !== b;
    }))
    .attr("id", d => "state" + d.id)
    .attr("d", path);

topoJSON中,d.id是数字,ID不能以数字开头(所以我用了"state" + d.id)。德州的 id 是 48.

这是您的代码,正在运行:https://bl.ocks.org/anonymous/b2114787193d018fc094763a92872333

PS:您不需要在 D3 代码中使用 document.getElementById。您会发现使用 D3 selectors 更容易且用途更广。

PS2:你的州边界应该 "state-borders" 作为 class,而不是 id:你 不能 对不同的元素具有相同的 ID。 ID 是唯一的。