Chuck McQuilkin

my writings, design experiements & code

Web Designer Depot Accessibility Article

Posted by on Jan 19, 2016 in UX, Web Design | No Comments

I wrote an article inspired by all that I have learned so far about accessibility on Web Designer Depot.

Patterns with Processing

Posted by on Sep 29, 2014 in Art, Code | No Comments

Over the last year or so I have been experimenting on and off with Processing, the programing platform for designers and artists. You can see the full potential of Processing in a book I recommend called Generative Gestaltung. But Processing doesn’t have to be used to create interactive prototypes or generative art. It can also be used to generate complex 2D patterns. The programs that created the images below are relatively easy to understand but still produce remarkable results.

Nested “for” loops were used in different combinations to create the patterns below. These programs (called processing “sketches”) create a set of x and y coordinates and replicate a line, shape or a pattern down and to the right across the x and y axis. In the Fish Scales image below the magic happens here:


for (int x = 0; x<=width; x+=20) // loop of x
{
  for (int y=0; y<=height; y+=20) // loop of y
  {
     ...
     ellipse(x, y, 40, 40);
  }
  ...
  ellipse(x,y,40,40);
}

Above you will see β€œfor” loops, one inside the other (with some extra code redacted). Basically a for loop sets a counter, tests for a condition, then iterates. The loop travels across the image, testing whether the sequence has have left the bottom or right edge of the image and adding new circles as it goes. I have linked the images of the Processing sketches to their authors (and code).

processing dot pattern Escher-like Processing Pattern Fish Scales Processing Pattern Plaid Processing Pattern Triangles Processing Pattern Truchet Processing Pattern Truchet Processing Pattern Truchet Processing Pattern Truchet Processing Pattern

Simply-List: iOS Web App with Local Storage

Posted by on Nov 15, 2013 in Code, Snippets, Web Design | No Comments

As Steve Jobs famously said, “Design is how it works.” The role of a Web designer increasingly requires some ability to write code because good design goes beyond appearances.

I built my own mobile web app to challenge myself to design a web app that would look and feel like a native iOS app. A todo list app makes a good beginner project. A warning, because my aim is targeting iOS it has not been designed to work on Firefox or IE:

Try Out Simply-List


Local storage is relatively new to the web, and a part of the HTML5 specification. It allows web applications to store more data on the client’s device than will fit in a cookie and retain it even if the user reloads the page. Local storage is currently supported by all major browsers except Opera Mini.

Apple’s HTML5 Offline Application Cache spec provides guidelines for creating offline web apps. Incorporating these guidelines into the web app mean that the app will not only store the user’s to-dos when they load the app in their browser but it will work when the user has no Internet connection. There are two main things that need are needed to make the app function offline on iOS. A link to a manifest file needs to be included at the top of the HTML document:


<html manifest="path/filename">

Add the following tags to instruct iOS to hide the status bar and tell iOS where to find the app’s startup and iOS icons:


<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta names="apple-mobile-web-app-status-bar-style"content="black"/>
<link rel="apple-touch-icon-precomposed" href="apple-touch-icon-precomposed.png" />

Some additional tags instruct iOS to hide the status bar and tell iOS where to find the app’s startup and iOS icon images. When the user saves the app to their home screen, it shows up there just like a native app. When the user launches the app, the startup screen fills the screen of their device while the app loads.

Creating the manifest file is not as complex as it may sound. A manifest file is just a text file that is served with the MIME type of “text/cache-manifest” and saved with a filename ending in “.manifest.” Here is an example:


CACHE MANIFEST
# v20131109

# cache 

index.html

You can change the MIME type with your FTP program (or the command line). The manifest file is just a list of all the files your app needs to function offline.

HTML

The HTML structure is a container div surrounding a div for the todo list that contains a clear all button, header, and placeholder unordered list and an input form to add to the todo list. Simplicity is the goal so we omit an add button, instead an item will be added when the user exits the input field.

JavaScript

First we’ll create the function that runs the app (named Todos). This function will set most of the functions that will react to user input. The most important of these is the function below, bound to the change event on the input field (named description). This function will add whatever the user leaves in the form to the unordered list when the user exits the field and trigger the save function:


        $('#description').change( function() {
           var todo = $('#description').val();
           var listItems = $("#todos").children();
           var newID = listItems.length + 1;
           $('#todos').append("<li id='"+newID+"'><input id='checkbox"+newID+"'class='checkbox' type='checkbox'/><label for='todo"+newID+"'>" + todo + "</label><a class='delete-btn icon-cancel-7' id='delete-btn-"+newID+"'>Delete</a></li>");
           $('#form')[0].reset();
           addSwipeTo("#todos li");
           saveTodos();
           return false;
        }); 

The user’s input will be appended to the end of the list. The save function below will update local storage.


    var saveTodos = function() {
        $('li').each(function(i) {
            var todo = $(this).html();
            window.localStorage.setItem("ToDo:"+ (i+1), todo);
       });
    };

Creating a single save function means that this code won’t need to be re-written several times within the final app. All the local storage code will be within an if statement that checks whether the user’s browser supports local storage. The save function itself simply saves all the HTML content within each list item. Local storage can only save data in key value pairs. here we create a key by looping over the items in the list and adding “ToDo:” to the front of the incremental value (i) to avoid conflicts with any existing data in the user’s browser. The value corresponding to each key becomes the HTML content of each list item.

The CSS

The appearance of the check mark and the strike-through effect are accomplished using CSS and an icon font. It’s a nice effect that I stumbled upon on CSS Deck. The CSS uses a :before pseudo-element to position an attractive blue check box over the default HTML checkbox (which is hidden) and a :after pseudo-element to cover the empty box with a check-mark icon when the user checks off an item. The description of the todo item is crossed off using the plain HTML strike-through property. The icon font from Fontello allows us to add a check-mark icon to checked off items without using a CSS sprite. Icon fonts are vectors so they will display at full resolution on any display without adjustments, they are also smaller than their CSS sprite equivalent. Fontello makes it easy to include icon fonts in web projects.


	.to-do-list input[type=checkbox] {
		cursor: pointer;
		position: relative;
		visibility: hidden;
	}

The CSS above hides the HTML checkbox. The code below adds the custom checkbox icon after HTML checkbox and the strikethrough:


	.to-do-list input[type=checkbox]:checked:after {
                font-family: "todo";
                color: #999;
                font-size: 20px;
                font-weight: 100;
                /*absolutely positioned*/
                position: absolute; top: 0; left: 0;
		border: 2px solid #fff;
		color: #979797;
		content: '\e804';
	}
	.to-do-list input[type=checkbox]:checked + label {
		color: #979797;
		font-weight: normal;
		text-decoration: line-through;
	}

Mobile apps should support swipe gestures as well as tap/click equivalents. Luckily there are several libraries that allow us to detect swipe-events in mobile web apps. Here I use touch swipe to detect a generic right or left swipe gesture to show a delete button for over the swiped item. JQuery allows us to animate the appearance of the delete button. After the function has been defined it needs to be bound to the link items.

The delete button also uses our icon font for the “x” icon. The buttons already have event listeners and events attached to them in the ToDo function, shown below. When the user clicks on a delete button, the button’s parent list item’s ID is defined as a string, the ID is extracted from the end. We use slice here because we know the beginning of the list item’s ID will be prefixed with “todo” but we are not sure whether the ID will be one or two digits. We then search local storage for the item matching the ID and we remove it. The list item is then removed from the DOM with another JQuery animation. The complete JavaScript code is below:


(function() {
    //Enable swip to delete
    var addSwipeTo = function(selector) {  
         $(selector).swipe("destroy");
         $(selector).swipe({
            swipe:function(event, direction, distance, duration, fingerCount) {
                //console.log("You swiped " + direction );	
                if ( direction === 'left' || direction === 'right' ) {
                    (this).find('.delete-btn').animate({ opacity: 1, width: 'toggle' }, 200).addClass('open');
                } else { null }
            },
            threshold:0 //Default is 75px, set to 0 so any distance triggers swipe
          });
    };
    var saveTodos = function() {
        $('li').each(function(i) {
            var todo = $(this).html();
            window.localStorage.setItem("ToDo:"+ (i+1), todo);
       });
    };
    addSwipeTo("#todos li");
    if (window.localStorage) {
        function retrieveToDos() {
            var i = 0;
            var k;
            if ( localStorage.length > 0 ) {
                for (i = 0; i <= localStorage.length; i++) {
                    k = localStorage.key(i);
                    if (/ToDo:d+/.test(k)) {
                        $('#todos').append('<li>'+window.localStorage.getItem(k)+'</li>');
                    }
                }
            } else {
                var isTouchDevice = function() {  return 'ontouchstart' in window || 'onmsgesturechange' in window; };
                if (isTouchDevice != 'true') {
                    $('.tn-box').addClass('tn-box-active');
                } else { null }
            }
        } retrieveToDos();
        $('#description').change( function() {
           var todo = $('#description').val();
           var listItems = $("#todos").children();
           var newID = listItems.length + 1;
           $('#todos').append("<li id='"+newID+"'><input id='checkbox"+newID+"'class='checkbox' type='checkbox'/><label for='todo"+newID+"'>" + todo + "</label><a class='delete-btn icon-cancel-7' id='delete-btn-"+newID+"'>Delete</a></li>");
           $('#form')[0].reset();
           addSwipeTo("#todos li");
           saveTodos();
           return false;
        }); 
        setTimeout(ToDos(),2000); 
    } else {
        alert('your browser does not appear to support local storage');
    }
    
    function ToDos() {
        var deletebtn = $('.delete-btn');
        deletebtn.css('opacity', 0);
        deletebtn.toggle();
        
        $('.delete-btn').live('click', function(e) {
            var str = $(this).attr("id");
            var id = str.charAt( str.length-1 );
            console.log(id);
            window.localStorage.removeItem("ToDo:"+ id);
            $(this).parent().animate({ opacity: 0.25, left: '+=50', height: 'toggle'}, 500);
        });
        $(':checkbox').click( function() {
           var id = $(this).attr("id");
           if ($(this).is(':checked')) {
               $(this).attr('checked', 'checked');
               //console.log(id + ' is checked');
               saveTodos();
           } else {
               $(this).removeAttr('checked');
               //console.log(id + ' is unchecked');
               saveTodos();
           }
        });
        $('#clear').click( function() {
            window.localStorage.clear();
            location.reload();
            return false;
        });
        addSwipeTo("#todos li");
    } // end ToDos function
})();

Sources

HTML5 makes it possible to develop many different types of simple mobile apps using HTML, CSS, and JavaScript instead of Objective C or Java. For more info on how to Local storage check out the following:

How to use local storage for javascript

Refer to the following links to learn more about developing iOS web apps:

Backchannel

Offline Application Cache

A script is available below that generates an “add to home screen” reminder balloon to encourage repeat visitors to save the app on their device:

Add to Home Screen

Coffee Blog Post on RPA’s blog

Posted by on Feb 10, 2013 in Advertising | No Comments

In July I traveled to Costa Rica to attend a friend’s wedding. During the trip I was able to visit a coffee plantation. Ever since then I have thought about the visit whenever I fill my coffee cup at RPA. I wrote a short blog post about my experience on RPA’s culture blog.

Robert Egger

Posted by on Aug 6, 2012 in Design | No Comments

It’s always encouraging to hear a designer talk about what inspires them. Regardless of the field, design attracts people who are dedicated to making everything that they touch better.

Design ideas do seem to come directly from the experience of working with your hands, even if it just means sketching before heading to the computer.

Who killed the inactive button state? – Blog Post on UX Booth

Posted by on Jun 26, 2012 in UX | No Comments

A few weeks ago I was designing a web application that included a form. When it came time to design and spec the submit button and I realized that including an inactive (or disabled) state for submit button was not only unnecessary, but it would detract from the usability of the application. Please check out the blog post I wrote about inactive states on UXBooth.

Digital Photography Cheat Sheet

Posted by on Jun 5, 2012 in Art | No Comments

An awesome digital photography cheat sheet by Miguel Yatco for keeping all the details straight.

Instapol – MobileHackDays 2011 Winner

Posted by on Sep 20, 2011 in Web Design | No Comments

Last weekend I had the pleasure to work with three brilliant Harvey Mudd students, Ozzie Gooen, Rahul Swaminathan and Paul Hobbs building this mobile web app Instapol for Mobile Hack Days. Instapol is a mobile web application that allows presenters to gain instant feedback from their audience. Instapol creates real-time graphs of audience responses to questions.

Stephen Powers Sign Painter

Posted by on Aug 15, 2011 in Advertising, Art, Branding, Design | No Comments

Quoted from Drawn. Hand-painted lettering is powerful and eclectic, but also unique and surprising. There’s nothing else quite like a hand-painted sign.