📕
SEIRFX
  • Introduction
  • About These Notes
  • Schedule
  • Unit 2
    • Node
      • Internet Fundamentals
      • Full-Stack Fundamentals
      • Intro to Node
      • Node Modules
      • Node Packages
    • Express
      • Intro to Express
      • Routes
      • Routes Lab
      • Views
      • Templates
      • Layouts & Controllers
    • CRUD & REST
      • GET & POST
      • GET & POST Lab
      • PUT & DELETE
    • API Calls in Express
      • Axios
      • Request (no longer maintained)
    • Sequelize
      • Terminology
      • Setup
      • Using Models
      • Seeding Data
      • Validations and Migrations
      • Resources
      • 1:M Relationships
      • N:M Relationships
    • Express Authentication
      • Research Components
      • Code Components
      • Auth in Theory
        • Sessions
        • Passwords
        • Middleware
        • Hooks
      • Auth in Practice
        • Create the User
        • User Signup
        • Sessions
        • User Login
        • Authorization and Flash messages
  • Development Workflow
    • Command Line
      • The Terminal
      • Filesystem Navigation
      • File Manipulation
      • Additional Topics
    • Intro to Git
      • Version Control
      • Local Git
      • Remote Git
      • Git Recipes
    • Group Collaboration
      • Git Workflows
      • Project Roles and Tools
    • VS Code Tips & Tricks
  • HTML/CSS
    • HTML
    • CSS Selectors
    • CSS Box Model and Positioning
      • Box Model
      • Display and Positioning
      • Flexbox
      • Grid
      • Flexbox & Grid Games
      • Floats and Clears
      • Additional Topics
    • Advanced CSS
      • Responsive Design
      • Pseudo-Classes/Elements
      • Vendor Prefixes
      • Custom Properties
      • Additional Topics
    • Bootstrap
    • CSS Frameworks
    • Accessibility
  • JavaScript
    • Primitives
    • Arrays
    • Objects
      • Objects Lesson
      • Objects quick guide
      • Object-ception
    • Control Flow
      • Boolean Expressions
      • Conditionals
      • Loops
      • Promises
    • Functions
      • Scope
      • Callbacks
      • Higher Order Functions
      • Callbacks Review Lab
      • Timing Functions
      • Iterators
      • Combining Data Types
      • Combining Data Types Lab
    • Javascript in the browser
      • DOM and Events
      • DOM Manipulation
      • DOM Review
      • DOM Review Lab
      • HP DOM Lab
      • Programmatic DOM Manipulation
      • Grids & Pyramids
      • DOM & Data
      • DOM Events
      • Color Palette Picker
      • Sketchpad
    • HTML5 Canvas
    • How To Reduce Redundancy
    • OOP
      • Westworld Lab
      • OOP Factories
      • OOP Inheritance
      • OOP Inheritance Lab
      • Tomagotchi Lab
      • OOP Space Battle
      • OOP Snowman
      • (2019) JavaScript OOP
      • (2016) OOP with Classes
      • (1995) OOP with Prototypes
      • Constructors
      • Prototypes
    • Intro to TDD
    • Scoping
    • Inheritance
      • Prototypal Inheritance
      • Call, Apply, and other Functions
      • ES6 Inheritance
      • Resources
    • Custom Node Modules
    • Additional Topics
      • AJAX, Fetch, and Async/Await
      • AJAX w/JSON and Localstorage
        • AJAX w/JSON
        • Local Storage
      • Async module
      • Data Scraping
  • jQuery
    • Intro
      • DOM Manipulation
      • Reddit Practice
      • Styling
      • Events
    • Plugins
    • AJAX
  • APIs
    • Fetch
    • AJAX w/jQuery
    • AJAX w/Fetch
  • Databases
    • Intro to SQL
    • Advanced SQL
    • MongoDB
      • Intro to NoSQL
      • CRUD in MongoDB
      • Data Modeling
      • Intermediate Mongo
  • Left over Node/Express
    • Testing with Mocha and Chai
    • Mongoose
      • Mongoose Associations
    • JSON Web Tokens
      • Codealong
    • Additional Topics
      • oAuth
      • Geocoding with Mapbox
      • Geocoding and Google Maps
      • Cloudinary
      • Websockets with Socket.io
      • SASS
  • Ruby
    • Intro to Ruby
    • Ruby Exercises
    • Ruby Classes
    • Ruby Testing with Rspec
    • Ruby Inheritance
    • Ruby Data Scraping
  • Ruby on Rails
    • Intro to Rails
    • APIs with Rails
    • Asset Pipeline
    • Rails Auth and 1-M
      • Auth Components
    • Rails N:M
    • ActiveRecord Polymorphism
    • Additional Topics
      • oAuth
      • SASS
      • Rails Mailers
      • Cloudinary
      • Jekyll
  • React (Updated 2019)
    • ES6+/ESNext
      • Const and Let
      • Arrow Functions
      • Object Literals and String Interpolation
      • ES6 Recap
      • ES6 Activity
    • Intro to React
      • Create React App
      • Components and JSX
      • Virtual DOM
      • Props
      • Dino Blog Activity
      • Nested Components
      • Lab: LotR
    • React State
      • Code-Along: Edit Dino Blog
      • Lab: Simple Calc
      • Lifting State
    • React Router
      • Browser History/SPAs
      • React Router (lesson and full codealong)
      • Router Lab
    • Fetch and APIs
      • APIs with Fetch and Axios
      • Fetch the Weather
    • React Hooks
    • React LifeCycle
      • Lab: Component LifeCycle
    • React Deployment
    • Additional Topics
      • React Frameworks
        • Material UI Theming
      • Typescript
        • More Types and Syntax
        • Tsconfig and Declaration Files
        • Generics with Linked List
      • Redux
      • TypeScript
      • Context API
      • React Native
  • Meteor
  • Deployment and Config
    • Installfest
      • Mac OSX
      • Linux
      • Git Configuration
      • Sublime Packages
    • Deploy - Github Pages
    • Deploy - Node/Sequelize
    • Deploy - Node/MongoDB
    • Deploy React
    • Deploy - Rails
      • Foreman (Environment Variables)
    • Deploy - AWS Elastic Beanstalk
    • Deploy - S3 Static Sites
    • Deploy - Django
    • Deploy - Flask
  • Data Structures and Algorithms
    • Recursion
    • Problem Solving - Array Flatten
    • Binary Search
    • Algorithm Complexity
    • Stacks and Queues
    • Bracket Matching
    • Ruby Linked Lists
      • Sample Code
      • Beginner Exercises
      • Advanced Exercises
    • JS Linked Lists
      • Sample Code
      • Beginner Exercises
      • Beginner Solutions
    • Hash Tables
    • Intro to Sorting
    • Insertion Sort
    • Bucket Sort
    • Bubble Sort
    • Merge Sort
    • Quick Sort
    • Heap Sort
    • Sorting Wrapup
    • Hashmaps
    • Trees and Other Topics
  • Python
    • Python Installation
    • Intro to Python
    • Python Lists
    • Python Loops
    • Python Dictionaries
    • Python Sets and Tuples
    • Python Cheatsheet
    • Python Functions
    • Python Classes
    • Python Class Inheritance
    • Intro to Flask
    • Intro to SQLAlchemy
      • Flask and SQLAlchemy
    • Using PyMongo
    • Intro to Django
    • CatCollector CodeAlong
      • URLs, Views, Templates
      • Models, Migrations
      • Model Form CRUD
      • One-to-Many Relations
      • Many-to-Many Relations
      • Django Auth
    • Django Cheatsheet
    • Django Auth
    • Django Polls App Tutorial
    • Django School Tool Tutorial
    • Django 1:M Relationships
    • Custom Admin Views
    • Data Structures and Algorithms
      • Recursion
      • Binary Search
      • Stacks and Queues
      • Linked Lists
      • Binary Trees
      • Bubble Sort
      • TensorFlow & Neural Networks
    • Adjacent Topics
      • Raspberry Pi
      • Scripting
  • Assorted Topics
    • History of Computer Science
    • Regular Expressions
    • Being Successful in SEI
    • Internet Fundamentals
      • Internet Lab
    • Adjacent Workflow
      • UX/UI
      • Wireframing Exercise: Build an Idea
      • Agile
    • Post SEI
      • Learning Resources
      • Deliverables -> Portfolio
      • FAQ
  • Projects
    • Project 1
    • Project 2
    • Project 3
      • Project 3 Pitch Guidelines
    • Project 4
    • Past Projects
      • Project 1
      • Project 2
      • Project 3
      • Project 4
      • Portfolios
    • Post Project 2
    • MEAN Hackathon
      • Part 1: APIs
      • Part 2: Angular
    • Portfolio
  • Web Development Trends
  • Resources
    • APIs and Data
    • Tech Websites
    • PostgreSQL Cheat Sheet
    • Sequelize Cheat Sheet
    • Database Administration
  • Archived Section
    • (Archived) ReactJS
      • Intro to React
        • Todo List Codealong
        • Additional Topics
      • Deploy React
      • React with Gulp and Browserify
        • Setting up Gulp
        • Additional Gulp Tasks
      • React Router
        • OMDB Router
        • OMDB Search
        • Additional Resources
      • React Animations
        • CSS Animations
    • AngularJS
      • Intro to AngularJS
        • Components and SPA
        • Create an Angular App
      • Angular Directives and Filters
      • Angular Animation
      • Angular Bootstrap Directives
        • Bootstrap Modals
      • Angular $http
      • Angular Services
        • Service Recipes
        • ngResource
        • Star Wars Codealong
      • Angular Routing
      • Angular + Express
      • Angular Authentication
        • Additional Topics
      • Angular Components
      • Angular Custom Filters
      • Angular Custom Directives
Powered by GitBook
On this page
  • The Canvas Tag
  • Drawing on the Canvas
  • Attach Mouse Interactions
  • Erase Entire Canvas
  • Graphics Loop
  • Persist Previous Drawings
  • Refactor Draw Method Inside Rectangle Class

Was this helpful?

  1. JavaScript

HTML5 Canvas

PreviousSketchpadNextHow To Reduce Redundancy

Last updated 4 years ago

Was this helpful?

HTML5, released October 28th 2014, is the latest version of HTML. It builds on top of many years of specifications and development done since when HTML was first released by Tim Berners-Lee in 1993.

This site shows off what tags were included in each version of HTML from version 1 to version 5:

  • HTML 1 (1993)

    • <a>, <h1> - <h6>, <ul>, <li>, <p>, <title>

  • HTML 2 (Nov 24 1995)

    • <!DOCTYPE>, <html>, <head>, <body>, <meta>, <link>

    • <table>, <thead>, <tbody>, <tfoot>, <tr>, <td>

    • <form>, <input>, <select>, <option>, <textarea>

    • <em>, <strike>, <strong>, <u>, <i>,

    • <img>

  • HTML 3 (Jan 14 1997)

    • <div>, <center>, <font>

    • <script>, <style>

  • HTML 4 (Dec 18 1997)

    • <button>, <label>, <span>

    • <iframe>

  • HTML 5 (Oct 28 2014)

    • <audio>, <video>, <canvas>

    • <header>, <footer>, <nav>, <section>

    • <summary>, <time>, <progress>

    • <output>

It looks like HTML 1 was all about creating pages with basic text. HTML 2 introducted the HTML / HEAD / BODY structure of web pages we know today, and it gave us images, forms, inputs and tables. HTML 3 added divs, fonts and, most importantly, CSS and JavaScript as we know it. HTML 4 offered buttons, labels for inputs and iframes (which I feel are rarely used much anymore today). Finally, HTML 5 came out with some new semantic improvements by giving developers the header, footer, nav, section and summary tags. Those elements don't do much to make things look different on the page but they're useful for developers to be able to add meaning to their web pages.

Perhaps the most exciting features of HTML 5 are the addition of the <audio>, <video> and <canvas> tags. In the past, users relied on technologies like Flash in order to create rich interactive multimedia content on the web. The introduction of these new multimedia tags allowed developers and netizens to have native in-browser support for <audio> <video> experiences for the first time! Woo!

The Canvas Tag

The audio and video tags are alright. They allow a page to play audio and movies. What's really cool is the <canvas> tag. The <canvas> tag is basically a block element that the browser can programatically draw on. Think of it like a <div> where you can use JavaScript to execute Microsoft Paint commands on. The canvas element provides an API to JavaScript where it can do things like draw lines, draw curvers, fill in shapes, and draw images to the canvas.

Note: the canvas element has limitations. The biggest limitation is that the canvas element is only showing an image at the end of the day. Although it will allow you to draw cool, unique things on the page the canvas is not good for creating text that users want to highlight, or displaying links people can click on. So: canvas is great at displaying things, but keep in mind that if you ever draw text to the canvas the text won't act like text on a website that can be highlighted and copied and pasted. The text will act like text that's inside of an image.

Drawing on the Canvas

Check out this repo to bare-bones page with a canvas we can draw on.

The canvas element provides us with something called it's context. Think of context like a repo for canvas methods. Canvas supports a variety of different contexts, primarily 2D and 3D. We'll be using our canvas for drawing simple two-dimensional images so we'll grab the 2D context off the canvas.

The canvas element is the canvas we paint on, the context is like our paintbrush. We'll use the context to paint rectangles at first. The context provides us with two ways to draw a rectangle. We can stroke or fill a rectangle. Stroke a rectangle produces an outline of a rectangle with a hollow see-through center. Filling a rectangle draws a solid rectangle. We can "dip" the context paintbrush into two seperate colors for the stroke and fill.

Let's fill a black rectangle and stroke it's border with a 5px red line.

<body>
  <h1>Canvas 101</h1>
  <canvas id="easel"></canvas>
</body>
document.addEventListener("DOMContentLoaded", main);

function main() {
  // Get a reference to the canvas and grab something called the "context" off
  // it.  The context defines how we interact with the canvas. We're not doing
  // 3D so we grab 2D.
  var canvas = document.getElementById("easel");
  var ctx = canvas.getContext("2d");

  // The canvas doesn't register the same way as a div, so if you set the width
  // and height properties in your CSS file, you'll end up stretching the canvas
  // which automatically has 2:1 ratio (width of 300px and a height of 150px). 
  // You can get around this by putting the width and height in the HTML or doing
  // it programatically by assigning attributes with Javascript
  canvas.setAttribute('width', '800');
  canvas.setAttribute('height', '800');

  // It turns out to be useful to attach the width and height properties to the
  // ctx too, so it knows how big it's canvas is. 
  ctx.width = canvas.width;
  ctx.height = canvas.height;

  // Define some variables for the x,y coordinates of where we'll draw
  // and the width and height of rectangles we'll draw.
  var xx = 50;
  var yy = 80;
  var width = 100;
  var height = 150;

  // The ctx is like our paintbrush. Let's set the width of a line we'll draw
  // and choose different colors for fill (the inside of shapes) and for it's
  // stroke (a line on the border of shapes).
  ctx.fillStyle = 'black';
  ctx.strokeStyle = 'red';
  ctx.lineWidth = 5;

  // fill an entire rectangle
  // then stroke around it's edges with red.
  ctx.fillRect(xx, yy, width, height);
  ctx.strokeRect(xx, yy, width, height);
}

Attach Mouse Interactions

Cool. That's some simple canvas work right there! Let's make things more interesting by making the canvas draw a rectangle wherever someone clicks.

Although the canvas element provides us the unique ability to draw things on a web page it still behaves like all other HTML elements. We can style the width, height, position and border of it. We can also attach click handlers to it.

Let's write a function that accepts an x and y parameter and draws a small rectangle at that location. Then, let's attach a click handler so whenever someone clicks on the canvas element we extract the x and y coordinates from the click event and pass the coordinates to the draw rectangle function.

Oh, the function will need access to the ctx variable too. We'll pass that as a parameter too.

The click event object has lots of different x and y coordinate information:

  • clientY - y distance from the top left corner of the webpage, under the

    bookmarks and URL location bar. Ignores scrolling. If the user scrolls down

    1,000 pixels and clicks on the page just under their bookmarks bar the y

    value will stay close to zero.

  • layerY - y distance from the mouse to the closest positioned element.

  • offsetY - y distance from the top left corner of the element that was

    clicked on.

  • pageY - y distance from the top left corner of the page, including any

    scrolling. If a user scrolls down 1,000 pixels and clicks on the page just

    under their bookmarks bar the y-value will be close to 1,000.

  • screenY - y distance from the top left corner of the entire laptop screen,

    like (0,0) would be near the top-left Apple icon on a Mac.

  • y - an quick-shortcut alias for the clientY property.

Let's use the offsetX and offsetY properties off the event object.

function drawRectangle(x, y) {
  // these rectangles will be 50x50px squares
  var size = 50;

  ctx.fillStyle = 'purple';
  ctx.stokeStyle = 'yellow';
  ctx.lineWidth = 5;

  ctx.fillRect(x, y, size, size);
  ctx.strokeRect(x, y, size, size);
}
canvas.addEventListener("click", function(event) {
  drawRectangle(ctx, event.offsetX, event.offsetY);
});

Notice that ever new rectangle is drawn on top of everything else. It's just like painting over it.

Erase Entire Canvas

There gets to be a lot of rectangles on the canvas after the user clicks a bunch. Let's add a button that will let us erase everything on the canvas. The ctx object provides a .clearRect(x, y, width, height) function that allows us to erase everything on the canvas within a specified rectangular region.

<body>
  <h1>Canvas 101</h1>
  <div>
    <button id="clear">clear canvas</button>
  </div>
  <canvas id="easel"></canvas>
</body>
document.getElementById("clear").addEventListener("click", function() {
  clearCanvas(ctx);
});

function clearCanvas(ctx) {
  ctx.clearRect(0, 0, ctx.width, ctx.height);
}

Graphics Loop

OK, it's cool that there's a rectangle on the page when it loads, and it's cool that we can make more rectangles when someone clicks on the page. Let's make the page even better by having a rectangle float under the user's cursor as they move their cursor around the campus.

This is as easy as attaching another event handler to the canvas. We used a click listener before. Let's make a new one that listens for mouse movement and hook it up to the same drawRectangle function.

  canvas.addEventListener("mousemove", function(event) {
    drawRectangle(ctx, event.offsetX, event.offsetY);
  });

Hooking the canvas up to draw a rectangle every time the mouse moves ends up drawing a lot of rectangles to the page! Remember that every time something is painted to the canvas it just stays there. Everything gets painted over everything else. Let's fix this up by erasing everything on the canvas each time the mouse moves and then drawing our one new rectangle.

Every other rectangle gets deleted each time the mouse moves, but now there's just one rectangle that hovers under the user's mouse. Now our canvas looks very interactive and snappy! Very cool.

  canvas.addEventListener("mousemove", function(event) {
    clearCanvas(ctx);
    drawRectangle(ctx, event.offsetX, event.offsetY);
  });

Persist Previous Drawings

OK, it's cool that we're able to constantly draw a rectangle under the users's mouse, but it's a total shame that the rectangles we click to draw are immediately erased. Nothing persists. We only see the one rectangle under the mouse.

We need to change the program so that instead of only drawing the current rectangle when the mouse moves it should draw every rectangle that's ever been added to the canvas.

Right now our program looks like this:

draw the first rectangle on the screen
draw a new rectangle whenever someone clicks
erase the entire canvas and draw a rectangle whenver the mouse moves.

The problem with our program is the fact that we're erasing everything. But, we're at a catch-22. We need to erase everything so that we don't leave a trail of squares behind wherever the mouse goes.

We'll need to change our program to keep track of everywhere someone has clicked and we'll need to tell the program to draw all of the squares again each time it erases the screen.

Basically, instead of drawing rectangles immediately we'll instead add the coordinates of each rectangle to an array. Whenever we need to erase the screen we can run a for loop over the array of rectangles and immediately redraw them. We'll only add rectangles to the array that we want to stay forever. This means we can still draw rectangles that follow the mouse when it moves, but those mouse-move rectangles won't be added to the array and they won't be drawn in the future.

Our program will look like this:

draw the first rectangle to the screen
add that rectangle's coordinates to an array to remember where it goes
add new rectangle coordinates to the array whenever someone clicks
erase the screen whenever the mouse moves
redraw all of the rectangles in the array
draw one rectangle where the mouse was

How should the rectangles be stored in the array? We could use strings to have coordinates like ["0,0", "76,299"] or we could store coordinates in small arrays like [[0,0], [76,299]]. These options would get the job done, for sure, but they lack semantics. There's no real meaning imposed on the data when we store the data this way. Which coordinate is the x coordinate? Is the y coordinate in the first position or the second position? It's hard to remember, it's easy to make mistakes, and it's hard for whoever else comes to read our code later. Let's make life better.

We could store all of the rectangles as objects with x and y values like [{x: 0, y: 0}, {x: 76, y: 299}]. This is definitely better because the x and y values have become unambigious. We can still do better!

Rectangles are things, right? Things are, like, objects, right? Let's use object-oriented programming to create a class that models what a rectangle is! A class is even better than just an object with x and y properties because it has a name now too. We're clearly saying "these x and y coordinates represent a Rectangle." Just the fact that the class has a name, "Rectangle", makes our code even easier to understand.

Also, creating a class gives us a great place to attach more information in the future. Now that we have a rectangle class it would be easy for us to add other properties like size, color, outline line. All of this information all in one place. Amazing.

Make a new file called rectangle.js that contains the class definition for our rectangles and remember to attach a <script> reference to the new file in index.html.

class Rectangle() {
  constructor(x, y) {
    this.x = x;  
    this.y = y;
  }
}

Use the Rectangle class to create rectangles and save them to an array. Make a new function called redraw() that accepts ctx and an array as parameters and redraws all of the rectangles. Call the new redraw() function just after you erase the canvas when the mouse moves, and before you draw the new rectangle that hovers under the mouse.

Careful! Notice that pressing the "clear canvas" button now erases the canvas for a moment, but all of the rectangles come back as soon as the mouse moves. This is because although the canvas was cleared of everything that was painted on it, the array still maintains memory of all the rectangles it's supposed to be drawing. We must update our "clear canvas" click handler so it resets the array of rectangles back to empty too.

// introduce a new global variable
var RECTANGLES = [];

function addRectangle(x, y) {
  var rect = new Rectangle(x, y);
  RECTANGLES.push(rect);
}

function drawRectangles(ctx, rects) {
  rects.forEach(function(rect) {
    drawRectangle(ctx, rect.x, rect.y);
  });
}

canvas.addEventListener("click", function(event) {
  addRectangle(event.offsetX, event.offsetY);
  drawRectangle(ctx, event.offsetX, event.offsetY);
});

canvas.addEventListener("mousemove", function(event) {
  clearCanvas(ctx);
  drawRectangles(ctx, RECTANGLES);
  drawRectangle(ctx, event.offsetX, event.offsetY);
});

document.getElementById("clear").addEventListener("click", function(event) {
  clearCanvas(ctx);
  RECTANGLES = [];
});

Refactor Draw Method Inside Rectangle Class

Object oriented programming allows us to:

  1. model data that represents what objects are

  2. define functionality that defines what objects can do

Create a new function called draw on the Rectangle class that accepts a ctx as a parameter and has rectangles draw themselves onto the canvas with the ctx according to their own this.x, this.y and this.size values.

After doing this we can delete the drawRectangle function in main.js and simply iterate through rectangles and tell them to draw themselves. It's nice to keep everything related to rectangles inside the one file inside the one class.

The rectangle class provides a good pattern for us to follow if ever want to add more shapes or figures to this website. We can define classes for squares, create circles, triangles or anything else.

RECTANGLES.forEach(function(rect) {
  rect.draw(ctx);
});
class Rectangle {
  constructor(x, y, size) {
    // these rectangles default to being 50x50px squares
    this.size = size || 50;
    this.x = x;
    this.y = y;
  }

  draw(ctx) {
    // The ctx is like our paintbrush. Let's set the width of a line we'll draw
    // and choose different colors for fill (the inside of shapes) and for it's
    // stroke (a line on the border of shapes).
    ctx.fillStyle = 'purple';
    ctx.strokeStyle = 'black';
    ctx.lineWidth = 5;

    // fill an entire rectangle
    // then stroke around it's edges with red.
    ctx.fillRect(this.x, this.y, this.size, this.size);
    ctx.strokeRect(this.x, this.y, this.size, this.size);
  }
}
http://www.martinrinehart.com/frontend-engineering/engineers/html/html-tag-history.html
lots of rects with mouse movement!