Lesson 1

In this series of examples, we will build an interactive visualization of the locations of US airports. Little by little, we will build features that showcase the Lux scene graph infrastructure, walk through its features, and show how they simplify many of the typical programming tasks underlying interactive features. If you like diving in the code to get a feel for what it looks like, I encourage you to skip the text below and read the source right away. Otherwise, read on for longer explanations.

We start by initializing Lux and loading a JSON file containing the airport information:

    Lux.init();
    Lux.Net.json("airports.json", create);

The function create will create the visualization elements. The airport locations are given in latitude-longitude pairs, so we create the buffers that will let Lux associate these values with the points we will draw:

function create(json)
{
    var lats = make_buffer(json, "lat"),
        lons = make_buffer(json, "lon");

The coordinates that WebGL uses to address positions on a canvas are always normalized between -1 and 1 in all dimensions. This means that if we want to plot latitudes and longitudes, we need to transform them to the correct screen positions. In theory we could do this in Javascript and send WebGL the transformed positions every time, but this is not very efficient since we're dealing with more that 20 thousand points, and we want, in the future, to update the visualization at interactive rates. The solution is to create a transformation to be performed on the graphics card, by WebGL:

    var scale = Shade.Scale.linear(
        {domain: [Shade.vec(-180, -90), Shade.vec(180, 90)],
         range: [Shade.vec(-1, -1), Shade.vec(1, 1)]});
    var position = scale(Shade.vec(lons, lats));

The variable scale is storing a linear transformation (actually an affine transformation if you're nitpicking), that sends the vector [-180, -90] to [-1, -1], and the vector [180, 90] to [1, 1] (y coordinates in WebGL increase as you go up the canvas). This transformation is then applied to a vector representing the position of the point, Shade.vec(lons, lats). The variable position now holds an expression that denotes the result of transforming each element of the buffers we created by the specified linear transformation and representing them as 2D vectors.

We now create a visual primitive with the given position, and add it to the scene graph:

    Lux.Scene.add(Lux.Marks.dots({
        position: position,
        fill_color: Shade.color("white"),
        stroke_width: 1,
        elements: json.length
    }));
}

In this lesson, we hand-coded performed the transformation from latitude-longitude to screen coordinates. This is sufficiently convenient in a trivial example like this, but makes further changes in the code more complicated. We will now start modifying this example to take advantage of some powerful Lux features. In the next lesson, we will learn about Lux transformation nodes.

View the full source.

Back to the index.