├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── RELEASE.md ├── demo ├── _template.js ├── canvasspace.bindMouse.js ├── canvasspace.resize.js ├── circle.intersectCircle.js ├── circle.intersectCircle.mobile.js ├── circle.intersectPath.js ├── circle.intersectPoint.js ├── color.HSBtoRGB.js ├── color.HSLtoRGB.js ├── color.LABtoRGB.js ├── curve.bezier.js ├── curve.bspline.js ├── curve.cardinal.js ├── delaunay.generate.js ├── es6 │ ├── dist │ │ └── vector.field.js │ └── src │ │ └── vector.field.js ├── form.curve.js ├── form.fill.js ├── form.font.js ├── form.points.js ├── grid.canFit.js ├── grid.generate.js ├── grid.occupy.js ├── index.html ├── line.getPerpendicular.js ├── line.getPerpendicularFromPoint.js ├── line.intersectLine.js ├── mobile.html ├── mobile.multiTouch.js ├── mobileapp.html ├── noise.simplex2d.js ├── pair.collinear.js ├── pair.interpolate.js ├── pair.withinBounds.js ├── particle.collideLine2d.js ├── particle.play.js ├── point.max.js ├── point.quadrant.js ├── pointset.convexHull.js ├── pointset.sides.js ├── publish │ └── vector.field.js ├── rectangle.enclose.js ├── rectangle.intersectPath.js ├── rectangle.resizeCenterTo.js ├── samplepoints.poisson.js ├── shaping.linear.js ├── space.add.js ├── space.refresh.js ├── svgform.circle.js ├── svgform.scope.js ├── svgspace.remove.js ├── triangle.incenter.js ├── triangle.oppositeSide.js ├── vector.add.js ├── vector.field.js ├── vector.normalize.js ├── vector.projection.js ├── vector.rotate2D.js └── vector.scale2D.js ├── dist ├── core │ ├── elements │ │ ├── .map │ │ │ ├── CanvasSpace.js.map │ │ │ ├── Circle.js.map │ │ │ ├── Color.js.map │ │ │ ├── Const.js.map │ │ │ ├── Curve.js.map │ │ │ ├── DOMSpace.js.map │ │ │ ├── Form.js.map │ │ │ ├── Grid.js.map │ │ │ ├── Line.js.map │ │ │ ├── Matrix.js.map │ │ │ ├── Pair.js.map │ │ │ ├── Particle.js.map │ │ │ ├── ParticleSystem.js.map │ │ │ ├── Point.js.map │ │ │ ├── PointSet.js.map │ │ │ ├── Rectangle.js.map │ │ │ ├── SVGForm.js.map │ │ │ ├── SVGSpace.js.map │ │ │ ├── Space.js.map │ │ │ ├── Timer.js.map │ │ │ ├── Triangle.js.map │ │ │ ├── Util.js.map │ │ │ └── Vector.js.map │ │ ├── CanvasSpace.js │ │ ├── Circle.js │ │ ├── Color.js │ │ ├── Const.js │ │ ├── Curve.js │ │ ├── DOMSpace.js │ │ ├── Form.js │ │ ├── Grid.js │ │ ├── Line.js │ │ ├── Matrix.js │ │ ├── Pair.js │ │ ├── Particle.js │ │ ├── ParticleSystem.js │ │ ├── Point.js │ │ ├── PointSet.js │ │ ├── Rectangle.js │ │ ├── SVGForm.js │ │ ├── SVGSpace.js │ │ ├── Space.js │ │ ├── Timer.js │ │ ├── Triangle.js │ │ ├── Util.js │ │ └── Vector.js │ ├── pt-core-ns.js │ ├── pt-core-ns.min.js │ ├── pt-core.js │ ├── pt-core.js.map │ └── pt-core.min.js ├── extend │ ├── elements │ │ ├── Easing.js │ │ ├── GridCascade.js │ │ ├── Noise.js │ │ ├── ParticleEmitter.js │ │ ├── ParticleField.js │ │ ├── QuadTree.js │ │ ├── SamplePoints.js │ │ ├── StripeBound.js │ │ ├── UI.js │ │ └── map │ │ │ ├── Easing.js.map │ │ │ ├── GridCascade.js.map │ │ │ ├── Noise.js.map │ │ │ ├── ParticleEmitter.js.map │ │ │ ├── ParticleField.js.map │ │ │ ├── QuadTree.js.map │ │ │ ├── SamplePoints.js.map │ │ │ ├── StripeBound.js.map │ │ │ └── UI.js.map │ ├── pt-extend.js │ └── pt-extend.js.map ├── module │ └── pt.js ├── pt-ns.js ├── pt-ns.min.js ├── pt.js ├── pt.js.map └── pt.min.js ├── docgen.py ├── docs ├── css │ ├── docgen.css │ ├── docgen.scss │ ├── guide.css │ └── guide.scss ├── docgen.coffee ├── guide │ ├── INSTRUCTION.md │ ├── _convert.html │ ├── migration.html │ ├── migration.md │ ├── mobile.html │ ├── mobile.md │ ├── prism.css │ ├── prism.js │ ├── quickstart.html │ ├── quickstart.md │ ├── quickstart_demo.html │ ├── svg.html │ └── svg.md ├── images │ ├── pt │ │ ├── canvasspace.bindMouse.png │ │ ├── canvasspace.resize.png │ │ ├── circle.intersectCircle.png │ │ ├── circle.intersectPath.png │ │ ├── circle.intersectPoint.png │ │ ├── color.HSBtoRGB.png │ │ ├── color.HSLtoRGB.png │ │ ├── color.LABtoRGB.png │ │ ├── curve.bezier.png │ │ ├── curve.bspline.png │ │ ├── curve.cardinal.png │ │ ├── form.curve.png │ │ ├── form.fill.png │ │ ├── form.font.png │ │ ├── form.points.png │ │ ├── grid.generate.png │ │ ├── grid.occupy.png │ │ ├── index.png │ │ ├── index2.png │ │ ├── line.getPerpendicular.png │ │ ├── line.getPerpendicularFromPoint.png │ │ ├── line.intersectLine.png │ │ ├── pair.collinear.png │ │ ├── pair.interpolate.png │ │ ├── pair.withinBounds.png │ │ ├── particle.collideLine2d.png │ │ ├── particle.play.png │ │ ├── point.max.png │ │ ├── point.quadrant.png │ │ ├── pointset.convexhull.png │ │ ├── pointset.sides.png │ │ ├── rectangle.enclose.png │ │ ├── rectangle.intersectPath.png │ │ ├── rectangle.resizeCenterTo.png │ │ ├── samplepoints.poisson.png │ │ ├── shaping.linear.png │ │ ├── space.add.png │ │ ├── space.refresh.png │ │ ├── svgform.circle.png │ │ ├── svgform.scope.png │ │ ├── svgspace.remove.png │ │ ├── triangle.incenter.png │ │ ├── triangle.oppositeSide.png │ │ ├── vector.add.png │ │ ├── vector.field.png │ │ ├── vector.normalize.png │ │ ├── vector.projection.png │ │ ├── vector.rotate2D.png │ │ └── vector.scale2D.png │ └── quick-start-guide │ │ ├── console.png │ │ ├── mobile1.png │ │ ├── mobiletouch.gif │ │ ├── progress1.png │ │ ├── progress2.png │ │ ├── progress3.png │ │ ├── progress4.png │ │ └── progress5.png ├── index.html ├── index.js ├── js │ ├── demo.js │ └── docgen.js ├── json │ ├── core │ │ ├── CanvasSpace.json │ │ ├── Circle.json │ │ ├── Color.json │ │ ├── Const.json │ │ ├── Curve.json │ │ ├── DOMSpace.json │ │ ├── Easing.json │ │ ├── Form.json │ │ ├── Geom.json │ │ ├── Grid.json │ │ ├── Line.json │ │ ├── Matrix.json │ │ ├── Pair.json │ │ ├── Particle.json │ │ ├── ParticleSystem.json │ │ ├── Point.json │ │ ├── PointSet.json │ │ ├── Rectangle.json │ │ ├── SVGForm.json │ │ ├── SVGSpace.json │ │ ├── Space.json │ │ ├── Timer.json │ │ ├── Triangle.json │ │ ├── Util.json │ │ ├── Vector.json │ │ └── all.json │ └── extend │ │ ├── Delaunay.json │ │ ├── Easing.json │ │ ├── GridCascade.json │ │ ├── Noise.json │ │ ├── ParticleEmitter.json │ │ ├── ParticleField.json │ │ ├── QuadTree.json │ │ ├── SVGForm.json │ │ ├── SVGSpace.json │ │ ├── SamplePoints.json │ │ ├── Shaping.json │ │ ├── StripeBound.json │ │ ├── UI.json │ │ └── all.json └── underscore-min.js ├── favicon.ico ├── gulpfile.js ├── index.html ├── package.json ├── src └── coffee │ ├── core │ ├── CanvasSpace.coffee │ ├── Circle.coffee │ ├── Color.coffee │ ├── Const.coffee │ ├── Curve.coffee │ ├── DOMSpace.coffee │ ├── Form.coffee │ ├── Grid.coffee │ ├── Line.coffee │ ├── Matrix.coffee │ ├── Pair.coffee │ ├── Particle.coffee │ ├── ParticleSystem.coffee │ ├── Point.coffee │ ├── PointSet.coffee │ ├── Rectangle.coffee │ ├── SVGForm.coffee │ ├── SVGSpace.coffee │ ├── Space.coffee │ ├── Timer.coffee │ ├── Triangle.coffee │ ├── Util.coffee │ └── Vector.coffee │ └── extend │ ├── Delaunay.coffee │ ├── GridCascade.coffee │ ├── Noise.coffee │ ├── ParticleEmitter.coffee │ ├── ParticleField.coffee │ ├── QuadTree.coffee │ ├── SamplePoints.coffee │ ├── Shaping.coffee │ ├── StripeBound.coffee │ └── UI.coffee └── test ├── lib ├── jasmine-1.2.0 │ ├── ._MIT.LICENSE │ ├── ._jasmine-html.js │ ├── ._jasmine.css │ ├── ._jasmine.js │ ├── MIT.LICENSE │ ├── jasmine-html.js │ ├── jasmine.css │ └── jasmine.js ├── jquery-1.8.0.min.js └── underscore-min.js ├── spec └── point_spec.js └── spec_core.html /.gitignore: -------------------------------------------------------------------------------- 1 | .sass-cache 2 | node_modules 3 | .idea 4 | .map/*.* 5 | dist/core/**/*.js.map 6 | dist/extend/**/*.js.map 7 | .DS_Store -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src/ 2 | docs/ 3 | test/ 4 | .idea 5 | demo/ 6 | docgen.py 7 | index.html 8 | favicon.ico 9 | dist/core/ 10 | dist/extend/ 11 | dist/*.js 12 | dist/*.js.map -------------------------------------------------------------------------------- /demo/_template.js: -------------------------------------------------------------------------------- 1 | //// 0. Describe this demo 2 | window.demoDescription = ""; 3 | 4 | 5 | //// 1. Define Space and Form 6 | var colors = { 7 | a1: "#ff2d5d", a2: "#42dc8e", a3: "#2e43eb", a4: "#ffe359", 8 | b1: "#96bfed", b2: "#f5ead6", b3: "#f1f3f7", b4: "#e2e6ef" 9 | }; 10 | var space = new CanvasSpace("demo", colors.b4 ).display(); 11 | var form = new Form( space.ctx ); 12 | 13 | 14 | //// 2. Create Elements 15 | 16 | 17 | 18 | 19 | //// 3. Visualize, Animate, Interact 20 | space.add({ 21 | animate: function(time, fps, context) { 22 | 23 | }, 24 | onMouseAction: function(type, x, y, evt) { 25 | 26 | } 27 | }); 28 | 29 | 30 | // 4. Start playing 31 | space.bindMouse(); 32 | space.play(); -------------------------------------------------------------------------------- /demo/canvasspace.bindMouse.js: -------------------------------------------------------------------------------- 1 | //// 0. Describe this demo 2 | window.demoDescription = "A set of points records the mouse trail as the mouse moves. When mouse is down and dragging, the trail will extend. When released, the trail gradually shortens."; 3 | 4 | 5 | //// 1. Define Space and Form 6 | var colors = { 7 | a1: "#ff2d5d", a2: "#42dc8e", a3: "#2e43eb", a4: "#ffe359", 8 | b1: "#96bfed", b2: "#f5ead6", b3: "#f1f3f7", b4: "#e2e6ef" 9 | } 10 | var space = new CanvasSpace( "pt" ).setup( {bgcolor: colors.a4} ); 11 | var form = new Form( space ); 12 | 13 | 14 | //// 2. Create Elements 15 | 16 | // A Chain is a kind of Curve, which is a set of points 17 | function Chain() { 18 | Curve.apply( this, arguments ); 19 | 20 | this.hold = false; // whether mouse is pressed 21 | this.lineSize = 0.2; 22 | } 23 | Util.extend( Chain, Curve ); // extends Curve class 24 | 25 | // to animate the chain in Space 26 | Chain.prototype.animate= function(time, fps, context) { 27 | 28 | form.stroke("#222", this.lineSize, "round"); 29 | 30 | // draw the points as catmull-rom curve 31 | form.curve( this.catmullRom(5) ); 32 | 33 | // shorten the chain gradually 34 | if ( !this.hold ) { 35 | if (this.lineSize > 0.3) this.lineSize -= 0.2; 36 | if (this.points.length > 30) this.disconnect( Math.floor(this.points.length/100) ); 37 | } 38 | }; 39 | 40 | // to track mouse actions in Space 41 | Chain.prototype.onMouseAction = function(type, x, y, evt) { 42 | 43 | // when mouse move, add a point to the trail 44 | if (type == "move") { 45 | this.to(x,y); 46 | if (this.hold) this.lineSize += 0.02; 47 | } 48 | 49 | // check whether mouse is down 50 | if (type == "down") { 51 | this.hold = true; 52 | } else if (type == "up" || type == "out") { 53 | this.hold = false; 54 | } 55 | }; 56 | 57 | Chain.prototype.onTouchAction = Chain.prototype.onMouseAction; 58 | 59 | 60 | //// 3. Visualize, Animate, Interact 61 | 62 | // add a new Chain to Space 63 | space.add( new Chain() ); 64 | 65 | 66 | // 4. Start playing 67 | space.bindMouse(); // bind mouse events 68 | space.bindTouch(); 69 | space.play(); -------------------------------------------------------------------------------- /demo/canvasspace.resize.js: -------------------------------------------------------------------------------- 1 | //// 0. Describe this demo 2 | window.demoDescription = "Draw shapes based on the size of space. Resize the window and the drawing will update."; 3 | 4 | 5 | //// 1. Define Space and Form 6 | var colors = { 7 | a1: "#ff2d5d", a2: "#42dc8e", a3: "#2e43eb", a4: "#ffe359", 8 | b1: "#96bfed", b2: "#f5ead6", b3: "#f1f3f7", b4: "#e2e6ef" 9 | }; 10 | var space = new CanvasSpace("pt").setup( {bgcolor: colors.b1} ); 11 | var form = new Form( space ); 12 | 13 | 14 | //// 2. Create Elements 15 | var center = new Vector(); 16 | var line1 = new Line(); 17 | var line2 = new Line(); 18 | var rect = new Rectangle(); 19 | 20 | 21 | //// 3. Visualize, Animate, Interact 22 | space.add({ 23 | 24 | animate: function(time, fps, context) { 25 | 26 | // draw inner rectange 27 | form.stroke(false); 28 | form.fill(colors.a3); 29 | form.rect( rect ); 30 | 31 | // draw lines 32 | form.stroke("#ff0"); 33 | form.line( line1 ); 34 | form.stroke("#fff"); 35 | form.line( line2 ); 36 | 37 | // draw measurements 38 | form.fill("#fff"); 39 | var size = center.$multiply(2); 40 | form.font(space.size.y/5); 41 | form.text( new Point( 10, center.y+space.size.y/20), Math.floor( size.y ) ); 42 | form.font(20); 43 | form.text( new Point( center.x, 20), Math.floor( size.x ) ); 44 | 45 | }, 46 | 47 | // handler for Space resize 48 | onSpaceResize: function(x, y, evt) { 49 | 50 | // center is at half size 51 | center.set(x/2, y/2); 52 | 53 | var shift = x/10; 54 | line1.set(x/2 + shift, 0); 55 | line1.p1.set(x/2 - shift, y); 56 | 57 | line2.set(0, y/2 - shift); 58 | line2.p1.set(x, y/2 + shift); 59 | 60 | rect.size( x/2, y/2 ); 61 | rect.setCenter( x/2, y/2 ); 62 | } 63 | }); 64 | 65 | 66 | 67 | // 4. Start playing 68 | space.play(); -------------------------------------------------------------------------------- /demo/circle.intersectCircle.js: -------------------------------------------------------------------------------- 1 | //// 0. Describe this demo 2 | window.demoDescription = "A circle and a donut meets. Indicate their points of intersections."; 3 | 4 | 5 | //// 1. Define Space and Form 6 | var colors = { 7 | a1: "#ff2d5d", a2: "#42dc8e", a3: "#2e43eb", a4: "#ffe359", 8 | b1: "#96bfed", b2: "#f5ead6", b3: "#f1f3f7", b4: "#e2e6ef" 9 | }; 10 | var space = new CanvasSpace("pt").setup( {bgcolor: colors.a4} ); 11 | var form = new Form( space ); 12 | 13 | //// 2. Create Elements 14 | var mouse = new Circle( space.size.$divide(2) ).setRadius( Math.min(space.size.x, space.size.y)/4 ); 15 | var mouse2 = new Circle( space.size.$divide(2) ).setRadius( Math.min(space.size.x, space.size.y)/8 ); 16 | var circle = new Circle( space.size.$divide(2) ).setRadius( Math.min(space.size.x, space.size.y)/5 ); 17 | 18 | 19 | form.stroke( false ); 20 | 21 | //// 3. Visualize, Animate, Interact 22 | space.add({ 23 | animate: function(time, fps, context) { 24 | 25 | // draw circle and donut. Donut follows mouse position. 26 | form.fill( colors.a2 ); 27 | form.circle( mouse, mouse.radius, true ); 28 | 29 | form.fill( colors.a4 ); 30 | form.circle( mouse2, mouse2.radius, true ); 31 | 32 | form.fill( "rgba(50,50,50,.25)" ); 33 | form.circle( circle, circle.radius, true ); 34 | 35 | // Check intersections and draw the intersection points 36 | var ps = circle.intersectCircle( mouse ); 37 | var ps2 = circle.intersectCircle( mouse2 ); 38 | 39 | form.fill( colors.a1 ); 40 | for (var i=0; i 0) { 75 | mouse.set( touchPoints[0] ); 76 | mouse2.set( touchPoints[0] ); 77 | 78 | // 2 fingers pinch/expand to resize the mouse circles 79 | var r = (touchPoints.length > 1) ? touchPoints[1].distance( touchPoints[0] ) : Math.min(space.size.x, space.size.y)/4; 80 | mouse.setRadius( r ); 81 | 82 | // 3rd and 4th fingers: move and pinch/expand the static circle 83 | if ( touchPoints.length > 2 ) circle.set( touchPoints[2] ); 84 | if ( touchPoints.length > 3 ) circle.setRadius( touchPoints[3].distance( touchPoints[2]) ); 85 | } 86 | } 87 | 88 | }); 89 | 90 | 91 | // 4. Start playing 92 | space.bindMouse(); 93 | space.bindTouch(); 94 | space.play(); -------------------------------------------------------------------------------- /demo/circle.intersectPath.js: -------------------------------------------------------------------------------- 1 | //// 0. Describe this demo 2 | window.demoDescription = "A circle moves in a field of line segments. Check intersections on both line paths and line segments, and highlight the intersection points and paths"; 3 | 4 | 5 | //// 1. Define Space and Form 6 | var colors = { 7 | a1: "#ff2d5d", a2: "#42dc8e", a3: "#2e43eb", a4: "#ffe359", 8 | b1: "#96bfed", b2: "#f5ead6", b3: "#f1f3f7", b4: "#e2e6ef" 9 | }; 10 | var space = new CanvasSpace("pt").setup( {bgcolor: "#222"} ); 11 | var form = new Form( space ); 12 | 13 | 14 | //// 2. Create Elements 15 | var mouse = new Circle( space.size.$divide(2) ).setRadius(100); 16 | 17 | // random lines 18 | var pairs = []; 19 | for (var i=0; i<70; i++) { 20 | var r = new Vector( space.size.x/3*(Math.random()-Math.random()), space.size.x/3*(Math.random()-Math.random()) ); 21 | pairs.push( new Pair( space.size.$multiply( Math.random(), Math.random()) ).to( r).relative()); 22 | } 23 | 24 | //// 3. Visualize, Animate, Interact 25 | space.add({ 26 | animate: function(time, fps, context) { 27 | 28 | // go through each pair 29 | for (var i=0; i0) { 36 | 37 | // draw path intersections 38 | for (var j=0; j 0; 49 | 50 | // draw line segment intersections 51 | form.stroke( false ).fill( colors.a1 ); 52 | for (var k=0; k lineSize) { 46 | bezier.to( pt ); 47 | 48 | // remove last end point and 2 control points 49 | if (bezier.count() > 70) { 50 | bezier.disconnect( 3 ); 51 | } 52 | 53 | last = pt; 54 | lineSize = 50; 55 | } 56 | } 57 | }, 58 | 59 | onTouchAction: function(type, x, y, evt) { 60 | this.onMouseAction( type, x, y ); 61 | } 62 | }); 63 | 64 | 65 | // 4. Start playing 66 | space.bindMouse(); 67 | space.bindTouch(); 68 | space.play(); -------------------------------------------------------------------------------- /demo/curve.cardinal.js: -------------------------------------------------------------------------------- 1 | //// 0. Describe this demo 2 | window.demoDescription = "Two series of points oscillate in waves. Draw a curve that connects the points, and adjust the curve's tension."; 3 | 4 | 5 | //// 1. Define Space and Form 6 | var colors = { 7 | a1: "#ff2d5d", a2: "#42dc8e", a3: "#2e43eb", a4: "#ffe359", 8 | b1: "#96bfed", b2: "#f5ead6", b3: "#f1f3f7", b4: "#e2e6ef" 9 | }; 10 | var space = new CanvasSpace("pt").setup( {bgcolor: colors.b4} ); 11 | var form = new Form( space ); 12 | form.fill(false); 13 | 14 | //// 2. Create Elements 15 | var unit = space.size.$divide(10); 16 | var sizes = []; // amplitude 17 | var tension = 0.5; 18 | var tensionStep = 0; 19 | 20 | // cardinal curve points 21 | var pts = []; 22 | for (var i=0; i<12; i++) { 23 | pts.push( new Vector(unit.x*3.5, unit.y + unit.y*i/1.5)); 24 | sizes.push( Math.sin( i*Const.half_pi ) * unit.x * (i / 12) ) 25 | } 26 | 27 | var curve = null; // Curve 28 | 29 | 30 | //// 3. Visualize, Animate, Interact 31 | space.add( { 32 | animate: function ( time, fps, context ) { 33 | 34 | // draw curve's white shadow 35 | if (curve) { 36 | curve.moveBy( 20, 20 ); 37 | form.stroke( false ).fill( "#fff" ).polygon( curve.cardinal() ); 38 | } 39 | 40 | // generate curve points 41 | var curve1 = []; 42 | var curve2 = []; 43 | 44 | for (var i = 0; i < pts.length; i++) { 45 | curve1.push( pts[i].$add( sizes[i], 0 ) ); 46 | curve2.push( pts[i].$add( sizes[i] * -1 + unit.x * 3, unit.y / 2 ) ); 47 | 48 | // draw stripes between corresponding points on the curve 49 | if (i > 0 && i < pts.length - 1) { 50 | form.stroke( ((i % 2 === 0) ? colors.a2 : colors.a4), 10 ).line( new Line( curve1[curve1.length - 1] ).to( curve2[curve2.length - 1] ) ); 51 | } 52 | } 53 | 54 | // cardinal curve tension 55 | tensionStep++; 56 | tension = 0.5 + 0.5 * Math.sin( tensionStep % 360 * Const.deg_to_rad ); 57 | 58 | // draw cardinal curve 59 | curve = new Curve().to( curve1.concat( curve2.reverse() ) ); 60 | form.fill( false ).stroke( "#89a", 10 ).polygon( curve.cardinal( 10, tension ) ); 61 | 62 | }, 63 | 64 | onMouseAction: function ( type, x, y, evt ) { 65 | var d = space.size.$divide( 2 ).subtract( x, y ); 66 | var angle = Const.two_pi * (d.y / (unit.y * 5)); 67 | 68 | // calculate curve amplitude by sine wave 69 | for (var i = 0; i < pts.length; i++) { 70 | sizes[i] = Math.sin( angle + i * Const.half_pi ) * unit.x * (i / pts.length); 71 | } 72 | }, 73 | 74 | onTouchAction: function(type, x, y, evt) { 75 | this.onMouseAction( type, x, y ); 76 | } 77 | }); 78 | 79 | 80 | // 4. Start playing 81 | space.bindMouse(); 82 | space.bindTouch(); 83 | space.play(); -------------------------------------------------------------------------------- /demo/delaunay.generate.js: -------------------------------------------------------------------------------- 1 | //// 0. Describe this demo 2 | window.demoDescription = "A series of points forming a fibonacci spiral disc, distorted by mouse position, and connected as delaunay triangles."; 3 | 4 | 5 | //// 1. Define Space and Form 6 | var colors = { 7 | a1: "#ff2d5d", a2: "#42dc8e", a3: "#2e43eb", a4: "#ffe359", 8 | b1: "#96bfed", b2: "#f5ead6", b3: "#f1f3f7", b4: "#e2e6ef" 9 | }; 10 | var space = new CanvasSpace("pt").setup( {bgcolor: colors.a2} ); 11 | var form = new Form( space ); 12 | form.fill( false ); 13 | 14 | 15 | //// 2. Create Elements 16 | var mouse = new Circle( space.size.$divide(2) ).setRadius(50); 17 | var pts = fibonacci(150, space.size.x/2, space.size.$divide(2), 2); 18 | var de = new Delaunay(); 19 | 20 | 21 | // Generate fibonacci spiral points 22 | function fibonacci( num, scale, offset, smooth ) { 23 | if (!smooth) smooth = 0; 24 | var b = Math.round( smooth * Math.sqrt( num ) ); 25 | var phi = (Math.sqrt( 5 ) + 1) / 2; 26 | var pts = []; 27 | for (var i = 0; i < num; i++) { 28 | var r = (i > num - b) ? 1 : Math.sqrt( i - 0.5 ) / Math.sqrt( num - (b + 1) / 2 ); 29 | var theta = 2 * Math.PI * i / (phi * phi); 30 | pts.push( new Vector( r * scale * Math.cos( theta ), r * scale * Math.sin( theta ) ).add( offset ) ); 31 | } 32 | return pts; 33 | } 34 | 35 | //// 3. Visualize, Animate, Interact 36 | space.add( { 37 | animate: function ( time, fps, context ) { 38 | 39 | // rescale the points based on mouse position to each point 40 | var _pts = []; 41 | for (var i = 0; i < pts.length; i++) { 42 | var _p = pts[i].clone(); 43 | var dist = (mouse.radius - pts[i].distance( mouse )) / mouse.radius; 44 | _p.scale2D( 1 + dist, 1 + dist, mouse ); 45 | _pts.push( _p ); 46 | } 47 | 48 | // regenerate delaunay triangles 49 | de.points = _pts; 50 | de.generate(); 51 | 52 | // draw points, triangles and circumcircles 53 | form.stroke( false ).fill( "#fff" ).points( de.points, 7, true ); 54 | form.fill( false ); 55 | 56 | for (i = 0; i < de.mesh.length; i++) { 57 | form.stroke( colors.a4 ); 58 | form.circle( de.mesh[i].circle ); 59 | } 60 | 61 | for (i = 0; i < de.mesh.length; i++) { 62 | form.stroke( colors.a1 ); 63 | form.triangle( de.mesh[i].triangle ); 64 | } 65 | 66 | }, 67 | 68 | onMouseAction: function ( type, x, y, evt ) { 69 | if (type == "move") { 70 | mouse.set( x, y ); 71 | } 72 | }, 73 | 74 | onTouchAction: function(type, x, y, evt) { 75 | this.onMouseAction( type, x, y ); 76 | } 77 | }); 78 | 79 | 80 | // 4. Start playing 81 | space.bindMouse(); 82 | space.bindTouch(); 83 | space.play(); -------------------------------------------------------------------------------- /demo/form.curve.js: -------------------------------------------------------------------------------- 1 | //// 0. Describe this demo 2 | window.demoDescription = "Define 4 points which are the anchor and control points for different curves. Move the points to shift the curve."; 3 | 4 | 5 | //// 1. Define Space and Form 6 | var colors = { 7 | a1: "#ff2d5d", a2: "#42dc8e", a3: "#2e43eb", a4: "#ffe359", 8 | b1: "#96bfed", b2: "#f5ead6", b3: "#f1f3f7", b4: "#e2e6ef" 9 | }; 10 | var space = new CanvasSpace("pt").setup( {bgcolor: "#222"} ); 11 | var form = new Form( space ); 12 | 13 | 14 | //// 2. Create Elements 15 | var mouse = new Vector(); 16 | var threshold = 60; 17 | var pts = []; 18 | for (var i=0; i<4; i++) { 19 | pts.push( new Vector( space.size.x/2, (i+1) * space.size.y/5 ) ); 20 | } 21 | 22 | 23 | 24 | //// 3. Visualize, Animate, Interact 25 | space.add({ 26 | animate: function(time, fps, context) { 27 | 28 | // red catmull rom curve 29 | form.stroke(colors.a1, 2); 30 | form.curve( new Curve().to(pts).catmullRom() ); 31 | 32 | // green cardinal curve with tension 33 | form.stroke(colors.a2, 2); 34 | form.curve( new Curve().to(pts).cardinal( 15, 0.8) ); 35 | 36 | // blue bezier curve with higher precision curver (20 steps) 37 | form.stroke(colors.a3, 2); 38 | form.curve( new Curve().to(pts).bezier(20) ); 39 | 40 | // fill color for points 41 | form.stroke(false).fill( "#fff" ); 42 | 43 | for (var i=0; i 200) pts.shift(); 26 | if (counter++ % 20 == 0 && pts.length >= minPts) pts.shift(); 27 | 28 | // increase population when there are too few 29 | if (pts.length < minPts) { 30 | for (var i=pts.length; i 2 | 3 | 4 | 5 | Mobile test 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 58 | 59 | 60 | 61 |
62 |

Pt Mobile Demo (pixel ratio: )

63 |

1 finger to move
2 fingers to pinch or expand
3 or 4 fingers for more

64 |
65 | 66 |
67 |
68 |
69 | 70 |
71 | 50+ Demos are available on desktop 72 |
73 | 74 | 77 | 78 | 79 | 80 | 81 | 82 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /demo/noise.simplex2d.js: -------------------------------------------------------------------------------- 1 | //// 0. Describe this demo 2 | window.demoDescription = "Creating simplex noise. Work in progress"; 3 | 4 | //// 1. Define Space and Form 5 | var colors = { 6 | a1: "#ff2d5d", a2: "#42dc8e", a3: "#2e43eb", a4: "#ffe359", 7 | b1: "#96bfed", b2: "#f5ead6", b3: "#f1f3f7", b4: "#e2e6ef" 8 | }; 9 | var space = new CanvasSpace("demo", "#222" ).display(); 10 | var form = new Form( space ); 11 | 12 | 13 | //// 2. Create Elements 14 | var curve = new Curve(); 15 | var noise = new Noise(); 16 | noise.seed(0.04564903723075986); 17 | 18 | function getNoiseDistance( noise, noiseIncrement, dist, layerRatio, magnify ) { 19 | 20 | // noise parameters 21 | var na = layerRatio; 22 | var nb = 1 - layerRatio; 23 | 24 | // get next noise 25 | var layerset = noise.simplex2d( (na)+noiseIncrement, (nb)+noiseIncrement ); 26 | return dist * layerset * (0.5 + magnify*layerRatio); 27 | 28 | } 29 | 30 | //// 3. Visualize, Animate, Interact 31 | space.add({ 32 | animate: function(time, fps, context) { 33 | 34 | form.fill(false).stroke("#fff"); 35 | var pts = []; 36 | var n1 = 0; 37 | var n2 = 0; 38 | 39 | for (var i=0; i<40; i++) { 40 | 41 | n1 += 0.1; 42 | n2 += 5; 43 | 44 | var dn = getNoiseDistance( noise, n1, 50, 1, 1 ); 45 | pts[i] = new Vector( n2, dn + 500 ); 46 | form.point( pts[i], 1, false ); 47 | } 48 | 49 | form.line( new Line(0, 500).to(500, 500)); 50 | form.polygon( pts, false ); 51 | 52 | }, 53 | 54 | onMouseAction: function(type, x, y, evt) { 55 | if (type=="move") { 56 | 57 | } 58 | } 59 | }); 60 | 61 | 62 | // 4. Start playing 63 | space.bindMouse(); 64 | space.play(); -------------------------------------------------------------------------------- /demo/pair.collinear.js: -------------------------------------------------------------------------------- 1 | //// 0. Describe this demo 2 | window.demoDescription = "Pairs of points revolve around a center point. Draw a line whose color depends on whether the mouse position is on left or right side of the pair, or if the 3 points are collinear."; 3 | 4 | 5 | //// 1. Define Space and Form 6 | var colors = { 7 | a1: "#ff2d5d", a2: "#42dc8e", a3: "#2e43eb", a4: "#ffe359", 8 | b1: "#96bfed", b2: "#f5ead6", b3: "#f1f3f7", b4: "#e2e6ef" 9 | }; 10 | var space = new CanvasSpace("pt").setup( {bgcolor: "#222"} ); 11 | var form = new Form( space ); 12 | 13 | 14 | //// 2. Create Elements 15 | var pairs = []; 16 | var center = space.size.$divide(2); 17 | var mouse = center.clone(); 18 | 19 | var steps = 200; 20 | var r = Math.min( space.size.x, space.size.y ) * 0.4; 21 | var dr = Math.min( space.size.x, space.size.y ) * 0.4 / steps; 22 | 23 | // create pairs 24 | for (var i=0; i 10) return; 27 | 28 | var a = outer.size().$divide( 5 + Math.random() * 10, 10 + Math.random() * 15 ); 29 | var b = outer.size().$divide( 5 + Math.random() * 10, 10 + Math.random() * 15 ); 30 | var inner = new Pair( outer.$add( a ) ).to( outer.p1.$subtract( b ) ); 31 | 32 | this.inner.push( inner ); 33 | this.nest( inner ); 34 | }; 35 | 36 | Nest.prototype.init = function(id) { 37 | // 2-stop linear color gradient defined as a pair 38 | this.color = new Pair( Color.parseHex(colors["a"+id], true) ).to( Color.parseHex(colors["a"+(id+1)], true) ); 39 | 40 | this.nest( this ); 41 | return this; 42 | }; 43 | 44 | // draw nested pairs when space animates. 45 | Nest.prototype.animate = function(time, fps, context) { 46 | for (var i=0; i space.size.x || this.y < 0) { 38 | world.remove( this ); 39 | } 40 | }; 41 | 42 | // Particle use RK4 to integrate by default. Here we change it to Euler which is faster but less accurate. 43 | Speckle.prototype.integrate = function(t, dt) { 44 | return this.integrateEuler(t, dt); 45 | }; 46 | 47 | // calculate the forces 48 | Speckle.prototype.forces = function( state, t ) { 49 | var brownian = new Vector( (Math.random()-Math.random())/30, (Math.random()-Math.random())/30 ); // random 50 | var g = Particle.force_gravitation( state, t, this, mouse ); // mouse gravity 51 | return {force: brownian.add(g.force)}; 52 | }; 53 | 54 | 55 | //// 3. Visualize, Animate, Interact 56 | space.add({ 57 | animate: function(time, fps, context) { 58 | 59 | // fill background 60 | form.fill("rgba(0,0,0,0.05)"); 61 | form.rect( new Pair().to(space.size) ); 62 | 63 | // fill speckles 64 | form.fill( "rgba(255,255,200,.1)" ); 65 | 66 | // generate a new speckle every 25ms, remove when it's outside the space 67 | if (time-lastTime > 25 && world.particles.length<1000) { 68 | world.add( new Speckle(space.size.x/2, space.size.y/2) ); 69 | lastTime = time; 70 | } 71 | }, 72 | 73 | onMouseAction: function(type, x, y, evt) { 74 | if (type=="move") { 75 | mouse.set(x,y); 76 | } 77 | }, 78 | 79 | onTouchAction: function(type, x, y, evt) { 80 | this.onMouseAction( type, x, y ); 81 | } 82 | }); 83 | 84 | 85 | // 4. Start playing 86 | space.bindMouse(); 87 | space.bindTouch(); 88 | space.play(); -------------------------------------------------------------------------------- /demo/point.max.js: -------------------------------------------------------------------------------- 1 | //// 0. Describe this demo 2 | window.demoDescription = "A rectangular boundary is pinned by the minimum and maximum positions of a set of points. Move and click to change the points' positions."; 3 | 4 | 5 | //// 1. Define Space and Form 6 | var colors = { 7 | a1: "#ff2d5d", a2: "#42dc8e", a3: "#2e43eb", a4: "#ffe359", 8 | b1: "#96bfed", b2: "#f5ead6", b3: "#f1f3f7", b4: "#e2e6ef" 9 | } 10 | var space = new CanvasSpace("pt").setup( {bgcolor: "#222"} ); 11 | var form = new Form( space ); 12 | 13 | 14 | //// 2. Create Elements 15 | var pts = [ 16 | new Point( space.size.$divide(2) ), 17 | new Point( space.size.$divide(3) ), 18 | new Point( space.size.$divide(3).multiply(2) ) 19 | ]; 20 | var rect = new Rectangle( pts[1]).to( pts[2] ); 21 | var nextRect = new Rectangle( pts[1]).to( pts[2] ); 22 | 23 | 24 | // Calculate min and max points, and set the rectangular bound. 25 | function getMinMax() { 26 | var minPt = pts[0]; 27 | var maxPt = pts[0]; 28 | for (var i=1; i 5) { 68 | pts.splice(1, 1); 69 | } 70 | } 71 | }, 72 | 73 | onTouchAction: function(type, x, y, evt) { 74 | this.onMouseAction( type, x, y ); 75 | } 76 | }); 77 | 78 | 79 | // 4. Start playing 80 | space.bindMouse(); 81 | space.bindTouch(); 82 | space.play(); -------------------------------------------------------------------------------- /demo/point.quadrant.js: -------------------------------------------------------------------------------- 1 | //// 0. Describe this demo 2 | window.demoDescription = "Distribute points evenly on a surface. Check the quadrant of each point in relation to mouse position. Draw a corresponding corner for each point."; 3 | 4 | 5 | //// 1. Define Space and Form 6 | var colors = { 7 | a1: "#ff2d5d", a2: "#42dc8e", a3: "#2e43eb", a4: "#ffe359", 8 | b1: "#96bfed", b2: "#f5ead6", b3: "#f1f3f7", b4: "#e2e6ef", 9 | c1: "#111", c2: "#567", c3: "#abc", c4: "rgba(255,255,255,.9)" 10 | } 11 | var space = new CanvasSpace("pt").setup( {bgcolor: colors.c1} ); 12 | var form = new Form( space ); 13 | 14 | 15 | //// 2. Create Elements 16 | var pts = []; 17 | var mouseP = new Vector(); 18 | 19 | var gap = space.size.$subtract( 20, 20 ).divide( 10, 20 ); 20 | for (var i=0; i<=10; i++) { 21 | for (var j=0; j<=20; j++) { 22 | pts.push(new Vector( 10+gap.x*i, 10+gap.y*j)); 23 | } 24 | } 25 | 26 | // Get a line indicating the quadrant 27 | function cornerLine(p, quadrant, size) { 28 | 29 | switch (quadrant) { 30 | case Const.top_left: return new Pair(p).to(p.$add(size, size)); 31 | case Const.top_right: return new Pair(p).to(p.$add(-size, size)); 32 | case Const.bottom_left: return new Pair(p).to(p.$add(size, -size)); 33 | case Const.bottom_right: return new Pair(p).to(p.$add(-size, -size)); 34 | case Const.top: return new Pair(p).to(p.$add(0, size)); 35 | case Const.bottom: return new Pair(p).to(p.$add(0, -size)); 36 | case Const.left: return new Pair(p).to(p.$add(size, 0)); 37 | default: return new Pair(p).to(p.$add(-size, 0)); 38 | } 39 | }; 40 | 41 | // Draw the points 42 | function draw() { 43 | 44 | for (i=0; i lineSize) { 56 | 57 | pset.to( pt ); 58 | if (pset.points.length > 100) { 59 | pset.disconnect( 0 ); 60 | } 61 | 62 | last = pt; 63 | lineSize = Util.randomRange(20, 50); 64 | } 65 | } 66 | }, 67 | 68 | onTouchAction: function(type, x, y, evt) { 69 | this.onMouseAction( type, x, y ); 70 | } 71 | }); 72 | 73 | 74 | // 4. Start playing 75 | space.bindMouse(); 76 | space.bindTouch(); 77 | space.play(); -------------------------------------------------------------------------------- /demo/rectangle.enclose.js: -------------------------------------------------------------------------------- 1 | //// 0. Describe this demo 2 | window.demoDescription = "Draw pairs of rectangles, each of which contains a static original and a moving clone. Then draw a rectangle to enclose each pair, and draw intersection points between the moving clones."; 3 | 4 | 5 | //// 1. Define Space and Form 6 | var colors = { 7 | a1: "#ff2d5d", a2: "#42dc8e", a3: "#2e43eb", a4: "#ffe359", 8 | b1: "#96bfed", b2: "#f5ead6", b3: "#f1f3f7", b4: "#e2e6ef" 9 | }; 10 | var space = new CanvasSpace("pt").setup( {bgcolor: colors.b4} ); 11 | var form = new Form( space ); 12 | 13 | 14 | //// 2. Create Elements 15 | var unit = space.size.$divide(20); 16 | var mouse = new Vector( space.size.x/2, space.size.y/1.35); 17 | 18 | var rects = [ 19 | new Rectangle( unit.$multiply(2) ).to( unit.$multiply(12,5) ), 20 | new Rectangle( unit.$multiply(15, 1) ).to( unit.$multiply(18,8) ), 21 | new Rectangle( unit.$multiply(3, 7) ).to( unit.$multiply(6,9) ), 22 | new Rectangle( unit.$multiply(2, 10) ).to( unit.$multiply(6,14) ), 23 | new Rectangle( unit.$multiply(8, 7) ).to( unit.$multiply(13,11) ), 24 | new Rectangle( unit.$multiply(10, 12) ).to( unit.$multiply(16,15) ), 25 | new Rectangle( unit.$multiply(17, 10) ).to( unit.$multiply(19,12) ), 26 | new Rectangle( unit.$multiply(5, 16) ).to( unit.$multiply(18,18) ) 27 | ]; 28 | 29 | 30 | //// 3. Visualize, Animate, Interact 31 | space.add({ 32 | animate: function(time, fps, context) { 33 | 34 | var mag = mouse.distance( space.size.$divide(2) ); 35 | var d1 = mouse.$subtract( space.size.$divide(2) ).divide(10); 36 | var shadows = []; 37 | 38 | // calculate rect's "shadow" 39 | for (var i=0; i 0) form.fill( colors.a3 ).points( intersects, 3, true ); 57 | } 58 | } 59 | } 60 | 61 | // draw rects on top 62 | for (i=0; i 100) paths.shift(); // remove old lines 25 | 26 | // draw inner lines in rectangle by checking path intersection with mouse line 27 | form.fill(false ); 28 | for (var i=0; i= 2) { 31 | form.stroke( "rgba(255,255,255," + Math.max( 0.05, i / paths.length) + ")", ((i % 10) / 10 + 0.5) ); // dynamic stroke color and width 32 | form.line( new Line( ps[0] ).to( ps[1] ) ); 33 | } 34 | } 35 | form.stroke(colors.a4,2).line( mouseLine ); 36 | form.stroke(false).fill(colors.a4).point( mouseLine.p1, 3, true ) 37 | }, 38 | 39 | onMouseAction: function(type, x, y, evt) { 40 | if (type=="move") { 41 | if (paths.length < 1000) { 42 | mouseLine = new Line( space.size.$divide( 2 ) ).to( x, y ); 43 | paths.push( mouseLine ); 44 | } 45 | } 46 | }, 47 | 48 | onTouchAction: function(type, x, y, evt) { 49 | this.onMouseAction( type, x, y ); 50 | } 51 | }); 52 | 53 | 54 | // 4. Start playing 55 | space.bindMouse(); 56 | space.bindTouch(); 57 | space.play(); -------------------------------------------------------------------------------- /demo/rectangle.resizeCenterTo.js: -------------------------------------------------------------------------------- 1 | //// 0. Describe this demo 2 | window.demoDescription = "In a grid of rectangles, resize each one based on its distance as well as x y differences from the mouse position."; 3 | 4 | 5 | //// 1. Define Space and Form 6 | var colors = { 7 | a1: "#ff2d5d", a2: "#42dc8e", a3: "#2e43eb", a4: "#ffe359", 8 | b1: "#96bfed", b2: "#f5ead6", b3: "#f1f3f7", b4: "#e2e6ef" 9 | }; 10 | var space = new CanvasSpace("pt").setup( {bgcolor: colors.b4} ); 11 | var form = new Form( space ); 12 | form.stroke( false ); 13 | 14 | //// 2. Create Elements 15 | var rects = []; 16 | var mouse = new Vector(); 17 | var steps = 10; 18 | var gap = space.size.$subtract( 100, 100 ).divide( steps, steps*2 ); 19 | 20 | // create grid of rectangles 21 | for (var i=0; i<=steps; i++) { 22 | for (var j=0; j<=(steps*2); j++) { 23 | var rect = new Rectangle().to( 10, 10 ); 24 | rect.moveTo( 50 - 5.5 + gap.x * i, 50 - 5.5 + gap.y * j ); 25 | rect.setCenter(); 26 | rects.push( rect ); 27 | } 28 | } 29 | 30 | 31 | //// 3. Visualize, Animate, Interact 32 | space.add({ 33 | animate: function(time, fps, context) { 34 | for (var i=0; i 0.7) ? colors["a"+Math.ceil(Math.random()*4)] : "#000"; 27 | } 28 | Util.extend( Dust, Vector ); // extends Vector class 29 | 30 | 31 | // define an animate function so it can be animated when added into Space 32 | Dust.prototype.animate = function(time, fps, context) { 33 | 34 | // drift movement 35 | this.add( rand(1), (Math.random() - Math.random()*(1-this.weight/1.5)) ); 36 | 37 | // remove when done 38 | if (this.age++ > this.maxAge) space.remove(this); 39 | 40 | // glitter 41 | var gray = (this.maxAge-this.age)/this.maxAge * 0.4; 42 | gray = Math.max(0, Math.min( 0.6, (Math.random() > 0.5) ? gray + 0.05 : gray - 0.05 ) ); 43 | 44 | // draw dust 45 | form.fill( Util.toRGBColor( this.color, true, gray ) ); 46 | form.point( this, this.weight, true ); 47 | 48 | }; 49 | 50 | // a helper function for randomness 51 | function rand(r) { return Math.random() * r - Math.random() * r; } 52 | 53 | 54 | //// 3. Visualize, Animate, Interact 55 | space.add({ 56 | animate: function(time, fps, context) {}, 57 | 58 | onMouseAction: function(type, x, y, evt) { 59 | // When mouse moved, add two dust into space 60 | if (type=="move") { 61 | space.add( new Dust( x+rand(5), y+rand(5) ) ); 62 | space.add( new Dust( x+rand(5), y+rand(5) ) ); 63 | } 64 | }, 65 | 66 | onTouchAction: function(type, x, y, evt) { 67 | this.onMouseAction( type, x, y ); 68 | } 69 | }); 70 | 71 | // 4. Start playing 72 | space.bindMouse(); 73 | space.bindTouch(); 74 | space.play(); -------------------------------------------------------------------------------- /demo/space.refresh.js: -------------------------------------------------------------------------------- 1 | //// 0. Describe this demo 2 | window.demoDescription = "A point spins around the mouse position. As it moves, it traces out a line. Move the mouse very fast to break the continuous line."; 3 | 4 | 5 | //// 1. Define Space and Form 6 | var colors = { 7 | a1: "#ff2d5d", a2: "#42dc8e", a3: "#2e43eb", a4: "#ffe359", 8 | b1: "#96bfed", b2: "#f5ead6", b3: "#f1f3f7", b4: "#e2e6ef" 9 | }; 10 | var space = new CanvasSpace("pt").setup( {bgcolor: colors.a2} ); 11 | var form = new Form( space ); 12 | 13 | space.clear(); // fill background once and then no more repaint 14 | space.refresh(false); 15 | form.fill( false ); // no fill by default 16 | 17 | 18 | //// 2. Create Elements 19 | var ang = 0; 20 | var noise = 0; 21 | var mouse = new Vector(space.size.x/2, space.size.y/2); 22 | var lastPos = mouse.clone(); 23 | 24 | function spin() { 25 | // angles and radius 26 | ang += Const.one_degree * 2 * Math.random(); 27 | noise += Const.one_degree * Math.random()*10 - Const.one_degree * Math.random()*7; 28 | var r = 50 * Math.sin(noise); 29 | 30 | // next point 31 | var p = new Vector( Math.cos(ang)*r, Math.sin(ang)*r ); 32 | p.add(mouse); 33 | 34 | // break or continue drawing the line 35 | if (p.$subtract(lastPos).magnitude() < 20 ) { 36 | form.stroke( "rgba(255,255,255,.4)" ); 37 | form.line( new Pair(lastPos).to( p ) ); 38 | } 39 | 40 | lastPos.set( p ); 41 | } 42 | 43 | 44 | //// 3. Visualize, Animate, Interact 45 | space.add({ 46 | 47 | animate: function(time, fps, context) { 48 | spin(); 49 | }, 50 | 51 | onMouseAction: function(type, x, y, evt) { 52 | if (type === "move") { 53 | mouse.set(x, y); 54 | } 55 | }, 56 | 57 | onTouchAction: function(type, x, y, evt) { 58 | this.onMouseAction( type, x, y ); 59 | } 60 | }); 61 | 62 | 63 | // 4. Start playing 64 | space.bindMouse(); 65 | space.bindTouch(); 66 | space.play(); -------------------------------------------------------------------------------- /demo/svgform.circle.js: -------------------------------------------------------------------------------- 1 | //// 0. Describe this demo 2 | window.demoDescription = "Particle demo in SVG, with minimal change from the canvas version."; 3 | 4 | 5 | //// 1. Define Space and Form 6 | var colors = { 7 | a1: "#ff2d5d", a2: "#42dc8e", a3: "#2e43eb", a4: "#ffe359", 8 | b1: "#96bfed", b2: "#f5ead6", b3: "#f1f3f7", b4: "#e2e6ef" 9 | }; 10 | var space = new SVGSpace("pt", ready).setup({bgcolor: "#223"}); 11 | var form = new SVGForm( space ); 12 | 13 | 14 | //// 2. Create Elements 15 | 16 | var wall = new Line( space.size.$multiply( 0.33, 0.33)).to( space.size.$multiply(0.66, 0.66) ); 17 | var bound = new Pair().to( space.size ); 18 | 19 | // A Ball is a kind of Particle 20 | function Ball() { 21 | Particle.apply( this, arguments ); 22 | } 23 | Util.extend( Ball, Particle ); 24 | 25 | // animate this ball 26 | Ball.prototype.animate = function( time, frame, ctx ) { 27 | form.enterScope(this); // Distinguish each ball's scope (id attribute prefix) 28 | this.play(time, frame); 29 | form.stroke( false).fill(this.color); 30 | form.point( this, this.radius, true); 31 | }; 32 | 33 | // Particle use RK4 to integrate by default. Here we change it to Euler which is faster but less accurate. 34 | Ball.prototype.integrate = function(t, dt) { 35 | this.integrateEuler(t, dt); 36 | 37 | // check collision with other balls 38 | for (var i=0; i 56 | form.fill( false ).stroke( "#666" ); 57 | form.curve( new Curve().to(pts).catmullRom() ); 58 | 59 | 60 | form.fill("#abc").stroke(false); 61 | form.font(60, "Times New Roman"); 62 | form.text( mouse, mouse.x+", "+mouse.y ); 63 | }, 64 | 65 | onMouseAction: function(type, x, y, evt) { 66 | if (type=="move") { 67 | mouse.set(x,y); 68 | } 69 | }, 70 | 71 | onTouchAction: function(type, x, y, evt) { 72 | this.onMouseAction( type, x, y ); 73 | } 74 | }); 75 | 76 | 77 | // 4. Start playing 78 | // Here we need to make sure the svg dom is ready first, via callback function (see constructor SVGSpace(...)) 79 | function ready(bounds, elem) { 80 | form.scope("item", elem ); // initiate the scope which uses the svg dom as parent node 81 | space.bindMouse(); 82 | space.bindTouch(); 83 | space.play(); 84 | } -------------------------------------------------------------------------------- /demo/svgspace.remove.js: -------------------------------------------------------------------------------- 1 | //// 0. Describe this demo 2 | window.demoDescription = "Adding and removing circles in svg. Notice the rendering performance is much slower than html5 canvas."; 3 | 4 | 5 | //// 1. Define Space and Form 6 | var colors = { 7 | a1: "#ff2d5d", a2: "#42dc8e", a3: "#2e43eb", a4: "#ffe359", 8 | b1: "#96bfed", b2: "#f5ead6", b3: "#f1f3f7", b4: "#e2e6ef", 9 | c1: "#111", c2: "#567", c3: "#abc", c4: "rgba(255,255,255,.9)" 10 | }; 11 | 12 | var space = new SVGSpace("pt", ready).setup({bgcolor: colors.b2}); 13 | 14 | var form = new SVGForm( space ); 15 | form.stroke( false ); 16 | 17 | 18 | //// 2. Create Elements 19 | 20 | // A Dust is a kind of Vector 21 | function Dust() { 22 | Vector.apply( this, arguments ); // call Vector's constructor 23 | this.age = 0; 24 | this.maxAge = Math.random() * 500 + 50; 25 | this.weight = 0.25 + Math.random()*3; 26 | this.color = (this.weight > 0.7) ? colors["a"+Math.ceil(Math.random()*4)] : "#000"; 27 | } 28 | Util.extend( Dust, Vector ); // extends Vector class 29 | 30 | 31 | // define an animate function so it can be animated when added into Space 32 | Dust.prototype.animate = function(time, fps, context) { 33 | 34 | form.enterScope(this); 35 | 36 | // drift movement 37 | this.add( rand(1), (Math.random() - Math.random()*(1-this.weight/1.5)) ); 38 | 39 | // glitter 40 | var gray = (this.maxAge-this.age)/this.maxAge * 0.4; 41 | gray = Math.max(0, Math.min( 0.6, (Math.random() > 0.5) ? gray + 0.05 : gray - 0.05 ) ); 42 | 43 | // draw dust 44 | form.fill( Util.toRGBColor( this.color, true, gray ) ); 45 | form.point( this, this.weight, true ); 46 | 47 | // remove when done 48 | if (this.age++ > this.maxAge) space.remove(this); 49 | 50 | }; 51 | 52 | // a helper function for randomness 53 | function rand(r) { return Math.random() * r - Math.random() * r; } 54 | 55 | 56 | //// 3. Visualize, Animate, Interact 57 | space.add({ 58 | animate: function(time, fps, context) {}, 59 | 60 | onMouseAction: function(type, x, y, evt) { 61 | // When mouse moved, add two dust into space 62 | if (type=="move") { 63 | space.add( new Dust( x+rand(5), y+rand(5) ) ); 64 | space.add( new Dust( x+rand(5), y+rand(5) ) ); 65 | } 66 | }, 67 | 68 | onTouchAction: function(type, x, y, evt) { 69 | this.onMouseAction( type, x, y ); 70 | } 71 | }); 72 | 73 | 74 | // 4. Start playing 75 | // Here we need to make sure the svg dom is ready first, via callback function ( see constructor SVGSpace(...) ) 76 | function ready(bounds, elem) { 77 | form.scope("item", elem ); // initiate the scope which uses the svg dom as parent node 78 | space.bindMouse(); 79 | space.bindTouch(); 80 | space.play(); 81 | } -------------------------------------------------------------------------------- /demo/triangle.incenter.js: -------------------------------------------------------------------------------- 1 | //// 0. Describe this demo 2 | window.demoDescription = "Draw a triangle's inner and outer circles, and animate their changes when triangle's points change. Click to change a triangle's vertex position"; 3 | 4 | 5 | //// 1. Define Space and Form 6 | var colors = { 7 | a1: "#ff2d5d", a2: "#42dc8e", a3: "#2e43eb", a4: "#ffe359", 8 | b1: "#96bfed", b2: "#f5ead6", b3: "#f1f3f7", b4: "#e2e6ef" 9 | }; 10 | var space = new CanvasSpace("pt").setup( {bgcolor: colors.b4} ); 11 | var form = new Form( space ); 12 | form.stroke( false ); 13 | 14 | 15 | //// 2. Create Elements 16 | var center = space.size.$divide(2); 17 | var unit = space.size.$divide(20); 18 | unit = Math.min(unit.x, unit.y); 19 | var triangle = new Triangle( center.$subtract(0, unit*5) ) .to( center.$add( -unit*5, unit*2), center.$add( unit*5, unit*5) ) 20 | var target = {vec: null, t: 1, p: 0}; 21 | 22 | var pointSelect = 0; 23 | var timeInc = 0; 24 | 25 | // move a triangle's point to new position 26 | function setTarget(p) { 27 | if (!p) p = space.size.$multiply( Math.random(), Math.random() ); 28 | timeInc++; 29 | target.p++; 30 | target.t = 0; 31 | target.vec = p; 32 | } 33 | 34 | //// 3. Visualize, Animate, Interact 35 | space.add( { 36 | animate: function ( time, fps, context ) { 37 | 38 | // outer circle and first triangle 39 | form.stroke( false ).fill( "#fff" ).circle( triangle.circumcircle() ); 40 | form.fill( colors.a4 ).triangle( triangle ); 41 | 42 | // inner triangle 43 | var inner = triangle.medial(); 44 | form.fill( "#fff" ).triangle( inner ); 45 | 46 | // transition point to new position if needed. 47 | if (target.t < 1) { 48 | target.t += 0.01; 49 | var p = triangle.getAt( target.p % 3 ); 50 | p.set( new Pair( p ).to( target.vec ).interpolate( target.t ) ); 51 | 52 | } else if (time / 3000 > timeInc) { // every 3 seconds, make a switch 53 | setTarget(); 54 | } 55 | 56 | // draw inner triangle's inner and outer circles 57 | form.stroke( "rgba(255,45,93,.5)", 20 ).fill( false ).circle( inner.circumcircle() ); 58 | form.fill( colors.a3 ).stroke( false ).circle( inner.incircle() ); 59 | 60 | }, 61 | 62 | // on click, move a point to the mouse position 63 | onMouseAction: function ( type, x, y, evt ) { 64 | if (type == "up") { 65 | setTarget( new Vector( x, y ) ); 66 | } 67 | }, 68 | 69 | onTouchAction: function(type, x, y, evt) { 70 | this.onMouseAction( type, x, y ); 71 | } 72 | }); 73 | 74 | 75 | // 4. Start playing 76 | space.bindMouse(); 77 | space.bindTouch(); 78 | space.play(); -------------------------------------------------------------------------------- /demo/vector.add.js: -------------------------------------------------------------------------------- 1 | //// 0. Describe this demo 2 | window.demoDescription = "3 vectors originate from center, and one of them follows the mouse position. Calculate the vector additions and subtractions between them."; 3 | 4 | 5 | //// 1. Define Space and Form 6 | var colors = { 7 | a1: "#ff2d5d", a2: "#42dc8e", a3: "#2e43eb", a4: "#ffe359", 8 | b1: "#96bfed", b2: "#f5ead6", b3: "#f1f3f7", b4: "#e2e6ef" 9 | } 10 | var space = new CanvasSpace("pt").setup( {bgcolor: colors.b4} ); 11 | var form = new Form( space ); 12 | 13 | 14 | //// 2. Create Elements 15 | var center = new Vector(space.size.$divide(2)); 16 | var mouse = new Vector( space.size.x/2, space.size.y/1.35); 17 | var vec1 = new Vector( -space.size.x/4.2, -space.size.y/5.7 ); 18 | var vec2 = new Vector( space.size.x/3.2, -space.size.y/7.5 ); 19 | 20 | 21 | //// 3. Visualize, Animate, Interact 22 | space.add({ 23 | animate: function(time, fps, context) { 24 | 25 | form.stroke("#9ab"); 26 | 27 | // mouse vector. Gray line. 28 | var mouseVec = mouse.$subtract( center ); 29 | form.line( new Line( center ).to( mouseVec.$add( center ) ) ); 30 | 31 | form.stroke("#fff"); 32 | 33 | // Two fixed vectors vec1 and vec2, connected to center as blue lines. 34 | form.stroke( colors.b1, 2 ); 35 | form.line( new Line( center ).to( vec1.$add( center ) ) ); 36 | form.line( new Line( center ).to( vec2.$add( center ) ) ); 37 | 38 | // vector addition between mouse vector and vec1/vec1, and then connect to center as red line. 39 | form.stroke( colors.a1 ); 40 | var add1 = vec1.$add( mouseVec ); 41 | form.line( new Line( center ).to( add1.$add( center ) ) ); 42 | var add2 = vec2.$add( mouseVec ); 43 | form.line( new Line( center ).to( add2.$add( center ) ) ); 44 | 45 | // vector subtraction between mouse vector and vec1/vec1, and then connect to center as green line. 46 | form.stroke( colors.a2 ); 47 | var sub1 = vec1.$subtract( mouseVec ); 48 | var subline1 = new Line( center ).to( sub1.$add( center ) ); 49 | form.line( subline1 ); 50 | var sub2 = vec2.$subtract( mouseVec ); 51 | var subline2 = new Line( center ).to( sub2.$add( center ) ); 52 | form.line( subline2 ); 53 | 54 | // add the subtracted vectors to mouse position instead of to center. White lines. 55 | form.stroke( colors.b3, 1 ); 56 | var sub3 = vec1.$subtract( mouseVec ); 57 | var subline3 = new Line( mouse ).to( sub3.$add( mouse ) ); 58 | form.line( subline3 ); 59 | var sub4 = vec2.$subtract( mouseVec ); 60 | var subline4 = new Line( mouse ).to( sub4.$add( mouse ) ); 61 | form.line( subline4 ); 62 | 63 | // Draw mouse 64 | form.fill( colors.a1).stroke(false); 65 | form.point( mouse, 5, true ); 66 | 67 | }, 68 | 69 | onMouseAction: function(type, x, y, evt) { 70 | if (type=="move") { 71 | mouse.set(x,y); 72 | } 73 | }, 74 | 75 | onTouchAction: function(type, x, y, evt) { 76 | this.onMouseAction( type, x, y ); 77 | } 78 | }); 79 | 80 | 81 | // 4. Start playing 82 | space.bindMouse(); 83 | space.bindTouch(); 84 | space.play(); -------------------------------------------------------------------------------- /demo/vector.normalize.js: -------------------------------------------------------------------------------- 1 | //// 0. Describe this demo 2 | window.demoDescription = "Normalize the vector from center to mouse position. Use its direction to set a grid of vectors in various sizes."; 3 | 4 | 5 | //// 1. Define Space and Form 6 | var colors = { 7 | a1: "#ff2d5d", a2: "#42dc8e", a3: "#2e43eb", a4: "#ffe359", 8 | b1: "#96bfed", b2: "#f5ead6", b3: "#f1f3f7", b4: "#e2e6ef" 9 | }; 10 | var space = new CanvasSpace("pt").setup( {bgcolor: "#222"} ); 11 | var form = new Form( space ); 12 | 13 | 14 | //// 2. Create Elements 15 | var center = new Vector(space.size.$divide(2)); 16 | var mouse = new Vector( space.size.x/2, space.size.y/1.35); 17 | var spaceSize = space.size.magnitude()/2; 18 | 19 | // define a grid of vectors 20 | var gap = space.size.$subtract( 20, 20 ).divide( 10, 20 ); 21 | var vecs = []; 22 | for (var i=0; i<=10; i++) { 23 | for (var j = 0; j <= 20; j++) { 24 | vecs.push( new Vector( 10 + gap.x * i, 10 + gap.y * j ) ); 25 | } 26 | } 27 | 28 | 29 | //// 3. Visualize, Animate, Interact 30 | space.add({ 31 | animate: function(time, fps, context) { 32 | 33 | // calculate the normalized vector from center to mouse position 34 | var direction = mouse.$subtract( center).normalize(); 35 | form.stroke( colors.a4 ); 36 | form.line( new Line( center ).to( mouse ) ); 37 | 38 | // draw a grid of vectors, whose direction follows the mouse and magnitude is related to its position from center. 39 | form.stroke( "#fff" ); 40 | for (var i=0; i 0) ? 1 : -1; 34 | var a = Math.abs( Util.boundRadian( (mouse.y-center.y) / (space.size.y/2) ) * 4 ) * dir; 35 | var last = { vec: center, size: 2, angle: a }; 36 | 37 | for (var i=0; i<200; i++) { 38 | 39 | var c = colors["a"+(i%4 + 1)]; 40 | form.stroke( c, 40 * (300-i)/200 ); 41 | 42 | var next = nextVector( i, last.angle, last.size ); 43 | next.vec.add( last.vec ); 44 | 45 | // rotate around mouse position as anchor, if rotateAroundMouse is true 46 | if (rotateAroundMouse) { next.vec.rotate2D( next.angle/80, mouse ); } 47 | 48 | form.line( new Line( last.vec ).to( next.vec) ); 49 | last = next; 50 | } 51 | 52 | // rotate a dot around mouse point 53 | dot.rotate2D( Const.one_degree, mouse ); 54 | if (dot.distance(mouse) > 5) dot.add( mouse.$subtract(dot).divide(100) ); 55 | form.fill("#222").stroke("#fff"); 56 | 57 | form.point( dot, 5, true ); 58 | 59 | }, 60 | 61 | onMouseAction: function(type, x, y, evt) { 62 | if (type=="move") { 63 | mouse.set(x,y); 64 | } else if (type=="up") { 65 | rotateAroundMouse = !rotateAroundMouse; 66 | } 67 | }, 68 | 69 | onTouchAction: function(type, x, y, evt) { 70 | this.onMouseAction( type, x, y ); 71 | } 72 | }); 73 | 74 | 75 | // 4. Start playing 76 | space.bindMouse(); 77 | space.bindTouch(); 78 | space.play(); -------------------------------------------------------------------------------- /demo/vector.scale2D.js: -------------------------------------------------------------------------------- 1 | //// 0. Describe this demo 2 | window.demoDescription = "Scale a series of points on a path from an anchor, and get its reflection from other path. Connect each point and its reflected point with a line."; 3 | 4 | //// 1. Define Space and Form 5 | var colors = { 6 | a1: "#ff2d5d", a2: "#42dc8e", a3: "#2e43eb", a4: "#ffe359", 7 | b1: "#96bfed", b2: "#f5ead6", b3: "#f1f3f7", b4: "#e2e6ef" 8 | }; 9 | var space = new CanvasSpace("pt").setup( {bgcolor: colors.b2} ); 10 | var form = new Form( space ); 11 | 12 | 13 | //// 2. Create Elements 14 | var path = new Line().to( space.size ); 15 | var path2 = new Line( space.size.$multiply(0.9, 0) ).to( space.size.$multiply(0, 0.9) ); 16 | var mouse = new Vector( space.size.$divide(2) ); 17 | var spaceSize = space.size.magnitude(); 18 | 19 | //// 3. Visualize, Animate, Interact 20 | space.add({ 21 | animate: function(time, fps, context) { 22 | 23 | form.stroke("rgba(255,255,255,.7)", 10); 24 | form.lines( [path, path2] ); 25 | 26 | var normal = path.getPerpendicularFromPoint( mouse ); 27 | var normalSize = normal.$subtract(mouse).magnitude() / (spaceSize/4); 28 | 29 | var normal2 = path2.getPerpendicularFromPoint( mouse ); 30 | var normalSize2 = normal2.$subtract(mouse).magnitude() / (spaceSize/4); 31 | var num = 15; 32 | 33 | // 15 points evenly distributed on path 34 | for (var i=1; i\r\n\r\n # ## a property to store particles in this system as an Array\r\n @count = 0\r\n @particles = []\r\n\r\n # ## a property to track time in milliseconds\r\n @time = 0\r\n\r\n # @animateID = -1\r\n\r\n\r\n # ## add a particle to the system\r\n # @param `particle` a Particle\r\n # @return this system\r\n add : ( particle ) ->\r\n particle.id = @count++\r\n @particles.push( particle )\r\n return @\r\n\r\n\r\n # ## remove a particle which has a `particle.life` property. This marks the `particle.life.complete` as `true` for removal in next cycle.\r\n # @param `particle` a Particle\r\n # @return this system\r\n remove: (particle) ->\r\n if particle and particle.life then particle.life.complete = true\r\n return @\r\n\r\n\r\n # ## animate callback function which is called by` Space.play()`. Override this callback function to specify other animation loops\r\n # @param `time, frame, ctx` parameters for current time, fps, and rendering context, which will be passed by `Space` in callback\r\n animate : ( time, frame, ctx ) ->\r\n @time++\r\n\r\n _remove = []; # to be removed\r\n\r\n for p, i in @particles\r\n\r\n # if life is complete, mark for removal\r\n if p.life.complete\r\n _remove.push( i )\r\n\r\n # if active, animate it\r\n else if p.life.active\r\n p.animate( time, frame, ctx )\r\n\r\n # remove completed particles\r\n if _remove.length > 0\r\n for index in _remove\r\n @particles.splice(index, 1)\r\n\r\n\r\n\r\n# namespace\r\nthis.ParticleSystem = ParticleSystem\r\n\r\n"]} -------------------------------------------------------------------------------- /dist/core/elements/.map/Timer.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["Timer.coffee"],"names":[],"mappings":"AACA,IAAA;;AAAM;EAIS,eAAE,CAAF;;MAAE,IAAE;;IACf,IAAC,CAAA,QAAD,GAAY;IACZ,IAAC,CAAA,KAAD,GAAS;IACT,IAAC,CAAA,KAAD,GAAS,SAAC,CAAD,EAAG,CAAH,EAAK,CAAL,EAAO,CAAP;aAAa,CAAA,GAAE;IAAf;IACT,IAAC,CAAA,WAAD,GAAe,CAAC;EAJL;;kBASb,KAAA,GAAO,SAAC,KAAD;AACL,QAAA;IAAA,IAAA,GAAO,IAAI,CAAC,GAAL,CAAU,IAAI,CAAC,GAAL,CAAA,CAAA,GAAa,IAAC,CAAA,KAAxB,EAA+B,IAAC,CAAA,QAAhC;IAEP,IAAG,KAAA,IAAS,IAAA,IAAQ,IAAC,CAAA,QAArB;aACE,IAAC,CAAA,KAAD,GAAS,IAAI,CAAC,GAAL,CAAA,EADX;;EAHK;;kBASP,SAAA,GAAW,SAAC,IAAD;WACT,IAAC,CAAA,KAAD,GAAS;EADA;;kBAMX,KAAA,GAAO,SAAA;AACL,QAAA;IAAA,IAAA,GAAO,IAAI,CAAC,GAAL,CAAU,IAAI,CAAC,GAAL,CAAA,CAAA,GAAa,IAAC,CAAA,KAAxB,EAA+B,IAAC,CAAA,QAAhC;AACP,WAAO,IAAC,CAAA,KAAD,CAAQ,IAAR,EAAc,CAAd,EAAiB,CAAjB,EAAoB,IAAC,CAAA,QAArB;EAFF;;kBAQP,KAAA,GAAO,SAAE,QAAF;AACL,QAAA;IAAA,aAAA,CAAe,IAAC,CAAA,WAAhB;IACA,IAAC,CAAA,KAAD,CAAO,IAAP;IACA,EAAA,GAAK;IACL,IAAC,CAAA,WAAD,GAAe,WAAA,CAAa,CAAE,SAAA;AAC5B,UAAA;MAAA,CAAA,GAAI,EAAE,CAAC,KAAH,CAAA;MACJ,QAAA,CAAU,CAAV;MACA,IAAG,CAAA,IAAK,CAAR;eAAe,aAAA,CAAe,EAAE,CAAC,WAAlB,EAAf;;IAH4B,CAAF,CAAb,EAIZ,EAJY;AAKf,WAAO,IAAC,CAAA;EATH;;;;;;AAcT,IAAI,CAAC,KAAL,GAAa","file":"Timer.js","sourceRoot":"/source/","sourcesContent":["# ### Use a timer not to measure time, but to introduce rhythm. The conceptual hums of \"one two three, one two three\", when transfigured into patterns of sounds or words or dances, gives rise to various forms of aesthetic experiences. If time is a river, then timers are the mills we build along its banks.\r\nclass Timer\r\n\r\n # ## Create a Timer\r\n # @param `d` duration of the timer in milliseconds\r\n constructor: ( d=1000 ) ->\r\n @duration = d\r\n @_time = 0\r\n @_ease = (t,b,c,d) -> t/d\r\n @_intervalID = -1\r\n\r\n\r\n # ## Start or restart the timer\r\n # @param `reset` a boolean value to restart the timer from the beginning if set to `true`.\r\n start: (reset) ->\r\n diff = Math.min( Date.now() - @_time, @duration)\r\n\r\n if reset or diff >= @duration\r\n @_time = Date.now()\r\n\r\n\r\n # set an easing function to use in `check()`. See `Easing` class for a set of predefined easing functions\r\n # @param `ease` an easing function with 4 parameters `(current_time, start_value, change_in_value, duration_time)` and must return a number between 0 to 1\r\n setEasing: (ease) ->\r\n @_ease = ease\r\n\r\n\r\n # ## Check % of time that has elapsed currently.\r\n # @return a number between 0 to 1\r\n check: () ->\r\n diff = Math.min( Date.now() - @_time, @duration)\r\n return @_ease( diff, 0, 1, @duration )\r\n\r\n\r\n # Track time (using `setInterval()`)\r\n # @param `callback` a callback function which may include a `(t)` parameter to get current elapsed percentage (value between 0 to 1)\r\n # @return the intervalID from `setInterval()`\r\n track: ( callback ) ->\r\n clearInterval( @_intervalID )\r\n @start(true)\r\n me = @\r\n @_intervalID = setInterval( ( () ->\r\n t = me.check()\r\n callback( t )\r\n if t >= 1 then clearInterval( me._intervalID )\r\n ), 25 )\r\n return @_intervalID\r\n\r\n\r\n\r\n# namespace\r\nthis.Timer = Timer"]} -------------------------------------------------------------------------------- /dist/core/elements/Const.js: -------------------------------------------------------------------------------- 1 | var Const; 2 | 3 | Const = (function() { 4 | function Const() {} 5 | 6 | Const.xy = 'xy'; 7 | 8 | Const.yz = 'yz'; 9 | 10 | Const.xz = 'xz'; 11 | 12 | Const.xyz = 'xyz'; 13 | 14 | Const.identical = -1; 15 | 16 | Const.right = 3; 17 | 18 | Const.bottom_right = 4; 19 | 20 | Const.bottom = 5; 21 | 22 | Const.bottom_left = 6; 23 | 24 | Const.left = 7; 25 | 26 | Const.top_left = 0; 27 | 28 | Const.top = 1; 29 | 30 | Const.top_right = 2; 31 | 32 | Const.sideLabels = ["identical", "right", "bottom right", "bottom", "bottom left", "left", "top left", "top", "top right"]; 33 | 34 | Const.epsilon = 0.0001; 35 | 36 | Const.pi = Math.PI; 37 | 38 | Const.two_pi = 6.283185307179586; 39 | 40 | Const.half_pi = 1.5707963267948966; 41 | 42 | Const.quarter_pi = 0.7853981633974483; 43 | 44 | Const.one_degree = 0.017453292519943295; 45 | 46 | Const.rad_to_deg = 57.29577951308232; 47 | 48 | Const.deg_to_rad = 0.017453292519943295; 49 | 50 | Const.gravity = 9.81; 51 | 52 | Const.newton = 0.10197; 53 | 54 | Const.gaussian = 0.3989422804014327; 55 | 56 | return Const; 57 | 58 | })(); 59 | 60 | this.Const = Const; 61 | 62 | //# sourceMappingURL=.map/Const.js.map -------------------------------------------------------------------------------- /dist/core/elements/Matrix.js: -------------------------------------------------------------------------------- 1 | var Matrix; 2 | 3 | Matrix = (function() { 4 | function Matrix() {} 5 | 6 | Matrix.rotateAnchor2D = function(radian, anchor, axis) { 7 | var a, cosA, sinA; 8 | if (axis == null) { 9 | axis = Const.xy; 10 | } 11 | a = anchor.get2D(axis); 12 | cosA = Math.cos(radian); 13 | sinA = Math.sin(radian); 14 | return [cosA, sinA, 0, -sinA, cosA, 0, a.x * (1 - cosA) + a.y * sinA, a.y * (1 - cosA) - a.x * sinA, 1]; 15 | }; 16 | 17 | Matrix.reflectAnchor2D = function(line, axis) { 18 | var ang2, cosA, inc, sinA; 19 | if (axis == null) { 20 | axis = Const.xy; 21 | } 22 | inc = line.intercept(axis); 23 | ang2 = Math.atan(inc.slope) * 2; 24 | cosA = Math.cos(ang2); 25 | sinA = Math.sin(ang2); 26 | return [cosA, sinA, 0, sinA, -cosA, 0, -inc.yi * sinA, inc.yi + inc.yi * cosA, 1]; 27 | }; 28 | 29 | Matrix.shearAnchor2D = function(sx, sy, anchor, axis) { 30 | var a, tx, ty; 31 | if (axis == null) { 32 | axis = Const.xy; 33 | } 34 | a = anchor.get2D(axis); 35 | tx = Math.tan(sx); 36 | ty = Math.tan(sy); 37 | return [1, tx, 0, ty, 1, 0, -a.y * ty, -a.x * tx, 1]; 38 | }; 39 | 40 | Matrix.scaleAnchor2D = function(sx, sy, anchor, axis) { 41 | var a; 42 | if (axis == null) { 43 | axis = Const.xy; 44 | } 45 | a = anchor.get2D(axis); 46 | return [sx, 0, 0, 0, sy, 0, -a.x * sx + a.x, -a.y * sy + a.y, 1]; 47 | }; 48 | 49 | Matrix.scale2D = function(x, y) { 50 | return [x, 0, 0, 0, y, 0, 0, 0, 1]; 51 | }; 52 | 53 | Matrix.shear2D = function(x, y) { 54 | return [1, Math.tan(x), 0, Math.tan(y), 1, 0, 0, 0, 1]; 55 | }; 56 | 57 | Matrix.rotate2D = function(cosA, sinA) { 58 | return [cosA, sinA, 0, -sinA, cosA, 0, 0, 0, 1]; 59 | }; 60 | 61 | Matrix.translate2D = function(x, y) { 62 | return [1, 0, 0, 0, 1, 0, x, y, 1]; 63 | }; 64 | 65 | Matrix.transform2D = function(pt, m, axis, byValue) { 66 | var v, x, y; 67 | if (axis == null) { 68 | axis = Const.xy; 69 | } 70 | if (byValue == null) { 71 | byValue = false; 72 | } 73 | v = pt.get2D(axis); 74 | x = v.x * m[0] + v.y * m[3] + m[6]; 75 | y = v.x * m[1] + v.y * m[4] + m[7]; 76 | v.x = x; 77 | v.y = y; 78 | v = v.get2D(axis, true); 79 | if (!byValue) { 80 | pt.set(v); 81 | return pt; 82 | } 83 | return v; 84 | }; 85 | 86 | return Matrix; 87 | 88 | })(); 89 | 90 | this.Matrix = Matrix; 91 | 92 | //# sourceMappingURL=.map/Matrix.js.map -------------------------------------------------------------------------------- /dist/core/elements/ParticleSystem.js: -------------------------------------------------------------------------------- 1 | var ParticleSystem; 2 | 3 | ParticleSystem = (function() { 4 | function ParticleSystem() { 5 | this.count = 0; 6 | this.particles = []; 7 | this.time = 0; 8 | } 9 | 10 | ParticleSystem.prototype.add = function(particle) { 11 | particle.id = this.count++; 12 | this.particles.push(particle); 13 | return this; 14 | }; 15 | 16 | ParticleSystem.prototype.remove = function(particle) { 17 | if (particle && particle.life) { 18 | particle.life.complete = true; 19 | } 20 | return this; 21 | }; 22 | 23 | ParticleSystem.prototype.animate = function(time, frame, ctx) { 24 | var _remove, i, index, j, k, len, len1, p, ref, results; 25 | this.time++; 26 | _remove = []; 27 | ref = this.particles; 28 | for (i = j = 0, len = ref.length; j < len; i = ++j) { 29 | p = ref[i]; 30 | if (p.life.complete) { 31 | _remove.push(i); 32 | } else if (p.life.active) { 33 | p.animate(time, frame, ctx); 34 | } 35 | } 36 | if (_remove.length > 0) { 37 | results = []; 38 | for (k = 0, len1 = _remove.length; k < len1; k++) { 39 | index = _remove[k]; 40 | results.push(this.particles.splice(index, 1)); 41 | } 42 | return results; 43 | } 44 | }; 45 | 46 | return ParticleSystem; 47 | 48 | })(); 49 | 50 | this.ParticleSystem = ParticleSystem; 51 | 52 | //# sourceMappingURL=.map/ParticleSystem.js.map -------------------------------------------------------------------------------- /dist/core/elements/SVGSpace.js: -------------------------------------------------------------------------------- 1 | var SVGSpace, 2 | extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 3 | hasProp = {}.hasOwnProperty; 4 | 5 | SVGSpace = (function(superClass) { 6 | extend(SVGSpace, superClass); 7 | 8 | function SVGSpace(id, callback) { 9 | var b, s; 10 | SVGSpace.__super__.constructor.call(this, id, callback, 'svg'); 11 | if (this.space.nodeName.toLowerCase() !== "svg") { 12 | s = this._createElement("svg", this.id + "_svg"); 13 | this.space.appendChild(s); 14 | this.bound = this.space; 15 | this.space = s; 16 | b = this.bound.getBoundingClientRect(); 17 | this.resize(b.width, b.height); 18 | } 19 | } 20 | 21 | SVGSpace.prototype._createElement = function(elem, id) { 22 | var d; 23 | if (elem == null) { 24 | elem = "svg"; 25 | } 26 | d = document.createElementNS("http://www.w3.org/2000/svg", elem); 27 | if (id) { 28 | d.setAttribute("id", id); 29 | } 30 | return d; 31 | }; 32 | 33 | SVGSpace.svgElement = function(parent, name, id) { 34 | var elem; 35 | if (!parent || !parent.appendChild) { 36 | parent = this.space; 37 | if (!parent) { 38 | throw "parent parameter needs to be a DOM node"; 39 | } 40 | } 41 | elem = document.querySelector("#" + id); 42 | if (!elem) { 43 | elem = document.createElementNS("http://www.w3.org/2000/svg", name); 44 | elem.setAttribute("id", id); 45 | elem.setAttribute("class", id.substring(0, id.indexOf("-"))); 46 | parent.appendChild(elem); 47 | } 48 | return elem; 49 | }; 50 | 51 | SVGSpace.prototype.remove = function(item) { 52 | var i, len, t, temp; 53 | temp = this.space.querySelectorAll("." + SVGForm._scopeID(item)); 54 | for (i = 0, len = temp.length; i < len; i++) { 55 | t = temp[i]; 56 | t.parentNode.removeChild(t); 57 | } 58 | delete this.items[item.animateID]; 59 | return this; 60 | }; 61 | 62 | SVGSpace.prototype.removeAll = function() { 63 | while (this.space.firstChild) { 64 | this.space.removeChild(this.space.firstChild); 65 | return this; 66 | } 67 | }; 68 | 69 | return SVGSpace; 70 | 71 | })(DOMSpace); 72 | 73 | this.SVGSpace = SVGSpace; 74 | 75 | //# sourceMappingURL=.map/SVGSpace.js.map -------------------------------------------------------------------------------- /dist/core/elements/Timer.js: -------------------------------------------------------------------------------- 1 | var Timer; 2 | 3 | Timer = (function() { 4 | function Timer(d) { 5 | if (d == null) { 6 | d = 1000; 7 | } 8 | this.duration = d; 9 | this._time = 0; 10 | this._ease = function(t, b, c, d) { 11 | return t / d; 12 | }; 13 | this._intervalID = -1; 14 | } 15 | 16 | Timer.prototype.start = function(reset) { 17 | var diff; 18 | diff = Math.min(Date.now() - this._time, this.duration); 19 | if (reset || diff >= this.duration) { 20 | return this._time = Date.now(); 21 | } 22 | }; 23 | 24 | Timer.prototype.setEasing = function(ease) { 25 | return this._ease = ease; 26 | }; 27 | 28 | Timer.prototype.check = function() { 29 | var diff; 30 | diff = Math.min(Date.now() - this._time, this.duration); 31 | return this._ease(diff, 0, 1, this.duration); 32 | }; 33 | 34 | Timer.prototype.track = function(callback) { 35 | var me; 36 | clearInterval(this._intervalID); 37 | this.start(true); 38 | me = this; 39 | this._intervalID = setInterval((function() { 40 | var t; 41 | t = me.check(); 42 | callback(t); 43 | if (t >= 1) { 44 | return clearInterval(me._intervalID); 45 | } 46 | }), 25); 47 | return this._intervalID; 48 | }; 49 | 50 | return Timer; 51 | 52 | })(); 53 | 54 | this.Timer = Timer; 55 | 56 | //# sourceMappingURL=.map/Timer.js.map -------------------------------------------------------------------------------- /dist/extend/elements/Easing.js: -------------------------------------------------------------------------------- 1 | var Easing; 2 | 3 | Easing = (function() { 4 | function Easing() {} 5 | 6 | Easing.linear = function(t, b, c, d) { 7 | return c * (t /= d) + b; 8 | }; 9 | 10 | Easing._linear = function(t) { 11 | return Easing.linear(t, 0, 1, 1); 12 | }; 13 | 14 | Easing.quadIn = function(t, b, c, d) { 15 | return c * (t /= d) * t + b; 16 | }; 17 | 18 | Easing._quadIn = function(t) { 19 | return Easing.quadIn(t, 0, 1, 1); 20 | }; 21 | 22 | Easing.quadOut = function(t, b, c, d) { 23 | return -c * (t /= d) * (t - 2) + b; 24 | }; 25 | 26 | Easing._quadOut = function(t) { 27 | return Easing.quadOut(t, 0, 1, 1); 28 | }; 29 | 30 | Easing.cubicIn = function(t, b, c, d) { 31 | t = t / d; 32 | return c * t * t * t + b; 33 | }; 34 | 35 | Easing._cubicIn = function(t) { 36 | return Easing.cubicIn(t, 0, 1, 1); 37 | }; 38 | 39 | Easing.cubicOut = function(t, b, c, d) { 40 | t = t / d; 41 | return c * ((t - 1) * t * t + 1) + b; 42 | }; 43 | 44 | Easing._cubicOut = function(t) { 45 | return Easing.cubicOut(t, 0, 1, 1); 46 | }; 47 | 48 | Easing.elastic = function(t, b, c, d, el) { 49 | var a, p, s; 50 | if (el == null) { 51 | el = 0.3; 52 | } 53 | s = 1.70158; 54 | p = d * el; 55 | a = c; 56 | if (t === 0) { 57 | return b; 58 | } 59 | t = t / d; 60 | if (t === 1) { 61 | return b + c; 62 | } 63 | if (a < Math.abs(c)) { 64 | a = c; 65 | s = p / 4; 66 | } else if (a !== 0) { 67 | s = p / Const.two_pi * Math.asin(c / a); 68 | } else { 69 | s = 0; 70 | } 71 | return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * Const.two_pi / p) + c + b; 72 | }; 73 | 74 | Easing._elastic = function(t) { 75 | return Easing.elastic(t, 0, 1, 1); 76 | }; 77 | 78 | Easing.bounce = function(t, b, c, d) { 79 | if ((t /= d) < (1 / 2.75)) { 80 | return c * (7.5625 * t * t) + b; 81 | } else if (t < (2 / 2.75)) { 82 | return c * (7.5625 * (t -= 1.5 / 2.75) * t + 0.75) + b; 83 | } else if (t < (2.5 / 2.75)) { 84 | return c * (7.5625 * (t -= 2.25 / 2.75) * t + 0.9375) + b; 85 | } else { 86 | return c * (7.5625 * (t -= 2.625 / 2.75) * t + 0.984375) + b; 87 | } 88 | }; 89 | 90 | Easing._bounce = function(t) { 91 | return Easing.bounce(t, 0, 1, 1); 92 | }; 93 | 94 | return Easing; 95 | 96 | })(); 97 | 98 | this.Easing = Easing; 99 | 100 | //# sourceMappingURL=map/Easing.js.map -------------------------------------------------------------------------------- /dist/extend/elements/ParticleEmitter.js: -------------------------------------------------------------------------------- 1 | var ParticleEmitter, 2 | extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 3 | hasProp = {}.hasOwnProperty; 4 | 5 | ParticleEmitter = (function(superClass) { 6 | extend(ParticleEmitter, superClass); 7 | 8 | function ParticleEmitter() { 9 | ParticleEmitter.__super__.constructor.apply(this, arguments); 10 | this.system = null; 11 | this.lastTime = 0; 12 | this.animateID = -1; 13 | } 14 | 15 | ParticleEmitter.prototype.frequency = function(f) { 16 | return this.period = 1000 / f; 17 | }; 18 | 19 | ParticleEmitter.prototype.emit = function() {}; 20 | 21 | ParticleEmitter.prototype.animate = function(time, frame, ctx) { 22 | if (time - this.lastTime > this.period) { 23 | this.emit(); 24 | return this.lastTime = time; 25 | } 26 | }; 27 | 28 | return ParticleEmitter; 29 | 30 | })(Vector); 31 | 32 | this.ParticleEmitter = ParticleEmitter; 33 | 34 | //# sourceMappingURL=map/ParticleEmitter.js.map -------------------------------------------------------------------------------- /dist/extend/elements/ParticleField.js: -------------------------------------------------------------------------------- 1 | var ParticleField, 2 | extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 3 | hasProp = {}.hasOwnProperty; 4 | 5 | ParticleField = (function(superClass) { 6 | extend(ParticleField, superClass); 7 | 8 | function ParticleField() { 9 | ParticleField.__super__.constructor.apply(this, arguments); 10 | this.system = void 0; 11 | } 12 | 13 | ParticleField.prototype.check = function(particles, removal) { 14 | var i, len, p, temp; 15 | if (removal == null) { 16 | removal = false; 17 | } 18 | temp = []; 19 | for (i = 0, len = particles.length; i < len; i++) { 20 | p = particles[i]; 21 | if (this.hasIntersect(p)) { 22 | this.work(p); 23 | } else { 24 | temp.push(p); 25 | } 26 | } 27 | return (removal ? temp : particles); 28 | }; 29 | 30 | ParticleField.prototype.work = function(p) {}; 31 | 32 | return ParticleField; 33 | 34 | })(Rectangle); 35 | 36 | this.ParticleField = ParticleField; 37 | 38 | //# sourceMappingURL=map/ParticleField.js.map -------------------------------------------------------------------------------- /dist/extend/elements/UI.js: -------------------------------------------------------------------------------- 1 | var UI, 2 | extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, 3 | hasProp = {}.hasOwnProperty; 4 | 5 | UI = (function(superClass) { 6 | extend(UI, superClass); 7 | 8 | UI.dragTarget = null; 9 | 10 | function UI() { 11 | UI.__super__.constructor.apply(this, arguments); 12 | this.dragging = false; 13 | } 14 | 15 | UI.prototype.animate = function(time, frame, ctx) { 16 | ctx.fillStyle = '#f00'; 17 | return Form.rect(ctx, this); 18 | }; 19 | 20 | UI.prototype.onMouseAction = function(type, x, y, evt) { 21 | if (this.intersectPoint(x, y)) { 22 | if (type === 'drag' && !UI.dragTarget) { 23 | this.dragging = true; 24 | UI.dragTarget = this; 25 | } 26 | } 27 | if (this.dragging && type === 'move') { 28 | this.moveTo(x, y).moveBy(this.size().multiply(-0.5)); 29 | } 30 | if (type === 'drop') { 31 | this.dragging = false; 32 | return UI.dragTarget = null; 33 | } 34 | }; 35 | 36 | return UI; 37 | 38 | })(Rectangle); 39 | 40 | this.UI = UI; 41 | 42 | //# sourceMappingURL=map/UI.js.map -------------------------------------------------------------------------------- /dist/extend/elements/map/ParticleEmitter.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["ParticleEmitter.coffee"],"names":[],"mappings":"AAEA,IAAA,eAAA;EAAA;;;AAAM;;;EAMS,yBAAA;IACX,kDAAA,SAAA;IAEA,IAAC,CAAA,MAAD,GAAU;IACV,IAAC,CAAA,QAAD,GAAY;IACZ,IAAC,CAAA,SAAD,GAAa,CAAC;EALH;;4BAQb,SAAA,GAAW,SAAC,CAAD;WAAO,IAAC,CAAA,MAAD,GAAU,IAAA,GAAO;EAAxB;;4BAGX,IAAA,GAAM,SAAA,GAAA;;4BAKN,OAAA,GAAS,SAAE,IAAF,EAAQ,KAAR,EAAe,GAAf;IACP,IAAG,IAAA,GAAO,IAAC,CAAA,QAAR,GAAmB,IAAC,CAAA,MAAvB;MACE,IAAC,CAAA,IAAD,CAAA;aACA,IAAC,CAAA,QAAD,GAAY,KAFd;;EADO;;;;GAtBmB;;AA8B9B,IAAI,CAAC,eAAL,GAAuB","file":"ParticleEmitter.js","sourceRoot":"/source/","sourcesContent":["\r\n# # Particle Emitter\r\nclass ParticleEmitter extends Vector\r\n\r\n # ## Constructor\r\n # @param {system} Particle System\r\n # @param {position} position of the emitter\r\n # @param {frequency} number of particles to emit per second\r\n constructor: ( ) ->\r\n super\r\n\r\n @system = null\r\n @lastTime = 0\r\n @animateID = -1 # for Space loop\r\n\r\n # ## Set frequency of emisson. f = how many per second.\r\n frequency: (f) -> @period = 1000 / f\r\n\r\n # ## emit a particle (abstract method)\r\n emit: ->\r\n # override to define an emitter function\r\n # e.g @system.add( new Particle( @position ) )\r\n\r\n # ## animate function to be called by Space\r\n animate: ( time, frame, ctx ) ->\r\n if time - @lastTime > @period\r\n @emit()\r\n @lastTime = time\r\n\r\n\r\n\r\n# namespace\r\nthis.ParticleEmitter = ParticleEmitter"]} -------------------------------------------------------------------------------- /dist/extend/elements/map/ParticleField.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["ParticleField.coffee"],"names":[],"mappings":"AACA,IAAA,aAAA;EAAA;;;AAAM;;;EAES,uBAAA;IACX,gDAAA,SAAA;IACA,IAAC,CAAA,MAAD,GAAU;EAFC;;0BAOb,KAAA,GAAO,SAAC,SAAD,EAAY,OAAZ;AACL,QAAA;;MADiB,UAAQ;;IACzB,IAAA,GAAO;AACP,SAAA,2CAAA;;MACE,IAAG,IAAC,CAAA,YAAD,CAAe,CAAf,CAAH;QACE,IAAC,CAAA,IAAD,CAAO,CAAP,EADF;OAAA,MAAA;QAGE,IAAI,CAAC,IAAL,CAAW,CAAX,EAHF;;AADF;AAMA,WAAO,CAAK,OAAH,GAAgB,IAAhB,GAA0B,SAA5B;EARF;;0BAYP,IAAA,GAAM,SAAC,CAAD,GAAA;;;;GArBoB;;AA2B5B,IAAI,CAAC,aAAL,GAAqB","file":"ParticleField.js","sourceRoot":"/source/","sourcesContent":["# # An area that influence force, velocity, etc of particles inside it\r\nclass ParticleField extends Rectangle\r\n\r\n constructor: ()->\r\n super\r\n @system = undefined\r\n\r\n # ## check particles to work on\r\n # @param {particles} array of particles\r\n # @param {removal} if true and if particle within bound, then remove it from array\r\n check: (particles, removal=false) ->\r\n temp = []\r\n for p in particles\r\n if @hasIntersect( p ) # within\r\n @work( p )\r\n else\r\n temp.push( p )\r\n\r\n return ( if removal then temp else particles )\r\n\r\n # ## apply the changes to a particle (abstract method), used in check()\r\n # @param {p} a particle\r\n work: (p) ->\r\n\r\n\r\n\r\n\r\n# namespace\r\nthis.ParticleField = ParticleField"]} -------------------------------------------------------------------------------- /dist/extend/elements/map/UI.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["UI.coffee"],"names":[],"mappings":"AACA,IAAA,EAAA;EAAA;;;AAAM;;;EAGJ,EAAC,CAAA,UAAD,GAAa;;EAEA,YAAA;IACX,qCAAA,SAAA;IACA,IAAC,CAAA,QAAD,GAAY;EAFD;;eAIb,OAAA,GAAU,SAAC,IAAD,EAAO,KAAP,EAAc,GAAd;IACR,GAAG,CAAC,SAAJ,GAAgB;WAChB,IAAI,CAAC,IAAL,CAAW,GAAX,EAAgB,IAAhB;EAFQ;;eAIV,aAAA,GAAe,SAAC,IAAD,EAAO,CAAP,EAAU,CAAV,EAAa,GAAb;IACb,IAAG,IAAC,CAAA,cAAD,CAAiB,CAAjB,EAAoB,CAApB,CAAH;MACE,IAAG,IAAA,KAAQ,MAAR,IAAmB,CAAC,EAAE,CAAC,UAA1B;QACE,IAAC,CAAA,QAAD,GAAY;QACZ,EAAE,CAAC,UAAH,GAAgB,KAFlB;OADF;;IAKA,IAAG,IAAC,CAAA,QAAD,IAAc,IAAA,KAAQ,MAAzB;MACE,IAAC,CAAA,MAAD,CAAQ,CAAR,EAAU,CAAV,CAAY,CAAC,MAAb,CAAqB,IAAC,CAAA,IAAD,CAAA,CAAO,CAAC,QAAR,CAAiB,CAAC,GAAlB,CAArB,EADF;;IAGA,IAAG,IAAA,KAAQ,MAAX;MACE,IAAC,CAAA,QAAD,GAAY;aACZ,EAAE,CAAC,UAAH,GAAgB,KAFlB;;EATa;;;;GAbA;;AA4BjB,IAAI,CAAC,EAAL,GAAU","file":"UI.js","sourceRoot":"/source/","sourcesContent":["# # A simple handle that can be dragged by mouse\r\nclass UI extends Rectangle\r\n\r\n # class variable tracks if a handle has been dragged (to avoid dragging multiple handles at once)\r\n @dragTarget: null\r\n\r\n constructor: () ->\r\n super\r\n @dragging = false\r\n\r\n animate : (time, frame, ctx) ->\r\n ctx.fillStyle = '#f00'\r\n Form.rect( ctx, this )\r\n\r\n onMouseAction: (type, x, y, evt) ->\r\n if @intersectPoint( x, y )\r\n if type == 'drag' and !UI.dragTarget\r\n @dragging = true\r\n UI.dragTarget = this\r\n\r\n if @dragging and type == 'move'\r\n @moveTo(x,y).moveBy( @size().multiply(-0.5) ) # move and anchor by center point\r\n\r\n if type == 'drop'\r\n @dragging = false\r\n UI.dragTarget = null\r\n\r\n\r\n# namespace\r\nthis.UI = UI"]} -------------------------------------------------------------------------------- /docs/guide/INSTRUCTION.md: -------------------------------------------------------------------------------- 1 | ## Use markdown library with fenced code extension 2 | python -m markdown -x markdown.extensions.fenced_code quickstart.md > _convert.html 3 | 4 | ## Update fenced code to use prism class 5 | "```language-javascript" 6 | 7 | ### If extra line found in generated , remove with regex 8 | `\n ` -------------------------------------------------------------------------------- /docs/guide/_convert.html: -------------------------------------------------------------------------------- 1 |

Pt: Migration Guide

2 |

v0.2.0: Space constructor

3 |

In Pt v0.2.0, we refactored the constructor function for Space to make it simpler and clearer.

4 |

Previously in 0.1.x, the old constructor function works like this:

5 |
// new CanvasSpace( canvas_id, bgcolor ).display( container_id, readyCallback, devicePixelSupport);
 6 | // for example:
 7 | 
 8 | new CanvasSpace().display("#myDiv")
 9 | new CanvasSpace("myCanvas", "#F00").display("#myDiv", readyFunc, true)
10 | 
11 | 12 |

The container and canvas id has been a source of confusion for some users. The new constructor function now works like this:

13 |
// new CanvasSpace( domID, readyCallback ).setup( properties );
14 | // for example:
15 | 
16 | new CanvasSpace()
17 | new CanvasSpace("#elem")
18 | new CanvasSpace("#elem", readyFunc).setup({ bgcolor: "#F00", retina: true })
19 | 
20 | 21 |

You can now simply pass an id to the constructor, 22 | and it's smart enough to find out whether it's a container like <div> or <canvas> and fill in the rest. If no "id" is specified, it assumes you are targeting an existing element in DOM with id="pt" attribute.

23 |

A new setup function lets you pass parameters to initialize the space, as each type of space may offer different kind of setups. 24 | Also notice that the ready callback is now an optional second parameter in the constructor.

25 |

v0.2.0: SVG

26 |

SVGSpace and SVGForm are now in the core library. If you don't need anything else in extend library and wants to save a tiny bit of bandwidth, you may use pt-core.min.js instead of pt.min.js. 27 | Otherwise no change is neeed.

28 |

getScope function is now called enterScope in v0.2.0 to make it clearer. 29 | The old function name will continue to work, but will print a warning in the console.

-------------------------------------------------------------------------------- /docs/guide/migration.md: -------------------------------------------------------------------------------- 1 | # Pt: Migration Guide 2 | 3 | ### v0.2.0: Space constructor 4 | In Pt v0.2.0, we refactored the constructor function for Space to make it simpler and clearer. 5 | 6 | Previously in 0.1.x, the old constructor function works like this: 7 | 8 | ```language-javascript 9 | // new CanvasSpace( canvas_id, bgcolor ).display( container_id, readyCallback, devicePixelSupport); 10 | // for example: 11 | 12 | new CanvasSpace().display("#myDiv") 13 | new CanvasSpace("myCanvas", "#F00").display("#myDiv", readyFunc, true) 14 | ``` 15 | 16 | The container and canvas id has been a source of confusion for some users. The new constructor function now works like this: 17 | 18 | ```language-javascript 19 | // new CanvasSpace( domID, readyCallback ).setup( properties ); 20 | // for example: 21 | 22 | new CanvasSpace() 23 | new CanvasSpace("#elem") 24 | new CanvasSpace("#elem", readyFunc).setup({ bgcolor: "#F00", retina: true }) 25 | ``` 26 | 27 | You can now simply pass an id to the constructor, 28 | and it's smart enough to find out whether it's a container like `
` or `` and fill in the rest. If instantiated without parameters, it assumes you are targeting an existing element in DOM with `id="pt"` attribute. 29 | 30 | A new `setup` function lets you pass parameters to initialize the space, as each type of space may offer different kind of setups. 31 | Also notice that the ready callback is now an optional second parameter in the constructor. 32 | 33 | ### v0.2.0: SVG 34 | `SVGSpace` and `SVGForm` are now in the *core* library. If you don't need anything else in *extend* library and wants to save a tiny bit of bandwidth, you may use `pt-core.min.js` instead of `pt.min.js`. 35 | Otherwise no change is neeed. 36 | 37 | `getScope` function is now called [`enterScope`](http://localhost:2016/docs/#func-SVGForm-enterScope) in v0.2.0 to make it clearer. 38 | The old function name will continue to work, but will print a warning in the console. -------------------------------------------------------------------------------- /docs/guide/quickstart_demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Pt - getting started 5 | 6 | 9 | 10 | 11 | 12 | 13 |
14 | Back to Quick Start Guide 15 | Source Code 16 | 17 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /docs/guide/svg.md: -------------------------------------------------------------------------------- 1 | # Pt: SVG Guide 2 | 3 | Pt enables you to express an idea in a variety of forms and spaces. 4 | SVG is another kind of space, in which every element is in a DOM (Document Object Model). 5 | But don't worry, it's easy to write almost identical code for both SVG and Canvas. This is a quick guide to show you how. 6 | 7 | ### Set up 8 | First of all, we'll create an `SVGSpace` instead of a `CanvasSpace`. 9 | 10 | ```language-javascript 11 | var space = new SVGSpace("pt", ready); 12 | ``` 13 | 14 | You may notice a second parameter called `ready`. This is a callback function which we'll define now: 15 | 16 | ```language-javascript 17 | function ready(bounds, elem) { 18 | form.scope("item", elem ); // initiate the scope which uses the svg dom as parent node 19 | space.bindMouse(); 20 | space.play(); 21 | } 22 | ``` 23 | 24 | Because of how DOM works (it's kind of a pain), we have to wait till the DOM elements are ready before we can use them. 25 | Hence we use a callback function `ready` to put all the initiation code inside. 26 | 27 | The one additional function we use here is `form.scope("item", elem)`. 28 | This initiates the container element (second parameter, passed from callback function) for our svg space , 29 | and give it a custom name called "item", which will be used to identify child elements inside it. 30 | 31 | 32 | ### Scope 33 | In ``, elements are simply painted on top of each other, 34 | and in each cycle everything is usually wiped and repainted. 35 | In DOM, elements persist. We may clear and recreate them again and again like ``, but that will be very slow. 36 | It'll be better if we keep track of DOM elements and update their attributes when needed. 37 | 38 | `SVGForm` solves this with a function called `enterScope(item)`. 39 | It's a way of saying: Hey, take note of new and existing elements in this group and update them as needed. 40 | The `item` parameter is simply the animate-able object you added to space. 41 | 42 | In short, and in most cases, you may simply add this `enterScope` function in the beginning of `animate` callback function, and that's it. 43 | 44 | ```language-javascript 45 | space.add({ 46 | animate: function(time, fps, context) { 47 | // enter group scope. "this" refers to this object we are adding to space 48 | form.enterScope( this ); 49 | 50 | // do stuff here, no additional changes needed. 51 | form.fill("#f00").point( new Point( 100, 100 ) ); 52 | } 53 | }); 54 | ``` 55 | 56 | 57 | ### Examples 58 | To recap: first initiate a parent scope in a ready callback function, 59 | and then in the beginning of your object's `animate` function, call the `enterScope` function. Done! 60 | 61 | If you want to change it back to CanvasSpace, simply change `SVGSpace` to `CanvasSpace`, and `SVGForm` to `Form` in the instantiation. 62 | The `scope` functions have no effects in CanvasSpace and won't break your code. 63 | 64 | Take a look at the source code in the [SVG demos](../../demo/index.html?name=svgform.scope). It's pretty straightforward. -------------------------------------------------------------------------------- /docs/images/pt/canvasspace.bindMouse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/canvasspace.bindMouse.png -------------------------------------------------------------------------------- /docs/images/pt/canvasspace.resize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/canvasspace.resize.png -------------------------------------------------------------------------------- /docs/images/pt/circle.intersectCircle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/circle.intersectCircle.png -------------------------------------------------------------------------------- /docs/images/pt/circle.intersectPath.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/circle.intersectPath.png -------------------------------------------------------------------------------- /docs/images/pt/circle.intersectPoint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/circle.intersectPoint.png -------------------------------------------------------------------------------- /docs/images/pt/color.HSBtoRGB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/color.HSBtoRGB.png -------------------------------------------------------------------------------- /docs/images/pt/color.HSLtoRGB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/color.HSLtoRGB.png -------------------------------------------------------------------------------- /docs/images/pt/color.LABtoRGB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/color.LABtoRGB.png -------------------------------------------------------------------------------- /docs/images/pt/curve.bezier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/curve.bezier.png -------------------------------------------------------------------------------- /docs/images/pt/curve.bspline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/curve.bspline.png -------------------------------------------------------------------------------- /docs/images/pt/curve.cardinal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/curve.cardinal.png -------------------------------------------------------------------------------- /docs/images/pt/form.curve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/form.curve.png -------------------------------------------------------------------------------- /docs/images/pt/form.fill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/form.fill.png -------------------------------------------------------------------------------- /docs/images/pt/form.font.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/form.font.png -------------------------------------------------------------------------------- /docs/images/pt/form.points.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/form.points.png -------------------------------------------------------------------------------- /docs/images/pt/grid.generate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/grid.generate.png -------------------------------------------------------------------------------- /docs/images/pt/grid.occupy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/grid.occupy.png -------------------------------------------------------------------------------- /docs/images/pt/index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/index.png -------------------------------------------------------------------------------- /docs/images/pt/index2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/index2.png -------------------------------------------------------------------------------- /docs/images/pt/line.getPerpendicular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/line.getPerpendicular.png -------------------------------------------------------------------------------- /docs/images/pt/line.getPerpendicularFromPoint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/line.getPerpendicularFromPoint.png -------------------------------------------------------------------------------- /docs/images/pt/line.intersectLine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/line.intersectLine.png -------------------------------------------------------------------------------- /docs/images/pt/pair.collinear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/pair.collinear.png -------------------------------------------------------------------------------- /docs/images/pt/pair.interpolate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/pair.interpolate.png -------------------------------------------------------------------------------- /docs/images/pt/pair.withinBounds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/pair.withinBounds.png -------------------------------------------------------------------------------- /docs/images/pt/particle.collideLine2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/particle.collideLine2d.png -------------------------------------------------------------------------------- /docs/images/pt/particle.play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/particle.play.png -------------------------------------------------------------------------------- /docs/images/pt/point.max.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/point.max.png -------------------------------------------------------------------------------- /docs/images/pt/point.quadrant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/point.quadrant.png -------------------------------------------------------------------------------- /docs/images/pt/pointset.convexhull.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/pointset.convexhull.png -------------------------------------------------------------------------------- /docs/images/pt/pointset.sides.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/pointset.sides.png -------------------------------------------------------------------------------- /docs/images/pt/rectangle.enclose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/rectangle.enclose.png -------------------------------------------------------------------------------- /docs/images/pt/rectangle.intersectPath.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/rectangle.intersectPath.png -------------------------------------------------------------------------------- /docs/images/pt/rectangle.resizeCenterTo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/rectangle.resizeCenterTo.png -------------------------------------------------------------------------------- /docs/images/pt/samplepoints.poisson.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/samplepoints.poisson.png -------------------------------------------------------------------------------- /docs/images/pt/shaping.linear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/shaping.linear.png -------------------------------------------------------------------------------- /docs/images/pt/space.add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/space.add.png -------------------------------------------------------------------------------- /docs/images/pt/space.refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/space.refresh.png -------------------------------------------------------------------------------- /docs/images/pt/svgform.circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/svgform.circle.png -------------------------------------------------------------------------------- /docs/images/pt/svgform.scope.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/svgform.scope.png -------------------------------------------------------------------------------- /docs/images/pt/svgspace.remove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/svgspace.remove.png -------------------------------------------------------------------------------- /docs/images/pt/triangle.incenter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/triangle.incenter.png -------------------------------------------------------------------------------- /docs/images/pt/triangle.oppositeSide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/triangle.oppositeSide.png -------------------------------------------------------------------------------- /docs/images/pt/vector.add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/vector.add.png -------------------------------------------------------------------------------- /docs/images/pt/vector.field.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/vector.field.png -------------------------------------------------------------------------------- /docs/images/pt/vector.normalize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/vector.normalize.png -------------------------------------------------------------------------------- /docs/images/pt/vector.projection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/vector.projection.png -------------------------------------------------------------------------------- /docs/images/pt/vector.rotate2D.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/vector.rotate2D.png -------------------------------------------------------------------------------- /docs/images/pt/vector.scale2D.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/pt/vector.scale2D.png -------------------------------------------------------------------------------- /docs/images/quick-start-guide/console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/quick-start-guide/console.png -------------------------------------------------------------------------------- /docs/images/quick-start-guide/mobile1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/quick-start-guide/mobile1.png -------------------------------------------------------------------------------- /docs/images/quick-start-guide/mobiletouch.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/quick-start-guide/mobiletouch.gif -------------------------------------------------------------------------------- /docs/images/quick-start-guide/progress1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/quick-start-guide/progress1.png -------------------------------------------------------------------------------- /docs/images/quick-start-guide/progress2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/quick-start-guide/progress2.png -------------------------------------------------------------------------------- /docs/images/quick-start-guide/progress3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/quick-start-guide/progress3.png -------------------------------------------------------------------------------- /docs/images/quick-start-guide/progress4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/quick-start-guide/progress4.png -------------------------------------------------------------------------------- /docs/images/quick-start-guide/progress5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/docs/images/quick-start-guide/progress5.png -------------------------------------------------------------------------------- /docs/json/core/Easing.json: -------------------------------------------------------------------------------- 1 | { 2 | "cls": "Easing", 3 | "description": "

Easing functions based on Robert Penner's

", 4 | "extend": "", 5 | "file": "Geom.coffee", 6 | "funcs": [], 7 | "props": [], 8 | "statics": [ 9 | { 10 | "description": "

Linear interpolation

", 11 | "name": "linear", 12 | "param": [ 13 | "

t current time or iteration

", 14 | "

b start value

", 15 | "

c change in value

", 16 | "

d duration time or total iteration

" 17 | ], 18 | "pname": "t, b, c, d" 19 | }, 20 | { 21 | "description": "

Runge-Kutta-4 integrator (adopted from gafferongames.com)

", 22 | "name": "RK4", 23 | "param": [ 24 | "

c, d the derivative of c is d. If c is position, then d is velocity.

", 25 | "

func acceleration function(c, d, dt, t)

", 26 | "

dt change in time

", 27 | "

t current time

" 28 | ], 29 | "pname": "c, d, func, dt, t", 30 | "return": "

an object with {c, d} properties where the derivative of c is d.

" 31 | }, 32 | { 33 | "description": "

A static function to pre-calculate a sine and cosine table. To use this, convert radian to angle as an integer, and then get table index by finding modulus angle%360

", 34 | "name": "sinCosTable", 35 | "param": [], 36 | "pname": "", 37 | "return": "

an object with {sin, cos} properties.

" 38 | }, 39 | { 40 | "description": "

A simple implementation of Mitchell's Best Neighor Algorithm to generate one sample. (Consider using SamplePoints class instead)

", 41 | "name": "bestCandidate", 42 | "param": [ 43 | "

bound a Rectangle object to specify the bounding box

", 44 | "

items an array of existing items

", 45 | "

samples number of sampling. Default to 10.

" 46 | ], 47 | "pname": "bound, items, samples=10", 48 | "return": "

o Vector object which is best candidate

" 49 | } 50 | ] 51 | } -------------------------------------------------------------------------------- /docs/json/core/ParticleSystem.json: -------------------------------------------------------------------------------- 1 | { 2 | "cls": "ParticleSystem", 3 | "description": "

A particle system keeps track of particles, and regulate them with rules specific to a system. It can also hold constant values from gravitational to cosmic, and specify whether a god may play dice here.

", 4 | "extend": "", 5 | "file": "ParticleSystem.coffee", 6 | "funcs": [ 7 | { 8 | "description": "

Create a ParticleSystem to track a set of particles

", 9 | "name": "ParticleSystem", 10 | "param": [], 11 | "pname": "" 12 | }, 13 | { 14 | "description": "

add a particle to the system

", 15 | "name": "add", 16 | "param": [ 17 | "

particle a Particle

" 18 | ], 19 | "pname": "particle", 20 | "return": "

this system

" 21 | }, 22 | { 23 | "description": "

remove a particle which has a particle.life property. This marks the particle.life.complete as true for removal in next cycle.

", 24 | "name": "remove", 25 | "param": [ 26 | "

particle a Particle

" 27 | ], 28 | "pname": "particle", 29 | "return": "

this system

" 30 | }, 31 | { 32 | "description": "

animate callback function which is called bySpace.play(). Override this callback function to specify other animation loops

", 33 | "name": "animate", 34 | "param": [ 35 | "

time, frame, ctx parameters for current time, fps, and rendering context, which will be passed by Space in callback

" 36 | ], 37 | "pname": "time, frame, ctx" 38 | } 39 | ], 40 | "props": [ 41 | { 42 | "description": "

a property to store particles in this system as an Array

", 43 | "name": "count", 44 | "param": [] 45 | }, 46 | { 47 | "description": "

a property to track time in milliseconds

", 48 | "name": "time", 49 | "param": [] 50 | } 51 | ], 52 | "statics": [] 53 | } -------------------------------------------------------------------------------- /docs/json/core/SVGSpace.json: -------------------------------------------------------------------------------- 1 | { 2 | "cls": "SVGSpace", 3 | "description": "

SVGSpace is an extension of DOMSpace that represents an svg element in DOM. Also refers to DOMSpace for inherited methods.

", 4 | "extend": "DOMSpace", 5 | "file": "SVGSpace.coffee", 6 | "funcs": [ 7 | { 8 | "description": "

Create a SVGSpace which represents a svg element

", 9 | "name": "SVGSpace", 10 | "param": [ 11 | "

id Specify an element by its \"id\" attribute as string, or by the element object itself. An element can be an existing <svg>, or a <div> container in which a new <svg> will be created. If left empty, a <div id=\"pt\"><svg id=\"pt_svg\" /></div> will be added to DOM. Use css to customize its appearance if needed.

", 12 | "

callback an optional callback function(boundingBox, spaceElement) to be called when element is appended and ready. A \"ready\" event will also be fired from the space's element when it's appended, which can be tracked with spaceInstance.space.addEventListener(\"ready\")

" 13 | ], 14 | "pname": "id, callback" 15 | }, 16 | { 17 | "demo": "svgspace.remove", 18 | "description": "

Remove an item from this Space

", 19 | "name": "remove", 20 | "param": [ 21 | "

an object with an auto-assigned animateID property

" 22 | ], 23 | "pname": "item", 24 | "return": "

this space

" 25 | }, 26 | { 27 | "description": "

Remove all items from this Space

", 28 | "name": "removeAll", 29 | "param": [], 30 | "pname": "", 31 | "return": "

this space

" 32 | } 33 | ], 34 | "props": [], 35 | "statics": [ 36 | { 37 | "description": "

A static helper method to add a svg element inside a node. Usually you don't need to use this directly. See methods in SVGForm instead.

", 38 | "name": "svgElement", 39 | "param": [ 40 | "

parent the parent node element, or null to use current <svg> as parent.

", 41 | "

name a string of element name, such as \"rect\" or \"circle\"

", 42 | "

id id attribute of the new element

" 43 | ], 44 | "pname": "parent, name, id" 45 | } 46 | ] 47 | } -------------------------------------------------------------------------------- /docs/json/core/Timer.json: -------------------------------------------------------------------------------- 1 | { 2 | "cls": "Timer", 3 | "description": "

Use a timer not to measure time, but to introduce rhythm. The conceptual hums of \"one two three, one two three\", when transfigured into patterns of sounds or words or dances, gives rise to various forms of aesthetic experiences. If time is a river, then timers are the mills we build along its banks.

", 4 | "extend": "", 5 | "file": "Timer.coffee", 6 | "funcs": [ 7 | { 8 | "description": "

Create a Timer

", 9 | "name": "Timer", 10 | "param": [ 11 | "

d duration of the timer in milliseconds

" 12 | ], 13 | "pname": "d=1000" 14 | }, 15 | { 16 | "description": "

Start or restart the timer

", 17 | "name": "start", 18 | "param": [ 19 | "

reset a boolean value to restart the timer from the beginning if set to true.

" 20 | ], 21 | "pname": "reset" 22 | }, 23 | { 24 | "description": "

Check % of time that has elapsed currently.

", 25 | "name": "check", 26 | "param": [], 27 | "pname": "", 28 | "return": "

a number between 0 to 1

" 29 | } 30 | ], 31 | "props": [], 32 | "statics": [] 33 | } -------------------------------------------------------------------------------- /docs/json/extend/Delaunay.json: -------------------------------------------------------------------------------- 1 | { 2 | "cls": "Delaunay", 3 | "description": "

Generate a set of triangles from a set of points, so that none of the points will be inside the circumcenter of any triangle.

", 4 | "extend": "PointSet", 5 | "file": "Delaunay.coffee", 6 | "funcs": [ 7 | { 8 | "description": "

Create a new Delaunay which extends PointSet. The generated results are stored in this.mesh.

", 9 | "eg": "

new Delaunay() new Delaunay(1,2,3) new Delaunay([2,4]) new Delaunay({x:3, y:6, z:9}).to(1,2,3) new Delaunay(1,2,3).to([p1, p2, p3, p4, p5])

", 10 | "name": "Delaunay", 11 | "param": [ 12 | "

args Similar to Point constructor, use comma-separated values, an array, or an object as parameters to specify the anchor point. Use to() to add points to the set.

" 13 | ], 14 | "pname": "", 15 | "return": "

a new Delaunay object

" 16 | }, 17 | { 18 | "description": "

Calculate delaunay triangulation and store the results in this.mesh array

", 19 | "name": "generate", 20 | "param": [], 21 | "pname": "", 22 | "return": "

an array of {i, j, k, triangle, circle} which records the indices of the vertices, and the calculated triangles and circumcircles

" 23 | } 24 | ], 25 | "props": [], 26 | "statics": [] 27 | } -------------------------------------------------------------------------------- /docs/json/extend/Easing.json: -------------------------------------------------------------------------------- 1 | { 2 | "cls": "Easing", 3 | "description": "

Simple easing functions based on Robert Penner's functions.

", 4 | "extend": "", 5 | "file": "Easing.coffee", 6 | "funcs": [], 7 | "props": [], 8 | "statics": [ 9 | { 10 | "description": "

Linear interpolation

", 11 | "name": "linear", 12 | "param": [ 13 | "

t current time or iteration

", 14 | "

b start value

", 15 | "

c change in value

", 16 | "

d duration time or total iteration

" 17 | ], 18 | "pname": "t, b, c, d", 19 | "return": "

interpolated value

" 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /docs/json/extend/GridCascade.json: -------------------------------------------------------------------------------- 1 | { 2 | "cls": "GridCascade", 3 | "description": "

(In progress) Like Grid, but expand the rows as needed to fit more items.

", 4 | "extend": "Grid", 5 | "file": "GridCascade.coffee", 6 | "funcs": [ 7 | { 8 | "description": "

Clear the layout and re-make the initial grid

simplified because rows are auto-expanded in fit()

", 9 | "name": "resetLayout", 10 | "param": [], 11 | "pname": "" 12 | }, 13 | { 14 | "description": "

Mark a certain area in the grid as occupied. This also checks for new rows, which is not checked in Grid

", 15 | "name": "occupy", 16 | "param": [ 17 | "

x column index

", 18 | "

y row index

", 19 | "

W column width

", 20 | "

h row size

" 21 | ], 22 | "pname": "x, y, w, h", 23 | "return": "

this grid

" 24 | }, 25 | { 26 | "description": "

optimize the iteration by starting at a row that has free cells

", 27 | "name": "findStartRow", 28 | "param": [], 29 | "pname": "" 30 | }, 31 | { 32 | "description": "

fit this area within the grid. This expands new rows to fit more items as needed.

", 33 | "name": "fit", 34 | "param": [ 35 | "

width number of columns

", 36 | "

height number of rows

" 37 | ], 38 | "pname": "cols, rows", 39 | "return": "

an object with properties row and column to specify the top left position, columnSize and rowSize to specify the resulting size in grid units, and bound which is the actual area as a Rectangle object.

" 40 | } 41 | ], 42 | "props": [], 43 | "statics": [] 44 | } -------------------------------------------------------------------------------- /docs/json/extend/Noise.json: -------------------------------------------------------------------------------- 1 | { 2 | "cls": "Noise", 3 | "description": "

Generate Perlin and Simplex2D noise.

", 4 | "extend": "Vector", 5 | "file": "Noise.coffee", 6 | "funcs": [ 7 | { 8 | "description": "

Generate a different noise by seeding

", 9 | "eg": "

noise.seed(0.1), noise.seed(Math.random())

", 10 | "name": "seed", 11 | "param": [ 12 | "

seed a value between 0 to 1

" 13 | ], 14 | "pname": "seed" 15 | }, 16 | { 17 | "description": "

Get a 2D perlin noise value. Increase the x and y parameters by a small amount (eg, 0.01) at each step to get a smooth noise.

", 18 | "eg": "

noise.perlin2D(), noise.perlin2D(10.001, 0.1)

", 19 | "name": "perlin2D", 20 | "param": [ 21 | "

x, y optional x and y dimension, or leave empty to use this vector's x and y position

" 22 | ], 23 | "pname": "xin=@x, yin=@y", 24 | "return": "

a value between 0 to 1

" 25 | }, 26 | { 27 | "description": "

Get a 2D simplex noise value. Increase the x and y parameters by a small amount (eg, 0.01) at each step to get a smooth noise.

", 28 | "eg": "

noise.simplex2D(), noise.simplex2D(10.001, 0.1)

", 29 | "name": "simplex2D", 30 | "param": [ 31 | "

x, y optional x and y dimension, or leave empty to use this vector's x and y position

" 32 | ], 33 | "pname": "xin=@x, yin=@y", 34 | "return": "

a value between -1 to 1

" 35 | } 36 | ], 37 | "props": [], 38 | "statics": [] 39 | } -------------------------------------------------------------------------------- /docs/json/extend/ParticleEmitter.json: -------------------------------------------------------------------------------- 1 | { 2 | "cls": "ParticleEmitter", 3 | "description": "

(In progress) A very basic particle emitter

", 4 | "extend": "Vector", 5 | "file": "ParticleEmitter.coffee", 6 | "funcs": [ 7 | { 8 | "description": "

Constructor

", 9 | "name": "ParticleEmitter", 10 | "param": [], 11 | "pname": "" 12 | }, 13 | { 14 | "description": "

Initiate with an instance of a ParticleSystem

", 15 | "name": "init", 16 | "param": [], 17 | "pname": "system" 18 | }, 19 | { 20 | "description": "

Set frequency of emisson.

", 21 | "name": "frequency", 22 | "param": [ 23 | "

f how many per second.

" 24 | ], 25 | "pname": "f" 26 | }, 27 | { 28 | "description": "

emit a particle (abstract method)

", 29 | "name": "emit", 30 | "param": [], 31 | "pname": "" 32 | }, 33 | { 34 | "description": "

animate function to be called by Space

", 35 | "name": "animate", 36 | "param": [], 37 | "pname": "time, frame, ctx" 38 | } 39 | ], 40 | "props": [], 41 | "statics": [] 42 | } -------------------------------------------------------------------------------- /docs/json/extend/ParticleField.json: -------------------------------------------------------------------------------- 1 | { 2 | "cls": "ParticleField", 3 | "description": "

(In progress) An area that influence force, velocity, etc of particles inside it

", 4 | "extend": "Rectangle", 5 | "file": "ParticleField.coffee", 6 | "funcs": [ 7 | { 8 | "description": "

check particles to work on

", 9 | "name": "check", 10 | "param": [ 11 | "

{particles} array of particles

", 12 | "

{removal} if true and if particle within bound, then remove it from array

" 13 | ], 14 | "pname": "particles, removal=false" 15 | }, 16 | { 17 | "description": "

apply the changes to a particle (abstract method), used in check()

", 18 | "name": "work", 19 | "param": [ 20 | "

{p} a particle

" 21 | ], 22 | "pname": "p" 23 | } 24 | ], 25 | "props": [], 26 | "statics": [] 27 | } -------------------------------------------------------------------------------- /docs/json/extend/QuadTree.json: -------------------------------------------------------------------------------- 1 | { 2 | "cls": "QuadTree", 3 | "description": "

A basic quad tree implementation

", 4 | "extend": "Rectangle", 5 | "file": "QuadTree.coffee", 6 | "funcs": [ 7 | { 8 | "description": "

Create a new QuadTree, which is a kind of Rectangle

", 9 | "name": "QuadTree", 10 | "param": [], 11 | "pname": "" 12 | }, 13 | { 14 | "description": "

Get a list of quads in which this point is contained

", 15 | "name": "getQuads", 16 | "param": [ 17 | "

p is a Point

", 18 | "

list Optional existing list to append to

" 19 | ], 20 | "pname": "p, list=[]" 21 | }, 22 | { 23 | "description": "

Get a list of items in this point's deepest quad

", 24 | "name": "getItems", 25 | "param": [ 26 | "

p a Point

" 27 | ], 28 | "pname": "p" 29 | }, 30 | { 31 | "description": "

Add an item into this QuadTree. Split to sub quads if needed.

", 32 | "name": "addToQuad", 33 | "param": [], 34 | "pname": "item" 35 | }, 36 | { 37 | "description": "

Split this into 4 quads using Rectangle's quadrant()

", 38 | "name": "splitQuad", 39 | "param": [], 40 | "pname": "" 41 | }, 42 | { 43 | "description": "

reset this quad, removing items and sub-quads

", 44 | "name": "resetQuad", 45 | "param": [], 46 | "pname": "" 47 | } 48 | ], 49 | "props": [], 50 | "statics": [] 51 | } -------------------------------------------------------------------------------- /docs/json/extend/SVGSpace.json: -------------------------------------------------------------------------------- 1 | { 2 | "cls": "SVGSpace", 3 | "description": "

SVGSpace is an extension of DOMSpace that represents an svg element in DOM. Also refers to DOMSpace for inherited methods.

", 4 | "extend": "DOMSpace", 5 | "file": "SVGSpace.coffee", 6 | "funcs": [ 7 | { 8 | "description": "

Create a SVGSpace which represents a svg element

", 9 | "name": "SVGSpace", 10 | "param": [ 11 | "

id an optional string which refers to the \"id\" attribute of a DOM element. It can either refer to an existing <svg>, or a <div> container in which a new <svg> will be created. If left empty, a <div id=\"pt\"><svg id=\"pt_svg\" /></div> will be added to DOM. Use css to customize its appearance if needed.

", 12 | "

callback an optional callback function(boundingBox, spaceElement) to be called when element is appended and ready. A \"ready\" event will also be fired from the space's element when it's appended, which can be tracked with spaceInstance.space.addEventListener(\"ready\")

" 13 | ], 14 | "pname": "id, callback" 15 | }, 16 | { 17 | "demo": "svgspace.remove", 18 | "description": "

Remove an item from this Space

", 19 | "name": "remove", 20 | "param": [ 21 | "

an object with an auto-assigned animateID property

" 22 | ], 23 | "pname": "item", 24 | "return": "

this space

" 25 | }, 26 | { 27 | "description": "

Remove all items from this Space

", 28 | "name": "removeAll", 29 | "param": [], 30 | "pname": "", 31 | "return": "

this space

" 32 | } 33 | ], 34 | "props": [], 35 | "statics": [ 36 | { 37 | "description": "

A static helper method to add a svg element inside a node. Usually you don't need to use this directly. See methods in SVGForm instead.

", 38 | "name": "svgElement", 39 | "param": [ 40 | "

parent the parent node element, or null to use current <svg> as parent.

", 41 | "

name a string of element name, such as \"rect\" or \"circle\"

", 42 | "

id id attribute of the new element

" 43 | ], 44 | "pname": "parent, name, id" 45 | } 46 | ] 47 | } -------------------------------------------------------------------------------- /docs/json/extend/SamplePoints.json: -------------------------------------------------------------------------------- 1 | { 2 | "cls": "SamplePoints", 3 | "description": "

Point sampling using Best Candidate and Poisson methods.

", 4 | "extend": "PointSet", 5 | "file": "SamplePoints.coffee", 6 | "funcs": [ 7 | { 8 | "description": "

Construct a point sampler

", 9 | "name": "SamplePoints", 10 | "param": [], 11 | "pname": "" 12 | }, 13 | { 14 | "description": "

Add a bound.

", 15 | "name": "setBounds", 16 | "param": [ 17 | "

b the bounding box

", 18 | "

anchor a boolean value. If set to true, then current position is set to bound's position

" 19 | ], 20 | "pname": "b, anchor=false", 21 | "return": "

this sampler

" 22 | }, 23 | { 24 | "description": "

Initiate a best candidate sampler

", 25 | "name": "bestCandidateSampler", 26 | "param": [], 27 | "pname": "", 28 | "return": "

this sampler

" 29 | }, 30 | { 31 | "description": "

Initiate a poisson sampler using Bridson's algorithm

Based on http://bl.ocks.org/mbostock/19168c663618b7f07158

", 32 | "name": "poissonSampler", 33 | "param": [], 34 | "pname": "radius", 35 | "return": "

this sampler

" 36 | }, 37 | { 38 | "description": "

Get a sample from poisson sampler or best-candidate sampler.

", 39 | "name": "sample", 40 | "param": [ 41 | "

numSamples number of times to sample. Defaults to 10 times

", 42 | "

type sampling type, either \"poisson\" or \"bestcandidate\". Defaults to \"bestcandidate\".

" 43 | ], 44 | "pname": "numSamples=10, type=false", 45 | "return": "

a point, or false if no more sample can be found

" 46 | } 47 | ], 48 | "props": [], 49 | "statics": [ 50 | { 51 | "description": "

A static implementation of Mitchell's Best Neighor Algorithm to generate one sample. (Consider using SamplePoints object instead)

", 52 | "name": "bestCandidate", 53 | "param": [ 54 | "

bound a Rectangle object to specify the bounding box

", 55 | "

items an array of existing items

", 56 | "

samples number of sampling. Default to 10.

" 57 | ], 58 | "pname": "bound, items, samples=10", 59 | "return": "

o Vector object which is best candidate

" 60 | } 61 | ] 62 | } -------------------------------------------------------------------------------- /docs/json/extend/StripeBound.json: -------------------------------------------------------------------------------- 1 | { 2 | "cls": "StripeBound", 3 | "description": "

A Bound subdivided in horizontal and vertical stripes

", 4 | "extend": "Rectangle", 5 | "file": "StripeBound.coffee", 6 | "funcs": [ 7 | { 8 | "description": "

Determines the number of stripes by frequency, and change method to frequency

", 9 | "name": "setFrequency", 10 | "param": [], 11 | "pname": "x, y" 12 | }, 13 | { 14 | "description": "

Set number of strips by number, and change method to stripes

", 15 | "name": "setStripes", 16 | "param": [], 17 | "pname": "x, y" 18 | }, 19 | { 20 | "description": "

get stripes as boxes

", 21 | "name": "getStripes", 22 | "param": [], 23 | "pname": "", 24 | "return": "

boxes of {columns:[Pairs], rows:[Pairs]}

" 25 | }, 26 | { 27 | "description": "

get stripes as lines

", 28 | "name": "getStripeLines", 29 | "param": [], 30 | "pname": "", 31 | "return": "

lines of {columns:[Pairs], rows:[Pairs]}

" 32 | }, 33 | { 34 | "description": "

create a masking area for canvas clipping. Defaults to position in the center of the bound, unless anchor paramater is set

", 35 | "name": "setMask", 36 | "param": [ 37 | "

w, h mask width and height

", 38 | "

anchor optional anchor point, or leave unset to default anchor position which is center of the bound.

" 39 | ], 40 | "pname": "w, h, anchor=false" 41 | }, 42 | { 43 | "description": "

anchor mask to bound's origin position

", 44 | "name": "anchorMask", 45 | "param": [], 46 | "pname": "" 47 | } 48 | ], 49 | "props": [], 50 | "statics": [] 51 | } -------------------------------------------------------------------------------- /docs/json/extend/UI.json: -------------------------------------------------------------------------------- 1 | { 2 | "cls": "UI", 3 | "description": "

(In progress) A simple handle that can be dragged by mouse

", 4 | "extend": "Rectangle", 5 | "file": "UI.coffee", 6 | "funcs": [], 7 | "props": [], 8 | "statics": [] 9 | } -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/favicon.ico -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ptjs", 3 | "version": "0.2.4", 4 | "description": "An experimental library based on the ideas of Point, Form, and Space", 5 | "author": "William Ngan", 6 | "devDependencies": { 7 | "event-stream": "^3.3.0", 8 | "gulp": "^3.8.10", 9 | "gulp-util": "^3.0.1", 10 | "gulp-concat": "^2.4.3", 11 | "gulp-rename": "^1.2.0", 12 | "gulp-insert": "^0.4.0", 13 | "gulp-uglify": "^1.0.2", 14 | "gulp-sourcemaps": "^1.5.2", 15 | "gulp-coffee": "^2.2.0", 16 | "gulp-babel": "^5.2.0", 17 | "run-sequence": "^1.2.2" 18 | }, 19 | "main": "dist/module/pt.js", 20 | "directories": { 21 | "doc": "docs", 22 | "test": "test" 23 | }, 24 | "dependencies": {}, 25 | "scripts": { 26 | "test": "echo \"Error: no test specified\" && exit 1" 27 | }, 28 | "repository": { 29 | "type": "git", 30 | "url": "https://github.com/williamngan/pt.git" 31 | }, 32 | "keywords": [ 33 | "graphics", 34 | "canvas", 35 | "svg" 36 | ], 37 | "license": "Apache", 38 | "bugs": { 39 | "url": "https://github.com/williamngan/pt/issues" 40 | }, 41 | "homepage": "https://github.com/williamngan/pt" 42 | } 43 | -------------------------------------------------------------------------------- /src/coffee/core/Const.coffee: -------------------------------------------------------------------------------- 1 | # ### A list of useful constant values for calculations and labeling. 2 | class Const 3 | 4 | # ## represents the xy plane 5 | @xy = 'xy' 6 | 7 | # ## represents the yz plane 8 | @yz = 'yz' 9 | 10 | # ## reporesents the xz plane 11 | @xz = 'xz' 12 | 13 | # ## represents xyz space 14 | @xyz = 'xyz' 15 | 16 | # ## represents identical point or value 17 | @identical = -1 18 | 19 | # ## represents right position or direction 20 | @right = 3 21 | 22 | # ## represents bottom right position or direction 23 | @bottom_right = 4 24 | 25 | # ## represents bottom position or direction 26 | @bottom = 5 27 | 28 | # ## represents bottom left position or direction 29 | @bottom_left = 6 30 | 31 | # ## represents left position or direction 32 | @left = 7 33 | 34 | # ## represents top left position or direction 35 | @top_left = 0 36 | 37 | # ## represents top position or direction 38 | @top = 1 39 | 40 | # ## represents top right position or direction 41 | @top_right = 2 42 | 43 | # ## an array of strings to label position constants above. Eg, `Const.sideLabels[ Const.top_left]` will return the string "top left" 44 | @sideLabels = ["identical", "right", "bottom right", "bottom", "bottom left", "left", "top left", "top", "top right"] 45 | 46 | # ## represents an arbitrary very small number. It is set as 0.0001 here. 47 | @epsilon = 0.0001 48 | 49 | # ## pi radian (180 deg) 50 | @pi = Math.PI 51 | 52 | # ## two pi radian (360deg) 53 | @two_pi = 6.283185307179586 54 | 55 | # ## half pi radian (90deg) 56 | @half_pi = 1.5707963267948966 57 | 58 | # ## pi/4 radian (45deg) 59 | @quarter_pi = 0.7853981633974483 60 | 61 | # ## pi/180 = 1 degree in radian 62 | @one_degree = 0.017453292519943295 63 | 64 | # ## multiply this constant with a radian to get a degree 65 | @rad_to_deg = 57.29577951308232 66 | 67 | # ## multiply this constant with a degree to get a radian 68 | @deg_to_rad = 0.017453292519943295 69 | 70 | # ## Gravity acceleration (unit = m/s^2) and gravity force (unit = Newton) on 1kg of mass. 71 | @gravity = 9.81 72 | 73 | # ## 1 Newton = 0.10197 Kilogram-force 74 | @newton = 0.10197 75 | 76 | # ## Gaussian constant (1 / Math.sqrt(2 * Math.PI)) 77 | @gaussian = 0.3989422804014327 78 | 79 | 80 | 81 | # namespace 82 | this.Const = Const -------------------------------------------------------------------------------- /src/coffee/core/ParticleSystem.coffee: -------------------------------------------------------------------------------- 1 | # ### A particle system keeps track of particles, and regulate them with rules specific to a system. It can also hold constant values from gravitational to cosmic, and specify whether a god may play dice here. 2 | class ParticleSystem 3 | 4 | # ## Create a ParticleSystem to track a set of particles 5 | constructor : () -> 6 | 7 | # ## a property to store particles in this system as an Array 8 | @count = 0 9 | @particles = [] 10 | 11 | # ## a property to track time in milliseconds 12 | @time = 0 13 | 14 | # @animateID = -1 15 | 16 | 17 | # ## add a particle to the system 18 | # @param `particle` a Particle 19 | # @return this system 20 | add : ( particle ) -> 21 | particle.id = @count++ 22 | @particles.push( particle ) 23 | return @ 24 | 25 | 26 | # ## remove a particle which has a `particle.life` property. This marks the `particle.life.complete` as `true` for removal in next cycle. 27 | # @param `particle` a Particle 28 | # @return this system 29 | remove: (particle) -> 30 | if particle and particle.life then particle.life.complete = true 31 | return @ 32 | 33 | 34 | # ## animate callback function which is called by` Space.play()`. Override this callback function to specify other animation loops 35 | # @param `time, frame, ctx` parameters for current time, fps, and rendering context, which will be passed by `Space` in callback 36 | animate : ( time, frame, ctx ) -> 37 | @time++ 38 | 39 | _remove = []; # to be removed 40 | 41 | for p, i in @particles 42 | 43 | # if life is complete, mark for removal 44 | if p.life.complete 45 | _remove.push( i ) 46 | 47 | # if active, animate it 48 | else if p.life.active 49 | p.animate( time, frame, ctx ) 50 | 51 | # remove completed particles 52 | if _remove.length > 0 53 | for index in _remove 54 | @particles.splice(index, 1) 55 | 56 | 57 | 58 | # namespace 59 | this.ParticleSystem = ParticleSystem 60 | 61 | -------------------------------------------------------------------------------- /src/coffee/core/SVGSpace.coffee: -------------------------------------------------------------------------------- 1 | # ### SVGSpace is an extension of DOMSpace that represents an svg element in DOM. Also refers to DOMSpace for inherited methods. 2 | class SVGSpace extends DOMSpace 3 | 4 | # ## Create a SVGSpace which represents a svg element 5 | # @param `id` Specify an element by its "id" attribute as string, or by the element object itself. An element can be an existing ``, or a `
` container in which a new `` will be created. If left empty, a `
` will be added to DOM. Use css to customize its appearance if needed. 6 | # @param `callback` an optional callback `function(boundingBox, spaceElement)` to be called when element is appended and ready. A "ready" event will also be fired from the space's element when it's appended, which can be tracked with `spaceInstance.space.addEventListener("ready")` 7 | constructor: ( id, callback ) -> 8 | super( id, callback, 'svg') 9 | 10 | if @space.nodeName.toLowerCase() != "svg" 11 | s = @_createElement("svg", @id+"_svg" ) 12 | @space.appendChild( s ) 13 | @bound = @space 14 | @space = s 15 | 16 | # size is known so set it immediately 17 | b = @bound.getBoundingClientRect() 18 | @resize( b.width, b.height ) 19 | 20 | 21 | 22 | # A private function to create the svg namespaced element. This will create a if elem parameter is not set. 23 | _createElement: ( elem="svg", id ) -> 24 | d = document.createElementNS( "http://www.w3.org/2000/svg", elem ) 25 | if (id) then d.setAttribute("id", id ) 26 | return d 27 | 28 | 29 | # ## A static helper method to add a svg element inside a node. Usually you don't need to use this directly. See methods in `SVGForm` instead. 30 | # @param `parent` the parent node element, or `null` to use current `` as parent. 31 | # @param `name` a string of element name, such as `"rect"` or `"circle"` 32 | # @param `id` id attribute of the new element 33 | @svgElement: (parent, name, id) -> 34 | 35 | if (!parent || !parent.appendChild) 36 | parent = @space 37 | if !parent then throw( "parent parameter needs to be a DOM node" ) 38 | 39 | elem = document.querySelector("#"+id); 40 | 41 | if (!elem) 42 | elem = document.createElementNS( "http://www.w3.org/2000/svg", name) 43 | elem.setAttribute("id",id) 44 | elem.setAttribute("class",id.substring(0, id.indexOf("-"))) 45 | parent.appendChild( elem ) 46 | 47 | return elem 48 | 49 | 50 | # ## Remove an item from this Space 51 | # @param an object with an auto-assigned `animateID` property 52 | # @demo svgspace.remove 53 | # @return this space 54 | remove : (item) -> 55 | temp = @space.querySelectorAll( "."+SVGForm._scopeID(item) ) 56 | 57 | for t in temp 58 | t.parentNode.removeChild(t) 59 | 60 | delete @items[ item.animateID ] 61 | return @ 62 | 63 | 64 | # ## Remove all items from this Space 65 | # @return this space 66 | removeAll: () -> 67 | while (@space.firstChild) 68 | @space.removeChild(@space.firstChild) 69 | return @ 70 | 71 | 72 | # namescape 73 | this.SVGSpace = SVGSpace -------------------------------------------------------------------------------- /src/coffee/core/Timer.coffee: -------------------------------------------------------------------------------- 1 | # ### Use a timer not to measure time, but to introduce rhythm. The conceptual hums of "one two three, one two three", when transfigured into patterns of sounds or words or dances, gives rise to various forms of aesthetic experiences. If time is a river, then timers are the mills we build along its banks. 2 | class Timer 3 | 4 | # ## Create a Timer 5 | # @param `d` duration of the timer in milliseconds 6 | constructor: ( d=1000 ) -> 7 | @duration = d 8 | @_time = 0 9 | @_ease = (t,b,c,d) -> t/d 10 | @_intervalID = -1 11 | 12 | 13 | # ## Start or restart the timer 14 | # @param `reset` a boolean value to restart the timer from the beginning if set to `true`. 15 | start: (reset) -> 16 | diff = Math.min( Date.now() - @_time, @duration) 17 | 18 | if reset or diff >= @duration 19 | @_time = Date.now() 20 | 21 | 22 | # set an easing function to use in `check()`. See `Easing` class for a set of predefined easing functions 23 | # @param `ease` an easing function with 4 parameters `(current_time, start_value, change_in_value, duration_time)` and must return a number between 0 to 1 24 | setEasing: (ease) -> 25 | @_ease = ease 26 | 27 | 28 | # ## Check % of time that has elapsed currently. 29 | # @return a number between 0 to 1 30 | check: () -> 31 | diff = Math.min( Date.now() - @_time, @duration) 32 | return @_ease( diff, 0, 1, @duration ) 33 | 34 | 35 | # Track time (using `setInterval()`) 36 | # @param `callback` a callback function which may include a `(t)` parameter to get current elapsed percentage (value between 0 to 1) 37 | # @return the intervalID from `setInterval()` 38 | track: ( callback ) -> 39 | clearInterval( @_intervalID ) 40 | @start(true) 41 | me = @ 42 | @_intervalID = setInterval( ( () -> 43 | t = me.check() 44 | callback( t ) 45 | if t >= 1 then clearInterval( me._intervalID ) 46 | ), 25 ) 47 | return @_intervalID 48 | 49 | 50 | 51 | # namespace 52 | this.Timer = Timer -------------------------------------------------------------------------------- /src/coffee/extend/ParticleEmitter.coffee: -------------------------------------------------------------------------------- 1 | # ### (In progress) A very basic particle emitter 2 | class ParticleEmitter extends Vector 3 | 4 | # ## Constructor 5 | constructor: ( ) -> 6 | super 7 | 8 | @system = null 9 | @lastTime = 0 10 | @period = 0 11 | @animateID = -1 # for Space loop 12 | 13 | # ## Initiate with an instance of a `ParticleSystem` 14 | init: ( system ) -> 15 | @system = system 16 | 17 | # ## Set frequency of emisson. 18 | # @param `f` how many per second. 19 | frequency: (f) -> 20 | @period = 1000 / f 21 | return @ 22 | 23 | # ## emit a particle (abstract method) 24 | emit: -> 25 | # override to define an emitter function 26 | # e.g @system.add( new Particle( @position ) ) 27 | 28 | # ## animate function to be called by Space 29 | animate: ( time, frame, ctx ) -> 30 | if time - @lastTime > @period 31 | @emit() 32 | @lastTime = time 33 | 34 | 35 | # namespace 36 | this.ParticleEmitter = ParticleEmitter -------------------------------------------------------------------------------- /src/coffee/extend/ParticleField.coffee: -------------------------------------------------------------------------------- 1 | # ### (In progress) An area that influence force, velocity, etc of particles inside it 2 | class ParticleField extends Rectangle 3 | 4 | constructor: ()-> 5 | super 6 | @system = undefined 7 | 8 | # ## check particles to work on 9 | # @param {particles} array of particles 10 | # @param {removal} if true and if particle within bound, then remove it from array 11 | check: (particles, removal=false) -> 12 | temp = [] 13 | for p in particles 14 | if @hasIntersect( p ) # within 15 | @work( p ) 16 | else 17 | temp.push( p ) 18 | 19 | return ( if removal then temp else particles ) 20 | 21 | # ## apply the changes to a particle (abstract method), used in check() 22 | # @param {p} a particle 23 | work: (p) -> 24 | 25 | 26 | 27 | 28 | # namespace 29 | this.ParticleField = ParticleField -------------------------------------------------------------------------------- /src/coffee/extend/QuadTree.coffee: -------------------------------------------------------------------------------- 1 | # ### A basic quad tree implementation 2 | class QuadTree extends Rectangle 3 | 4 | # ## Create a new QuadTree, which is a kind of Rectangle 5 | constructor: () -> 6 | super 7 | 8 | # when split, this is an object with topLeft, topRight, bottomLeft, and bottomRight 9 | @quads = false 10 | 11 | @items = [] 12 | 13 | @depth = 0 14 | @max_depth = 6 15 | @max_items = 2 16 | 17 | 18 | # ## Get a list of quads in which this point is contained 19 | # @param `p` is a Point 20 | # @param `list` Optional existing list to append to 21 | getQuads: ( p, list=[] ) -> 22 | 23 | if @intersectPoint( p ) 24 | 25 | list.push( @ ) 26 | 27 | if @quads 28 | for k, q of @quads 29 | if q.intersectPoint( p ) 30 | q.getQuads( p, list ) 31 | 32 | return list 33 | 34 | # ## Get a list of items in this point's deepest quad 35 | # @param `p` a Point 36 | getItems: ( p ) -> 37 | 38 | if @intersectPoint( p ) 39 | 40 | if !@quads then return @items 41 | 42 | if @quads 43 | for k, q of @quads 44 | if q.intersectPoint( p ) 45 | return q.getItems( p ) 46 | 47 | return [] 48 | 49 | # ## Add an item into this QuadTree. Split to sub quads if needed. 50 | addToQuad: (item) -> 51 | 52 | if !item then return -1 53 | 54 | # if this has subs quads 55 | if @quads 56 | for k, q of @quads 57 | _depth = q.addToQuad( item ) 58 | if _depth > 0 then return _depth # return depth if it's added 59 | 60 | # otherwise return -1 61 | return -1 62 | 63 | # if this has no sub quads and it contains item 64 | if !@quads and @intersectPoint( item ) 65 | 66 | # if max size is reached and depth is not max, then split to sub quads 67 | if @items.length >= @max_items 68 | if @depth < @max_depth 69 | @splitQuad() 70 | return @addToQuad( item ) 71 | else 72 | return -1 73 | 74 | # if not max size yet, just add item and return current depth 75 | else 76 | @items.push( item ) 77 | return @depth 78 | 79 | # not contained in this quad 80 | return -1 81 | 82 | 83 | # ## Split this into 4 quads using Rectangle's `quadrant()` 84 | splitQuad: () -> 85 | 86 | # split to sub quads and increment depth 87 | @quads = @quadrants() 88 | for k, q of @quads 89 | q.depth = @depth+1 90 | 91 | # add current items to sub quads 92 | for item, i in @items 93 | _depth = @addToQuad( item ) 94 | 95 | # if it's added to sub quads, mark for removal 96 | if _depth > @depth 97 | @items[i] = null 98 | 99 | # remove items that are marked null 100 | for t in @items 101 | if !t 102 | @items.splice( t, 1 ) 103 | 104 | 105 | # ## reset this quad, removing items and sub-quads 106 | resetQuad: () -> 107 | @items = [] 108 | if @quads 109 | for k, q of @quads 110 | q.resetQuad() 111 | @quads = false 112 | 113 | 114 | 115 | # namespace 116 | this.QuadTree = QuadTree -------------------------------------------------------------------------------- /src/coffee/extend/StripeBound.coffee: -------------------------------------------------------------------------------- 1 | # ### A Bound subdivided in horizontal and vertical stripes 2 | class StripeBound extends Rectangle 3 | 4 | constructor: () -> 5 | super 6 | 7 | @frequency = new Point() 8 | @stripes = new Point() 9 | @method = 'frequency' 10 | 11 | @mask = null 12 | 13 | # ## Determines the number of stripes by frequency, and change method to frequency 14 | setFrequency: (x, y) -> 15 | @frequency = new Vector(x, y) 16 | @method = 'frequency' 17 | 18 | 19 | # ## Set number of strips by number, and change method to stripes 20 | setStripes: (x, y) -> 21 | @stripes = new Point(x,y) 22 | @method = 'stripes' 23 | 24 | 25 | # ## get stripes as boxes 26 | # @return boxes of `{columns:[Pairs], rows:[Pairs]}` 27 | getStripes: () -> 28 | size = @size() 29 | result = {columns: [], rows: []} 30 | 31 | # calculate frequency and spacing 32 | freq = if @method == 'frequency' then @frequency.clone() else size.$divide( @stripes ).floor() 33 | diff = size.$divide( freq ) 34 | 35 | # rows 36 | for d in [0..freq.y-1] 37 | dy = diff.y*d 38 | p = new Pair(0, dy).to(size.x, dy+diff.y).add(@) 39 | p.p1.add(@) 40 | result.rows.push( p ) 41 | 42 | # columns 43 | for d in [0..freq.x-1] 44 | dx = diff.x*d 45 | p = new Pair(dx, 0).to(dx+diff.x+0.5, size.y).add(@) 46 | p.p1.add(@) 47 | result.columns.push( p ) 48 | 49 | return result 50 | 51 | # ## get stripes as lines 52 | # @return lines of `{columns:[Pairs], rows:[Pairs]}` 53 | getStripeLines: () -> 54 | size = @size() 55 | result = {columns: [], rows: []} 56 | 57 | # calculate frequency and spaci ng 58 | freq = if @method == 'frequency' then @frequency.clone() else size.$divide( @stripes ).floor() 59 | diff = size.$divide( freq ) 60 | 61 | # rows 62 | for d in [0..freq.y] 63 | dy = diff.y*d 64 | p = new Pair(0, dy).to(size.x, dy).add(@) 65 | p.p1.add(@) 66 | result.rows.push( p ) 67 | 68 | # columns 69 | for d in [0..freq.x] 70 | dx = diff.x*d 71 | p = new Pair(dx, 0).to(dx, size.y).add(@) 72 | p.p1.add(@) 73 | result.columns.push( p ) 74 | 75 | return result 76 | 77 | 78 | # ## create a masking area for canvas clipping. Defaults to position in the center of the bound, unless anchor paramater is set 79 | # @param `w, h` mask width and height 80 | # @param `anchor` optional anchor point, or leave unset to default anchor position which is center of the bound. 81 | setMask: (w, h, anchor=false) -> 82 | @mask = new Rectangle(@x, @y) 83 | sz = @size() 84 | 85 | # center it if no anchor point is set 86 | if !anchor 87 | diff = sz.$subtract( w, h ).divide(2) 88 | anchor = new Point(@x+diff.x, @y+diff.y) 89 | else 90 | anchor = @.$add(anchor) 91 | 92 | # position and set size 93 | @mask.set( anchor.x, anchor.y).size(w, h) 94 | 95 | 96 | # ## anchor mask to bound's origin position 97 | anchorMask: () -> 98 | d = @.$subtract( @mask) 99 | @.moveBy(d) 100 | @mask.moveBy(d) 101 | 102 | # namespace 103 | this.StripeBound = StripeBound -------------------------------------------------------------------------------- /src/coffee/extend/UI.coffee: -------------------------------------------------------------------------------- 1 | # ### (In progress) A simple handle that can be dragged by mouse 2 | class UI extends Rectangle 3 | 4 | # class variable tracks if a handle has been dragged (to avoid dragging multiple handles at once) 5 | @dragTarget: null 6 | 7 | constructor: () -> 8 | super 9 | @dragging = false 10 | 11 | animate : (time, frame, ctx) -> 12 | ctx.fillStyle = '#f00' 13 | Form.rect( ctx, this ) 14 | 15 | onMouseAction: (type, x, y, evt) -> 16 | if @intersectPoint( x, y ) 17 | if type == 'drag' and !UI.dragTarget 18 | @dragging = true 19 | UI.dragTarget = this 20 | 21 | if @dragging and type == 'move' 22 | @moveTo(x,y).moveBy( @size().multiply(-0.5) ) # move and anchor by center point 23 | 24 | if type == 'drop' 25 | @dragging = false 26 | UI.dragTarget = null 27 | 28 | 29 | # namespace 30 | this.UI = UI -------------------------------------------------------------------------------- /test/lib/jasmine-1.2.0/._MIT.LICENSE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/test/lib/jasmine-1.2.0/._MIT.LICENSE -------------------------------------------------------------------------------- /test/lib/jasmine-1.2.0/._jasmine-html.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/test/lib/jasmine-1.2.0/._jasmine-html.js -------------------------------------------------------------------------------- /test/lib/jasmine-1.2.0/._jasmine.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/test/lib/jasmine-1.2.0/._jasmine.css -------------------------------------------------------------------------------- /test/lib/jasmine-1.2.0/._jasmine.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/williamngan/pt/52fee535c10fd2e39dbef612c8a888e0b4c66a7d/test/lib/jasmine-1.2.0/._jasmine.js -------------------------------------------------------------------------------- /test/lib/jasmine-1.2.0/MIT.LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008-2011 Pivotal Labs 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /test/spec_core.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Jasmine Spec Runner 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | --------------------------------------------------------------------------------