Vector.js

Vector is an open source javascript library for creating interactive graphics. View the repository, run the tests, or meet the team.

Notice

The masterbranch of this project is currently unmaintained. Development continues on the development branch on the repository. Thank you for your patience.

About

Welcome! Vector.js is a Javascript library for creating interactive graphics. The library uses the existing web standards: HTML, SVG, and CSS and has no dependencies.

Getting Started

To use this library, download the getting-started.tgz tar ball and follow the instructions below. The tar ball contains a folder with an index.html file and script.js file. The HTML file links the library’s style sheet, includes the script file which creates the interactive image, and has an element with an unique id that the interactive is rendered within.

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>Getting Started</title>
    <link rel="stylesheet" href="https://vectorjs.org/library.css">
  </head>
  <body>
    <div id="my-interactive"></div>
    <script type="module" src="script.js"></script>
  </body>
</html>

The script file imports the Interactive class from the website, constructs an interactive within the HTML element with the id “my-interactive”, and then creates a control point which can be dragged around. It also prints out the control and interactive objects to the console to play around with.

import Interactive from "https://vectorjs.org/interactive.js";

// Construct an interactive within the HTML element with the id "my-interactive"
let myInteractive = new Interactive("my-interactive");
myInteractive.border = true;

// Construct a control point at the the location (100, 100)
let control = myInteractive.control(100, 100);

// Print the two objects to the console
console.log( control, myInteractive);

To view the interactive, serve the folder containing the two files using a web server like Web Server for Chrome or your tool of choice. The result is a simple interactive with a draggable control point:

Elements

The library has basic visual and structural elements for creating graphics. The basic elements correspond to the elements of the Scalable Vector Graphics Specification. More complicated elements use one or more basic elements internally. Every element contains a root SVGElement attribute which gives access SVGElement Web API.

Ellipse

let ellipse = interactive.ellipse( 100, 75, 80, 40);

Line

let line = interactive.line( 50, 25, 150, 125);

Path

let line = interactive.path("M 50 50 Q 100 150 150 50");

Rectangle

let rectangle = interactive.rectangle( 50, 50, 100, 50);

Text

let text = interactive.text( 50, 75, "My Text");

TSpan

A text span element allows for text to be styled and positioned differently within a body of text. In the example below, a word is randomly selected to be bold to emphasize a part of the sentence.

let text = interactive.text( 50, 75, '');
text.tspan('normal. ');
text.tspan('bold. ').style.fontWeight = '600';
text.tspan('normal again.');

Group

The group element is a structural element for grouping other elements together. This is useful for applying styles, transformations, and other such things to multiple elements at once.

Input

User input drives the animations of these graphics and is the main focus of this library. These input elements are part of the SVG ecosystem and provide the end users with ways to manipulate and interact with the visual in front of them.

Button

The button element has a position, label, and default style. Defining the “onclick” method handles when a user clicks the button.

let button = interactive.button( 100, 75, "My Button");

Check Box

A checkbox has two different states: checked and unchecked. When a user clicks the box the state changes.

let checkBox = interactive.checkBox( 100, 75, "My Checkbox", false);

Control Point

A control point is a two dimensional point that can be clicked and dragged by the user. The control has a (x,y) position as well as its change in position (dx, dy).

let control = interactive.control( 150, 75);

The drop down allows users to select from a variety of options.

interactive.dropdownControl(20, 60, ["red", "green", "blue"], 0);

Radio Control

The radio control elements allows the user to select from a list of options. Only one option can be selected at a time.

let radio = interactive.radioControl(100, 50, ["red","green","blue"]);

Scrubber

The scrubber has a play and pause button that start and stop the animation. The position indicator can also be dragged to change the state of the scrubber.

let scrubber = interactive.scrubber( 100, 75, 400);

Slider

A slider has a position and zero or more of the following options: min, max, step, value, and width.

let slider = interactive.slider( 75, 75, {
  min: 100,
  max: 200,
  step: 25,
  value: 125,
  width: 200
});

Interaction

There are two forms of handling interaction within our software system. The first form is reactive programming. Elements can be related together using dependency functions, similar to how cells are related together in a spreadsheet application. These dependencies are explicit and give dependents access to the data of the elements they rely on. These dependencies also define how the interactive should update elements and in what order the update should happen when an element’s state is changed.

The second, more tradditional, form of handling interaction is event driven programming. Event handler properties are surfaced in elements where it seemed useful. Otherwise, access to all of the event handlers is available throught the root SVGElement and the native web APIs.

Reactive Programming

All elements contain the ability to define dependencies to other elements. An element declares what it is dependent on using the “addDependency” function and then defines an update function which describes how the element should update itself. Circular dependencies will cause an exception. By convention, an element should only use the data of the elements it has declared itself dependent on.

let control1 = interactive.control( 100, 100);
let control2 = interactive.control( 200, 200);
control2.addDependency(control1);
control2.update = function(){
  this.x += control1.dx;
};

An example of how this approach can be used to generate complicated interactives is given by the Riemann Sum example below. In this example, there are a fair number more elements that have been related together using the reactive approach.

To visualize what is happening, the elements that are related together are highlighted and labeled in blue. Then the dependency graph on the right shows the user defined depencies represented as arrows. For example, the dependency between the control point the control point “control1” (B) and the text “label” (E), is represented as B → E in the graph.

Event Handling

Keyboard Input

Key board input can be used to change the state of an interactive as well as control different elements within the interactive. The example below highlights the numbers one through five with the corresponding key on the keyboard when pressed.

window.onkeydown = function( event ) {
  ...
}

Mouse Input

Mouse input can be used to change the state of an interactive. Mouse input consists of the mouse’s position, when the users clicks the interactive, etc.

// register a mouse click handler
interactive.root.onmouseclick = (event) => {
  // ...
}

// register a mouse move handlers
interactive.root.onmousemove = (event) => {
  // ...
}

Animation

While animation isn’t the main focus the library, some basic animations can be achieved using some built in elements like the scrubber element, and the native web API requestAnimationFrame.

Time Line Animation

Adding a time-line to an interactive gives the user control over a basic animation. For beginner users, the scrubber is a great element to animate parts of an interactive. It allows the user to start, stop, and “scrub” to different parts of the animation.

Coordinates

The coordinate system of the interactive image follows the SVG standard: the default origin is the top left corner of the image and the positive x direction is to the right and the positive y direction is down. This is visualized by the control point below.

Changing the Origin

The origin of the interactive coordinate system can be moved by changing the .originX or .originY property of an Interactive object. The origin can also be specified when the object is constructed. In the code snippet below the origin is specified to be the point (300,150) relative to the top left corner of the interactive.

let interactive = new Interactive('my-id',{
  width: 600,
  height: 300,
  originX: 300,
  originY: 150
});

The interactive object created using the above code snippet results in the coordinate system demonstrated below. Note, the y-coordinate is flipped from the cartesian coordinate system.

Setting the View Box

The more general form of setting the origin of the interactive object which is derived from the SVG base class is setting the view box of the SVG element. This is extremely useful, especially when paired with the getBoundingBox method implemented by every SVGGraphics element. The two interactive shown below both contain a grid of rectangles. The interactive on the left contains a rectangle which represents the view box that is being applied to the interactive on the right.

The set view box function takes in a x position, y position, width and height. The (x,y) position represents the top-left-most position of the rectangle, the width and height specify the dimensions of the rectangle.

interactive.setViewBox( left, top, width, height);

Styling

The appearance of elements within this library can be styled using CSS. Styles can either be applied using a user defined style sheet or directly within the Javascript file. Helper classes are provided for the convenience of the user.

Basic Styling

Basic geometric elements have two basic properties: fill and stroke. Fill is the area contained within the shape and stroke is the edge of the geometric shape. These styles can be accessed through the style property.

let rectangle = interactive.rectangle( 50, 50, 100, 50);
rectangle.style.fill = 'blue';
rectangle.style.stroke = 'red';
rectangle.style.strokeWidth = '1px';

Custom Styling

Every element within the library has a root property which is a SVG element. This root element contains zero or more child elements all of which can have custom styling applied to them through CSS selectors or Javascript. The style sheet for the library can be found in the library.css file. Typically, elements have an associated class that gives them their default look and feel.

Modules

As of now, the library has three modules that provide the ability to create complex elements with a suitable level of abstraction. Each module utilizes the core functionality of the library in their implementation.

Graphs

The graphing module is used to display basic graphs in the form of node link diagrams. Both directed and undirected graphs are supported. The module allows for the creations of individual nodes which can be connected via edges. Additionally, the graphing module supports the Reingold-Tilford “tidy” layout for automatically drawing trees.

Maps

The Map Module is used to plot geographic data in SVG format. Our library supports GeoJson which is the most popular data standard for representing geographical data. The SVG path’s get grouped by feature, meaning that manipulating the map objects is straight forward. For more information on this, please go to our Map Module Tutorial or take a look at some map examples.

Interactive World Map

import {Interactive, getScriptName} from '../../index.js';
import {globalData} from './maps-json.js';

let myInteractive = new Interactive(getScriptName());
let map = myInteractive.map(globalData);

Custom Maps

Any data that is in the GeoJson format can be rendered with our library. That means that if you can find the data for it, we can plot it. For more information on how GeoJson works and where to find it, go to the Map Module tutorial.

Plots

Plots visualize the output of one or more functions in the Cartesian Coordinate System. To construct a plot, the user provides the dimensions of the plot and the function to be plotted.

let scale = 300/Math.PI;
interactive.plot(Math.sin, {
  title: "Sine Function",
  originX: 0,
  originY: 150,
  scaleX: scale,
  scaleY: scale,
});