On Github jonathanolson / slides-scenery
Jonathan OlsonPhET Interactive Simulations | University of Colorado Boulder
Most libraries focus on either Canvas, SVG or WebGL
Most libraries only support one renderer at a time
Most libraries have few of these
Higher performance by splitting content into layers
greenContainer.layerSplit = true; // will be isolated in a layer
// Create a scene graph over a positioned block-level element var scene = new scenery.Scene( $( '#hello-world-scene' ) ); // Add our text scene.addChild( new scenery.Text( 'Hello World', { centerX: 200, // the center of our text's bounds is at x = 200 centerY: 50, // the center of our text's bounds is at y = 50 font: '40px sans-serif', fill: '#eee' } ) ); // Paint any changes (in this case, our text). scene.updateScene();
// simple shapes can be accelerated scene.addChild( new scenery.Rectangle( 10, 10, 100, 80, { fill: '#f00', stroke: '#fff', lineWidth: 2 } ) ); scene.addChild( new scenery.Path( { shape: kite.Shape.regularPolygon( 8, 30 ), fill: '#0f0', x: 150, y: 50 } ) ); scene.addChild( new scenery.Path( { // Canvas-like Path API. Supports SVG Shape( 'M0 90Q155 50 0 10Z' ) shape: new kite.Shape().lineTo( 0, 90 ) .quadraticCurveTo( 155, 50, 0, 10 ) .close(), fill: '#00f', x: 190 } ) );
var imageUrl = 'http://phet.colorado.edu/sims/energy-skate-park/' + 'energy-skate-park-basics-thumbnail.png'; // direct URL reference, but cannot position based on bounds scene.addChild( new scenery.Image( imageUrl, { x: 100, y: -30, rotation: Math.PI / 6, } ) ); // can also pass in HTMLImageElement or HTMLCanvasElement references var img = document.createElement( 'img' ); img.src = imageUrl; scene.addChild( new scenery.Image( img, { opacity: 0.25, scale: 2 } ) );
var element = document.createElement( 'span' ); element.innerHTML = '<label style="display: inline;">Type in me:</label>' + '<input type="text">'; scene.addChild( new scenery.DOM( element, { x: 120, rotation: Math.PI / 6 } ) ); // HTML, with the same styling and positioning as Text scene.addChild( new scenery.HTMLText( '<em>Italic</em> and <b>Bold</b> ', { fontSize: 30, bottom: 230, centerX: 200, fill: '#9aa' } ) );
first.fill = 'rgba(255,127,0,0.8)'; // full support for CSS colors // linear gradients secondBottom.fill = new scenery.LinearGradient( 0, 0, 100, 0 ) .addColorStop( 0, '#000' ) .addColorStop( 1, '#666' ); // radial gradients secondTop.fill = new scenery.RadialGradient( 32, 32, 5, 64, 64, 60 ) .addColorStop( 0, '#0ff' ) .addColorStop( 1, 'rgba(0,127,255,0)' ); // patterns var transform = dot.Matrix3.rotation2( Math.PI / 6 ) .timesMatrix( dot.Matrix3.scale( 0.3 ) ); third.fill = new scenery.Pattern( img ).setTransformMatrix( transform );
first.stroke = 'rgba(255,127,0,0.8)'; // full support for CSS colors // linear gradients secondBottom.stroke = new scenery.LinearGradient( 0, 0, 100, 0 ) .addColorStop( 0, '#000' ) .addColorStop( 1, '#666' ); // radial gradients secondTop.stroke = new scenery.RadialGradient( 32, 32, 5, 64, 64, 60 ) .addColorStop( 0, '#0ff' ) .addColorStop( 1, 'rgba(0,127,255,0)' ); // patterns var transform = dot.Matrix3.rotation2( Math.PI / 6 ) .timesMatrix( dot.Matrix3.scale( 0.3 ) ); third.stroke = new scenery.Pattern( img ).setTransformMatrix( transform );
Supports all Canvas line styles
// vertical layout path.top = 20; fastText.top = path.bottom + 20; accurateText.top = fastText.bottom + 20; // horizontal layout fastText.left = 20; // offset from the left path.centerX = fastText.centerX; // center the path above accurateText.left = path.left; // align the lower text with the pathPossible to implement higher-level layout on top
Multi-touch abstraction over DOM3/Touch/Pointer/MSPointer
section.cursor = 'pointer'; // change the cursor when the mouse is over a section _.each( scene.children, function( section ) { // move each section individually section.addInputListener( new scenery.SimpleDragHandler() ); } );
Under development:
And 2 more: Build an Atom and Balloons and Static Electricity
Require.js for modularization
Mostly feature-complete, working on performance
2D Shape Handling | phetsims.github.io/kite
Math, with a focus on linear algebra | phetsims.github.io/dot
var v = dot( 10, -5 ) // shorthand for Vector2, used for points and vectors // v.x and v.y are the components v.normalized().times( 5 ).plus( dot( 1, 2 ) ).x // immutable, matches formulas v.normalize().multiply( 5 ).add( dot( 1, 2 ) ).x // mutable, minimizes GCs dot.Matrix3.rotation2( Math.PI / 6 ).timesVector2( v ) // immutable dot.Matrix3.rotation2( Math.PI / 6 ).multiplyVector2( v ) // mutable
If opacity is applied to a node whose children are across different layers, they will need to be handled differently:
<!-- layers before --> <div style="opacity: 0.6;"> <canvas><!-- red circle layer --></canvas> <svg><!-- blue circle layer --></svg> </div> <!-- layers after -->
Mixed Canvas/SVG/DOM not accessible by default
Soon: Creating DOM peers for each interactive node, with subtree control over the tab order
(or catch me after)
Jonathan Olson
github.com/jonathanolson | jonathan.olson@colorado.edu
Thanks to the PhET team (phet.colorado.edu), especially Sam Reid, Chris Malley, John Blanco and director Kathy Perkins