{"id":7956,"date":"2026-06-01T10:49:20","date_gmt":"2026-06-01T15:49:20","guid":{"rendered":"https:\/\/justinparrtech.com\/JustinParr-Tech\/?p=7956"},"modified":"2026-06-01T13:05:35","modified_gmt":"2026-06-01T18:05:35","slug":"tales-from-the-land-of-javascript-abuse-of-fillrect","status":"publish","type":"post","link":"https:\/\/justinparrtech.com\/JustinParr-Tech\/tales-from-the-land-of-javascript-abuse-of-fillrect\/","title":{"rendered":"Tales from the Land of Javascript &#8211; Abuse of fillRect()"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-7958\" src=\"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-content\/uploads\/jsfillrect-01-banner.png\" alt=\"\" width=\"564\" height=\"66\" srcset=\"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-content\/uploads\/jsfillrect-01-banner.png 564w, https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-content\/uploads\/jsfillrect-01-banner-300x35.png 300w\" sizes=\"auto, (max-width: 564px) 100vw, 564px\" \/><\/p>\n<p>I accidentally figured out how to make compute-expensive blobs in JavaScript using fillRect().\u00a0 And&#8230;.how to fix it.<\/p>\n<p><!--more--><\/p>\n<p>&nbsp;<\/p>\n<h2>Background<\/h2>\n<p>I am a true believer in Javascript as a teaching tool, and I&#8217;ve been working on several Javascript projects lately.\u00a0 Most recently, I was using fillRect() to draw squares on a canvas, and got some QUITE unexpected results.<\/p>\n<p>In Javascript, you start with a HTML &#8220;Canvas&#8221; element, then to draw shapes, you get the &#8220;context&#8221; of that object:<\/p>\n<pre>&lt;html&gt;\r\n&lt;body&gt;\r\n&lt;canvas ID=bob WIDTH=400 HEIGHT=300&gt;&amp;nbsp;&lt;\/canvas&gt;\r\n&lt;script&gt;\r\nvar canv=document.getElementById(\"bob\");\r\nvar ctxt=canv.getContext(\"2d\");\r\nctxt.fillStyle=\"#00ff00\"; \/\/green\r\nctxt.fillRect(30,20,10,10);\r\n&lt;\/script&gt;\r\n&lt;\/body&gt;<\/pre>\n<p>The code above would roughly produce the output below:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-7959\" src=\"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-content\/uploads\/jsfillrect-02-1block.png\" alt=\"\" width=\"288\" height=\"234\" \/><\/p>\n<p>(note that the green square has a border &#8211; this has been added for visual clarity and is NOT depicted in the code)<\/p>\n<p>That all works correctly.<\/p>\n<p><strong>However, on a much larger canvas (around 900 x 500)\u00a0 with a few hundred rectangles, I found that the script quickly bogged down.<\/strong><\/p>\n<p>For example, to refresh this shape (on the larger canvas) was taking 1 to 2 seconds:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-7960\" src=\"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-content\/uploads\/jsfillrect-03-slowglider.png\" alt=\"\" width=\"288\" height=\"234\" \/><\/p>\n<p>Obviously, this is completely outside the range of acceptable performance.\u00a0 In fact, it was so bad that if I had a video playing in another window, the video would stutter.<\/p>\n<p>The data is structured as a 2d array.\u00a0 If the cell contains a &#8220;1&#8221; it gets rendered as a green square, if it contains &#8220;0&#8221; it gets rendered as the background color.<\/p>\n<p>My render loop originally looked like this:<\/p>\n<pre>var cx,cy;\r\nvar C1=CELLSIZE-1;\r\nfor(var x=0 ; x&lt;MAXX ; x++){\r\n  cx=x*CELLSIZE;\r\n  for(var y=0 ; y&lt;MAXY ; y++){\r\n    cy=y*CELLSIZE;\r\n    ctx.fillStyle=gridstyles[ grid[x][y] ];\r\n    ctx.fillRect( cx , cy , cx+C1 , cy+C1 );\r\n  }\r\n}<\/pre>\n<p>Where, &#8220;grid&#8221; contains a 1 or 0 for each cell, and &#8220;gridstyles&#8221; is an array that has a corresponding style for each possible value of grid.<\/p>\n<p>&nbsp;<\/p>\n<h2>Troubleshooting and Fixing<\/h2>\n<p>You might notice that, given only two possible states, ONE of them, the zero or background state, can be pre-rendered, which is the first thing I tried:<\/p>\n<pre>var cx,cy;\r\nvar C1=CELLSIZE-1;\r\n\r\n<span style=\"color: #00ffff;\">ctx.fillStyle=gridstyles[0];\r\nctx.fillRect(0,0,MAXX*CELLSIZE,MAXY*CELLSIZE);\r\nctx.fillStyle=gridstyles[1];<\/span>\r\n\r\nfor(var x=0 ; x&lt;MAXX ; x++){\r\n  cx=x*CELLSIZE;\r\n  for(var y=0 ; y&lt;MAXY ; y++){\r\n    cy=y*CELLSIZE;\r\n    <span style=\"color: #bfbfbf;\">\/\/ctx.fillStyle=gridstyles[ grid[x][y] ];<\/span>\r\n    <span style=\"color: #00ffff;\">if(grid[x][y])<\/span>\r\n      ctx.fillRect( cx , cy , cx+C1 , cy+C1 );\r\n  }\r\n}<\/pre>\n<p>The reason I didn&#8217;t do this originally, is that I intend to run more complex simulations later, and therefore it won&#8217;t necessarily benefit me later to pre-render the background.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-7961\" src=\"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-content\/uploads\/jsfillrect-04-approach1-600x262.png\" alt=\"\" width=\"600\" height=\"262\" srcset=\"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-content\/uploads\/jsfillrect-04-approach1-600x262.png 600w, https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-content\/uploads\/jsfillrect-04-approach1-300x131.png 300w, https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-content\/uploads\/jsfillrect-04-approach1.png 660w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<p>The above should have given me a huge performance boost, but didn&#8217;t.\u00a0 Instead, I started getting these weird blobs (and insignificant performance benefit):<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-7962\" src=\"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-content\/uploads\/jsfillrect-05-results1-600x262.png\" alt=\"\" width=\"600\" height=\"262\" srcset=\"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-content\/uploads\/jsfillrect-05-results1-600x262.png 600w, https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-content\/uploads\/jsfillrect-05-results1-300x131.png 300w, https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-content\/uploads\/jsfillrect-05-results1.png 660w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<p>I even tried off-screen rendering, where oscanvas \/ osctx is an off-screen canvas \/ context:<\/p>\n<pre>osctx.fillStyle=gridstyles[0];\r\nosctx.fillRect(0,0,CWIDTH,CHEIGHT);\r\nosctx.fillStyle=gridstyles[1];\r\n\t\r\nfor(var x=0; x&lt;GWIDTH; x++){\r\n  cx=x*CELLSIZE;\r\n\t\t\r\n  for(var y=0 ; y&lt;GHEIGHT; y++){\r\n\t\t\t\r\n    if(grid[x][y]==1){\r\n      cy=y*CELLSIZE;\r\n\r\n      osctx.fillRect(cx,cy,cx+C1,cy+C1);\r\n    }\r\n  }\r\n}\r\n\r\nctx.drawImage(oscanvas, 0, 0);\r\n\r\n<\/pre>\n<p>In this case, all drawing steps are performed on the &#8220;off-screen&#8221; context, then the last step is to copy the bitmap of the off-screen canvas to the visible canvas&#8217;s context.<\/p>\n<p>Still no performance gain.<\/p>\n<p>After some troubleshooting, I figured out that the squares were being rendered like this, which gives us a significant clue to what&#8217;s going on:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-7963\" src=\"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-content\/uploads\/jsfillrect-06-results2-600x262.png\" alt=\"\" width=\"600\" height=\"262\" srcset=\"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-content\/uploads\/jsfillrect-06-results2-600x262.png 600w, https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-content\/uploads\/jsfillrect-06-results2-300x131.png 300w, https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-content\/uploads\/jsfillrect-06-results2.png 660w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<p>The syntax for fillRect is:<\/p>\n<pre>context.fillRect( Xcoord , Ycoord , Width , Height );\r\n<\/pre>\n<p>I had accidentally assumed the wrong syntax:<\/p>\n<pre>context.fillRect( X1 , Y1 , X2 , Y2 );\r\n<\/pre>\n<p>In my defense, I regularly work with about 8 programming \/ scripting languages, and some of them use X2\/Y2 syntax, but essentially, I was feeding X2 and Y2 in to fillRect instead of width \/ height.<\/p>\n<p>To put this in perspective, this was effectively painting the same square many multiple times per render frame.\u00a0 Even worse, most of these rectangles were being drawn waaaay beyond the edges of the canvas (on or off screen).<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-7964\" src=\"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-content\/uploads\/jsfillrect-07-virtual.png\" alt=\"\" width=\"594\" height=\"486\" srcset=\"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-content\/uploads\/jsfillrect-07-virtual.png 594w, https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-content\/uploads\/jsfillrect-07-virtual-300x245.png 300w\" sizes=\"auto, (max-width: 594px) 100vw, 594px\" \/><\/p>\n<p>In fact, the lower-right square would actually be rendered as a rectangle slightly larger than the entire canvas!<\/p>\n<p>Originally, when I was rendering both active and inactive squares, by rendering from left-to-right, top-to-bottom, this masked the behavior because each right-hand step nibbled away the trailing part of the previous &#8220;square&#8221;.\u00a0 Likewise, as each new row began, the progression of that row nibbled away the lower trailing portion of the &#8220;squares&#8221; above them.<\/p>\n<p>When I pre-rendered the background, the inactive portions of the active squares were no longer being nibbled away.<\/p>\n<p>In short, instead of rendering ( MAXX * MAXY * CELLSIZE * CELLSIZE ) pixels, I was rendering the same pixel hundreds of times in some cases, making it around ( MAXX^2\/2 * MAXY^2\/2 * CELLSIZE^4\/2 ) pixels that were being rendered per frame!<\/p>\n<p>The corrected code looks like this:<\/p>\n<pre>ctx.fillRect( cx , cy , C1 , C1 );<\/pre>\n<p>Where &#8220;C1&#8221; is constant equal to (CELLSIZE -1).\u00a0 Yes, I KNOW the optimizer should catch this, but I try not to rely on the optimizer.<\/p>\n<p>&nbsp;<\/p>\n<h2>Conclusion<\/h2>\n<p>ALWAYS double check your syntax\u00a0 :-)<\/p>\n<p>I thought a few people might enjoy reading about my misadventure, so if you made it this far, thank you for reading.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I accidentally figured out how to make compute-expensive blobs in JavaScript using fillRect().\u00a0 And&#8230;.how to fix it.<\/p>\n","protected":false},"author":16,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-7956","post","type-post","status-publish","format-standard","hentry","category-other-stuff"],"_links":{"self":[{"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/posts\/7956","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/users\/16"}],"replies":[{"embeddable":true,"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/comments?post=7956"}],"version-history":[{"count":9,"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/posts\/7956\/revisions"}],"predecessor-version":[{"id":7972,"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/posts\/7956\/revisions\/7972"}],"wp:attachment":[{"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/media?parent=7956"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/categories?post=7956"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/tags?post=7956"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}