Let's put a square on the screen. Here we'll be introduced to two Samsara primitives:
Surface and
Context.
A Surface wraps a DOM element in which you can place arbitrary HTML content. By default Surfaces
appear as <div> tags (though any valid HTML tag can be substituted).
A Context establishes a 3D environment in CSS so that perspective and 3D transforms behave
appropriately. It has no visual representation, but is the root from which all other content is rendered.
Contexts are mounted to existing DOM nodes, and all Surfaces added to them show up in HTML as a nested elements.
To get a square on the screen, we represent the square as a Surface and provide it a size, content, basic CSS
properties, and add it to a Context.
var Surface = Samsara.DOM.Surface;
var Context = Samsara.DOM.Context;
var surface = new Surface({
content : 'hello', // innerHTML
size : [100, 100], // [width, height] in pixels
properties : { // CSS style properties
background : 'red'
}
});
var context = new Context();
context.add(surface);
context.mount(document.querySelector('#myApp'));
See the Pen getting-started-1 by SamsaraJS (@samsaraJS) on CodePen.
Starting from a Context and adding nodes builds up the render tree: a JavaScript representation of the layout of a page.
Read more about the render tree here.
Let's place this square somewhere else. To do so, we'll see we can add more than just Surfaces to a Context.
Surfaces are the leaves of the render tree, everything between them and a Context are nodes that modify the
layouts and sizes of the surfaces beneath them.
transform, align, origin, opacity, size,
proportions, margins, and aspectRatio.You can read more about nodes and the values they accept here. Here's an example where
we add a node with a transform property that takes a Samsara Transform
to translate the surface to the right by 100px.
Transform corresponds to CSS3 transforms,
allowing you to translate, rotate, skew and scale DOM elements. Transforms ultimately end in in-lined CSS properties
for the Surfaces they affect.var Transform = Samsara.Core.Transform;
context
.add({transform : Transform.translateX(100)})
.add(surface);
See the Pen getting-started-3 by SamsaraJS (@samsaraJS) on CodePen.
You can experiment with other transforms like Transform.skewX(Math.PI/4), Transform.scaleY(2), etc.
Transforms can also be compounded together with the Transform.compose and Transform.composeMany methods.
var scaleAndRotate = Transform.compose(
Transform.scaleX(2),
Transform.rotateY(Math.PI/4)
);
We've been creating Surfaces with a static size set to [100, 100]. Many properties in Samsara can take dynamic values.
To change a value over time we can use a Transitionable.
Transitionable represents a number or array of numbers that changes over time. Values can be interpolated using
easing curves, and physical transitions like springs.You can read more about Transitionables here. In this example, we animate the size from [100, 100] to
[200, 200] with an easing curve.
var size = new Transitionable([100, 100]);
var surface = new Surface({
content : 'click me',
size : size,
properties : {background : 'red'}
});
surface.on('click', function(){
size.set([200, 200], {curve : 'easeOutBounce', duration : 1000});
});
See the Pen BoqdrW by SamsaraJS (@samsaraJS) on CodePen.
Other properties on Surface that can take streaming values are: origin, opacity, proportions, margins and aspectRatio.
Let's rotate the Surface as we animate its size. We'll use a physics transition for the rotation.
A rotation is a type of Transform, and Transitionables don't directly output Transform types.
However, Transitionables have a map method, which we will use to convert values to Transforms.
var size = new Transitionable([50, 50]);
var angle = new Transitionable(0);
var surface = new Surface({
size : size,
properties : {background : 'red'},
origin : [.5,.5] // sets the "origin" point to the center of the surface
});
surface.on('click', function(){
size.set([150, 150], {curve : 'easeOutBounce', duration : 1000});
angle.set(Math.PI, {curve : 'spring', period : 100, damping : .3});
});
// map the transitionable's value to a Transform
var rotation = angle.map(function(angle){
return Transform.rotateZ(angle);
});
var context = new Context();
context
.add({
transform : rotation,
align : [.5,.5] // aligns the origin point of the surface with the center of the context
})
.add(surface);
context.mount(document.querySelector('#myApp'));
See the Pen getting-started-compound-animation by SamsaraJS (@samsaraJS) on CodePen.
Above we sneakily introduced the concepts of align and origin in order to center the square. Read more about
these layout primitives here.
One of SamsaraJS's core principles is to make synchronizing animation simple.
In the following example we will grow the size of one Surface while keeping another Surface adjacent to it.
var t = new Transitionable(1);
// map the transitionable to a size for the red surface
var redSize = t.map(function(value){
var length = 100 * value;
return [length, length];
});
// map the transitionable to a `Transform` for the blue surface
// this will offset it in sync with the growing size of the redSurface
var blueTransform = t.map(function(value){
return Transform.translateX(100 * value);
});
var redSurface = new Surface({
content : 'click me',
size : redSize,
properties : {background : 'red'}
});
var blueSurface = new Surface({
size : [100, 100],
properties : {background : 'blue'}
});
redSurface.on('click', function(){
t.set(2, {duration : 1000, curve : 'easeOutBounce'});
});
var context = new Context();
// build the render tree
context.add(redSurface);
context
.add({transform : blueTransform})
.add(blueSurface);
context.mount(document.getElementById('myApp'));
See the Pen getting-started-4 by SamsaraJS (@samsaraJS) on CodePen.
There's another way to to this in SamsaraJS as well. Surface's have a size
property which is a stream. So you could replace blueTransform with
var blueTransform = redSurface.size.map(function(size){
return Transform.translateX(size[0]);
});
This will work without even if the size of the redSurface is animating, and avoids the need to hardcore the value 100
in multiple places.
At the expense of pedagogy, we're going to jump ahead a few steps. We'll use user input from the mouse instead of a
Transitionable in the above example. We'll allow the redSurface to be draggable, and have its size increase with
the drag behavior, all-the-while keeping the blueSurface adjacent.
See the Pen EVdvOJ by SamsaraJS (@samsaraJS) on CodePen.
This scrapes the surface of what SamsaraJS can do. Read through more of the guide, explore the API in depth
from the reference documentation, or take a look at the
examples to see more practical applications.