Wednesday, May 27, 2015

OpenSeadragon 2.0: Forest-to-Tree Zooming

Today we cross a major threshold!

OpenSeadragon turns 2.0 and brings with it full support for zooming multiple high-resolution images in the same scene. Imagine all the pages of an ancient manuscript laid out on your screen and being able to seamlessly zoom in to the smallest detail on any page.

Back in 2008 when OpenSeadragon (then called Seadragon Ajax) was first released — when IE 7 was Microsoft's top browser and woolly mammoths wandered the frozen steppes — smoothly zooming a single image in pure JavaScript was quite the feat! We could only dream about the sort of cool multi-image scenarios Blaise demoed using a native app with GPU-accelerated code in his famous TED talk.

OpenSeadragon doesn't yet do everything shown in that video, but multi-image opens up some exciting new possibilities! Check out these demos for some inspiration:



OpenSeadragon + Rdio: swim across a sea of high-resolution album artwork, discovering new music as you go.




OpenSeadragon + Flickr: hop from image to tag to image on Flickr's most interesting photos of the day.




Chris Jordan Infinite Zoom: kick back and fill your screen with Chris Jordan's giant photo montages.


If you're new to OpenSeadragon, you should also check out all the great work people have done with the single-image version, such as this gigantic panorama of Mont Blanc and this amazingly detailed story-map of Central America.

Now what are you waiting for? Make some cool multi-image OpenSeadragon things!

Labels: ,


Tuesday, February 03, 2015

self = this

I teach JavaScript, and one of the things I've found most confuses people is the self = this pattern (some people even go to great lengths to avoid learning about it). I haven't been able to find a good post on it, so here's my attempt. If you're not interested in JavaScript, feel free to skip this and read some of my other fine posts.

Okay, I'll start with a concise definition and then explain in depth.

Use the self = this pattern whenever you have a function nested inside of an object's method, and you want to access the object's properties.

Assign self in the object's method and use it inside the nested function. Here's how it looks:

var myObject = {
  aMethod: function() {
    var self = this;

    this.aProperty = 'foo';

    setTimeout(function() {
      console.log(self.aProperty); // outputs 'foo'
    }, 1);
  }
};

So, let's explain further.

Objects with Functions

While you can certainly write plenty of JavaScript without ever attaching a function to an object, I find that organizing my code into objects makes things a lot cleaner. To avoid junking up the global namespace, I usually define a single global object (named "App" or some such) that all of my variables and functions are attached to. To further organize, I'll group related functions and variables into sub-objects attached to the main object.

Most objects will have a mix of variables (called properties when they are part of an object) and functions (called methods when they are part of an object). Here's a simple object with one of each:

var myObject = {
  aProperty: 'foo', 
  aMethod: function() {
  }
};

Inside an object's methods, there's a special variable, named this, that is a reference to that object. If the method wants to access any of the object's properties or other methods, it does so through that variable, like so:

var myObject = {
  aProperty: 'foo', 
  aMethod: function() {
    console.log(this.aProperty); // outputs 'foo'
  }
};

This special variable is managed by JavaScript; you don't have to assign it, and in fact you can't. It's assigned automatically for every function. If it's an object method, this is a reference to the object. For any other object, this is a reference to the global variable namespace.

Nested Functions

In JavaScript, you can nest functions inside of other functions, including object methods. This is a common practice when working with user events, network requests, timers, etc.

var myObject = {
  aMethod: function() {
    setTimeout(function() {
    }, 1);
  }
};

One handy feature of nested functions is that the inner function has access to all of the variables defined in the outer function. This is called closure.

var myObject = {
  aMethod: function() {
    var a = 'foo';

    setTimeout(function() {
      console.log(a); // outputs 'foo'
    }, 1);
  }
};

The one exception is the special this variable; since the nested function is just a regular function, not an object method, its this is a reference to the global namespace.

var aProperty = 'global';

var myObject = {
  aMethod: function() {
    this.aProperty = 'local';
    
    setTimeout(function() {
      console.log(this.aProperty); // outputs 'global'
    }, 1);
  }
};

Putting It All Together

So, we need a way to get a reference to the object to be available inside the nested function. Closure to the rescue! We assign another (non-special) variable, e.g. self, with the object from this. Since this variable isn't overwritten for each function (unlike this), we can use it inside the inner function.

var myObject = {
  aMethod: function() {
    var self = this;

    this.aProperty = 'foo';

    setTimeout(function() {
      console.log(self.aProperty); // outputs 'foo'
    }, 1);
  }
};

Notes

  • There's nothing magic about the word self; you can use whatever variable name you want. However, self is the most commonly used variable name for this pattern, so it's a good choice for clarity's sake.
  • If a method needs a var self = this; line, I always put it at the very top of the method. Putting it at the top isn't absolutely necessary, but I think it's a good convention; that way you don't have to go hunting to see if it's defined.
  • this is only set up properly if you call the method via the object, like myObject.aMethod(). If you instead call the method indirectly, such as when you pass it to another function (e.g. setTimeout(myObject.aMethod, 1)), this won't be set up. To deal with this, we use closures again, like so: setTimeout(function() { myObject.aMethod(); }, 1).
  • It's actually possible in certain cases for this to not be the object or the global namespace. By using JavaScript's apply or call features, you can set this to whatever you want when you're calling a function. jQuery uses this in its event handlers, for instance.

Tuesday, January 06, 2015

Be More Awesome

With education, as with many things, I find it's useful to start from basic principles. There are so many options and philosophies, it's easy to get overwhelmed. A good mission statement can cut through all that, or at least give you a place to start.

So, here's ours:

The goal is for Caitlyn to become more awesome. Our strategy for becoming more awesome is to learn new skills and improve existing ones. The only way to learn/improve skills is through practice. Therefore her job is to practice, and to improve her ability to practice (since practicing is itself also a skill).

Practice can be made more effective with:

  • Instruction and examples
  • Feedback
  • The proper tools
  • A conducive environment
  • Goals and rewards
  • Other skills
  • No doubt many more things

All of these are worth gathering when possible, but none of them are worth waiting for.

That's it.

I suppose one other question worth answering is, "Which skills should we practice?" To be honest, I don't think it really matters that much. All skills are useful, and all can be translated to other contexts, and at any rate the most important skill is how to practice effectively. That said, some of the most important skills are what you might call building block skills; those that many other skills are based on. Reading, writing, and math are the obvious ones, but there are many more, such as time management, teamwork, research, and experimentation.

Anyway, with this simple mission statement, we can focus on what's important while allowing a broad range of variation.

Labels: ,


Tuesday, October 21, 2014

How I Rdio

I've been a fan of Rdio for years now (which, come to think of it, is probably why I work for them). More interesting, though, than the question, “What music service do you use?” is, “How do you actually use it?” Here then, is my answer. For starters, it should be noted that while in general I love Rdio’s UI, there are various things I’ve found to be missing that I’ve gone ahead and built for myself using Rdio’s lovely JavaScript API (which, as it turns out, I also built; that’s how I know how lovely it is). With that in mind, let’s take a tour:

The Tunes Must Flow

I listen to music most frequently while working at my computer. During the workday, I just want to have excellent music playing, and I want to stay in the flow. For me this means whole albums, because each album has a consistency that doesn’t grab your attention with each track change. This also means being able to queue up a whole bunch of albums ahead of time, so I don’t have to stop and fiddle with my music periodically throughout the day. Fortunately, Rdio excels at thinking in terms of albums, and it’s got a fine queue. Every so often, when the queue runs low, I’ll jam a new pile on; I’ve generally got dozens of albums lined up.

Discovery


When I’m not working, I do like to fiddle with music, as a leisure-time activity. In the evenings I sometimes wander around, checking things out, adding new stuff to my queue or favorites, etc. This is the modern-day equivalent of my old habit of haunting music stores, looking for that next great find. If I'm looking for new music, I'll use Fathom or the social stuff that shows up on Rdio’s homepage feed or the "here are new albums from your favorite artists" feature that shows up in notifications.

Once I’ve found a promising-sounding album, I toss it on the queue for a full listening during the workday. Every few days I go to Music Triage which shows me any new albums I've listened to that I haven't already triaged. Here I quickly add things to my favorites or mark things I didn't like. In this way I make sure nothing falls through the cracks, without having to pay attention throughout the day.

Rediscovery

It turns out music discovery these days is so great, I’ve got a new problem: hundreds of albums I’ve discovered and liked enough to add to my favorites but never listened to again because I was off to the next big thing. To listen to music I already know I like, and hopefully connect more deeply with things I’ve discovered, I pull up Collection Random and use it to quickly queue up a bunch of albums. I find this "show me some stuff randomly from my collection" better than any sort of rational sorting… otherwise you end up falling into ruts.

Mid-Queue Interruptions

My next-most-frequent music-listening station is in the kitchen while cooking and cleaning. I usually want to listen to something entirely different there; more upbeat and attention-grabbing. If I think of it before leaving my computer, I push an appropriate album ahead of the queue (in Rdio’s Mac interface, it’s command-clicking the play button on any album). Unfortunately, Rdio’s mobile app doesn’t support such things, so I’ve made Mobile Queue to support reorganizing the queue on my mobile web browser.

So there you have it

…my music “workflow”. Who knows what my music rhythm will be like in a year, but for now this is working great, and I love having the power to customize my interactions as needed.  At the moment, I think I’ve found a good balance between finding new stuff and listening to favorites, with a minimum of ongoing effort (not counting the initial development time, which was fun noodling anyway).

How about you? How do you use your music service?

Labels:


Tuesday, February 04, 2014

Video Games

I played a lot of videogames as a kid (mostly on the Apple II, and then later on the Mac). At the time, of course, I just thought of it as fun, but now I realize I learned a lot doing so. Problem solving and resilience/determination are high on the list. You can't get anywhere in this world without being willing to try and fail and try again. Video games are great way to instill that instinct.

Of course Caitlyn has been playing games on the iPad for years now, but computer games are a different beast. In the past, we've focused on puzzle games; they make you think, but there's no time pressure, and not much need for eye/hand coordination. That was good for when she was younger, but now she's ready for more of a challenge.

We started with Return to Dark Castle, which is a remake of one of my favorite games from when I was kid. Now we're playing FEZ, which is delightful. Platformers seem like a good point on the videogame spectrum at the moment. They provide exploration and puzzle solving, but with an added level of arcade action, but not too intense yet.

I'm on the lookout for the next game. Any suggestions?

Labels: ,


Tuesday, January 28, 2014

JavaScript & Uncorrected Video

There is this continuing debate that rages in tech circles: If you're going to make an app, should it be web or native? The true answer, of course, is that it depends. I'm a web guy, though, so when I enter the fray, it's generally on that side.

The common perception of web tech is that it's easier, but produces inferior results. You can slap something together in a fraction of the time, but it's not going to have that slick, polished quality you expect from native apps.

It all reminds me of the old film vs digital thing the movie industry went through a while ago. I was working in Hollywood at the time, and there was a lot of buzz about the liberating potential of digital video, but also a lot of criticism of its inferior quality.

Well, to some extent it was inferior, because it was still young, but there was more than that at play. The thing is, when you shoot film, you have to get it developed, and part of this process is making sure the colors came out right, and you get the tonal range you want, etc. Without that color correction step, film looks horrible, unusable. With video (digital or otherwise), you can skip that step; uncorrected video isn't great, but it's not as horrible as uncorrected film. So, since you can skip it, lots of people did, and video got this reputation for having that bland, washed out look. Over time, however, people clued in, and now tons of movies are shot on digital, but they're always color corrected. At this point, film and digital are virtually indistinguishable to the viewer, and what the cinematographer uses is more just a question of personal taste than any technical consideration.

Back in JavaScript land, we have a similar situation. The technology is still young, so it was pretty bad not that long ago. Like digital video, it's liberating; your app can run anywhere, and you can get started with a set of simple tools. The fact that it's easier, however, gives us the uncorrected video problem: people who don't know what they're doing can still create JavaScript apps. They may be crappy apps, but they work. With a native app, there's a higher bar; if you don't know what you're doing, you're likely to not end up with anything usable at all. The native apps that survive generally have a decent level of quality.

But when someone who really knows what they're doing builds a JavaScript app, you can get the flexibility you expect from the web and the polish you expect from native, just like digital video can look great if you bother to color correct it. For me, that's the best of both worlds, though of course your mileage may vary.

My favorite example of a slick mobile web app is Forecast.io (at least on the iPhone). I'm doing my best to walk the talk as well with Driftory and Gimme Shiny, both of which work great on mobile.

Tuesday, January 21, 2014

Homeschooling

This last summer, Caitlyn made the transition from regular school to homeschool, and so far I'm delighted! I homeschooled as a kid; I'm excited to be diving back in now with Caitlyn. I haven't written anything about it here (unlike Christina) so it's time to catch up:

We always intended to homeschool her, but it was important to us that she got a chance to experience mainstream school for as long as she wanted to (no forbidden fruits there), and that homeschool be her choice. Regular school is something that kind of happens to you; homeschool takes a lot more personal responsibility, at least the way we're doing it. She needs to really want it in order for it to work. We made it clear what's expected of her, so she knew what she was getting into.

Towards the end of second grade she came to us and said she was ready. We insisted she finish out the year, which she did reluctantly. In the end, the last day of school was both exciting and sad, saying goodbye to the place she'd spent so much time for the last three years, and hello to a whole new way of life.

We used the summer to ease into the concept of homeschool (starting with a two-week field trip to Canada), and we started in earnest in the autumn. Of course, even now, we're still figuring out the right mix of activities. A lot of her day is what's generally described as "unschooling", where she's left to pursue her own interests, but Christina is working with her directly on a few fundamentals. We figure she can get into chemistry, history, basket weaving, etc. as the mood strikes her, and she's likely to go deep on some subjects and shallow on others, which is fine. Everybody's gotta get a firm foundation in the three Rs, though. Reading is not an issue; she's already a voracious reader, chewing through 350-page books in a weekend. Math and writing are not as favored, so Christina works with her on those subjects.

When left to her own devices, Caitlyn's favorite subject is art, and her skill is increasing steadily. She's learning firsthand the value of practice! She has an art tutor who comes over every other week, and both Christina and I also mentor her in various ways on the subject.

One of the wonderful things about homeschooling today, at least in this part of the world, is that there's an amazing amount of resources, and a strong support network. She regularly gets together with her friends (other homeschoolers, friends from the neighborhood, friends she met in school) for both structured and unstructured activities. Several of her homeschool companions get together at one house for science, and then back to ours for tea and poetry with Christina.

Of course this means Christina's getting to learn more about poetry, too. This is one of the hidden benefits of homeschooling; the parents get to learn as well. Caitlyn is interested in Spanish, so all three of us are taking a course together. Her interest in art means we all get to practice our art-making more, etc.

Let's see, what else? Circus class continues, and she's doing theater again. She gets quality time at the public library, and she's got a library account on her computer so she can order books whenever she wants. She's also learning general computer use and typing. I'm taking advantage of time to work with her on subjects that were dear to my heart as a kid. We're doing programming together, as well as Legos, of course.

Surely it will continue to evolve, but I feel like we're off to a good start. The three of us have embarked upon a great adventure together!

Labels: ,


Tuesday, January 07, 2014

Hire Me!

I'm footloose and freelance, so theoretically I could be flitting from project to project. The reality is I seem to find big, meaty projects and focus on them for over a year each. For the last year and a half, I've been devoted to Rdio, creating their new JavaScript API, their new developer site, and several other things I can't speak about yet. That all came to a sudden halt in November, when they laid off a chunk of their staff, including me. So here I go, back to being footloose!

Coming off a big project like this is like coming off a long-term relationship. It's this strange combination of distressing and liberating, and all I want now is a rebound fling. Or maybe I do want something more lasting, but I'm shy to commit until we've gotten to know each other.

Anyway, here I am, on the prowl again. If you're looking for an experienced, design-oriented JavaScript developer, I'm your man! I can do anything from architecture to animation, but I especially love interaction work, getting the behaviors just right. Even better if we're pushing the boundaries of the web as we know it.

Check out my portfolio, my resume, my GitHub profile, and/or this bit on my prototyping skills, then hit me up! Who knows, we may just fall for each other.

Labels:


Tuesday, December 31, 2013

2013

Man, it's been almost a year since I last posted here! I blame Twitter, luring me away with its brevity and wit and whatnot.

Well, perhaps it's time for a little catch-up. Let's see, what have I been up to this last year?
I'm entering 2014 without a clue as to what I'll be working on, but I'm sure it will be lovely. I'm looking forward to the continuing homeschool adventure for the whole family.

Maybe I'll even write some more blog posts.

Tuesday, January 29, 2013

HTML5 for .NET Developers

We need more JavaScript developers! There are too many jobs, and not enough qualified devs. The thing is, JavaScript isn't even that hard, and it's actually quite beautiful, but you've got to take the time to get to know it.

There's a huge pool of talented developers in the .NET world, hitherto sheltered from JavaScript, but now starting to become curious. For a long time, Microsoft urged devs to shun HTML and JavaScript in favor of the tidy, self-contained world of .NET. They scared us with horror stories about browser incompatibility and unreliable open source libraries. Even if you wanted to do interesting things on the client side, there was Silverlight to keep you in the safe Microsoft bubble.

It worked for a while, but now the winds have changed. All of the interesting stuff that's happening in the client-side world today is done in HTML, JavaScript, and CSS. With Node.js, JavaScript is becoming an important language on the server. With Windows 8, even Microsoft has embraced these technologies, leaving a lot of developers feeling stuck. Having never taken the time to learn the open web stack, is it too late now?

Jim Jackson and I wrote HTML5 for .NET Developers as an invitation, to help bring these folks into this new world. We give you a crash course in the core web technologies, as well as an introduction to some of the latest additions. Since each chapter is its own little project, we give you lots of great starting points for your own explorations.

Throughout the book, we're sensitive to the issues particular to folks coming from the .NET world. One of the common problems is trying to program JavaScript like it's C#. You can kind of do it, but you end up with a mess that's worse than either language on their own. We show you how to program JavaScript like it wants to be programmed, and everything is much smoother. It may take an open mind at first, but it's worth it.

People are also often overwhelmed by the fact that, while .NET is relatively self-contained, the JavaScript world is wide open; you're using all these libraries from different places, on all these different platforms, and there's new stuff every day. The good news is you don't have to learn it all, and there are tons of other people using the same stuff, sharing their discoveries, and helping each other out. We help you establish a beachhead from which you can continue to expand your knowledge.

So, if you're JavaScript-curious, come on in, the water's fine! Buy our book, play with our examples, hang out on Stack Overflow, and make stuff! When you do, let me know… I'd love to see what you come up with!