preface

Let’s draw a line chart this time, so let’s analyze what it takes to draw a line chart?

  1. Coordinate axes (one vertical and one horizontal)
  2. A little grid line to make it look nice
  3. A line chart must have smooth curves
  4. It would be nice if I had another path to draw the lines

Good above is we want step by step to draw the line chart out of the steps !!!!

Let’s take a look at the effect first:

start

Start the tasks listed above

Step 1 (Draw the axes)

<! 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 height = 500, width = 500, margin = 25;
    // Define our SVG canvas space container
    let svg = d3.select('body')
             .append('svg')
             .attr('width',width)
             .attr('height',height)


    // Draw a horizontal axis
    function drawXAxis() {
         // To create a linear scale, use the axes required
         const xScale = d3.scaleLinear().domain([0.10]).range([0, width - margin * 2]);

        // Create the x axis at the bottom
        const xAxis = d3.axisBottom(xScale);

        // Insert the axes into SVG
        svg.append('g').attr('class'.'x-axis').attr('transform'.function(){
            // Shift it to the bottom x pair, we need to draw the Y-axis
            return `translate(${margin}.${ height - margin }) `
        }).call(xAxis);
    }



     // Draw a vertical axis
     function drawYAxis() {
         // To create a linear scale, use the axes required
         const yScale = d3.scaleLinear().domain([10.0]).range([0, width - margin * 2]);

        // Create the x axis at the bottom
        const yAxis = d3.axisLeft(yScale);

        // Insert the axes into SVG
        svg.append('g').attr('class'.'y-axis').attr('transform'.function(){
            // Shift it to the bottom x pair, we need to draw the Y-axis
            return `translate(${margin}.${ margin }) `
        }).call(yAxis);
    }

    drawXAxis();
    drawYAxis();

</script>

Copy the code

Effect presentation:

Code analysis; It’s just two coordinate axes, and then it’s shifted to staggered positions, our x and y axes. Is the model out !!!! Let’s keep going

Step 2 (Draw grid lines)

Previous DOM rendering diagram:

Let’s observe the DOM structure of our coordinate axis. It is wrapped in a G container, and then there are the small lines of our coordinate axis and the words of the scale.

Let’s put a link in there, so we don’t have to worry about translate

Code part:

<! 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 height = 500, width = 500, margin = 25;
    // Define our SVG canvas space container
    let svg = d3.select('body')
             .append('svg')
             .attr('width',width)
             .attr('height',height)


    // Draw a horizontal axis
    function drawXAxis() {
         // To create a linear scale, use the axes required
         const xScale = d3.scaleLinear().domain([0.10]).range([0, width - margin * 2]);

        // Create the x axis at the bottom
        const xAxis = d3.axisBottom(xScale);

        // Insert the axes into SVG
        svg.append('g').attr('class'.'x-axis').attr('transform'.function(){
            // Shift it to the bottom x pair, we need to draw the Y-axis
            return `translate(${margin}.${ height - margin }) `
        }).call(xAxis);
    }



     // Draw a vertical axis
     function drawYAxis() {
         // To create a linear scale, use the axes required
         const yScale = d3.scaleLinear().domain([10.0]).range([0, width - margin * 2]);

        // Create the x axis at the bottom
        const yAxis = d3.axisLeft(yScale);

        // Insert the axes into SVG
        svg.append('g').attr('class'.'y-axis').attr('transform'.function(){
            // Shift it to the bottom x pair, we need to draw the Y-axis
            return `translate(${margin}.${ margin }) `
        }).call(yAxis);
    }

    function drawGrid() {
        // Draw the Y-axis line
        d3.selectAll('.y-axis .tick')
           .append('line')
           .attr('x1'.0)
           .attr('y1'.0)
           // Font-size: 16px! Important
           .attr('x2',(height - margin * 2))
           .attr('y2'.0)
           .attr('stroke'.'#e4e4e4')

        // Draw the X-axis line
        d3.selectAll('.x-axis .tick')
           .append('line')
           .attr('x1'.0)
           .attr('y1'.0)
           .attr('x2'.0)
           .attr('y2',(- height  + margin * 2))
           .attr('stroke'.'#e4e4e4')} (async function draw() {
      await drawXAxis();
      await drawYAxis();
      awaitdrawGrid(); }) ();</script>
Copy the code

Effect presentation:

Summary: Two lines drawn as grid, code changes part addeddrawGridmethods

Step 3 (Draw path line)

Draw line graph line, in fact, is a day path path, some people should question this path calculation position is not good trouble ah? D3js has an API (d3.line()) to convert a set of [{x: 1, y: 1}, {x: 2, y:2}] to this type of path

Code drawing:

<! 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 height = 500, width = 500, margin = 25;
    // Define our SVG canvas space container
    let svg = d3.select('body')
             .append('svg')
             .attr('width',width)
             .attr('height',height);

     // To create a linear scale, use the axes required
    const yScale = d3.scaleLinear().domain([10.0]).range([0, width - margin * 2]);
    const xScale = d3.scaleLinear().domain([0.10]).range([0, width - margin * 2]);

    // Draw a horizontal axis
    function drawXAxis() {

        // Create the x axis at the bottom
        const xAxis = d3.axisBottom(xScale);

        // Insert the axes into SVG
        svg.append('g').attr('class'.'x-axis').attr('transform'.function(){
            // Shift it to the bottom x pair, we need to draw the Y-axis
            return `translate(${margin}.${ height - margin }) `
        }).call(xAxis);
    }



     // Draw a vertical axis
     function drawYAxis() {
        // Create the x axis at the bottom
        const yAxis = d3.axisLeft(yScale);

        // Insert the axes into SVG
        svg.append('g').attr('class'.'y-axis').attr('transform'.function(){
            // Shift it to the bottom x pair, we need to draw the Y-axis
            return `translate(${margin}.${ margin }) `
        }).call(yAxis);
    }

    function drawGrid() {
        // Draw the Y-axis line
        d3.selectAll('.y-axis .tick')
           .append('line')
           .attr('x1'.0)
           .attr('y1'.0)
           // Font-size: 16px! Important
           .attr('x2',(height - margin * 2))
           .attr('y2'.0)
           .attr('stroke'.'#e4e4e4')

        // Draw the X-axis line
        d3.selectAll('.x-axis .tick')
           .append('line')
           .attr('x1'.0)
           .attr('y1'.0)
           .attr('x2'.0)
           .attr('y2',(- height  + margin * 2))
           .attr('stroke'.'#e4e4e4')}// Data definition, two lines
    const data = [
        [
            {x:0.y:6},
            {x:1.y:5},
            {x:2.y:3},
            {x:3.y:5},
            {x:4.y:5},
            {x:6.y:4},
            {x:7.y:3},
            {x:8.y:3},
            {x:9.y:2},
            {x:10.y:10},
        ],
        d3.range(10).map(function(i){
            return {x:i,y:Math.min(i)}
        })
    ]

    function drawLine() {
        //d3.line generates a path from the array coordinates
        let line = d3.line()
                .x(function(d){
                    M0,0, L, 1,2..... This sample
                  return xScale(d.x)
                })
                .y(function(d){
                  return yScale(d.y)
                })
      / / add the path
      svg.selectAll('path.path')
       .data(data)
       .enter()
       .append('path')
       .attr('class'.'path')
       .attr('d'.function(d){
          return line(d)
        })
       .attr('stroke'.'#2e6be6')
       .attr('fill'.'none')
       .attr('transform'.`translate(${margin}.${margin}) `)} (async function draw() {
      await drawXAxis();
      await drawYAxis();
      await drawGrid();
      awaitdrawLine(); }) ();</script>
Copy the code

Effect presentation:

Conclusion: Make use ofd3.line()Help us generate path path, new functiondrawLine()Does it feel like something’s missing? Yeah, it feels like the nodes aren’t obvious, but it would be nice if the curves were smooth, right?

Discount map rendering effect optimization

The nodes are not obvious, right? Smooth curve?

Analysis: Nodes not obvious? Let’s look at the chart and see that they have a circle at each point and the curve is smooth, right? Curve (d3.curvecardinal)

Code rendering:

<! 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 height = 500, width = 500, margin = 25;
    // Define our SVG canvas space container
    let svg = d3.select('body')
             .append('svg')
             .attr('width',width)
             .attr('height',height);

     // To create a linear scale, use the axes required
    const yScale = d3.scaleLinear().domain([10.0]).range([0, width - margin * 2]);

    const xScale = d3.scaleLinear().domain([0.10]).range([0, width - margin * 2]);

    // Draw a horizontal axis
    function drawXAxis() {

        // Create the x axis at the bottom
        const xAxis = d3.axisBottom(xScale);

        // Insert the axes into SVG
        svg.append('g').attr('class'.'x-axis').attr('transform'.function(){
            // Shift it to the bottom x pair, we need to draw the Y-axis
            return `translate(${margin}.${ height - margin }) `
        }).call(xAxis);
    }



     // Draw a vertical axis
     function drawYAxis() {
        // Create the x axis at the bottom
        const yAxis = d3.axisLeft(yScale);

        // Insert the axes into SVG
        svg.append('g').attr('class'.'y-axis').attr('transform'.function(){
            // Shift it to the bottom x pair, we need to draw the Y-axis
            return `translate(${margin}.${ margin }) `
        }).call(yAxis);
    }

    function drawGrid() {
        // Draw the Y-axis line
        d3.selectAll('.y-axis .tick')
           .append('line')
           .attr('x1'.0)
           .attr('y1'.0)
           // Font-size: 16px! Important
           .attr('x2',(height - margin * 2))
           .attr('y2'.0)
           .attr('stroke'.'#e4e4e4')

        // Draw the X-axis line
        d3.selectAll('.x-axis .tick')
           .append('line')
           .attr('x1'.0)
           .attr('y1'.0)
           .attr('x2'.0)
           .attr('y2',(- height  + margin * 2))
           .attr('stroke'.'#e4e4e4')}// Data definition, two lines
    const data = [
        [
            {x:0.y:6},
            {x:1.y:5},
            {x:2.y:3},
            {x:3.y:5},
            {x:4.y:5},
            {x:6.y:4},
            {x:7.y:3},
            {x:8.y:3},
            {x:9.y:2},
            {x:10.y:10},
        ],
        d3.range(10).map(function(i){
            return {x:i,y:Math.min(i)}
        })
    ]

    function drawLine() {
        //d3.line generates a path from the array coordinates
        let line = d3.line()
                .x(function(d){
                    M0,0, L, 1,2..... This sample
                  return xScale(d.x)
                })
                .y(function(d){
                  return yScale(d.y)
                })
                .curve(d3.curveCardinal)  // Curve effect
          
      svg.selectAll('path.path')
       .data(data)
       .enter()
       .append('path')
       .attr('class'.'path')
       .attr('d'.function(d){
          return line(d)
        })
       .attr('stroke'.'#2e6be6')
       .attr('fill'.'none')
       .attr('transform'.`translate(${margin}.${margin}) `)}function drawCircle() {
        data.forEach(item= > {
           svg.append('g')
              .selectAll('.circle')
              .data(item)
              .attr('class'.'circle')
              .enter()
              .append('circle')
              .attr('cx'.function(d){return xScale(d.x)})
              .attr('cy'.function(d){return yScale(d.y)})
              .attr('r'.4)
              .attr('transform'.`translate(${margin}.${margin}) `)
              .attr('fill'.'#fff')
              .attr('stroke'.'rgba(56, 8, 228, .5)')}); } (async function draw() {
      await drawXAxis();
      await drawYAxis();
      await drawGrid();
      await drawLine();
      awaitdrawCircle(); }) ();</script>
Copy the code

Effect rendering (isn’t it much better) :

Summary: NewdrawCircle()Draw a dot usingD3.line ().curve() Draws a curve

Step 4 (Get the wire moving)

How do I get wired animation to work?

For path animations using SVG’s stroke-Dashoffset and stroke-dasharray lines, delay is specified in batches for each point

Stroke-dasharray: used to draw dashed lines stroke-dasharray: Offset of dashed lines

So the question is, right? Can I draw a solid line with a dotted line? Of course you can animate it with this dotted line offset. In zhang Xinxu’s blog, I found an easy to understand explanation: In Chinese, a ham sausage is 12 cm long, and dotted lines should be drawn on it. The dotted lines are 15 cm apart. If there is no Dashoffset, the first 15 cm of ham sausage will be covered with chili sauce! It’s actually only 12 centimeters, so what we’re seeing is the whole ham sausage with chili sauce. Now, dashoffset is also 15cm, so the dotted line is shifted back 15cm. As a result, the chili sauce is spread on the ham sausage, which means there is no chili sauce at all. If you use the line SVG above, the line is invisible. When we reduce the Dashoffset value, we see that the chili sauce on the sausage appears little by little, as if it were applied from the root of the sausage.

Rendering effect:

Code implementation:

<! 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 height = 500, width = 500, margin = 25;
    // Define our SVG canvas space container
    let svg = d3.select('body')
             .append('svg')
             .attr('width',width)
             .attr('height',height);

     // To create a linear scale, use the axes required
    const yScale = d3.scaleLinear().domain([10.0]).range([0, width - margin * 2]);

    const xScale = d3.scaleLinear().domain([0.10]).range([0, width - margin * 2]);

    // Draw a horizontal axis
    function drawXAxis() {

        // Create the x axis at the bottom
        const xAxis = d3.axisBottom(xScale);

        // Insert the axes into SVG
        svg.append('g').attr('class'.'x-axis').attr('transform'.function(){
            // Shift it to the bottom x pair, we need to draw the Y-axis
            return `translate(${margin}.${ height - margin }) `
        }).call(xAxis);
    }



     // Draw a vertical axis
     function drawYAxis() {
        // Create the x axis at the bottom
        const yAxis = d3.axisLeft(yScale);

        // Insert the axes into SVG
        svg.append('g').attr('class'.'y-axis').attr('transform'.function(){
            // Shift it to the bottom x pair, we need to draw the Y-axis
            return `translate(${margin}.${ margin }) `
        }).call(yAxis);
    }

    function drawGrid() {
        // Draw the Y-axis line
        d3.selectAll('.y-axis .tick')
           .append('line')
           .attr('x1'.0)
           .attr('y1'.0)
           // Font-size: 16px! Important
           .attr('x2',(height - margin * 2))
           .attr('y2'.0)
           .attr('stroke'.'#e4e4e4')

        // Draw the X-axis line
        d3.selectAll('.x-axis .tick')
           .append('line')
           .attr('x1'.0)
           .attr('y1'.0)
           .attr('x2'.0)
           .attr('y2',(- height  + margin * 2))
           .attr('stroke'.'#e4e4e4')}// Data definition, two lines
    const data = [
        [
            {x:0.y:6},
            {x:1.y:5},
            {x:2.y:3},
            {x:3.y:5},
            {x:4.y:5},
            {x:6.y:4},
            {x:7.y:3},
            {x:8.y:3},
            {x:9.y:2},
            {x:10.y:10},
        ],
        d3.range(10).map(function(i){
            return {x:i,y:Math.min(i)}
        })
    ]

    function drawLine() {
        //d3.line generates a path from the array coordinates
        let line = d3.line()
                .x(function(d){
                    M0,0, L, 1,2..... This sample
                  return xScale(d.x)
                })
                .y(function(d){
                  return yScale(d.y)
                })
                .curve(d3.curveCardinal)  // Curve effect
          
      svg.selectAll('path.path')
       .data(data)
       .enter()
       .append('path')
       .attr('class'.'path')
       .attr('d'.function(d){
          return line(d)
        })
       .attr('stroke'.'#2e6be6')
       .attr('fill'.'none')
       .attr('transform'.`translate(${margin}.${margin}) `)}function drawCircle() {
        data.forEach(item= > {
           svg.append('g')
              .selectAll('.circle')
              .data(item)
              .enter()
              .append('circle')
              .attr('class'.'circle')
              .attr('cx'.function(d){return xScale(d.x)})
              .attr('cy'.function(d){return yScale(d.y)})
              .attr('r'.4)
              .attr('transform'.`translate(${margin}.${margin}) `)
              .attr('fill'.'#fff')
              .attr('stroke'.'rgba(56, 8, 228, .5)')
              .style('stroke-width'.0);
       });
    }


    function drawAnimations() {
        // Line animation
        svg.selectAll('path.path')
        .attr('stroke'.'#2e6be6')
        .attr('transform'.'translate (25, 25)')
        .style('stroke-dasharray'.function(){
            return d3.select(this).node().getTotalLength()
        })
        .style('stroke-dashoffset'.function(){
            return d3.select(this).node().getTotalLength()
        })
        .transition()
        .duration(2000)
        .delay(200)
        .ease(d3.easeLinear)
        
        .style('stroke-dashoffset'.0);

       / / dot
       svg.selectAll('.circle')
            .style('stroke-width'.0)
            .transition()
            .duration(1000)
            .delay(function(d,i){
                return i * 100
            })
            .ease(d3.easeLinear)
            .style('stroke-width'.1)} (async function draw() {
      await drawXAxis();
      await drawYAxis();
      await drawGrid();
      await drawLine();
      await drawCircle();
      awaitdrawAnimations(); }) ();</script>
Copy the code

Effect:

conclusion

Is the basic line chart already drawn? Tooltip, Legend….. Send it when I’m done with it.

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