Skip to content

1.Selection

yuanlii edited this page Jul 2, 2019 · 21 revisions

Selection

main tutorial

  • D3.select --> selects the first matching element
  • d3.selectAll --> selects all matching elements.

Update selection with functions

an example:

d3.selectAll('circle')
.attr('cx', function(d, i) {
	return i * 100;
});
  • d is the joined data
  • i is the index of the element within the selection

Another example (entire code):

<html>
    <head>
        <link rel="stylesheet" href="index.css">
        <title>Learn D3.js</title>
    </head>

    <style>
        rect {
	        fill: #ddd;
        }        
    </style>

    <body>
        <!-- begin by creating several squares  -->
        <svg width='800' height='600'>
            <g transform="translate(70, 20)">
                <rect width="30" height="30" y="0" />
                <rect width="30" height="30" y="40" />
                <rect width="30" height="30" y="80" />
                <rect width="30" height="30" y="120" />
            </g>
        </svg>

        <!-- define an action button -->
        <div class="menu">
            <button onClick="update();">Click to update rect elements using function(d, i)</button>
        </div>
        
        <script src="https://d3js.org/d3.v4.min.js"></script>
        <!-- reference to index.js -->
        <script src="index.js"></script>
    </body>
</html>

selection_square

Oftentimes will use anonymous function, but can also use named function as below:

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

function update() {
	d3.selectAll('rect')
		.attr('x', positionRects
		);
}

Event Handler

We can add event handlers to selected elements using .on which expects a callback function into which is passed two arguments d and i. | "Event Call-back Function"

  • d is the joined data
  • i is the index of the element within the selection.
d3.selectAll('circle')
  .on('click', function(d, i) {
	// in the event call-back function, "this" variable is bound to DOM element
    d3.select(this)
      .style('fill', 'orange');
  });

Note that this is a DOM element and not a D3 selection so if we wish to modify it using D3 we must first select it using d3.select(this).

Inserting and removing elements

  • .append - Elements can be added to a selection; commonly used in the context of enter/exit where it has different behaviour;
  • .insert - add elements to a selection; .insert is similar to .append but it allows us to specify a before element to which, you guessed it, the new element is attached.
  • .remove - elements can be removed

an example of .append(): img

<html>
    <head>
        <link rel="stylesheet" href="index.css">
        <title>Learn D3.js</title>
    </head>

    <style>
        body {
            font-family: "Helvetica Neue", Helvetica, sans-serif;
            font-size: 14px;
            color: #333;
        }   
        circle {
	        fill: orange;
        }  
        g.item text {
            fill: #ddd;
            font-size: 70px;
            text-anchor: middle;
            font-weight: bold;
        }
    </style>

    <body>
        <!-- create an empty container first -->
        <svg width='800' height='140'>
            <g transform="translate(70, 70)">
                <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>
            </g>
        </svg>
        
        <script src="https://d3js.org/d3.v4.min.js"></script>
        <!-- reference to index.js -->
        <script>
            d3.selectAll('g.item')
            .append('text')
            // add text to each g.item
            .text(function(d, i) {
                return i + 1;
            })
            //   specify the position of the item
                .attr('y', 50)
                .attr('x', 30);

        </script>
    </body>
</html>

Another example of using .insert():

d3.selectAll('g.item')
   // insert text before circle
  .insert('text', 'circle')
  .text(function(d, i) {
    return i + 1;
  });

and it would look like below: img

Removing

.remove removes all the elements in a selection.

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

Chaining

selection functions such as .style, .attr and .on can be chained.

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

entire code:

<html>
    <head>
        <link rel="stylesheet" href="index.css">
        <title>Learn D3.js</title>
    </head>

    <style>
        body {
            font-family: "Helvetica Neue", Helvetica, sans-serif;
            font-size: 14px;
            color: #333;
        }   
        circle {
	        fill: orange;
        }  
        g.item text {
            fill: #ddd;
            font-size: 70px;
            text-anchor: middle;
            font-weight: bold;
        }
    </style>

    <body>
        <!-- create an empty container first -->
        <svg width='800' height='140'>
            <g transform="translate(70, 70)">
                <circle r="40" cx="120" />
                <circle r="40" cx="240"/>
                <circle r="40" cx="360"/>
                <circle r="40" cx="480"/>
            </g>
        </svg>
        
        <!-- create a button with onClick function set-->
        <div class="status">
            Click on a circle
        </div>


        <script src="https://d3js.org/d3.v4.min.js"></script>
        <!-- reference to index.js -->
        <script>
            d3.selectAll('circle')
            .style('fill', 'orange')
            .attr('r', 20)
            .on('click', function(d, i) {
                d3.select('.status')
                .text('You clicked on circle ' + i);
            });
            
        </script>
    </body>
</html>

Each and Call

.each allows a function to be called on each element of a selection and .call allows a function to be called on the selection itself.

entire code:

<html>
    <head>
        <link rel="stylesheet" href="index.css">
        <title>Learn D3.js</title>
    </head>

    <style>
        body {
            font-family: "Helvetica Neue", Helvetica, sans-serif;
            font-size: 14px;
            color: #333;
        }   
        circle {
	        fill: orange;
        }  
        g.item text {
            fill: #ddd;
            font-size: 70px;
            text-anchor: middle;
            font-weight: bold;
        }
    </style>

    <body>
        <!-- create an empty container first -->
        <svg width='800' height='140'>
            <g transform="translate(70, 70)">
                <g class="item" transform="translate(0, 0)"></g>
                <g class="item" transform="translate(120, 0)"></g>
                <g class="item" transform="translate(240, 0)"></g>
            </g>
        </svg>
        
        <script src="https://d3js.org/d3.v4.min.js"></script>
        <!-- reference to index.js -->
        <script>
            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);
                        
        </script>
    </body>
</html>

Triple Equals in javascript: When using triple equals === in JavaScript, we are testing for strict equality. This means both the type and the value we are comparing have to be the same.

实现的效果是:odd -> orange, non-odd -> 灰色 img

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);
  });

In the case of .call D3 passes in the selection itself. This is a common pattern for reusable components.

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);

假如使用.call(),注意上面svg里面设置的是:

<g class="item" transform = "translate(0,0)"></g>;

若使用.each(), 则上面svg里面设置的是:

<circle r="40",rx="20"></circle>

Filtering and sorting selections

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.

Sorting

sort by score using:

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

内部selection有点迷 - 这个link帮助理解 entire code:

<html>
    <head>
        <link rel="stylesheet" href="index.css">
        <title>Learn D3.js</title>
    </head>

    <style>
        body {
            font-family: "Helvetica Neue", Helvetica, sans-serif;
            font-size: 14px;
            color: #333;
        }   
        
        .person {
            height: 20px;
            position: relative;
        }

        .person .label {
            width: 90px;
            text-align: right;
        }

        .person .bar {
            height: 19px;
            background-color: steelblue;
            position: absolute;
            left: 100px;
        }

        .person div {
            display: inline-block;
        }
 

    </style>

    <body>
    
        <div id="wrapper">
        </div>

        <div class="menu">
            <button onClick="sort();">Sort</button>
        </div>
        
        <script src="https://d3js.org/d3.v4.min.js"></script>
        <!-- reference to index.js -->
        <script>
            
            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;
                    });
                }

        </script>
    </body>
</html>

Clone this wiki locally