Part 3: Feedback and Conclusion
Work around 3: Canvas
Recently I had been doing some investigations into the new HTML5 features and functionality, including the canvas element. There had been quite a few impressive demonstrations of what canvas was capable of on compatible browsers. It seemed to be extremely responsive, and could deal in absolute positioning which would completely bypass the current text formatting issues. In fact, if canvas was fast enough there was a chance I could revisit the Caesar Cipher Letter Frequency exercise and have it update the entire bar graph every time the shift value updated.
All I would have to do is completely rewrite how the bar graph and labels are generated!
Fortunately, a lot of the code was still reusable. All of the loops and variables that used relative position could carry over. Mostly it was just a matter of substituting the new function calls, and dealing with slightly different variable passing. For instance, while the graphie function may require the four coordinate points of a quadrilateral to draw a rectangle, canvas needed the top left (x,y) positions as well as the width and height to do the same.
One portion of the graphie code I decided to keep was the interactive slider. While it would have been possible to recreate this using canvas, that would involve a lot of time and duplicate work that would only be used in this exercise. There were already a lot of nice touches in the existing slider, such as hovering over the dot increasing its size, the ability to automatically lock it to horizontal movement, and snapping to specific positions on a grid.
As it was, I simply created a function to update the canvas element, and then called it directly from the 'on move' event from the existing slider code. The quick proof of concept I worked up ran incredibly fast! Everything on the page updated smoothly, even as it redrew the entire bar graph every time it updated; and the graphics still looked exactly like the rest of the site.
Feedback: Workaround 3b
It was around this time my exercises started gaining notice on the khan boards...
My original submission was the exercise code just after workaround 1, which had gotten a lot of positive feedback from some of the other Khan volunteers; this was highly encouraging! That was also when one of the reviewers first brought up the Internet Explorer issue and started my misadventures in CSS browser compatibility and IE conditional statements. Which eventually led me to this point in the story...
So I finally managed to grab the ear of some of the Khan developers, on both the Trello board and the chat channel. One of the first questions I asked them was what the specific browser compatibility specs were for the site. The response came back that they tried to support the most recent version of Fire Fox and Chrome, as well as Internet Explorer versions as early as 8.
IE 8 does not support the canvas element. Ahh...
But no worry! A quick bit of searching shows that people have already tackled this problem, and created a library called excanvas.js. Including and linking to this library on your website allows IE8 to generate canvas like graphics using the same canvas code you use for modern browsers, within certain limitations. The result is a 'canvas emulation' just for IE8 browsers, which reproduces most of the normal canvas functionality, albeit a little bit slower.
A quick IE conditional comment, GitHub update, and push to my repository meant I now had a fully working exercise that should behave identically on all of the required browsers!
Good effort! But...
Upon which I was notified that Khan academy had actually considered canvas before, but had rejected it in favor of Raphael.js for precisely this reason. They did not want to require an additional library such as excanvas, just for the sake of IE 8 compatibility. Instead, they opted for a solution that would run consistently on all browsers without artificial emulation (hence Raphael.js). Which means that canvas was out...
Which is kind of a shame, because canvas seems like it has a lot to offer both in terms of power and performance.
At first glance it also seems slightly contradictory, that wanting to avoid including the excanvas.js library just for the sake of IE8, results in them using the Raphael.js library just for the sake of IE8... but as I noticed, the excanvas IE8 emulation ran differently then it did on other browsers. The performance was slower, the graphics were rendered differently and slightly 'off'. At least with Raphael, the way it behaves in IE8 is the same way it will behave in modern Chrome, or Firefox, or Android.
As I continued to talk with the developers, I was able to learn a bit more about how to use the graphie library and the differences between the two...
For one thing, Canvas is a stateless drawing platform. That means it does not natively keep track of the shapes or objects you are drawing on screen. In order to redraw one element you have to redraw everything on the screen, or at least everything in the surrounding sub section.
Raphael.js on the other hand, or at least its graphie implementation, actually keeps track of the state of the elements you draw by allowing you to assign them to variable names. It ended up being possible to assign those labels and bars I was generating to an array of variable, and then call var.remove() to delete individual elements while leaving the rest of the screen alone. Otherwise I would have had to redraw the entire screen or overwrite the existing image with a background colored rectangle.
They also gave me some advice about what might have been causing the label redrawing lag during my initial attempt. It seems that one of the variables passed to draw label was whether or not to use MathJax to format complex mathematical equation symbols as text. MathJax can potentially cause quite a bit of slow down every time it is called. While I am almost certain I was not enabling this option on my initial attempt, unfortunately that was before I had made my first GitHub commit so I will never be sure.
Regardless, this gave me a new direction to work in. Canvas was out, so now I would retry creating the graphie solution with this new found knowledge.
There and back again
One of my immediate concerns was that I would no longer be able to update the bar graph image, without the speed that canvas had afforded. It was a very nice and responsive feature, but ultimately it was not really necessary. Consistent coding conventions and compatibility would have to come first.
Still, I started walking back all of my previous changes, from the canvas implementation to the CSS and HTML injection workarounds. With the new bits of advice from the Khan developers, I quickly coded up the chang I would need to get a graphie version of the exercise functional again. Then, after a quick save and some trepidation, I opened up the page in my local test environment and began testing the interactive slider...
It worked! Sailing the slider across the screen caused all of the labels to update exactly where they needed to be! A quick tour of the other browsers showed similar result, meaning no more browser compatibility issues!
The graphie exercises were definitely slower then canvas had been, but no where near as bad as the crippling lag my very first implementation had suffered. With renewed enthusiasm and daring to hope, I next set out to see if I could still salvage the bar graph update feature as well.
This required one minor rework, in order to facilitate the var.remove() function for the bar graph. Previously the bar graph and the slider had been in two separate script sections on the page. In order to keep a persistent array of the bar 'objects' though, I would have to combine the two tools into a single script block.
In addition to combining the code logic, this also posed a slight problem with the scale of the image. When designating an area to be used in a graphie drawing, one of the things the template required you to include was the scale of the image. In the case of the letter frequency graph, I had to scale the image quite small in order to fit the 52 columns as well as spacing.
The Interactive slider however, had required much less scaling to fit on the page. Trying to include the slider into the same block as the bar graph meant that they would be using the same scale values. So either one or the other would be skewed in the process.
It was a little annoying, but more tedious than difficult to straighten that out. I opted to adjust the slider to the bar graph scale values, since that would result in fewer changes to even them out. After some tweaking in values, both of the tools looked presentable and were properly formatted; And I'll take pixel precision art tweaks over browser compatibility issues any day. A quick save and load and...
Success! The bar graph redraw actually worked as well, and without any additional slow down. What ever had happened with the label redraw between my first iteration and now, it was finally all falling into place. Again, not quite as fast as the canvas solution had been; but it was a consistent solution and meant I could git rid of all of the other fiddly workarounds and extraneous libraries I had included to get my other versions working.
So after a long string of various workarounds, challenges, and leanings, I arrived at a working solution back where I had started; though not without being a little wiser for the journey.
A lot has happened since submitting my first iteration, while all this was going on...
During my initial submission, one of the people whose attention I had attracted was actually the same person who had created the Cryptography video series for the site, Brit Cruise. He asked me if I would like to help him design a Cryptography Challenge\Assessment that he had been planing on creating for the site! Naturally I jumped at the chance.
This resulted in yet another adventure in collaborative design and development, which I probably won't go into detail about here. A lot of it was back and forth discussion about narrative and puzzle design, though I also got to do some quick scripting to create the tools we used to generate the secret codes.
Frankly it would spoil to much of the actual codes involved if I went into it in detail. But if you are really interested you can find that the challenge has already been released on the site as the Cryptography Challenge 101! Here's a quick teaser of the final code in the challenge! Though you will probably need some information from the site to figure it out...
Meanwhile, the other exciting news is that they have begun to release my exercises on the Khan Academy site! The first exercise on Caesar Cipher Decryption can be found in their Ancient Cryptography series, and the others are soon to follow. They might not add these exercises to the knowledge map, or at least not right now; but still, it is exciting to have been able to contribute something that was actually published on the site!
While that is all for the project article series, the exercise adventure isn't quite over yet...
It seems during the course of my own development, they have been working on the Khan site as well. One of the things they have been making changes to is the way in which they draw labels on the page...
This has resulted in a completely new graphical glitch that slightly and temporarily distorts my Cipher Slider labels again. It seems that iterative development is never done... but that might just have to be a story for another day!