transformations.yaml (10439B)
1 - name: 2d.transformation.order 2 desc: Transformations are applied in the right order 3 code: | 4 ctx.fillStyle = '#f00'; 5 ctx.fillRect(0, 0, 100, 50); 6 7 ctx.scale(2, 1); 8 ctx.rotate(Math.PI / 2); 9 ctx.fillStyle = '#0f0'; 10 ctx.fillRect(0, -50, 50, 50); 11 @assert pixel 75,25 == 0,255,0,255; 12 expected: green 13 14 15 - name: 2d.transformation.scale.basic 16 desc: scale() works 17 code: | 18 ctx.fillStyle = '#f00'; 19 ctx.fillRect(0, 0, 100, 50); 20 21 ctx.scale(2, 4); 22 ctx.fillStyle = '#0f0'; 23 ctx.fillRect(0, 0, 50, 12.5); 24 @assert pixel 90,40 == 0,255,0,255; 25 expected: green 26 27 - name: 2d.transformation.scale.zero 28 desc: scale() with a scale factor of zero works 29 code: | 30 ctx.fillStyle = '#0f0'; 31 ctx.fillRect(0, 0, 100, 50); 32 33 ctx.save(); 34 ctx.translate(50, 0); 35 ctx.scale(0, 1); 36 ctx.fillStyle = '#f00'; 37 ctx.fillRect(0, 0, 100, 50); 38 ctx.restore(); 39 40 ctx.save(); 41 ctx.translate(0, 25); 42 ctx.scale(1, 0); 43 ctx.fillStyle = '#f00'; 44 ctx.fillRect(0, 0, 100, 50); 45 ctx.restore(); 46 47 @assert pixel 50,25 == 0,255,0,255; 48 expected: green 49 50 - name: 2d.transformation.scale.negative 51 desc: scale() with negative scale factors works 52 code: | 53 ctx.fillStyle = '#f00'; 54 ctx.fillRect(0, 0, 100, 50); 55 56 ctx.save(); 57 ctx.scale(-1, 1); 58 ctx.fillStyle = '#0f0'; 59 ctx.fillRect(-50, 0, 50, 50); 60 ctx.restore(); 61 62 ctx.save(); 63 ctx.scale(1, -1); 64 ctx.fillStyle = '#0f0'; 65 ctx.fillRect(50, -50, 50, 50); 66 ctx.restore(); 67 @assert pixel 25,25 == 0,255,0,255; 68 @assert pixel 75,25 == 0,255,0,255; 69 expected: green 70 71 - name: 2d.transformation.scale.large 72 desc: scale() with large scale factors works 73 notes: Not really that large at all, but it hits the limits in Firefox. 74 code: | 75 ctx.fillStyle = '#f00'; 76 ctx.fillRect(0, 0, 100, 50); 77 78 ctx.scale(1e5, 1e5); 79 ctx.fillStyle = '#0f0'; 80 ctx.fillRect(0, 0, 1, 1); 81 @assert pixel 50,25 == 0,255,0,255; 82 expected: green 83 84 - name: 2d.transformation.scale.nonfinite 85 desc: scale() with Infinity/NaN is ignored 86 code: | 87 ctx.fillStyle = '#f00'; 88 ctx.fillRect(0, 0, 100, 50); 89 90 ctx.translate(100, 10); 91 @nonfinite ctx.scale(<0.1 Infinity -Infinity NaN>, <0.1 Infinity -Infinity NaN>); 92 93 ctx.fillStyle = '#0f0'; 94 ctx.fillRect(-100, -10, 100, 50); 95 96 @assert pixel 50,25 == 0,255,0,255; 97 expected: green 98 99 - name: 2d.transformation.scale.multiple 100 desc: Multiple scale()s combine 101 code: | 102 ctx.fillStyle = '#f00'; 103 ctx.fillRect(0, 0, 100, 50); 104 105 ctx.scale(Math.sqrt(2), Math.sqrt(2)); 106 ctx.scale(Math.sqrt(2), Math.sqrt(2)); 107 ctx.fillStyle = '#0f0'; 108 ctx.fillRect(0, 0, 50, 25); 109 @assert pixel 90,40 == 0,255,0,255; 110 expected: green 111 112 113 - name: 2d.transformation.rotate.zero 114 desc: rotate() by 0 does nothing 115 code: | 116 ctx.fillStyle = '#f00'; 117 ctx.fillRect(0, 0, 100, 50); 118 119 ctx.rotate(0); 120 ctx.fillStyle = '#0f0'; 121 ctx.fillRect(0, 0, 100, 50); 122 @assert pixel 50,25 == 0,255,0,255; 123 expected: green 124 125 - name: 2d.transformation.rotate.radians 126 desc: rotate() uses radians 127 code: | 128 ctx.fillStyle = '#f00'; 129 ctx.fillRect(0, 0, 100, 50); 130 131 ctx.rotate(Math.PI); // should fail obviously if this is 3.1 degrees 132 ctx.fillStyle = '#0f0'; 133 ctx.fillRect(-100, -50, 100, 50); 134 @assert pixel 50,25 == 0,255,0,255; 135 expected: green 136 137 - name: 2d.transformation.rotate.direction 138 desc: rotate() is clockwise 139 code: | 140 ctx.fillStyle = '#f00'; 141 ctx.fillRect(0, 0, 100, 50); 142 143 ctx.rotate(Math.PI / 2); 144 ctx.fillStyle = '#0f0'; 145 ctx.fillRect(0, -100, 50, 100); 146 @assert pixel 50,25 == 0,255,0,255; 147 expected: green 148 149 - name: 2d.transformation.rotate.wrap 150 desc: rotate() wraps large positive values correctly 151 code: | 152 ctx.fillStyle = '#f00'; 153 ctx.fillRect(0, 0, 100, 50); 154 155 ctx.rotate(Math.PI * (1 + 4096)); // == pi (mod 2*pi) 156 // We need about pi +/- 0.001 in order to get correct-looking results 157 // 32-bit floats can store pi*4097 with precision 2^-10, so that should 158 // be safe enough on reasonable implementations 159 ctx.fillStyle = '#0f0'; 160 ctx.fillRect(-100, -50, 100, 50); 161 @assert pixel 50,25 == 0,255,0,255; 162 @assert pixel 98,2 == 0,255,0,255; 163 @assert pixel 98,47 == 0,255,0,255; 164 expected: green 165 166 - name: 2d.transformation.rotate.wrapnegative 167 desc: rotate() wraps large negative values correctly 168 code: | 169 ctx.fillStyle = '#f00'; 170 ctx.fillRect(0, 0, 100, 50); 171 172 ctx.rotate(-Math.PI * (1 + 4096)); 173 ctx.fillStyle = '#0f0'; 174 ctx.fillRect(-100, -50, 100, 50); 175 @assert pixel 50,25 == 0,255,0,255; 176 @assert pixel 98,2 == 0,255,0,255; 177 @assert pixel 98,47 == 0,255,0,255; 178 expected: green 179 180 - name: 2d.transformation.rotate.nonfinite 181 desc: rotate() with Infinity/NaN is ignored 182 code: | 183 ctx.fillStyle = '#f00'; 184 ctx.fillRect(0, 0, 100, 50); 185 186 ctx.translate(100, 10); 187 @nonfinite ctx.rotate(<0.1 Infinity -Infinity NaN>); 188 189 ctx.fillStyle = '#0f0'; 190 ctx.fillRect(-100, -10, 100, 50); 191 192 @assert pixel 50,25 == 0,255,0,255; 193 expected: green 194 195 - name: 2d.transformation.translate.basic 196 desc: translate() works 197 code: | 198 ctx.fillStyle = '#f00'; 199 ctx.fillRect(0, 0, 100, 50); 200 201 ctx.translate(100, 50); 202 ctx.fillStyle = '#0f0'; 203 ctx.fillRect(-100, -50, 100, 50); 204 @assert pixel 90,40 == 0,255,0,255; 205 expected: green 206 207 - name: 2d.transformation.translate.nonfinite 208 desc: translate() with Infinity/NaN is ignored 209 code: | 210 ctx.fillStyle = '#f00'; 211 ctx.fillRect(0, 0, 100, 50); 212 213 ctx.translate(100, 10); 214 @nonfinite ctx.translate(<0.1 Infinity -Infinity NaN>, <0.1 Infinity -Infinity NaN>); 215 216 ctx.fillStyle = '#0f0'; 217 ctx.fillRect(-100, -10, 100, 50); 218 219 @assert pixel 50,25 == 0,255,0,255; 220 expected: green 221 222 223 - name: 2d.transformation.transform.identity 224 desc: transform() with the identity matrix does nothing 225 code: | 226 ctx.fillStyle = '#f00'; 227 ctx.fillRect(0, 0, 100, 50); 228 229 ctx.transform(1,0, 0,1, 0,0); 230 ctx.fillStyle = '#0f0'; 231 ctx.fillRect(0, 0, 100, 50); 232 @assert pixel 50,25 == 0,255,0,255; 233 expected: green 234 235 - name: 2d.transformation.transform.skewed 236 desc: transform() with skewy matrix transforms correctly 237 code: | 238 // Create green with a red square ring inside it 239 ctx.fillStyle = '#0f0'; 240 ctx.fillRect(0, 0, 100, 50); 241 ctx.fillStyle = '#f00'; 242 ctx.fillRect(20, 10, 60, 30); 243 ctx.fillStyle = '#0f0'; 244 ctx.fillRect(40, 20, 20, 10); 245 246 // Draw a skewed shape to fill that gap, to make sure it is aligned correctly 247 ctx.transform(1,4, 2,3, 5,6); 248 // Post-transform coordinates: 249 // [[20,10],[80,10],[80,40],[20,40],[20,10],[40,20],[40,30],[60,30],[60,20],[40,20],[20,10]]; 250 // Hence pre-transform coordinates: 251 var pts=[[-7.4,11.2],[-43.4,59.2],[-31.4,53.2],[4.6,5.2],[-7.4,11.2], 252 [-15.4,25.2],[-11.4,23.2],[-23.4,39.2],[-27.4,41.2],[-15.4,25.2], 253 [-7.4,11.2]]; 254 ctx.beginPath(); 255 ctx.moveTo(pts[0][0], pts[0][1]); 256 for (var i = 0; i < pts.length; ++i) 257 ctx.lineTo(pts[i][0], pts[i][1]); 258 ctx.fill(); 259 @assert pixel 21,11 == 0,255,0,255; 260 @assert pixel 79,11 == 0,255,0,255; 261 @assert pixel 21,39 == 0,255,0,255; 262 @assert pixel 79,39 == 0,255,0,255; 263 @assert pixel 39,19 == 0,255,0,255; 264 @assert pixel 61,19 == 0,255,0,255; 265 @assert pixel 39,31 == 0,255,0,255; 266 @assert pixel 61,31 == 0,255,0,255; 267 expected: green 268 269 - name: 2d.transformation.transform.multiply 270 desc: transform() multiplies the CTM 271 code: | 272 ctx.fillStyle = '#f00'; 273 ctx.fillRect(0, 0, 100, 50); 274 275 ctx.transform(1,2, 3,4, 5,6); 276 ctx.transform(-2,1, 3/2,-1/2, 1,-2); 277 ctx.fillStyle = '#0f0'; 278 ctx.fillRect(0, 0, 100, 50); 279 @assert pixel 50,25 == 0,255,0,255; 280 expected: green 281 282 - name: 2d.transformation.transform.nonfinite 283 desc: transform() with Infinity/NaN is ignored 284 code: | 285 ctx.fillStyle = '#f00'; 286 ctx.fillRect(0, 0, 100, 50); 287 288 ctx.translate(100, 10); 289 @nonfinite ctx.transform(<0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>); 290 291 ctx.fillStyle = '#0f0'; 292 ctx.fillRect(-100, -10, 100, 50); 293 294 @assert pixel 50,25 == 0,255,0,255; 295 expected: green 296 297 - name: 2d.transformation.setTransform.skewed 298 code: | 299 // Create green with a red square ring inside it 300 ctx.fillStyle = '#0f0'; 301 ctx.fillRect(0, 0, 100, 50); 302 ctx.fillStyle = '#f00'; 303 ctx.fillRect(20, 10, 60, 30); 304 ctx.fillStyle = '#0f0'; 305 ctx.fillRect(40, 20, 20, 10); 306 307 // Draw a skewed shape to fill that gap, to make sure it is aligned correctly 308 ctx.setTransform(1,4, 2,3, 5,6); 309 // Post-transform coordinates: 310 // [[20,10],[80,10],[80,40],[20,40],[20,10],[40,20],[40,30],[60,30],[60,20],[40,20],[20,10]]; 311 // Hence pre-transform coordinates: 312 var pts=[[-7.4,11.2],[-43.4,59.2],[-31.4,53.2],[4.6,5.2],[-7.4,11.2], 313 [-15.4,25.2],[-11.4,23.2],[-23.4,39.2],[-27.4,41.2],[-15.4,25.2], 314 [-7.4,11.2]]; 315 ctx.beginPath(); 316 ctx.moveTo(pts[0][0], pts[0][1]); 317 for (var i = 0; i < pts.length; ++i) 318 ctx.lineTo(pts[i][0], pts[i][1]); 319 ctx.fill(); 320 @assert pixel 21,11 == 0,255,0,255; 321 @assert pixel 79,11 == 0,255,0,255; 322 @assert pixel 21,39 == 0,255,0,255; 323 @assert pixel 79,39 == 0,255,0,255; 324 @assert pixel 39,19 == 0,255,0,255; 325 @assert pixel 61,19 == 0,255,0,255; 326 @assert pixel 39,31 == 0,255,0,255; 327 @assert pixel 61,31 == 0,255,0,255; 328 expected: green 329 330 - name: 2d.transformation.setTransform.multiple 331 code: | 332 ctx.fillStyle = '#f00'; 333 ctx.fillRect(0, 0, 100, 50); 334 335 ctx.setTransform(1/2,0, 0,1/2, 0,0); 336 ctx.setTransform(); 337 ctx.setTransform(2,0, 0,2, 0,0); 338 ctx.fillStyle = '#0f0'; 339 ctx.fillRect(0, 0, 50, 25); 340 @assert pixel 75,35 == 0,255,0,255; 341 expected: green 342 343 - name: 2d.transformation.setTransform.nonfinite 344 desc: setTransform() with Infinity/NaN is ignored 345 code: | 346 ctx.fillStyle = '#f00'; 347 ctx.fillRect(0, 0, 100, 50); 348 349 ctx.translate(100, 10); 350 @nonfinite ctx.setTransform(<0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>, <0 Infinity -Infinity NaN>); 351 352 ctx.fillStyle = '#0f0'; 353 ctx.fillRect(-100, -10, 100, 50); 354 355 @assert pixel 50,25 == 0,255,0,255; 356 expected: green