d3js selections深入理解


D3 selections選擇DOM元素以便可以對這些dom元素做相應的操作,比如:更改其style,修改其屬性,執行data-join操作,或者插入、刪除相應elements

比如,如果給定5個circles:

我們可以使用d3.selectAll來選中所有的circles,並且通過.style和.attr來修改其樣式或者屬性

d3.selectAll('circle')
  .style('fill', 'orange')
  .attr('r', function() {
    return 10 + Math.random() * 40;
  });

 

Making selections

D3有兩個函數來執行選擇操作:d3.select和d3.selectAll

d3.select進選中第一個匹配的元素。而d3.selectAll則選中所有匹配的元素。這兩個函數都接收一個參數來指定選擇器字符串:和css選擇器相同語法 selector string.

比如我們使用css class類名來選擇

d3.selectAll('.item').

Modifying elements

一旦我們完成了選擇得到了selection,則我們可以使用selection的以下函數:

Name Behaviour Example
.style Update the style d3.selectAll('circle').style('fill', 'red')
.attr Update an attribute d3.selectAll('rect').attr('width', 10)
.classed Add/remove a class attribute d3.select('.item').classed('selected', true)
.property Update an element's property d3.selectAll('.checkbox').property('checked', false)
.text Update the text content d3.select('div.title').text('My new book')
.html Change the html content d3.select('.legend').html('<div class="block"></div><div>0 - 10</div>')

需要注意的是,無論是select還是selectAll返回的selection,執行上面的操作都將對所有選中的元素產生影響。

Updating selections with functions

除了傳入常量值到對應attr,style函數外,我們也可以傳入一個函數,,該函數輸出值作為attr, style最終設定的值:

d3.selectAll('circle')
  .attr('cx', function(d, i) {
    return i * 100;
  });

該函數將自動接收(d,i).  d 是joined在該元素上的數據 (參考 data joins section) 而 i 則是該元素在selection中對應的index

如果我們希望根據其在selection中的index來更改selection中的元素對應的x軸位置,比如我們希望水平布置rect元素在不同的位置(而不是堆砌在一起):

d3.selectAll('rect')
  .attr('x', function(d, i) {
    return i * 40;
  });

大多數情況下,傳入一個匿名函數就好,但是我們也可以使用命名的

function positionRects(d, i) {
  return i * 40;
}

d3.selectAll('rect')
  .attr('x', 

Handling events

我們可以通過selection.on()來為selection中的elements添加事件處理函數,而這個事件處理函數,同樣地會傳入d和i兩個參數以方便處理。同樣地,d是本元素joined data,i則是本元素在selection中的index值,下面是列出的主要event時間

 

Event name Description
click Element has been clicked
mouseenter Mouse pointer has moved onto the element
mouseover Mouse pointer has moved onto the element or its children
mouseleave Mouse pointer has moved off the element
mouseout Mouse pointer has moved off the element or its children
mousemove Mouse pointer has moved over the element

比如下面我們寫一個小的代碼,實現當點擊后就修改其text指明是第幾個元素被點擊

d3.selectAll('circle')
  .on('click', function(d, i) {
    d3.select('.status')
      .text('You clicked on circle ' + i);
  });

需要注意的是,在事件回調函數中,this的值是DOM 元素本身,和selection無關!如果要使用d3對該dom操作,必須先做select操作:

d3.selectAll('circle')
  .on('click', function(d, i) {
    d3.select(this)  // this指被點擊的dom元素,而不是d3 selection!
      .style('fill', 'orange');
  });

Inserting and removing elements

我們看一個例子:3個g元素,每個g都包含了一個circle:

<g class="item" transform="translate(0, 0)">
  <circle r="40" />
</g>
<g class="item" transform="translate(120, 0)">
  <circle r="40" />
</g>
<g class="item" transform="translate(240, 0)">
  <circle r="40" />
</g>

我們可以插入一個 text element到每個g元素中:

d3.selectAll('g.item')
  .append('text')
  .text(function(d, i) {
    return i + 1;
  });

最終的結果是在每個g.item元素中追加了一個text元素,其text值為對應i的值:

<g class="item" transform="translate(0, 0)">
  <circle r="40" />
  <text>1</text>
</g>
<g class="item" transform="translate(120, 0)">
  <circle r="40" />
  <text>2</text>
</g>
<g class="item" transform="translate(240, 0)">
  <circle r="40" />
  <text>3</text>
</g>

.remove 刪除selection中的元素:

d3.selectAll('circle')
  .remove();

Chaining

絕大部分selection的方法都仍然返回selection本身,因此這意味着我們可以鏈式方法繼續調用其他的方法:

d3.selectAll('circle')
  .style('fill', 'orange')
  .attr('r', 20)
  .on('click', function(d, i) {
    d3.select('.status')
      .text('You clicked on circle ' + i);
  });

Each and call

.each 允許對每個selection中的每個元素執行一段函數功能(同樣傳入d,i, this參數可以使用), .call 則允許對 selection itself. 執行相應的函數功能

看下面的例子:

function addNumberedCircle(d, i) {
  d3.select(this)
    .append('circle')
    .attr('r', 40);

  d3.select(this)
    .append('text')
    .text(i + 1)
    .attr('y', 50)
    .attr('x', 30);
}

d3.selectAll('g.item')
  .each(addNumberedCircle);

再看一個.each 調用的例子

   d3.selectAll('circle')

  .each(function(d, i) {
    var odd = i % 2 === 1;

    d3.select(this)
      .style('fill', odd ? 'orange' : '#ddd')  // 對奇偶元素使用不用的顏色和半徑大小
      .attr('r', odd ? 40 : 20);
  });

而.call則傳入selection本身,這實際上是javascript本身的特性!

function addNumberedCircle(selection) {
  selection
    .append('circle')
    .attr('r', 40);

  selection
    .append('text')
    .text(function(d, i) {
      return i + 1;
    })
    .attr('y', 50)
    .attr('x', 30);
}

d3.selectAll('g.item')
  .call(addNumberedCircle);

 

Filtering and sorting selections

We can filter a selection using .filter. A function is usually passed into .filter which returns true if the element should be included. .filter returns the filtered selection.

我們也可以使用selection的.filter方法來過濾對應selection中的元素。通常我們通過傳入一個函數(該函數同樣具有d,i,this可以訪問)給到.filter方法來告訴d3,如果該函數返回true則該i元素將被包含住,如果返回false,則不被包含在filter的返回selection中,而.filter則返回filtered selection.

比如下面的例子中我們對偶數的元素來着色為orange色,奇數元素作色為藍色:

d3.selectAll('circle')
  .filter(function(d, i) { // filter返回偶數的元素
    return i % 2 === 0;
  })
  .style('fill', 'orange');// 偶數元素作色為橘色
d3.selectAll('circle')
  .filter(function(d, i) { // filter返回奇數的元素
    return i % 2 === 1;
  })
  .style('fill', 'blue'); // 奇數元素作色為藍色

.sort()排序只有在有joined數據時才有意義。我們可以傳入一個比較函數來調用.sort對selection中的元素執行排序操作。比較函數本身有兩個參數,通常為a,b分別代表了被比較的兩個元素上綁定的datam.如果比較函數返回負值,那么a將在b之前,如果是正,則a放在b之后。

下面假定selection上有以下綁定的數據:

[
{"name":"Andy","score":37},
{"name":"Beth","score":39},
{"name":"Craig","score":31},
{"name":"Diane","score":35},
{"name":"Evelyn","score":38}
]

 

  d3.selectAll('.person')
    .sort(function(a, b) {
      return b.score - a.score;
    });
myData = [
  {
    "name": "Andy",
    "score": 37
  },
  {
    "name": "Beth",
    "score": 39
  },
  {
    "name": "Craig",
    "score": 31
  },
  {
    "name": "Diane",
    "score": 35
  },
  {
    "name": "Evelyn",
    "score": 38
  }
];

var barWidth = 400;
var barScale = d3.scaleLinear().domain([0, 100]).range([0, barWidth]);

var u = d3.select('#wrapper')
  .selectAll('.person')
  .data(myData);

var entering = u.enter()
  .append('div')
  .classed('person', true);

entering.append('div')
  .classed('label', true)
  .text(function(d) {
    return d.name;
  });

entering.append('div')
  .classed('bar', true)
  .style('width', function(d) {
    return barScale(d.score) + 'px';
  });

function sort() {
  d3.selectAll('.person')
    .sort(function(a, b) {
      return b.score - a.score;
    });
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM