We need to display 5 millions of dots (or very simple graphics objects) on a screen at the same time and we want to interact with each of the dots (e.g., change their colors or drag/drop them).
To achieve this, we usually run a for-loop through 5 millions items in the worst case O(N) to access and change the states of the dot, according to the mouse coordinates (x, y). Due to the huge number of the objects, this approach causes lots of overhead (we have to run the for-loop of five millions whenever a user selects a dot). I have already tested this approach but it was almost impossible to make an interactive tool with this. Is there anyway to rapidly and efficiently access the dots without running the million for-loop and causing this performance problem?
You really haven’t given many details
These questions quickly come to mind:
With this lack of specificity in mind...
...Divide and conquer:
Divide your dot array into multiple parts
This will allow you to examine far fewer array elements when searching for the 1 you need.
Create a container object with 1980 elements representing the 1980 “x” coordinates on the screen.
var container={};
for(var x=1;x<=1980;x++){
container[x]=[];
}
Each container element is an array of dot objects with their dot centers on that x-coordinate.
Every dot object has enough info to locate and redraw itself.
A dot at x-coordinate == 125 might be defined like this:
{x:125,y:100,r:2,color:"red",canvas:1};
When you want to add a dot, push a dot object to the appropriate "x" element of the container object.
// add a dot with x screen coordinate == 952
container[952].push({x:952,y:100,r:2,color:"red",canvas:1});
Dots can be drawn based on the dot objects:
function drawDot(dot,context){
context.beginPath();
context.fillStyle=dot.color;
context.arc(dot.x,dot.y,dot.r,0,PI2,false);
context.closePath();
context.fill();
}
When the user selects a dot, you can find it quickly by pulling the few container elements around the X where the user clicked:
function getDotsNearX(x,radius){
// pull arrays from "x" plus/minus "radius"
var dotArrays=[]
for(var i=x-radius;i<=x+radius;i++){
dotArrays.push(container[i]);
}
return(dotArray);
}
Now you can process the dots in these highly targeted arrays instead of all 5 million array elements.
When the user moves a dot to a new position, just pull the dot object out of its current container element and push it into the appropriate new "x" container element.
Divide your dots onto multiple overlaying canvases
To improve drawing performance, you will want to disburse your dots across multiple canvas overlayed on each other.
The dot element includes a canvas property to identify on which canvas this dot will be drawn.