Part Two: Interactive tools
The next step in creating my cryptography exercises for Khan Academy involves creating a set of interactive tools. By combining visual elements as well as interactive mouse events, it will make the individual problems a lot more engaging.
- Part 1: Khan Academy Code Base
- Part 2: Interactive Tools
- Part 3: Feedback and Conclusion
A pirates favorite kind of Graph...
For the first tool, I wanted to create a letter frequency bar graph that compares the average letter frequency of English to the letter frequency in a Caesar Cipher. This allowed the user to compare the difference between the two, and then figure out how much they would have to shift the graph in order for them to line up. There were already a few exercises that utilized bar graphs for mean, median, and mode exercises; which would serve as a good template for what I wanted to do.
The way the Khan framework builds a bar graph is using the graphie.js library (which works on top of raphael.js). This library gives you a series of functions to draw lines and basic geometric shapes on a web page. So in order to build something like a bar graph, every single line, rectangle, and letter has to be placed individually, using a absolute position relative to the image space. While out of context these shapes can be relatively meaningless, putting it all together results in the following image...
In this case, each of the blue rectangles were drawn in a loop, where the vertical value stayed the same but the horizontal value incremented for each pass of the loop. Same for the orange rectangles (and the alphabet labels), except they would have a slight offset such as +0.5 so they appeared next to the blue rectangles. Even the border of the bar graph was created using two separate class to a draw line function.
Getting the height of the rectangles was simply a matter of using the functions I had already created in my crypro library. One to return the array for the English language frequency, and another to dynamically build a frequency array based on a given encrypted message. Both of these arrays were normalized, and then scaled so they could be fitted to the size of the graph.
Eventually I might come back and add some more functionality to this graph. But the first version of this graph turned out rather well. So on to the next tool and the start of my problems...
Crossing the line
The next goal was to create a way for students to quickly translate an encrypted alphabet to its decrypted counterpart. While this is possible without a tool, it is a very time consuming task; and once a student has translated the first few letters they have probably already gotten the point. Khan has an example of one such tool in their programing sandbox, but I wanted a version that could be included on the exercise page (And didn't allow the student to outright spoil the answer by typing it in).
To accomplish this, I took advantage of a Khan library called interactive.js, which had been used in a few exercises to build interactive number lines. In these exercises, you could click and drag an orange dot to a specific point on the line to indicate an answer. This was accomplished using mouse click events, and even offered several options such as making sure the dot would 'snap' into position at certain points, or restrict its movement to a specific space.
For these exercises, I wanted the marks on the line to indicate letters with one side being the original alphabet and the other being the encrypted alphabet. Moving the orange dot to the right would then update the labels on the encrypted alphabet so you could see what a specific letter mapped to when you applied a specific shift. I could then reuse this tool on any number of crypto exercises. Encrypting or Decrypting. Caesar or Viegenere Ciphers.
The final result for my interactive slider looks like this.
However, things were a bit more complicated this time...
Performance Anxiety
My first attempt using both graphie.js and interactive.js, resulted in two issues.
While the interactive library automatically updated the position of the orange dot as it slides along the line, I would have to manually update the labels. This was currently done using a loop that drew each label individually at a specific position. But if I tried to run that loop again, every time the dot position was updated, it would paint those letters over the existing letters making them unreadable. I might have been able to get around this, if I first tried to draw a background colored rectangle across all of the letters to 'disappear' them, if not for the second issue.
When ever I started moving the orange dot on the number line, with the redraw loop in place, the page would freeze. For some reason, trying to redraw 26 individual letters caused the code to run slow enough that the interactive line wouldn't update smoothly anymore. Even when I constrained the loop to only redraw 5 letters, it was still moving unacceptably slow and choppy.
This means I would have to find some other way to update a string of alphabet characters on the web page...
Workaround 1: JavaScript CSS
Recently, I've been writing a lot of small Grease Monkey script's for some side projects. These GM scripts can be told to activate when you visit specific URL's, where it will then use JavaScript to remove, add, or replace HTML elements within that page before it loads. For instance, I could write a GM script that runs whenever I visit Google, and have it replace the Google image with my favorite cat and/or ninja picture. The key point here is that JavaScript can be used to change the content at a specific point in a web page.
First I replaced the labels used for the bottom part of the interactive slider with an HTML span. Next, taking advantage of my existing crypto library, I can send a message comprised of the letters of the alphabet and it will return it to me with all of the letters shifted in place. So now whenever the Interactive slider update event fired, it would only need to make a single call to update the page, using the string returned by my function. This seemed to work great and was a lot more responsive then trying to paint 26 individual letters.
While implementing this for the encrypted alphabet, I decided to expand on this idea and created another HTML element that would contain a copy of the encrypted message. During the same slider event, I would re-encrypt that secret message with the new shift so users could see the message decrypted in real time. As the user gradually drags the slider over the actual shift used to encrypt the message, they can see the words suddenly transition from random gibberish into a meaningful sentence.
A little to the left... just a little bit more...
Of course this new approach brought a new set of problems. While the graphie version had drawn the labels using absolute positions (x,y), my new approach was relying on HTML formatting and spacing. In some fonts letters take up different amounts of space; Various internet browsers render HTML in different ways; and users may have different settings across even the same type of browser such as text size or zoom...
First I had to try and line up the alphabet string with the interactive slider ticks and the letters above. Using CSS to control the HTML style for this element, I set it to a mono-spaced font so all of the characters would take up the same amount of space. I also ended up tweaking both the space between characters, and the space between tick marks in the original graphie code to get it lined up with the spacing of the font. But since the code had been using the x position of the tick mark to calculate the message shift, adjusting the value (to 1.2) meant a bunch of other changes to various equations to compensate.
After a few of these tweaks, it was finally looking good on my current development browser! But now my code was slightly more complicated, and had a new CSS section added that wasn't there before. And introducing CSS means checking how it looks in other versions of other browsers...
90% of the time writing code, the other 90% fixing Browser compatibility issues
No. Seriously. Developing the mock up exercises was relatively easy to do, even with the slight detours. But I ended up spending the same amount of time it took to code all four exercises, as I did just trying to track down a single browser compatibility issue...
So at first glance the interactive slider looked great in Firefox. It even looked great in Chrome. But once someone tried using it in IE, a new issue quickly became apparent.
Specifically, the CSS setting for letter spacing apparently renders differently in Internet Explorer then it does in Firefox and Chrome. Setting the value to something that looked correct in IE changed how it looked in FF, and vice versa. So now I needed to find a new work around to fix my current workaround...
My initial research of dealing with IE compatibility issues introduced me to the concept of IE conditional comments. These are specially formatted HTML comments which most other browser will ignore, but when structured a certain way will allow Internet Explorer to implement the HTML or code inside the comment. You can even target specific versions of IE. It looked like a really good fix, so when I tried to use these conditional comments myself they failed miserably.
Internet Explorer would just completely ignore the conditional comments completely, and I had no idea why. One theory I had was that somewhere in the Khan Academy framework, it striped out specific HTML or scripting elements for security reasons. But I just didn't know if that was true, or where to even begin trying to suss out this issue. I ended up banging my head on this for a few hours over a few days, and ended up trying to research a few alternative approaches unsuccessfully.
Work around 2: CSS Hack
After a while, something started gnawing at the back of my mind. On the IE conditional comments pages, most of them referenced a specific version of IE, with the highest version referring to IE 9. My version of IE was version 10, though it could be those pages were simply out of date. So I did a specific search for IE 10 conditional comments. This quickly revealed that IE 10 had stopped supporting them all together... A fact which all of the other older sites suggestion the use of conditional comments failed to mention. *table flip*
In fact, wikipedia currently (6/6/2013) says IE 10 still supports them on the conditional comments page. But says it doesn't support them on the IE 10 page...
A little wiser now, doing a targeted search for IE 10 compatibility workarounds came up with a CSS hack that does work. A css hack usually involves taking advantage of some obscure browser option or setting that only exist on a specific version of a specific browser. Even if this browser option is completely unrelated to what you are trying to do, it can sometimes be used to target browser specific changes.
Most sites also generally warn that CSS hacks are a bad idea, since they are taking advantage of unintended behavior and may be unreliable. On the other hand, because of the ridiculousness of many browser incompatibility issues, they still get used.
Using this hack to set a separate CSS letter spacing value just for Internet Explorer, the interactive slider formatted correctly for the latest version of all three major browsers! Now I just had to worry about older versions of IE, as well as Safari, Opera, Tablets, iPhone... Actually just kidding! There's still an obscure formatting issue with the modern browsers!
And other fairly stupid fairy tales
Remember this paragraph from way back when? "In some fonts letters take up different amounts of space; Various internet browsers render HTML in different ways; and users may have different settings across even the same type of browser such as text size or zoom...". That's called foreshadowing.
So yet another way to change the way your browser formats an HTML page is by changing the text size on the screen. One of the easiest ways to do this is the zoom function, which you can commonly change by holding Ctrl + scrolling the mouse wheel (Go ahead and try it!). People with prehistoric mouses can usually find the zoom option in the view drop down of their browser.
Once again, different browsers handle this differently. Some browsers change the size of text, while others scale the image of the entire page being rendered, or even some combination of the two.
Funnily enough IE worked at any Zoom level without a hitch, now that it had the correct letter spacing applied. It was Firefox and Chrome causing the trouble this time. And they had been doing so well...
So when a user views this page in FF or Chrome while they have a significant zoom value, all of the carefully crafted formatting would would fail spectacularly. This is espsecialy horrible because it is a non-intuitive problem. Users may not even realize they are on a non-default browser zoom, either because they changed it some time long ago and forgot, or they accidentally adjusted it without realizing. And it is definitely not appropriate that you ask users to change that setting before using your website.
Any zoom that went below 80% or above 120% would mess up the formatting. And if the letters won't line up properly, that defeat's the purpose of having the slider in the first place.
Seeing that this would likely involve an even more complex browser specific work around, I decided to take a brief detour. Maybe this HTML formatting approach wasn't so great after all. Maybe there was some other way I could approach the problem using absolute positioning again...
So join me next time in part 3 of my Khan Academy Exercise project, as I chase after the next great workaround!