score:2
instead of trying to create threads and artificial breaks you could speed up your code by precalculation an image data array. you code so far has two flaws:
- you draw every single pixel individualy
- you redraw pixels that are already there
because of the sheer number of data points, those two flaws can add up really quickly. when you run your original fiddle you see that after just a second, the picture doesn't change anymore but you are still drawing pixels over the same area for maybe 20 further seconds. so here is an example of how can do it with the putimagedata()
function:
function createpicturearray() {
var res, i, max_i;
var canvasel = d3.select('#test').node();
var ctx = canvasel.getcontext('2d');
var data;
res = ctx.getimagedata(0, 0, width, height);
data = res.data;
for (i = 0, max_i = data.length; i < max_i; i++) {
data[i] = 255;
}
return res;
}
function generatedata(size) {
var i, x, y, s, res, data, randomx, randomy;
randomx = d3.random.normal(width/2 , 80);
randomy = d3.random.normal(height/2, 80);
res = createpicturearray();
data = res.data;
for (i = 0; i < size; i++) {
x = parseint(randomx());
y = parseint(randomy());
s = 4 * y * width + 4 * x;
if (data.length > s && data[s + 1] !== 0) {
data[s + 1] = 0;
data[s + 2] = 0;
}
}
return res;
}
function main() {
var canvasel = d3.select('#test').node();
var ctx = canvasel.getcontext('2d');
width = canvasel.width;
height = canvasel.height;
data = generatedata(2000000);
ctx.putimagedata(data, 0, 0);
}
main()
this example creates 2 million data points but feel free to increase it to 20 million. on my machine it took about 7 seconds. so there is still room for optimization but at least i didn't experienced severe freezing.
what happens is that you create your random numbers one after the other and for each number pair you calculate the correct pixel inside the image data array and you set that pixel to red if it has not already been set red.
score:1
both javascript and ui updates such as redraws and reflows run in a single "browser ui thread". the browser ui thread works on a queuing system where tasks are kept until the process is idle. once idle, the next task in the queue is retrieved and executed.
techniques like settimeout() and requestanimationframe defer execution of your task and allow some breathing space for the ui to update, but when those tasks are eventually run, it's still one at a time, not concurrently. thus any such task will always block the execution of any other.
html5 introduces web workers, which allow you to pass javascript to a separate thread, where it is executed concurrently with the ui thread. the javascript you execute within a web worker is isolated from the ui thread, and you cannot make any updates to the ui from the web worker. however a web worker would be ideal for something like your generate_data() function.
here's a great web worker tutorial and here's a browser compatibility matrix.
score:3
javascript is a single threaded system. functions that essentially create a callback like settimeout will still kill a single threaded system.
edit:
as per the comments, there are some creative ways to give the single thread javascript the illusion of executing large logic functions asynchronously, thus freeing up the process for executing things like click handlers.
@v3ss0n depending on where in your code the process freeze occurs you have a couple of options as follows:
1) process freezes during creation of the array: loading 20 mil items into an array could take a while, and i would recommend not doing this. there is more than 1 way to approach this, but i would move as much heavy looping logic as i can outside of javascript and possibly to a web-service. this has it's own challenges such as attempting to send 20 mil items back to the client, that is a bad idea. but if you can split it up into manageable groups of coordinates (20-100 max) and then make multiple web service calls as needed (using something like jquery ajax method http://api.jquery.com/jquery.ajax/) then all that your javascript has to worry about is appending the items. that will stream data to you over a period of time, so don't expect it to be instant, but should not freeze the browser if it is having difficulties looping through the coordinate creation function 20 mil time.
2) process freezes during rendering of each individual point: the fix for this is a little more creative and can also be used for the above process if you do not want to use web services. first look at the following code:
var renderingcounter = 0;
var asynctimer = null; // keep the render timer global to prevent duplicate renders from being run
function startrender(){
// test if existing async render is running
if(asynctimer != null){
// existing async timer, clear the timer and clear the canvas
clearinterval(asynctimer);
renderingcounter = 0;
// code for clearing the canvas ..
};
// create interval object
var asynctimer = setinterval(function (){
// at the begining of each start render, test if all points have been rendered
if(renderingcounter >= pointarray.length){
// kill the asynctimer
clearinterval(asynctimer);
asynctimer = null;
renderingcounter = 0; // reset the counter
return;
};
while(renderingcounter < 100){ // only draw 100 items
if(renderingcounter >= pointarray.length){ // make sure you are not out of array bounds
return;
};
// execute display code for that point
}; // loop
}, 40);
}
the above code splits up the rendering process into 100 point groups. upon completion of a group it pauses for 40 milliseconds, this should free up enough time on the main thread to allow execution for other items to continues (such as ui). the global variable renderingcounter will keep the current progress through the array. the code also has checks for current running rendering timers if the function gets re-called during rendering (in the example it kills the current rendering and resets it). if the rendering timer still causes hangs, you can increase the pause interval.
those two methods of approaching asynchronous execution should provide enough flexibility to allow rendering or data reading from server side web services (should you ever go that direction) while still keeping a fluid ui
Source: stackoverflow.com
Related Query
- How can i process huge javascript array (array of 20 mil coordinates) in browser side efficiently?
- How can I use D3.js to take an array of Javascript objects use them in a line graph?
- How can I parse csv data from a javascript array of strings for use in d3 graphs
- How can we create multi column table using multi array JSON using d3 and crossfilter javascript frameworks
- Using Javascript D3 library, how can I determine mouse position in data set of an area element on mousemove event?
- How can I convert SVG coordinates (x,y) defined relatively to an element into absolute coordinates/position?
- How to count and convert an array with specific condition javascript
- How can I draw an arc with array of points in d3 v4
- How can I run a javascript as a node.js script without the DOM?
- How to change JSON data to Javascript array of objects with D3
- How to check an array to see if a value is in there, javascript
- How can I sum an array with D3?
- How can I bind an array of objects to arcs in a D3 pie chart?
- How to reshaping Data in Javascript from array to object without losing some of the data
- How can I Loop through array to assign html to tooltip
- How to manipulate JSON objects into an array with javascript
- how to draw an array of circles in a straight line, in the bottom of the browser window
- Javascript - Can not access array elements of an array created from a csv file
- How can I access all keys and values in an array of objects without looping
- how can i use correctly the functions which have been already developed in javascript into an application in angular 4?
- In D3, how can I receive current X,Y coordinates of an element while a transition is running?
- How to map an array of objects correctly in Javascript
- How can I skip an element of an array when I perform a .data (data) in d3.js
- How can I dynamically generate javascript within a script tag using jade and express
- How can I iterate through an array over and over again while assigning each of its values to all the svgs in my DOM
- How can I get the source code from a page using javascript
- How to use a JSON file as an array of objects in Javascript
- How to convert the large bio-format file to database-like file that can be asynchronously accessed width JavaScript
- How can you update an array with knockout?
- How do I create and write to a new file (csv) and have the browser download it with javascript or D3.js?
More Query from same tag
- Coloring a map using D3.js
- 2 circles and 1 line in one data entry in d3.js
- d3.js and svg: panning while zoomed in/out doesn't work
- How can I find out what projection my pre-projected GeoJSON is using?
- dc.js Boxplots displaying values
- Tooltip with Multi-Series Line Chart in Vega-Lite API
- Do d3.js and angular.js step on each other's toes?
- How to use the D3 diagonal function to draw curved lines?
- Placement of .transition for lines in d3?
- d3.js Force Chart with zoomable/pan
- D3 Mouse Move on Two Graphs at once
- Why my d3 line chart only has two ticks on x axis?
- d3's pinch-to-zoom not working in IE/Edge?
- Incorrect text in x.ticks( ) using d3.js
- d3 enter().append() not appending all elements of my array
- D3 Table Example with Array of Arrays Yields Empty TD Tags
- JS does not work if i remove alert statement
- dynamic js with phantomjs in local html file
- D3 Chart Legend Labels getting overlapped
- D3 JS - Uncaught TypeError: Cannot read property 'length' of undefined - seems related to data issue
- Drawing a line with two different colors using D3
- D3.js contour plot not working (Possible bug of d3 contour)
- d3.js Force Diagram
- How can I add more time-series data after drawing a D3 line chart?
- D3 Time scales based only on hours and not bound to dates
- Reduce code - duplicated code appending svg images
- Why isn't my drag scaling in d3?
- How do I translate d3.js nodes?
- in d3.js how do you add and remove multiple lines on different click events?
- Retrieve part of json file from an external website (sparkfun)