D3.js animion - displaying in browsers


#1

Good day/night!

I got this code on Codepen https://codepen.io/alextechflow/pen/QxeJwv
How can I get it to show up in a div?

I have the D3.js link added to my index.html
Is there something else I am missing here? My div is empty.


#2

Like this perhaps…

<!DOCTYPE HTML>
<html lang="en">
<head>

<meta charset="utf-8">
<meta name="viewport" content="width=device-width,height=device-height,initial-scale=1">

<title>untitled document</title>

<!--<link rel="stylesheet" href="screen.css" media="screen">-->

<style media="screen">
html, body {
    height: 100%;
    width: 100%;
    margin: 0;
 }

body {
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: #f9f9f9;
    font: 100% / 162% verdana, arial, helvetica, sans-serif;
 }

#container {
    position: relative;
    display: inline-block;
    border: 0.25em solid #56fefe;
    border-radius: 0.75em;
    background: #060200;
    box-shadow: 0.5em 0.5em 0.5em rgba( 0, 0, 0, 0.4 );
 }

#container ul {
    position: absolute;
    z-index: 2;
    top: 50%;
    left: 50%;
    transform: translate( -50%, -50% );
    margin: 0;
    padding: 0;
    list-style: none;
    color: #fff;
 }

.ring {
    stroke: #56fefe;
    stroke-width: 2;
 }

</style>

</head>
<body>

 <div id="container">

  <svg height="0" width="0">
   <defs>
    <filter id="glow">
     <feGaussianBlur stdDeviation="10" result="coloredBlur"/>
     <feMerge>
       <feMergeNode in="coloredBlur"/>
       <feMergeNode in="SourceGraphic"/>
     </feMerge>
    </filter>
   </defs>
  </svg>

  <ul>
   <li>item 1</li>
  </ul>

 </div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.3.0/snap.svg-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>

<script>
(function() {
   'use strict';
// Configuration
const maxRadius = 100;
const gap = 10;
const padding = 25;
const height = (maxRadius + padding) * 2;
const width = (maxRadius + padding) * 2;

// Random data
const dataSet = [
  {
    value: 34,
    total: 100
  },
  {
    value: 21,
    total: 100
  },
  {
    value: 353,
    total: 520
  },
  {
    value: 35,
    total: 340
  }
];

// Append SVG element to body
const svg = d3.select('#container')
  .append('svg')
  .attr('height', height)
  .attr('width', width)
  .attr('class', 'rings');

// Append a bunch of circle elements based on number of items in the dataSet and set attributes
const rings = svg.selectAll('circle')
  .data(dataSet)
  .enter()
  .append('circle')
  .attr('cx', width/2)
  .attr('cy', height/2)
  .attr('fill', 'none')
  .attr('class', 'ring');

// Build the initial state of the rings
rings.each(function(d, i) {
  const element = this;
  const radius = maxRadius - (gap * i);
  // Calculates the circumference of the circle
  const length = Math.PI * (radius * 2);
  // Calculate the percentage of the data.value over data.total
  const value = (d.value/d.total) * length;
  
  // Animates the stroke depending on the percentage calculated
  d3.select(element)
    .attr('r', radius)
    .attr('stroke-dasharray', length)
    .attr('stroke-dashoffset', length)
    .transition()
    .duration(2000)
    .attr('stroke-dashoffset', value);
});

function rotate(element) {
  // Randomiser to set the direction of the rotation
  const s = (Math.floor(Math.random() * 11) % 2 === 0 ? '-' : '');
  // Initial position of rings
  element.transform('r0, ' + width/2 + ',' + height/2);
  // Randomised rotation animation which recursively calls itself as a callback
  element.animate({ transform: 'r' + s + '360, ' + width/2 + ',' + height/2 }, 
   (Math.random() * 1000) + 2000, 
   mina.linear, () => rotate(element));
};

// Rotating animation using Snap.svg
rings.each(function() { 
  const element = this;
  // Start the animation
  rotate(Snap(element));
})
}());
</script>

</body>
</html>

coothead


#3

Ah, I see now. I did not have snap.svg linked to it.

Thank you very much. It is working now. :slight_smile:


#4

 
 
        No problem, you’re very welcome. :winky:
 
 

Your actual problem was here…

// Append SVG element to body
const svg = d3.select('body')

…which I changed to …


// Append SVG element to body
const svg = d3.select('#container')

…the id of the div container.

        coothead


#5

I see. Thanks for pointing that out.

And how can I clone and add this same graph/svg to another HTML element (<ul> or <li>)?

I’ve tried adding new IDs and creating extra variables for rings and the svg itself but I can’t get it to show up twice on my page.

The goal is to have each

  • element wrapped up in this animated circle of moving rings.
    I have 3 <li>s in total.

  • #6

    Hi there AlexTechFlow,

    try it like this…

    <!DOCTYPE HTML>
    <html lang="en">
    <head>
    
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,height=device-height,initial-scale=1">
    
    <title>untitled document</title>
    
    <!--<link rel="stylesheet" href="screen.css" media="screen">-->
    
    <style media="screen">
    
    html, body {
        height: 100%;
        margin:0;
     }
    
    body {
        display: flex;
        align-items: center;
        background-color: #f9f9f9;
        font: 100% / 162% verdana, arial, helvetica, sans-serif;
        overflow: hidden;
     }
    
    #container {
        display: flex;
        justify-content: center; 
        flex-direction: row;
        flex-wrap: wrap; 
        max-width: 31em;
        padding: 0;
        margin: 1em auto;
        list-style: none;
        animation: spin 12s infinite linear;
     }
    
    #container li {
        position: relative;
        display: inline-block;
        margin: 0.5em;
        border: 0.25em solid #56fefe;
        border-radius: 50%;
        background: #060200;
        box-shadow: 0.5em 0.5em 0.5em rgba( 0, 0, 0, 0.4 );
     }
    
    #container li span{
        position: absolute;
        z-index: 2;
        top: 40%;
        left: 30%;
        font-size: 1.1em;
        font-weight: bold;
        color: #fff;
        animation: spin2 12s infinite linear;
     }
    
    .ring {
        stroke: #56fefe;
        stroke-width: 2;
     }
    
    @keyframes spin {
    0% {
        transform: rotateZ( 0 );
      }
    100% {
        transform: rotateZ( 360deg );
      }
     }
    
    @keyframes spin2 {
    0% {
        transform: rotateZ( 0 );
      }
    100% {
        transform: rotateZ( -360deg );
      }
     }
    </style>
    
    </head>
    <body>
    
    <ul id="container">
    
     <li>
    
      <svg height="0" width="0">
       <defs>
        <filter>
         <feGaussianBlur stdDeviation="10" result="coloredBlur"/>
         <feMerge>
           <feMergeNode in="coloredBlur"/>
           <feMergeNode in="SourceGraphic"/>
         </feMerge>
        </filter>
       </defs>
      </svg>
    
     <span>item 1</span>
    
     </li><li>
    
      <svg height="0" width="0">
       <defs>
        <filter>
         <feGaussianBlur stdDeviation="10" result="coloredBlur"/>
         <feMerge>
           <feMergeNode in="coloredBlur"/>
           <feMergeNode in="SourceGraphic"/>
         </feMerge>
        </filter>
       </defs>
      </svg>
    
     <span>item 2</span>
    
     </li><li>
    
      <svg height="0" width="0">
       <defs>
        <filter>
         <feGaussianBlur stdDeviation="10" result="coloredBlur"/>
         <feMerge>
           <feMergeNode in="coloredBlur"/>
           <feMergeNode in="SourceGraphic"/>
         </feMerge>
        </filter>
       </defs>
      </svg>
    
     <span>item 3</span>
    
     </li>
    </ul>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.3.0/snap.svg-min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
    
    <script>
    (function() {
       'use strict';
    // Configuration
    const maxRadius = 60;
    const gap = 10;
    const padding = 20;
    const height = (maxRadius + padding) * 2;
    const width = (maxRadius + padding) * 2;
    
    // Random data
    const dataSet = [
      {
        value: 34,
        total: 100
      },
      {
        value: 21,
        total: 100
      },
      {
        value: 353,
        total: 520
      },
      {
        value: 35,
        total: 340
      }
    ];
    
    // Append SVG element to body
    const svg = d3.selectAll('#container li')
      .append('svg')
      .attr('height', height)
      .attr('width', width)
      .attr('class', 'rings');
    
    // Append a bunch of circle elements based on number of items in the dataSet and set attributes
    const rings = svg.selectAll('circle')
      .data(dataSet)
      .enter()
      .append('circle')
      .attr('cx', width/2)
      .attr('cy', height/2)
      .attr('fill', 'none')
      .attr('class', 'ring');
    
    // Build the initial state of the rings
    rings.each(function(d, i) {
      const element = this;
      const radius = maxRadius - (gap * i);
      // Calculates the circumference of the circle
      const length = Math.PI * (radius * 2);
      // Calculate the percentage of the data.value over data.total
      const value = (d.value/d.total) * length;
      
      // Animates the stroke depending on the percentage calculated
      d3.select(element)
        .attr('r', radius)
        .attr('stroke-dasharray', length)
        .attr('stroke-dashoffset', length)
        .transition()
        .duration(2000)
        .attr('stroke-dashoffset', value);
    });
    
    function rotate(element) {
      // Randomiser to set the direction of the rotation
      const s = (Math.floor(Math.random() * 11) % 2 === 0 ? '-' : '');
      // Initial position of rings
      element.transform('r0, ' + width/2 + ',' + height/2);
      // Randomised rotation animation which recursively calls itself as a callback
      element.animate({ transform: 'r' + s + '360, ' + width/2 + ',' + height/2 }, 
       (Math.random() * 1000) + 2000, 
       mina.linear, () => rotate(element));
    };
    
    // Rotating animation using Snap.svg
    rings.each(function() { 
      const element = this;
      // Start the animation
      rotate(Snap(element));
    })
    }());
    </script>
    
    </body>
    </html>
    

    coothead


    #7

    This is working also. Thank you very much :slight_smile:

    So I see that you changed the location for the svg

    // Append SVG element to body
    const svg = d3.select('#container li')
    

    And then added a copy of the original svg to each li.

    I tried to create #container2 and ran into trouble (no animation displayed).

    // Append SVG element to body
    const svg = d3.select('#container', '#container2')
    

    But it is working well now with each <li> animated. This is exactly what I was going after. Thank you so much!


    #8

    No that would not have worked. :wonky:

    I actually used …

    const svg = d3.selectAll('#container li')
    

    coothead


    #9

    Ah, I see. I need to learn more D3.js
    Thanks for your help.