Skip to content

Canvas specific Golfing Tricks

Vivek edited this page Jul 6, 2021 · 7 revisions

Clearing the canvas

Simply: c.width|=0

"There's a difference there too, clearRect only clears the pixels, while setting the width of height of the canvas clears all the other state too, like fillStyle, transforms, etc" - sigveseb

In fact you can | with various small numbers with little or no consequence, so this clearing can be combined with other variable setup: c.width|=N=600

Set canvas width to 300: c.width=-1

Color

You can get hsl using a template string, and you can omit the final ')' because browsers are lenient when parsing it:

x.fillStyle=`hsl(${X},80%,${i}%`

There is a further trick which omits one of the commas (and replaces the other with a space), but this breaks in Safari:

x.fillStyle=`hsl(${X} 80%${i}%` // breaks in Safari (always black)

If you need specific RGB or RGBA colors, the longer way using CSS hex format is:

x.fillStyle='#RRGGBB' 
// or
x.fillStyle='#RRGGBBAA'

For fixed RGB colors without transparency, you can save a couple of bytes by finding a color with a short name that matches what you need - the following standard HTML/CSS color names are less than 7 characters long and will save 1 to 4 bytes compared to their RGB representation

red, tan, aqua, blue, cyan, gold, gray, lime, navy, peru, pink, plum, snow, teal, azure, beige, black, brown, 
coral, green, ivory, khaki, linen, olive, wheat, white, bisque, indigo, maroon, orange, orchid, purple, salmon, sienna, silver, tomato, violet, yellow

In most cases this will also be shorter than the dwitter specific R(R,G,B) function (8 chars) because single digit RGB values are just black

The other option is is to use this format:

x.fillStyle='#RGB' 
// or
x.fillStyle='#RGBA'

You are restricted to a 4-bit value (one hex digit) for each of the R, G, B and A channels, but that is 4096 hues, and 16 levels of transparency - which is adequate in most cases

Text instead of rects?

It is shorter to draw text than to fill a rectangle if your w and h can be fixed small constants. So instead of little dots, you could consider little unicodes.

x.fillRect(x,y,w,h)
x.fillText(n,x,y)

Since JS implicitly casts n to a string it saves two bytes

n can be a single numerical digit or a variable. The default font is quite tiny, so it can substitute for a filled rectangle in most cases. Using a variable that contains a longer number lets you create a longer "rectangle" from the text.

Using arcs to draw polygons?

Pro tip from pavel:

x.lineTo(X+r*C(a),Y+r*S(a))
// is the same as
x.arc(X,Y,r,a,a)

Other

x.fill('evenodd') is significantly shorter than x.globalCompositeOperation='xor';x.fill()

If you are using color, using the alpha from hsla(... is usually shorter than a separate x.globalAlpha=0.5

Are you put off using x.transform() because it doesn't reset. Try x.setTransform() instead! But note that it is different: it takes a matrix rather than a string of transforms.

Setting font size

// Long ways:
x.font='99px sans'
x.font='99px sa'

// Short way
x.font='9em"'
x.font="9em'"

Note that on Mac OS X, 256em seems to be the maximum. After that, text and emoji just disappear!

Using Path2d instead of multiple primitives

If you’re using beginPath it can be shorter to use Path2D instead (credit veubeke):

x.beginPath(),x.arc(...),x.fill()
x.fill(P=new Path2D,P.arc(...))

Canvas effects

x.shadowBlur=20;x.shadowColor="#000"