Custom modal windows using canvas and MooTools

In my previous post Fun with canvas and MooTools: a Rectangle class, I explained that I wanted to make a modal window for a project at my workplace. I was interested in using MochaUI, but felt it was a bit heavy for my needs. I started playing with the canvas element (using excanvas.js for Internet Explorer support), and wound up making a useful Rectangle class that can quickly draw shapes in canvas using JavaScript.

Shortly afterward I built a simple modal window class named Modal using MooTools. This class combines a dynamic canvas drawing API (the Rectangle class) with dynamic DOM element generation to create on-demand modal windows using no external images. My goal was to make this about as easy to use as a normal JavaScript alert, prompt or confirm window.

I’ve been playing with it over the last week or so, and while it’s nowhere near perfect (esp. the ‘close’ button), I think it’s good enough for my project at work. I figured I’d post it here in case anyone wants to have a look. Feel free to use it if you like, but remember it comes as-is with no warranties! View Modal.js here.

Note: The code in Modal.js is subject to change!

I’m completely open to suggestions for code improvements (my code still feels ‘hacky’ to me), but I’m not really interested in adding new features at the moment. If you really want a full-featured, well-crafted window system, you should use Greg Houston’s MochaUI.

Modal Examples:

The default

The simplest way to invoke the window is:

var modal = new Modal({ title: "My title", html: "<p>My html code goes here</p>" });

Simple no-frills

You have the option of not using a window titlebar or ‘close’ button:

var html = "<p>This is a modal window without any title bar.</p>";

var modal = new Modal({
    html: html,
    width: 300,
    height: 200,
    edgeMargin: 1,
    windowRadius: 9,
    opacity: 0.80,
    colors: {
        modalBackground: "#CCC",
        windowBackground: "#999",
        contentBackground: "#EFEFEF"
   },
   showTitleBar: false
});

Public Methods

close() This closes the modal window. Once the window is closed, the elements are destroyed and garbage collected using MooTools’ element.destroy method.

var mymodal = new Modal({
    title: "My title",
    html: "<p><a href='#' onclick='return goAway()'>Close me</a></p>"
});

function goAway(){
    mymodal.close();
    return false;
}

Options

The options available in the Modal class are:

Text

  • title (String) Text content for titlebar. String format, loads into an h1 element.
  • html (String) Text content for the main window content. Loads into a div.
  • padding (Number, default is 12) Indicates how much padding the content div gets, in pixels.
  • font (String, default is “Verdana, Geneva”) Sets CSS style for the title and window content. Can be overridden by inline styles.
  • fontSize (String, default is “small”) Sets CSS style for the window content div. Can be overridden by inline styles.

Size/shape

  • width (Number, default is 350) Width of window before the drop shadow gets added, in pixels.
  • height (Number, default is 200) Width of window before the drop shadow gets added, in pixels.
  • shadowSize (Number, default is 6) Size of drop shadow, in pixels (note: not 100% pixel perfect measurements).
  • titlebarHeight (Number, default is 28) Size of titlebar, in pixels.
  • edgeMargin (Number, default is 1) Size of window chrome between shadow and content area, in pixels.
  • windowRadius (object OR number) Size of window corner radius, in pixels. If a number is specified, all four corners get the same radius. If an object is used, each corner gets the number specified (see below).
    • windowRadius.topLeft (Number, default is 9)
    • windowRadius.topRight (Number, default is 9)
    • windowRadius.bottomLeft (Number, default is 3)
    • windowRadius.bottomRight (Number, default is 3)

Behavior

  • animate (Boolean, default is true) Indicates whether or not to fade out the modal background when dismissing the window.
  • backgroundClickDismissesModal (Boolean, default is true) Indicates whether or not clicking the background will dismiss the modal window.
  • closeButton (Boolean, default is true) Indicates whether or not to include a close button. Only works when showTitleBar is also set to true.
  • showTitleBar (Boolean, default is true) Indicates whether or not the title bar should be rendered.

Colors

  • opacity (Number, default is 0.66) Indicates the opacity level of the background modal div. Number must be between 0 and 1.
  • colors (object) Child properties are used to specify colors for window elements. All color parameters accept standard CSS color conventions, including hex and RGB.
    • colors.modalBackground (Default is #000) Background modal div.
    • colors.windowBackground (Default is #AAA) Window chrome color.
    • colors.windowTitleBar (object) Used to create a gradient background for the window’s title bar. Accepts two properties: top and bottom.
      • colors.windowTitleBar.top (Default is “#F5F5F5”)
      • colors.windowTitleBar.bottom (Default is “#AAA”)
    • colors.contentBackground. (Default is “#F8F8F8”) Color of the canvas element behind the content div.
    • colors.closeButton (object) Used to create a the background and stroke for the closeButton.
      • colors.closeButton.fill (object) Used to create a gradient background for the closeButton.
        • colors.closeButton.fill.top (Default is “#F5F5F5”)
        • colors.closeButton.fill.bottom (Default is “#F36”)
      • colors.closeButton.stroke (object) Used to create a gradient stroke for the closeButton (does not work in Internet Explorer).
        • colors.closeButton.stroke.top (Default is “#FFF”)
        • colors.closeButton.stroke.bottom (Default is “#F00”)

Drawbacks

A system like this is bound to have drawbacks, and the biggest one is probably accessibility. Users with a screen reader or similar device may find the custom modal completely unusable. This is the same problem most RIAs face due to dynamically generated content. I’m considering implementing a check that uses a traditional JavaScript alert, prompt or confirm window in lieu of the custom modal if the user is using a screen reader. The check may or may not be based on whether WAI-ARIA mode is activated, but I have a long way to go before I’m ready for that! (Side note: To see WAI-ARIA in action, check out Google Reader.)

Another drawback is the mingling of my CSS with my JavaScript; in most cases I don’t like using JavaScript to set styles, except to set a classname. However, in this case I want the modal window to be as simple as possible and look nice out-of-the-box without requiring adding CSS files and all that jazz.

Lastly, I’d like to point out that the window doesn’t auto-size to fit the content. However, if the the HTML content doesn’t fit, the main content div will sprout scrollbars, ensuring you still have access to all of the content.

Anyway, this has been a fun experiment for me. It’s taught me a lot about what goes into creating feature-rich and flexible JavaScript widgets. I have nothing but respect for people who make JavaScript-based UI components like the folks behind MochaUI, Dojo, and YUI. It’s a TON of work.

Fun with canvas and MooTools: a Rectangle class

Greg Houston’s uber-cool MochaUI has led me to experiment with the canvas element the last few days.

I first saw MochaUI sometime in 2007. While I was duly impressed, I couldn’t quite find a use for it and filed it away in my bottomless “play with this later” drawer.

Recently at work I realized I needed a good modal window that was more extensible than JavaScript’s built-in confirm and prompt windows. MochaUI looked like a handy way to get slick modal windows into my project, but I soon realized that MochaUI is designed to do much, much more than I need, and therefore is (for my purposes) bloated. So, in typical DIY fashion here at pipwerks, I decided to borrow a page from Greg’s book and make my own MochaUI-inspired modal window using the canvas element, CSS, HTML, and MooTools.

Before I could get into the full modal window code, I needed to understand the canvas element, and learn how to manipulate it. Luckily for me, it isn’t much different than ActionScript’s drawing API. After evaluating what I’d need for my little modal window, I whipped up a MooTools-based JavaScript class that produces canvas rectangles in the blink of an eye. Check out the test suite.

Here’s how you’d instantiate a plain-jane rectangle with no stroke and a pink fill:

var canvas = new Element("canvas", {width:300, height:200}).inject(document.body);
var rect = new Rectangle({
    canvas: canvas
    width: 300,
    height: 200,
    x: 0,
    y:0,
    fill: "#F36"
});

Want rounded corners? Just add a radius parameter:

var rect = new Rectangle({
    canvas: canvas
    width: 300,
    height: 200,
    x: 0,
    y:0,
    fill: "#F36",
    radius: 9
});

As demonstrated by the test suite, the class includes the ability to specify the radius of each corner, the fill type and color (solid or linear gradient), and the stroke weight and color (including linear gradient).

For those of you unfamiliar with the canvas element, there are a host of additional options I chose not to build into my class, including join type for lines, radial gradients, and image backgrounds. For the purposes of my modal window, I didn’t need that stuff and wanted to keep it simple (and smaller file size). Feel free to modify the class for yourself, though.

Sometime in the next day or two, I’ll write about my modal window and provide test links. I’ll also cover the fugly hack required to get Internet Explorer to work with canvas.

Until then…

UPDATE: Read about the Modal class here.

PS: Disclaimers:

  1. If you’re wondering why I didn’t include a sample of the class in action on this page, my WordPress install uses jQuery, which conflicts with MooTools. I didn’t feel like fighting it tonight.
  2. I don’t write JS classes often, so I’m sure mine could use some cleanup. Feel free to make suggestions!