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

Utilize only certain JSON properties within JavaScript

I have access to an array of JSON objects. [ { Id: "1", StartNo: "1", ChipNo: "0", CategoryId: "0", Wave: "0", Club: "", FirstName: "Lotta", LastName: "Svenström", FullName: "Lotta Svenström", ZipCode: "24231" }, {...} ] My goal is to create a new data ...

Utilizing Jquery to automatically scroll to a specific div on page load by setting an

I am attempting to automatically scroll to the div specified in the URL. The URL may include one of 21 different IDs such as: url.com/test#lite1 url.com/test#lite2 url.com/test#lite3 This scrolling action should happen when the page loads (so that user ...

Prevent ESLint from linting files with non-standard extensions

My .estintrc.yaml: parser: "@typescript-eslint/parser" parserOptions: sourceType: module project: tsconfig.json tsconfigRootDir: ./ env: es6: true browser: true node: true mocha: true plugins: - "@typescript-eslint" D ...

Achieve the central element while scrolling on the window

What am I doing wrong? I've been attempting to target the #second element on scroll Here is an example with console.log CODEPEN EXAMPLE $(window).scroll(function(){ var section = $("#second").offset().left, scrollXpos = $( ...

Parsley JS - Personalized Validation for Ensuring selected Items meet Minimum Value Requirements

Is it possible to validate a form so that at least 5 select boxes are set to Yes? If there are fewer than 5, the form should not submit and display an error message. I believe a custom validator is needed for this task. To see a complete example, check ou ...

Building a DOM element using jQuery

I have a function $(document).ready(function () { $("#btnhighlight").click(function () { var htext = $("#txthighlighttext").val(); $("#lstCodelist option").each(function () { var sp = $(this).text(); ...

Remove any instances of null from an array

I am facing an issue while sending an object with JSON. When I iterate through the object using a for loop, the JSON sent is correct but there are null values in the array. I suspect that the problem lies in the myValue.children[index]= item; assignment. I ...

Use vue.js to add a block of content after every sixth iteration in a loop

Currently, I have a list of offer cards rendering through a loop. I am adding a row div every 3rd column (bootstrap) element. Now, I need to also add another column element (banner block) for every 6th element in order to achieve a layout like the one show ...

The challenge of Cross-Origin Resource Sharing with AjaxSubmit compared to a traditional Ajax request

My dilemma involves two applications interacting on Google's App Engine, each operating within its own domain. To enable communication between them, I have successfully implemented CORS in Python using the following code: self.response.headers.add_he ...

"Retrieve real-time information from the server directly on the client side

Within my express router, I validate the data submitted on a form and then render another page if the data is valid, passing along the form data. My goal is to be able to access this passed data on the client-side. In the chat.ejs view, I have a chatroom.j ...

Expandable Grid Sections in React MUI

Is there a way to create a grid layout where items with showDefault: true are always displayed at the top, and then users can click an arrow button to expand the grid and also show the items with showDefault: false? Any suggestions on how to achieve this? ...

I'm currently working on incorporating an edit feature into the create form by utilizing server actions in the latest version of Next.js, version 14

The issue arises when the create form's type (id) parameter is null, which does not align with prisma's (edit info). export function AboutForm({ id }: { id: number }) { const router = useRouter(); const [err, setErr] = useState("&qu ...

Learning to parse a JSON file in Java

I need assistance with reading a Json file. The content of my Json File is as follows: [ { "arguments" : [ { "IsEnabled" : "false", "class" : "UITextField", "width" : 238, "parent" : { "class" : "UIVie ...

How can I access the data variables from a JSON request within a function?

My task involves loading multiple JSON files from an array called bunchOfData, with each file having a corresponding URL. How can I access my variable "myI" within the processData function? for(var i = 0; i < bunchOfData.length; i++){ $.getJS ...

Extracting text from an HTML file and passing it to an Express.js server: A beginner

Currently, I'm attempting to retrieve the values from an HTML text field and store them in variables. I require HTML to capture these values and return the response within the .html file. HTML: <body> <form> ...

Incorporating JSON data seamlessly into a visually appealing Highcharts pie chart

It seems like I'm facing a minor issue here. Everything was working fine until... $(document).ready(function() { // Original data var data = [{ "name": "Tokyo", "y": 3.0 }, { "name": "NewYork", "y": 2.0 }, { "name": "Berlin", ...

Revamping Legacy React Native Projects with the Redux Toolkit

Is there a way to integrate redux toolkit with the existing store, reducer, and dispatch methods in my project without creating new ones? I am looking to update react-redux to the latest version. Please provide guidance and assistance. store.js ` import ...

jqGrid display/hide columns options dialogue box

I am looking to implement a feature that allows users to toggle columns in my jqGrid. I came across a module for this purpose, but unfortunately, it is no longer supported in jqGrid 4.x. I have searched for a replacement module without success. Are there ...

What steps need to be taken to set up Node.js to accommodate requests from external sources beyond just localhost?

After creating an application using NextJs, I successfully built it and ran it on a node server by executing 'npm run start' in Powershell. Everything works perfectly when accessing it locally through port 80. However, my Windows Server 2019 does ...

Having trouble with creating a new Next.js app using the latest version with npx?

Having some difficulty with the "npx create-next-app@latest" command while setting up Next.js. As a newcomer to both the community and Next.js, I could use some assistance in resolving this problem. Upon running the command, an unfamiliar message was displ ...