2017-01-30 20 views
1

Я пытаюсь запустить функцию, которая оттеняет отдельные состояния карты TOPOJSON D3 на основе данных.Как запустить функцию после D3 TOPOJSON загрузить карту

Однако функция продолжает работать до того, как состояния загрузятся/появятся в SVG. Функция, которая строит карту, вызывается в функции готовности документа. Я попытался добавить прослушиватель событий к состояниям. Атрибут .on вызывает функцию, которая должна затенять состояния и использовала window.load. Но функция, которая оттеняет состояния продолжает работать до того состояния появляются на экране, и, таким образом, возвращает значение 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 

ответ

2

d3.json является асинхронным. Это означает, что весь код, который приходит после него, запустит сразу, то есть код не будет ждать для d3.json, чтобы закончить.

Использование $(document).ready() или window.load не имеет значения. Пути появятся в DOM только после того, как d3.json получит файл (btw, большой файл) и рисует SVG. Таким образом, вам нужно будет подождать d3.json, чтобы вы могли выбрать эти пути.

Решение: вызвать вашу функцию в нижней части 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.

EDIT: Для того, чтобы выбрать состояние (то есть, путь) по ID, вы должны установить идентификаторы путей первого (прямо сейчас, у них нет 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); 

В topoJSONd.id s - это номера, и вы не можете запустить идентификатор по номеру (именно поэтому я использовал "state" + d.id). Идентификатор Техаса является 48.

Вот ваш код, работающий: https://bl.ocks.org/anonymous/b2114787193d018fc094763a92872333

PS: Вам не нужно использовать document.getElementById в коде D3. Вы увидите, что использование селекторов D3 проще и универсальнее.

PS2: Ваши государственные границы должны иметь «государственные границы» в качестве class, а не как id: вы не имеют одинаковый идентификатор для разных элементов. Идентификаторы уникальны.

+0

Это все равно возвращает mainstate как null. Я переместил вызов colorstates() на d3.json до и после определения функции. Оба возвращают mainstate как null. – auto

+0

Итак, у вас есть * другая * проблема: нет элемента с ID = "texas". Как вы устанавливаете идентификаторы? –

+0

«texas» создается, когда функции создаются в d3 из topojson. Я добавил предупреждение в colorstates(), и предупреждение запускается до того, как карта появится в браузере. – auto