Contents

*   *   *

HTML attributes

class

I want <span class="TKAdjustableNumber" data-var="cookies"></span> cookies.

The class attribute normally specifies a CSS class which gives an element a style. With Tangle, it can also specify a JavaScript class which gives an element a behavior. It might turn an element into a control that adjusts a variable, or a view that displays a variable. It is common to define a class in both CSS and Tangle, for appearance and behavior respectively.

A number of basic classes are included with TangleKit. For details on how to create and plug in your own classes, see Tangle.classes.

An element can have any number of classes, like so:

<span class="MyClass MyOtherClass" data-var="cookies">

Any of the classes can be defined in CSS, JavaScript, both, or neither. You might use one class for the visual presentation of a variable, and another to provide interactive manipulation.

data-var

I ate <span data-var="cookies"></span> cookies.

The data-var attribute specifies a variable. You typically use it to display the variable's value in some way, or to specify which variable a class should adjust.

The data-var attribute can go on any element. If the element has a class, the variable name will be passed to the class's initialize method, and the variable's value will be passed to the class's update method whenever it changes.

If none of the element's classes has an update method, Tangle will insert the variable's value into the element (before any existing content), and update it whenever it changes. The value will be formatted with the data-format attribute, if present. Tangle won't insert anything if any class has an update method, because it assumes that class is handling the display of the variable.

An element can have multiple variables, like so:

<span class="MyClass" data-var="cookies tacos">

All variable names will be passed to MyClass's initialize method, and all values will be passed to MyClass's update method. This is useful for two-dimensional controls that adjust two variables at once, or views that depend on multiple variables. See Tangle.classes for details.

data-format

That cookie costs $<span data-var="cost" data-format="%.2f"></span>.

The variable is presented with the given format. You can specify a printf-style format, or define your own format functions. To use printf-style formats, you must include a sprintf library, such as the one that is provided with TangleKit. For details on defining custom formats, see Tangle.formats.

If you specify multiple variables in the data-var attribute, all values will be passed to the format:

The cookies cost $<span data-var="cost quantity" data-format="%.2f per %d"></span>.

If you are using a custom format, you can pass parameters to it, separated by spaces. See Tangle.formats for details.

<span data-var="cookies" data-format="myFormat parameter1 parameter2">

other data attributes

Classes may make use of other attributes with the data- prefix. For example, specifying the minimum and maximum values for a TKAdjustableNumber:

<span class="TKAdjustableNumber" data-var="cookies" data-min="0" data-max="20">

These additional attributes are passed to the class's initialize method, via the options parameter.

For details on what attributes a class accepts, see the documentation for the individual class.

*   *   *

JavaScript API

new Tangle

var tangle = new Tangle (rootElement, model);
var tangle = new Tangle (document.getElementById("calorieCalculator"), {
    initialize: function () { this.cookies = 4; },
    update:     function () { this.calories = this.cookies * 50; }
});

Creates a new tangle. Tangle looks under rootElement for elements with classes or variables. Classes are initialized, and the model is set as described below.

You may create as many tangles as you like, with different rootElements or models. Each one keeps track of its own variables and classes. Typically you will create a tangle for each "interactive widget" in your document.

setModel

tangle.setModel(newModel);
tangle.setModel({
    initialize: function () { this.cookies = 4; },
    update:     function () { this.calories = this.cookies * 50; }
});

This method changes and resets the current model.

The model should be an object with initialize and update methods. When the model is set, the initialize method is called to set the initial values of variables, and the update method is called to calculate variables derived from those. When a variable is changed subsequently via tangle.setValue, the update method will be called again to recalculate derived variables.

You may also define any methods that you want to use internally:

{  initialize: function () { this.cookies = 4; },
   update:     function () { this.calories = this.cookies * this.getCalPerCookie(); },
   getCalPerCookie: function () { ... }
}

getValue

var value = tangle.getValue(variable);
var numberOfCookies = tangle.getValue("cookies");

Returns the current value of a variable.

setValue

tangle.setValue(variable, newValue);
tangle.setValue("cookies", 17);

Sets a new value for a variable. If the new value is different than the old one, the model is updated.

A variable is typically a number, but can be of any type. If you are using a reference type such as an Array, be aware that you cannot update the model by mutating the array. Instead, pass a new or copied array to tangle.setValue.

setValues

tangle.setValues({ variableName:value, variableName:value });
tangle.setValues({ cookies:17, cupcakes:12 });

Sets values for multiple variables at once.

*   *   *

Tangle.classes

Tangle.classes.MyClass = {
    initialize: function (element, options, tangle, variable) { ... },  // optional
    update: function (element, value) { ... }   // optional
};

A Tangle class lets you associate some JavaScript code with an HTML element. It's typically used to define a control that adjusts a variable, or a view that displays a variable, although more creative uses are possible.

If your HTML contains:

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

then when the tangle is created, MyClass will be instantiated for that element, and if there is an initialize method, it will be called, and passed the name of the variable. If there is an update method, it will be called when the specified variable is initialized or changed, and passed the value of the variable.

initialize

The initialize method is a good place to add event listeners to the element, to set up an interactive control. The following example implements a control that increments the variable when it is clicked.

Tangle.classes.ClickableNumber = {
    initialize: function (element, options, tangle, variable) {
        element.onclick = function () {
            var value = tangle.getValue(variable);
            tangle.setValue(variable, value + 1);
        };
    }
};

The options parameter is described below.

update

The update method is for updating the element's appearance or contents when the variable changes. The following example resizes the element's width when the variable changes, perhaps for a bar in a bar chart.

Tangle.classes.StretchyBar = {
    update: function (element, value) {
        element.style.width = "" + value + "px";
    }
};

other methods

You may also define any methods that you want to use internally.

Tangle.classes.StretchyBar = {
    update: function (element, value) {
        var width = value * this.getStretchiness();
        element.style.width = "" + width + "px";
    },
    getStretchiness: function () {
        ...
    }
};

CSS

Because these are CSS classes as well as Tangle classes, you can often specify the element's style in a CSS file, and only deal with behavior in JavaScript.

.ClickableNumber {
    color: #46f;
    border-bottom: 1px dashed #46f;
    cursor: pointer;
}

framework classes

If Tangle.classes.MyClass is a function instead of an object, Tangle will call it as a constructor, instead of directly invoking an initialize method. So, if you're using a framework such as MooTools that has its own notion of what a "class" is, you can use its classes directly, and take advantage of inheritance and other features.

Tangle.classes.MyClass = new Class({  // assuming we're using MooTools
    Extends: MyBaseClass,
    initialize: function (element, options, tangle, variable) {
       this.parent(element, options, tangle, variable);
       ...
    }
});

multiple variables

An HTML element can specify any number of variables, and they will all be passed to initialize and update. For example, if your class expects two variables:

<span class="MyClass" data-var="cookies cupcakes">

you would define it like so:

Tangle.classes.MyClass = {
    initialize: function (element, options, tangle, variable1, variable2) { ... },
    update: function (element, value1, value2) { ... }
};

This is useful for two-dimensional controls that adjust two variables at once, or views that display multiple variables.

options

The initialize method is passed an options parameter:

Tangle.classes.MyClass = {
    initialize: function (element, options, tangle, variable) { ... }
};

The options parameter is an object containing the data- attributes of the elements. (The "data-" prefix is removed.) If your HTML is:

<span class="MyClass" data-min="1" data-max="10">

then options will be an object like so:

{ min:"1", max:"10" }

*   *   *

Tangle.formats

Tangle.formats.myFormat = function (value) { return "..."; }

A Tangle format defines how to present a value. If your HTML is:

<span data-var="fractionOfCookiesRemaining" data-format="percent">

then when the variable is updated, the following function will be called to turn the value into a string.

Tangle.formats.percent = function (value) {     // formats 0.42 as "42%"
    return "" + Math.round(value * 100) + "%";
};

You can often use printf-style formats instead, but Tangle.formats is available for your custom formatting needs. To use printf-style formats, you must include a sprintf library, such as the one that is provided with TangleKit.

multiple variables

If the data-var attribute specifies multiple variables, all values will be passed to the function.

<span data-var="cookies cupcakes" data-format="myFormat">
Tangle.formats.myFormat = function (value1, value2) { return "..."; }

parameters

You can specify parameters in the data-format attribute, separated by spaces. These strings will be passed to the function, after the variable values.

<span data-var="cookies" data-format="myFormat huge">
Tangle.formats.myFormat = function (value, size) { return "..."; }

*   *   *

TangleKit

TangleKit is an optional collection of Tangle classes and formats, for adjusting variables and visualizing values. You can grab whichever components you want, use them, extend them, modify them, or just learn from them and make your own.

TangleKit is currently pretty rudimentary, and not yet documented here. You can look through TangleKit.js for what's currently available. Perhaps you'd even like to contribute to it.