Space

Space provides a general context for its points to be expressed. Each subclass of Space represents a specific context. Currently Pts includes CanvasSpace which corresponds to the canvas element, and SVGSpace which lets you create vector graphics in svg format instead. There is also an experimental HTMLSpace which renders forms in basic html elements. Soon we will have spaces for other contexts too.

CanvasSpace can be created like this:

let space = new CanvasSpace( "#hello" );
space.setup({ bgcolor: "#123", retina: true });

The "#hello" is a selector string that selects an element in the html page. If the element is a <canvas>, it will be used by CanvasSpace. If the element is a <div> or other block element, a new <canvas> will be appended into it. You may also pass a HTMLElement directly, instead of a query selector string.

Once the space is created, you can optionally call the setup function to specify its background color (bgcolor) and other properties. Take a look at the setup documentation for more.

Now the space is set up, let's look at what it can do.

Players

A space by itself is void of form. Let's add a "player" to it. A player can be either a function or an object with specific properties.

space.add( (time, ftime) => {
  // do things
});

In the above, we use add to add a simple callback function. It has 2 parameters: time which gives the current running time, and ftime which gives the time taken to draw the previous frame. This callback is like an animation loop, which will be called continuously when the player plays.

Let's look at a more elaborate player:

space.add( {
  start: (bound, space) => { 
    // code for init 
  },
  animate: (time, ftime, space) => { 
    // code for animation 
  },
  action: (type, x, y, event) => { 
    // code for interaction 
  },
  resize: (size, event) => { 
    // code for resize 
  }
} );

Here we add an object that conforms to the IPlayer interface, which defines 4 optional callback functions:

You may add multiple players into a space, each taking care of specific parts of a scene. Use add and remove to manage a space's players.

Animation and interaction

You can tell a space to play or stop its players using play, stop and other functions:

space.play();
space.playOnce( 1000 ); // play 1 sec then stop
space.pause();
space.resume();
space.stop();

Using bindMouse and bindTouch, you can easily make the space respond to user interactions. Once the space can receive mouse or touch events, you can track the events using a player's action callback function, as described above.

// You can chain multiple functions together
space.bindMouse().bindTouch().play();

CanvasSpace also provides a couple convenient properties which you may access once the space is initiated. .pointer gives you the current pointer position. .size, .center, .width, .height and .innerBound are handy to get a space's size and center point. .element and .parent returns the html elements of this space.

CanvasSpace also supports offscreen rendering which may help with rendering complex scene. Take a look at the source code of this study for more.

Form

In the Get Started guide, we made an analogy of paper and pencil when introducing Space and Form. So CanvasForm represents a pencil to draw on CanvasSpace. You can get the form with a single function call.

let space = new CanvasSpace("#paper");
let form = space.getForm(); // get default CanvasForm

CanvasForm includes many convenient functions to draw shapes on <canvas> element. Usually, you'll use these drawing functions in a player's animate function like this:

// Draw points inside the animate callback function
space.add( (time, ftime) => {
    form.stroke("#fff").fill("#f03").circle( c );
    form.point( p, 10 );   
} );

If you need more advanced canvas functions, you can get canvas' rendering context by accessing ctx property. For example: form.ctx.clip().

js:space_form

A demo of drawing different shapes

And since both Space and Form are javascript classes, you can extend them to override its functions and add new ones.

SVG Space

You can easily switch you code from CanvasSpace to SVGSpace in 3 easy steps:

First, initiate space as SVGSpace instead of CanvasSpace. If you use space.getForm(), then it will return an SVGForm instead of CanvasForm automatically.

Second, in the beginning of your animate callback function, add this line:

form.scope( this );

This keeps track of the created svg or dom elements to optimize rendering.

Lastly, if you use es6 arrow function in a player's callback functions, for example:

animate: (time, ftime) => ...

You should change it back to the standard form:

animate: function( time, ftime) ...

The arrow function automatically binds this and will confuse the form.scope(this) call.

Take a look at the source code of the svg demo. It's pretty straightforward.

HTML Space

There's also experimental support for rendering HTML elements using HTMLSpace, which you can use by making similar changes in your code as described in SVG section above.

Take a look at the html demo and its source code. Because of the limitations of HTML, you cannot draw polygon, arc, and some other shapes with it.

If you use Pts with React or other web rendering frameworks, it will be better to use the props and states of their virtual DOM implementations instead.

Cheat sheet

The quickest way to start is to use the quickStart function, which initiates a CanvasSpace and adds space and form instances into current scope. You can create an interactive piece in 2 lines of code:

Pts.namespace( this ); // not needed if using npm package

let run = Pts.quickStart( "elemID", "#f03" )
run( (time, ftime) => form.fill("#f03").point( space.pointer, 10, "circle" ) );

The following snippet is a typical template for creating a Pts space and form. Use this if you need more than an animation loop. You can add either an animation function or an IPlayer object to a space. (See above for details)

Pts.namespace( this ); // not needed if using npm package

var space = new CanvasSpace("elemID").setup({ retina: true });
var form = space.getForm();

space.add( (time, ftime) => {
  form.fill("#f03").point( space.pointer, 10, "circle" ); 
} );

space.bindMouse().bindTouch().play();