{"id":702,"date":"2020-09-22T11:38:55","date_gmt":"2020-09-22T11:38:55","guid":{"rendered":"https:\/\/potatodie.nl\/diffuse-write-ups\/?p=702"},"modified":"2021-10-03T08:18:41","modified_gmt":"2021-10-03T08:18:41","slug":"fun-with-canvas-transforms","status":"publish","type":"post","link":"https:\/\/potatodie.nl\/diffuse-write-ups\/fun-with-canvas-transforms\/","title":{"rendered":"Fun with canvas transforms"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Making use of coordinate system transformations can make drawing on the html5 element <code>canvas<\/code> much easier. But sometimes it is confusing how transforms work. What is it that is actually transformed?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Active or passive?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A simple example. Let&#8217;s draw a square in the left top corner of a canvas<\/p>\n\n\n<div class=\"wp-block-advanced-gutenberg-blocks-code\">\n  <header class=\"wp-block-advanced-gutenberg-blocks-code__header\">\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__lang is-lang-js\">\n      JS    <\/div>\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__file\">\n          <\/div>\n  <\/header>\n  <textarea \n    class=\"wp-block-advanced-gutenberg-blocks-code__source\" \n    name=\"codemirror-1969946519\" \n    id=\"codemirror-1969946519\"\n  >let ctx = document.getElementById(&#039;canvas1&#039;).getContext(&#039;2d&#039;)\nctx.fillStyle=&quot;#f12&quot;\nctx.fillRect(0, 0, 100, 100)<\/textarea>\n  <script>\n    CodeMirror.fromTextArea( document.getElementById('codemirror-1969946519'), {\n      mode: 'javascript',\n      readOnly: true,\n      theme: 'hopscotch', \n      lineNumbers: false,\n      firstLineNumber: 1,\n      matchBrackets: true,\n      indentUnit: 4,\n      tabSize: 4,\n      lineWrapping: true,\n    } ); \n  <\/script>\n<\/div>\n\n\n\n<div class=\"wp-block-group\"><div class=\"wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow\">\n<canvas id=\"canvas1\" style=\"background: orange;\" width=\"300\" height=\"200\"><\/canvas>\n\n\n\n<p class=\"wp-block-paragraph\">Now we could apply a transform, like<\/p>\n\n\n<div class=\"wp-block-advanced-gutenberg-blocks-code\">\n  <header class=\"wp-block-advanced-gutenberg-blocks-code__header\">\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__lang is-lang-js\">\n      JS    <\/div>\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__file\">\n          <\/div>\n  <\/header>\n  <textarea \n    class=\"wp-block-advanced-gutenberg-blocks-code__source\" \n    name=\"codemirror-324586483\" \n    id=\"codemirror-324586483\"\n  >ctx.translate(75, 50)<\/textarea>\n  <script>\n    CodeMirror.fromTextArea( document.getElementById('codemirror-324586483'), {\n      mode: 'javascript',\n      readOnly: true,\n      theme: 'hopscotch', \n      lineNumbers: false,\n      firstLineNumber: 1,\n      matchBrackets: true,\n      indentUnit: 4,\n      tabSize: 4,\n      lineWrapping: true,\n    } ); \n  <\/script>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\">And you might expect that the square we have drawn will move 75 pixels to the right and 50 pixels down. But that doesn&#8217;t happen. One might say the transformation is passive: it leaves already drawn graphics alone.<\/p>\n<\/div><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Coordinate systems<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">What <code>translate<\/code> (or any canvas transform) does is change the coordinate system of the rendering context. If we would now draw a second square, with the same parameters for left and top, this square would appear 75 pixels to the right and 50 pixels down.<\/p>\n\n\n<div class=\"wp-block-advanced-gutenberg-blocks-code\">\n  <header class=\"wp-block-advanced-gutenberg-blocks-code__header\">\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__lang is-lang-js\">\n      JS    <\/div>\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__file\">\n          <\/div>\n  <\/header>\n  <textarea \n    class=\"wp-block-advanced-gutenberg-blocks-code__source\" \n    name=\"codemirror-785100046\" \n    id=\"codemirror-785100046\"\n  >ctx.fillStyle=&quot;#21f&quot;\nctx.fillRect(0, 0, 100, 100)<\/textarea>\n  <script>\n    CodeMirror.fromTextArea( document.getElementById('codemirror-785100046'), {\n      mode: 'javascript',\n      readOnly: true,\n      theme: 'hopscotch', \n      lineNumbers: false,\n      firstLineNumber: 1,\n      matchBrackets: true,\n      indentUnit: 4,\n      tabSize: 4,\n      lineWrapping: true,\n    } ); \n  <\/script>\n<\/div>\n\n\n\n<div class=\"wp-block-group\"><div class=\"wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow\">\n<canvas id=\"canvas2\" style=\"background: orange;\" width=\"300\" height=\"200\"><\/canvas>\n<\/div><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">So the canvas itself has a fixed coordinate system, with the origin in the top-left corner. We can manipulate (transform) the rendering context&#8217;s coordinate sytems, but as soon as something is drawn it is fixed to the canvas. To move an existing graphic, or scale or rotate it, you just have to redraw it from scratch, using a suitable transformation.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Cherries<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Well, let&#8217;s make use of those transforms and create the following graphic with minimal math trouble.<\/p>\n\n\n\n<div class=\"wp-block-group\"><div class=\"wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow\">\n<canvas id=\"canvas3\" style=\"background: white; width: 340px;\" width=\"340\" height=\"340\"><\/canvas>\n<\/div><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">You see that the drawing consists of multiple copies of a basis element, a cherry with a stem (or a circle with a line if you like). It would be quite a lot of work if we had to calculate all coordinates of every copy. Instead we just transform the rendering context and draw one copy each time, calling<code> drawCherry()<\/code> in the code below.<\/p>\n\n\n<div class=\"wp-block-advanced-gutenberg-blocks-code\">\n  <header class=\"wp-block-advanced-gutenberg-blocks-code__header\">\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__lang is-lang-js\">\n      JS    <\/div>\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__file\">\n          <\/div>\n  <\/header>\n  <textarea \n    class=\"wp-block-advanced-gutenberg-blocks-code__source\" \n    name=\"codemirror-612010707\" \n    id=\"codemirror-612010707\"\n  >const \u03c0 = Math.PI;\n\nfunction drawCherry(ctx) {\n  ctx.beginPath();\n  ctx.lineWidth = 6;\n  ctx.moveTo(0, 0);\n  ctx.lineTo(0, 100);\n  ctx.moveTo(20, 120);\n  ctx.arc(0, 120, 20, 0, \u03c0 * 2, true);\n  ctx.stroke();\n}\n\nctx = document.getElementById(&quot;canvas3&quot;).getContext(&quot;2d&quot;);\nctx.strokeStyle = &quot;black&quot;;\n\nctx.translate(170, 170);\n\nvar n = 8;\nfor (i = 0; i &lt; n; i++) {\n  ctx.rotate(\u03c0 \/ 4);\n  ctx.save();\n  drawCherry(ctx);\n  ctx.translate(0, 50);\n  ctx.rotate(\u03c0 \/ 4);\n  ctx.scale(0.5, 0.5);\n  drawCherry(ctx);\n  ctx.restore();\n}<\/textarea>\n  <script>\n    CodeMirror.fromTextArea( document.getElementById('codemirror-612010707'), {\n      mode: 'javascript',\n      readOnly: true,\n      theme: 'hopscotch', \n      lineNumbers: false,\n      firstLineNumber: 1,\n      matchBrackets: true,\n      indentUnit: 4,\n      tabSize: 4,\n      lineWrapping: true,\n    } ); \n  <\/script>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">More transforms<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A <a href=\"https:\/\/potatodie.nl\/diffuse-write-ups\/transforms-and-symmetry-of-triangles\/\" data-type=\"post\" data-id=\"863\">follow-up post<\/a> uses transforms to create a seamless pattern based on triangles. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Making use of coordinate system transformations can make drawing on the html5 element canvas much easier. But sometimes it is confusing how transforms work. What is it that is actually transformed? Let&#8217;s clear that up and see how to use it.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[30,50,20,7],"tags":[39,12],"class_list":["post-702","post","type-post","status-publish","format-standard","hentry","category-geometry","category-graphics","category-javascript","category-web-development","tag-canvas","tag-transform"],"acf":[],"_links":{"self":[{"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/posts\/702","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/comments?post=702"}],"version-history":[{"count":46,"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/posts\/702\/revisions"}],"predecessor-version":[{"id":997,"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/posts\/702\/revisions\/997"}],"wp:attachment":[{"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/media?parent=702"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/categories?post=702"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/tags?post=702"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}