Joseph Hallenbeck


April 22, 2014

Wanted: An Unobtrusive Javascript Framework

Filed under: Software Development — Tags: , , , — Joseph @ 9:42 pm

Flattr this!

I decided to spend the last couple of weeks introducing myself to some of the big MVC Javascript Frameworks that have gotten so much traction over the last couple of years. I sadly, have found the field littered with frameworks that happily violate the principle of Unobtrusive Javascript and am wondering — is there any solid MVC Javascript Framework that is clean and unobtrusive, will I need to keep rolling my own, or am I just a Luddite?

Unobtrusive Javascript

Now first, I must admit that I feel as though I am a technological Luddite when it comes to the rise of Javascript. When I started making websites the standard advice was to keep as much of the document generation on the server-side as possible and to practice what is called “unobtrusive” Javascript.

The idea of unobtrusive Javascript has been a paramount item of good front-end design. Namely, that you clearly separate your concerns and avoid reliance on server-side scripts. HTML ought be semantically distinct from style or behavior and we do this by keeping our markup in one file, our style-sheets in another, and our Javascript in a third file. We do not inline our styles nor our Javascript and we try to keep them distinct so that even if the style-sheet or Javascript never loads the unstyled, un-scripted document is still in a usable state.

The earlier concept, simply keeping things separated decouples the reliance of our code on any one element. We can change the markup, the style, or the behavior of our application without necessarily impacting the other two elements.

The latter idea is a concept refereed to as failing gracefully. Namely, it is that we put fall backs into our application such that if the Javascript does not work, the user can still make use of the web application. There’s a lot of ways that we can do something like this:

  • Have an ajax form submit normally if the browser does not support ajax
  • Add form submit buttons that are hidden using Javascript on load.
  • Make sure client-side generated content has some kind of fall-back view that is generated server-side

The list goes on and on, but you begin to get the idea. Vasilis van Gemert has opened a great discussion about arguments against building Javascript based documents and his comments section is ripe with the reasons that unobtrusive Javascript is still very much relevant to the day-to-day development of websites.

Obtrusive Javascript is where you get page behaviors and views that are only accessibly if the client has Javascript support. The result of these websites is that they are completely un-usable without their supporting Javascript files. We can see this on websites that:

  • Only allow a form to be submitted via a Javascript call
  • Links whose destination is dynamically generated with Javascript
  • Views that are created by generating and appending DOM elements client-side rather than server-side

Now, I grant that unobtrusive Javascript can be hard. Sometimes there just isn’t a suitable fallback. Some times you are running late on a project and the fact that it runs fine on 99% of the browsers means it’s time to just shove it out the door and be on your way. However, I do believe it is a good idea to keep the principle of separating concerns and failing gracefully in mind whenever adding client-side behaviors to an application.

State of Affairs for Javascript MVC

I will address in some article my own personal solutions to structuring a Javascript application as well as the challenge of coming up with a solid framework for addressing UX and DOM manipulation without turning into spaghetti code or re-inventing the solution with each website. Yet, it is typically a good idea to go with a community framework in a team environment since it offers a familiar structure between projects and programmers on a team. For this reason, I embarked on working my way through some of the more popular Javascript MVC frameworks to see what they offer and decide which one, if any offers an unobtrusive solution. My concern is that on a cursory look (AngularJS and EmberJS) both seem to scatter Javascript snippets throughout the document and in the latter case invents a whole new template language that it injects into a script tag. Oh dear.

The only Javascript framework that I have come upon that makes any attempt at keeping any kind of unobtrusive fallback seems to be Knockout.js. That said, it is not the sexiest of new frameworks out there.

Knockout.js

Example:

HTML

<p>First name: <input data-bind="value: firstName" /></p>
<p>Last name: <input data-bind="value: lastName" /></p>
<p>Full name: <strong data-bind="text: fullName"></strong></p>

Javascript

// This is a simple *viewmodel*
function AppViewModel() {
  this.firstName = ko.observable("Bert");
  this.lastName = ko.observable("Bertington");
  this.fullName = ko.computed( function() {
    return this.firstName() + " " + this.lastName();
  }, this);
  this.capitalizeLastName = function() {
    var currentVal = this.lastName();
    this.lastName( currentVal.toUpperCase() );
  }
}

// Activates knockout.js
ko.applyBindings(new AppViewModel());

Knockout works by using the data attribute to bind to DOM elements. This means that if the Javascript happens to fail we are still left with your typical document with typical document behaviors. Take the above example clip. If the data-bind attributes are ignored we would still get a form with a first and last name. Indeed, we could even fill that form in server side by assigning value="Bert" and value="Bertington" to the first name and last name inputs.

On top of this, there is something about Knockout that just makes sense. It isn’t as flashy as Angular or Ember. It doesn’t seem to incorporate any new trendy templating systems, massive API libraries, or require us to create half a dozen separate Java script files for controllers, models, and parts of views.


February 3, 2014

Fiddling with HTML5’s Canvas

Filed under: Software Development — Tags: , , — Joseph @ 8:33 pm

Flattr this!

I had my first real exposure to the HTML5 Canvas element this week. It was a fairly fun transport back to Intro to Computer Graphics and my school days working in C.

Canvas provides a very simple bitmap surface for drawing, but it does so at the expense of loosing out on a lot of the built-in DOM. I suppose there is a good reason for not building an interface into canvas to treat drawings created with contexts as interactive objects, but sadly this leaves us with having to recreate a lot of that interactivity (has a user clicked on a polygon in the canvas? is the user hovering over a polygon on the canvas?) up to us to implement using javascript.

So let’s dive in and see what canvas is capable of doing!

This complete tutorial is available as a fiddle on jsfiddle.net. Check it out.

Getting Started

Let’s begin with the absolute basics. First, we need the element itself which is simply a “canvas” element with a specified id that we’ll later use to interact with it. By putting some textual content inside the canvas element we give some fallback for older browsers that might not offer canvas support.

<canvas id="myCanvas">Your browser does not support canvas.</canvas>

Now we need to interface with the element itself. This is done using javascript:

var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d")

We are doing two things here. First, we are getting the canvas element from the DOM, second we are getting a context from that element. In this case that context is the “2d” context which defines a simple drawing API that we can use to draw on our canvas.

Drawing a Polygon

The “2d” context API defines a number of methods for interacting with the canvas element. Let’s look at how we can use this to draw a blue triangle on our canvas:

context.moveTo(25, 25);
context.lineTo(75, 100);
context.lineTo(125, 25);
context.fillStyle = "#0000ff"; // Alternative: "rgba(0,0,255,1)"
context.fill();

Recall that pixels on a computer screen are mapped as though the screen was in the fourth quadrant of a plane — that is they spread out with x values growing larger as the pixels are placed further to the right and y values growing larger as they move towards the bottom of the screen. This puts the value 0,0 at the upper left corner of your screen and 25,100 located twenty five pixels to the right and one hundred pixels from the top.

The first three lines of code can be thought of as moving an invisible (or very light) pencil around the canvas. The first moves our pencil to the position 25,25 which should start the drawing near the upper-left corner of the canvas. The second line draws a line down 75 pixels and over and additional 25 pixels. The third returns to 25 pixels from the top, but 125 pixels from the left-hand side of the canvas.

The forth and fifth lines simply define the color to fill our polygon with and to actually do the filling. In this case we passed a hex value for blue, but we could alternatively used and rgba (red, green, blue, alpha) value if we wanted transparency.

Adding Interactivity

One thing you will note about our blue triangle: we can not tie off DOM events to it. The context merely draws on the canvas, but the drawings themselves do not exist in the DOM. The closest we can do is capture events on the canvas itself (onClick, hover, etc.). It is up to us to then decide if those events were just interacting with the canvas or whether they should are interacting with something drawn on the canvas.

First, we must recognize that each position that we move or draw the context to is a vertices.

PNPOLY is our solution, and to be honest, I did not come up with this one but found the answer on Stack Overflow

function pnpoly( nvert, vertx, verty, testx, testy ) {
  var i, j, c = false;
  for( i = 0, j = nvert-1; i < nvert; j = i++ ) {
    if( ( ( verty[i] > testy ) != ( verty[j] > testy ) ) &&
      ( testx < ( vertx[j] - vertx[i] ) * ( testy - verty[i] ) / 
      ( verty[j] - verty[i] ) + vertx[i] ) )           
    {
        c = !c;
    }
  }
  return c;
}
$('#myCanvas').click( function( e ) {
  var x = e.clientX;
  var y = e.clientY;
  alert( pnpoly( 3, [25,75,125], [25,100,25], x, y ) + ' x:' + x + ' y:'  + y );
});

PNPOLY takes five variables: the number of vertices (corners) on our polygon, an array of the X values, an array of the Y values, and the x/y cordinates where the user clicked on the canvas. Now if we add this to our code and run it we should see an alert saying either true or false as to whether we clicked inside or outside of our triangle.

Accounting for Global (Window) and Local Cordinate Systems

It is not easy to see on the jsFiddle website, but we can run into some issues with mapping between the local and global coordinate systems. e.clientX and e.clientY map to the document coordinate system not the canvas itself. We may, in some instances find ourselves needing to map between the local (canvas) coordinates which begins with 0,0 at the upper-left corner of the canvas element and the document coordinate system which begins with 0,0 at the upper-left most corner of the page.

This can occur when our canvas is absolutely positioned or positioned inside a fixed element. In these cases we must include the offset of the canvas from the document coordinate system to find where the click is actually occurring:

$('#myCanvas').click( function( e ) {
  var offset = $(this).offset();
  var x = e.clientX - offset.left;
  var y = e.clientY - offset.top;
  alert( pnpoly( 3, [25,75,125], [25,100,25], x, y ) + ' x:' + x + ' y:'  + y );
});

Note our additions to the first three lines in our function. The first line retrieves the offset for the position of our canvas from it’s global position. We then subtract that offset from e.clientX and e.clientY to get the coordinates of the click in the canvas’s coordinate system.

We might also need to add another variable to our offsets and that is to account for scrolling. If we have a canvas inside a fixed position element then we must also account for any potential scrolling that might have occurred. We do this via the scrollTop() and scrollLeft() jQuery functions:

$('#myCanvas').click( function( e ) {
  var offset = $(this).offset();
  var x = e.clientX - offset.left + $(window).scrollLeft();
  var y = e.clientY - offset.top + $(window).scrollTop();
  alert( pnpoly( 3, [25,75,125], [25,100,25], x, y ) + ' x:' + x + ' y:'  + y );
});

In fact, we can safely include the offset(), scrollLeft(), and scrollTop() calls even if we are neither using absolute nor fixed positioned elements since these values will simply be 0 in the case of a statically positioned canvas.


March 28, 2011

Automatic Lightbox on WordPress via JavaScript

Filed under: Software Development — Tags: , — Joseph @ 2:37 am

Flattr this!

I dabbling more and more with JavaScript lately. In the past my solutions to most site-related problems has been to write server-side PHP modules to add whatever functionality I needed. Since I started using WordPress to manage my site content, I started finding myself using JavaScript to ease-up on the amount of html that I need to type into my post boxes. Take Lightbox for an example. Lightbox is a pretty amazing piece of JavaScript that easily creates animated slideshows out of a series of image links. I use it on my art and photography pages. The problem with Lightbox? Telling Lightbox to animate a link rather than just link straight to the pictures is very verbose. For example to create this animation:

Ivan Sketch “This ink wash panel from my webcomic ‘Ivan @ the End of the World,’ shows my growing interest in the use of water-based ink washes to depict gradient shading in my works.”

I need to type the following into WordPress:

<a title="This ink wash panel from my webcomic Ivan @ the End of the World, 
          shows my growing interest in the use of water-based ink washes to 
          depict gradient shading in my works."
   rel="lightbox[sketch]" 
   href="http://joehallenbeck.com/images/art/sketch_ivan.jpg" >
    <img class="aligncenter" 
         src="http://joehallenbeck.com/images/art/sketch_ivan.jpg" 
         alt="Ivan Panel" width="60%" />
</a>

Why so much text? First, Lightbox uses the anchor’s title attribute to generate a caption rather than the image’s alt text. The result is the repetition of the string value for the alt and title attributes. Second, lightbox uses the anchor tag’s href value to direct the browser to load the full resolution image. This allows the image tag to point to a smaller thumbnail picture. Yet in most cases of blogging, the thumbnail is just the original picture reduced to fit into the blog’s div. If this is the case than the href attribute on the anchor is merely replicating the src attribute on the image tag. What we really want, is to shorten the monstrosity above into this:

<a>
    <img class="aligncenter" 
         src="http://joehallenbeck.com/images/art/sketch_ivan.jpg" 
         alt="This ink wash panel from my webcomic 'Ivan @ the End of the World,' 
              shows my growing interest in the use of water-based ink washes to 
              depict gradient shading in my works." width="60%">
</a>

So much shorter! But how? The solution is in a very simple JavaScript function that I wrote which adds the Lightbox script to all images surrounded by empty anchor tags:

*  lightboxThis is a convenient method for transforming all anchored
*  images in a specified div into lightbox images. To use
*  lightboxThis call it during the onload event in the  tag
*  and pass it the divId for images that should be lightboxed.
*  @param string divId The unique id, all images wrapped in empty anchor
*   tags (&lt;a>&lt;/a>) in the specified div will be transformed into
*   lighbox images. Note: this method uses the img alt attribute
*   to determine the caption and will only work if an alt tag is
*   included in each image, if no caption is desired set the alt
*   attribute to alt=" ".
*  @param optional bool group If this parameter is set to true than
*   lighboxThis will group all images in the specified div into
*   a lighbox group with the name of the unique div id as the
*   group name (e.g. rel="lighbox[divId]")
*/
function lightboxThis(divId, group) {
    var anchors = document.getElementById(divId).getElementsByTagName("a");
    for (i = 0; i &lt; anchors.length; i++) {
        var innerChild = 0;
    innerChild = anchors[i].getElementsByTagName("img");
    if (innerChild[0] && !anchors[i].href) {
        anchors[i].href = innerChild[0].src;
        anchors[i].title = innerChild[0].alt;
        if(!group) { anchors[i].rel = "lightbox"; }
            else { anchors[i].rel = "lightbox["+divId+"]"; }
    }
    }
}

If you’re interested in implementing this on your own blog simply copy the function into your WordPress theme’s header and surround it with tags. Then you need to add the following to your theme’s <body> tag:

body onload="lightboxThis('blog_area')">

Where ‘blog_area’ is the name for the div id where your blog’s posts reside.




Copyright 2011 - 2017 Joseph Hallenbeck Powered by WordPress