This is the 8th day of my participation in the August Text Challenge.More challenges in August

Text, insert, remove, classed

text

Text is used to draw text

  • Usage:
<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Document</title>
</head>
<body>
    <div id="main">
        <p class="item"></p>
        <p class="item"></p>
        <p class="item"></p>
        <p class="item"></p>
        <p class="item"></p>
        <p class="item"></p>
        <p class="item"></p>
        <p class="item"></p>
        <p class="item"></p>
        <p class="item"></p>
        <p class="item"></p>
    </div>
</body>
</html>
<script src="https://d3js.org/d3.v5.min.js"></script>

<script>
 //style
let main= d3.select('#main')
            .style('width'.'500px')
            .style('height'.'500px');

main.selectAll('.item')
    .style('height'.'30px')
    .style('width'.'100%')
    .style('background'.(d, i) = > {
        console.log(d,'d>>>>>>......... ')
       return i % 2 ? 'red' : 'blue'
    })
    .text('p')

</script>
Copy the code

Rendering effect:

Statement:Redraw the text in SVG using SVG textDraw this with d3js:

d3.select('svg')
  .append('text')
  .attr('x'.10)
  .attr('y'.20)
  .style('cursor'.'default')
  .text('svg-text')
Copy the code

insert

Append is append like an element, insert is append like an element before append like append

  • Usage Examples:
<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Document</title>
</head>
<body>
    <div id="main">
    </div>
</body>
</html>
<script src="https://d3js.org/d3.v5.min.js"></script>

<script>
// append
const svg = d3.select('#main')
              .insert('svg')
              .attr('width'.500)
              .attr('height'.500);

 //append a rect to add some attributes
 svg.insert('rect')
    .attr('width'.100)
    .attr('height'.100)
    .attr('fill'.'red')
    .attr('x'.10)
    .attr('y'.10)
    .attr('stroke'.'blue')
</script>
Copy the code

Rendering effect:

classed

Adding one more class to a classed class means that an element is bound to more than one class

  • Usage Examples:
d3.select('svg')
  .class('svg')
  .classed('svg-container')
Copy the code

Let’s go to today’s theme

D3js data binding

The data report

  • 1. Data is a situation where an array is bounddata(data)This sample is the index of the bound data by default, and can also be this sampledata(data, (d,idx) => d)Specify to bind a field,This binding is important and will be discussed later
  • 2. Draw multiple RECTs and share binding data with them. You can see the last oneconsole.log()The corresponding binding 1, 2, 3, 4, 5, 6, 7 is printed
<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Document</title>
</head>
<body>
    
</body>
</html>
<script src="https://d3js.org/d3.v5.min.js"></script>

<script>
    const svg = d3.select('body')
                .append('svg')
                .attr('width'.500)
                .attr('height'.500);

    

    const data = [1.2.3.4.5.6.7];

    data.forEach((item= > {
        svg.append('rect')
        .attr('width'.20)
        .attr('height'.20)
        .attr('x'.20 * item)
        .attr('y'.20 * item)
        .attr('fill'.'red')
    }))

    

    svg.selectAll('rect')
       .data(data)
       .attr('stroke'.(d,idx) = > {
           console.log(d,'d')})</script>
Copy the code

Effect presentation:

datum

Datum does the same thing as data, it binds data, it binds individual data

  • Usage examples
svg.select('rect')
       .datum(1)
       .attr('stroke'.(d,idx) = > {
           console.log(d,'d')})Copy the code

Data, datum Obtain data

The above mentioned binding data, that binding data can be obtained; The last line of console.log() outputs :[1,2,3,4,5,6,7]

  • Usage Examples:
<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Document</title>
</head>
<body>
    
</body>
</html>
<script src="https://d3js.org/d3.v5.min.js"></script>

<script>
    const svg = d3.select('body')
                .append('svg')
                .attr('width'.500)
                .attr('height'.500);

    

    const data = [1.2.3.4.5.6.7];

    data.forEach((item= > {
        svg.append('rect')
        .attr('width'.20)
        .attr('height'.20)
        .attr('x'.20 * item)
        .attr('y'.20 * item)
        .attr('fill'.'red')
    }))



    svg.selectAll('rect')
       .data(data)
       .attr('stroke'.(d,idx) = > {
           console.log(d,'d')})console.log(svg.selectAll('rect').data(),'data')
</script>
Copy the code

enter

You should remember that I created the rect with forEach, which was a bit of a drag. D3 also has its own way of creating multiple elements with data. For example, the following code is to select multiple RECt bindings and call Enter, and then append is insufficient to add data using append method

Enter Example

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Document</title>
</head>
<body>
    
</body>
</html>
<script src="https://d3js.org/d3.v5.min.js"></script>

<script>
    const svg = d3.select('body')
                .append('svg')
                .attr('width'.500)
                .attr('height'.500);

    

    const data = [1.2.3.4.5.6.7];



    svg.selectAll('rect')
       .data(data)
       .enter()
       .append('rect')
       .attr('width'.20)
       .attr('height'.20)
       //d stands for bound data,idx stands for index, and each method in D3 can use the callback function
       .attr('x'.(d,idx) = > 20 * d)
       .attr('y'.(d,idx) = > 20 * d)
       .attr('fill'.'red')
       .attr('stroke'.'blue')
       .attr('strokeWidth'.1)
    
</script>
Copy the code

Rendering effect:

exit

Exit is not automatically filled when there is less data and more selections. It can be used with remove to remove redundant elements

Usage Examples:

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Document</title>
</head>
<body>
    
</body>
</html>
<script src="https://d3js.org/d3.v5.min.js"></script>

<script>
    const svg = d3.select('body')
                .append('svg')
                .attr('width'.500)
                .attr('height'.500);

    

    const data = [1.2.3.4.5.6.7];

    [1.2.3.4.5.6.7.8.9.10].forEach((item= > {
        svg.append('rect')
        .attr('width'.20)
        .attr('height'.20)
        .attr('x'.20 * item)
        .attr('y'.20 * item)
        .attr('fill'.'red')
    }))



    svg.selectAll('rect')
       .data(data)
       .exit()
       .remove()

    console.log(svg.selectAll('rect').data(),'data')
</script>
Copy the code

How do you implement a data-driven approach?

In fact, the data binding can be divided into three layers;

1. Rendering layer; 2. Modify layer; 3. Delete the layer;

  • 1. Rendering layer:enter()(Data binding will determine whether the next call will enter the Enter layer based on the value you bind.)
  • 2. Modification layer:data()(Data binding will determine if you have modified the data based on the data binding)
  • 3, Delete layer:exit()(Data binding will detect which data you delete based on the data you bind)

The code analyzes the level of data binding

We have all three levels, so you can think of it that way for the moment

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Document</title>
</head>
<body>
    
</body>
</html>
<script src="https://d3js.org/d3.v5.min.js"></script>

<script>
    const svg = d3.select('body')
                .append('svg')
                .attr('width'.500)
                .attr('height'.500);

    

    const data = [{id: 1.fill: 'red'.x: 20.y: 20}, {id: 2.fill: 'blue'.x: 40.y: 40}, {id: 3.fill: 'yellow'.x: 60.y: 60}, {id: 4.fill: 'black'.x: 80.y: 80}];
    

   / / modified layer
   const update = svg.selectAll('rect')
       .data(data)

    / / rendering layer
    const enter = update.enter();

    / / delete the layer
    const exit = update.exit();

    enter.append('rect')
       .attr('width'.20)
       .attr('height'.20)
        .attr('x'.(d,idx) = > d.x)
        .attr('y'.(d,idx) = > d.y)
        .attr('fill'.(d) = > d.fill)
       .attr('stroke'.'blue')
       .attr('strokeWidth'.1)
    
    exit.remove()
</script>
Copy the code

Rendering effect:

Encapsulate as a data-driven function

Put those layers in a function to be data-driven. And you can kind of think about the three levels,

  • The first time a function is called to draw: it must enter the draw layer, and all other layers are empty
  • The second call to draw means that the data has changed (for example, the color has changed to fill) and that changes the data into the modification layer
  • Call the function again and draw (delete one data, add one day data) this is based on what you bind.data(data d => d.id)The default for detection is index

Code examples:

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Document</title>
</head>
<body>
    <div>
        <button onclick="remove()">Delete a piece of data</button>
        <button onclick="add()">Add a piece of data</button>
        <button onclick="exit()">Modifying a data item</button>
        <button onclick="all()">Add a data item, modify a data item, and delete a data item</button>
    </div>
</body>
</html>
<script src="https://d3js.org/d3.v5.min.js"></script>

<script>
    const svg = d3.select('body')
                .append('svg')
                .attr('width'.500)
                .attr('height'.500);

    

    let data = [{id: 1.fill: 'red'.x: 20.y: 20}, {id: 2.fill: 'blue'.x: 40.y: 40}, {id: 3.fill: 'yellow'.x: 60.y: 60}, {id: 4.fill: 'black'.x: 80.y: 80}];
    
    draw()
function draw() {
    / / modified layer
    const update = svg.selectAll('rect')
       .data(data)

    update.attr('x'.(d,idx) = > d.x)
        .attr('y'.(d,idx) = > d.y)
        .attr('fill'.(d) = > d.fill)

    / / rendering layer
    const enter = update.enter();

    / / delete the layer
    const exit = update.exit();

    enter.append('rect')
       .attr('width'.20)
       .attr('height'.20)
        .attr('x'.(d,idx) = > d.x)
        .attr('y'.(d,idx) = > d.y)
        .attr('fill'.(d) = > d.fill)
       .attr('stroke'.'blue')
       .attr('strokeWidth'.1)
    
    exit.remove()
}

function remove() {
    data.pop();
    draw();
}

function add() {
    data.push({id: Math.random() * 200.fill: 'violet'.x: 120.y: 120});
    draw();
}

function exit() {
    data[0].fill = 'orange';
    draw();
}

function all() {
    data.shift();
    data.push({id: Math.random() * 200.fill: 'green'.x: 150.y: 150});
    data[0].fill = 'pink';
    console.log(data,'data')
    draw();
}

 
</script>
Copy the code

Effect rendering: you may find that clicking the last button does not reflect any data(the problem is data binding. Data (data)). Instead, make it recognize id.data(data, d => d.id).

Correct data-driven functions

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Document</title>
</head>
<body>
    <div>
        <button onclick="remove()">Delete a piece of data</button>
        <button onclick="add()">Add a piece of data</button>
        <button onclick="exit()">Modifying a data item</button>
        <button onclick="all()">Add a data item, modify a data item, and delete a data item</button>
    </div>
</body>
</html>
<script src="https://d3js.org/d3.v5.min.js"></script>

<script>
    const svg = d3.select('body')
                .append('svg')
                .attr('width'.500)
                .attr('height'.500);

    

    let data = [{id: 1.fill: 'red'.x: 20.y: 20}, {id: 2.fill: 'blue'.x: 40.y: 40}, {id: 3.fill: 'yellow'.x: 60.y: 60}, {id: 4.fill: 'black'.x: 80.y: 80}];
    
    draw()
function draw() {
    / / modified layer
    const update = svg.selectAll('rect')
       .data(data, d= > d.id)
    update.attr('x'.(d,idx) = > d.x)
        .attr('y'.(d,idx) = > d.y)
        .attr('fill'.(d) = > d.fill)

    / / rendering layer
    const enter = update.enter();

    / / delete the layer
    const exit = update.exit();

    enter.append('rect')
       .attr('width'.20)
       .attr('height'.20)
        .attr('x'.(d,idx) = > d.x)
        .attr('y'.(d,idx) = > d.y)
        .attr('fill'.(d) = > d.fill)
       .attr('stroke'.'blue')
       .attr('strokeWidth'.1)
    
    exit.remove()
}

function remove() {
    data.pop();
    draw();
}

function add() {
    data.push({id: Math.random() * 200.fill: 'violet'.x: Math.random() * 200.y: Math.random() * 200});
    draw();
}

function exit() {
    data[0].fill = 'orange';
    draw();
}

function all() {
    data.shift();
    data.push({id: Math.random() * 200.fill: 'green'.x: 150.y: 150});
    data[0].fill = 'pink';
    console.log(data,'data')
    draw();
}

 
</script>
Copy the code

conclusion

In fact, you can compare canvas. If you want to change, delete, add or modify an element in canvas, you always have to redraw it. Data binding of D3 + SVG helps us solve the advantage of no need to erase the redraw. After writing the drawing function, it would be good to call the drawing function if the data is changed. It would be even better to have a watch that listens to the data. You can refer to my own watch that I implemented before

conclusion

  • Hi, I am Mihara and thank you for watching and I will work harder.
  • Each method is typed out and verified, and can be copied if necessary.
  • If you give help a thumbs-up 👍 is even better thank you ~~~~~
  • We look forward to your attention