Jekyll2024-02-07T16:56:23-05:00https://www.robertlysik.com/feed.xmlRobert LysikSoftware developerRobert LysikMigrating from WordPress to Jekyll2019-12-26T00:00:00-05:002019-12-26T00:00:00-05:00https://www.robertlysik.com/jekyll/migrating-from-wordpress-to-jekyll<p>I decided to do some clean-up of this blog and migrate off of WordPress in the process. The site is now hosted on <a href="https://pages.github.com/" title="GitHub Pages">GitHub Pages</a> and uses <a href="https://jekyllrb.com/" title="Jekyll" target="_blank">Jekyll</a> for static site generation.</p>
<p>The following sections explain the steps I took to do this migration.</p>
<h3 id="backup-wordpress-site">Backup WordPress Site</h3>
<p>First, I logged in to my existing WordPress site and did a full backup and export, this includes the MySQL database as well as the static site files, such as images, associated with the posts.</p>
<p>I then imported the WordPress database into a MySQL instance on my local Windows machine using MySQL Workbench.</p>
<h3 id="enable-windows-subsystem-for-linux">Enable Windows Subsystem for Linux</h3>
<p>Jekyll requires the Ruby development environment, and although there is a description for how to <a href="https://jekyllrb.com/docs/installation/windows/#installation-via-rubyinstaller" title="Install via RubyInstaller">install via RubyInstaller</a>, the better option appears to be to use the Windows Subsystem for Linux and <a href="https://jekyllrb.com/docs/installation/windows/#installation-via-bash-on-windows-10" title="Install via Bash on Windows 10">install via bash</a>, if possible.</p>
<p>Since I’m using a Windows 10 machine for development the <a href="https://docs.microsoft.com/en-us/windows/wsl/about" title="Windows Subsystem for Linux" target="_blank">Windows Subsystem for Linux</a> is available and is easy enough to enable.</p>
<p>To enable <a href="https://docs.microsoft.com/en-us/windows/wsl/install-win10" title="WSL" target="_blank">WSL</a>, run the following PowerShell command as administrator, and then restart the computer when prompted.</p>
<figure class="highlight"><pre><code class="language-powershell" data-lang="powershell"><span class="n">Enable-WindowsOptionalFeature</span><span class="w"> </span><span class="nt">-Online</span><span class="w"> </span><span class="nt">-FeatureName</span><span class="w"> </span><span class="nx">Microsoft-Windows-Subsystem-Linux</span></code></pre></figure>
<p>Once WSL has been enabled, you can then install your Linux distribution of choice using the Windows Store app. In my case, I chose to install the Ubuntu LTS distro.</p>
<h3 id="install-jekyll-and-import-posts-from-wordpress">Install Jekyll and Import Posts from WordPress</h3>
<p>Now that WSL is enabled and Ubuntu has been installed, it should be possible to <a href="https://jekyllrb.com/docs/installation/windows/#installation-via-bash-on-windows-10" title="Install Jekyll via Bash on Windows 10">install Jekyll via the WSL bash prompt</a>.</p>
<p>Update repo lists and packages:</p>
<p><code class="language-plaintext highlighter-rouge">sudo apt-get update -y && sudo apt-get upgrade -y</code></p>
<p>Install Ruby:</p>
<figure class="highlight"><pre><code class="language-shell" data-lang="shell"><span class="nb">sudo </span>apt-add-repository ppa:brightbox/ruby-ng
<span class="nb">sudo </span>apt-get update
<span class="nb">sudo </span>apt-get <span class="nb">install </span>ruby2.5 ruby2.5-dev build-essential dh-autoreconf</code></pre></figure>
<p>Update Ruby gems:</p>
<p><code class="language-plaintext highlighter-rouge">gem update</code></p>
<p>And finally, install Jekyll:</p>
<p><code class="language-plaintext highlighter-rouge">gem install jekyll bundler</code></p>
<p><strong>NOTE</strong>: I ran into an issue with permissions when running <code class="language-plaintext highlighter-rouge">gem update</code> and <code class="language-plaintext highlighter-rouge">gem install jekyll bundler</code>. In order to fix this the following lines had to be added to the end of my .bashrc file as described <a href="https://jekyllrb.com/docs/troubleshooting/#no-sudo" target="_blank">here</a>.</p>
<figure class="highlight"><pre><code class="language-shell" data-lang="shell"><span class="c"># Ruby exports</span>
<span class="nb">export </span><span class="nv">GEM_HOME</span><span class="o">=</span><span class="nv">$HOME</span>/gems
<span class="nb">export </span><span class="nv">PATH</span><span class="o">=</span><span class="nv">$HOME</span>/gems/bin:<span class="nv">$PATH</span></code></pre></figure>
<p>Now that Jekyll was up and running, I ran <code class="language-plaintext highlighter-rouge">jekyll new blog</code> and then changed directory into the newly created blog folder.</p>
<p>Jekyll provides utilies to import posts from other blogging systems, such as WordPress. In order to use the import utility for WordPress, I first needed to install some additional gems:</p>
<p><code class="language-plaintext highlighter-rouge">gem install unidecode sequel mysql2 htmlentities</code></p>
<p>I could now import the posts from WordPress using the <code class="language-plaintext highlighter-rouge">jekyll-import</code> utility as described <a href="https://import.jekyllrb.com/docs/wordpress/">here</a>.</p>
<figure class="highlight"><pre><code class="language-shell" data-lang="shell">ruby <span class="nt">-r</span> rubygems <span class="nt">-e</span> <span class="s1">'require "jekyll-import";
JekyllImport::Importers::WordPress.run({
"dbname" => "[database-name]",
"user" => "[user-name]",
"password" => "[password]",
"host" => "127.0.0.1",
"port" => "3306",
"socket" => "",
"table_prefix" => "wp_",
"site_prefix" => "",
"clean_entities" => true,
"comments" => true,
"categories" => true,
"tags" => true,
"more_excerpt" => true,
"more_anchor" => true,
"extension" => "html",
"status" => ["publish"]
})'</span></code></pre></figure>
<p><strong>NOTE</strong>: ipaddress, rather than ‘localhost’, seems to work for the host setting. I was able to connect to the MySQL instance running in Windows from the WSL environment.</p>
<p>This command extracts the posts from the WordPress database and creates a folder named _posts. Each post consists of a file with an .html extension and contains the YAML front-matter at the top of the page with post title, author, tags, etc. The remainder of the file consists of the post content in HTML markup.</p>
<p>I also copied all the image files that I had exported from WordPress to a new <code class="language-plaintext highlighter-rouge">/images/posts/</code> folder within the blog folder in WSL.</p>
<h3 id="editing-posts-with-visual-studio-code">Editing Posts with Visual Studio Code</h3>
<p>I could use VIM to edit the posts from the command line, but I’d really prefer to use a tool like Visual Studio Code. Thankfully, there is the <a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-wsl" title="Remote - WSL">Remote - WSL</a> extension for VS Code that allows you to open a folder in the Windows Subsystem for Linux from VS Code running under Windows.</p>
<p>As described on the Remote - WSL extension page:</p>
<blockquote>
<p>Remote - WSL runs commands and extensions directly in WSL so you don’t have to worry about pathing issues, binary compatibility, or other cross-OS challenges. You’re able to use VS Code in WSL just as you would from Windows.</p>
</blockquote>
<p>I decided to rename the files in the _posts folder using the .md extenstion and reformat manually using <a href="https://daringfireball.net/projects/markdown/basics" title="Markdown">Markdown</a> using global search and replace. Much of this can be quickly done, but links and image tags require some extra care. The path to the image files had changed since I had moved all the images under an <code class="language-plaintext highlighter-rouge">/images/posts/</code> folder. I also went through each of the links and tested them out. Most had been upgraded to use HTTPS since I had first posted the blog entries. Surprisingly, most links were still valid, or required only minor modifications.</p>
<p>The end result is a very satisfying easy to read post using Markdown with no distracting HTML syntax.</p>
<p>I was then able to test the result by running <code class="language-plaintext highlighter-rouge">jekyll serve</code> in the WSL bash prompt, and view the result in my browser.</p>
<p>Once I was satisfied with the conversion to Markdown, I did a <code class="language-plaintext highlighter-rouge">git init</code> within the blog folder, followed by <code class="language-plaintext highlighter-rouge">git add .</code> and <code class="language-plaintext highlighter-rouge">git commit -m "Initial version"</code>.</p>
<p><strong>NOTE</strong>: Before you add files with git, make sure you have a .gitignore file, mine contains:</p>
<figure class="highlight"><pre><code class="language-shell" data-lang="shell">_site
.sass-cache
.jekyll-cache
.jekyll-metadata
vendor</code></pre></figure>
<p>You definitely don’t want to add the generated output in the _site folder to your repository.</p>
<h3 id="create-github-pages-repo">Create GitHub Pages Repo</h3>
<p>To create a <a href="https://help.github.com/en/github/working-with-github-pages/creating-a-github-pages-site" title="Create a GitHub Pages Site">GitHub Pages Site</a>, create a new repository in your GitHub account named <em>{username}.github.io</em>, or in my case: rmlysik.github.io.</p>
<p>Now that the GitHub repo had been created, I could add it as a remote for the blog repo:</p>
<p><code class="language-plaintext highlighter-rouge">git remote add origin https://github.com/rmlysik/rmlysik.github.io.git</code></p>
<p>followed by:</p>
<p><code class="language-plaintext highlighter-rouge">git push</code></p>
<p>to upload the committed changes.</p>
<h3 id="configure-custom-domain">Configure Custom Domain</h3>
<p>Since I already had a domain registered for my previous WordPress blog, I figured I would transfer this over to the GitHub pages site after I had gotten it working. This was also very straightforward, as described <a href="https://help.github.com/en/github/working-with-github-pages/managing-a-custom-domain-for-your-github-pages-site" title="Managing a Custom Domain for Your GitHub Pages Site">here</a>.</p>
<p>I chose to configure a subdomain as the custom domain using ‘www.robertlysik.com’ as the subdomain.</p>
<p>The only hitch appeared to be that I had previously registered my domain for <a href="https://hstspreload.org/" title="HSTS">HSTS</a>, and initally I was getting certificate errors. I couldn’t enable SSL immediately for the GitHub pages site after configuring the custom URL, I was told I needed to wait 24 hours. But the next day, I was able to tick the box to enable SSL, and that fixed the issues I was having.</p>
<h3 id="final-thoughts">Final Thoughts</h3>
<p>Although there’s a bit of setup involved, I like the fact that my entire blog is now under version control and I don’t have any additional requirements, such as a database and blogging application to maintain. It’s very easy to edit the posts using VS Code, and Markdown is a lot cleaner and faster to work with than HTML. I can preview my changes locally in a browser while running <code class="language-plaintext highlighter-rouge">jekyll serve</code> in my WSL bash prompt, and it’s just a matter of a <code class="language-plaintext highlighter-rouge">git push</code> to deploy my changes to the site.</p>Robert LysikI decided to do some clean-up of this blog and migrate off of WordPress in the process. The site is now hosted on GitHub Pages and uses Jekyll for static site generation.JavaScript Snowflake2013-11-26T20:57:31-05:002013-11-26T20:57:31-05:00https://www.robertlysik.com/javascript/generative%20art/javascript-snowflake<p>It’s getting to be that time of the year again. Soon I’ll have to break out the shovel, but before then, I thought I’d put together a short tutorial on how to draw a snowflake using JavaScript and the HTML canvas element.</p>
<p>Here’s what the final product will look like:</p>
<p><img src="/images/posts/2013/11/snowflake1.png" alt="Snowflake" title="Snowflake" /></p>
<p>If you’d like to try this out on your own, here’s what you’ll need:</p>
<ul>
<li>A text editor. Notepad.exe will work fine for this.</li>
<li>A browser that supports the HTML 5 canvas element. This can be any one of the following browsers:</li>
</ul>
<table>
<tbody>
<tr>
<td><strong>Browser</strong></td>
<td><strong>Version</strong></td>
</tr>
<tr>
<td>Chrome</td>
<td>≥ 29.0</td>
</tr>
<tr>
<td>Firefox</td>
<td>≥ 23.0</td>
</tr>
<tr>
<td>Internet Explorer</td>
<td>≥ 9.0</td>
</tr>
<tr>
<td>Safari</td>
<td>≥ 5.1</td>
</tr>
</tbody>
</table>
<h2 id="the-basics">The Basics</h2>
<p>To get started, we’ll create a basic HTML document with a canvas element, script tag and a simple draw function. Open your text editor program and type in, or copy and paste, the following:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="o"><!</span><span class="nx">DOCTYPE</span> <span class="nx">html</span><span class="o">></span>
<span class="o"><</span><span class="nx">html</span><span class="o">></span>
<span class="o"><</span><span class="nx">head</span><span class="o">></span>
<span class="o"><</span><span class="nx">title</span><span class="o">></span><span class="nx">Snowflake</span><span class="o"><</span><span class="sr">/title</span><span class="err">>
</span><span class="o"><</span><span class="nx">script</span> <span class="nx">type</span><span class="o">=</span><span class="dl">"</span><span class="s2">text/javascript</span><span class="dl">"</span><span class="o">></span>
<span class="kd">function</span> <span class="nx">draw</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">canvas</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">myCanvas</span><span class="dl">'</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">canvas</span><span class="p">.</span><span class="nx">getContext</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">context</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">getContext</span><span class="p">(</span><span class="dl">'</span><span class="s1">2d</span><span class="dl">'</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="o"><</span><span class="sr">/script</span><span class="err">>
</span><span class="o"><</span><span class="sr">/head</span><span class="err">>
</span><span class="o"><</span><span class="nx">body</span> <span class="nx">onload</span><span class="o">=</span><span class="dl">"</span><span class="s2">draw();</span><span class="dl">"</span><span class="o">></span>
<span class="o"><</span><span class="nx">canvas</span> <span class="nx">width</span><span class="o">=</span><span class="dl">"</span><span class="s2">640</span><span class="dl">"</span> <span class="nx">height</span><span class="o">=</span><span class="dl">"</span><span class="s2">640</span><span class="dl">"</span> <span class="nx">id</span><span class="o">=</span><span class="dl">"</span><span class="s2">myCanvas</span><span class="dl">"</span><span class="o">><</span><span class="sr">/canvas</span><span class="err">>
</span><span class="o"><</span><span class="sr">/body</span><span class="err">>
</span><span class="o"><</span><span class="sr">/html></span></code></pre></figure>
<p>Now save this as an HTML document, for example, snowflake.html. Make sure that the extension is .html and not .txt. After you save the file, you could open it in a browser, but unfortunately you won’t see much at this point. This will be the framework around which we’ll build the rest of our snowflake drawing program.</p>
<p>Things to note:</p>
<ul>
<li>Line 17: Our canvas element, on which we’ll be drawing our snowflake, has been given an ID of “myCanvas” and is 640 by 640 pixels.</li>
<li>Line 16: The JavaScript <strong>draw</strong> function is called after the page is loaded.</li>
<li>Line 8: In our <strong>draw</strong> function, a reference to the canvas element is obtained from the document object using the method <strong>getElementById</strong>.</li>
<li>Line 10: The 2D drawing context is obtained from the canvas element by calling its <strong>getContext</strong> method. If available, the context can then be used to draw to the canvas element.</li>
</ul>
<p>The context is the 2D Cartesian surface with its origin represented by the coordinates (0,0) in the upper left corner. The y-coordinate increases as we move downward and the x-coordinate increases as we move to the right. In our example, the lower right coordinates for the 2D canvas context are (640,640), as shown below:</p>
<p><img src="/images/posts/2013/11/00_grid_with_points.png" alt="Cartesian Grid" title="Cartesian Grid" /></p>
<h2 id="snowflake-symmetry">Snowflake Symmetry</h2>
<p>What do we know about a snowflake? They’re ice crystals that form with six, generally symmetric, arms. To draw our snowflake we’ll have six evenly distributed lines radiating from the center of our drawing. Imagine that our snowflake sits within a circle, each arm extends from the center of the circle to the outer edge of the circle. Since a circle is 360°, or 2π radians, the angle between each arm is 60°, or π/3 radians, as illustrated below:</p>
<p><img src="/images/posts/2013/11/six_slices_of_a_pie.png" alt="Six Sections of a Circle" title="Six Sections of a Circle" /></p>
<h2 id="translation-please">Translation Please</h2>
<p>To make things easier for us, the 2D context object provides the <strong>translate</strong> method which shifts the 2D context to a new position. The advantage of this is that we can locate the origin wherever we want to by using <strong>translate</strong>, rather than calculating the offset from the upper left corner of the drawing surface. In our case it would be really helpful to relocate the origin to the center of the drawing surface. We can do this by calling the translate function with the new x and y coordinates for the origin. Since our canvas is 640 pixels wide and 640 pixels high, the midpoint is (320,320), which is where we want our new origin, as shown in the illustration below:</p>
<p><img src="/images/posts/2013/11/01_grid_translate.png" alt="Translate Context"" title="Translate Context" /></p>
<p>Now, we were easily able to determine what the midpoint should be because we’d specifically defined our canvas with dimensions of 640px x 640px, but what if we decide to change those dimensions in the future? Wouldn’t it be easier to have our program calculate the midpoint for us? Since we’ve obtained a reference to the canvas element using the function <strong>getElementByID</strong>, we can get the width and height properties of the element and store those in variables named <strong>width</strong> and <strong>height</strong>. We can then calculate the midpoint where we would like to translate the 2D context to as <strong>width/2</strong> and <strong>height/2</strong>:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="kd">function</span> <span class="nx">draw</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">canvas</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">myCanvas</span><span class="dl">'</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">canvas</span><span class="p">.</span><span class="nx">getContext</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">context</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">getContext</span><span class="p">(</span><span class="dl">'</span><span class="s1">2d</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">width</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">width</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">height</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">height</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">translate</span><span class="p">(</span><span class="nx">width</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span><span class="nx">height</span><span class="o">/</span><span class="mi">2</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<h2 id="painting-a-path-with-brush-strokes">Painting a Path with Brush Strokes</h2>
<p>There are two steps to drawing a line, first we must define a path, then we can make it visible by applying a brush stroke. To accomplish this, we’ll use the context methods <strong>beginPath</strong>, <strong>moveTo</strong>, <strong>lineTo</strong> and <strong>stroke</strong> to draw our line.</p>
<p>When starting a new path, we must call the method <strong>beginPath</strong> first. The function <strong>moveTo</strong> establishes where our path will start from, in our case we want to start from the origin (0,0), so we call the <strong>moveTo</strong> method with those coordinates. Next, we’ll call <strong>lineTo</strong> with the coordinates of the point to which we want to draw a line (300,0). Finally, we can apply a brush stroke to the path to make it visible by calling <strong>stroke</strong>.</p>
<p><img src="/images/posts/2013/11/02_grid_lineTo.png" alt="Drawing a Line" title="Drawing a Line" /></p>
<p>When we put it all together, our draw function now looks like:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="kd">function</span> <span class="nx">draw</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">canvas</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">myCanvas</span><span class="dl">'</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">canvas</span><span class="p">.</span><span class="nx">getContext</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">context</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">getContext</span><span class="p">(</span><span class="dl">'</span><span class="s1">2d</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">width</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">width</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">height</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">height</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">translate</span><span class="p">(</span><span class="nx">width</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span><span class="nx">height</span><span class="o">/</span><span class="mi">2</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">beginPath</span><span class="p">();</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">moveTo</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">lineTo</span><span class="p">(</span><span class="mi">300</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">stroke</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>Edit the <strong>draw</strong> function as shown above and then save your snowflake.html file. If you open the document in a browser now, you should see the line that we just drew:</p>
<p><img src="/images/posts/2013/11/first_line-580x578.png" alt="First Line" title="First Line" /></p>
<p>That doesn’t look like much, does it? We can dress this up a little bit by changing the background color, the color and width of the line and the line end cap style.</p>
<p><strong>Try it out</strong>:</p>
<ul>
<li>How can you change the length of the line?</li>
<li>How can you change where the line starts from? For example, instead of starting from the origin (0,0) pick a different point, what happens?</li>
<li>What if you remove the line that reads <strong>context.translate(width/2, height/2)</strong>? Where is the line drawn? Try experimenting with different coordinates for the <strong>translate</strong> command.</li>
</ul>
<h2 id="adding-some-style">Adding Some Style</h2>
<p>Colors are defined in terms of red, green and blue components. The minimum value that can be assigned to a color component is 0, the maximum is 255 or FF in hexadecimal (base-16). When specifying a color using hexadecimal notation, the value is prefixed with the # character. To get bright red, the red component is set to to its maximum value (FF), while the green and blue components are set to their minimum values (00), giving us “#FF0000”, likewise bright green is “#00FF00” and bright blue is “#0000FF”. To get pure white, all three components are set to their maximum values, “#FFFFFF”, while to get black, they are all set to their minimum values, “#000000”.</p>
<p>For this project, I chose a dark blue which includes red and green components as well as blue “#162D50”. For the brush stroke color for the line, I chose white “#FFFFFF”. You can experiment with changing these values to get colors that you like, or you can choose a color using a <a href="https://www.w3schools.com/colors/colors_picker.asp" title="color picker tool" target="_blank">color picker tool</a>.</p>
<p>The context property <strong>strokeStyle</strong> can be used to set the color of the brush that we use to paint the path with. Likewise, the context property <strong>fillStyle</strong> can be used to set the color that we use to fill in a shape with. We’ll use this property with the method <strong>fillRect</strong> to set the background color of our canvas. The property <strong>lineWidth</strong> sets the width of the brush in pixels, and <strong>lineCap</strong> sets the style of the end caps for the line. The lineCap can be set to “butt”, “round”, or “square”. For our snowflake I’ve chosen to use a round end cap to each line.</p>
<p>The updated draw method, shown below, sets the properties for the fill and stroke, and draws a rectangle the size of the canvas using the dark blue fill color.</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="kd">function</span> <span class="nx">draw</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">canvas</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">myCanvas</span><span class="dl">'</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">canvas</span><span class="p">.</span><span class="nx">getContext</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">context</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">getContext</span><span class="p">(</span><span class="dl">'</span><span class="s1">2d</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">width</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">width</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">height</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">height</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">lineWidth</span> <span class="o">=</span> <span class="mi">20</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">lineCap</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">round</span><span class="dl">'</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">fillStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">#162D50</span><span class="dl">"</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">strokeStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">#FFFFFF</span><span class="dl">"</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">fillRect</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="nx">width</span><span class="p">,</span><span class="nx">height</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">translate</span><span class="p">(</span><span class="nx">width</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span><span class="nx">height</span><span class="o">/</span><span class="mi">2</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">beginPath</span><span class="p">();</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">moveTo</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">lineTo</span><span class="p">(</span><span class="mi">300</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">stroke</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>If you update the <strong>draw</strong> function with the code shown above and save the file, when you view the result in a browser you should see something similar to this:</p>
<p><img src="/images/posts/2013/11/snowflake_01.png" alt="First Line with Color" title="First Line with Color" /></p>
<p>That’s better, but it’s still not much, is it?</p>
<p><strong>Try it out</strong>:</p>
<ul>
<li>Pick another set of colors for the background and line color.</li>
<li>Change the width of the line.</li>
<li>Change the end cap style to “butt” or “square”</li>
</ul>
<h2 id="rotation">Rotation</h2>
<p>Recall that previously we had said that a snowflake has six arms that are distributed evenly, and that the angle between each arm is 60°, or π/3 radians. Therefore, our next step will be to draw another line, starting from the origin, and forming an angle of 60° with our first line. Thankfully, the context object provides us with another method, <strong>rotate</strong>, that makes our lives easier when it comes to this. Just as we had redefined the origin by using the <strong>translate</strong> method to move the context, we can employ the <strong>rotate</strong> method to turn the entire context a specified angle in radians relative to its existing position, as shown below:</p>
<p><img src="/images/posts/2013/11/03_grid_rotate.png" alt="Rotate Context" title="Rotate Context" /></p>
<p>Now that we’ve rotated the context, we can draw our second line. Since the origin remains the same as with our first line, the code to draw our second line is exactly the same as our first line:</p>
<p><img src="/images/posts/2013/11/04_grid_lineTo_2.png" alt="Drawing a Second Line" title="Drawing a Second Line" /></p>
<p>Here’s our updated <strong>draw</strong> function:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="kd">function</span> <span class="nx">draw</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">canvas</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">myCanvas</span><span class="dl">'</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">canvas</span><span class="p">.</span><span class="nx">getContext</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">context</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">getContext</span><span class="p">(</span><span class="dl">'</span><span class="s1">2d</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">width</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">width</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">height</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">height</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">lineWidth</span> <span class="o">=</span> <span class="mi">20</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">lineCap</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">round</span><span class="dl">'</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">fillStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">#162D50</span><span class="dl">"</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">strokeStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">#FFFFFF</span><span class="dl">"</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">fillRect</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="nx">width</span><span class="p">,</span><span class="nx">height</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">translate</span><span class="p">(</span><span class="nx">width</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span><span class="nx">height</span><span class="o">/</span><span class="mi">2</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">beginPath</span><span class="p">();</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">moveTo</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">lineTo</span><span class="p">(</span><span class="mi">300</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">stroke</span><span class="p">();</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">rotate</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">PI</span><span class="o">/</span><span class="mi">3</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">beginPath</span><span class="p">();</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">moveTo</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">lineTo</span><span class="p">(</span><span class="mi">300</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">stroke</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>Update the draw function and save the file. When you view the result in the browser you should see the second arm of our snowflake:</p>
<p><img src="/images/posts/2013/11/snowflake_02.png" alt="Snowflake with Two Arms" title="Snowflake with Two Arms" /></p>
<p>Now we’re getting somewhere!</p>
<h2 id="wash-rinse-repeat">Wash, Rinse, Repeat</h2>
<p>To draw the next arm, we perform the same steps once again. First we rotate the context:</p>
<p><img src="/images/posts/2013/11/05_grid_rotate_2.png" alt="Second Rotation" title="Second Rotation" /></p>
<p>Then we draw a line:</p>
<p><img src="/images/posts/2013/11/06_grid_lineTo_3.png" alt="Third Line" title="Third Line" /></p>
<p>Here’s what the code should look like now:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="kd">function</span> <span class="nx">draw</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">canvas</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">myCanvas</span><span class="dl">'</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">canvas</span><span class="p">.</span><span class="nx">getContext</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">context</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">getContext</span><span class="p">(</span><span class="dl">'</span><span class="s1">2d</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">width</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">width</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">height</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">height</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">lineWidth</span> <span class="o">=</span> <span class="mi">20</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">lineCap</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">round</span><span class="dl">'</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">fillStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">#162D50</span><span class="dl">"</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">strokeStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">#FFFFFF</span><span class="dl">"</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">fillRect</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="nx">width</span><span class="p">,</span><span class="nx">height</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">translate</span><span class="p">(</span><span class="nx">width</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span><span class="nx">height</span><span class="o">/</span><span class="mi">2</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">beginPath</span><span class="p">();</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">moveTo</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">lineTo</span><span class="p">(</span><span class="mi">300</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">stroke</span><span class="p">();</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">rotate</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">PI</span><span class="o">/</span><span class="mi">3</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">beginPath</span><span class="p">();</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">moveTo</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">lineTo</span><span class="p">(</span><span class="mi">300</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">stroke</span><span class="p">();</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">rotate</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">PI</span><span class="o">/</span><span class="mi">3</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">beginPath</span><span class="p">();</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">moveTo</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">lineTo</span><span class="p">(</span><span class="mi">300</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">stroke</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<h2 id="getting-loopy">Getting Loopy</h2>
<p>Are you noticing a pattern? This is getting awfully repetitive, isn’t it? To save ourselves the trouble of typing the same thing over and over again, we can use a <strong>for</strong> loop instead. The <strong>for</strong> loop requires that we provide three statements: a statement that gets executed prior to the start of the loop, a condition which must be met to continue the loop, and a statement that gets executed after each pass through the loop. In our case, we want to execute the code that draws the line and rotates the context six times. We’ll use a variable to keep track of how many times to execute the block of code, let’s call it count. We’ll set it to zero initially, check to see that it is less than six in order to continue our loop, and add one to it after each pass. We’ll put the code that we want to execute repeatedly within the loop block.</p>
<p>The new version of our <strong>draw</strong> function that uses a <strong>for</strong> loop now looks like this:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="kd">function</span> <span class="nx">draw</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">canvas</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">myCanvas</span><span class="dl">'</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">canvas</span><span class="p">.</span><span class="nx">getContext</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">context</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">getContext</span><span class="p">(</span><span class="dl">'</span><span class="s1">2d</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">width</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">width</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">height</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">height</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">lineWidth</span> <span class="o">=</span> <span class="mi">20</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">lineCap</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">round</span><span class="dl">'</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">fillStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">#162D50</span><span class="dl">"</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">strokeStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">#FFFFFF</span><span class="dl">"</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">fillRect</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="nx">width</span><span class="p">,</span><span class="nx">height</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">translate</span><span class="p">(</span><span class="nx">width</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span><span class="nx">height</span><span class="o">/</span><span class="mi">2</span><span class="p">);</span>
<span class="k">for</span><span class="p">(</span><span class="kd">var</span> <span class="nx">count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">count</span> <span class="o"><</span> <span class="mi">6</span><span class="p">;</span> <span class="nx">count</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">beginPath</span><span class="p">();</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">moveTo</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">lineTo</span><span class="p">(</span><span class="mi">300</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">stroke</span><span class="p">();</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">rotate</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">PI</span><span class="o">/</span><span class="mi">3</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span></code></pre></figure>
<p>Things to note:</p>
<ul>
<li>Line 13: Starts our <strong>for</strong> loop. The first statement “var count = 0;” declares the variable count and sets it equal to zero. The next statement “count < 6;” is the condition that must be met for the loop to continue. The last statement “count++;” adds one to the count variable after each pass through the loop. The ++ notation is shorthand for count = count + 1.</li>
<li>Lines 14-17: This is the code that we want to execute during each pass of the loop. First we draw our line, then we rotate the context. Note that the block of code to be executed must be enclosed by curly braces { }.</li>
</ul>
<p>If you change your draw function and view the result in a browser you should now see all six arms of our snowflake:</p>
<p><img src="/images/posts/2013/11/Snowflake_06.png" alt="Snowflake with Six Arms" title="Snowflake with Six Arms" /></p>
<p><strong>Try it out</strong>:</p>
<ul>
<li>Can you change the number of arms that are drawn? Can you draw 8 arms, 12 arms? Where do you need to make changes in order to get the correct number of arms drawn?</li>
<li>What happens when you change the starting point for each line? For example, what happens when you change the starting point from (0,0) to (0,50)? What about (50,0)? Try experimenting with different values.</li>
<li>EXTRA CREDIT 1: Can you gradually increase the length of each arm from zero up to the full 300 pixel length? HINT: Think about how you can use the count variable here.</li>
<li>EXTRA CREDIT 2: Can you draw two different sets of lines, an inner line and an outer line? How can you get the program to draw the picture shown below?</li>
</ul>
<p><img src="/images/posts/2013/11/extra_credit_2.png" alt="Extra Credit 2" title="Extra Credit 2" /></p>
<h2 id="branches">Branches</h2>
<p>What we have now is nice, but it doesn’t really look like the snowflake at the start of this article, does it? It’s missing something…</p>
<p>We’re going to use the <strong>translate</strong> and <strong>rotate</strong> methods that we had used earlier to add branches to the arms of our snowflake. First we’ll draw a segment of our line and then we’ll translate the context so that the origin is the endpoint of the line. Next we’ll rotate the context and draw one branch, then we’ll rotate in the opposite direction and draw the second branch.</p>
<p>To make this code somewhat easier to read, we’ll break up these tasks by writing two new functions, <strong>drawSegment</strong> and <strong>drawBranch</strong>. We’ll call <strong>drawSegment</strong> three times to draw each of the segments of our snowflake arm. In turn, the <strong>drawSegment</strong> function will call the <strong>drawBranch</strong> function twice, once for each direction that we are drawing the branch.</p>
<p>Here’s the final version of the <strong>draw</strong> function as well as the two new functions <strong>drawSegment</strong> and <strong>drawBranch</strong>:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="kd">function</span> <span class="nx">draw</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">canvas</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">myCanvas</span><span class="dl">'</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">canvas</span><span class="p">.</span><span class="nx">getContext</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">context</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">getContext</span><span class="p">(</span><span class="dl">'</span><span class="s1">2d</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">width</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">width</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">height</span> <span class="o">=</span> <span class="nx">canvas</span><span class="p">.</span><span class="nx">height</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">lineWidth</span> <span class="o">=</span> <span class="mi">20</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">lineCap</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">round</span><span class="dl">'</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">fillStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">#162D50</span><span class="dl">"</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">strokeStyle</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">#FFFFFF</span><span class="dl">"</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">fillRect</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="nx">width</span><span class="p">,</span><span class="nx">height</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">translate</span><span class="p">(</span><span class="nx">width</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span><span class="nx">height</span><span class="o">/</span><span class="mi">2</span><span class="p">);</span>
<span class="k">for</span><span class="p">(</span><span class="kd">var</span> <span class="nx">count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">count</span> <span class="o"><</span> <span class="mi">6</span><span class="p">;</span> <span class="nx">count</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">save</span><span class="p">();</span>
<span class="nx">drawSegment</span><span class="p">(</span><span class="nx">context</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="mi">40</span><span class="p">);</span>
<span class="nx">drawSegment</span><span class="p">(</span><span class="nx">context</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="mi">80</span><span class="p">);</span>
<span class="nx">drawSegment</span><span class="p">(</span><span class="nx">context</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">restore</span><span class="p">();</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">rotate</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">PI</span><span class="o">/</span><span class="mi">3</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">drawSegment</span><span class="p">(</span><span class="nx">context</span><span class="p">,</span> <span class="nx">segmentLength</span><span class="p">,</span> <span class="nx">branchLength</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">beginPath</span><span class="p">();</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">moveTo</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">lineTo</span><span class="p">(</span><span class="nx">segmentLength</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">stroke</span><span class="p">();</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">translate</span><span class="p">(</span><span class="nx">segmentLength</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">branchLength</span> <span class="o">></span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">drawBranch</span><span class="p">(</span><span class="nx">context</span><span class="p">,</span> <span class="nx">branchLength</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="nx">drawBranch</span><span class="p">(</span><span class="nx">context</span><span class="p">,</span> <span class="nx">branchLength</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">drawBranch</span><span class="p">(</span><span class="nx">context</span><span class="p">,</span> <span class="nx">branchLength</span><span class="p">,</span> <span class="nx">direction</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">save</span><span class="p">();</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">rotate</span><span class="p">(</span><span class="nx">direction</span><span class="o">*</span><span class="nb">Math</span><span class="p">.</span><span class="nx">PI</span><span class="o">/</span><span class="mi">3</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">moveTo</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">lineTo</span><span class="p">(</span><span class="nx">branchLength</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">stroke</span><span class="p">();</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">restore</span><span class="p">();</span>
<span class="p">}</span></code></pre></figure>
<p>Things to note:</p>
<ul>
<li>Line 14: We introduced the context <strong>save</strong> method here. This function saves the current attributes of our context so that it can be restored at a later point. This allows us to apply translations and rotations to the context without affecting operations that follow, as long as we restore to the point at which we saved the context.</li>
<li>Lines 15-17: The new <strong>drawSegment</strong> function is called three times. For each call we pass in the context and a segmentLength of 100 pixels. The branchLength is set to 40 pixels on the first call, 80 pixels on the second call and on the third call it is zero, meaning that no branches should be drawn.</li>
<li>Line 18: The context <strong>restore</strong> method is called to restore the original context so that the next arm can be drawn.</li>
<li>Lines 25-28: The <strong>drawSegment</strong> function starts by drawing a line.</li>
<li>Line 29: The origin is moved to the endpoint of the line that was just drawn by calling <strong>translate</strong>.</li>
<li>Lines 30-33: If the branchLength is greater than zero, we call the <strong>drawBranch</strong> function twice, changing direction on the second call. The direction can be either 1 or -1 to indicate right or left.</li>
<li>Lines 36-43: In our <strong>drawBranch</strong> function the context is first saved, then it is rotated in the specified direction, either right (1) or left (-1). A line is drawn, and finally the context is restored.</li>
</ul>
<p>If you enter the code and save the updated file, when you view the HTML document in your browser you should see the completed snowflake:</p>
<p><img src="/images/posts/2013/11/snowflake1.png" alt="Snowflake" title="Snowflake" /></p>
<p><strong>Try it out</strong>:</p>
<ul>
<li>Try changing the length of the segments and the branches. What happens if you put branches on the last segment?</li>
<li>Try adding another segment to each arm. What do you have to do to the lengths of each segment?</li>
<li>EXTRA CREDIT: Rather than using a fixed value of 100 pixels for segment length, can you calculate the segment length as a ratio of the canvas width?</li>
</ul>
<h2 id="final-thoughts">Final Thoughts</h2>
<p>Thanks for following along, I hope you were able to get your program to draw a snowflake, and that you tried to experiment with the code to see how it affects the drawing. Good luck and keep experimenting!</p>
<p>The complete source code for this project is maintained at:</p>
<p><a href="https://github.com/rmlysik/javascript-snowflake" title="JavaScript Snowflake" target="_blank">JavaScript Snowflake</a></p>Robert LysikIt’s getting to be that time of the year again. Soon I’ll have to break out the shovel, but before then, I thought I’d put together a short tutorial on how to draw a snowflake using JavaScript and the HTML canvas element.Touch Tomorrow at WPI2013-06-16T09:43:56-04:002013-06-16T09:43:56-04:00https://www.robertlysik.com/robotics/wpi/engineering/touch-tomorrow-at-wpi<p>On Saturday, June 8th we visited <a href="https://www.wpi.edu/" title="Worcester Polytechnic Institute" target="_blank">Worcester Polytechnic Institute</a> (WPI) in Worcester, Massachusetts for the <a href="https://wp.wpi.edu/touchtomorrow/" title="Touch Tomorrow" target="_blank">Touch Tomorrow</a> festival. This was a free all day science, technology and robotics festival. Thankfully the weather was beautiful making it a wonderful day to visit the campus and take in all the exhibits.</p>
<p>We arrived at the WPI campus around 11:00, and after parking in the parking garage off Salisbury Street, we made our way to the main campus. As we left the parking garage there were some folks from WPI who greeted us, gave the kids Mission Cards with a schedule of events, and provided us with bracelets that showed we were visiting for the Touch Tomorrow festival. They also let us know that we could download the <a href="https://guidebook.com/" title="Guidebook" target="_blank">Guidebook</a> smart phone app which had the event schedule, campus map and other festival information.</p>
<p><img src="/images/posts/2013/06/Touch-Tomorrow-Mission-Card-580x401.jpg" alt="Touch Tomorrow Mission Card" title="Touch Tomorrow Mission Card" /></p>
<p>After climbing the steps from the parking garage area up to the main campus (whew!) our first stop was, you guessed it, the rest rooms at the Sports and Recreation Center building, which just happened to be adjacent to the stairway leading from the parking garage. Inside the main hall was set up with a number of exhibits related to robotics, space exploration and science, but our tummies were grumbling (especially mine) so we opted to look for someplace to get something to eat first.</p>
<p>On the way to look for a place to eat we met up with my wife’s cousin, his wife and their three children. We then found our way over to the Campus Center where there is a wonderful cafeteria on the lower level. After filling up we headed off to visit the festival exhibits.</p>
<h2 id="mars-colonization">Mars Colonization</h2>
<p>On the main floor of the Campus Center there were also some exhibits set up. At one there was a gentleman discussing the prospects for colonization of Mars. He asked my son if he would be interested in going to Mars to live. However, it would be a one-way trip, he cautioned, since the expense of a return trip would make it impractical. What did he think, would he like to go? My son looked a bit scared at the prospect, probably a sensible attitude :)</p>
<p>What would living on Mars be like? I suspect that some people would be enthusiastic about the prospect of living on Mars. Would it be ethical to try to raise a family there, however? As an adult traveling to Mars one would still hold in memory what life on Earth was like, and so that might make life bearable, but what about a child who only knows the confines of an underground bunker designed to shield them from the harsh environment of Mars? Their only knowledge of Earth would be through pictures and video. Would that be enough to satisfy them, or would their curiosity demand that they travel to Earth? What if they couldn’t return? Sounds like the short story “The Million-Year Picnic” by Ray Bradbury, except that the real Mars is not quite as bucolic as the Mars of Bradbury’s fiction.</p>
<h2 id="mm-math">M&M Math</h2>
<p>Just outside the Campus Center a table was set up with the M&M Math activity which the kids participated in. Here is where we also met up with another of Thao’s cousins, his wife and their two children. Altogether our gaggle of kids now included five girls and two boys. At the M&M Math activity table each child was given a worksheet and a bag of M&Ms. They were then supposed to open the bag and use the M&Ms to answer basic arithmetic questions. One of the questions, at the end of the worksheet, instructed them to “Put two M&Ms in your mouth”, and then asked “How many are left over?” If only all math was taught this way!</p>
<p><img src="/images/posts/2013/06/MM-Math-580x797.jpg" alt="M&M Math Worksheet" title="M&M Math Worksheet" /></p>
<h2 id="computer-games-and-animation">Computer Games and Animation</h2>
<p>Next we visited the Fuller Laboratories building where there was an exhibit showcasing projects by students enrolled in the <a href="https://www.wpi.edu/academics/departments/interactive-media-game-development" title="Interactive Media and Game Development" target="_blank">Interactive Media and Game Development</a> (IMGD) program at WPI. My son was especially interested in this since he wants to pursue game development as a career.</p>
<p>The computer lab was set up with a number of different games that the students had created. My daughter especially liked one game that let you make a pizza, while my son was engrossed by another game where you played the part of a fish trying to escape from a sushi chef. We also had a chance to try a game that was similar to Portal that enabled you to explore a virtual world.</p>
<p><img src="/images/posts/2013/06/IMG_1564-580x433.jpg" alt="Playing Computer Games at the IMGD Lab" title="Playing Computer Games at the IMGD Lab" /></p>
<p>While there, I had the opportunity to talk with a recent graduate of the IMGD program. She explained that there are basically two tracks in the IMGD program, one devoted to animation and art, and one devoted to programming. She had initially been interested in the art aspects of game development, but had then switched to the programming track. Interestingly, upon graduation she had taken a job as a software developer with a company that specialized in electrical engineering. I had so many more questions to ask her, but unfortunately by then everyone was ready to move on to the next exhibit. In particular, I wondered how successful graduates of the IMGD program were at obtaining employment with game development companies. Did she decide that game development wasn’t for her, and why? Did WPI help graduates get internships with game development companies? Are the prospects for game developers not as good as for general software development? Hmmm… is game development a viable career option?</p>
<h2 id="student-robotics-exhibit">Student Robotics Exhibit</h2>
<p>After leaving the Fuller Lab building, we stopped next door at the Atwater Kent Lab where a student robotics exhibit had been set up. There the kids were able to navigate a small robot using an iPad. Another robot was set up to mimic the motion of participants and in an adjoining room, a table was set up with various remote controlled robots that the kids could drive. Downstairs two large research robots, Archie and Baxter, were on display.</p>
<h2 id="scale-of-the-universe-presentation">Scale of the Universe Presentation</h2>
<p><img src="/images/posts/2013/06/Screen-Shot-2013-06-14-at-2.46.34-PM-580x290.png" alt="The Scale of the Universe 2" title="The Scale of the Universe 2" /></p>
<p>At Olin Hall, on the way back from the Atwater Kent Lab, we sat in on a presentation about the scale of the universe. A professor from WPI led a tour of the universe from the the everyday scale of people and houses to the very large scale of planets, stars, and galaxies. He then reversed course and explored the very tiny world of bacteria, viruses, atoms, electrons, quarks, finally stopping at the quantum foam. The presentation was assisted by the wonderful web based interactive animation <a href="http://htwins.net/scale2/" title="The Scale of the Universe 2" target="_blank">The Scale of the Universe 2</a> developed by Cary and Michael Huang that is reminiscent of the <a href="https://www.eamesoffice.com/the-work/powers-of-ten/" title="Powers of 10" target="_blank">Powers of 10</a> film by Charles and Ray Eames. Our favorite new words from the presentation are yottameter (10<sup>24</sup> meters), yoctometer (10<sup>-24</sup> meters), and the Eridanus Supervoid :)</p>
<h2 id="exhibition-hall">Exhibition Hall</h2>
<p>We made our way back to the Sports and Recreation Center which was being used as the main exhibition area. Inside there were many tables set up by all sorts of organizations, from the <a href="http://www.worcesterhistory.org/" title="Worcester Historical Museum" target="_blank">Worcester Historical Museum</a>, VEX Robotics, iRobot Corporation and the Discovery Museums, among others. The Worcester Historical Museum had an exhibit with information about Worcester’s links to the space program, especially <a href="https://en.wikipedia.org/wiki/Robert_H._Goddard" title="Robert H. Goddard" target="_blank">Robert H. Goddard</a>, builder of the first liquid fueled rocket and a graduate of WPI. There was also a table where you could find out more about summer programs for kids at WPI, including game programming and robotics. The kids were also able to get their photos as astronauts:</p>
<p><img src="/images/posts/2013/06/Touch-Tomorrow-Michael-Astronaut-580x380.jpg" alt="Touch Tomorrow - Astronaut" title="Touch Tomorrow - Astronaut" /></p>
<h2 id="robot-band-and-festival-close">Robot Band and Festival Close</h2>
<p>Our final stop was the Quad where there was a performance of a robot band being held. On the Quad there was also a wooden mock-up of the NASA Mars Curiosity Rover, as well as a functioning exploration rover. The kids were even invited to lay down side-by-side while the rover was navigated over them via remote control!
After the close of the festival at 4:00 we hung around on the quad while the kids had fun playing tag. We then stopped for dinner at Ruby Tuesday where the kids were able to sit all together at a really long table before heading off on the long ride back home.</p>
<h2 id="guidebook-app">Guidebook App</h2>
<p>Throughout the day, I was regularly referring to the Guidebook app on my iPhone where I could look up event listings for the festival and view a campus map of WPI. I think providing the festival information using the iPhone app was a nice idea and went well with the overall technology theme of the event.
In using the app, however, I found it a bit difficult to navigate using the provided map. The map was essentially the same PDF document that is available from the main WPI website, so it wasn’t ideal for viewing on the small screen of an iPhone. In addition, I had to switch back and forth between the event listings and the map in order to figure out where to go and how to get there.</p>
<p>Even though I like the app, I think there may be some room for improvement that would make using this app even more useful. In particular:</p>
<ul>
<li>Let users plan their visit by selecting events that interest them, thereby creating a personal itinerary that they can refer to throughout their visit.</li>
<li>Use GPS to provide customized directions between your current location and the location of the next venue on your itinerary.</li>
<li>Help users quickly find rest rooms, food and first-aid using GPS assisted directions. This would be especially helpful for parents with kids in tow :)</li>
</ul>
<p>I suspect that the GPS enabled instructions and tailoring the map for display on a smart phone are not trivial enhancements. This would definitely be an interesting project, though, and would make the app a lot more useful than a printed brochure.</p>
<h2 id="final-thoughts">Final Thoughts</h2>
<p>We all had a great time at the Touch Tomorrow festival. It was my first time visiting WPI and I thought that the campus was really beautiful. There were plenty of fun and interesting activities to keep everyone busy the entire day, and best of all, it was free! We’re looking forward to attending the festival next year.</p>Robert LysikOn Saturday, June 8th we visited Worcester Polytechnic Institute (WPI) in Worcester, Massachusetts for the Touch Tomorrow festival. This was a free all day science, technology and robotics festival. Thankfully the weather was beautiful making it a wonderful day to visit the campus and take in all the exhibits.Processing Monsters Meets Career Day2012-11-22T17:53:42-05:002012-11-22T17:53:42-05:00https://www.robertlysik.com/scratch/processing/generative%20art/processing-monsters-meets-career-day<p>It was almost exactly four years ago, back in December of 2008, that I was invited to give a brief talk to the Career Club at my son’s elementary school about the profession of Software Engineering. At the time I had been reading Daniel Shiffman’s book <a href="http://learningprocessing.com/" title="Learning Processing" target="_blank">Learning Processing</a> and was thinking about how the Processing programming language could be used as a tool for introducing kids to programming.</p>
<p>The Career Club was organized by one of the teachers at the elementary school and consisted of kids in the fifth and sixth grades who were interested enough in learning about career paths that they were willing to give up their recess to hear folks like me blather on about what they did for a living. I felt it would be safe to come in as a presenter since my son, at the time, was in Kindergarten so I was in no danger of humiliating him with my presence at his school.</p>
<h3 id="on-being-a-software-engineer">On Being a Software Engineer</h3>
<p>The obligatory first part of my presentation dealt with standard questions about my career choice.</p>
<p><strong>What is Software Engineering?</strong></p>
<p>I apologize, but I fell back on Wikipedia here, “software engineering is the application of a systematic, disciplined, quantifiable approach to the development, operation, and maintenance of software.” What does that mean exactly? Software engineers don’t just write code all willy-nilly, they employ a process so they can ensure that what they develop meets their customer’s needs and is of the highest possible quality. A simplification I know…but that’s the general idea, no?</p>
<p><strong>What is a typical day like?</strong></p>
<p>Oddly enough, my days mainly consist of supporting existing systems: making updates as required, tracking down and fixing bugs that may raise their ugly little heads, adding new features that our customers ask for. On occasion I’ll have the opportunity to work on developing an entirely new application. This is where the full software engineering process comes into play, with requirements gathering, analysis and design, implementation, testing, and deployment.</p>
<p><strong>How did I become interested in Software Engineering?</strong></p>
<p>The earliest experience that was related to my future career was writing programs in APL (yes, that <a href="https://en.wikipedia.org/wiki/APL_(programming_language)APL" title="APL" target="_blank">APL</a>) at a summer camp at a local university. I don’t remember exactly when this was, though it was probably in middle school. Despite being simplistic programs (e.g. calculate the area of a circle, convert temperature from Fahrenheit to Celsius) I thought this was very cool. Probably the most appealing thing about it was that I could control what the computer did by writing a short program. At about the same time my parents had bought an Apple II computer which I used to tap out programs in the BASIC programming language. Nothing earth shattering here, mainly simple games. I did write a program for keeping track of the money that my paper route customers owed me, though.</p>
<p><strong>How do you become a Software Engineer?</strong></p>
<p>The path I recommended was to pursue an undergraduate degree in Computer Science followed by graduate work in Software Engineering. This is, essentially, the route I had followed, though it was a bit more complicated along the way for me. If you’re fortunate enough you may get to work for a company that will cover your graduate degree education expenses as mine had.</p>
<h3 id="introducing-processing-and-scratch">Introducing Processing and Scratch</h3>
<p>This was only a twenty minute presentation, mind you, and I wanted to give the kids something more than a dry talk about Software Engineering so I switched gears at this point to do a demo of two of the most accessible programming languages out there at the time, <a href="https://www.processing.org/" title="Processing" target="_blank">Processing</a> and <a href="https://scratch.mit.edu/" title="Scratch" target="_blank">Scratch</a>.</p>
<p>Processing was developed by <a href="http://reas.com/" title="Casey Reas" target="_blank">Casey Reas</a> and <a href="https://benfry.com/" title="Ben Fry" target="_blank">Ben Fry</a> back in 2001 at the MIT Media Lab when they were both students of <a href="https://maedastudio.com/" title="John Maeda" target="_blank">John Maeda</a>. It is based on Java and is intended primarily for use as a tool in the visual arts. For this reason it has been streamlined for drawing to the screen. A program written in Processing relies primarily on implementing two functions: setup and draw. A simple program that draws a circle 50 pixels in diameter centered in a 200x200 pixel display window is written as:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kt">void</span> <span class="nf">setup</span><span class="o">()</span> <span class="o">{</span>
<span class="n">size</span><span class="o">(</span><span class="mi">200</span><span class="o">,</span> <span class="mi">200</span><span class="o">);</span>
<span class="o">}</span>
<span class="kt">void</span> <span class="nf">draw</span><span class="o">()</span> <span class="o">{</span>
<span class="n">ellipse</span><span class="o">(</span><span class="mi">100</span><span class="o">,</span> <span class="mi">100</span><span class="o">,</span> <span class="mi">50</span><span class="o">,</span> <span class="mi">50</span><span class="o">);</span>
<span class="o">}</span></code></pre></figure>
<p>Which results in:</p>
<p><img src="/images/posts/2012/11/circle.png" alt="Circle" title="Circle" /></p>
<p>This is why I thought Processing would be a great way to introduce programming to kids. You can write a minimal amount of code and get immediate and gratifying results.</p>
<h3 id="processing-monsters">Processing Monsters</h3>
<p>Also about this time I had come across a website created by <a href="http://lukasvojir.com/" title="Lukas Vojir" target="_blank">Lukas Vojir</a> called Processing Monsters. He had created this website as part of his effort to learn Processing and he encouraged others to submit their creations to post on his website. The only rules were that the monsters must be in black and white and may respond to mouse input only. His stated goal was to create a short music reactive video using the monsters.</p>
<p>The website as it looked in December of 2008:</p>
<p><img src="/images/posts/2012/11/ProcessingMonsters-580x542.png" alt="Processing Monsters" title="Processing Monsters" /></p>
<p>Among the creations on this website was one called Blink Eye Monster by <a href="https://about.me/mb09" title="Lam Chi Fai" target="_blank">Lam Chi Fai</a>, aka mb09, which I found to be exceptionally well written. This sketch featured a snake-like creature that followed the path of the mouse pointer. The creature seemed to float above a field of grass that swayed gently whenever it passed.</p>
<p><img src="/images/posts/2012/11/BlinkEyeMonsterBW-580x290.png" alt="Blink Eye Monster" title="Blink Eye Monster" /></p>
<p>I took this sketch as an example of how a software problem can be broken down into parts. I asked the students to think about how the body of the monster was created.</p>
<p>I explained that as a Software Engineer one would analyze this problem and break it down into its constituent parts. The monster, for instance, is composed of an eye and body parts. We would likely express this in a class diagram similar to the one shown below:</p>
<p><img src="/images/posts/2012/11/Blink-Eye-Monster-Class-Diagram-580x259.png" alt="Blink Eye Monster Class Diagram" title="Blink Eye Monster Class Diagram" /></p>
<p>It turns out that the body is composed of a series of circles, diminishing in size from head to tail. By gradually diminishing the size and offsetting each circle it gives the illusion of a continuous form.</p>
<p><img src="/images/posts/2012/11/MonsterBodyParts-580x290.png" alt="Monster Body Parts" title="Monster Body Parts" /></p>
<p>The code to accomplish this is a bit complex, and involves quite a bit of trigonometry. I briefly showed the code for updating the position of a segment of the monster’s body, but I didn’t go into a detailed explanation as to how all this works.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kt">void</span> <span class="nf">Update</span><span class="o">(</span><span class="kt">float</span> <span class="n">_x</span><span class="o">,</span> <span class="kt">float</span> <span class="n">_y</span><span class="o">)</span>
<span class="o">{</span>
<span class="k">if</span><span class="o">(</span><span class="n">dist</span><span class="o">(</span><span class="n">x</span><span class="o">,</span><span class="n">y</span><span class="o">,</span><span class="n">_x</span><span class="o">,</span><span class="n">_y</span><span class="o">)></span> <span class="mi">5</span><span class="o">)</span>
<span class="o">{</span>
<span class="kt">float</span> <span class="n">d</span> <span class="o">=</span> <span class="n">dist</span><span class="o">(</span><span class="n">x</span><span class="o">,</span><span class="n">y</span><span class="o">,</span><span class="n">_x</span><span class="o">,</span><span class="n">_y</span><span class="o">);</span>
<span class="kt">float</span> <span class="n">angle</span> <span class="o">=</span> <span class="n">atan2</span><span class="o">((</span><span class="n">y</span><span class="o">-</span><span class="n">_y</span><span class="o">),(</span><span class="n">x</span><span class="o">-</span><span class="n">_x</span><span class="o">));</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">_x</span> <span class="o">+</span> <span class="n">cos</span><span class="o">(</span><span class="n">angle</span><span class="o">)</span> <span class="o">*</span> <span class="mi">5</span><span class="o">;</span>
<span class="n">y</span> <span class="o">=</span> <span class="n">_y</span> <span class="o">+</span> <span class="n">sin</span><span class="o">(</span><span class="n">angle</span><span class="o">)</span> <span class="o">*</span> <span class="mi">5</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">else</span>
<span class="o">{</span>
<span class="kt">float</span> <span class="n">d</span> <span class="o">=</span> <span class="n">dist</span><span class="o">(</span><span class="n">x</span><span class="o">,</span><span class="n">y</span><span class="o">,</span><span class="n">_x</span><span class="o">,</span><span class="n">_y</span><span class="o">);</span>
<span class="kt">float</span> <span class="n">angle</span> <span class="o">=</span> <span class="n">atan2</span><span class="o">((</span><span class="n">y</span><span class="o">-</span><span class="n">_y</span><span class="o">),(</span><span class="n">x</span><span class="o">-</span><span class="n">_x</span><span class="o">));</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">_x</span> <span class="o">+</span> <span class="n">cos</span><span class="o">(</span><span class="n">angle</span><span class="o">)</span> <span class="o">*</span> <span class="n">d</span><span class="o">;</span>
<span class="n">y</span> <span class="o">=</span> <span class="n">_y</span> <span class="o">+</span> <span class="n">sin</span><span class="o">(</span><span class="n">angle</span><span class="o">)</span> <span class="o">*</span> <span class="n">d</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
<p>The grass is constructed in a similar manner. Each blade of grass is composed of quadrilaterals of diminishing width aligned end to end. To illustrate this, in the image below I’ve eliminated the fill color and made the stroke visible. I’ve also reduced the number of grass blades and exaggerated their size by increasing the width factor.</p>
<p><img src="/images/posts/2012/11/GrassBlades-580x290.png" alt="Grass Blades" title="Grass Blades" /></p>
<p>Not only does the grass bend and sway based upon the motion of the monster, but Perlin noise is also employed to simulate gentle swaying due to wind. I don’t know about you, but I was thoroughly impressed by the effort that Lam Chi Fai put into creating this sketch.
As you can tell, there is a lot going on in this one program that could be the basis of mathematics assignments in middle school on up.</p>
<h3 id="scratch">Scratch</h3>
<p>Following my discussion of the Blink Eye Monster, I briefly demonstrated the Scratch programming environment and showed the students a couple of the games that are provided as examples with the tool. I also demonstrated how to create a basic program in Scratch by dragging and connecting programming blocks to build scripts.</p>
<p><img src="/images/posts/2012/11/Screen-Shot-2012-11-22-at-5.46.56-PM-580x444.png" alt="Scratch" title="Scratch" /></p>
<p>The Scratch website is also a great resource for sharing and learning about how to program. It’s very easy to upload any program you’ve created, as well as to download and experiment with code that others have written.</p>
<h3 id="and-now-for-something-completely-different">And Now for Something Completely Different…</h3>
<p>In retrospect, I may have presented this differently. My goal was to get the kids in the audience excited about the idea of programming and envision themselves pursuing Software Engineering as a career. To that end, I think it may have been better to have involved them in the process, rather than having them listen to me while I demonstrated something on a screen.</p>
<p>So what would I have done instead? I think I would have involved them in a programming game, one that doesn’t require the use of a computer. The objective of the game is to write a program that allows a robot to navigate from one end of the classroom to the other, avoiding any obstacles in its path. The obstacles could be desks or chairs scattered throughout the room. Likewise, the goal could be a desk, chair or a square laid out with masking tape on the floor. The only commands that the robot understands are turn left (90 degrees to left), turn right (90 degrees to right), or move n steps, where n is the number of steps forward that the robot should move. Each step could represent a tile in the floor, or if you’re exceptionally ambitious, a grid could be laid out with masking tape in advance of the presentation.</p>
<p>The students would get a chance to study the obstacle course and then write down their program on paper. I would then ask for volunteers for a programmer and someone to play the part of the robot. The programmer would then read each step of their program aloud and the student playing the robot would follow their instructions. If the robot was able to successfully navigate to the goal, the obstacles would be rearranged and someone else would get the opportunity to be the programmer. Hopefully, several students would have had an opportunity to play the role of the programmer or robot within the allotted time.</p>
<p>At the end of the presentation, I would have then pointed the students to the Scratch and Processing websites and encouraged them to try their hand at writing a program using these tools.</p>
<h3 id="final-thoughts">Final Thoughts</h3>
<p>Some time later I received a card from the school, thanking me for presenting to the Career Club. Notice anything familiar?</p>
<p><img src="/images/posts/2012/11/IMG_1324-580x753.jpg" alt="Career Day Thank You Note" title="Career Day Thank You Note" /></p>
<p>Rather than the black and white field of grass as in the original program, the card shows the monster hovering over a field of green. Whoever drew the illustration for the card recalled that during the presentation I had briefly uncommented one of the original lines of code that had changed the fill color for each blade of grass from black to a random shade of green:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="n">col</span> <span class="o">=</span> <span class="n">color</span><span class="o">(</span><span class="mi">51</span><span class="o">+</span><span class="n">random</span><span class="o">(</span><span class="mi">5</span><span class="o">),</span><span class="mi">200</span><span class="o">+</span><span class="n">random</span><span class="o">(</span><span class="mi">55</span><span class="o">),</span><span class="mi">90</span><span class="o">+</span><span class="n">random</span><span class="o">(</span><span class="mi">165</span><span class="o">));</span>
<span class="c1">//col = color(0);</span></code></pre></figure>
<p><img src="/images/posts/2012/11/BlinkEyeMonster-580x290.png" alt="Blink Eye Monster" title="Blink Eye Monster" /></p>
<p>I don’t know if anyone was inspired to pursue a career as a Software Engineer as a result of my presentation. Hopefully no one was deterred by it.</p>
<p>Unfortunately, I haven’t had the opportunity to be involved in any Career Club presentations following this one. The following year the fifth and sixth grades for all elementary schools in the district were consolidated into a single school, my son’s school is now Kindergarten to Fourth grade. I’m not sure if the Career Club was reconstituted at the new school. It would be a shame if it wasn’t since I believe that this is the time in life when children start to form ideas about what they’ll do as adults.</p>
<p>Sadly, the <a href="http://www.rmx.cz/monsters/" title="Processing Monsters" target="_blank">Processing Monsters</a> website appears to be defunct as well. I’m not sure if a video was ever created using the various monsters that were submitted.</p>
<p>Fortunately there are still websites that allow you to share your Processing sketches with the world, among these are <a href="https://www.openprocessing.org/" title="OpenProcessing" target="_blank">OpenProcessing</a> and <a href="https://experiments.withgoogle.com/hascanvas" title="HasCanvas" target="_blank">HasCanvas</a>.</p>
<p><img src="/images/posts/2012/11/OpenProcessing.png" alt="OpenProcessing" title="OpenProcessing" /></p>
<p><img src="/images/posts/2012/11/HasCanvas-580x309.png" alt="HasCanvas" title="HasCanvas" /></p>
<p>There is also a very neat project created by <a href="https://ertdfgcvb.xyz/" title="Andreas Gysin" target="_blank">Andreas Gysin</a> called <a href="https://www.creativeapplications.net/processing/the-abyss-tutorial/" title="The Abyss" target="_blank">The Abyss</a> which enables you to create your own creature and set it loose to roam about on the screen.</p>
<iframe src="http://player.vimeo.com/video/24134931?color=ffffff" frameborder="0" width="740" height="400"></iframe>
<p>My original inspiration for this post derives from the fact that Daniel Shiffman is out with a new book called “<a href="https://natureofcode.com/" title="The Nature of Code" target="_blank">The Nature of Code</a>” where he explores mathematical models of natural systems using the Processing programming language. Like his previous book “Learning Processing” this is a very approachable book for learning programming and the mathematics behind simulation. I highly recommend it.</p>
<p>I would also like to extend my thanks to Lukas Vojir and Lam Chi Fai for their excellent work related to Processing. Their projects are what makes the internet such an amazing resource.</p>
<p>Finally, how would you present Software Engineering to fifth and sixth graders? What are your thoughts on using Scratch and Processing to introduce kids to programming? Do you think kids would get anything out of the programming game exercise I described? Let me know in the comments.</p>Robert LysikIt was almost exactly four years ago, back in December of 2008, that I was invited to give a brief talk to the Career Club at my son’s elementary school about the profession of Software Engineering. At the time I had been reading Daniel Shiffman’s book Learning Processing and was thinking about how the Processing programming language could be used as a tool for introducing kids to programming.Happy Carl Sagan Day!2012-11-09T18:59:24-05:002012-11-09T18:59:24-05:00https://www.robertlysik.com/carl%20sagan/happy-carl-sagan-day<p>Carl Edward Sagan was born on this day in 1934. His 13 part television series Cosmos aired in the autumn of 1980 when I was still in middle school. Like many other people, I was deeply affected by this program and by the sense of wonder that Carl Sagan projected.</p>
<p><img src="/images/posts/2012/11/Carl_Sagan_Planetary_Society.jpg" alt="Carl Sagan - source Wikipedia.org" title="Carl Sagan - source Wikipedia.org" /></p>
<p>The Planetary Society will be hosting a <a href="https://www.planetary.org/blogs/mat-kaplan/20121108-sagan_celebration_webcast_promo.html" title="Sagan Celebration" target="_blank">Sagan Celebration</a> at 7:00 PM Pacific time today.</p>Robert LysikCarl Edward Sagan was born on this day in 1934. His 13 part television series Cosmos aired in the autumn of 1980 when I was still in middle school. Like many other people, I was deeply affected by this program and by the sense of wonder that Carl Sagan projected.RoboBrrd!2012-11-08T20:00:29-05:002012-11-08T20:00:29-05:00https://www.robertlysik.com/robotics/robobrrd/arduino/robobrrd<p>Do you have kids, or are you a kid at heart? If so, do yourself a favor and visit <a href="https://www.indiegogo.com/projects/robobrrd#/" title="Indiegogo" target="_blank">Indiegogo</a> to sign up as a <a href="http://robotgrrl.com/robobrrd/" title="RoboBrrd" target="_blank">RoboBrrd</a> contributor. I am definitely looking forward to working with my kids to build our very own RoboBrrd! How could I not contribute to this project?</p>
<p><img src="/images/posts/2012/11/RoboBrrd.jpg" alt="RoboBrrd" title="RoboBrrd" /></p>
<p>I’ve been following the progress of Erin Kennedy, aka <a href="https://twitter.com/robotgrrl" title="RobotGrrl" target="_blank">RobotGrrl</a>, the creator of RoboBrrd, on her project since she had started back in 2011. The first time I’d seen RoboBrrd was on the Make magazine website as a robotics project, and from that moment I understood that she’d hit on something that was very special.</p>
<p>This was a robot built from popsicle sticks, felt, pipe cleaners and ping-pong balls! This was an inherently friendly, approachable robot. It was also a brilliant learning platform. By building it out of ordinary items it took away the fear of tinkering with it. It is endlessly customizable, just break out the glue gun and some popsicle sticks and you can add new functionality!</p>
<p>RoboBrrd fully embraces the Maker philosophy that you don’t really own something unless you can tear it apart and customize it. We need to let kids know that it’s OK to do this, that it’s not off-limits. The best way to learn is to tinker. If kids are afraid to touch a robot lest they break it, how can we expect to them to ever build up confidence that they can create something on their own?</p>
<p>The production version of RoboBrrd relies on somewhat more sturdy laser-cut MDF boards that can stand up to the abuse that kids will likely dish out to it. I still like the crafty feel of the project and the fact that it embraces customization. I suspect that kids will be more likely to personally identify with a robot that they can make their own, and are encouraged to decorate and modify to their heart’s content.</p>
<p>I can’t wait for my RoboBrrd kit to arrive. I’m looking forward to seeing what types of behaviors we can code for this robot that take advantage of the light sensors, LEDs, speaker and servos. Hopefully this will be a fun learning experience for my kids and me!</p>Robert LysikDo you have kids, or are you a kid at heart? If so, do yourself a favor and visit Indiegogo to sign up as a RoboBrrd contributor. I am definitely looking forward to working with my kids to build our very own RoboBrrd! How could I not contribute to this project?Farewell Summer - Ray Bradbury 1920 - 20122012-11-04T09:27:38-05:002012-11-04T09:27:38-05:00https://www.robertlysik.com/ray%20bradbury/farewell-summer-ray-bradbury-1920-2012<p>When did I start reading the short stories of Ray Bradbury? I can’t recall exactly, though I do remember seeing books of his lying on the end table at my Uncle’s home. “R is for Rocket”, “S is for Space”, “The Martian Chronicles”…Irresistible, especially for a young boy. It’s also been quite a long time since I’d read any of Ray Bradbury’s stories, I suspect that I’d last picked up one of his books in high school. When I’d heard of his death in June of this year I thought I might borrow a book from the library and re-read those stories with my son, aged 9, at bedtime…or perhaps not. The stories that I most clearly remember are “All Summer in a Day” and “The Veldt”.</p>
<p>The story “All Summer in a Day” is set on on Venus where it is nearly always raining, except for a brief time once every seven years when the clouds break and the sun reveals itself for only a few hours before being obscured again, and the torrential rains resume. A girl, Margot, is taunted and ostracized because she claims to remember what the sun looks and feels like, having come from Earth with her parents when when she was only five. The other children in her class have no real memory of the sun, having been born on Venus, and having been only two when the sun briefly appeared through the clouds. In spite, the other children lock Margot in a closet on the day that the sun is expected to appear. When the sun does appear the children quickly forget about Margot and are lost in play outside. When the clouds return and the rains resume the children trudge back indoors, and only then remember Margot. They return to the closet and slowly open the door to let Margot out. The story was originally published in 1954, prior to the Soviet Venera and U.S. Mariner probes that would reveal the intense atmospheric pressure and a temperature that would make life on Venus impossible. Had the setting been some unnamed cloud covered planet around a distant sun there would not be the dissonance with our current understanding of Venus. However, the setting is incidental to the story. As with other of Bradbury’s stories, the science fiction aspects are just a way for him to explore human relationships. In “All Summer in a Day” Bradbury explores the cruelty that can sometimes be shown to an outsider.</p>
<p>The family in “The Veldt” lives in a modern home with every possible convenience. There are machines to cook and clean, even to scrub your back as you take a bath. The parents have also installed a nursery which projects a three dimensional simulation of any scene the occupant can imagine, complete with realistic smells and sounds. As the story begins the parents have become concerned with the children’s use of the nursery which appears to have become fixed on projecting a scene from the African veldt, with lions in the distance tearing into their prey. Gone are Aladdin, the cow jumping over the moon, Pegasus, and other staples of childhood imagination. The parents have also become concerned that the house has supplanted them, since it performs all the cooking, cleaning and entertainment. After consulting with a child psychologist who shares their concerns, they inform the children that they will be shutting down the nursery and other conveniences and take a vacation from the automated world of their home. Understandably, this goes over poorly with the children who throw a tantrum. The parents relent and turn the nursery back on briefly while they go to pack for their vacation trip. While packing, the parents hear the children crying for them to come quickly. As they run through the house in search of the children, they enter the nursery and the door slams behind them. “Don’t let them switch off the nursery and the house” they hear their son Peter say. A while later the psychologist arrives at the home to find the children enjoying a picnic in the nursery. “Where are your father and mother?”, he asks. “Oh, they’ll be here directly” the children reply ominously. Ray Bradbury has been quoted as saying that he didn’t want to describe the future, he wanted to <em>prevent</em> it. “The Veldt” is a warning against a future where we become too dependent upon our inventions. In “The Veldt”, he seems to have anticipated the present proliferation of television, mobile devices and video games.</p>
<p>As I began to re-read these stories I came to the conclusion that I’m not quite ready to sit down with my son to read them at bedtime. Perhaps when he is a bit older. Bradbury’s world is one of quintessential Americana, yet just below the surface lies something dark and foreboding.</p>
<p>The sound of a band playing wakes you from a pleasant afternoon nap. Making your way downstairs you notice that the house is empty. You open the front door, step out on the porch, and to your amazed eyes you see your family, friends and neighbors gathered together. A marching band strikes up a tune. What could possibly be the reason? <em>It’s your special day</em>. A parade forms with you as the leader, marching down to the water where a boat awaits…</p>
<p>Farewell Ray Bradbury…</p>Robert LysikWhen did I start reading the short stories of Ray Bradbury? I can’t recall exactly, though I do remember seeing books of his lying on the end table at my Uncle’s home. “R is for Rocket”, “S is for Space”, “The Martian Chronicles”…Irresistible, especially for a young boy. It’s also been quite a long time since I’d read any of Ray Bradbury’s stories, I suspect that I’d last picked up one of his books in high school. When I’d heard of his death in June of this year I thought I might borrow a book from the library and re-read those stories with my son, aged 9, at bedtime…or perhaps not. The stories that I most clearly remember are “All Summer in a Day” and “The Veldt”.Scratch Day 2012 @ MIT2012-06-04T22:30:26-04:002012-06-04T22:30:26-04:00https://www.robertlysik.com/scratch/mit/scratch%20day/scratch-day-2012-mit<p>I took my wife and children (ages 5 and 9) to Boston on Saturday May 19 for <a href="https://day.scratch.mit.edu/" title="Scratch Day" target="_blank">Scratch Day</a> at the MIT Media Lab. We all had a great time there and are looking forward to next year’s event.</p>
<h3 id="what-is-scratch">What is Scratch?</h3>
<p><a href="https://scratch.mit.edu/about" title="Scratch" target="_blank">Scratch</a> is a visual programming language that enables you to construct programs by dragging and dropping code blocks. For example, using Scratch if I wanted to play the “meow” sound 10 times, I’d drag a repeat block onto the script area and then drag a play sound block into the repeat block, like so:</p>
<p><img src="/images/posts/2012/05/Scratch-repeat-block.gif" alt="Scratch Repeat Block" title="Scratch Repeat Block" /></p>
<p>By linking these blocks together you can create quite sophisticated programs.</p>
<h3 id="whats-so-great-about-scratch">What’s So Great about Scratch?</h3>
<p>Scratch gives kids, and adults too, tools to create games, interactive stories, art projects, you name it, without getting bogged down with too many details. And it gives you just enough to make something useful right away. My son got the hang of it quite quickly and was able to create a rudimentary game on his own.
The other great thing about Scratch is the community and code sharing. After you create a Scratch project, it’s very easy to upload to the Scratch website where it can be shared with everyone else in the Scratch community. Other people can play the game you created, and if they’re interested in how you created it they can download the code to their machine, open it up and experiment with it. That’s exactly how my son was able to advance his learning as he built his games. He found games that he liked, downloaded the code and then tried to incorporate what he learned from the code into his own games. The best part is that he was able to do this all on his own. :)</p>
<h3 id="scratch-day">Scratch Day</h3>
<p><img src="/images/posts/2012/06/Scratch-Day-MIT-2012-Schedule-300x300.jpg" alt="Scratch Day Schedule of Events" title="Scratch Day Schedule of Events" /></p>
<p>When we arrived for Scratch Day we checked in and were given a Scratch Day program of events and a scavenger hunt card. The scavenger hunt card was a clever way to get people to meet, rather than sticking their noses in their laptops. In order to complete your scavenger hunt card you need to ask someone a question and have them sign your card. The questions were listed on the card and were all related to Scratch, so that made it relatively painless. When the cards were completed you could hand them in for a raffle drawing to be held at the end of the event.</p>
<p><img src="/images/posts/2012/06/Scratch-Day-MIT-2012-Scavanger-Hunt-300x288.jpg" alt="Scratch Scavenger Hunt" title="Scratch Scavenger Hunt" /></p>
<h4 id="lunch">Lunch</h4>
<p>Now, for $10.00 admission this can’t be beat: When we arrived they had pizza lunch for everybody! Believe me, running around trying to find a place to eat once we had driven three hours to get to Boston would have been a headache, so I’m really glad they had planned for lunch for everyone.
After lunch we went to the orientation session where they described the various activities that would be going on during the afternoon. My son had signed up for a Show and Tell session to describe a game he had been working on, so that was one of the first events we attended.</p>
<h4 id="show-and-tell">Show and Tell</h4>
<p>The Show and Tell sessions were a way to get a chance to hear about others experiences with Scratch as well as to show off work that you were doing. Among the projects that were presented that I found interesting was a game called <a href="https://scratch.mit.edu/projects/2549355/" title="Natural Selection" target="_blank">Natural Selection</a> where you played a bug who needed to get food, but you also needed to blend into the background if you didn’t want to get eaten. Those bugs that could survive would pass their genes on to the next generation.</p>
<h4 id="create">Create</h4>
<p>We also were able to work on some projects with <a href="https://education.lego.com/en-us/products/lego-education-wedo-2-0-core-set/45300" title="WeDo" target="_blank">WeDo</a>, the programmable Lego bricks that work with Scratch, and the <a href="https://www.picocricket.com/picoboard.html" title="PicoBoard" target="_blank">PicoBoard</a> sensors that enable you to create programs that interact with the world. The PicoBoard included a light sensor, sound sensor, a push button and a slider. My son and I worked on some simple Scratch programs that changed the background color based upon how loud sounds were, or how bright light was. Another father and son worked quite some time on a project using the WeDo Lego robotics kit to make a working elevator which they demonstrated during the reflection session at the end of the day.</p>
<h4 id="the-future-scratch-20">The Future: Scratch 2.0</h4>
<p>One of the benefits of Scratch Day was to get a glimpse of changes coming in the next version of Scratch. This version will provide a web-based editor, however a downloadable version that can be used offline will also reportedly be available as well.
Some of the features that will be available in this version include:</p>
<ul>
<li>Procedures: Wrap code that is re-used in a procedure. You’ll even be able to pass parameters to your procedure.</li>
<li>Cloning: Allows duplication of sprites in a game, such as multiple enemies or missiles.</li>
<li>Cloud Data: Now you’ll be able to store parameters in a database. For example a high score chart for a game, or survey results.</li>
</ul>
<p>These new features will open up a lot of new possibilities for programming.</p>
<h3 id="next-year">Next Year</h3>
<p>We’re already looking forward to next year’s Scratch Day event. My son has been busy writing more games, and my daughter may even have a game of her own by then that she can demo during the Show and Tell sessions!</p>Robert LysikI took my wife and children (ages 5 and 9) to Boston on Saturday May 19 for Scratch Day at the MIT Media Lab. We all had a great time there and are looking forward to next year’s event.I’ve Finished the Ruby on Rails Tutorial…Now What?2012-05-10T23:30:32-04:002012-05-10T23:30:32-04:00https://www.robertlysik.com/ruby%20on%20rails/ive-finished-the-ruby-on-rails-tutorial-now-what<p>It was perhaps unrealistic, but I’d hoped that when at long last I’d completed the final chapter of the <a href="https://www.railstutorial.org/book" title="Ruby on Rails Tutorial" target="_blank">Ruby on Rails Tutorial</a>, the clouds would part, there would be a chorus singing, and I would fully comprehend Rails. Alas, it was not to be. I now have more questions than I had before I started with the tutorial, but at least I’ve seen the process through to completion. So what’s next?</p>
<p>Michael Hartl has recommendations for adding extensions to the micro-blogging application that was developed during the course of the tutorial. Among these suggested extensions are messaging, follower notifications, sign-up confirmation and search. I’m especially interested in adding the ability to send email notifications from the web application so I’m planning to start work on that next. I’m sure this will be a bit challenging, but I expect that I’ll learn a great deal more by trying to solve this problem myself rather than have the author step me through the process.</p>
<p>After that, I’m still trying to decide what will be my first priority. I’d like to embark on developing my own application, but I am still not 100% comfortable with what’s going on with the Rails framework. I’d also like to become more comfortable with the Ruby programming language. Oh, and then there’s RSpec and BDD, and using GIT as a version control system…</p>
<p>So, my reading list is now looking like this:</p>
<ul>
<li><a href="https://pragprog.com/book/rails4/agile-web-development-with-rails" title="Agile Web Development with Rails (4th edition)" target="_blank">Agile Web Development with Rails (4th edition)</a> by Sam Ruby</li>
<li><a href="https://pragprog.com/book/ruby3/programming-ruby-1-9" title="Programming Ruby 1.9 (3rd edition)" target="_blank">Programming Ruby 1.9 (3rd edition)</a> by Dave Thomas, with Chad Fowler and Andy Hunt</li>
<li><a href="https://pragprog.com/book/achbd/the-rspec-book" title="The RSpec Book: Behaviour-Driven Development with RSpec, Cucumber, and Friends" target="_blank">The RSpec Book: Behaviour-Driven Development with RSpec, Cucumber, and Friends</a> by David Chelimsky, Dave Astels, Zach Dennis, Aslak Hellesøy, Bryan Helmkamp and Dan North</li>
<li><a href="https://git-scm.com/book/en/v2" title="Pro Git" target="_blank">Pro Git</a> by Scott Chacon</li>
</ul>
<p>And finally, a book I came across just today after seeing the Ruby Weekly newsletter:</p>
<ul>
<li><a href="https://leanpub.com/everydayrailsrspec" title="Everyday Rails Testing with RSpec" target="_blank">Everyday Rails Testing with RSpec</a> A practical approach to test-driven development by Aaron Sumner</li>
</ul>
<p>I feel as though the Ruby on Rails Tutorial provided an overview of the process, sort of like a bus tour of the city, with the tour guide pointing out sights along the way. Now it’s time to get off the bus and explore on foot…</p>Robert LysikIt was perhaps unrealistic, but I’d hoped that when at long last I’d completed the final chapter of the Ruby on Rails Tutorial, the clouds would part, there would be a chorus singing, and I would fully comprehend Rails. Alas, it was not to be. I now have more questions than I had before I started with the tutorial, but at least I’ve seen the process through to completion. So what’s next?Counting Down2012-05-01T23:23:22-04:002012-05-01T23:23:22-04:00https://www.robertlysik.com/ruby%20on%20rails/javascript/counting-down<p>I generally learn more by doing something rather than just reading about it, or watching someone else do something. I’ve been working through each of the exercises in the Ruby on Rails tutorial with the hope that some of this knowledge will sink in. I’ve now reached the exercises for the penultimate :) chapter of the tutorial, and the last exercise for this chapter is prefaced with the warning <strong>challenging</strong>:</p>
<blockquote>
<p>Add a JavaScript display to the Home page to count down from 140 characters.</p>
</blockquote>
<h3 id="the-plan">The Plan</h3>
<p>Simple enough, I imagine. We’ll just display the number of remaining characters below the text field like so:</p>
<p><img src="/images/posts/2012/04/MicropostCounter.png" alt="Micropost Counter" title="MicropostCounter" /></p>
<p>The first thing we’ll do is add a div to the existing partial for the home page that I’ll call “counter” (line 6):</p>
<p>app/views/shared/_micropost_form.html.erb</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="o"><</span><span class="sx">%= form_for(@micropost) do |f| %>
<%=</span> <span class="n">render</span> <span class="s1">'shared/error_messages'</span><span class="p">,</span> <span class="ss">object: </span><span class="n">f</span><span class="p">.</span><span class="nf">object</span> <span class="sx">%>
<div class="field"></span>
<span class="o"><</span><span class="sx">%= f.text_area :content, placeholder: "Compose new micropost..."%>
</div>
<div id=</span><span class="s2">"counter"</span><span class="o">></span><span class="mi">140</span><span class="o"><</span><span class="sr">/div>
<%= f.submit "Post", class: "btn btn-large btn-primary" %>
<% end %></span></code></pre></figure>
<p>Unfortunately this places the counter in an awkward location:</p>
<p><img src="/images/posts/2012/04/BeforeCSS1.png" alt="Counter Position Prior to CSS Change" title="BeforeCSS" /></p>
<p>So to fix this, we’ll add a class “counter” to the div:</p>
<figure class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt"><div</span> <span class="na">id=</span><span class="s">"counter"</span> <span class="na">class=</span><span class="s">"counter"</span><span class="nt">></span>140<span class="nt"></div></span></code></pre></figure>
<p>And add a “counter” class definition to the custom.css.scss file in the microposts section:</p>
<p>app/assets/stylesheets/custom.css.scss</p>
<figure class="highlight"><pre><code class="language-css" data-lang="css"><span class="c">/* microposts */</span>
<span class="nc">.counter</span> <span class="p">{</span>
<span class="nl">float</span><span class="p">:</span> <span class="nb">right</span><span class="p">;</span>
<span class="p">}</span></code></pre></figure>
<p>Now the counter will be displayed in the lower right corner as shown in the first example.</p>
<h3 id="the-script">The Script</h3>
<p>Next comes the JavaScript. We need to subtract the length of text for the textarea element from 140 and display the result in the counter div.
Since we’re already pulling in jQuery, I figured we might as well take advantage of it:</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">$</span><span class="p">(</span><span class="nb">document</span><span class="p">).</span><span class="nx">ready</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#micropost_content</span><span class="dl">"</span><span class="p">).</span><span class="nx">keyup</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#counter</span><span class="dl">"</span><span class="p">).</span><span class="nx">text</span><span class="p">(</span><span class="mi">140</span> <span class="o">-</span> <span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nx">val</span><span class="p">().</span><span class="nx">length</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">});</span></code></pre></figure>
<p>So what’s going on here?</p>
<p>[1] Wait for the document to load using $(document).ready().</p>
<p>[2] Bind our handler method to the keyup event for the micropost_content textarea element. <code class="language-plaintext highlighter-rouge">$("#micropost_content")</code> returns the element having an id matching micropost_content. keyup() binds the specified function to the keyup event.</p>
<p>[3] Set the text of the counter div element to the difference of 140 and the length of the text in the micropost_content element. $this refers to the micropost_content textarea element.</p>
<p>To give this counter added emphasis, it would be nice to set the color of the text to red when the value becomes negative.</p>
<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">$</span><span class="p">(</span><span class="nb">document</span><span class="p">).</span><span class="nx">ready</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#micropost_content</span><span class="dl">"</span><span class="p">).</span><span class="nx">keyup</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">counter</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#counter</span><span class="dl">"</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">charsRemaining</span> <span class="o">=</span> <span class="mi">140</span> <span class="o">-</span> <span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nx">val</span><span class="p">().</span><span class="nx">length</span><span class="p">;</span>
<span class="nx">counter</span><span class="p">.</span><span class="nx">text</span><span class="p">(</span><span class="nx">charsRemaining</span><span class="p">);</span>
<span class="nx">counter</span><span class="p">.</span><span class="nx">css</span><span class="p">(</span><span class="dl">'</span><span class="s1">color</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">charsRemaining</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">?</span> <span class="dl">'</span><span class="s1">red</span><span class="dl">'</span> <span class="p">:</span> <span class="dl">'</span><span class="s1">black</span><span class="dl">'</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">});</span></code></pre></figure>
<p>Points of interest:</p>
<p>[3] The counter variable was added so that we don’t need to traverse the DOM again to get the micropost_content element.</p>
<p>[4] The value of the variable charsRemaining will be displayed in the counter div and will also be used to determine the text color.</p>
<p>[6] Here the jQuery css() method is used to set the value of the ‘color’ property of the counter element. The ternary operator is employed to return the text color, reads as “If charsRemaining is less than zero, return ‘red’ otherwise return ‘black’”. The string returned is passed as an argument to the css() method to set the ‘color’ property.
Now when the maximum number of characters is exceeded the text should be red:</p>
<p><img src="/images/posts/2012/05/LimitExceeded.png" alt="Micropost Limit Exceeded" title="LimitExceeded" /></p>
<p>Although I could probably leave the script tag in the micropost form partial, I’d rather like to have it pulled into the head element of the document. I came across one suggestion for how to do this on <a href="https://stackoverflow.com/questions/3437585/best-way-to-add-page-specific-javascript-in-a-rails-3-app" title="StackOverflow" target="_blank">StackOverflow</a>. First, wrap the script section in a content_for block, like so:</p>
<p>app/views/shared/_micropost_form.html.erb</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="o"><</span><span class="sx">% content_for </span><span class="ss">:head</span> <span class="k">do</span> <span class="sx">%>
<script type="text/javascript"></span>
<span class="err">$</span><span class="p">(</span><span class="n">document</span><span class="p">).</span><span class="nf">ready</span><span class="p">(</span><span class="n">function</span><span class="p">()</span> <span class="p">{</span>
<span class="err">$</span><span class="p">(</span><span class="s2">"#micropost_content"</span><span class="p">).</span><span class="nf">keyup</span><span class="p">(</span><span class="n">function</span><span class="p">()</span> <span class="p">{</span>
<span class="n">var</span> <span class="n">counter</span> <span class="o">=</span> <span class="err">$</span><span class="p">(</span><span class="s2">"#counter"</span><span class="p">);</span>
<span class="n">var</span> <span class="n">charsRemaining</span> <span class="o">=</span> <span class="mi">140</span> <span class="o">-</span> <span class="err">$</span><span class="p">(</span><span class="n">this</span><span class="p">).</span><span class="nf">val</span><span class="p">().</span><span class="nf">length</span><span class="p">;</span>
<span class="n">counter</span><span class="p">.</span><span class="nf">text</span><span class="p">(</span><span class="n">charsRemaining</span><span class="p">);</span>
<span class="n">counter</span><span class="p">.</span><span class="nf">css</span><span class="p">(</span><span class="s1">'color'</span><span class="p">,</span> <span class="p">(</span><span class="n">charsRemaining</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">?</span> <span class="s1">'red'</span> <span class="p">:</span> <span class="s1">'black'</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">});</span>
<span class="o"><</span><span class="sr">/script>
<% end %></span></code></pre></figure>
<p>Then yield to the block in the application layout (line 8):</p>
<p>app/views/layouts/application.html.erb</p>
<figure class="highlight"><pre><code class="language-html" data-lang="html"><span class="cp"><!DOCTYPE html></span>
<span class="nt"><html></span>
<span class="nt"><head></span>
<span class="nt"><title><</span><span class="err">%=</span> <span class="na">full_title</span><span class="err">(</span><span class="na">yield</span><span class="err">(</span><span class="na">:title</span><span class="err">))</span> <span class="err">%</span><span class="nt">></title></span>
<span class="nt"><</span><span class="err">%=</span> <span class="na">stylesheet_link_tag</span> <span class="err">"</span><span class="na">application</span><span class="err">",</span> <span class="na">media:</span> <span class="err">"</span><span class="na">all</span><span class="err">"</span> <span class="err">%</span><span class="nt">></span>
<span class="nt"><</span><span class="err">%=</span> <span class="na">javascript_include_tag</span> <span class="err">"</span><span class="na">application</span><span class="err">"</span> <span class="err">%</span><span class="nt">></span>
<span class="nt"><</span><span class="err">%=</span> <span class="na">csrf_meta_tags</span> <span class="err">%</span><span class="nt">></span>
<span class="nt"><</span><span class="err">%=</span> <span class="na">yield</span> <span class="na">:head</span> <span class="err">%</span><span class="nt">></span>
<span class="nt"><</span><span class="err">%=</span> <span class="na">render</span> <span class="err">'</span><span class="na">layouts</span><span class="err">/</span><span class="na">shim</span><span class="err">'</span> <span class="err">%</span><span class="nt">></span>
<span class="nt"></head></span>
<span class="nt"><body></span>
<span class="nt"><</span><span class="err">%=</span> <span class="na">render</span> <span class="err">'</span><span class="na">layouts</span><span class="err">/</span><span class="na">header</span><span class="err">'</span> <span class="err">%</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"container"</span><span class="nt">></span>
<span class="nt"><</span><span class="err">%</span> <span class="na">flash.each</span> <span class="na">do</span> <span class="err">|</span><span class="na">key</span><span class="err">,</span> <span class="na">value</span><span class="err">|</span> <span class="err">%</span><span class="nt">></span>
<span class="nt"><</span><span class="err">%=</span> <span class="na">content_tag</span><span class="err">(</span><span class="na">:div</span><span class="err">,</span> <span class="na">value</span><span class="err">,</span> <span class="na">class:</span> <span class="err">"</span><span class="na">alert</span> <span class="na">alert-#</span><span class="err">{</span><span class="na">key</span><span class="err">}")</span> <span class="err">%</span><span class="nt">></span>
<span class="nt"><</span><span class="err">%</span> <span class="na">end</span> <span class="err">%</span><span class="nt">></span>
<span class="nt"><</span><span class="err">%=</span> <span class="na">yield</span> <span class="err">%</span><span class="nt">></span>
<span class="nt"><</span><span class="err">%=</span> <span class="na">render</span> <span class="err">'</span><span class="na">layouts</span><span class="err">/</span><span class="na">footer</span><span class="err">'</span> <span class="err">%</span><span class="nt">></span>
<span class="nt"><</span><span class="err">%=</span> <span class="na">debug</span><span class="err">(</span><span class="na">params</span><span class="err">)</span> <span class="na">if</span> <span class="na">Rails.env.development</span><span class="err">?</span> <span class="err">%</span><span class="nt">></span>
<span class="nt"></div></span>
<span class="nt"></body></span>
<span class="nt"></html></span></code></pre></figure>
<p>If you view source on the home page now you should see that the counter script appears in the head element. Furthermore, when you browse to any other page, the counter script shouldn’t exist.</p>Robert LysikI generally learn more by doing something rather than just reading about it, or watching someone else do something. I’ve been working through each of the exercises in the Ruby on Rails tutorial with the hope that some of this knowledge will sink in. I’ve now reached the exercises for the penultimate :) chapter of the tutorial, and the last exercise for this chapter is prefaced with the warning challenging: