Getting Started

Tangle lets you write documents that change.

Let's say you're writing an article about dieting, and want to discuss the calorie content of various foods. You might write the following.

When you eat 3 cookies, you consume 150 calories. That's 7% of your recommended daily calories.

That's a true statement, but it only applies directly to those few readers who eat 3 cookies a day. Most of your readers eat more or less. What if the reader could adjust the statement to see information about their own situation? What if readers could explore alternative scenarios as well?

When you eat cookies, you consume calories. That's % of your recommended daily calories.

Let's see how to write this example.

Variables

We start by identifying the variables — those parts of the statement that need to change. In this case, there are three varying numbers in the statement, so we need three variables.

When you eat 3 cookies, you consume 150 calories. That's 7% of your recommended daily calories.

We'll call these variables cookies, calories, and dailyPercent respectively.

HTML

Now, let's look at the HTML for the statement.

<p>When you eat 3 cookies, you consume <b>150 calories</b>.
   That's 7% of your recommended daily calories.</p>
data-var

Let's start with the "150 calories" part. Notice that it's inside <b> tags, to make it bold. We'll make two simple changes:

<p>When you eat 3 cookies, you consume <b data-var="calories"> calories</b>.
   That's 7% of your recommended daily calories.</p>

First, we added the data-var="calories" attribute to the <b> tag. This tells Tangle to insert the value of the "calories" variable inside the tag. So, if the calories variable were 500, it would appear as "500 calories".

Second, we removed the "150" from inside the tag, because Tangle is going to insert the correct number itself.

span

Now, let's look at the "7%" part. It's not inside a tag, so we need to put it inside one. The <span> tag is typically used for this purpose. Unlike <b>, it has no intrinsic meaning of its own — it's simply a generic container that we can attach style and variable information to.

<p>When you eat 3 cookies, you consume <b data-var="calories"> calories</b>.
   That's <span data-var="dailyPercent">%</span> of your recommended daily calories.</p>

Tangle will insert the value of the "dailyPercent" variable at the start of the span.

class

Now, we'll look at the "3 cookies" part. This part isn't just dynamic — it's interactive. We want the reader to be able to adjust the variable by dragging on the number. For this, we use a class. A Tangle class can describe how the reader interacts with an HTML element, or how a variable should be displayed.

We'll use the class "TKAdjustableNumber", which comes with TangleKit. (The "TK" prefix refers to "TangleKit".) TangleKit is a collection of basic classes for you to use. Once you start tangling more heavily, you might want to start making your own classes.

<p>When you eat <span class="TKAdjustableNumber" data-var="cookies"> cookies</span>,
   you consume <b data-var="calories"> calories</b>. That's 
   <span data-var="dailyPercent">%</span> of your recommended daily calories.</p>
id

Finally, we need to make sure that we're able to find this statement from JavaScript. The easiest way to do so is to add an id attribute to the tag that contains it. In this case, our statement is inside a <p> paragraph tag, and we can name it like so:

<p id="calorieCalculator">
  When you eat <span class="TKAdjustableNumber" data-var="cookies"> cookies</span>,
  you consume <b data-var="calories"> calories</b>. That's 
  <span data-var="dailyPercent">%</span> of your recommended daily calories.</p>

That's all we need to do with the HTML. Next, we'll tell Tangle how to calculate those variables.

JavaScript

In JavaScript, we need to "create a tangle" for all of the HTML elements and variables involved in this particular statement. We do so with new Tangle, like so:

var tangle = new Tangle(rootElement, model);

But first, we need the rootElement and the model.

rootElement

The rootElement refers to the element that contains our statement. In this case, we put an id attribute on the surrounding paragraph, so we can find it easily:

var rootElement = document.getElementById("calorieCalculator");
model

The model tells Tangle how to initialize and update the variables. It has this form:

var model = {
    initialize: function () { ... },
    update: function () { ... }
};

The initialize method runs when the tangle is first created. This is where you set the initial values of independent variables. We want the statement initially to read, "When you eat 3 cookies...", so we need the cookies variable to start at 3.

var model = {
    initialize: function () {
        this.cookies = 3;
    },
    update: function () { ... }
};

The update method runs whenever a variable changes. This is where you describe how to calculate "derived variables" — variables that depend on others. The calories variable can be calculated from cookies:

var model = {
    initialize: function () {
        this.cookies = 3;
    },
    update: function () {
        this.calories = this.cookies * 50;
    }
};

and the dailyPercent variable can be calculated from calories.

var model = {
    initialize: function () {
        this.cookies = 3;
    },
    update: function () {
        this.calories = this.cookies * 50;
        this.dailyPercent = 100 * this.calories / 2100;
    }
};

This works fine, but it's a little hard to read. Someone perusing this code might not immediately understand what the "50" and "2100" are all about. Let's give them more descriptive names.

var model = {
    initialize: function () {
        this.cookies = 3;
        this.caloriesPerCookie = 50;
        this.dailyCalories = 2100;
    },
    update: function () {
        this.calories = this.cookies * this.caloriesPerCookie;
        this.dailyPercent = 100 * this.calories / this.dailyCalories;
    }
};

The code is now much easier to follow. And later, if we want caloriesPerCookie or dailyCalories to be adjustable, we can do so directly in the HTML, without touching the JavaScript.

new Tangle

We can now create the tangle. Instead of writing out the rootElement and model separately, we typically just define them inline, like so:

var tangle = new Tangle (document.getElementById("calorieCalculator"), {
    initialize: function () {
        this.cookies = 3;
        this.caloriesPerCookie = 50;
        this.dailyCalories = 2100;
    },
    update: function () {
        this.calories = this.cookies * this.caloriesPerCookie;
        this.dailyPercent = 100 * this.calories / this.dailyCalories;
    }
});

That's all there is to the JavaScript.

Formats and Classes

We're almost done. But when we try it out, we get this:

When you eat cookies, you consume calories. That's % of your recommended daily calories.

Our dailyPercent is perhaps a little more precise than necessary. To tell Tangle how to properly display that variable, we can specify a format.

Formats

In the HTML, we add a data-format attribute:

That's <span data-var="dailyPercent" data-format="%.0f">%</span>
of your recommended daily calories.

%.0f is known as a printf-style format, which is a standard language for describing how numbers should be printed. Here, we specified that we wanted to round off the number, with no digits after the decimal point.

It's possible to create your own format functions and use those as well, but in this case, the printf format works fine.

When you eat cookies, you consume calories. That's % of your recommended daily calories.

Classes

Currently, we can adjust the cookies variable by dragging it, thanks to the TKAdjustableNumber class that we specified:

<span data-var="cookies" class="TKAdjustableNumber">

Perhaps you don't like dragging, and would rather let your readers type in a number instead. We can simply switch the class to TKNumberField:

<span data-var="cookies" class="TKNumberField">

And our statement becomes:

When you eat cookies, you consume calories. That's % of your recommended daily calories.

TangleKit contains a growing selection of classes, and you can define your own classes easily.

Possibilities

We just worked through a very simple example, to give you a taste of what you can tangle. But there's much more you can do.

You might want to look over the API reference, or just download Tangle and dive right in.