Archive for the ‘jQuery’ Category

CSS3, jQuery(), and musicology: Another “circle” for understanding Western notes….

May 13, 2011

On my personal page, I have an experiment in CSS and jQuery and musicology: The page represents the default key of C Major, using a clock-like representation of the notes of the scale. C – the root, or I degree of the scale – is represented at “noon”, and each note follows 1 or 2 “hours” later depending on the number of semi-tones separating the notes.

Associated with the IV and vii degrees (Fa and Ti) are functions to change key: In any key, sharpening IV/Fa moves the key forward by a fifth, e.g., from C Major to G Major. Likewise, flattening vii/Ti moves the key backward by a fifth, e.g., from C Major to F Major. (Minor keys are always the vi degree of the major scale, i.e., the La note, e.g., A minor in the case of C Major… …and that’s all we need to know about minor keys for now.)

The idea of the circle is to represent visually what happens in any key: The major chords are always in the 12 o’clock, 5 o’clock, and 7 o’clock positions, the minors in 2, 4, and 9, and the diminished in 11. Always. That’s kind of cool.

The idea of the clock comes from the fact that we use a 12 hour clock and there are 12 semi-tones in the Western scale. Isn’t that conveeeenient!

The CSS part of the experiment is using CSS3 to draw the circle and position the notes. That part works fine. But the associated flatten/sharpen functions aren’t getting placed properly, and even when they are, they don’t work as expected: Clicking the underlined word is supposed to move the key forward or backward.

For some reason, this only works in the Linear version – below the circle is an underlined function to switch from a circular view to a linear view and everything works fine in the linear view: One can switch to linear, change the key, then switch back to circular to see where the notes now live. Fixing this is problem #1.

The Javascript/jQuery experiment is doing all the heavy lifting (changing keys, sharpening/flattening notes, etc.) from within Javascript, mostly using jQuery(). This includes switching from Linear to Circular view, which is done by toggling the CSS file in use, and storing the current CSS type – line or circle – in the class of the div that is used to toggle the CSS. That’s kind of cool.

There are a lot of inefficiencies in the Javascript. For example, there is a lot of DOM access and many DOM updates, and each update will cause a page reflow. This isn’t a big problem for such a small page, nor is it a problem on a powerful device, but on a larger, more complex page or on a mobile device this might be unacceptable.

Another problem is that there may or may not be a memory leak in the use of the temporary newKey object in some of the Javascript. Again, not a huge concern in a small page that is likely shortlived, but in a long-lived app on a mobile device, this might be problematic. If this problem exists, it is because of my still having a “C like” concept of scope – lexical scope – and not having adjusted to how scoping is different in languages like perl and Javascript, which use dynamic scope. So I may be creating stack objects and leaving them orphaned.

One note about the use of objects Vs arrays: I’m using objects instead of arrays because it was simply easier to declare and define them, e.g., the natural notes in C Major object, but this does lead to some awkwardisms:

  • When a new object is created, I have to iterate through the existing object and initialize each element of the new object, since there is no “copy object” function/method, at least not as far as I can tell. (Setting “newKey = oldKey;” just makes newKey a reference to oldKey, meaning changes to newKey affect oldKey, not what I wanted. See comments above re orphaning.)
  • No slice() method for making the copy/initialize operation simpler. A lot of other arrayisms that might have been handy are also missing (but maybe this forced to me sort out presentation and content a little more clearly).

What’s next? Well….

  • It would be nice to get the accidental functions working in the circular view, but this might be an FF 3.6 thing (I don’t have FF 4, so I’ve not tried it yet to see if it does the CSS3 circle thing any better (my fave extensions aren’t available under FF 4 – yet – and I don’t like the change in status bar, so I’m sticking with 3.6 and the Meerkat). Next step is to try this under Safari and some mobile devices and see if it works there. If so, FF bug (maybe); if not, bug in my knowledge.
  • A definite bug in my knowledge is CSS positioning – it’s still quite mysterious to me, which is why the accidental function labels are not where there should be in the circular view. (My first attempt had them as child div of the IV and vii degree divs, which worked great, but that made updating the notes difficult and made hiding them after -7/+7 difficult (and also mixed function content with real content and broke the presentation/content barrier, sort of, I think). I might be able to play with $().empty(), $().append(), and $().replace() some more to do this, e.g., by having the labels as child divs and replacing only the sibling content, but that is more advanced DOM walking/updating than I know how to do yet. Maybe later.)
  • (If I were to figure out that last bit, I might add degree labels to the notes, e.g., “I: C”, especially in the linear view, and maybe even have the degree outside the circle in circular view. Cool idea. No idea how to get there yet.)
  • The two CSS files have overlap, which means maintenance headaches, having to change things in two places. Having three files (common, line, circle) would be more elegant, and perhaps simpler to maintain, but changing this now would violate the IIABDFI principle. I violated said principle two weekends ago, and spent the next week restoring my main laptop to a functional state. I keep saying I don’t believe in patching working systems – not practicing what I preach really, really hurt. But at least I got to see how ugly the Narwhal is. Sigh. Happy to be back with the Meerkat, thank you.
  • It would be nice to animate the transition, so that notes slide clockwise or counterclockwise, with the accidentals appearing/disappearing appropriately. But this would likely mean abandoning the use of CSS3 to draw the circle. I think. Unless I played games with incrementing the rotation angle for the degrees, which would then require resettig the degrees once they’d hit their new positions. Ugh.
  • I’m fixing the degrees, i.e., I == noon, ii == 2, iii == 4, etc., and moving the notes, but another way to draw the circle would be to use the notes as id for their elements instead of degree, then use something like the animation described above to move things around. I think that’s kind of nasty, as it seems to be break good practice associated with separating presentation and content: Right now, the “content” is the set of notes, while degrees are used to control how they are presented (by fixing the location of the degree, which makes sense, because degree is fixed), and degree is also used as the key in the note hashes (again, this makes sense because degree is fixed and notes are variable). But structuring based on notes might make animation easier. I might try it just to learn something.
  • Testing on other browsers (Safari, iDevices, Android). Forget about IE, I fully expect IE CSS3 shog of epic proportions.
  • Counting accidentals then hiding the appropriate function feels like a kludge, but I cannot think of more elegant way of doing it.
  • Understanding how jQuery scope works: It took a while for me to get functions ordered and nested appropriately within $().ready() so that I could call showKey() to do the display work, and I still don’t fully get that. More experiments will help.

Give credit where credit is due. I was inspired to do this after seeing the CSS3 clock created by Keran McKenzie, so props to him. Thanks!

The jQuery() team deserve massive praise for their work (and not just praise). The following pages were helpful in figuring out how to do specific bits:


Follow

Get every new post delivered to your Inbox.