var N = 1000
const dim = {
width: 1024,
height: 768
}
var ctxs = []
const SZ = 4
const SZ2 = 2 * SZ
const TWO_PI = 2 * Math.PI
for (let i = 0; i < 6; i++) {
const canvas = document.createElement("canvas")
Object.assign(canvas, dim)
ctxs.push(canvas.getContext("2d"))
}
function randXY() {
const x = dim.width * Math.random()|0
const y = dim.height * Math.random()|0
return [x, y]
}
/*
* Square stuff
*/
function drawSquare() {
ctxs[0].rect(randXY(), SZ2, SZ2)
}
const buffer = document.createElement("canvas")
buffer.width = SZ2
buffer.height = 2 * SZ2
const bufferCtx = buffer.getContext("2d")
bufferCtx.fillRect(0, 0, SZ2, SZ2)
function drawImageSquare() {
ctxs[1].drawImage(buffer, 0, 0, SZ2, SZ2, randXY(), SZ2, SZ2)
}
const imageDataSquare = bufferCtx.getImageData(0, 0, SZ2, SZ2)
function putImageDataSquare() {
ctxs[2].putImageData(imageDataSquare, randXY())
}
/*
* Circle stuff
*/
function drawCircle() {
const ctx = ctxs[3]
ctx.arc(randXY(), SZ, 0, TWO_PI)
ctx.closePath()
}
// draw a circle onto the buffer, below the square
bufferCtx.beginPath()
bufferCtx.arc(SZ2, 1.5*SZ2, SZ, 0, TWO_PI)
bufferCtx.closePath()
bufferCtx.fill()
function drawImageCircle() {
ctxs[4].drawImage(buffer, 0, SZ2, SZ2, SZ2, randXY(), SZ2, SZ2)
}
const imageDataCircle = bufferCtx.getImageData(0, SZ2, SZ2, SZ2)
function putImageDataCircle() {
ctxs[5].putImageData(imageDataCircle, randXY())
}
function doMany(func) {
for (let i = 0; i < N; i++) {
func()
}
}
ctxs[0].beginPath()
doMany(drawSquare)
ctxs[0].fill()
ctxs[1].beginPath()
doMany(drawCircle)
ctxs[1].fill()
doMany(drawImageSquare)
doMany(drawImageCircle)
doMany(putImageDataSquare)
doMany(putImageDataCircle)
--enable-precise-memory-info
flag.
Test case name | Result |
---|---|
draw squares | |
draw circles | |
drawImage squares | |
drawImage circles | |
putImageData squares | |
putImageData circles |
Test name | Executions per second |
---|---|
draw squares | 554.2 Ops/sec |
draw circles | 300.6 Ops/sec |
drawImage squares | 78.9 Ops/sec |
drawImage circles | 84.1 Ops/sec |
putImageData squares | 4.2 Ops/sec |
putImageData circles | 5.8 Ops/sec |
Measuring performance of JavaScript microbenchmarks is crucial for developers, and MeasureThat.net provides a valuable platform to compare different approaches.
Benchmark Definition
The provided JSON represents the benchmark definition for measuring the performance of drawing sprites (filled circles and squares) using various canvas methods. The benchmark consists of six test cases:
draw squares
: Drawing multiple squares using path drawing methods.draw circles
: Drawing multiple circles using the arc method.drawImage squares
: Drawing multiple squares by copying them from a buffer using the drawImage
method.drawImage circles
: Drawing multiple circles by copying them from a buffer using the drawImage
method.putImageData squares
: Drawing multiple squares by copying pixel data from a buffer using the putImageData
method.putImageData circles
: Drawing multiple circles by copying pixel data from a buffer using the putImageData
method.Options Compared
The benchmark compares different approaches for drawing sprites, which can significantly impact performance:
draw squares
): This approach involves using the canvas's path API to draw shapes. It is generally faster than other methods but may require more memory.draw circles
): This approach uses the arc
method to draw circles, which can be slower than path drawing methods due to its iterative nature.Performance Implications
The benchmark results show varying performance across different browsers and devices:
draw squares
and draw circles
have similar performance, with Opera 82 performing better than Chrome 96.drawImage squares
and drawImage circles
have slower performance compared to path drawing methods, but still faster than pixel data manipulation.putImageData squares
and putImageData circles
have the slowest performance, indicating that copying and manipulating pixel data is not an efficient approach.Conclusion
The benchmark highlights the importance of choosing the right approach for drawing sprites in JavaScript. Path drawing methods and the arc method tend to be faster than copy-and-paste approaches, while pixel data manipulation is generally slower. Developers should consider these factors when optimizing their performance-critical code.