How can we manage JSON data in chunks during a progress event?

My dilemma involves dealing with a server request that may bring back a substantial JSON list (around 100K records, approximately 50 Mb) of points to be presented on a canvas using D3js. To ensure interactivity and save memory, I am keen on rendering them as they stream in. Here's what I've done so far:

Firstly, I activated Chunked transfer encoding at the server end + Additionally, this is what I experimented with on the client side:

d3.json('?json=qDefects&operationid=' + opid) // my request 
  .on("load", function (json) {
    draw(json); // although it works, there's a significant delay that I want to eliminate...
  })
  .on("progress", function (json) {
   draw(json); // unfortunately, this fails: json isn't accessible at this point
  })
 .get();

I'm curious if there's a way to manage the JSON data in portions as it loads. Would restructuring the JSON data be beneficial? Currently, it's a single array setup like this:

[{"x":1, "y":2},{"x":2, "y":3}, // chunk 1
...
{"x":6845, "y":239426},{"x":51235, "y":234762}] // last chunk

Do you think splitting the points into smaller arrays would be advantageous?

Answer №1

Check out the provided fiddle: http://jsfiddle.net/Q5Jag/12412/

Although it is true that you cannot modify the progress event directly, a simple workaround is to use an external variable. By implementing the code below, you can reprocess the string and send it to d3:

var x = ''
d3.json("https://api.myjson.com/bins/1d7yoi")
  .on("progress", function(d) {
    x = d.responseText
    x = "ehllo" + x;
    console.log(x)
  })
  .on("load", function() {
    console.log("done")
  })
  .get()

You have the flexibility to assign responseText to the variable x and manipulate x according to your requirements.

Answer №2

After considering the suggestions from earlier responses, I have come up with the following solution:

function loadProgress(callback) {
  let start = 0;
  return function (event) {
    let str = event.responseText.substr(start); 
    let i = str.indexOf("{");                  
    let j = str.lastIndexOf("}");
    str = "[" + str.substr(i, j) + "]";
    let data = JSON.parse(str);
    callback(data);
    start = start + j + 1;
  }
}

d3.json('?json=qDefects&operationid=' + opid)
  .on("progress", loadProgress(draw));

This setup works effectively for my situation where there are no nested {}. I have ensured that the server provides chunks corresponding to each record of my request, resulting in matching {} in the responseText.

Although this approach still generates a lengthy and potentially unnecessary responseText, as well as an extra json parse step, I am able to manage it at the moment.

Answer №3

In short: The JSON cannot be manipulated using the progress event.


To begin with, it is likely that you are using d3.request (D3 v3 and v4) instead of d3.fetch (D3 v5). It is important to note this distinction because both micro libraries have a method with the same name, d3.json. However, in the former, d3.json is an XMLHttpRequest while in the latter, it is a Promise.

More importantly, this appears to be (unfortunately) an XY problem. You mentioned wanting to "draw them as they arrive in order to favor interactivity and spare memory," but the issue is that even if you could manipulate the data as it arrives (which you cannot, as explained below), D3 will only start rendering after the XHR or Promise has finished downloading the data. This means that with 50MB of data, the user would face a blank page for several seconds. Therefore, it might be beneficial to reconsider the size of the data file and the overall data visualization approach.

Regarding your initial question:

The progress event is primarily used for monitoring progress. As per the W3 Consortium:

This specification defines an event interface — ProgressEvent — that can be used for measuring progress. (emphasis mine)

We can confirm this through the following example (using an array containing the objects you provided repeated multiple times). While we can access the loaded JSON using srcElement.response, it is not possible to modify it:

d3.json("https://api.myjson.com/bins/1d7yoi")
  .on("progress", function(d) {
    console.log(d.srcElement.response)
  })
  .on("load", function() {
    console.log("done")
  })
  .get()
<script src="https://d3js.org/d3.v4.min.js"></script>

For instance, in this attempt to modify the string within the progress event, no changes occur:

d3.json("https://api.myjson.com/bins/1d7yoi")
  .on("progress", function(d) {
    d.srcElement.response[0] = "foo";
    console.log("First character is: " + d.srcElement.response[0])
  })
  .on("load", function(data) {
    console.log("JSON:" + JSON.stringify(data))
  })
  .get()
<script src="https://d3js.org/d3.v4.min.js"></script>

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

How jQuery stops the submission of a form

Sample HTML Code <p><select name="status" class="form-control" id="showThisItem"> <option value=""> Select Status </option> <option value="Paid"> Paid </option> <option value="Unpa ...

Troubleshooting Android: Issues with Data Integration in MySQL Database Without any Error Notifications

I've been working on implementing a login/register feature for an app I'm developing (Just to clarify, this app is currently for personal use only, so I'm not focusing on making the passwords extremely secure at this stage). However, when I ...

Glitches and sudden jumps occur when using the useMediaQuery function in Material UI

Implementing Material UI's useMediaQuery() hook, I have embedded the theme provider and initialized a variable in this way: const theme = useTheme(); const isSmall = useMediaQuery(theme.breakpoints.down('sm') ); I am utilizing the isSmall v ...

Obtaining template attributes in CKEditor: A guide

I have been working with the template plugin in CKEditor to load predefined templates. Each template is defined as follows: templates: [ { title: "Quickclick 1", image: "template1.png", description: "Quickclick 1 template", html_et: "& ...

How to toggle the visibility of an element in an array using AngularJS and JavaScript

Is there a way to show additional information when an item in ng-repeat is clicked, and then hide this extra info when the mouse leaves that same item? One issue I am facing with the code snippet below is that when a user clicks on a different item, it al ...

Base64 Encoded Key for Implementing CURL Rest API

I have been trying to establish an integration with a REST API that requires a Base64 encoded key for authentication, but I am facing difficulties in getting it to work. When attempting to connect, the API only responds with the following error message: ...

Having trouble with implementing the .addclass function in a dice roller project

I'm looking to have the element with id=die load initially, and then on a button click event labeled "click me," apply the corresponding CSS class such as 'die1,' 'die2,' and so forth. function roll() { var die = Math.floor(Ma ...

Maximizing the potential of NestJS apps with Docker

I am working on a NestJS project that consists of multiple apps structured as follows: my-project: -- apps; --- app-one ---- src ---- tsconfig.app.json --- app-two ---- src ---- tsconfig.app.json -- libs -- package.json -- etc... Within this project, I ha ...

Managing two separate instances with swiper.js

Currently, I have set up two instances of swiper.js and I am looking to scroll both while interacting with just one of them. Update: My primary objective is to replicate the core functionality seen on the swiper homepage. Update 2: I came across this lin ...

Using jQuery to deactivate buttons upon submission or clicking within forms and hyperlinks

Within my Rails application, there are buttons that send data to the server. Some of these buttons are part of a form while others are standalone. I am seeking a solution to implement my jQuery code, which disables the buttons upon click, for both scenario ...

Automatically preselect the checkbox inputs with the API and update their status when they are interacted with

Hello fellow developer, I trust you are doing well. I am looking to have the checkboxes automatically checked based on data from the API and update their status when interacted with. I've tried different approaches but haven't found the right sol ...

Troubleshooting a Messaging Error between Background and Another Script

Attempting to transfer selected text from the current page to an HTML page using message passing: content script to background script, then background script to the HTML page. However, encountering errors if the HTML page is not already open, and even gett ...

Theme.breakpoints.down not being acknowledged by MUI breakpoints

The Challenge: Implement a hamburger menu to replace the navMenu on tablet and smaller screens After successfully compiling in VS code terminal, encountering an error in the browser: Error Message: TypeError: Cannot read properties of undefined (reading ...

Exploring the possibilities of node-webkit: node-odbc encounters a setback

Currently, I'm in the process of developing a desktop application utilizing node-webkit. The main functionality of the app involves querying an Oracle database. To establish the connection with the database, I have integrated node-odbc. To ensure tha ...

Is there no "on" function available in the Node readline module?

I am currently working on building a Node.js application that reads a text file line by line using the 'readline' module and displays it in the console. var lineReader = require('readline'); lineReader.createInterface({ input: fs.cre ...

Is it possible to manipulate the attribute of an object using Object.defineProperty when a value is passed as a function parameter?

As I delve into understanding reactivity in Vue, the concept of how reactivity is achieved when passing a value as a function parameter perplexes me. //here is the actual code snippet var obj = {a: 'aa'} function reactive(obj, key, value) { ...

Accessing a specific item from a detailed JSON structure using PHP

Currently, I am working on creating a trading bot and one of the key steps is obtaining the current market value for a specific cryptocurrency. I am specifically looking to extract the "Last" nested parameter from this JSON array: array(3) { ["success"]= ...

Is this loader going through a triple loop?

<style> .loader { position: fixed; left: 0px; top: 0px; width: 100%; height: 100%; z-index: 9999; background-repeat: no-repeat; background: url('images/page-loader.gif'); } </style> <script src="//ajax.googleapis.com/ajax/libs/jque ...

Numerous Google Gauges featuring varying sets of options

Currently, I am facing a challenge involving the insertion of multiple instances of Google Gauges (or Highchart Gauges) on a single page. The goal is to utilize different option sets and separate their placement accordingly. Unfortunately, the solution pro ...

Tips for inserting Weather Underground forecast icons

I am new to Python programming and I am attempting to display weather icons from the Weather Underground forecast. However, the icon is not showing in the labelimg1 line without giving any errors. Can someone assist me with this? Below is a snippet of the ...