Как обновить цвет заливки на существующих элементах svg с помощью d3.js?



Итак, я пытаюсь сделать карту из Ан .svg-файл я создал с помощью Illustrator, потому что это карта Нидерландов с не такими простыми регионами.



Все регионы имеют свой собственный # ID.



Теперь я пытаюсь раскрасить каждую область в соответствии с их значением в наборе данных. Я могу заставить цвет на регионах с помощью CSS я сделал это на одном регионе, но это, очевидно, не хорошее решение.



Если я, например, попытаюсь выбрать(#id), а затем изменить.attr ("заполнение", "красный"); он не делает работа.



Как бы я обновил цвета области по id, используя d3.js в соответствии со значением d[1] в наборе данных ?



Файлы: https://gist.github.com/gordonhatusupy/9466794



Прямая связь: http://www.gordonjakob.me/regio_map/

449   1  
svg

1 ответ:

Проблема в том, что ваш файл Illustrator уже определяет цвета заливки для отдельных элементов <path>, а значения идентификаторов-для родительских элементов <g>. Дочерние элементы наследуют стили от родителей, но только в том случае, если у дочернего элемента нет собственных значений.

Есть пара вещей, которые вы можете сделать, чтобы изменить его:
  1. Измените файл Illustrator так, чтобы пути не были заполнены. Затем они унаследуют цвет заливки, установленный на родитель.

  2. Выберите пути напрямую, используя d3.selectAll("g#id path") или d3.select("g#id").selectAll("path"); в любой версии будут выбраны все элементы <path>, являющиеся потомками элемента <g> с идентификатором "id". Затем вы можете установить атрибут fill непосредственно для перезаписи значения из Illustrator.


Как обсуждалось в комментариях к основному вопросу, если вы хотите сделать этот шаг дальше и фактически присоединить данные к элементам для дальнейшего использования (например, в обработчике событий), проще всего способ заключается в циклическом просмотре набора данных, выделении каждого элемента, а затем использовании .datum(newData) способ прикрепления данных к каждому элементу:

dataset.forEach(function(d){ //d is of form [id,value]
    d3.select("g#"+d[0]) //select the group matching the id
      .datum(d) //attach this data for future reference
      .selectAll("path, polygon") //grab the shapes
      .datum(d) //attach the data directly to *each* shape for future reference
      .attr("fill", colour(d[1]) ); //colour based on the data
});

Http://jsfiddle.net/ybAj5/6/

Если вы хотите иметь возможность выбрать все элементы верхнего уровня <g> в будущем, я бы предложил также дать им класс, чтобы вы могли выбрать их, например, d3.select("g.region"). Например:

dataset.forEach(function(d){ //d is of form [id,value]
    d3.select("g#"+d[0]) //select the group matching the id
      .datum(d) //attach this data for future reference
      .classed("region", true) //add a class, without erasing any existing classes
      .selectAll("path, polygon") //grab the shapes
      .datum(d) //attach the data directly to *each* shape for future reference
      .attr("fill", colour(d[1]) ); //colour based on the data
});

d3.selectAll("g.region")
  .on("click", function(d,i) {
         infoBox.html("<strong>" + d[0] + ": </strong>" + d[1] ); 
          //print the associated data to the page
  });

Пример реализации: http://jsfiddle.net/ybAj5/7/

Хотя использование dataset.forEach не кажется полным использованием возможностей d3, на самом деле это намного проще, чем пытаться присоединить весь набор данных сразу - тем более, что существует такая вариабельность в структуре областей, некоторые из которых имеют вложенные <g> элементы:

//Option two: select all elements at once and create a datajoin
d3.selectAll("g[id]") //select only g elements that have id values
    .datum(function(){
        var id=d3.select(this).attr("id"); 
        return [id, null]; })
        //create an initial [id, value] dataset based on the id attribute, 
        //with null value for now
    .data(dataset, function(d){return d[0];}) 
       //use the first entry in [id,value] as the key
       //to match the dataset with the placeholder data we just created for each
    .selectAll("path, polygon") //grab the shapes
    .datum(function(){
        return d3.select(this.parentNode).datum() ||
        d3.select(this.parentNode.parentNode).datum();
    }) //use the parent's data if it exists, else the grandparent's data
    .attr("fill", function(d){return d?colour(d[1]):"lightgray";});
         //set the colour based on the data, if there is a valid data element
         //else use gray.

Эта скрипка показывает приведенный выше код в действии, но я снова рекомендую использовать подход forEach.

Comments

    Ничего не найдено.