What is the best way to display circles (generated from JSON data) in reverse order by incorporating a delay function?

I am currently working on creating an interactive visualization using circles that expand over a specified period, all centered at the same point.

I have a script that generates these circles and saves the data in a JSON file. The smallest circle is positioned at the top of the image linked above.

Take a look at the code snippet below. Essentially, the script appends circle data to an SVG element with visibility initially set to hidden. Subsequently, the circles are revealed one by one.

While attempting to append the circles, I experimented with the .lower() function to reverse their order as per the JSON file. If appended in the original order, each subsequent circle would overlay the previous ones. However, this resulted in the animation plotting in reverse where the larger circle appeared first.

Further, I tried including a similar '.lower()' function in the transition method within the reveal function to display each circle behind the previously revealed one, but this caused the code to malfunction. Any guidance here would be greatly appreciated.

html,
body,
#svg {
  background-color: #FFFFFF;
}
<html>

<head>
  <meta charset="utf-8" />
  <title>Visualizer</title>
</head>

<body>
  <div>
    <button onclick="plotStatically(0, 0, 'testingcircle.json')">Draw Static &#9658;</button>

    <button onclick="plotConsecutively(0, 0, 'testingcircle.json')">Draw Dynamic &#9658;</button>
  </div>


  <script src="https://d3js.org/d3.v5.min.js" charset="utf-8"></script>

  <script>
    function plotConsecutively(x, y, nameFile) {

      d3.json(nameFile).then(function(data) {

        var svgHeight = window.innerHeight - 100;
        var svgWidth = window.innerWidth - 10;

        var svg = d3.select('body').append('svg')
          .attr('width', svgWidth)
          .attr('height', svgHeight);

        svg.selectAll("circle")
          .data(data)
          .enter()
          .append('circle')
          .attr('r', function(d) {
            return d.r;
          })
          .attr('cx', function(d) {
            return d.cx + x;
          })
          .attr('cy', function(d) {
            return d.cy + y;
          })
          .attr('fill', function(d) {
            return d.fill;
          })
          .attr('visibility', 'hidden')

        svg.selectAll("circle")
          .transition()
          .delay(function(d, i) {
            return 3.4 * i;
          })
          .duration(10)
          .attr('visibility', 'visible');
      })
    }


    function plotStatically(x, y, nameFile) {

      d3.json(nameFile).then(function(data) {

        var svgHeight = window.innerHeight - 100;
        var svgWidth = window.innerWidth - 10;

        var svg = d3.select('body').append('svg')
          .attr('width', svgWidth)
          .attr('height', svgHeight);

        svg.selectAll("circle")
          .data(data)
          .enter()
          .append('circle')
          .attr('r', function(d) {
            return d.r;
          })
          .attr('cx', function(d) {
            return d.cx;
          })
          .attr('cy', function(d) {
            return d.cy;
          })
          .attr('fill', function(d) {
            return d.fill;
          });
      })
    }
  </script>


</body>

</html>

Answer №1

It seems like you were almost there.

One key point to remember is to append the larger circles to the SVG first, so they don't cover up the smaller circles below them. A simple way to achieve this is by reversing the order of the data array right after retrieving results from the JSON file:

d3.json(nameFile).then(function(data) {

  data = data.reverse();
  ...

To display the circles from inside out, adjust the delay function to assign the shortest delay to the items at the end of the array (smaller circles) and the longest delay to the items at the beginning of the array (larger circles).

The third argument in the delay() function is the NodesList containing all selected DOM elements, allowing you to use the length property for your calculations.

...
.delay(function(d, i, circleNodes) {
  return 3.4 * ((circleNodes.length - 1) - i);
})
...

let data = [
  {"r":5,"cx":100,"cy":100,"fill":"red"},       {"r":10,"cx":100,"cy":100,"fill":"magenta"},{"r":15,"cx":100,"cy":100,"fill":"orange"},{"r":20,"cx":100,"cy":100,"fill":"green"},{"r":25,"cx":100,"cy":100,"fill":"blue"}
];

data = data.reverse();

function plotConsecutively() {

    var svg = d3.select('#svg')
      .append('svg')
      .attr('width', 200)
      .attr('height', 200);

    svg.selectAll("circle")
      .data(data)
      .enter()
      .append('circle')
      .attr('r', function(d) {
        return d.r;
      })
      .attr('cx', function(d) {
        return d.cx;
      })
      .attr('cy', function(d) {
        return d.cy;
      })
      .attr('fill', function(d) {
        return d.fill;
      })
      .attr('visibility', 'hidden')

    svg.selectAll('circle')
      .transition()
      .delay(function(d, i, nodes) {
        return 150 * ((nodes.length - 1) - i);
      })
      .duration(10)
      .attr('visibility', 'visible');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

<button onclick="plotConsecutively()">Draw Dynamic &#9658;</button>

<div id="svg"></div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the solution for the error "Firebase limitToLast is undefined"?

How can I restrict the number of items returned when watching the 'value' in my Firebase database? I keep getting an undefined error when using orderByChild on my Firebase reference. $scope.watchRef = new Firebase(ActiveFirebase.getBaseURL() ...

Is there a way to call a Vue function from an onclick event in JavaScript?

Creating a vue component and trying to call a function defined in Vue methods using the onClick attribute when modifying innerHTML is resulting in an error message stating "showModal is not defined". Here is the showModal function where I'm simply try ...

Navigate to a specific section in an Accordion with the help of jQuery

I currently have 2 pages: page1.html, which contains a series of links, and page2.html, where an Accordion is located. The Query: I'm wondering if it's feasible to link directly to a specific section within the Accordion. For instance, if I want ...

Click to Resize Window with the Same Dimensions

I have a link on my website that opens a floating window containing more links when clicked. <a href='javascript:void(0);' onclick='window.open("http://mylink.html","ZenPad","width=150, height=900");' target='ZenPad'>&l ...

Ways to stop a ng-click event on a child div controller from activating an ng-click in the parent controller?

http://plnkr.co/edit/gB7MtVOOHH0FBJYa6P8t?p=preview The example above demonstrates a parent-child controller setup. In the child controller, when a button is clicked, it displays the div showPop and emits an event to the $rootScope. Upon receiving this e ...

Executing JavaScript code within an AJAX request

Having a problem with an AJAX function that I need help solving: PAGE A represents the main page. PAGE X represents the content loaded via AJAX. RES A represents the results from PAGE A. RES B represents the new results loaded via AJAX. PAGE A initially ...

The BottomNavigation component in MUI has a minimum size limit of 400px when it displays 5 items

My issue involves a bottom navigation bar with 5 elements. When the window is resized to less than 400px, the bottom navigation does not shrink, instead maintaining a minimum width of 400px and causing a scrollbar to appear on the x-axis. You can view a m ...

Troubleshooting HTML Output Display Issues

I've been trying to post my content exactly as I submit it, but for some reason, it's not working. When I enter two paragraphs in a post, the output doesn't maintain that formatting. Instead, it removes the paragraph breaks and displays the ...

Animating a background image to slide in from the bottom to the top using CSS transition

Here is a link to a codepen example: https://codepen.io/jon424/pen/XWzGNLe The current effect in this example involves covering an image with a white square, moving from top to bottom when the "toggle" button is clicked. I am interested in reversing this ...

Export web application content to PDF through rendering on the server side

Our interactive web application, which includes multiple d3 charts, is built with vue. Currently, I am able to export our webpage to a PDF file by utilizing canvg and html2canvas to convert the content into PNG format. The PNG file is then transmitted to t ...

How to create a clickable link using Vuetify's v-btn component

As a newcomer to vue and vuetify, I would greatly appreciate some explanation and examples. My goal is to create a button that directs users to an external site, like youtube.com. Below is the code I currently have, but unfortunately it's not function ...

What is the best way to determine the count of elements in an array that have the active property set to true?

Can anyone help me figure out the most efficient way to solve this problem? (Filter, ng-repeat, or another method?) <div>Number of active items: {{product.length}} </div> //total number of items <div>Number of inactive items: {{product.l ...

Implementing a JQuery modal with backend coding

I have encountered a problem in my ASP.NET code-behind where I am trying to incorporate a modal popup. Despite my efforts, I have not been able to successfully implement it. Do you have any suggestions on how I should proceed with this process? <scrip ...

Changing the Div heights in Material UI with grid layout customization

I have a project that requires me to implement material-ui. Is there a way I can adjust the width and height of the div containing the "Sign In With" text (as shown in the first image) to bring the buttons closer to the text? Transformation from this: ht ...

What is the process for incorporating ejs into the source attribute of an image element?

Code Snippet: <img class="card-img-top" alt="..."><%= articles.image %><img> Server Setup: const express = require('express') const app = express() const router = require('./routes/article') app ...

Using Gson for multiple serialized names with the same data type

I am facing a challenge with my class: public void results{ @SerializedName("object1") @Expose private Object1 object1; @SerializedName("object2") @Expose private Object2 object2; @SerializedName("object3") @Expose private Object3 object3; @Serialized ...

main.js:1 ERROR TypeError: Unable to access property 'querySelectorAll' of null

I am currently using Chartist in conjunction with Angular to generate charts. However, I am encountering a problem where the charts do not display when the server is running, and an error appears on the console. Strangely enough, refreshing the page caus ...

The initial click event for the input element in Jquery is not functioning correctly

I found a jQuery date selector online and the script looked something like this... <script type="text/javascript> $(document).ready(function () { $("#date3").click(function() { $("#date3").scroller({ preset: 'datetime' }); wheels = []; whe ...

Eliminate the escape character ' ' from dynamic JSON by utilizing ExpandoObject and IDictionary

I have been working on generating a dynamic JSON using ExpandoObject and IDictionary. Here is an example of my code: DataTable dt_MappedColumns = new DataTable(); dt_MappedColumns.Columns.Add("Sr.No"); dt_MappedColumns.Columns.Add("TColumnName"); ...

When a link is clicked, submit a form and send it to several email addresses simultaneously

My form has been styled using the uniform jQuery plugin. Instead of using an input type submit for submitting the form, I have utilized a link and added some effects to it to prevent it from being formatted with uniform. <form> <ul> ...