Last active
March 20, 2018 11:44
-
-
Save thinkbigthings/1c5a47575c55f2f7004da60a633edf38 to your computer and use it in GitHub Desktop.
plot lots of points on a canvas using real-to-screen coordinate transformation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<body> | |
<canvas id="myCanvas" width="1000" height="500" style="border:1px solid #000000;"> | |
Your browser does not support the HTML5 canvas tag. | |
</canvas> | |
<script> | |
// experiment with big data sets (1M seems ok) | |
const data = Array(500000); | |
for(let i=0; i<data.length; i++) { | |
// data[i] = { x:i, y:Math.random()*50 - 25}; | |
data[i] = { x:i*2*3.1416/data.length, y:Math.sin(i*2*3.1416/data.length)}; | |
} | |
// Math.max overflows if array is too big, use reduce instead | |
const fastMin = (array) => array.reduce( (a,b) => (a < b) ? a : b ); | |
const fastMax = (array) => array.reduce( (a,b) => (a > b) ? a : b ); | |
let domain = data.map(p => p.x); | |
let range = data.map(p => p.y); | |
// real coordinates | |
let r={ | |
xmin:fastMin(domain), | |
xmax:fastMax(domain), | |
ymin:fastMin(range), | |
ymax:fastMax(range) | |
}; | |
// screen coordinates | |
let s={ | |
ymin:0, | |
xmin:0, | |
xmax:1000, | |
ymax:500 | |
}; | |
// TODO unit test the equation, but I think this is right | |
// TODO Can save my ideas in an account in codepen | |
let xscale = (s.xmax-s.xmin)/(r.xmax-r.xmin); | |
let yscale = (s.ymax-s.ymin)/(r.ymax-r.ymin); | |
const toScreenX = (x) => ( x-r.xmin)*xscale; | |
const toScreenY = (y) => (-y-r.ymin)*yscale; | |
const realToScreen = function(p, callback) { | |
callback( toScreenX(p.x), toScreenY(p.y) ); | |
} | |
const c = document.getElementById("myCanvas"); | |
const ctx = c.getContext("2d"); | |
const plot = (x,y) => ctx.fillRect(x, y, 1, 1); | |
// terms: clipping, viewport, real/world coordinates, screen coordinates, grouping | |
// TODO mouse move/drag interaction | |
// TODO use a viewport for clipping | |
// TODO use grouping to reduce number of points to render | |
// TODO write as a react component | |
const start = new Date().getTime(); | |
// reset entire canvas with bg color | |
ctx.fillStyle="#FFFFFF"; | |
ctx.fillRect(0,0,1000,500); | |
// draw the points | |
ctx.fillStyle="#BBBBFF"; | |
data.forEach(p => realToScreen(p, plot)); | |
const finish = new Date().getTime(); | |
console.log(finish - start); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment