Basic JavaScript Graphics

Let’s do some graphics, but not much. Just the basics. Baby steps. Baby steps. All we’re doing here is one example for each type of graphics technique.

Simple DOM Manipulation

A browser window contains elements. Elements can have colors (even gradients), borders, background colors, background images, fancy borders, opacity settings, and all kinds of paddings and margins. Elements can even be images! With rounded borders we can get circles. Importantly, CSS also allows elements to be positioned. With JavaScript, we can vary all of these settings over time to make animations.

Directly manipulating the DOM is tedious and error-prone and requires a lot of code. You rarely would ever do such a thing in real code; however, it is useful to know how it works. So study the code here a little and don’t fret too much if the code seems unwieldy.

Here’s a bouncing ball program using low-level, DOM-manipulating JavaScript:

Here’s the code. Note the use of requestAnimationFrame, which takes a function that should be executed before the next time the browser repaints.

bouncingballs.js
/*
 * A script illustrating bouncing balls. The HTML should provide a container div
 * (id = 'bounceContainer') and a button (id = 'startOrStopBounce') that toggles
 * the animation.
 */

window.addEventListener('load', () => {
  const container = document.getElementById('bounceContainer');
  const button = document.getElementById('startOrStopBounce');

  class Ball {
    constructor(x, y, dx, dy, diameter, color) {
      // Initial model
      Object.assign(this, { x, y, dx, dy, diameter });

      // Initial view
      this.div = document.createElement('div');
      Object.assign(this.div.style, {
        left: `${x}px`,
        top: `${y}px`,
        width: `${diameter}px`,
        height: `${diameter}px`,
        borderRadius: `${diameter / 2}px`,
        backgroundColor: color,
        position: 'absolute',
      });
      container.appendChild(this.div);
    }

    move() {
      // Update the model
      [this.x, this.y] = [this.x + this.dx, this.y + this.dy];
      if (this.x < 0 || this.x > container.clientWidth - this.diameter) {
        this.x = Math.max(0, Math.min(this.x, container.clientWidth - this.diameter));
        this.dx = -this.dx;
      }
      if (this.y < 0 || this.y > container.clientHeight - this.diameter) {
        this.y = Math.max(0, Math.min(this.y, container.clientHeight - this.diameter));
        this.dy = -this.dy;
      }

      // Update the view
      [this.div.style.left, this.div.style.top] = [`${this.x}px`, `${this.y}px`];
    }
  }

  const advance = () => {
    balls.forEach(ball => ball.move());
    if (button.value === 'STOP') {
      requestAnimationFrame(advance);
    }
  };

  button.addEventListener('click', () => {
    button.value = (button.value === 'STOP') ? 'START' : (requestAnimationFrame(advance), 'STOP');
  });

  const balls = [
    new Ball(20, 70, 3, 2, 30, 'rgba(90, 255, 95, 0.5)'),
    new Ball(500, 300, -3, -3, 35, 'rgba(200, 41, 199, 0.5)'),
    new Ball(140, 10, 5, 5, 40, 'rgba(250, 50, 10, 0.4)'),
  ];
});

CSS-Only Graphics

There are millions of examples on the web of using only CSS for interesting graphics. Here are just a few:

See the Pen Pure CSS Rainbow Sinus Road by Keith Wyland (@keithwyland) on CodePen.

Canvas

HTML features a <canvas> element, designed for drawing.

Canvas drawing is done with JavaScript. You obtain a context object for the canvas, either a 2d context or a 3d context and use methods on the context object to draw. If you need interactivity and animation, basic JavaScript methods for timing and events apply as usual. Here’s an example we’ll go over in class:

shapes.js
/*
 * A script that draws random shapes in a canvas whose id is named 'shapes'.
 */

window.addEventListener('load', () => {
  const canvas = document.getElementById('shapes');
  const width = canvas.width;
  const height = canvas.height;
  const ctx = canvas.getContext('2d');
  const random255 = () => Math.floor(Math.random() * 255);
  const randomColor = () => `rgba(${random255()},${random255()},${random255()},0.5`;
  const randomX = () => (Math.random() * width) - 50;
  const randomY = () => (Math.random() * height) - 50;
  const randomSide = () => (Math.random() * 100) + 20;
  const randomRadius = () => (Math.random() * 50) + 20;

  const drawShapes = () => {
    for (let i = 0; i < 50; i += 1) {
      ctx.fillStyle = randomColor();
      ctx.fillRect(randomX(), randomY(), randomSide(), randomSide());
      ctx.fillStyle = randomColor();
      ctx.beginPath();
      ctx.arc(randomX(), randomY(), randomRadius(), 0, Math.PI * 2, true);
      ctx.closePath();
      ctx.fill();
    }
  };

  canvas.addEventListener('click', drawShapes);

  canvas.addEventListener('dblclick', () => ctx.clearRect(0, 0, width, height));

  drawShapes();
});

SVG

TODO

D3

Start at the D3 Gallery.

TODO

WebGL

WebGL, (Web Graphics Library) is a JavaScript library for 3D graphics. Your 3D graphics use your device’s GPU for hardware acceleration. Rendering is done on a canvas element. Here’s a very basic example:

TODO