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 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.
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.
Now we need to interface with the element itself. This is done using
javascript:
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:
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
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:
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:
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.
Perhaps one of the most scenic diversions from I-90 when driving across
Montana. A turn off at Big Timber and head south arcing along W. Boulder Road
to Livingston. In this instance, I caught a freak ranstorm that was coming down
over the wilderness.