All posts by Chris West

Canvas – Making A Simple Logo

A few days ago while I was working on updating my resume I thought about ways to add my simple “CW” (short for Chris West of course) logo to it. At the time of writing this article I presented my logo on CWestify.com using CSS3:



Leveraging the Canvas

One great thing that Mozilla has promoted for years is the <canvas>. As long as the canvas is not tainted it can turn its contents into an image (PNG or JPG). The great thing about using PNGs is their support of transparency and partial transparency. So the question is, “how do you draw HTML on a <canvas>?” Without using a library you can actually do so by inlining the styles and then turning the HTML code into SVG:


  
    
CW

Next we can either get the outerHTML of this SVG element or we can store the value directly in JavaScript (I will choose the latter for this example):

var data = '\
  \
    \
      
\
CW
\
\
\
';

Now we need to turn this SVG into something the <canvas> will display. The <canvas> will display images so we can load the SVG code into an image’s source:

// Define an image and set the source of the image to the SVG
var img = new Image();
img.src = 'data:image/svg+xml;base64,' + window.btoa(data);

Once the image object loads, we can then draw it onto the <canvas>:

// Variable to store the data URI for the PNG
var strPNG;

// Define an image
var img = new Image();

// Once the image loads draw it onto a new canvas
img.onload = function() {
  // Create a canvas
  var canvas = document.createElement('canvas');
  canvas.style.height = 0;
  canvas.height = 300;
  canvas.width = 300;

  // Draw the image onto the canvas
  canvas.getContext('2d').drawImage(img, 0, 0);

  // Store the image's data URI in a variable for later
  strPNG = canvas.toDataURL();
};

// Set the source of the image to the SVG data
img.src = 'data:image/svg+xml;base64,' + window.btoa(data);

Of course, since we are creating a <canvas> without adding it to the DOM we wanted to immediately use it to get its data URI and store it off into a variable (strPNG) for later use. All together the code looks like this:

var data = '\
  \
    \
      
\
CW
\
\
\
'; // Define an image var img = new Image(); // Once the image loads draw it onto a new canvas img.onload = function() { // Create a canvas var canvas = document.createElement('canvas'); canvas.style.height = 0; canvas.height = 300; canvas.width = 300; // Draw the image onto the canvas canvas.getContext('2d').drawImage(img, 0, 0); // Do something useful with the PNG's URI doSomethingWithLogoURI(canvas.toDataURL()); }; // Set the source of the image to the SVG data img.src = 'data:image/svg+xml;base64,' + window.btoa(data);

As you can see in the code above, after drawing the image on the canvas we call the doSomethingWithLogoURI() function so that it can use it.

Resulting PNG Image

Using this method produced an image in Chrome which I then saved off and uploaded to this blog so that regardless of the browser’s CSS3 capabilities my logo will always look the same:

CWestify Logo

CWestify Logo

Conclusion

Now we know that as long as we don’t taint the canvas with some outside source, we can basically turn any HTML element into a PNG. If we wanted to we could even use the method I outlined a while back to make such an image downloadable upon clicking on it. Perhaps this may open up your mind to other cool applications. Have fun! :cool:

Canvas – Animating Pacman Head In JavaScript

If your browser supports <canvas> (which if it doesn’t you need to switch to a better one :lol: ) you can see a simple JavaScript animation:

Image (with link) Canvas

Drawing Pacman

Drawing Pacman is quite a small task as you would imagine. It simply involves drawing a partial circle with lines going back to the center. Assuming that context refers to the 2D context of the <canvas> (canvas.getContext('2d')) the following code could be used to draw the shape of Pacman’s head:

// An arc which goes from 36 degrees to 324 degrees to draw Pacman's head
context.beginPath();
context.arc(100, 100, 100, 0.2 * Math.PI, 1.8 * Math.PI);

// The line leading back to the center and then closing the path to finish the
// open mouth
context.lineTo(100, 100);
context.closePath();

// Fill pacman's head yellow
context.fillStyle = "#FF0";
context.fill();

Next, since Pacman is cartoony, let’s add an outline to him:

// Outline the head
context.strokeStyle = '#000';
context.stroke();

Now we can add the eye to this popular cyclops :lol::

// A circle for the eye
context.beginPath();
context.arc(100, 50, 10, 0, 2 * Math.PI);
context.fillStyle = "#000";
context.fill();

// Outline the eye
context.strokeStyle = '#FFF';
context.stroke();

You’ll notice that I actually have a clickable <img> element which contains a still version of Pacman drawn when the page was loaded. It was drawn and loaded into the <img> by leveraging the canvas’ toDataURL() function:

img.src = canvas.toDataURL();

Animating Pacman’s Head

Now that we have animated him we need to figure out how we want him to open and close his mouth. This is where a little bit of trigonometry comes into play.

To calculate the x position (horizontal position) of a point on a circle given a specific degree we can use cosine (Math.cos()):

var x = Math.cos(degree * Math.PI / 180);

To calculate the y position (vertical position) of a point on a circle given a specific degree we can use sine (Math.sin()):

var y = Math.sin(degree * Math.PI / 180);

Since we first drew Pacman with his mouth open pretty wide, let’s assume that is as wide as his mouth gets. Let’s also assume that he will close his mouth completely. If we are going to make both the top and bottom of his mouth move in until closing we can assume that they will meet in the middle. Originally we drew his mouth starting at an angle of 36° (0.2 * Math.PI) on the top and 324° (1.8 * Math.PI) on the bottom. This means that the distance that either side will cover to close will only be 36° (or 0.2 * Math.PI). Keeping all of this in mind, here is a function to draw Pacman with his mouth open a specified percent (a number ranging from 0 to 100):

function drawPacman(pctOpen) {
  // Convert percent open to a float
  var fltOpen = pctOpen / 100;

  // Clear the canvas to draw the next part of the animation
  context.clearRect(0, 0, canvas.width, canvas.height);
  
  // An arc which stops at a specific percent to allow for the
  // open mouth to be drawn
  context.beginPath();
  context.arc(100, 100, 100, fltOpen * 0.2 * Math.PI, (2 - fltOpen * 0.2) * Math.PI);

  // The line leading back to the center and then closing the
  // path to finish the open mouth.
  context.lineTo(100, 100);
  context.closePath();

  // Fill pacman's head yellow
  context.fillStyle = "#FF0";
  context.fill();
  
  // Outline the head
  context.strokeStyle = '#000';
  context.stroke();
}

Animating Pacman’s Eye

Making Pacman open and close his mouth is relatively straightforward once we understand how to leverage cosine and sine. The slightly harder task is to get the eye to move accordingly.

Originally we put his eye in an upper horizontally centered position. The upper horizontally centered position of a circle is at 90° (which is 0.5 * Math.PI).

We also established that the distance of the center of the eye from the center of Pacman’s head is 50. We know this because Pacman’s center is at 100,100 and his eye is centered at 100,50 (50 pixels above the center of Pacman’s head).

Keeping all of this in mind we need to leverage cosine and sine to move Pacman’s eye only 36° (0.2 * Math.PI) to the right when his mouth closes:

function drawPacman(pctOpen) {
  // ...code for drawing Pacman's head

  // A circle for the eye
  var angle = Math.PI * (0.3 + fltOpen * 0.2),
      xDelta = 50 * Math.cos(angle),
      yDelta = 50 * Math.sin(angle);
  context.beginPath();
  context.arc(100 + xDelta, 100 - yDelta, 10, 0, 2 * Math.PI);
  context.fillStyle = "#000";
  context.fill();
  
  // Outline the eye
  context.strokeStyle = '#FFF';
  context.stroke();
}

Here we establish the angle at which the eye is positioned based on the percent that the mouth is open. We are also using deltas to offset the eye from the center at the right angle.

Now we can put everything together and use setInterval() to animate Pacman:



In the end there wasn’t TOO much math involved and we end up with a neat little animation. Have fun! :cool:

My Interactive Resume – Part 1

Here is my first quick pass at an online resume:
http://CWestify.com/resume/

There are plenty of times when we want to add everything to our resume to let potential employers know our worth but it can be difficult to know how to really summarize everything.

Project Search

There are times when we want these potential employers to be able to browse our projects with ease, perhaps searching through them by keywords. For that reason I added a search which populates the typeahead suggestion box with keywords for my projects.
Resume - Project Search Section

Even though I ended up coding everything from scratch just because I wanted to challenge myself, it’s easily conceivable that one could do this using bootstrap and a typeahead plugin. My project information is actually stored away in JavaScript:

var projects = [
  {
    title: 'CWestify.com',
    description: 'A site full of custom code written in PHP and JS primarily containing small online apps such as the Emoji Search.',
    url: 'http://cwestify.com/',
    dates: [new Date('2015/01/01')],
    keywords: ['PHP', 'JavaScript', 'YourJS', 'HTML', 'CSS', 'HTML5', 'CSS3', 'MySQL'],
    languages: ['PHP', 'JavaScript', 'HTML', 'CSS', 'MySQL']
  },
  {
    title: 'CWestBlog.com',
    priority: true,
    description: 'My blog which showcases a lot of the JavaScript solutions I have come up with over the years.  This site gets thousands of visits every week due to the specificity of the solutions I have posted.  Besides JavaScript I also wrote articles about Python, CSS3, Java, VBScript, mathematics and much more.',
    url: 'http://cwestblog.com/',
    dates: [new Date('2011/03/31')],
    keywords: ['JavaScript', 'PHP', 'YourJS', 'HTML', 'CSS', 'HTML5', 'CSS3', 'Excel', 'node.js', 'Java', 'Python', 'Math', 'Blog', 'Wordpress', 'VBScript', 'JSON', 'VBA', 'HTA', 'MySQL'],
    languages: ['PHP', 'JavaScript', 'HTML', 'CSS', 'MySQL']
  },
  ...
];

As you can see I store the keywords for each project in an array. The keywords for all of the projects are then put into an array and their frequency is kept with each keyword.

Hiding Contact Information from Bots

Of course, if you want to put your resume online it is important that you take steps to hide your contact info from bots/web-scrapers. For that reason I decided to use reCAPTCHA. In order to actually see my contact information the user will have to click through the step(s) of reCAPTCHA.
Resume - Contact Info with CAPTCHA

Conclusion

I personally am mostly happy with how my interactive resume turned out, but I do have ideas for how to improve it:

  1. Make it mobile friendly.
  2. Add buttons that will allow me to pick and choose what I want printed if I decide to print it out.
  3. Change the design to make it a little more poppy but at the same time still professional.

Let me know if you have any other ideas of how to make an online version of a resume better and more interactive. :cool: