diff --git a/Gulpfile.js b/Gulpfile.js index 21d75cd..0b1cec3 100644 --- a/Gulpfile.js +++ b/Gulpfile.js @@ -29,10 +29,10 @@ var exec = require('child_process').exec; var buildDirectory = 'build'; var server; -gulp.task('default', ['build:dev', 'build:examples']); +gulp.task('default', ['build:dev']); gulp.task('dev', function(callback) { - sequence('build:examples', 'watch', 'serve', callback); + sequence('watch', 'serve', callback); }); gulp.task('release', function(callback) { @@ -43,7 +43,7 @@ gulp.task('release', function(callback) { message: 'cannot build release as there are uncomitted changes' }); } else { - sequence('build:examples', 'test', 'bump', 'reload', 'build:release', 'doc', 'changelog', callback); + sequence('test', 'bump', 'reload', 'build:release', 'doc', 'changelog', callback); } }); }); @@ -95,12 +95,6 @@ gulp.task('build:release', function() { return build(extend(extend({}, pkg), { version: pkg.version })); }); -gulp.task('build:examples', function() { - return gulp.src('examples/**/*.js') - .pipe(concat('Examples.js')) - .pipe(gulp.dest('demo/js')); -}); - gulp.task('watch', function() { var b = browserify({ entries: ['src/module/main.js'], @@ -123,8 +117,6 @@ gulp.task('watch', function() { b.on('update', bundle); bundle(); - - gulp.watch('examples/**/*.js', ['build:examples']); }); gulp.task('bump', function() { diff --git a/demo/css/style.css b/demo/css/style.css deleted file mode 100644 index 067244e..0000000 --- a/demo/css/style.css +++ /dev/null @@ -1,131 +0,0 @@ -body { - background: #222; - font-family: Georgia, Times, "Times New Roman", serif; - color: #aaa; -} - -body.mobile { - font-size: 0.9em; -} - -* { - padding: 0; - margin: 0; -} - -h1 { - color: #fff; - display: block; - margin: 0 0 1em 0; - font-weight: normal; - font-size: 30px; -} - -.is-mobile h1 { - font-size: 18px; -} - -.nav-sep { - padding: 0 5px; -} - -.nav-links a, -.nav-links a:link, -.nav-links a:visited, -.nav-links a:active, -.nav-links a:hover { - color: #aaa; - text-decoration: none; - border-bottom: 1px solid #555; - padding: 0 0 2px 0; -} - -.container { - max-width: 800px; - margin: 0 auto; - padding: 48px 280px 0 32px; -} - -.ins-auto-hide .container { - padding-left: 32px; -} - -.gui-auto-hide .container { - padding-right: 32px; -} - -.is-mobile .container { - padding: 6% 6% 0 6%; -} - -.is-fullscreen #canvas-container { - width: 100%; - height: 100%; -} - -.is-fullscreen #canvas-container canvas { - margin: 0; - max-width: 100%; - max-height: 100%; -} - -.mobile .container { - padding: 50px 40px 0 40px; -} - -canvas { - margin: 40px 0; - max-width: 100%; -} - -.mobile canvas { - margin: 0; -} - -canvas:active { - cursor: pointer; - cursor: -webkit-grabbing; -} - -.controls-container { - margin: 40px 0 0 0; - width: 100%; -} - -#canvas-container { - margin: 20px 0; -} - -#demo-select { - padding: 8px 10px; - width: 40%; - color: #000; -} - -#demo-reset { - padding: 8px 10px; - color: #000; -} - -#demo-start { - display: block; - margin: 50px 0; - padding: 20px 40px; - width: 200px; - color: #000; -} - -.demo-view-source { - display: inline-block; - margin: 0 0 0 22px; - font-size: 13px; - opacity: 0.5; -} - -.dg.a { - margin-right: 0; -} - -svg { - display: none; -} \ No newline at end of file diff --git a/demo/index.html b/demo/index.html index 9029700..37074e3 100644 --- a/demo/index.html +++ b/demo/index.html @@ -1,91 +1,90 @@ - - - - - - + + + + + + + + + + - - + Matter.js Demo + + + + - - + + - - + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + \ No newline at end of file diff --git a/demo/js/Demo.js b/demo/js/Demo.js index 0dde0d7..f7e8751 100644 --- a/demo/js/Demo.js +++ b/demo/js/Demo.js @@ -7,370 +7,276 @@ */ (function() { + var sourceLinkRoot = 'https://github.com/liabru/matter-js/blob/master/examples'; - var _isBrowser = typeof window !== 'undefined' && window.location, - _useInspector = _isBrowser && window.location.hash.indexOf('-inspect') !== -1, - _isMobile = _isBrowser && /(ipad|iphone|ipod|android)/gi.test(navigator.userAgent), - _isAutomatedTest = !_isBrowser || window._phantom; - - var Matter = _isBrowser ? window.Matter : require('../../build/matter-dev.js'); - - var Demo = {}; - Matter.Demo = Demo; - - if (!_isBrowser) { - module.exports = Demo; - window = {}; - } - - // Matter aliases - var Body = Matter.Body, - Example = Matter.Example, - Engine = Matter.Engine, - World = Matter.World, - Common = Matter.Common, - Bodies = Matter.Bodies, - Events = Matter.Events, - Mouse = Matter.Mouse, - MouseConstraint = Matter.MouseConstraint, - Runner = Matter.Runner, - Render = Matter.Render; - - // MatterTools aliases - if (window.MatterTools) { - var Gui = MatterTools.Gui, - Inspector = MatterTools.Inspector; - } - - Demo.create = function(options) { - var defaults = { - isManual: false, - sceneName: 'mixed', - sceneEvents: [] - }; - - return Common.extend(defaults, options); - }; - - Demo.init = function() { - var demo = Demo.create(); - Matter.Demo._demo = demo; - - // get container element for the canvas - demo.container = document.getElementById('canvas-container'); - - // create an example engine (see /examples/engine.js) - demo.engine = Example.engine(demo); - - // run the engine - demo.runner = Engine.run(demo.engine); - - // create a debug renderer - demo.render = Render.create({ - element: demo.container, - engine: demo.engine - }); - - // run the renderer - Render.run(demo.render); - - // add a mouse controlled constraint - demo.mouseConstraint = MouseConstraint.create(demo.engine, { - element: demo.render.canvas - }); - - World.add(demo.engine.world, demo.mouseConstraint); - - // pass mouse to renderer to enable showMousePosition - demo.render.mouse = demo.mouseConstraint.mouse; - - // get the scene function name from hash - if (window.location.hash.length !== 0) - demo.sceneName = window.location.hash.replace('#', '').replace('-inspect', ''); - - // set up a scene with bodies - Demo.reset(demo); - Demo.setScene(demo, demo.sceneName); - - // set up demo interface (see end of this file) - Demo.initControls(demo); - - // pass through runner as timing for debug rendering - demo.engine.metrics.timing = demo.runner; - - return demo; - }; - - // call init when the page has loaded fully - if (!_isAutomatedTest) { - if (window.addEventListener) { - window.addEventListener('load', Demo.init); - } else if (window.attachEvent) { - window.attachEvent('load', Demo.init); - } - } - - Demo.setScene = function(demo, sceneName) { - Example[sceneName](demo); - }; - - // the functions for the demo interface and controls below - Demo.initControls = function(demo) { - var demoSelect = document.getElementById('demo-select'), - demoReset = document.getElementById('demo-reset'); - - // create a Matter.Gui - if (!_isMobile && Gui) { - demo.gui = Gui.create(demo.engine, demo.runner, demo.render); - - // need to add mouse constraint back in after gui clear or load is pressed - Events.on(demo.gui, 'clear load', function() { - demo.mouseConstraint = MouseConstraint.create(demo.engine, { - element: demo.render.canvas - }); - - World.add(demo.engine.world, demo.mouseConstraint); - }); - } - - // create a Matter.Inspector - if (!_isMobile && Inspector && _useInspector) { - demo.inspector = Inspector.create(demo.engine, demo.runner, demo.render); - - Events.on(demo.inspector, 'import', function() { - demo.mouseConstraint = MouseConstraint.create(demo.engine); - World.add(demo.engine.world, demo.mouseConstraint); - }); - - Events.on(demo.inspector, 'play', function() { - demo.mouseConstraint = MouseConstraint.create(demo.engine); - World.add(demo.engine.world, demo.mouseConstraint); - }); - - Events.on(demo.inspector, 'selectStart', function() { - demo.mouseConstraint.constraint.render.visible = false; - }); - - Events.on(demo.inspector, 'selectEnd', function() { - demo.mouseConstraint.constraint.render.visible = true; - }); - } - - // go fullscreen when using a mobile device - if (_isMobile) { - var body = document.body; - - body.className += ' is-mobile'; - demo.render.canvas.addEventListener('touchstart', Demo.fullscreen); - - var fullscreenChange = function() { - var fullscreenEnabled = document.fullscreenEnabled || document.mozFullScreenEnabled || document.webkitFullscreenEnabled; - - // delay fullscreen styles until fullscreen has finished changing - setTimeout(function() { - if (fullscreenEnabled) { - body.className += ' is-fullscreen'; - } else { - body.className = body.className.replace('is-fullscreen', ''); - } - }, 2000); - }; - - document.addEventListener('webkitfullscreenchange', fullscreenChange); - document.addEventListener('mozfullscreenchange', fullscreenChange); - document.addEventListener('fullscreenchange', fullscreenChange); - } - - // keyboard controls - document.onkeypress = function(keys) { - // shift + a = toggle manual - if (keys.shiftKey && keys.keyCode === 65) { - Demo.setManualControl(demo, !demo.isManual); + var demo = MatterTools.Demo.create({ + toolbar: { + title: 'matter-js', + url: 'https://github.com/liabru/matter-js', + reset: true, + source: true, + inspector: true, + tools: true, + fullscreen: true, + exampleSelect: true + }, + tools: { + inspector: true, + gui: true + }, + inline: false, + resetOnOrientation: true, + examples: [ + { + name: 'Air Friction', + id: 'airFriction', + init: Example.airFriction, + sourceLink: sourceLinkRoot + '/airFriction.js' + }, + { + name: 'Attractors', + id: 'attractors', + init: Example.attractors, + sourceLink: sourceLinkRoot + '/attractors.js' + }, + { + name: 'Avalanche', + id: 'avalanche', + init: Example.avalanche, + sourceLink: sourceLinkRoot + '/avalanche.js' + }, + { + name: 'Ball Pool', + id: 'ballPool', + init: Example.ballPool, + sourceLink: sourceLinkRoot + '/ballPool.js' + }, + { + name: 'Bridge', + id: 'bridge', + init: Example.bridge, + sourceLink: sourceLinkRoot + '/bridge.js' + }, + { + name: 'Broadphase', + id: 'broadphase', + init: Example.broadphase, + sourceLink: sourceLinkRoot + '/broadphase.js' + }, + { + name: 'Car', + id: 'car', + init: Example.car, + sourceLink: sourceLinkRoot + '/car.js' + }, + { + name: 'Catapult', + id: 'catapult', + init: Example.catapult, + sourceLink: sourceLinkRoot + '/catapult.js' + }, + { + name: 'Chains', + id: 'chains', + init: Example.chains, + sourceLink: sourceLinkRoot + '/chains.js' + }, + { + name: 'Circle Stack', + id: 'circleStack', + init: Example.circleStack, + sourceLink: sourceLinkRoot + '/circleStack.js' + }, + { + name: 'Cloth', + id: 'cloth', + init: Example.cloth, + sourceLink: sourceLinkRoot + '/cloth.js' + }, + { + name: 'Collision Filtering', + id: 'collisionFiltering', + init: Example.collisionFiltering, + sourceLink: sourceLinkRoot + '/collisionFiltering.js' + }, + { + name: 'Composite Manipulation', + id: 'compositeManipulation', + init: Example.compositeManipulation, + sourceLink: sourceLinkRoot + '/compositeManipulation.js' + }, + { + name: 'Compound Bodies', + id: 'compound', + init: Example.compound, + sourceLink: sourceLinkRoot + '/compound.js' + }, + { + name: 'Compound Stack', + id: 'compoundStack', + init: Example.compoundStack, + sourceLink: sourceLinkRoot + '/compoundStack.js' + }, + { + name: 'Concave', + id: 'concave', + init: Example.concave, + sourceLink: sourceLinkRoot + '/concave.js' + }, + { + name: 'Events', + id: 'events', + init: Example.events, + sourceLink: sourceLinkRoot + '/events.js' + }, + { + name: 'Friction', + id: 'friction', + init: Example.friction, + sourceLink: sourceLinkRoot + '/friction.js' + }, + { + name: 'Reverse Gravity', + id: 'gravity', + init: Example.gravity, + sourceLink: sourceLinkRoot + '/gravity.js' + }, + { + name: 'Gyroscope', + id: 'gyro', + init: Example.gyro, + sourceLink: sourceLinkRoot + '/gyro.js' + }, + { + name: 'Manipulation', + id: 'manipulation', + init: Example.manipulation, + sourceLink: sourceLinkRoot + '/manipulation.js' + }, + { + name: 'Mixed Shapes', + id: 'mixed', + init: Example.mixed, + sourceLink: sourceLinkRoot + '/mixed.js' + }, + { + name: 'Newton\'s Cradle', + id: 'newtonsCradle', + init: Example.newtonsCradle, + sourceLink: sourceLinkRoot + '/newtonsCradle.js' + }, + { + name: 'Pyramid', + id: 'pyramid', + init: Example.pyramid, + sourceLink: sourceLinkRoot + '/pyramid.js' + }, + { + name: 'Raycasting', + id: 'raycasting', + init: Example.raycasting, + sourceLink: sourceLinkRoot + '/raycasting.js' + }, + { + name: 'Restitution', + id: 'restitution', + init: Example.restitution, + sourceLink: sourceLinkRoot + '/restitution.js' + }, + { + name: 'Rounded Corners (Chamfering)', + id: 'rounded', + init: Example.rounded, + sourceLink: sourceLinkRoot + '/rounded.js' + }, + { + name: 'Sensors', + id: 'sensors', + init: Example.sensors, + sourceLink: sourceLinkRoot + '/sensors.js' + }, + { + name: 'Sleeping', + id: 'sleeping', + init: Example.sleeping, + sourceLink: sourceLinkRoot + '/sleeping.js' + }, + { + name: 'Slingshot', + id: 'slingshot', + init: Example.slingshot, + sourceLink: sourceLinkRoot + '/slingshot.js' + }, + { + name: 'Soft Body', + id: 'softBody', + init: Example.softBody, + sourceLink: sourceLinkRoot + '/softBody.js' + }, + { + name: 'Sprites', + id: 'sprites', + init: Example.sprites, + sourceLink: sourceLinkRoot + '/sprites.js' + }, + { + name: 'Stack', + id: 'stack', + init: Example.stack, + sourceLink: sourceLinkRoot + '/stack.js' + }, + { + name: 'Static Friction', + id: 'staticFriction', + init: Example.staticFriction, + sourceLink: sourceLinkRoot + '/staticFriction.js' + }, + { + name: 'Stress', + id: 'stress', + init: Example.stress, + sourceLink: sourceLinkRoot + '/stress.js' + }, + { + name: 'Stress 2', + id: 'stress2', + init: Example.stress2, + sourceLink: sourceLinkRoot + '/stress2.js' + }, + { + name: 'Concave SVG Paths', + id: 'svg', + init: Example.svg, + sourceLink: sourceLinkRoot + '/svg.js' + }, + { + name: 'Terrain', + id: 'terrain', + init: Example.terrain, + sourceLink: sourceLinkRoot + '/terraing.js' + }, + { + name: 'Time Scaling', + id: 'timescale', + init: Example.timescale, + sourceLink: sourceLinkRoot + '/timescale.js' + }, + { + name: 'Views', + id: 'views', + init: Example.views, + sourceLink: sourceLinkRoot + '/views.js' + }, + { + name: 'Wrecking Ball', + id: 'wreckingBall', + init: Example.wreckingBall, + sourceLink: sourceLinkRoot + '/wreckingBall.js' } + ] + }); - // shift + q = step - if (keys.shiftKey && keys.keyCode === 81) { - if (!demo.isManual) { - Demo.setManualControl(demo, true); - } - - Runner.tick(demo.runner, demo.engine); - } - }; - - // initialise demo selector - demoSelect.value = demo.sceneName; - Demo.setUpdateSourceLink(demo.sceneName); - - demoSelect.addEventListener('change', function(e) { - Demo.reset(demo); - Demo.setScene(demo,demo.sceneName = e.target.value); - - if (demo.gui) { - Gui.update(demo.gui); - } - - var scrollY = window.scrollY; - window.location.hash = demo.sceneName; - window.scrollY = scrollY; - Demo.setUpdateSourceLink(demo.sceneName); - }); - - demoReset.addEventListener('click', function(e) { - Demo.reset(demo); - Demo.setScene(demo, demo.sceneName); - - if (demo.gui) { - Gui.update(demo.gui); - } - - Demo.setUpdateSourceLink(demo.sceneName); - }); - }; - - Demo.setUpdateSourceLink = function(sceneName) { - var demoViewSource = document.getElementById('demo-view-source'), - sourceUrl = 'https://github.com/liabru/matter-js/blob/master/examples'; - demoViewSource.setAttribute('href', sourceUrl + '/' + sceneName + '.js'); - }; - - Demo.setManualControl = function(demo, isManual) { - var engine = demo.engine, - world = engine.world, - runner = demo.runner; - - demo.isManual = isManual; - - if (demo.isManual) { - Runner.stop(runner); - - // continue rendering but not updating - (function render(time){ - runner.frameRequestId = window.requestAnimationFrame(render); - Events.trigger(engine, 'beforeUpdate'); - Events.trigger(engine, 'tick'); - engine.render.controller.world(engine); - Events.trigger(engine, 'afterUpdate'); - })(); - } else { - Runner.stop(runner); - Runner.start(runner, engine); - } - }; - - Demo.fullscreen = function(demo) { - var _fullscreenElement = demo.render.canvas; - - if (!document.fullscreenElement && !document.mozFullScreenElement && !document.webkitFullscreenElement) { - if (_fullscreenElement.requestFullscreen) { - _fullscreenElement.requestFullscreen(); - } else if (_fullscreenElement.mozRequestFullScreen) { - _fullscreenElement.mozRequestFullScreen(); - } else if (_fullscreenElement.webkitRequestFullscreen) { - _fullscreenElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); - } - } - }; - - Demo.reset = function(demo) { - var world = demo.engine.world, - i; - - World.clear(world); - Engine.clear(demo.engine); - - // clear scene graph (if defined in controller) - if (demo.render) { - var renderController = demo.render.controller; - if (renderController && renderController.clear) - renderController.clear(demo.render); - } - - // clear all scene events - if (demo.engine.events) { - for (i = 0; i < demo.sceneEvents.length; i++) - Events.off(demo.engine, demo.sceneEvents[i]); - } - - if (demo.mouseConstraint && demo.mouseConstraint.events) { - for (i = 0; i < demo.sceneEvents.length; i++) - Events.off(demo.mouseConstraint, demo.sceneEvents[i]); - } - - if (world.events) { - for (i = 0; i < demo.sceneEvents.length; i++) - Events.off(world, demo.sceneEvents[i]); - } - - if (demo.runner && demo.runner.events) { - for (i = 0; i < demo.sceneEvents.length; i++) - Events.off(demo.runner, demo.sceneEvents[i]); - } - - if (demo.render && demo.render.events) { - for (i = 0; i < demo.sceneEvents.length; i++) - Events.off(demo.render, demo.sceneEvents[i]); - } - - demo.sceneEvents = []; - - // reset id pool - Body._nextCollidingGroupId = 1; - Body._nextNonCollidingGroupId = -1; - Body._nextCategory = 0x0001; - Common._nextId = 0; - - // reset random seed - Common._seed = 0; - - // reset mouse offset and scale (only required for Demo.views) - if (demo.mouseConstraint) { - Mouse.setScale(demo.mouseConstraint.mouse, { x: 1, y: 1 }); - Mouse.setOffset(demo.mouseConstraint.mouse, { x: 0, y: 0 }); - } - - demo.engine.enableSleeping = false; - demo.engine.world.gravity.scale = 0.001; - demo.engine.world.gravity.y = 1; - demo.engine.world.gravity.x = 0; - demo.engine.timing.timeScale = 1; - - var offset = 5; - World.add(world, [ - Bodies.rectangle(400, -offset, 800.5 + 2 * offset, 50.5, { isStatic: true }), - Bodies.rectangle(400, 600 + offset, 800.5 + 2 * offset, 50.5, { isStatic: true }), - Bodies.rectangle(800 + offset, 300, 50.5, 600.5 + 2 * offset, { isStatic: true }), - Bodies.rectangle(-offset, 300, 50.5, 600.5 + 2 * offset, { isStatic: true }) - ]); - - if (demo.mouseConstraint) { - World.add(world, demo.mouseConstraint); - } - - if (demo.render) { - var renderOptions = demo.render.options; - renderOptions.wireframes = true; - renderOptions.hasBounds = false; - renderOptions.showDebug = false; - renderOptions.showBroadphase = false; - renderOptions.showBounds = false; - renderOptions.showVelocity = false; - renderOptions.showCollisions = false; - renderOptions.showAxes = false; - renderOptions.showPositions = false; - renderOptions.showAngleIndicator = true; - renderOptions.showIds = false; - renderOptions.showShadows = false; - renderOptions.showVertexNumbers = false; - renderOptions.showConvexHulls = false; - renderOptions.showInternalEdges = false; - renderOptions.showSeparations = false; - renderOptions.background = '#fff'; - - if (_isMobile) { - renderOptions.showDebug = true; - } - } - }; + document.body.appendChild(demo.dom.root); + MatterTools.Demo.start(demo); })(); \ No newline at end of file diff --git a/demo/js/DemoMobile.js b/demo/js/DemoMobile.js deleted file mode 100644 index 3f367b8..0000000 --- a/demo/js/DemoMobile.js +++ /dev/null @@ -1,161 +0,0 @@ -(function() { - - // Matter aliases - var Engine = Matter.Engine, - World = Matter.World, - Bodies = Matter.Bodies, - Composites = Matter.Composites, - Common = Matter.Common, - MouseConstraint = Matter.MouseConstraint; - - var Demo = {}; - - var _engine, - _sceneName = 'mixed', - _sceneWidth, - _sceneHeight, - _deviceOrientationEvent; - - Demo.init = function() { - var canvasContainer = document.getElementById('canvas-container'), - demoStart = document.getElementById('demo-start'); - - demoStart.addEventListener('click', function() { - demoStart.style.display = 'none'; - - _engine = Engine.create(canvasContainer, { - render: { - options: { - wireframes: true, - showAngleIndicator: true, - showDebug: true - } - } - }); - - Demo.fullscreen(); - - setTimeout(function() { - var runner = Engine.run(_engine); - - // pass through runner as timing for debug rendering - _engine.metrics.timing = runner; - - Demo.updateScene(); - }, 800); - }); - - window.addEventListener('deviceorientation', function(event) { - _deviceOrientationEvent = event; - Demo.updateGravity(event); - }, true); - - window.addEventListener('touchstart', Demo.fullscreen); - - window.addEventListener('orientationchange', function() { - Demo.updateGravity(_deviceOrientationEvent); - Demo.updateScene(); - Demo.fullscreen(); - }, false); - }; - - window.addEventListener('load', Demo.init); - - Demo.mixed = function() { - var _world = _engine.world; - - Demo.reset(); - - World.add(_world, MouseConstraint.create(_engine)); - - var stack = Composites.stack(20, 20, 10, 5, 0, 0, function(x, y, column, row) { - switch (Math.round(Common.random(0, 1))) { - - case 0: - if (Common.random() < 0.8) { - return Bodies.rectangle(x, y, Common.random(20, 40), Common.random(20, 40), { friction: 0.01, restitution: 0.4 }); - } else { - return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(20, 30), { friction: 0.01, restitution: 0.4 }); - } - break; - case 1: - return Bodies.polygon(x, y, Math.round(Common.random(4, 6)), Common.random(20, 40), { friction: 0.01, restitution: 0.4 }); - - } - }); - - World.add(_world, stack); - }; - - Demo.updateScene = function() { - if (!_engine) - return; - - _sceneWidth = document.documentElement.clientWidth; - _sceneHeight = document.documentElement.clientHeight; - - var boundsMax = _engine.world.bounds.max, - renderOptions = _engine.render.options, - canvas = _engine.render.canvas; - - boundsMax.x = _sceneWidth; - boundsMax.y = _sceneHeight; - - canvas.width = renderOptions.width = _sceneWidth; - canvas.height = renderOptions.height = _sceneHeight; - - Demo[_sceneName](); - }; - - Demo.updateGravity = function(event) { - if (!_engine) - return; - - var orientation = window.orientation, - gravity = _engine.world.gravity; - - if (orientation === 0) { - gravity.x = Common.clamp(event.gamma, -90, 90) / 90; - gravity.y = Common.clamp(event.beta, -90, 90) / 90; - } else if (orientation === 180) { - gravity.x = Common.clamp(event.gamma, -90, 90) / 90; - gravity.y = Common.clamp(-event.beta, -90, 90) / 90; - } else if (orientation === 90) { - gravity.x = Common.clamp(event.beta, -90, 90) / 90; - gravity.y = Common.clamp(-event.gamma, -90, 90) / 90; - } else if (orientation === -90) { - gravity.x = Common.clamp(-event.beta, -90, 90) / 90; - gravity.y = Common.clamp(event.gamma, -90, 90) / 90; - } - }; - - Demo.fullscreen = function(){ - var _fullscreenElement = _engine.render.canvas; - - if (!document.fullscreenElement && !document.mozFullScreenElement && !document.webkitFullscreenElement) { - if (_fullscreenElement.requestFullscreen) { - _fullscreenElement.requestFullscreen(); - } else if (_fullscreenElement.mozRequestFullScreen) { - _fullscreenElement.mozRequestFullScreen(); - } else if (_fullscreenElement.webkitRequestFullscreen) { - _fullscreenElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); - } - } - }; - - Demo.reset = function() { - var _world = _engine.world; - - Common._seed = 2; - - World.clear(_world); - Engine.clear(_engine); - - var offset = 5; - World.addBody(_world, Bodies.rectangle(_sceneWidth * 0.5, -offset, _sceneWidth + 0.5, 50.5, { isStatic: true })); - World.addBody(_world, Bodies.rectangle(_sceneWidth * 0.5, _sceneHeight + offset, _sceneWidth + 0.5, 50.5, { isStatic: true })); - World.addBody(_world, Bodies.rectangle(_sceneWidth + offset, _sceneHeight * 0.5, 50.5, _sceneHeight + 0.5, { isStatic: true })); - World.addBody(_world, Bodies.rectangle(-offset, _sceneHeight * 0.5, 50.5, _sceneHeight + 0.5, { isStatic: true })); - }; - -})(); \ No newline at end of file diff --git a/demo/js/lib/matter-0.8.0.js b/demo/js/lib/matter-0.8.0.js deleted file mode 100644 index 3184f5c..0000000 --- a/demo/js/lib/matter-0.8.0.js +++ /dev/null @@ -1,6360 +0,0 @@ -/** -* matter-0.8.0.js 0.8.0-alpha 2014-05-04 -* http://brm.io/matter-js/ -* License: MIT -*/ - -/** - * The MIT License (MIT) - * - * Copyright (c) 2014 Liam Brummitt - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -(function() { - -var Matter = {}; - -// Begin Matter namespace closure - -// All Matter modules are included below during build -// Outro.js then closes at the end of the file - - -// Begin src/body/Body.js - -/** -* See [Demo.js](https://github.com/liabru/matter-js/blob/master/demo/js/Demo.js) -* and [DemoMobile.js](https://github.com/liabru/matter-js/blob/master/demo/js/DemoMobile.js) for usage examples. -* -* @class Body -*/ - -var Body = {}; - -(function() { - - var _nextGroupId = 1; - - /** - * Description to be written. - * @method create - * @param {} options - * @return {body} body - */ - Body.create = function(options) { - var defaults = { - id: Common.nextId(), - type: 'body', - label: 'Body', - angle: 0, - vertices: Vertices.fromPath('L 0 0 L 40 0 L 40 40 L 0 40'), - position: { x: 0, y: 0 }, - force: { x: 0, y: 0 }, - torque: 0, - positionImpulse: { x: 0, y: 0 }, - constraintImpulse: { x: 0, y: 0, angle: 0 }, - speed: 0, - angularSpeed: 0, - velocity: { x: 0, y: 0 }, - angularVelocity: 0, - isStatic: false, - isSleeping: false, - motion: 0, - sleepThreshold: 60, - density: 0.001, - restitution: 0, - friction: 0.1, - frictionAir: 0.01, - groupId: 0, - slop: 0.05, - timeScale: 1, - render: { - visible: true, - sprite: { - xScale: 1, - yScale: 1 - }, - lineWidth: 1.5 - } - }; - - var body = Common.extend(defaults, options); - - _initProperties(body); - - return body; - }; - - /** - * Description - * @method nextGroupId - * @return {Number} Unique groupID - */ - Body.nextGroupId = function() { - return _nextGroupId++; - }; - - /** - * Initialises body properties - * @method _initProperties - * @private - * @param {body} body - */ - var _initProperties = function(body) { - // calculated properties - body.axes = body.axes || Axes.fromVertices(body.vertices); - body.area = Vertices.area(body.vertices); - body.bounds = Bounds.create(body.vertices); - body.mass = body.mass || (body.density * body.area); - body.inverseMass = 1 / body.mass; - body.inertia = body.inertia || Vertices.inertia(body.vertices, body.mass); - body.inverseInertia = 1 / body.inertia; - body.positionPrev = body.positionPrev || { x: body.position.x, y: body.position.y }; - body.anglePrev = body.anglePrev || body.angle; - body.render.fillStyle = body.render.fillStyle || (body.isStatic ? '#eeeeee' : Common.choose(['#556270', '#4ECDC4', '#C7F464', '#FF6B6B', '#C44D58'])); - body.render.strokeStyle = body.render.strokeStyle || Common.shadeColor(body.render.fillStyle, -20); - - // update geometry - Vertices.create(body.vertices, body); - var centre = Vertices.centre(body.vertices); - Vertices.translate(body.vertices, body.position); - Vertices.translate(body.vertices, centre, -1); - Vertices.rotate(body.vertices, body.angle, body.position); - Axes.rotate(body.axes, body.angle); - Bounds.update(body.bounds, body.vertices, body.velocity); - - Body.setStatic(body, body.isStatic); - Sleeping.set(body, body.isSleeping); - }; - - /** - * Sets the body as static, including isStatic flag and setting mass and inertia to Infinity - * @method setStatic - * @param {bool} isStatic - */ - Body.setStatic = function(body, isStatic) { - body.isStatic = isStatic; - - if (isStatic) { - body.restitution = 0; - body.friction = 1; - body.mass = body.inertia = body.density = Infinity; - body.inverseMass = body.inverseInertia = 0; - body.render.lineWidth = 1; - - body.positionPrev.x = body.position.x; - body.positionPrev.y = body.position.y; - body.anglePrev = body.angle; - body.angularVelocity = 0; - body.speed = 0; - body.angularSpeed = 0; - body.motion = 0; - } - }; - - /** - * Description - * @method resetForcesAll - * @param {body[]} bodies - */ - Body.resetForcesAll = function(bodies) { - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i]; - - // reset force buffers - body.force.x = 0; - body.force.y = 0; - body.torque = 0; - } - }; - - /** - * Description - * @method applyGravityAll - * @param {body[]} bodies - * @param {vector} gravity - */ - Body.applyGravityAll = function(bodies, gravity) { - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i]; - - if (body.isStatic || body.isSleeping) - continue; - - // apply gravity - body.force.y += body.mass * gravity.y * 0.001; - body.force.x += body.mass * gravity.x * 0.001; - } - }; - - /** - * Description - * @method updateAll - * @param {body[]} bodies - * @param {number} deltaTime - * @param {number} timeScale - * @param {number} correction - * @param {bounds} worldBounds - */ - Body.updateAll = function(bodies, deltaTime, timeScale, correction, worldBounds) { - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i]; - - if (body.isStatic || body.isSleeping) - continue; - - // don't update out of world bodies - // TODO: viewports - if (body.bounds.max.x < worldBounds.min.x || body.bounds.min.x > worldBounds.max.x - || body.bounds.max.y < worldBounds.min.y || body.bounds.min.y > worldBounds.max.y) - continue; - - Body.update(body, deltaTime, timeScale, correction); - } - }; - - /** - * Description - * @method update - * @param {body} body - * @param {number} deltaTime - * @param {number} timeScale - * @param {number} correction - */ - Body.update = function(body, deltaTime, timeScale, correction) { - var deltaTimeSquared = Math.pow(deltaTime * timeScale * body.timeScale, 2); - - // from the previous step - var frictionAir = 1 - body.frictionAir * timeScale * body.timeScale, - velocityPrevX = body.position.x - body.positionPrev.x, - velocityPrevY = body.position.y - body.positionPrev.y; - - // update velocity with verlet integration - body.velocity.x = (velocityPrevX * frictionAir * correction) + (body.force.x / body.mass) * deltaTimeSquared; - body.velocity.y = (velocityPrevY * frictionAir * correction) + (body.force.y / body.mass) * deltaTimeSquared; - - body.positionPrev.x = body.position.x; - body.positionPrev.y = body.position.y; - body.position.x += body.velocity.x; - body.position.y += body.velocity.y; - - // update angular velocity with verlet integration - body.angularVelocity = ((body.angle - body.anglePrev) * frictionAir * correction) + (body.torque / body.inertia) * deltaTimeSquared; - body.anglePrev = body.angle; - body.angle += body.angularVelocity; - - // track speed and acceleration - body.speed = Vector.magnitude(body.velocity); - body.angularSpeed = Math.abs(body.angularVelocity); - - // transform the body geometry - Vertices.translate(body.vertices, body.velocity); - if (body.angularVelocity !== 0) { - Vertices.rotate(body.vertices, body.angularVelocity, body.position); - Axes.rotate(body.axes, body.angularVelocity); - } - Bounds.update(body.bounds, body.vertices, body.velocity); - }; - - /** - * Description - * @method applyForce - * @param {body} body - * @param {vector} position - * @param {vector} force - */ - Body.applyForce = function(body, position, force) { - body.force.x += force.x; - body.force.y += force.y; - var offset = { x: position.x - body.position.x, y: position.y - body.position.y }; - body.torque += (offset.x * force.y - offset.y * force.x) * body.inverseInertia; - }; - - /** - * Description - * @method translate - * @param {body} body - * @param {vector} translation - */ - Body.translate = function(body, translation) { - body.positionPrev.x += translation.x; - body.positionPrev.y += translation.y; - body.position.x += translation.x; - body.position.y += translation.y; - Vertices.translate(body.vertices, translation); - Bounds.update(body.bounds, body.vertices, body.velocity); - }; - - /** - * Description - * @method rotate - * @param {body} body - * @param {number} angle - */ - Body.rotate = function(body, angle) { - body.anglePrev += angle; - body.angle += angle; - Vertices.rotate(body.vertices, angle, body.position); - Axes.rotate(body.axes, angle); - Bounds.update(body.bounds, body.vertices, body.velocity); - }; - - /** - * Scales the body, including updating physical properties (mass, area, axes, inertia), from a point (default is centre) - * @method translate - * @param {body} body - * @param {number} scaleX - * @param {number} scaleY - * @param {vector} point - */ - Body.scale = function(body, scaleX, scaleY, point) { - // scale vertices - Vertices.scale(body.vertices, scaleX, scaleY, point); - - // update properties - body.axes = Axes.fromVertices(body.vertices); - body.area = Vertices.area(body.vertices); - body.mass = body.density * body.area; - body.inverseMass = 1 / body.mass; - - // update inertia (requires vertices to be at origin) - Vertices.translate(body.vertices, { x: -body.position.x, y: -body.position.y }); - body.inertia = Vertices.inertia(body.vertices, body.mass); - body.inverseInertia = 1 / body.inertia; - Vertices.translate(body.vertices, { x: body.position.x, y: body.position.y }); - - // update bounds - Bounds.update(body.bounds, body.vertices, body.velocity); - }; - -})(); - -; // End src/body/Body.js - - -// Begin src/body/Composite.js - -/** -* See [Demo.js](https://github.com/liabru/matter-js/blob/master/demo/js/Demo.js) -* and [DemoMobile.js](https://github.com/liabru/matter-js/blob/master/demo/js/DemoMobile.js) for usage examples. -* -* @class Composite -*/ - -// TODO: composite translate, rotate - -var Composite = {}; - -(function() { - - /** - * Description - * @method create - * @param {} options - * @return {composite} A new composite - */ - Composite.create = function(options) { - return Common.extend({ - id: Common.nextId(), - type: 'composite', - parent: null, - isModified: false, - bodies: [], - constraints: [], - composites: [], - label: 'Composite' - }, options); - }; - - /** - * Sets the composite's `isModified` flag. - * If `updateParents` is true, all parents will be set (default: false). - * If `updateChildren` is true, all children will be set (default: false). - * @method setModified - * @param {composite} composite - * @param {boolean} isModified - * @param {boolean} updateParents - * @param {boolean} updateChildren - */ - Composite.setModified = function(composite, isModified, updateParents, updateChildren) { - composite.isModified = isModified; - - if (updateParents && composite.parent) { - Composite.setModified(composite.parent, isModified, updateParents, updateChildren); - } - - if (updateChildren) { - for(var i = 0; i < composite.composites.length; i++) { - var childComposite = composite.composites[i]; - Composite.setModified(childComposite, isModified, updateParents, updateChildren); - } - } - }; - - /** - * Generic add function. Adds one or many body(s), constraint(s) or a composite(s) to the given composite. - * @method add - * @param {composite} composite - * @param {} object - * @return {composite} The original composite with the objects added - */ - Composite.add = function(composite, object) { - var objects = [].concat(object); - - for (var i = 0; i < objects.length; i++) { - var obj = objects[i]; - - switch (obj.type) { - - case 'body': - Composite.addBody(composite, obj); - break; - case 'constraint': - Composite.addConstraint(composite, obj); - break; - case 'composite': - Composite.addComposite(composite, obj); - break; - case 'mouseConstraint': - Composite.addConstraint(composite, obj.constraint); - break; - - } - } - - return composite; - }; - - /** - * Generic remove function. Removes one or many body(s), constraint(s) or a composite(s) to the given composite. - * Optionally searching its children recursively. - * @method remove - * @param {composite} composite - * @param {} object - * @param {boolean} deep - * @return {composite} The original composite with the objects removed - */ - Composite.remove = function(composite, object, deep) { - var objects = [].concat(object); - - for (var i = 0; i < objects.length; i++) { - var obj = objects[i]; - - switch (obj.type) { - - case 'body': - Composite.removeBody(composite, obj, deep); - break; - case 'constraint': - Composite.removeConstraint(composite, obj, deep); - break; - case 'composite': - Composite.removeComposite(composite, obj, deep); - break; - case 'mouseConstraint': - Composite.removeConstraint(composite, obj.constraint); - break; - - } - } - - return composite; - }; - - /** - * Description - * @method addComposite - * @param {composite} compositeA - * @param {composite} compositeB - * @return {composite} The original compositeA with the objects from compositeB added - */ - Composite.addComposite = function(compositeA, compositeB) { - compositeA.composites.push(compositeB); - compositeB.parent = compositeA; - Composite.setModified(compositeA, true, true, false); - return compositeA; - }; - - /** - * Removes a composite from the given composite, and optionally searching its children recursively - * @method removeComposite - * @param {composite} compositeA - * @param {composite} compositeB - * @param {boolean} deep - * @return {composite} The original compositeA with the composite removed - */ - Composite.removeComposite = function(compositeA, compositeB, deep) { - var position = compositeA.composites.indexOf(compositeB); - if (position !== -1) { - Composite.removeCompositeAt(compositeA, position); - Composite.setModified(compositeA, true, true, false); - } - - if (deep) { - for (var i = 0; i < compositeA.composites.length; i++){ - Composite.removeComposite(compositeA.composites[i], compositeB, true); - } - } - - return compositeA; - }; - - /** - * Removes a composite from the given composite - * @method removeCompositeAt - * @param {composite} composite - * @param {number} position - * @return {composite} The original composite with the composite removed - */ - Composite.removeCompositeAt = function(composite, position) { - composite.composites.splice(position, 1); - Composite.setModified(composite, true, true, false); - return composite; - }; - - /** - * Description - * @method addBody - * @param {composite} composite - * @param {body} body - * @return {composite} The original composite with the body added - */ - Composite.addBody = function(composite, body) { - composite.bodies.push(body); - Composite.setModified(composite, true, true, false); - return composite; - }; - - /** - * Removes a body from the given composite, and optionally searching its children recursively - * @method removeBody - * @param {composite} composite - * @param {body} body - * @param {boolean} deep - * @return {composite} The original composite with the body removed - */ - Composite.removeBody = function(composite, body, deep) { - var position = composite.bodies.indexOf(body); - if (position !== -1) { - Composite.removeBodyAt(composite, position); - Composite.setModified(composite, true, true, false); - } - - if (deep) { - for (var i = 0; i < composite.composites.length; i++){ - Composite.removeBody(composite.composites[i], body, true); - } - } - - return composite; - }; - - /** - * Removes a body from the given composite - * @method removeBodyAt - * @param {composite} composite - * @param {number} position - * @return {composite} The original composite with the body removed - */ - Composite.removeBodyAt = function(composite, position) { - composite.bodies.splice(position, 1); - Composite.setModified(composite, true, true, false); - return composite; - }; - - /** - * Description - * @method addConstraint - * @param {composite} composite - * @param {constraint} constraint - * @return {composite} The original composite with the constraint added - */ - Composite.addConstraint = function(composite, constraint) { - composite.constraints.push(constraint); - Composite.setModified(composite, true, true, false); - return composite; - }; - - /** - * Removes a constraint from the given composite, and optionally searching its children recursively - * @method removeConstraint - * @param {composite} composite - * @param {constraint} constraint - * @param {boolean} deep - * @return {composite} The original composite with the constraint removed - */ - Composite.removeConstraint = function(composite, constraint, deep) { - var position = composite.constraints.indexOf(constraint); - if (position !== -1) { - Composite.removeConstraintAt(composite, position); - } - - if (deep) { - for (var i = 0; i < composite.composites.length; i++){ - Composite.removeConstraint(composite.composites[i], constraint, true); - } - } - - return composite; - }; - - /** - * Removes a body from the given composite - * @method removeConstraintAt - * @param {composite} composite - * @param {number} position - * @return {composite} The original composite with the constraint removed - */ - Composite.removeConstraintAt = function(composite, position) { - composite.constraints.splice(position, 1); - Composite.setModified(composite, true, true, false); - return composite; - }; - - /** - * Removes all bodies, constraints and composites from the given composite - * Optionally clearing its children recursively - * @method clear - * @param {world} world - * @param {boolean} keepStatic - * @param {boolean} deep - */ - Composite.clear = function(composite, keepStatic, deep) { - if (deep) { - for (var i = 0; i < composite.composites.length; i++){ - Composite.clear(composite.composites[i], keepStatic, true); - } - } - - if (keepStatic) { - composite.bodies = composite.bodies.filter(function(body) { return body.isStatic; }); - } else { - composite.bodies.length = 0; - } - - composite.constraints.length = 0; - composite.composites.length = 0; - Composite.setModified(composite, true, true, false); - - return composite; - }; - - /** - * Returns all bodies in the given composite, including all bodies in its children, recursively - * @method allBodies - * @param {composite} composite - * @return {body[]} All the bodies - */ - Composite.allBodies = function(composite) { - var bodies = [].concat(composite.bodies); - - for (var i = 0; i < composite.composites.length; i++) - bodies = bodies.concat(Composite.allBodies(composite.composites[i])); - - return bodies; - }; - - /** - * Returns all constraints in the given composite, including all constraints in its children, recursively - * @method allConstraints - * @param {composite} composite - * @return {constraint[]} All the constraints - */ - Composite.allConstraints = function(composite) { - var constraints = [].concat(composite.constraints); - - for (var i = 0; i < composite.composites.length; i++) - constraints = constraints.concat(Composite.allConstraints(composite.composites[i])); - - return constraints; - }; - - /** - * Returns all composites in the given composite, including all composites in its children, recursively - * @method allComposites - * @param {composite} composite - * @return {composite[]} All the composites - */ - Composite.allComposites = function(composite) { - var composites = [].concat(composite.composites); - - for (var i = 0; i < composite.composites.length; i++) - composites = composites.concat(Composite.allComposites(composite.composites[i])); - - return composites; - }; - - /** - * Searches the composite recursively for an object matching the type and id supplied, null if not found - * @method get - * @param {composite} composite - * @param {number} id - * @param {string} type - * @return {object} The requested object, if found - */ - Composite.get = function(composite, id, type) { - var objects, - object; - - switch (type) { - case 'body': - objects = Composite.allBodies(composite); - break; - case 'constraint': - objects = Composite.allConstraints(composite); - break; - case 'composite': - objects = Composite.allComposites(composite).concat(composite); - break; - } - - if (!objects) - return null; - - object = objects.filter(function(object) { - return object.id.toString() === id.toString(); - }); - - return object.length === 0 ? null : object[0]; - }; - - /** - * Moves the given object(s) from compositeA to compositeB (equal to a remove followed by an add) - * @method move - * @param {compositeA} compositeA - * @param {object[]} objects - * @param {compositeB} compositeB - * @return {composite} Returns compositeA - */ - Composite.move = function(compositeA, objects, compositeB) { - Composite.remove(compositeA, objects); - Composite.add(compositeB, objects); - return compositeA; - }; - - /** - * Assigns new ids for all objects in the composite, recursively - * @method rebase - * @param {composite} composite - * @return {composite} Returns composite - */ - Composite.rebase = function(composite) { - var objects = Composite.allBodies(composite) - .concat(Composite.allConstraints(composite)) - .concat(Composite.allComposites(composite)); - - for (var i = 0; i < objects.length; i++) { - objects[i].id = Common.nextId(); - } - - Composite.setModified(composite, true, true, false); - - return composite; - }; - -})(); - -; // End src/body/Composite.js - - -// Begin src/body/World.js - -/** -* See [Demo.js](https://github.com/liabru/matter-js/blob/master/demo/js/Demo.js) -* and [DemoMobile.js](https://github.com/liabru/matter-js/blob/master/demo/js/DemoMobile.js) for usage examples. -* -* @class World -*/ - -var World = {}; - -(function() { - - /** - * Description - * @method create - * @constructor - * @param {} options - * @return {world} A new world - */ - World.create = function(options) { - var composite = Composite.create(); - - var defaults = { - label: 'World', - gravity: { x: 0, y: 1 }, - bounds: { - min: { x: 0, y: 0 }, - max: { x: 800, y: 600 } - } - }; - - return Common.extend(composite, defaults, options); - }; - - // World is a Composite body - // see src/module/Outro.js for these aliases: - - /** - * An alias for Composite.clear since World is also a Composite (see Outro.js) - * @method clear - * @param {world} world - * @param {boolean} keepStatic - */ - - /** - * An alias for Composite.add since World is also a Composite (see Outro.js) - * @method addComposite - * @param {world} world - * @param {composite} composite - * @return {world} The original world with the objects from composite added - */ - - /** - * An alias for Composite.addBody since World is also a Composite (see Outro.js) - * @method addBody - * @param {world} world - * @param {body} body - * @return {world} The original world with the body added - */ - - /** - * An alias for Composite.addConstraint since World is also a Composite (see Outro.js) - * @method addConstraint - * @param {world} world - * @param {constraint} constraint - * @return {world} The original world with the constraint added - */ - -})(); - -; // End src/body/World.js - - -// Begin src/collision/Contact.js - -/** -* _Internal Class_, not generally used outside of the engine's internals. -* -* @class Contact -*/ - -var Contact = {}; - -(function() { - - /** - * Description - * @method create - * @param {vertex} vertex - * @return {contact} A new contact - */ - Contact.create = function(vertex) { - return { - id: Contact.id(vertex), - vertex: vertex, - normalImpulse: 0, - tangentImpulse: 0 - }; - }; - - /** - * Description - * @method id - * @param {vertex} vertex - * @return {Number} Unique contactID - */ - Contact.id = function(vertex) { - return vertex.body.id + '_' + vertex.index; - }; - -})(); - -; // End src/collision/Contact.js - - -// Begin src/collision/Detector.js - -/** -* _Internal Class_, not generally used outside of the engine's internals. -* -* @class Detector -*/ - -// TODO: speculative contacts - -var Detector = {}; - -(function() { - - /** - * Description - * @method collisions - * @param {pair[]} broadphasePairs - * @param {engine} engine - * @return {array} collisions - */ - Detector.collisions = function(broadphasePairs, engine) { - var collisions = [], - metrics = engine.metrics, - pairsTable = engine.pairs.table; - - for (var i = 0; i < broadphasePairs.length; i++) { - var bodyA = broadphasePairs[i][0], - bodyB = broadphasePairs[i][1]; - - // NOTE: could share a function for the below, but may drop performance? - - if (bodyA.groupId && bodyB.groupId && bodyA.groupId === bodyB.groupId) - continue; - - if ((bodyA.isStatic || bodyA.isSleeping) && (bodyB.isStatic || bodyB.isSleeping)) - continue; - - metrics.midphaseTests += 1; - - // mid phase - if (Bounds.overlaps(bodyA.bounds, bodyB.bounds)) { - - // find a previous collision we could reuse - var pairId = Pair.id(bodyA, bodyB), - pair = pairsTable[pairId], - previousCollision; - - if (pair && pair.isActive) { - previousCollision = pair.collision; - } else { - previousCollision = null; - } - - // narrow phase - var collision = SAT.collides(bodyA, bodyB, previousCollision); - - metrics.narrowphaseTests += 1; - - if (collision.reused) - metrics.narrowReuseCount += 1; - - if (collision.collided) { - collisions.push(collision); - metrics.narrowDetections += 1; - } - } - } - - return collisions; - }; - - /** - * Description - * @method bruteForce - * @param {body[]} bodies - * @param {engine} engine - * @return {array} collisions - */ - Detector.bruteForce = function(bodies, engine) { - var collisions = [], - metrics = engine.metrics, - pairsTable = engine.pairs.table; - - for (var i = 0; i < bodies.length; i++) { - for (var j = i + 1; j < bodies.length; j++) { - var bodyA = bodies[i], - bodyB = bodies[j]; - - // NOTE: could share a function for the below, but may drop performance? - - if (bodyA.groupId && bodyB.groupId && bodyA.groupId === bodyB.groupId) - continue; - - if ((bodyA.isStatic || bodyA.isSleeping) && (bodyB.isStatic || bodyB.isSleeping)) - continue; - - metrics.midphaseTests += 1; - - // mid phase - if (Bounds.overlaps(bodyA.bounds, bodyB.bounds)) { - - // find a previous collision we could reuse - var pairId = Pair.id(bodyA, bodyB), - pair = pairsTable[pairId], - previousCollision; - - if (pair && pair.isActive) { - previousCollision = pair.collision; - } else { - previousCollision = null; - } - - // narrow phase - var collision = SAT.collides(bodyA, bodyB, previousCollision); - - metrics.narrowphaseTests += 1; - - if (collision.reused) - metrics.narrowReuseCount += 1; - - if (collision.collided) { - collisions.push(collision); - metrics.narrowDetections += 1; - } - } - } - } - - return collisions; - }; - -})(); - -; // End src/collision/Detector.js - - -// Begin src/collision/Grid.js - -/** -* See [Demo.js](https://github.com/liabru/matter-js/blob/master/demo/js/Demo.js) -* and [DemoMobile.js](https://github.com/liabru/matter-js/blob/master/demo/js/DemoMobile.js) for usage examples. -* -* @class Grid -*/ - -var Grid = {}; - -(function() { - - /** - * Description - * @method create - * @param {number} bucketWidth - * @param {number} bucketHeight - * @return {grid} A new grid - */ - Grid.create = function(bucketWidth, bucketHeight) { - return { - buckets: {}, - pairs: {}, - pairsList: [], - bucketWidth: bucketWidth || 48, - bucketHeight: bucketHeight || 48 - }; - }; - - /** - * Description - * @method update - * @param {grid} grid - * @param {body[]} bodies - * @param {engine} engine - * @param {boolean} forceUpdate - */ - Grid.update = function(grid, bodies, engine, forceUpdate) { - var i, col, row, - world = engine.world, - buckets = grid.buckets, - bucket, - bucketId, - metrics = engine.metrics, - gridChanged = false; - - metrics.broadphaseTests = 0; - - for (i = 0; i < bodies.length; i++) { - var body = bodies[i]; - - if (body.isSleeping && !forceUpdate) - continue; - - // don't update out of world bodies - if (body.bounds.max.x < 0 || body.bounds.min.x > world.bounds.width - || body.bounds.max.y < 0 || body.bounds.min.y > world.bounds.height) - continue; - - var newRegion = _getRegion(grid, body); - - // if the body has changed grid region - if (!body.region || newRegion.id !== body.region.id || forceUpdate) { - - metrics.broadphaseTests += 1; - - if (!body.region || forceUpdate) - body.region = newRegion; - - var union = _regionUnion(newRegion, body.region); - - // update grid buckets affected by region change - // iterate over the union of both regions - for (col = union.startCol; col <= union.endCol; col++) { - for (row = union.startRow; row <= union.endRow; row++) { - bucketId = _getBucketId(col, row); - bucket = buckets[bucketId]; - - var isInsideNewRegion = (col >= newRegion.startCol && col <= newRegion.endCol - && row >= newRegion.startRow && row <= newRegion.endRow); - - var isInsideOldRegion = (col >= body.region.startCol && col <= body.region.endCol - && row >= body.region.startRow && row <= body.region.endRow); - - // remove from old region buckets - if (!isInsideNewRegion && isInsideOldRegion) { - if (isInsideOldRegion) { - if (bucket) - _bucketRemoveBody(grid, bucket, body); - } - } - - // add to new region buckets - if (body.region === newRegion || (isInsideNewRegion && !isInsideOldRegion) || forceUpdate) { - if (!bucket) - bucket = _createBucket(buckets, bucketId); - _bucketAddBody(grid, bucket, body); - } - } - } - - // set the new region - body.region = newRegion; - - // flag changes so we can update pairs - gridChanged = true; - } - } - - // update pairs list only if pairs changed (i.e. a body changed region) - if (gridChanged) - grid.pairsList = _createActivePairsList(grid); - }; - - /** - * Description - * @method clear - * @param {grid} grid - */ - Grid.clear = function(grid) { - grid.buckets = {}; - grid.pairs = {}; - grid.pairsList = []; - }; - - /** - * Description - * @method _regionUnion - * @private - * @param {} regionA - * @param {} regionB - * @return CallExpression - */ - var _regionUnion = function(regionA, regionB) { - var startCol = Math.min(regionA.startCol, regionB.startCol), - endCol = Math.max(regionA.endCol, regionB.endCol), - startRow = Math.min(regionA.startRow, regionB.startRow), - endRow = Math.max(regionA.endRow, regionB.endRow); - - return _createRegion(startCol, endCol, startRow, endRow); - }; - - /** - * Description - * @method _getRegion - * @private - * @param {} grid - * @param {} body - * @return CallExpression - */ - var _getRegion = function(grid, body) { - var bounds = body.bounds, - startCol = Math.floor(bounds.min.x / grid.bucketWidth), - endCol = Math.floor(bounds.max.x / grid.bucketWidth), - startRow = Math.floor(bounds.min.y / grid.bucketHeight), - endRow = Math.floor(bounds.max.y / grid.bucketHeight); - - return _createRegion(startCol, endCol, startRow, endRow); - }; - - /** - * Description - * @method _createRegion - * @private - * @param {} startCol - * @param {} endCol - * @param {} startRow - * @param {} endRow - * @return ObjectExpression - */ - var _createRegion = function(startCol, endCol, startRow, endRow) { - return { - id: startCol + ',' + endCol + ',' + startRow + ',' + endRow, - startCol: startCol, - endCol: endCol, - startRow: startRow, - endRow: endRow - }; - }; - - /** - * Description - * @method _getBucketId - * @private - * @param {} column - * @param {} row - * @return BinaryExpression - */ - var _getBucketId = function(column, row) { - return column + ',' + row; - }; - - /** - * Description - * @method _createBucket - * @private - * @param {} buckets - * @param {} bucketId - * @return bucket - */ - var _createBucket = function(buckets, bucketId) { - var bucket = buckets[bucketId] = []; - return bucket; - }; - - /** - * Description - * @method _bucketAddBody - * @private - * @param {} grid - * @param {} bucket - * @param {} body - */ - var _bucketAddBody = function(grid, bucket, body) { - // add new pairs - for (var i = 0; i < bucket.length; i++) { - var bodyB = bucket[i]; - - if (body.id === bodyB.id || (body.isStatic && bodyB.isStatic)) - continue; - - // keep track of the number of buckets the pair exists in - // important for Grid.update to work - var pairId = Pair.id(body, bodyB), - pair = grid.pairs[pairId]; - - if (pair) { - pair[2] += 1; - } else { - grid.pairs[pairId] = [body, bodyB, 1]; - } - } - - // add to bodies (after pairs, otherwise pairs with self) - bucket.push(body); - }; - - /** - * Description - * @method _bucketRemoveBody - * @private - * @param {} grid - * @param {} bucket - * @param {} body - */ - var _bucketRemoveBody = function(grid, bucket, body) { - // remove from bucket - bucket.splice(bucket.indexOf(body), 1); - - // update pair counts - for (var i = 0; i < bucket.length; i++) { - // keep track of the number of buckets the pair exists in - // important for _createActivePairsList to work - var bodyB = bucket[i], - pairId = Pair.id(body, bodyB), - pair = grid.pairs[pairId]; - - if (pair) - pair[2] -= 1; - } - }; - - /** - * Description - * @method _createActivePairsList - * @private - * @param {} grid - * @return pairs - */ - var _createActivePairsList = function(grid) { - var pairKeys, - pair, - pairs = []; - - // grid.pairs is used as a hashmap - pairKeys = Common.keys(grid.pairs); - - // iterate over grid.pairs - for (var k = 0; k < pairKeys.length; k++) { - pair = grid.pairs[pairKeys[k]]; - - // if pair exists in at least one bucket - // it is a pair that needs further collision testing so push it - if (pair[2] > 0) { - pairs.push(pair); - } else { - delete grid.pairs[pairKeys[k]]; - } - } - - return pairs; - }; - -})(); - -; // End src/collision/Grid.js - - -// Begin src/collision/Pair.js - -/** -* _Internal Class_, not generally used outside of the engine's internals. -* -* @class Pair -*/ - -var Pair = {}; - -(function() { - - /** - * Description - * @method create - * @param {collision} collision - * @return {pair} A new pair - */ - Pair.create = function(collision, timestamp) { - var bodyA = collision.bodyA, - bodyB = collision.bodyB; - - var pair = { - id: Pair.id(bodyA, bodyB), - bodyA: bodyA, - bodyB: bodyB, - contacts: {}, - activeContacts: [], - separation: 0, - isActive: true, - timeCreated: timestamp, - timeUpdated: timestamp, - inverseMass: bodyA.inverseMass + bodyB.inverseMass, - friction: Math.min(bodyA.friction, bodyB.friction), - restitution: Math.max(bodyA.restitution, bodyB.restitution), - slop: Math.max(bodyA.slop, bodyB.slop) - }; - - Pair.update(pair, collision, timestamp); - - return pair; - }; - - /** - * Description - * @method update - * @param {pair} pair - * @param {collision} collision - */ - Pair.update = function(pair, collision, timestamp) { - var contacts = pair.contacts, - supports = collision.supports, - activeContacts = pair.activeContacts; - - pair.collision = collision; - activeContacts.length = 0; - - if (collision.collided) { - for (var i = 0; i < supports.length; i++) { - var support = supports[i], - contactId = Contact.id(support), - contact = contacts[contactId]; - - if (contact) { - activeContacts.push(contact); - } else { - activeContacts.push(contacts[contactId] = Contact.create(support)); - } - } - - pair.separation = collision.depth; - Pair.setActive(pair, true, timestamp); - } else { - if (pair.isActive === true) - Pair.setActive(pair, false, timestamp); - } - }; - - /** - * Description - * @method setActive - * @param {pair} pair - * @param {bool} isActive - */ - Pair.setActive = function(pair, isActive, timestamp) { - if (isActive) { - pair.isActive = true; - pair.timeUpdated = timestamp; - } else { - pair.isActive = false; - pair.activeContacts.length = 0; - } - }; - - /** - * Description - * @method id - * @param {body} bodyA - * @param {body} bodyB - * @return {number} Unique pairId - */ - Pair.id = function(bodyA, bodyB) { - if (bodyA.id < bodyB.id) { - return bodyA.id + '_' + bodyB.id; - } else { - return bodyB.id + '_' + bodyA.id; - } - }; - -})(); - -; // End src/collision/Pair.js - - -// Begin src/collision/Pairs.js - -/** -* _Internal Class_, not generally used outside of the engine's internals. -* -* @class Pairs -*/ - -var Pairs = {}; - -(function() { - - var _pairMaxIdleLife = 1000; - - /** - * Creates a new pairs structure - * @method create - * @param {object} options - * @return {pairs} A new pairs structure - */ - Pairs.create = function(options) { - return Common.extend({ - table: {}, - list: [], - collisionStart: [], - collisionActive: [], - collisionEnd: [] - }, options); - }; - - /** - * Description - * @method update - * @param {object} pairs - * @param {collision[]} collisions - */ - Pairs.update = function(pairs, collisions, timestamp) { - var pairsList = pairs.list, - pairsTable = pairs.table, - collisionStart = pairs.collisionStart, - collisionEnd = pairs.collisionEnd, - collisionActive = pairs.collisionActive, - activePairIds = [], - collision, - pairId, - pair, - i; - - // clear collision state arrays, but maintain old reference - collisionStart.length = 0; - collisionEnd.length = 0; - collisionActive.length = 0; - - for (i = 0; i < collisions.length; i++) { - collision = collisions[i]; - - if (collision.collided) { - pairId = Pair.id(collision.bodyA, collision.bodyB); - activePairIds.push(pairId); - - pair = pairsTable[pairId]; - - if (pair) { - // pair already exists (but may or may not be active) - if (pair.isActive) { - // pair exists and is active - collisionActive.push(pair); - } else { - // pair exists but was inactive, so a collision has just started again - collisionStart.push(pair); - } - - // update the pair - Pair.update(pair, collision, timestamp); - } else { - // pair did not exist, create a new pair - pair = Pair.create(collision, timestamp); - pairsTable[pairId] = pair; - - // push the new pair - collisionStart.push(pair); - pairsList.push(pair); - } - } - } - - // deactivate previously active pairs that are now inactive - for (i = 0; i < pairsList.length; i++) { - pair = pairsList[i]; - if (pair.isActive && activePairIds.indexOf(pair.id) === -1) { - Pair.setActive(pair, false, timestamp); - collisionEnd.push(pair); - } - } - }; - - /** - * Description - * @method removeOld - * @param {object} pairs - */ - Pairs.removeOld = function(pairs, timestamp) { - var pairsList = pairs.list, - pairsTable = pairs.table, - indexesToRemove = [], - pair, - collision, - pairIndex, - i; - - for (i = 0; i < pairsList.length; i++) { - pair = pairsList[i]; - collision = pair.collision; - - // never remove sleeping pairs - if (collision.bodyA.isSleeping || collision.bodyB.isSleeping) { - pair.timeUpdated = timestamp; - continue; - } - - // if pair is inactive for too long, mark it to be removed - if (timestamp - pair.timeUpdated > _pairMaxIdleLife) { - indexesToRemove.push(i); - } - } - - // remove marked pairs - for (i = 0; i < indexesToRemove.length; i++) { - pairIndex = indexesToRemove[i] - i; - pair = pairsList[pairIndex]; - delete pairsTable[pair.id]; - pairsList.splice(pairIndex, 1); - } - }; - - /** - * Clears the given pairs structure - * @method create - * @param {object} options - * @param {pairs} pairs - */ - Pairs.clear = function(pairs) { - pairs.table = {}; - pairs.list.length = 0; - pairs.collisionStart.length = 0; - pairs.collisionActive.length = 0; - pairs.collisionEnd.length = 0; - return pairs; - }; - -})(); - -; // End src/collision/Pairs.js - - -// Begin src/collision/Query.js - -/** -* Functions for performing collision queries -* -* @class Query -*/ - -var Query = {}; - -(function() { - - /** - * Casts a ray segment against a set of bodies and returns all collisions, ray width is optional. Intersection points are not provided. - * @method ray - * @param {body[]} bodies - * @param {vector} startPoint - * @param {vector} endPoint - * @return {object[]} Collisions - */ - Query.ray = function(bodies, startPoint, endPoint, rayWidth) { - rayWidth = rayWidth || Number.MIN_VALUE; - - var rayAngle = Vector.angle(startPoint, endPoint), - rayLength = Vector.magnitude(Vector.sub(startPoint, endPoint)), - rayX = (endPoint.x + startPoint.x) * 0.5, - rayY = (endPoint.y + startPoint.y) * 0.5, - ray = Bodies.rectangle(rayX, rayY, rayLength, rayWidth, { angle: rayAngle }), - collisions = []; - - for (var i = 0; i < bodies.length; i++) { - var bodyA = bodies[i]; - - if (Bounds.overlaps(bodyA.bounds, ray.bounds)) { - var collision = SAT.collides(bodyA, ray); - if (collision.collided) { - collision.body = collision.bodyA = collision.bodyB = bodyA; - collisions.push(collision); - } - } - } - - return collisions; - }; - - /** - * Returns all bodies whose bounds are inside (or outside if set) the given set of bounds, from the given set of bodies - * @method region - * @param {body[]} bodies - * @param {bounds} bounds - * @param {bool} outside - * @return {body[]} The bodies matching the query - */ - Query.region = function(bodies, bounds, outside) { - var result = []; - - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i], - overlaps = Bounds.overlaps(body.bounds, bounds); - if ((overlaps && !outside) || (!overlaps && outside)) - result.push(body); - } - - return result; - }; - -})(); - -; // End src/collision/Query.js - - -// Begin src/collision/Resolver.js - -/** -* _Internal Class_, not generally used outside of the engine's internals. -* -* @class Resolver -*/ - -var Resolver = {}; - -(function() { - - var _restingThresh = 4, - _positionDampen = 0.2, - _positionWarming = 0.6; - - /** - * Description - * @method solvePosition - * @param {pair[]} pairs - * @param {number} timeScale - */ - Resolver.solvePosition = function(pairs, timeScale) { - var i, - pair, - collision, - bodyA, - bodyB, - vertex, - vertexCorrected, - normal, - bodyBtoA; - - // find impulses required to resolve penetration - for (i = 0; i < pairs.length; i++) { - pair = pairs[i]; - - if (!pair.isActive) - continue; - - collision = pair.collision; - bodyA = collision.bodyA; - bodyB = collision.bodyB; - vertex = collision.supports[0]; - vertexCorrected = collision.supportCorrected; - normal = collision.normal; - - // get current separation between body edges involved in collision - bodyBtoA = Vector.sub(Vector.add(bodyB.positionImpulse, vertex), - Vector.add(bodyA.positionImpulse, vertexCorrected)); - - pair.separation = Vector.dot(normal, bodyBtoA); - } - - for (i = 0; i < pairs.length; i++) { - pair = pairs[i]; - - if (!pair.isActive) - continue; - - collision = pair.collision; - bodyA = collision.bodyA; - bodyB = collision.bodyB; - normal = collision.normal; - positionImpulse = ((pair.separation * _positionDampen) - pair.slop) * timeScale; - - if (bodyA.isStatic || bodyB.isStatic) - positionImpulse *= 2; - - if (!(bodyA.isStatic || bodyA.isSleeping)) { - bodyA.positionImpulse.x += normal.x * positionImpulse; - bodyA.positionImpulse.y += normal.y * positionImpulse; - } - - if (!(bodyB.isStatic || bodyB.isSleeping)) { - bodyB.positionImpulse.x -= normal.x * positionImpulse; - bodyB.positionImpulse.y -= normal.y * positionImpulse; - } - } - }; - - /** - * Description - * @method postSolvePosition - * @param {body[]} bodies - */ - Resolver.postSolvePosition = function(bodies) { - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i]; - - if (body.positionImpulse.x !== 0 || body.positionImpulse.y !== 0) { - // move the body without changing velocity - body.position.x += body.positionImpulse.x; - body.position.y += body.positionImpulse.y; - body.positionPrev.x += body.positionImpulse.x; - body.positionPrev.y += body.positionImpulse.y; - - // update body geometry - Vertices.translate(body.vertices, body.positionImpulse); - Bounds.update(body.bounds, body.vertices, body.velocity); - - // dampen accumulator to warm the next step - body.positionImpulse.x *= _positionWarming; - body.positionImpulse.y *= _positionWarming; - } - } - }; - - /** - * Description - * @method preSolveVelocity - * @param {pair[]} pairs - */ - Resolver.preSolveVelocity = function(pairs) { - var impulse = {}, - i, - j, - pair, - contacts, - collision, - bodyA, - bodyB, - normal, - tangent, - contact, - contactVertex, - normalImpulse, - tangentImpulse, - offset; - - for (i = 0; i < pairs.length; i++) { - pair = pairs[i]; - - if (!pair.isActive) - continue; - - contacts = pair.activeContacts; - collision = pair.collision; - bodyA = collision.bodyA; - bodyB = collision.bodyB; - normal = collision.normal; - tangent = collision.tangent; - - // resolve each contact - for (j = 0; j < contacts.length; j++) { - contact = contacts[j]; - contactVertex = contact.vertex; - normalImpulse = contact.normalImpulse; - tangentImpulse = contact.tangentImpulse; - - // total impulse from contact - impulse.x = (normal.x * normalImpulse) + (tangent.x * tangentImpulse); - impulse.y = (normal.y * normalImpulse) + (tangent.y * tangentImpulse); - - // apply impulse from contact - if (!(bodyA.isStatic || bodyA.isSleeping)) { - offset = Vector.sub(contactVertex, bodyA.position); - bodyA.positionPrev.x += impulse.x * bodyA.inverseMass; - bodyA.positionPrev.y += impulse.y * bodyA.inverseMass; - bodyA.anglePrev += Vector.cross(offset, impulse) * bodyA.inverseInertia; - } - - if (!(bodyB.isStatic || bodyB.isSleeping)) { - offset = Vector.sub(contactVertex, bodyB.position); - bodyB.positionPrev.x -= impulse.x * bodyB.inverseMass; - bodyB.positionPrev.y -= impulse.y * bodyB.inverseMass; - bodyB.anglePrev -= Vector.cross(offset, impulse) * bodyB.inverseInertia; - } - } - } - }; - - /** - * Description - * @method solveVelocity - * @param {pair[]} pairs - */ - Resolver.solveVelocity = function(pairs, timeScale) { - var impulse = {}, - timeScaleSquared = timeScale * timeScale; - - for (var i = 0; i < pairs.length; i++) { - var pair = pairs[i]; - - if (!pair.isActive) - continue; - - var collision = pair.collision, - bodyA = collision.bodyA, - bodyB = collision.bodyB, - normal = collision.normal, - tangent = collision.tangent, - contacts = pair.activeContacts, - contactShare = 1 / contacts.length; - - // update body velocities - bodyA.velocity.x = bodyA.position.x - bodyA.positionPrev.x; - bodyA.velocity.y = bodyA.position.y - bodyA.positionPrev.y; - bodyB.velocity.x = bodyB.position.x - bodyB.positionPrev.x; - bodyB.velocity.y = bodyB.position.y - bodyB.positionPrev.y; - bodyA.angularVelocity = bodyA.angle - bodyA.anglePrev; - bodyB.angularVelocity = bodyB.angle - bodyB.anglePrev; - - // resolve each contact - for (var j = 0; j < contacts.length; j++) { - var contact = contacts[j], - contactVertex = contact.vertex, - offsetA = Vector.sub(contactVertex, bodyA.position), - offsetB = Vector.sub(contactVertex, bodyB.position), - velocityPointA = Vector.add(bodyA.velocity, Vector.mult(Vector.perp(offsetA), bodyA.angularVelocity)), - velocityPointB = Vector.add(bodyB.velocity, Vector.mult(Vector.perp(offsetB), bodyB.angularVelocity)), - relativeVelocity = Vector.sub(velocityPointA, velocityPointB), - normalVelocity = Vector.dot(normal, relativeVelocity); - - var tangentVelocity = Vector.dot(tangent, relativeVelocity), - tangentSpeed = Math.abs(tangentVelocity), - tangentVelocityDirection = Common.sign(tangentVelocity); - - // raw impulses - var normalImpulse = (1 + pair.restitution) * normalVelocity, - normalForce = Common.clamp(pair.separation + normalVelocity, 0, 1); - - // coulomb friction - var tangentImpulse = tangentVelocity; - if (tangentSpeed > normalForce * pair.friction * timeScaleSquared) - tangentImpulse = normalForce * pair.friction * timeScaleSquared * tangentVelocityDirection; - - // modify impulses accounting for mass, inertia and offset - var oAcN = Vector.cross(offsetA, normal), - oBcN = Vector.cross(offsetB, normal), - share = contactShare / (pair.inverseMass + bodyA.inverseInertia * oAcN * oAcN + bodyB.inverseInertia * oBcN * oBcN); - normalImpulse *= share; - tangentImpulse *= share; - - // handle high velocity and resting collisions separately - if (normalVelocity < 0 && normalVelocity * normalVelocity > _restingThresh * timeScaleSquared) { - // high velocity so clear cached contact impulse - contact.normalImpulse = 0; - contact.tangentImpulse = 0; - } else { - // solve resting collision constraints using Erin Catto's method (GDC08) - - // impulse constraint, tends to 0 - var contactNormalImpulse = contact.normalImpulse; - contact.normalImpulse = Math.min(contact.normalImpulse + normalImpulse, 0); - normalImpulse = contact.normalImpulse - contactNormalImpulse; - - // tangent impulse, tends to -maxFriction or maxFriction - var contactTangentImpulse = contact.tangentImpulse; - contact.tangentImpulse = Common.clamp(contact.tangentImpulse + tangentImpulse, -tangentSpeed, tangentSpeed); - tangentImpulse = contact.tangentImpulse - contactTangentImpulse; - } - - // total impulse from contact - impulse.x = (normal.x * normalImpulse) + (tangent.x * tangentImpulse); - impulse.y = (normal.y * normalImpulse) + (tangent.y * tangentImpulse); - - // apply impulse from contact - if (!(bodyA.isStatic || bodyA.isSleeping)) { - bodyA.positionPrev.x += impulse.x * bodyA.inverseMass; - bodyA.positionPrev.y += impulse.y * bodyA.inverseMass; - bodyA.anglePrev += Vector.cross(offsetA, impulse) * bodyA.inverseInertia; - } - - if (!(bodyB.isStatic || bodyB.isSleeping)) { - bodyB.positionPrev.x -= impulse.x * bodyB.inverseMass; - bodyB.positionPrev.y -= impulse.y * bodyB.inverseMass; - bodyB.anglePrev -= Vector.cross(offsetB, impulse) * bodyB.inverseInertia; - } - } - } - }; - -})(); - -; // End src/collision/Resolver.js - - -// Begin src/collision/SAT.js - -/** -* _Internal Class_, not generally used outside of the engine's internals. -* -* @class SAT -*/ - -// TODO: true circles and curves - -var SAT = {}; - -(function() { - - /** - * Description - * @method collides - * @param {body} bodyA - * @param {body} bodyB - * @param {collision} previousCollision - * @return {collision} collision - */ - SAT.collides = function(bodyA, bodyB, previousCollision) { - var overlapAB, - overlapBA, - minOverlap, - collision, - prevCol = previousCollision, - canReusePrevCol = false; - - if (prevCol) { - // estimate total motion - var motion = bodyA.speed * bodyA.speed + bodyA.angularSpeed * bodyA.angularSpeed - + bodyB.speed * bodyB.speed + bodyB.angularSpeed * bodyB.angularSpeed; - - // we may be able to (partially) reuse collision result - // but only safe if collision was resting - canReusePrevCol = prevCol && prevCol.collided && motion < 0.2; - - // reuse collision object - collision = prevCol; - } else { - collision = { collided: false, bodyA: bodyA, bodyB: bodyB }; - } - - if (prevCol && canReusePrevCol) { - // if we can reuse the collision result - // we only need to test the previously found axis - var axes = [prevCol.bodyA.axes[prevCol.axisNumber]]; - - minOverlap = _overlapAxes(prevCol.bodyA.vertices, prevCol.bodyB.vertices, axes); - collision.reused = true; - - if (minOverlap.overlap <= 0) { - collision.collided = false; - return collision; - } - } else { - // if we can't reuse a result, perform a full SAT test - - overlapAB = _overlapAxes(bodyA.vertices, bodyB.vertices, bodyA.axes); - - if (overlapAB.overlap <= 0) { - collision.collided = false; - return collision; - } - - overlapBA = _overlapAxes(bodyB.vertices, bodyA.vertices, bodyB.axes); - - if (overlapBA.overlap <= 0) { - collision.collided = false; - return collision; - } - - if (overlapAB.overlap < overlapBA.overlap) { - minOverlap = overlapAB; - collision.bodyA = bodyA; - collision.bodyB = bodyB; - } else { - minOverlap = overlapBA; - collision.bodyA = bodyB; - collision.bodyB = bodyA; - } - - // important for reuse later - collision.axisNumber = minOverlap.axisNumber; - } - - collision.collided = true; - collision.normal = minOverlap.axis; - collision.depth = minOverlap.overlap; - - bodyA = collision.bodyA; - bodyB = collision.bodyB; - - // ensure normal is facing away from bodyA - if (Vector.dot(collision.normal, Vector.sub(bodyB.position, bodyA.position)) > 0) - collision.normal = Vector.neg(collision.normal); - - collision.tangent = Vector.perp(collision.normal); - - collision.penetration = { - x: collision.normal.x * collision.depth, - y: collision.normal.y * collision.depth - }; - - // find support points, there is always either exactly one or two - var verticesB = _findSupports(bodyA, bodyB, collision.normal), - supports = [verticesB[0]]; - - if (Vertices.contains(bodyA.vertices, verticesB[1])) { - supports.push(verticesB[1]); - } else { - var verticesA = _findSupports(bodyB, bodyA, Vector.neg(collision.normal)); - - if (Vertices.contains(bodyB.vertices, verticesA[0])) { - supports.push(verticesA[0]); - } - - if (supports.length < 2 && Vertices.contains(bodyB.vertices, verticesA[1])) { - supports.push(verticesA[1]); - } - } - - collision.supports = supports; - collision.supportCorrected = Vector.sub(verticesB[0], collision.penetration); - - return collision; - }; - - /** - * Description - * @method _overlapAxes - * @private - * @param {} verticesA - * @param {} verticesB - * @param {} axes - * @return result - */ - var _overlapAxes = function(verticesA, verticesB, axes) { - var projectionA = {}, - projectionB = {}, - result = { overlap: Number.MAX_VALUE }, - overlap, - axis; - - for (var i = 0; i < axes.length; i++) { - axis = axes[i]; - - _projectToAxis(projectionA, verticesA, axis); - _projectToAxis(projectionB, verticesB, axis); - - overlap = projectionA.min < projectionB.min - ? projectionA.max - projectionB.min - : projectionB.max - projectionA.min; - - if (overlap <= 0) { - result.overlap = overlap; - return result; - } - - if (overlap < result.overlap) { - result.overlap = overlap; - result.axis = axis; - result.axisNumber = i; - } - } - - return result; - }; - - /** - * Description - * @method _projectToAxis - * @private - * @param {} projection - * @param {} vertices - * @param {} axis - */ - var _projectToAxis = function(projection, vertices, axis) { - var min = Vector.dot(vertices[0], axis), - max = min; - - for (var i = 1; i < vertices.length; i += 1) { - var dot = Vector.dot(vertices[i], axis); - - if (dot > max) { - max = dot; - } else if (dot < min) { - min = dot; - } - } - - projection.min = min; - projection.max = max; - }; - - /** - * Description - * @method _findSupports - * @private - * @param {} bodyA - * @param {} bodyB - * @param {} normal - * @return ArrayExpression - */ - var _findSupports = function(bodyA, bodyB, normal) { - var nearestDistance = Number.MAX_VALUE, - vertexToBody = { x: 0, y: 0 }, - vertices = bodyB.vertices, - bodyAPosition = bodyA.position, - distance, - vertex, - vertexA = vertices[0], - vertexB = vertices[1]; - - // find closest vertex on bodyB - for (var i = 0; i < vertices.length; i++) { - vertex = vertices[i]; - vertexToBody.x = vertex.x - bodyAPosition.x; - vertexToBody.y = vertex.y - bodyAPosition.y; - distance = -Vector.dot(normal, vertexToBody); - - if (distance < nearestDistance) { - nearestDistance = distance; - vertexA = vertex; - } - } - - // find next closest vertex using the two connected to it - var prevIndex = vertexA.index - 1 >= 0 ? vertexA.index - 1 : vertices.length - 1; - vertex = vertices[prevIndex]; - vertexToBody.x = vertex.x - bodyAPosition.x; - vertexToBody.y = vertex.y - bodyAPosition.y; - nearestDistance = -Vector.dot(normal, vertexToBody); - vertexB = vertex; - - var nextIndex = (vertexA.index + 1) % vertices.length; - vertex = vertices[nextIndex]; - vertexToBody.x = vertex.x - bodyAPosition.x; - vertexToBody.y = vertex.y - bodyAPosition.y; - distance = -Vector.dot(normal, vertexToBody); - if (distance < nearestDistance) { - nearestDistance = distance; - vertexB = vertex; - } - - return [vertexA, vertexB]; - }; - -})(); - -; // End src/collision/SAT.js - - -// Begin src/constraint/Constraint.js - -/** -* See [Demo.js](https://github.com/liabru/matter-js/blob/master/demo/js/Demo.js) -* and [DemoMobile.js](https://github.com/liabru/matter-js/blob/master/demo/js/DemoMobile.js) for usage examples. -* -* @class Constraint -*/ - -// TODO: fix instabillity issues with torque -// TODO: linked constraints -// TODO: breakable constraints -// TODO: collidable constraints -// TODO: allow constrained bodies to sleep -// TODO: handle 0 length constraints properly -// TODO: impulse caching and warming - -var Constraint = {}; - -(function() { - - var _minLength = 0.000001, - _minDifference = 0.001; - - /** - * Description - * @method create - * @param {} options - * @return {constraint} constraint - */ - Constraint.create = function(options) { - var constraint = options; - - // if bodies defined but no points, use body centre - if (constraint.bodyA && !constraint.pointA) - constraint.pointA = { x: 0, y: 0 }; - if (constraint.bodyB && !constraint.pointB) - constraint.pointB = { x: 0, y: 0 }; - - // calculate static length using initial world space points - var initialPointA = constraint.bodyA ? Vector.add(constraint.bodyA.position, constraint.pointA) : constraint.pointA, - initialPointB = constraint.bodyB ? Vector.add(constraint.bodyB.position, constraint.pointB) : constraint.pointB, - length = Vector.magnitude(Vector.sub(initialPointA, initialPointB)); - - constraint.length = constraint.length || length || _minLength; - - // render - var render = { - visible: true, - lineWidth: 2, - strokeStyle: '#666' - }; - - constraint.render = Common.extend(render, constraint.render); - - // option defaults - constraint.id = constraint.id || Common.nextId(); - constraint.label = constraint.label || 'Constraint'; - constraint.type = 'constraint'; - constraint.stiffness = constraint.stiffness || 1; - constraint.angularStiffness = constraint.angularStiffness || 0; - constraint.angleA = constraint.bodyA ? constraint.bodyA.angle : constraint.angleA; - constraint.angleB = constraint.bodyB ? constraint.bodyB.angle : constraint.angleB; - - return constraint; - }; - - /** - * Description - * @method solveAll - * @param {constraint[]} constraints - * @param {number} timeScale - */ - Constraint.solveAll = function(constraints, timeScale) { - for (var i = 0; i < constraints.length; i++) { - Constraint.solve(constraints[i], timeScale); - } - }; - - /** - * Description - * @method solve - * @param {constraint} constraint - * @param {number} timeScale - */ - Constraint.solve = function(constraint, timeScale) { - var bodyA = constraint.bodyA, - bodyB = constraint.bodyB, - pointA = constraint.pointA, - pointB = constraint.pointB; - - // update reference angle - if (bodyA && !bodyA.isStatic) { - constraint.pointA = Vector.rotate(pointA, bodyA.angle - constraint.angleA); - constraint.angleA = bodyA.angle; - } - - // update reference angle - if (bodyB && !bodyB.isStatic) { - constraint.pointB = Vector.rotate(pointB, bodyB.angle - constraint.angleB); - constraint.angleB = bodyB.angle; - } - - var pointAWorld = pointA, - pointBWorld = pointB; - - if (bodyA) pointAWorld = Vector.add(bodyA.position, pointA); - if (bodyB) pointBWorld = Vector.add(bodyB.position, pointB); - - if (!pointAWorld || !pointBWorld) - return; - - var delta = Vector.sub(pointAWorld, pointBWorld), - currentLength = Vector.magnitude(delta); - - // prevent singularity - if (currentLength === 0) - currentLength = _minLength; - - // solve distance constraint with Gauss-Siedel method - var difference = (currentLength - constraint.length) / currentLength, - normal = Vector.div(delta, currentLength), - force = Vector.mult(delta, difference * 0.5 * constraint.stiffness * timeScale * timeScale); - - // if difference is very small, we can skip - if (Math.abs(1 - (currentLength / constraint.length)) < _minDifference * timeScale) - return; - - var velocityPointA, - velocityPointB, - offsetA, - offsetB, - oAn, - oBn, - bodyADenom, - bodyBDenom; - - if (bodyA && !bodyA.isStatic) { - // point body offset - offsetA = { - x: pointAWorld.x - bodyA.position.x + force.x, - y: pointAWorld.y - bodyA.position.y + force.y - }; - - // update velocity - bodyA.velocity.x = bodyA.position.x - bodyA.positionPrev.x; - bodyA.velocity.y = bodyA.position.y - bodyA.positionPrev.y; - bodyA.angularVelocity = bodyA.angle - bodyA.anglePrev; - - // find point velocity and body mass - velocityPointA = Vector.add(bodyA.velocity, Vector.mult(Vector.perp(offsetA), bodyA.angularVelocity)); - oAn = Vector.dot(offsetA, normal); - bodyADenom = bodyA.inverseMass + bodyA.inverseInertia * oAn * oAn; - } else { - velocityPointA = { x: 0, y: 0 }; - bodyADenom = bodyA ? bodyA.inverseMass : 0; - } - - if (bodyB && !bodyB.isStatic) { - // point body offset - offsetB = { - x: pointBWorld.x - bodyB.position.x - force.x, - y: pointBWorld.y - bodyB.position.y - force.y - }; - - // update velocity - bodyB.velocity.x = bodyB.position.x - bodyB.positionPrev.x; - bodyB.velocity.y = bodyB.position.y - bodyB.positionPrev.y; - bodyB.angularVelocity = bodyB.angle - bodyB.anglePrev; - - // find point velocity and body mass - velocityPointB = Vector.add(bodyB.velocity, Vector.mult(Vector.perp(offsetB), bodyB.angularVelocity)); - oBn = Vector.dot(offsetB, normal); - bodyBDenom = bodyB.inverseMass + bodyB.inverseInertia * oBn * oBn; - } else { - velocityPointB = { x: 0, y: 0 }; - bodyBDenom = bodyB ? bodyB.inverseMass : 0; - } - - var relativeVelocity = Vector.sub(velocityPointB, velocityPointA), - normalImpulse = Vector.dot(normal, relativeVelocity) / (bodyADenom + bodyBDenom); - - if (normalImpulse > 0) normalImpulse = 0; - - var normalVelocity = { - x: normal.x * normalImpulse, - y: normal.y * normalImpulse - }; - - var torque; - - if (bodyA && !bodyA.isStatic) { - torque = Vector.cross(offsetA, normalVelocity) * bodyA.inverseInertia * (1 - constraint.angularStiffness); - - Sleeping.set(bodyA, false); - - // clamp to prevent instabillity - // TODO: solve this properlly - torque = Common.clamp(torque, -0.01, 0.01); - - // keep track of applied impulses for post solving - bodyA.constraintImpulse.x -= force.x; - bodyA.constraintImpulse.y -= force.y; - bodyA.constraintImpulse.angle += torque; - - // apply forces - bodyA.position.x -= force.x; - bodyA.position.y -= force.y; - bodyA.angle += torque; - } - - if (bodyB && !bodyB.isStatic) { - torque = Vector.cross(offsetB, normalVelocity) * bodyB.inverseInertia * (1 - constraint.angularStiffness); - - Sleeping.set(bodyB, false); - - // clamp to prevent instabillity - // TODO: solve this properlly - torque = Common.clamp(torque, -0.01, 0.01); - - // keep track of applied impulses for post solving - bodyB.constraintImpulse.x += force.x; - bodyB.constraintImpulse.y += force.y; - bodyB.constraintImpulse.angle -= torque; - - // apply forces - bodyB.position.x += force.x; - bodyB.position.y += force.y; - bodyB.angle -= torque; - } - - }; - - /** - * Performs body updates required after solving constraints - * @method postSolveAll - * @param {body[]} bodies - */ - Constraint.postSolveAll = function(bodies) { - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i], - impulse = body.constraintImpulse; - - // update geometry and reset - Vertices.translate(body.vertices, impulse); - - if (impulse.angle !== 0) { - Vertices.rotate(body.vertices, impulse.angle, body.position); - Axes.rotate(body.axes, impulse.angle); - impulse.angle = 0; - } - - Bounds.update(body.bounds, body.vertices); - - impulse.x = 0; - impulse.y = 0; - } - }; - -})(); - -; // End src/constraint/Constraint.js - - -// Begin src/constraint/MouseConstraint.js - -/** -* See [Demo.js](https://github.com/liabru/matter-js/blob/master/demo/js/Demo.js) -* and [DemoMobile.js](https://github.com/liabru/matter-js/blob/master/demo/js/DemoMobile.js) for usage examples. -* -* @class MouseConstraint -*/ - -var MouseConstraint = {}; - -(function() { - - /** - * Description - * @method create - * @param {engine} engine - * @param {} options - * @return {MouseConstraint} A new MouseConstraint - */ - MouseConstraint.create = function(engine, options) { - var mouse = engine.input.mouse; - - var constraint = Constraint.create({ - label: 'Mouse Constraint', - pointA: mouse.position, - pointB: { x: 0, y: 0 }, - length: 0.01, - stiffness: 0.1, - angularStiffness: 1, - render: { - strokeStyle: '#90EE90', - lineWidth: 3 - } - }); - - var defaults = { - type: 'mouseConstraint', - mouse: mouse, - dragBody: null, - dragPoint: null, - constraint: constraint - }; - - var mouseConstraint = Common.extend(defaults, options); - - Events.on(engine, 'tick', function(event) { - var allBodies = Composite.allBodies(engine.world); - MouseConstraint.update(mouseConstraint, allBodies); - }); - - return mouseConstraint; - }; - - /** - * Description - * @method update - * @param {MouseConstraint} mouseConstraint - * @param {body[]} bodies - */ - MouseConstraint.update = function(mouseConstraint, bodies) { - var mouse = mouseConstraint.mouse, - constraint = mouseConstraint.constraint; - - if (mouse.button === 0) { - if (!constraint.bodyB) { - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i]; - if (Bounds.contains(body.bounds, mouse.position) - && Vertices.contains(body.vertices, mouse.position)) { - constraint.pointA = mouse.position; - constraint.bodyB = body; - constraint.pointB = { x: mouse.position.x - body.position.x, y: mouse.position.y - body.position.y }; - constraint.angleB = body.angle; - Sleeping.set(body, false); - } - } - } - } else { - constraint.bodyB = null; - constraint.pointB = null; - } - - if (constraint.bodyB) { - Sleeping.set(constraint.bodyB, false); - constraint.pointA = mouse.position; - } - }; - -})(); - -; // End src/constraint/MouseConstraint.js - - -// Begin src/core/Common.js - -/** -* _Internal Class_, not generally used outside of the engine's internals. -* -* @class Common -*/ - -var Common = {}; - -(function() { - - Common._nextId = 0; - - /** - * Description - * @method extend - * @param {} obj - * @param {boolean} deep - * @return {} obj extended - */ - Common.extend = function(obj, deep) { - var argsStart, - args, - deepClone; - - if (typeof deep === 'boolean') { - argsStart = 2; - deepClone = deep; - } else { - argsStart = 1; - deepClone = true; - } - - args = Array.prototype.slice.call(arguments, argsStart); - - for (var i = 0; i < args.length; i++) { - var source = args[i]; - - if (source) { - for (var prop in source) { - if (deepClone && source[prop] && source[prop].constructor === Object) { - if (!obj[prop] || obj[prop].constructor === Object) { - obj[prop] = obj[prop] || {}; - Common.extend(obj[prop], deepClone, source[prop]); - } else { - obj[prop] = source[prop]; - } - } else { - obj[prop] = source[prop]; - } - } - } - } - - return obj; - }; - - /** - * Creates a new clone of the object, if deep is true references will also be cloned - * @method clone - * @param {} obj - * @param {bool} deep - * @return {} obj cloned - */ - Common.clone = function(obj, deep) { - return Common.extend({}, deep, obj); - }; - - /** - * Description - * @method keys - * @param {} obj - * @return {string[]} keys - */ - Common.keys = function(obj) { - if (Object.keys) - return Object.keys(obj); - - // avoid hasOwnProperty for performance - var keys = []; - for (var key in obj) - keys.push(key); - return keys; - }; - - /** - * Description - * @method values - * @param {} obj - * @return {array} Array of the objects property values - */ - Common.values = function(obj) { - var values = []; - - if (Object.keys) { - var keys = Object.keys(obj); - for (var i = 0; i < keys.length; i++) { - values.push(obj[keys[i]]); - } - return values; - } - - // avoid hasOwnProperty for performance - for (var key in obj) - values.push(obj[key]); - return values; - }; - - /** - * Description - * @method shadeColor - * @param {string} color - * @param {number} percent - * @return {string} A hex colour string made by lightening or darkening color by percent - */ - Common.shadeColor = function(color, percent) { - // http://stackoverflow.com/questions/5560248/programmatically-lighten-or-darken-a-hex-color - var colorInteger = parseInt(color.slice(1),16), - amount = Math.round(2.55 * percent), - R = (colorInteger >> 16) + amount, - B = (colorInteger >> 8 & 0x00FF) + amount, - G = (colorInteger & 0x0000FF) + amount; - return "#" + (0x1000000 + (R < 255 ? R < 1 ? 0 : R :255) * 0x10000 - + (B < 255 ? B < 1 ? 0 : B : 255) * 0x100 - + (G < 255 ? G < 1 ? 0 : G : 255)).toString(16).slice(1); - }; - - /** - * Description - * @method shuffle - * @param {array} array - * @return {array} array shuffled randomly - */ - Common.shuffle = function(array) { - for (var i = array.length - 1; i > 0; i--) { - var j = Math.floor(Math.random() * (i + 1)); - var temp = array[i]; - array[i] = array[j]; - array[j] = temp; - } - return array; - }; - - /** - * Description - * @method choose - * @param {array} choices - * @return {object} A random choice object from the array - */ - Common.choose = function(choices) { - return choices[Math.floor(Math.random() * choices.length)]; - }; - - /** - * Description - * @method isElement - * @param {object} obj - * @return {boolean} True if the object is a HTMLElement, otherwise false - */ - Common.isElement = function(obj) { - // http://stackoverflow.com/questions/384286/javascript-isdom-how-do-you-check-if-a-javascript-object-is-a-dom-object - try { - return obj instanceof HTMLElement; - } - catch(e){ - return (typeof obj==="object") && - (obj.nodeType===1) && (typeof obj.style === "object") && - (typeof obj.ownerDocument ==="object"); - } - }; - - /** - * Description - * @method clamp - * @param {number} value - * @param {number} min - * @param {number} max - * @return {number} The value clamped between min and max inclusive - */ - Common.clamp = function(value, min, max) { - if (value < min) - return min; - if (value > max) - return max; - return value; - }; - - /** - * Description - * @method sign - * @param {number} value - * @return {number} -1 if negative, +1 if 0 or positive - */ - Common.sign = function(value) { - return value < 0 ? -1 : 1; - }; - - /** - * Description - * @method now - * @return {number} the current timestamp (high-res if avaliable) - */ - Common.now = function() { - // http://stackoverflow.com/questions/221294/how-do-you-get-a-timestamp-in-javascript - // https://gist.github.com/davidwaterston/2982531 - - var perf = window.performance; - - if (perf) { - perf.now = perf.now || perf.webkitNow || perf.msNow || perf.oNow || perf.mozNow; - return +(perf.now()); - } - - return +(new Date()); - }; - - - /** - * Description - * @method random - * @param {number} min - * @param {number} max - * @return {number} A random number between min and max inclusive - */ - Common.random = function(min, max) { - return min + Math.random() * (max - min); - }; - - /** - * Converts a CSS hex colour string into an integer - * @method colorToNumber - * @param {string} colorString - * @return {number} An integer representing the CSS hex string - */ - Common.colorToNumber = function(colorString) { - colorString = colorString.replace('#',''); - - if (colorString.length == 3) { - colorString = colorString.charAt(0) + colorString.charAt(0) - + colorString.charAt(1) + colorString.charAt(1) - + colorString.charAt(2) + colorString.charAt(2); - } - - return parseInt(colorString, 16); - }; - - /** - * A wrapper for console.log, for providing errors and warnings - * @method log - * @param {string} message - * @param {string} type - */ - Common.log = function(message, type) { - if (!console || !console.log) - return; - - var style; - - switch (type) { - - case 'warn': - style = 'color: coral'; - break; - case 'error': - style = 'color: red'; - break; - - } - - console.log('%c [Matter] ' + type + ': ' + message, style); - }; - - /** - * Returns the next unique sequential ID - * @method nextId - * @return {Number} Unique sequential ID - */ - Common.nextId = function() { - return Common._nextId++; - }; - -})(); - -; // End src/core/Common.js - - -// Begin src/core/Engine.js - -/** -* See [Demo.js](https://github.com/liabru/matter-js/blob/master/demo/js/Demo.js) -* and [DemoMobile.js](https://github.com/liabru/matter-js/blob/master/demo/js/DemoMobile.js) for usage examples. -* -* @class Engine -*/ - -// TODO: viewports - -var Engine = {}; - -(function() { - - var _fps = 60, - _deltaSampleSize = _fps, - _delta = 1000 / _fps; - - var _requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame - || window.mozRequestAnimationFrame || window.msRequestAnimationFrame - || function(callback){ window.setTimeout(function() { callback(Common.now()); }, _delta); }; - - /** - * Description - * @method create - * @param {HTMLElement} element - * @param {object} options - * @return {engine} engine - */ - Engine.create = function(element, options) { - - // options may be passed as the first (and only) argument - options = Common.isElement(element) ? options : element; - element = Common.isElement(element) ? element : null; - - var defaults = { - enabled: true, - positionIterations: 6, - velocityIterations: 4, - constraintIterations: 2, - enableSleeping: false, - timeScale: 1, - input: {}, - events: [], - timing: { - fps: _fps, - timestamp: 0, - delta: _delta, - correction: 1, - deltaMin: 1000 / _fps, - deltaMax: 1000 / (_fps * 0.5), - timeScale: 1, - isFixed: false - }, - render: { - element: element, - controller: Render - } - }; - - var engine = Common.extend(defaults, options); - - engine.render = engine.render.controller.create(engine.render); - engine.world = World.create(engine.world); - engine.pairs = Pairs.create(); - engine.metrics = engine.metrics || Metrics.create(); - engine.input.mouse = engine.input.mouse || Mouse.create(engine.render.canvas); - - engine.broadphase = engine.broadphase || { - current: 'grid', - grid: { - controller: Grid, - instance: Grid.create(), - detector: Detector.collisions - }, - bruteForce: { - detector: Detector.bruteForce - } - }; - - return engine; - }; - - /** - * An optional utility function that provides a game loop, that handles updating the engine for you. - * Calls `Engine.update` and `Engine.render` on the `requestAnimationFrame` event automatically. - * Handles time correction and non-fixed dynamic timing (if enabled). - * Triggers `beforeTick`, `tick` and `afterTick` events. - * @method run - * @param {engine} engine - */ - Engine.run = function(engine) { - var counterTimestamp = 0, - frameCounter = 0, - deltaHistory = [], - timePrev, - timeScalePrev = 1; - - (function render(time){ - _requestAnimationFrame(render); - - if (!engine.enabled) - return; - - var timing = engine.timing, - delta, - correction; - - // create an event object - var event = { - timestamp: time - }; - - Events.trigger(engine, 'beforeTick', event); - - if (timing.isFixed) { - // fixed timestep - delta = timing.delta; - } else { - // dynamic timestep based on wall clock between calls - delta = (time - timePrev) || timing.delta; - timePrev = time; - - // optimistically filter delta over a few frames, to improve stability - deltaHistory.push(delta); - deltaHistory = deltaHistory.slice(-_deltaSampleSize); - delta = Math.min.apply(null, deltaHistory); - - // limit delta - delta = delta < timing.deltaMin ? timing.deltaMin : delta; - delta = delta > timing.deltaMax ? timing.deltaMax : delta; - - // time correction for delta - correction = delta / timing.delta; - - // update engine timing object - timing.delta = delta; - } - - // time correction for time scaling - if (timeScalePrev !== 0) - correction *= timing.timeScale / timeScalePrev; - - if (timing.timeScale === 0) - correction = 0; - - timeScalePrev = timing.timeScale; - - // fps counter - frameCounter += 1; - if (time - counterTimestamp >= 1000) { - timing.fps = frameCounter * ((time - counterTimestamp) / 1000); - counterTimestamp = time; - frameCounter = 0; - } - - Events.trigger(engine, 'tick', event); - - // if world has been modified, clear the render scene graph - if (engine.world.isModified) - engine.render.controller.clear(engine.render); - - // update - Engine.update(engine, delta, correction); - - // trigger events that may have occured during the step - _triggerCollisionEvents(engine); - _triggerMouseEvents(engine); - - // render - Engine.render(engine); - - Events.trigger(engine, 'afterTick', event); - })(); - }; - - /** - * Moves the simulation forward in time by `delta` ms. Triggers `beforeUpdate` and `afterUpdate` events. - * @method update - * @param {engine} engine - * @param {number} delta - * @param {number} correction - * @return engine - */ - Engine.update = function(engine, delta, correction) { - correction = (typeof correction !== 'undefined') ? correction : 1; - - var world = engine.world, - timing = engine.timing, - broadphase = engine.broadphase[engine.broadphase.current], - broadphasePairs = [], - i; - - // increment timestamp - timing.timestamp += delta * timing.timeScale; - timing.correction = correction; - - // create an event object - var event = { - timestamp: engine.timing.timestamp - }; - - Events.trigger(engine, 'beforeUpdate', event); - - // get lists of all bodies and constraints, no matter what composites they are in - var allBodies = Composite.allBodies(world), - allConstraints = Composite.allConstraints(world); - - // reset metrics logging - Metrics.reset(engine.metrics); - - // if sleeping enabled, call the sleeping controller - if (engine.enableSleeping) - Sleeping.update(allBodies); - - // applies gravity to all bodies - Body.applyGravityAll(allBodies, world.gravity); - - // update all body position and rotation by integration - Body.updateAll(allBodies, delta, timing.timeScale, correction, world.bounds); - - // update all constraints - for (i = 0; i < engine.constraintIterations; i++) { - Constraint.solveAll(allConstraints, timing.timeScale); - } - Constraint.postSolveAll(allBodies); - - // broadphase pass: find potential collision pairs - if (broadphase.controller) { - - // if world is dirty, we must flush the whole grid - if (world.isModified) - broadphase.controller.clear(broadphase.instance); - - // update the grid buckets based on current bodies - broadphase.controller.update(broadphase.instance, allBodies, engine, world.isModified); - broadphasePairs = broadphase.instance.pairsList; - } else { - - // if no broadphase set, we just pass all bodies - broadphasePairs = allBodies; - } - - // narrowphase pass: find actual collisions, then create or update collision pairs - var collisions = broadphase.detector(broadphasePairs, engine); - - // update collision pairs - var pairs = engine.pairs, - timestamp = timing.timestamp; - Pairs.update(pairs, collisions, timestamp); - Pairs.removeOld(pairs, timestamp); - - // wake up bodies involved in collisions - if (engine.enableSleeping) - Sleeping.afterCollisions(pairs.list); - - // iteratively resolve velocity between collisions - Resolver.preSolveVelocity(pairs.list); - for (i = 0; i < engine.velocityIterations; i++) { - Resolver.solveVelocity(pairs.list, timing.timeScale); - } - - // iteratively resolve position between collisions - for (i = 0; i < engine.positionIterations; i++) { - Resolver.solvePosition(pairs.list, timing.timeScale); - } - Resolver.postSolvePosition(allBodies); - - // update metrics log - Metrics.update(engine.metrics, engine); - - // clear force buffers - Body.resetForcesAll(allBodies); - - // clear all composite modified flags - if (world.isModified) - Composite.setModified(world, false, false, true); - - Events.trigger(engine, 'afterUpdate', event); - - return engine; - }; - - /** - * Renders the world by calling its defined renderer `engine.render.controller`. Triggers `beforeRender` and `afterRender` events. - * @method render - * @param {engine} engineA - * @param {engine} engineB - */ - Engine.render = function(engine) { - // create an event object - var event = { - timestamp: engine.timing.timestamp - }; - - Events.trigger(engine, 'beforeRender', event); - engine.render.controller.world(engine); - Events.trigger(engine, 'afterRender', event); - }; - - /** - * Description - * @method merge - * @param {engine} engineA - * @param {engine} engineB - */ - Engine.merge = function(engineA, engineB) { - Common.extend(engineA, engineB); - - if (engineB.world) { - engineA.world = engineB.world; - - Engine.clear(engineA); - - var bodies = Composite.allBodies(engineA.world); - - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i]; - Sleeping.set(body, false); - body.id = Common.nextId(); - } - } - }; - - /** - * Description - * @method clear - * @param {engine} engine - */ - Engine.clear = function(engine) { - var world = engine.world; - - Pairs.clear(engine.pairs); - - var broadphase = engine.broadphase[engine.broadphase.current]; - if (broadphase.controller) { - var bodies = Composite.allBodies(world); - broadphase.controller.clear(broadphase.instance); - broadphase.controller.update(broadphase.instance, bodies, engine, true); - } - }; - - /** - * Triggers mouse events - * @method _triggerMouseEvents - * @private - * @param {engine} engine - */ - var _triggerMouseEvents = function(engine) { - var mouse = engine.input.mouse, - mouseEvents = mouse.sourceEvents; - - if (mouseEvents.mousemove) { - Events.trigger(engine, 'mousemove', { - mouse: mouse - }); - } - - if (mouseEvents.mousedown) { - Events.trigger(engine, 'mousedown', { - mouse: mouse - }); - } - - if (mouseEvents.mouseup) { - Events.trigger(engine, 'mouseup', { - mouse: mouse - }); - } - - // reset the mouse state ready for the next step - Mouse.clearSourceEvents(mouse); - }; - - /** - * Triggers collision events - * @method _triggerMouseEvents - * @private - * @param {engine} engine - */ - var _triggerCollisionEvents = function(engine) { - var pairs = engine.pairs; - - if (pairs.collisionStart.length > 0) { - Events.trigger(engine, 'collisionStart', { - pairs: pairs.collisionStart - }); - } - - if (pairs.collisionActive.length > 0) { - Events.trigger(engine, 'collisionActive', { - pairs: pairs.collisionActive - }); - } - - if (pairs.collisionEnd.length > 0) { - Events.trigger(engine, 'collisionEnd', { - pairs: pairs.collisionEnd - }); - } - }; - - /* - * - * Events Documentation - * - */ - - /** - * Fired at the start of a tick, before any updates to the engine or timing - * - * @event beforeTick - * @param {} event An event object - * @param {DOMHighResTimeStamp} event.timestamp The timestamp of the current tick - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired after engine timing updated, but just before engine state updated - * - * @event tick - * @param {} event An event object - * @param {DOMHighResTimeStamp} event.timestamp The timestamp of the current tick - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired just before an update - * - * @event beforeUpdate - * @param {} event An event object - * @param {DOMHighResTimeStamp} event.timestamp The timestamp of the current tick - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired after engine update and all collision events - * - * @event afterUpdate - * @param {} event An event object - * @param {DOMHighResTimeStamp} event.timestamp The timestamp of the current tick - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired just before rendering - * - * @event beforeRender - * @param {} event An event object - * @param {DOMHighResTimeStamp} event.timestamp The timestamp of the current tick - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired after rendering - * - * @event afterRender - * @param {} event An event object - * @param {DOMHighResTimeStamp} event.timestamp The timestamp of the current tick - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired after engine update and after rendering - * - * @event afterTick - * @param {} event An event object - * @param {DOMHighResTimeStamp} event.timestamp The timestamp of the current tick - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired when the mouse has moved (or a touch moves) during the last step - * - * @event mousemove - * @param {} event An event object - * @param {mouse} event.mouse The engine's mouse instance - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired when the mouse is down (or a touch has started) during the last step - * - * @event mousedown - * @param {} event An event object - * @param {mouse} event.mouse The engine's mouse instance - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired when the mouse is up (or a touch has ended) during the last step - * - * @event mouseup - * @param {} event An event object - * @param {mouse} event.mouse The engine's mouse instance - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired after engine update, provides a list of all pairs that have started to collide in the current tick (if any) - * - * @event collisionStart - * @param {} event An event object - * @param {} event.pairs List of affected pairs - * @param {DOMHighResTimeStamp} event.timestamp The timestamp of the current tick - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired after engine update, provides a list of all pairs that are colliding in the current tick (if any) - * - * @event collisionActive - * @param {} event An event object - * @param {} event.pairs List of affected pairs - * @param {DOMHighResTimeStamp} event.timestamp The timestamp of the current tick - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - - /** - * Fired after engine update, provides a list of all pairs that have ended collision in the current tick (if any) - * - * @event collisionEnd - * @param {} event An event object - * @param {} event.pairs List of affected pairs - * @param {DOMHighResTimeStamp} event.timestamp The timestamp of the current tick - * @param {} event.source The source object of the event - * @param {} event.name The name of the event - */ - -})(); - -; // End src/core/Engine.js - - -// Begin src/core/Events.js - -/** -* See [Demo.js](https://github.com/liabru/matter-js/blob/master/demo/js/Demo.js) -* and [DemoMobile.js](https://github.com/liabru/matter-js/blob/master/demo/js/DemoMobile.js) for usage examples. -* -* @class Events -*/ - -var Events = {}; - -(function() { - - /** - * Subscribes a callback function to the given object's eventName - * @method on - * @param {} object - * @param {string} eventNames - * @param {function} callback - */ - Events.on = function(object, eventNames, callback) { - var names = eventNames.split(' '), - name; - - for (var i = 0; i < names.length; i++) { - name = names[i]; - object.events = object.events || {}; - object.events[name] = object.events[name] || []; - object.events[name].push(callback); - } - - return callback; - }; - - /** - * Removes the given event callback. If no callback, clears all callbacks in eventNames. If no eventNames, clears all events. - * @method off - * @param {} object - * @param {string} eventNames - * @param {function} callback - */ - Events.off = function(object, eventNames, callback) { - if (!eventNames) { - object.events = {}; - return; - } - - // handle Events.off(object, callback) - if (typeof eventNames === 'function') { - callback = eventNames; - eventNames = Common.keys(object.events).join(' '); - } - - var names = eventNames.split(' '); - - for (var i = 0; i < names.length; i++) { - var callbacks = object.events[names[i]], - newCallbacks = []; - - if (callback) { - for (var j = 0; j < callbacks.length; j++) { - if (callbacks[j] !== callback) - newCallbacks.push(callbacks[j]); - } - } - - object.events[names[i]] = newCallbacks; - } - }; - - /** - * Fires all the callbacks subscribed to the given object's eventName, in the order they subscribed, if any - * @method trigger - * @param {} object - * @param {string} eventNames - * @param {} event - */ - Events.trigger = function(object, eventNames, event) { - var names, - name, - callbacks, - eventClone; - - if (object.events) { - if (!event) - event = {}; - - names = eventNames.split(' '); - - for (var i = 0; i < names.length; i++) { - name = names[i]; - callbacks = object.events[name]; - - if (callbacks) { - eventClone = Common.clone(event, false); - eventClone.name = name; - eventClone.source = object; - - for (var j = 0; j < callbacks.length; j++) { - callbacks[j].apply(object, [eventClone]); - } - } - } - } - }; - -})(); - -; // End src/core/Events.js - - -// Begin src/core/Metrics.js - -/** -* _Internal Class_, not generally used outside of the engine's internals. -* -* @class Metrics -*/ - -var Metrics = {}; - -(function() { - - /** - * Description - * @method create - * @return {metrics} A new metrics - */ - Metrics.create = function() { - return { - extended: false, - narrowDetections: 0, - narrowphaseTests: 0, - narrowReuse: 0, - narrowReuseCount: 0, - midphaseTests: 0, - broadphaseTests: 0, - narrowEff: 0.0001, - midEff: 0.0001, - broadEff: 0.0001, - collisions: 0, - buckets: 0, - bodies: 0, - pairs: 0 - }; - }; - - /** - * Description - * @method reset - * @param {metrics} metrics - */ - Metrics.reset = function(metrics) { - if (metrics.extended) { - metrics.narrowDetections = 0; - metrics.narrowphaseTests = 0; - metrics.narrowReuse = 0; - metrics.narrowReuseCount = 0; - metrics.midphaseTests = 0; - metrics.broadphaseTests = 0; - metrics.narrowEff = 0; - metrics.midEff = 0; - metrics.broadEff = 0; - metrics.collisions = 0; - metrics.buckets = 0; - metrics.pairs = 0; - metrics.bodies = 0; - } - }; - - /** - * Description - * @method update - * @param {metrics} metrics - * @param {engine} engine - */ - Metrics.update = function(metrics, engine) { - if (metrics.extended) { - var world = engine.world, - broadphase = engine.broadphase[engine.broadphase.current], - bodies = Composite.allBodies(world); - - metrics.collisions = metrics.narrowDetections; - metrics.pairs = engine.pairs.list.length; - metrics.bodies = bodies.length; - metrics.midEff = (metrics.narrowDetections / (metrics.midphaseTests || 1)).toFixed(2); - metrics.narrowEff = (metrics.narrowDetections / (metrics.narrowphaseTests || 1)).toFixed(2); - metrics.broadEff = (1 - (metrics.broadphaseTests / (bodies.length || 1))).toFixed(2); - metrics.narrowReuse = (metrics.narrowReuseCount / (metrics.narrowphaseTests || 1)).toFixed(2); - //if (broadphase.instance) - // metrics.buckets = Common.keys(broadphase.instance.buckets).length; - } - }; - -})(); - -; // End src/core/Metrics.js - - -// Begin src/core/Mouse.js - -/** -* _Internal Class_, not generally used outside of the engine's internals. -* -* @class Mouse -*/ - -var Mouse; - -(function() { - - /** - * Description - * @param {HTMLElement} element - */ - Mouse = function(element) { - var mouse = this; - - this.element = element || document.body; - this.absolute = { x: 0, y: 0 }; - this.position = { x: 0, y: 0 }; - this.mousedownPosition = { x: 0, y: 0 }; - this.mouseupPosition = { x: 0, y: 0 }; - this.offset = { x: 0, y: 0 }; - this.scale = { x: 1, y: 1 }; - this.wheelDelta = 0; - this.button = -1; - - this.sourceEvents = { - mousemove: null, - mousedown: null, - mouseup: null, - mousewheel: null - }; - - this.mousemove = function(event) { - var position = _getRelativeMousePosition(event, mouse.element), - touches = event.changedTouches; - - if (touches) { - mouse.button = 0; - event.preventDefault(); - } - - mouse.absolute.x = position.x; - mouse.absolute.y = position.y; - mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x; - mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y; - mouse.sourceEvents.mousemove = event; - }; - - this.mousedown = function(event) { - var position = _getRelativeMousePosition(event, mouse.element), - touches = event.changedTouches; - - if (touches) { - mouse.button = 0; - event.preventDefault(); - } else { - mouse.button = event.button; - } - - mouse.absolute.x = position.x; - mouse.absolute.y = position.y; - mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x; - mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y; - mouse.mousedownPosition.x = mouse.position.x; - mouse.mousedownPosition.y = mouse.position.y; - mouse.sourceEvents.mousedown = event; - }; - - this.mouseup = function(event) { - var position = _getRelativeMousePosition(event, mouse.element), - touches = event.changedTouches; - - if (touches) { - event.preventDefault(); - } - - mouse.button = -1; - mouse.absolute.x = position.x; - mouse.absolute.y = position.y; - mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x; - mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y; - mouse.mouseupPosition.x = mouse.position.x; - mouse.mouseupPosition.y = mouse.position.y; - mouse.sourceEvents.mouseup = event; - }; - - this.mousewheel = function(event) { - mouse.wheelDelta = Math.max(-1, Math.min(1, event.wheelDelta || -event.detail)); - event.preventDefault(); - }; - - Mouse.setElement(mouse, mouse.element); - }; - - /** - * Description - * @method create - * @param {HTMLElement} element - * @return {mouse} A new mouse - */ - Mouse.create = function(element) { - return new Mouse(element); - }; - - /** - * Sets the element the mouse is bound to (and relative to) - * @method setElement - * @param {mouse} mouse - * @param {HTMLElement} element - */ - Mouse.setElement = function(mouse, element) { - mouse.element = element; - - element.addEventListener('mousemove', mouse.mousemove); - element.addEventListener('mousedown', mouse.mousedown); - element.addEventListener('mouseup', mouse.mouseup); - - element.addEventListener("mousewheel", mouse.mousewheel); - element.addEventListener("DOMMouseScroll", mouse.mousewheel); - - element.addEventListener('touchmove', mouse.mousemove); - element.addEventListener('touchstart', mouse.mousedown); - element.addEventListener('touchend', mouse.mouseup); - }; - - /** - * Clears all captured source events - * @method clearSourceEvents - * @param {mouse} mouse - */ - Mouse.clearSourceEvents = function(mouse) { - mouse.sourceEvents.mousemove = null; - mouse.sourceEvents.mousedown = null; - mouse.sourceEvents.mouseup = null; - mouse.sourceEvents.mousewheel = null; - mouse.wheelDelta = 0; - }; - - /** - * Sets the offset - * @method setOffset - * @param {mouse} mouse - */ - Mouse.setOffset = function(mouse, offset) { - mouse.offset.x = offset.x; - mouse.offset.y = offset.y; - mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x; - mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y; - }; - - /** - * Sets the scale - * @method setScale - * @param {mouse} mouse - */ - Mouse.setScale = function(mouse, scale) { - mouse.scale.x = scale.x; - mouse.scale.y = scale.y; - mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x; - mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y; - }; - - /** - * Description - * @method _getRelativeMousePosition - * @private - * @param {} event - * @param {} element - * @return ObjectExpression - */ - var _getRelativeMousePosition = function(event, element) { - var elementBounds = element.getBoundingClientRect(), - rootNode = (document.documentElement || document.body.parentNode || document.body), - scrollX = (window.pageXOffset !== undefined) ? window.pageXOffset : rootNode.scrollLeft, - scrollY = (window.pageYOffset !== undefined) ? window.pageYOffset : rootNode.scrollTop, - touches = event.changedTouches, - x, y; - - if (touches) { - x = touches[0].pageX - elementBounds.left - scrollX; - y = touches[0].pageY - elementBounds.top - scrollY; - } else { - x = event.pageX - elementBounds.left - scrollX; - y = event.pageY - elementBounds.top - scrollY; - } - - return { - x: x / (element.clientWidth / element.width), - y: y / (element.clientHeight / element.height) - }; - }; - -})(); - -; // End src/core/Mouse.js - - -// Begin src/core/Sleeping.js - -/** -* _Internal Class_, not generally used outside of the engine's internals. -* -* @class Sleeping -*/ - -var Sleeping = {}; - -(function() { - - var _motionWakeThreshold = 0.18, - _motionSleepThreshold = 0.08, - _minBias = 0.9; - - /** - * Description - * @method update - * @param {body[]} bodies - */ - Sleeping.update = function(bodies) { - // update bodies sleeping status - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i], - motion = body.speed * body.speed + body.angularSpeed * body.angularSpeed; - - // wake up bodies if they have a force applied - if (body.force.x > 0 || body.force.y > 0) { - Sleeping.set(body, false); - continue; - } - - var minMotion = Math.min(body.motion, motion), - maxMotion = Math.max(body.motion, motion); - - // biased average motion estimation between frames - body.motion = _minBias * minMotion + (1 - _minBias) * maxMotion; - - if (body.sleepThreshold > 0 && body.motion < _motionSleepThreshold) { - body.sleepCounter += 1; - - if (body.sleepCounter >= body.sleepThreshold) - Sleeping.set(body, true); - } else if (body.sleepCounter > 0) { - body.sleepCounter -= 1; - } - } - }; - - /** - * Description - * @method afterCollisions - * @param {pair[]} pairs - */ - Sleeping.afterCollisions = function(pairs) { - // wake up bodies involved in collisions - for (var i = 0; i < pairs.length; i++) { - var pair = pairs[i]; - - // don't wake inactive pairs - if (!pair.isActive) - continue; - - var collision = pair.collision, - bodyA = collision.bodyA, - bodyB = collision.bodyB; - - // don't wake if at least one body is static - if ((bodyA.isSleeping && bodyB.isSleeping) || bodyA.isStatic || bodyB.isStatic) - continue; - - if (bodyA.isSleeping || bodyB.isSleeping) { - var sleepingBody = (bodyA.isSleeping && !bodyA.isStatic) ? bodyA : bodyB, - movingBody = sleepingBody === bodyA ? bodyB : bodyA; - - if (!sleepingBody.isStatic && movingBody.motion > _motionWakeThreshold) { - Sleeping.set(sleepingBody, false); - } - } - } - }; - - /** - * Description - * @method set - * @param {body} body - * @param {boolean} isSleeping - */ - Sleeping.set = function(body, isSleeping) { - if (isSleeping) { - body.isSleeping = true; - body.sleepCounter = body.sleepThreshold; - - body.positionImpulse.x = 0; - body.positionImpulse.y = 0; - - body.positionPrev.x = body.position.x; - body.positionPrev.y = body.position.y; - - body.anglePrev = body.angle; - body.speed = 0; - body.angularSpeed = 0; - body.motion = 0; - } else { - body.isSleeping = false; - body.sleepCounter = 0; - } - }; - -})(); - -; // End src/core/Sleeping.js - - -// Begin src/factory/Bodies.js - -/** -* See [Demo.js](https://github.com/liabru/matter-js/blob/master/demo/js/Demo.js) -* and [DemoMobile.js](https://github.com/liabru/matter-js/blob/master/demo/js/DemoMobile.js) for usage examples. -* -* @class Bodies -*/ - -// TODO: true circle bodies - -var Bodies = {}; - -(function() { - - /** - * Description - * @method rectangle - * @param {number} x - * @param {number} y - * @param {number} width - * @param {number} height - * @param {object} options - * @return {body} A new rectangle body - */ - Bodies.rectangle = function(x, y, width, height, options) { - options = options || {}; - - var rectangle = { - label: 'Rectangle Body', - position: { x: x, y: y }, - vertices: Vertices.fromPath('L 0 0 L ' + width + ' 0 L ' + width + ' ' + height + ' L 0 ' + height) - }; - - if (options.chamfer) { - var chamfer = options.chamfer; - rectangle.vertices = Vertices.chamfer(rectangle.vertices, chamfer.radius, - chamfer.quality, chamfer.qualityMin, chamfer.qualityMax); - delete options.chamfer; - } - - return Body.create(Common.extend({}, rectangle, options)); - }; - - /** - * Description - * @method trapezoid - * @param {number} x - * @param {number} y - * @param {number} width - * @param {number} height - * @param {number} slope - * @param {object} options - * @return {body} A new trapezoid body - */ - Bodies.trapezoid = function(x, y, width, height, slope, options) { - options = options || {}; - - slope *= 0.5; - var roof = (1 - (slope * 2)) * width; - - var x1 = width * slope, - x2 = x1 + roof, - x3 = x2 + x1; - - var trapezoid = { - label: 'Trapezoid Body', - position: { x: x, y: y }, - vertices: Vertices.fromPath('L 0 0 L ' + x1 + ' ' + (-height) + ' L ' + x2 + ' ' + (-height) + ' L ' + x3 + ' 0') - }; - - if (options.chamfer) { - var chamfer = options.chamfer; - trapezoid.vertices = Vertices.chamfer(trapezoid.vertices, chamfer.radius, - chamfer.quality, chamfer.qualityMin, chamfer.qualityMax); - delete options.chamfer; - } - - return Body.create(Common.extend({}, trapezoid, options)); - }; - - /** - * Description - * @method circle - * @param {number} x - * @param {number} y - * @param {number} radius - * @param {object} options - * @param {number} maxSides - * @return {body} A new circle body - */ - Bodies.circle = function(x, y, radius, options, maxSides) { - options = options || {}; - options.label = 'Circle Body'; - - // approximate circles with polygons until true circles implemented in SAT - - maxSides = maxSides || 25; - var sides = Math.ceil(Math.max(10, Math.min(maxSides, radius))); - - // optimisation: always use even number of sides (half the number of unique axes) - if (sides % 2 === 1) - sides += 1; - - // flag for better rendering - options.circleRadius = radius; - - return Bodies.polygon(x, y, sides, radius, options); - }; - - /** - * Description - * @method polygon - * @param {number} x - * @param {number} y - * @param {number} sides - * @param {number} radius - * @param {object} options - * @return {body} A new regular polygon body - */ - Bodies.polygon = function(x, y, sides, radius, options) { - options = options || {}; - - if (sides < 3) - return Bodies.circle(x, y, radius, options); - - var theta = 2 * Math.PI / sides, - path = '', - offset = theta * 0.5; - - for (var i = 0; i < sides; i += 1) { - var angle = offset + (i * theta), - xx = Math.cos(angle) * radius, - yy = Math.sin(angle) * radius; - - path += 'L ' + xx.toFixed(3) + ' ' + yy.toFixed(3) + ' '; - } - - var polygon = { - label: 'Polygon Body', - position: { x: x, y: y }, - vertices: Vertices.fromPath(path) - }; - - if (options.chamfer) { - var chamfer = options.chamfer; - polygon.vertices = Vertices.chamfer(polygon.vertices, chamfer.radius, - chamfer.quality, chamfer.qualityMin, chamfer.qualityMax); - delete options.chamfer; - } - - return Body.create(Common.extend({}, polygon, options)); - }; - -})(); - -; // End src/factory/Bodies.js - - -// Begin src/factory/Composites.js - -/** -* See [Demo.js](https://github.com/liabru/matter-js/blob/master/demo/js/Demo.js) -* and [DemoMobile.js](https://github.com/liabru/matter-js/blob/master/demo/js/DemoMobile.js) for usage examples. -* -* @class Composites -*/ - -var Composites = {}; - -(function() { - - /** - * Description - * @method stack - * @param {number} xx - * @param {number} yy - * @param {number} columns - * @param {number} rows - * @param {number} columnGap - * @param {number} rowGap - * @param {function} callback - * @return {composite} A new composite containing objects created in the callback - */ - Composites.stack = function(xx, yy, columns, rows, columnGap, rowGap, callback) { - var stack = Composite.create({ label: 'Stack' }), - x = xx, - y = yy, - lastBody, - i = 0; - - for (var row = 0; row < rows; row++) { - var maxHeight = 0; - - for (var column = 0; column < columns; column++) { - var body = callback(x, y, column, row, lastBody, i); - - if (body) { - var bodyHeight = body.bounds.max.y - body.bounds.min.y, - bodyWidth = body.bounds.max.x - body.bounds.min.x; - - if (bodyHeight > maxHeight) - maxHeight = bodyHeight; - - Body.translate(body, { x: bodyWidth * 0.5, y: bodyHeight * 0.5 }); - - x = body.bounds.max.x + columnGap; - - Composite.addBody(stack, body); - - lastBody = body; - i += 1; - } - } - - y += maxHeight + rowGap; - x = xx; - } - - return stack; - }; - - /** - * Description - * @method chain - * @param {composite} composite - * @param {number} xOffsetA - * @param {number} yOffsetA - * @param {number} xOffsetB - * @param {number} yOffsetB - * @param {object} options - * @return {composite} A new composite containing objects chained together with constraints - */ - Composites.chain = function(composite, xOffsetA, yOffsetA, xOffsetB, yOffsetB, options) { - var bodies = composite.bodies; - - for (var i = 1; i < bodies.length; i++) { - var bodyA = bodies[i - 1], - bodyB = bodies[i], - bodyAHeight = bodyA.bounds.max.y - bodyA.bounds.min.y, - bodyAWidth = bodyA.bounds.max.x - bodyA.bounds.min.x, - bodyBHeight = bodyB.bounds.max.y - bodyB.bounds.min.y, - bodyBWidth = bodyB.bounds.max.x - bodyB.bounds.min.x; - - var defaults = { - bodyA: bodyA, - pointA: { x: bodyAWidth * xOffsetA, y: bodyAHeight * yOffsetA }, - bodyB: bodyB, - pointB: { x: bodyBWidth * xOffsetB, y: bodyBHeight * yOffsetB } - }; - - var constraint = Common.extend(defaults, options); - - Composite.addConstraint(composite, Constraint.create(constraint)); - } - - composite.label += ' Chain'; - - return composite; - }; - - /** - * Connects bodies in the composite with constraints in a grid pattern, with optional cross braces - * @method mesh - * @param {composite} composite - * @param {number} columns - * @param {number} rows - * @param {boolean} crossBrace - * @param {object} options - * @return {composite} The composite containing objects meshed together with constraints - */ - Composites.mesh = function(composite, columns, rows, crossBrace, options) { - var bodies = composite.bodies, - row, - col, - bodyA, - bodyB, - bodyC; - - for (row = 0; row < rows; row++) { - for (col = 0; col < columns; col++) { - if (col > 0) { - bodyA = bodies[(col - 1) + (row * columns)]; - bodyB = bodies[col + (row * columns)]; - Composite.addConstraint(composite, Constraint.create(Common.extend({ bodyA: bodyA, bodyB: bodyB }, options))); - } - } - - for (col = 0; col < columns; col++) { - if (row > 0) { - bodyA = bodies[col + ((row - 1) * columns)]; - bodyB = bodies[col + (row * columns)]; - Composite.addConstraint(composite, Constraint.create(Common.extend({ bodyA: bodyA, bodyB: bodyB }, options))); - - if (crossBrace && col > 0) { - bodyC = bodies[(col - 1) + ((row - 1) * columns)]; - Composite.addConstraint(composite, Constraint.create(Common.extend({ bodyA: bodyC, bodyB: bodyB }, options))); - } - - if (crossBrace && col < columns - 1) { - bodyC = bodies[(col + 1) + ((row - 1) * columns)]; - Composite.addConstraint(composite, Constraint.create(Common.extend({ bodyA: bodyC, bodyB: bodyB }, options))); - } - } - } - } - - composite.label += ' Mesh'; - - return composite; - }; - - /** - * Description - * @method pyramid - * @param {number} xx - * @param {number} yy - * @param {number} columns - * @param {number} rows - * @param {number} columnGap - * @param {number} rowGap - * @param {function} callback - * @return {composite} A new composite containing objects created in the callback - */ - Composites.pyramid = function(xx, yy, columns, rows, columnGap, rowGap, callback) { - return Composites.stack(xx, yy, columns, rows, columnGap, rowGap, function(x, y, column, row, lastBody, i) { - var actualRows = Math.min(rows, Math.ceil(columns / 2)), - lastBodyWidth = lastBody ? lastBody.bounds.max.x - lastBody.bounds.min.x : 0; - - if (row > actualRows) - return; - - // reverse row order - row = actualRows - row; - - var start = row, - end = columns - 1 - row; - - if (column < start || column > end) - return; - - // retroactively fix the first body's position, since width was unknown - if (i === 1) { - Body.translate(lastBody, { x: (column + (columns % 2 === 1 ? 1 : -1)) * lastBodyWidth, y: 0 }); - } - - var xOffset = lastBody ? column * lastBodyWidth : 0; - - return callback(xx + xOffset + column * columnGap, y, column, row, lastBody, i); - }); - }; - - /** - * Description - * @method newtonsCradle - * @param {number} xx - * @param {number} yy - * @param {number} number - * @param {number} size - * @param {number} length - * @return {composite} A new composite newtonsCradle body - */ - Composites.newtonsCradle = function(xx, yy, number, size, length) { - var newtonsCradle = Composite.create({ label: 'Newtons Cradle' }); - - for (var i = 0; i < number; i++) { - var separation = 1.9, - circle = Bodies.circle(xx + i * (size * separation), yy + length, size, - { inertia: 99999, restitution: 1, friction: 0, frictionAir: 0.0001, slop: 0.01 }), - constraint = Constraint.create({ pointA: { x: xx + i * (size * separation), y: yy }, bodyB: circle }); - - Composite.addBody(newtonsCradle, circle); - Composite.addConstraint(newtonsCradle, constraint); - } - - return newtonsCradle; - }; - - /** - * Description - * @method car - * @param {number} xx - * @param {number} yy - * @param {number} width - * @param {number} height - * @param {number} wheelSize - * @return {composite} A new composite car body - */ - Composites.car = function(xx, yy, width, height, wheelSize) { - var groupId = Body.nextGroupId(), - wheelBase = -20, - wheelAOffset = -width * 0.5 + wheelBase, - wheelBOffset = width * 0.5 - wheelBase, - wheelYOffset = 0; - - var car = Composite.create({ label: 'Car' }), - body = Bodies.trapezoid(xx, yy, width, height, 0.3, { - groupId: groupId, - friction: 0.01, - chamfer: { - radius: 10 - } - }); - - var wheelA = Bodies.circle(xx + wheelAOffset, yy + wheelYOffset, wheelSize, { - groupId: groupId, - restitution: 0.5, - friction: 0.9, - density: 0.01 - }); - - var wheelB = Bodies.circle(xx + wheelBOffset, yy + wheelYOffset, wheelSize, { - groupId: groupId, - restitution: 0.5, - friction: 0.9, - density: 0.01 - }); - - var axelA = Constraint.create({ - bodyA: body, - pointA: { x: wheelAOffset, y: wheelYOffset }, - bodyB: wheelA, - stiffness: 0.5 - }); - - var axelB = Constraint.create({ - bodyA: body, - pointA: { x: wheelBOffset, y: wheelYOffset }, - bodyB: wheelB, - stiffness: 0.5 - }); - - Composite.addBody(car, body); - Composite.addBody(car, wheelA); - Composite.addBody(car, wheelB); - Composite.addConstraint(car, axelA); - Composite.addConstraint(car, axelB); - - return car; - }; - - /** - * Creates a simple soft body like object - * @method softBody - * @param {number} xx - * @param {number} yy - * @param {number} columns - * @param {number} rows - * @param {number} columnGap - * @param {number} rowGap - * @param {boolean} crossBrace - * @param {number} particleRadius - * @param {} particleOptions - * @param {} constraintOptions - * @return {composite} A new composite softBody - */ - Composites.softBody = function(xx, yy, columns, rows, columnGap, rowGap, crossBrace, particleRadius, particleOptions, constraintOptions) { - particleOptions = Common.extend({ inertia: Infinity }, particleOptions); - constraintOptions = Common.extend({ stiffness: 0.4 }, constraintOptions); - - var softBody = Composites.stack(xx, yy, columns, rows, columnGap, rowGap, function(x, y, column, row) { - return Bodies.circle(x, y, particleRadius, particleOptions); - }); - - Composites.mesh(softBody, columns, rows, crossBrace, constraintOptions); - - softBody.label = 'Soft Body'; - - return softBody; - }; - -})(); - -; // End src/factory/Composites.js - - -// Begin src/geometry/Axes.js - -/** -* _Internal Class_, not generally used outside of the engine's internals. -* -* @class Axes -*/ - -var Axes = {}; - -(function() { - - /** - * Description - * @method fromVertices - * @param {vertices} vertices - * @return {axes} A new axes from the given vertices - */ - Axes.fromVertices = function(vertices) { - var axes = {}; - - // find the unique axes, using edge normal gradients - for (var i = 0; i < vertices.length; i++) { - var j = (i + 1) % vertices.length, - normal = Vector.normalise({ - x: vertices[j].y - vertices[i].y, - y: vertices[i].x - vertices[j].x - }), - gradient = (normal.y === 0) ? Infinity : (normal.x / normal.y); - - // limit precision - gradient = gradient.toFixed(3).toString(); - - axes[gradient] = normal; - } - - return Common.values(axes); - }; - - /** - * Description - * @method rotate - * @param {axes} axes - * @param {number} angle - */ - Axes.rotate = function(axes, angle) { - if (angle === 0) - return; - - var cos = Math.cos(angle), - sin = Math.sin(angle); - - for (var i = 0; i < axes.length; i++) { - var axis = axes[i], - xx; - xx = axis.x * cos - axis.y * sin; - axis.y = axis.x * sin + axis.y * cos; - axis.x = xx; - } - }; - -})(); - -; // End src/geometry/Axes.js - - -// Begin src/geometry/Bounds.js - -/** -* _Internal Class_, not generally used outside of the engine's internals. -* -* @class Bounds -*/ - -var Bounds = {}; - -(function() { - - /** - * Description - * @method create - * @param {vertices} vertices - * @return {bounds} A new bounds object - */ - Bounds.create = function(vertices) { - var bounds = { - min: { x: 0, y: 0 }, - max: { x: 0, y: 0 } - }; - - if (vertices) - Bounds.update(bounds, vertices); - - return bounds; - }; - - /** - * Description - * @method update - * @param {bounds} bounds - * @param {vertices} vertices - * @param {vector} velocity - */ - Bounds.update = function(bounds, vertices, velocity) { - bounds.min.x = Number.MAX_VALUE; - bounds.max.x = Number.MIN_VALUE; - bounds.min.y = Number.MAX_VALUE; - bounds.max.y = Number.MIN_VALUE; - - for (var i = 0; i < vertices.length; i++) { - var vertex = vertices[i]; - if (vertex.x > bounds.max.x) bounds.max.x = vertex.x; - if (vertex.x < bounds.min.x) bounds.min.x = vertex.x; - if (vertex.y > bounds.max.y) bounds.max.y = vertex.y; - if (vertex.y < bounds.min.y) bounds.min.y = vertex.y; - } - - if (velocity) { - if (velocity.x > 0) { - bounds.max.x += velocity.x; - } else { - bounds.min.x += velocity.x; - } - - if (velocity.y > 0) { - bounds.max.y += velocity.y; - } else { - bounds.min.y += velocity.y; - } - } - }; - - /** - * Description - * @method contains - * @param {bounds} bounds - * @param {vector} point - * @return {boolean} True if the bounds contain the point, otherwise false - */ - Bounds.contains = function(bounds, point) { - return point.x >= bounds.min.x && point.x <= bounds.max.x - && point.y >= bounds.min.y && point.y <= bounds.max.y; - }; - - /** - * Description - * @method overlaps - * @param {bounds} boundsA - * @param {bounds} boundsB - * @return {boolean} True if the bounds overlap, otherwise false - */ - Bounds.overlaps = function(boundsA, boundsB) { - return (boundsA.min.x <= boundsB.max.x && boundsA.max.x >= boundsB.min.x - && boundsA.max.y >= boundsB.min.y && boundsA.min.y <= boundsB.max.y); - }; - - /** - * Translates the bounds by the given vector - * @method translate - * @param {bounds} bounds - * @param {vector} vector - */ - Bounds.translate = function(bounds, vector) { - bounds.min.x += vector.x; - bounds.max.x += vector.x; - bounds.min.y += vector.y; - bounds.max.y += vector.y; - }; - - /** - * Shifts the bounds to the given position - * @method shift - * @param {bounds} bounds - * @param {vector} position - */ - Bounds.shift = function(bounds, position) { - var deltaX = bounds.max.x - bounds.min.x, - deltaY = bounds.max.y - bounds.min.y; - - bounds.min.x = position.x; - bounds.max.x = position.x + deltaX; - bounds.min.y = position.y; - bounds.max.y = position.y + deltaY; - }; - -})(); - -; // End src/geometry/Bounds.js - - -// Begin src/geometry/Vector.js - -/** -* See [Demo.js](https://github.com/liabru/matter-js/blob/master/demo/js/Demo.js) -* and [DemoMobile.js](https://github.com/liabru/matter-js/blob/master/demo/js/DemoMobile.js) for usage examples. -* -* @class Vector -*/ - -// TODO: consider params for reusing vector objects - -var Vector = {}; - -(function() { - - /** - * Description - * @method magnitude - * @param {vector} vector - * @return {number} The magnitude of the vector - */ - Vector.magnitude = function(vector) { - return Math.sqrt((vector.x * vector.x) + (vector.y * vector.y)); - }; - - /** - * Description - * @method magnitudeSquared - * @param {vector} vector - * @return {number} The squared magnitude of the vector - */ - Vector.magnitudeSquared = function(vector) { - return (vector.x * vector.x) + (vector.y * vector.y); - }; - - /** - * Description - * @method rotate - * @param {vector} vector - * @param {number} angle - * @return {vector} A new vector rotated - */ - Vector.rotate = function(vector, angle) { - var cos = Math.cos(angle), sin = Math.sin(angle); - return { - x: vector.x * cos - vector.y * sin, - y: vector.x * sin + vector.y * cos - }; - }; - - /** - * Description - * @method rotateAbout - * @param {vector} vector - * @param {number} angle - * @param {vector} point - * @return {vector} A new vector rotated about the point - */ - Vector.rotateAbout = function(vector, angle, point) { - var cos = Math.cos(angle), sin = Math.sin(angle); - return { - x: point.x + ((vector.x - point.x) * cos - (vector.y - point.y) * sin), - y: point.y + ((vector.x - point.x) * sin + (vector.y - point.y) * cos) - }; - }; - - /** - * Description - * @method normalise - * @param {vector} vector - * @return {vector} A new vector normalised - */ - Vector.normalise = function(vector) { - var magnitude = Vector.magnitude(vector); - if (magnitude === 0) - return { x: 0, y: 0 }; - return { x: vector.x / magnitude, y: vector.y / magnitude }; - }; - - /** - * Description - * @method dot - * @param {vector} vectorA - * @param {vector} vectorB - * @return {number} The dot product of the two vectors - */ - Vector.dot = function(vectorA, vectorB) { - return (vectorA.x * vectorB.x) + (vectorA.y * vectorB.y); - }; - - /** - * Description - * @method cross - * @param {vector} vectorA - * @param {vector} vectorB - * @return {number} The cross product of the two vectors - */ - Vector.cross = function(vectorA, vectorB) { - return (vectorA.x * vectorB.y) - (vectorA.y * vectorB.x); - }; - - /** - * Description - * @method add - * @param {vector} vectorA - * @param {vector} vectorB - * @return {vector} A new vector added - */ - Vector.add = function(vectorA, vectorB) { - return { x: vectorA.x + vectorB.x, y: vectorA.y + vectorB.y }; - }; - - /** - * Description - * @method sub - * @param {vector} vectorA - * @param {vector} vectorB - * @return {vector} A new vector subtracted - */ - Vector.sub = function(vectorA, vectorB) { - return { x: vectorA.x - vectorB.x, y: vectorA.y - vectorB.y }; - }; - - /** - * Description - * @method mult - * @param {vector} vector - * @param {number} scalar - * @return {vector} A new vector multiplied by scalar - */ - Vector.mult = function(vector, scalar) { - return { x: vector.x * scalar, y: vector.y * scalar }; - }; - - /** - * Description - * @method div - * @param {vector} vector - * @param {number} scalar - * @return {vector} A new vector divided by scalar - */ - Vector.div = function(vector, scalar) { - return { x: vector.x / scalar, y: vector.y / scalar }; - }; - - /** - * Description - * @method perp - * @param {vector} vector - * @param {bool} negate - * @return {vector} The perpendicular vector - */ - Vector.perp = function(vector, negate) { - negate = negate === true ? -1 : 1; - return { x: negate * -vector.y, y: negate * vector.x }; - }; - - /** - * Description - * @method neg - * @param {vector} vector - * @return {vector} The negated vector - */ - Vector.neg = function(vector) { - return { x: -vector.x, y: -vector.y }; - }; - - /** - * Returns the angle in radians between the two vectors relative to the x-axis - * @method angle - * @param {vector} vectorA - * @param {vector} vectorB - * @return {number} The angle in radians - */ - Vector.angle = function(vectorA, vectorB) { - return Math.atan2(vectorB.y - vectorA.y, vectorB.x - vectorA.x); - }; - -})(); - -; // End src/geometry/Vector.js - - -// Begin src/geometry/Vertices.js - -/** -* See [Demo.js](https://github.com/liabru/matter-js/blob/master/demo/js/Demo.js) -* and [DemoMobile.js](https://github.com/liabru/matter-js/blob/master/demo/js/DemoMobile.js) for usage examples. -* -* @class Vertices -*/ - -// TODO: convex decomposition - http://mnbayazit.com/406/bayazit - -var Vertices = {}; - -(function() { - - /** - * Description - * @method create - * @param {vertices} vertices - * @param {body} body - */ - Vertices.create = function(vertices, body) { - for (var i = 0; i < vertices.length; i++) { - vertices[i].index = i; - vertices[i].body = body; - } - }; - - /** - * Description - * @method fromPath - * @param {string} path - * @return {vertices} vertices - */ - Vertices.fromPath = function(path) { - var pathPattern = /L\s*([\-\d\.]*)\s*([\-\d\.]*)/ig, - vertices = []; - - path.replace(pathPattern, function(match, x, y) { - vertices.push({ x: parseFloat(x, 10), y: parseFloat(y, 10) }); - }); - - return vertices; - }; - - /** - * Description - * @method centre - * @param {vertices} vertices - * @return {vector} The centre point - */ - Vertices.centre = function(vertices) { - var area = Vertices.area(vertices, true), - centre = { x: 0, y: 0 }, - cross, - temp, - j; - - for (var i = 0; i < vertices.length; i++) { - j = (i + 1) % vertices.length; - cross = Vector.cross(vertices[i], vertices[j]); - temp = Vector.mult(Vector.add(vertices[i], vertices[j]), cross); - centre = Vector.add(centre, temp); - } - - return Vector.div(centre, 6 * area); - }; - - /** - * Description - * @method area - * @param {vertices} vertices - * @param {bool} signed - * @return {number} The area - */ - Vertices.area = function(vertices, signed) { - var area = 0, - j = vertices.length - 1; - - for (var i = 0; i < vertices.length; i++) { - area += (vertices[j].x - vertices[i].x) * (vertices[j].y + vertices[i].y); - j = i; - } - - if (signed) - return area / 2; - - return Math.abs(area) / 2; - }; - - /** - * Description - * @method inertia - * @param {vertices} vertices - * @param {number} mass - * @return {number} The polygon's moment of inertia, using second moment of area - */ - Vertices.inertia = function(vertices, mass) { - var numerator = 0, - denominator = 0, - v = vertices, - cross, - j; - - // find the polygon's moment of inertia, using second moment of area - // http://www.physicsforums.com/showthread.php?t=25293 - for (var n = 0; n < v.length; n++) { - j = (n + 1) % v.length; - cross = Math.abs(Vector.cross(v[j], v[n])); - numerator += cross * (Vector.dot(v[j], v[j]) + Vector.dot(v[j], v[n]) + Vector.dot(v[n], v[n])); - denominator += cross; - } - - return (mass / 6) * (numerator / denominator); - }; - - /** - * Description - * @method translate - * @param {vertices} vertices - * @param {vector} vector - * @param {number} scalar - */ - Vertices.translate = function(vertices, vector, scalar) { - var i; - if (scalar) { - for (i = 0; i < vertices.length; i++) { - vertices[i].x += vector.x * scalar; - vertices[i].y += vector.y * scalar; - } - } else { - for (i = 0; i < vertices.length; i++) { - vertices[i].x += vector.x; - vertices[i].y += vector.y; - } - } - }; - - /** - * Description - * @method rotate - * @param {vertices} vertices - * @param {number} angle - * @param {vector} point - */ - Vertices.rotate = function(vertices, angle, point) { - if (angle === 0) - return; - - var cos = Math.cos(angle), - sin = Math.sin(angle); - - for (var i = 0; i < vertices.length; i++) { - var vertice = vertices[i], - dx = vertice.x - point.x, - dy = vertice.y - point.y; - - vertice.x = point.x + (dx * cos - dy * sin); - vertice.y = point.y + (dx * sin + dy * cos); - } - }; - - /** - * Description - * @method contains - * @param {vertices} vertices - * @param {vector} point - * @return {boolean} True if the vertices contains point, otherwise false - */ - Vertices.contains = function(vertices, point) { - for (var i = 0; i < vertices.length; i++) { - var vertice = vertices[i], - nextVertice = vertices[(i + 1) % vertices.length]; - if ((point.x - vertice.x) * (nextVertice.y - vertice.y) + (point.y - vertice.y) * (vertice.x - nextVertice.x) > 0) { - return false; - } - } - - return true; - }; - - /** - * Scales the vertices from a point (default is centre) - * @method scale - * @param {vertices} vertices - * @param {number} scaleX - * @param {number} scaleY - * @param {vector} point - */ - Vertices.scale = function(vertices, scaleX, scaleY, point) { - if (scaleX === 1 && scaleY === 1) - return vertices; - - point = point || Vertices.centre(vertices); - - var vertex, - delta; - - for (var i = 0; i < vertices.length; i++) { - vertex = vertices[i]; - delta = Vector.sub(vertex, point); - vertices[i].x = point.x + delta.x * scaleX; - vertices[i].y = point.y + delta.y * scaleY; - } - - return vertices; - }; - - /** - * Chamfers a set of vertices by giving them rounded corners, returns a new set of vertices. - * The radius parameter is a single number or an array to specify the radius for each vertex. - * @method chamfer - * @param {vertices} vertices - * @param {number[]} radius - * @param {number} quality - * @param {number} qualityMin - * @param {number} qualityMax - */ - Vertices.chamfer = function(vertices, radius, quality, qualityMin, qualityMax) { - radius = radius || [8]; - - if (!radius.length) - radius = [radius]; - - // quality defaults to -1, which is auto - quality = (typeof quality !== 'undefined') ? quality : -1; - qualityMin = qualityMin || 2; - qualityMax = qualityMax || 14; - - var centre = Vertices.centre(vertices), - newVertices = []; - - for (var i = 0; i < vertices.length; i++) { - var prevVertex = vertices[i - 1 >= 0 ? i - 1 : vertices.length - 1], - vertex = vertices[i], - nextVertex = vertices[(i + 1) % vertices.length], - currentRadius = radius[i < radius.length ? i : radius.length - 1]; - - if (currentRadius === 0) { - newVertices.push(vertex); - continue; - } - - var prevNormal = Vector.normalise({ - x: vertex.y - prevVertex.y, - y: prevVertex.x - vertex.x - }); - - var nextNormal = Vector.normalise({ - x: nextVertex.y - vertex.y, - y: vertex.x - nextVertex.x - }); - - var diagonalRadius = Math.sqrt(2 * Math.pow(currentRadius, 2)), - radiusVector = Vector.mult(Common.clone(prevNormal), currentRadius), - midNormal = Vector.normalise(Vector.mult(Vector.add(prevNormal, nextNormal), 0.5)), - scaledVertex = Vector.sub(vertex, Vector.mult(midNormal, diagonalRadius)); - - var precision = quality; - - if (quality === -1) { - // automatically decide precision - precision = Math.pow(currentRadius, 0.32) * 1.75; - } - - precision = Common.clamp(precision, qualityMin, qualityMax); - - // use an even value for precision, more likely to reduce axes by using symmetry - if (precision % 2 === 1) - precision += 1; - - var alpha = Math.acos(Vector.dot(prevNormal, nextNormal)), - theta = alpha / precision; - - for (var j = 0; j < precision; j++) { - newVertices.push(Vector.add(Vector.rotate(radiusVector, theta * j), scaledVertex)); - } - } - - return newVertices; - }; - -})(); - -; // End src/geometry/Vertices.js - - -// Begin src/render/Render.js - -/** -* See [Demo.js](https://github.com/liabru/matter-js/blob/master/demo/js/Demo.js) -* and [DemoMobile.js](https://github.com/liabru/matter-js/blob/master/demo/js/DemoMobile.js) for usage examples. -* -* @class Render -*/ - -// TODO: viewports -// TODO: two.js, pixi.js - -var Render = {}; - -(function() { - - /** - * Description - * @method create - * @param {object} options - * @return {render} A new renderer - */ - Render.create = function(options) { - var defaults = { - controller: Render, - element: null, - canvas: null, - options: { - width: 800, - height: 600, - background: '#fafafa', - wireframeBackground: '#222', - hasBounds: false, - enabled: true, - wireframes: true, - showSleeping: true, - showDebug: false, - showBroadphase: false, - showBounds: false, - showVelocity: false, - showCollisions: false, - showAxes: false, - showPositions: false, - showAngleIndicator: false, - showIds: false, - showShadows: false - } - }; - - var render = Common.extend(defaults, options); - - render.canvas = render.canvas || _createCanvas(render.options.width, render.options.height); - render.context = render.canvas.getContext('2d'); - render.textures = {}; - - render.bounds = render.bounds || { - min: { - x: 0, - y: 0 - }, - max: { - x: render.options.width, - y: render.options.height - } - }; - - Render.setBackground(render, render.options.background); - - if (Common.isElement(render.element)) { - render.element.appendChild(render.canvas); - } else { - Common.log('No "render.element" passed, "render.canvas" was not inserted into document.', 'warn'); - } - - return render; - }; - - /** - * Clears the renderer. In this implementation, this is a noop. - * @method clear - * @param {RenderPixi} render - */ - Render.clear = function(render) { - // nothing required to clear this renderer implentation - // if a scene graph is required, clear it here (see RenderPixi.js) - }; - - /** - * Sets the background CSS property of the canvas - * @method setBackground - * @param {render} render - * @param {string} background - */ - Render.setBackground = function(render, background) { - if (render.currentBackground !== background) { - var cssBackground = background; - - if (/(jpg|gif|png)$/.test(background)) - cssBackground = 'url(' + background + ')'; - - render.canvas.style.background = cssBackground; - render.canvas.style.backgroundSize = "contain"; - render.currentBackground = background; - } - }; - - /** - * Description - * @method world - * @param {engine} engine - */ - Render.world = function(engine) { - var render = engine.render, - world = engine.world, - canvas = render.canvas, - context = render.context, - options = render.options, - allBodies = Composite.allBodies(world), - allConstraints = Composite.allConstraints(world), - bodies = [], - constraints = [], - i; - - if (options.wireframes) { - Render.setBackground(render, options.wireframeBackground); - } else { - Render.setBackground(render, options.background); - } - - // clear the canvas with a transparent fill, to allow the canvas background to show - context.globalCompositeOperation = 'source-in'; - context.fillStyle = "transparent"; - context.fillRect(0, 0, canvas.width, canvas.height); - context.globalCompositeOperation = 'source-over'; - - // handle bounds - var boundsWidth = render.bounds.max.x - render.bounds.min.x, - boundsHeight = render.bounds.max.y - render.bounds.min.y, - boundsScaleX = boundsWidth / render.options.width, - boundsScaleY = boundsHeight / render.options.height; - - if (options.hasBounds) { - // filter out bodies that are not in view - for (i = 0; i < allBodies.length; i++) { - var body = allBodies[i]; - if (Bounds.overlaps(body.bounds, render.bounds)) - bodies.push(body); - } - - // filter out constraints that are not in view - for (i = 0; i < allConstraints.length; i++) { - var constraint = allConstraints[i], - bodyA = constraint.bodyA, - bodyB = constraint.bodyB, - pointAWorld = constraint.pointA, - pointBWorld = constraint.pointB; - - if (bodyA) pointAWorld = Vector.add(bodyA.position, constraint.pointA); - if (bodyB) pointBWorld = Vector.add(bodyB.position, constraint.pointB); - - if (!pointAWorld || !pointBWorld) - continue; - - if (Bounds.contains(render.bounds, pointAWorld) || Bounds.contains(render.bounds, pointBWorld)) - constraints.push(constraint); - } - - // transform the view - context.scale(1 / boundsScaleX, 1 / boundsScaleY); - context.translate(-render.bounds.min.x, -render.bounds.min.y); - } else { - constraints = allConstraints; - bodies = allBodies; - } - - if (!options.wireframes || (engine.enableSleeping && options.showSleeping)) { - // fully featured rendering of bodies - Render.bodies(engine, bodies, context); - } else { - // optimised method for wireframes only - Render.bodyWireframes(engine, bodies, context); - } - - if (options.showBounds) - Render.bodyBounds(engine, bodies, context); - - if (options.showAxes || options.showAngleIndicator) - Render.bodyAxes(engine, bodies, context); - - if (options.showPositions) - Render.bodyPositions(engine, bodies, context); - - if (options.showVelocity) - Render.bodyVelocity(engine, bodies, context); - - if (options.showIds) - Render.bodyIds(engine, bodies, context); - - if (options.showCollisions) - Render.collisions(engine, engine.pairs.list, context); - - Render.constraints(constraints, context); - - if (options.showBroadphase && engine.broadphase.current === 'grid') - Render.grid(engine, engine.broadphase[engine.broadphase.current].instance, context); - - if (options.showDebug) - Render.debug(engine, context); - - if (options.hasBounds) { - // revert view transforms - context.setTransform(1, 0, 0, 1, 0, 0); - } - }; - - /** - * Description - * @method debug - * @param {engine} engine - * @param {RenderingContext} context - */ - Render.debug = function(engine, context) { - var c = context, - world = engine.world, - render = engine.render, - options = render.options, - bodies = Composite.allBodies(world), - space = " "; - - if (engine.timing.timestamp - (render.debugTimestamp || 0) >= 500) { - var text = ""; - text += "fps: " + Math.round(engine.timing.fps) + space; - - if (engine.metrics.extended) { - text += "delta: " + engine.timing.delta.toFixed(3) + space; - text += "correction: " + engine.timing.correction.toFixed(3) + space; - text += "bodies: " + bodies.length + space; - - if (engine.broadphase.controller === Grid) - text += "buckets: " + engine.metrics.buckets + space; - - text += "\n"; - - text += "collisions: " + engine.metrics.collisions + space; - text += "pairs: " + engine.pairs.list.length + space; - text += "broad: " + engine.metrics.broadEff + space; - text += "mid: " + engine.metrics.midEff + space; - text += "narrow: " + engine.metrics.narrowEff + space; - } - - render.debugString = text; - render.debugTimestamp = engine.timing.timestamp; - } - - if (render.debugString) { - c.font = "12px Arial"; - - if (options.wireframes) { - c.fillStyle = 'rgba(255,255,255,0.5)'; - } else { - c.fillStyle = 'rgba(0,0,0,0.5)'; - } - - var split = render.debugString.split('\n'); - - for (var i = 0; i < split.length; i++) { - c.fillText(split[i], 50, 50 + i * 18); - } - } - }; - - /** - * Description - * @method constraints - * @param {constraint[]} constraints - * @param {RenderingContext} context - */ - Render.constraints = function(constraints, context) { - var c = context; - - for (var i = 0; i < constraints.length; i++) { - var constraint = constraints[i]; - - if (!constraint.render.visible || !constraint.pointA || !constraint.pointB) - continue; - - var bodyA = constraint.bodyA, - bodyB = constraint.bodyB; - - if (bodyA) { - c.beginPath(); - c.moveTo(bodyA.position.x + constraint.pointA.x, bodyA.position.y + constraint.pointA.y); - } else { - c.beginPath(); - c.moveTo(constraint.pointA.x, constraint.pointA.y); - } - - if (bodyB) { - c.lineTo(bodyB.position.x + constraint.pointB.x, bodyB.position.y + constraint.pointB.y); - } else { - c.lineTo(constraint.pointB.x, constraint.pointB.y); - } - - c.lineWidth = constraint.render.lineWidth; - c.strokeStyle = constraint.render.strokeStyle; - c.stroke(); - } - }; - - /** - * Description - * @method bodyShadows - * @param {engine} engine - * @param {body[]} bodies - * @param {RenderingContext} context - */ - Render.bodyShadows = function(engine, bodies, context) { - var c = context, - render = engine.render, - options = render.options; - - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i]; - - if (!body.render.visible) - continue; - - if (body.circleRadius) { - c.beginPath(); - c.arc(body.position.x, body.position.y, body.circleRadius, 0, 2 * Math.PI); - c.closePath(); - } else { - c.beginPath(); - c.moveTo(body.vertices[0].x, body.vertices[0].y); - for (var j = 1; j < body.vertices.length; j++) { - c.lineTo(body.vertices[j].x, body.vertices[j].y); - } - c.closePath(); - } - - var distanceX = body.position.x - render.options.width * 0.5, - distanceY = body.position.y - render.options.height * 0.2, - distance = Math.abs(distanceX) + Math.abs(distanceY); - - c.shadowColor = 'rgba(0,0,0,0.15)'; - c.shadowOffsetX = 0.05 * distanceX; - c.shadowOffsetY = 0.05 * distanceY; - c.shadowBlur = 1 + 12 * Math.min(1, distance / 1000); - - c.fill(); - - c.shadowColor = null; - c.shadowOffsetX = null; - c.shadowOffsetY = null; - c.shadowBlur = null; - } - }; - - /** - * Description - * @method bodies - * @param {engine} engine - * @param {body[]} bodies - * @param {RenderingContext} context - */ - Render.bodies = function(engine, bodies, context) { - var c = context, - render = engine.render, - options = render.options, - i; - - for (i = 0; i < bodies.length; i++) { - var body = bodies[i]; - - if (!body.render.visible) - continue; - - if (body.render.sprite && body.render.sprite.texture && !options.wireframes) { - // body sprite - var sprite = body.render.sprite, - texture = _getTexture(render, sprite.texture); - - if (options.showSleeping && body.isSleeping) - c.globalAlpha = 0.5; - - c.translate(body.position.x, body.position.y); - c.rotate(body.angle); - - c.drawImage(texture, texture.width * -0.5 * sprite.xScale, texture.height * -0.5 * sprite.yScale, - texture.width * sprite.xScale, texture.height * sprite.yScale); - - // revert translation, hopefully faster than save / restore - c.rotate(-body.angle); - c.translate(-body.position.x, -body.position.y); - - if (options.showSleeping && body.isSleeping) - c.globalAlpha = 1; - } else { - // body polygon - if (body.circleRadius) { - c.beginPath(); - c.arc(body.position.x, body.position.y, body.circleRadius, 0, 2 * Math.PI); - } else { - c.beginPath(); - c.moveTo(body.vertices[0].x, body.vertices[0].y); - for (var j = 1; j < body.vertices.length; j++) { - c.lineTo(body.vertices[j].x, body.vertices[j].y); - } - c.closePath(); - } - - if (!options.wireframes) { - if (options.showSleeping && body.isSleeping) { - c.fillStyle = Common.shadeColor(body.render.fillStyle, 50); - } else { - c.fillStyle = body.render.fillStyle; - } - - c.lineWidth = body.render.lineWidth; - c.strokeStyle = body.render.strokeStyle; - c.fill(); - c.stroke(); - } else { - c.lineWidth = 1; - c.strokeStyle = '#bbb'; - if (options.showSleeping && body.isSleeping) - c.strokeStyle = 'rgba(255,255,255,0.2)'; - c.stroke(); - } - } - } - - }; - - /** - * Optimised method for drawing body wireframes in one pass - * @method bodyWireframes - * @param {engine} engine - * @param {body[]} bodies - * @param {RenderingContext} context - */ - Render.bodyWireframes = function(engine, bodies, context) { - var c = context, - i, - j; - - c.beginPath(); - - for (i = 0; i < bodies.length; i++) { - var body = bodies[i]; - - if (!body.render.visible) - continue; - - c.moveTo(body.vertices[0].x, body.vertices[0].y); - - for (j = 1; j < body.vertices.length; j++) { - c.lineTo(body.vertices[j].x, body.vertices[j].y); - } - - c.lineTo(body.vertices[0].x, body.vertices[0].y); - } - - c.lineWidth = 1; - c.strokeStyle = '#bbb'; - c.stroke(); - }; - - /** - * Draws body bounds - * @method bodyBounds - * @param {engine} engine - * @param {body[]} bodies - * @param {RenderingContext} context - */ - Render.bodyBounds = function(engine, bodies, context) { - var c = context, - render = engine.render, - options = render.options; - - c.beginPath(); - - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i]; - - if (body.render.visible) - c.rect(body.bounds.min.x, body.bounds.min.y, body.bounds.max.x - body.bounds.min.x, body.bounds.max.y - body.bounds.min.y); - } - - if (options.wireframes) { - c.strokeStyle = 'rgba(255,255,255,0.08)'; - } else { - c.strokeStyle = 'rgba(0,0,0,0.1)'; - } - - c.lineWidth = 1; - c.stroke(); - }; - - /** - * Draws body angle indicators and axes - * @method bodyAxes - * @param {engine} engine - * @param {body[]} bodies - * @param {RenderingContext} context - */ - Render.bodyAxes = function(engine, bodies, context) { - var c = context, - render = engine.render, - options = render.options, - i, - j; - - c.beginPath(); - - for (i = 0; i < bodies.length; i++) { - var body = bodies[i]; - - if (!body.render.visible) - continue; - - if (options.showAxes) { - // render all axes - for (j = 0; j < body.axes.length; j++) { - var axis = body.axes[j]; - c.moveTo(body.position.x, body.position.y); - c.lineTo(body.position.x + axis.x * 20, body.position.y + axis.y * 20); - } - } else { - // render a single axis indicator - c.moveTo(body.position.x, body.position.y); - c.lineTo((body.vertices[0].x + body.vertices[body.vertices.length-1].x) / 2, - (body.vertices[0].y + body.vertices[body.vertices.length-1].y) / 2); - } - } - - if (options.wireframes) { - c.strokeStyle = 'indianred'; - } else { - c.strokeStyle = 'rgba(0,0,0,0.3)'; - } - - c.lineWidth = 1; - c.stroke(); - }; - - /** - * Draws body positions - * @method bodyPositions - * @param {engine} engine - * @param {body[]} bodies - * @param {RenderingContext} context - */ - Render.bodyPositions = function(engine, bodies, context) { - var c = context, - render = engine.render, - options = render.options, - body, - i; - - c.beginPath(); - - // render current positions - for (i = 0; i < bodies.length; i++) { - body = bodies[i]; - if (body.render.visible) { - c.arc(body.position.x, body.position.y, 3, 0, 2 * Math.PI, false); - c.closePath(); - } - } - - if (options.wireframes) { - c.fillStyle = 'indianred'; - } else { - c.fillStyle = 'rgba(0,0,0,0.5)'; - } - c.fill(); - - c.beginPath(); - - // render previous positions - for (i = 0; i < bodies.length; i++) { - body = bodies[i]; - if (body.render.visible) { - c.arc(body.positionPrev.x, body.positionPrev.y, 2, 0, 2 * Math.PI, false); - c.closePath(); - } - } - - c.fillStyle = 'rgba(255,165,0,0.8)'; - c.fill(); - }; - - /** - * Draws body velocity - * @method bodyVelocity - * @param {engine} engine - * @param {body[]} bodies - * @param {RenderingContext} context - */ - Render.bodyVelocity = function(engine, bodies, context) { - var c = context, - render = engine.render, - options = render.options; - - c.beginPath(); - - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i]; - - if (!body.render.visible) - continue; - - c.moveTo(body.position.x, body.position.y); - c.lineTo(body.position.x + (body.position.x - body.positionPrev.x) * 2, body.position.y + (body.position.y - body.positionPrev.y) * 2); - } - - c.lineWidth = 3; - c.strokeStyle = 'cornflowerblue'; - c.stroke(); - }; - - /** - * Draws body ids - * @method bodyIds - * @param {engine} engine - * @param {body[]} bodies - * @param {RenderingContext} context - */ - Render.bodyIds = function(engine, bodies, context) { - var c = context; - - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i]; - - if (!body.render.visible) - continue; - - c.font = "12px Arial"; - c.fillStyle = 'rgba(255,255,255,0.5)'; - c.fillText(body.id, body.position.x + 10, body.position.y - 10); - } - }; - - /** - * Description - * @method collisions - * @param {engine} engine - * @param {pair[]} pairs - * @param {RenderingContext} context - */ - Render.collisions = function(engine, pairs, context) { - var c = context, - options = engine.render.options, - pair, - collision, - i, - j; - - c.beginPath(); - - // render collision positions - for (i = 0; i < pairs.length; i++) { - pair = pairs[i]; - collision = pair.collision; - for (j = 0; j < pair.activeContacts.length; j++) { - var contact = pair.activeContacts[j], - vertex = contact.vertex; - c.rect(vertex.x - 1.5, vertex.y - 1.5, 3.5, 3.5); - } - } - - if (options.wireframes) { - c.fillStyle = 'rgba(255,255,255,0.7)'; - } else { - c.fillStyle = 'orange'; - } - c.fill(); - - c.beginPath(); - - // render collision normals - for (i = 0; i < pairs.length; i++) { - pair = pairs[i]; - collision = pair.collision; - - if (pair.activeContacts.length > 0) { - var normalPosX = pair.activeContacts[0].vertex.x, - normalPosY = pair.activeContacts[0].vertex.y; - - if (pair.activeContacts.length === 2) { - normalPosX = (pair.activeContacts[0].vertex.x + pair.activeContacts[1].vertex.x) / 2; - normalPosY = (pair.activeContacts[0].vertex.y + pair.activeContacts[1].vertex.y) / 2; - } - - c.moveTo(normalPosX - collision.normal.x * 8, normalPosY - collision.normal.y * 8); - c.lineTo(normalPosX, normalPosY); - } - } - - if (options.wireframes) { - c.strokeStyle = 'rgba(255,165,0,0.7)'; - } else { - c.strokeStyle = 'orange'; - } - - c.lineWidth = 1; - c.stroke(); - }; - - /** - * Description - * @method grid - * @param {engine} engine - * @param {grid} grid - * @param {RenderingContext} context - */ - Render.grid = function(engine, grid, context) { - var c = context, - options = engine.render.options; - - if (options.wireframes) { - c.strokeStyle = 'rgba(255,180,0,0.1)'; - } else { - c.strokeStyle = 'rgba(255,180,0,0.5)'; - } - - c.beginPath(); - - var bucketKeys = Common.keys(grid.buckets); - - for (var i = 0; i < bucketKeys.length; i++) { - var bucketId = bucketKeys[i]; - - if (grid.buckets[bucketId].length < 2) - continue; - - var region = bucketId.split(','); - c.rect(0.5 + parseInt(region[0], 10) * grid.bucketWidth, - 0.5 + parseInt(region[1], 10) * grid.bucketHeight, - grid.bucketWidth, - grid.bucketHeight); - } - - c.lineWidth = 1; - c.stroke(); - }; - - /** - * Description - * @method inspector - * @param {inspector} inspector - * @param {RenderingContext} context - */ - Render.inspector = function(inspector, context) { - var engine = inspector.engine, - mouse = engine.input.mouse, - selected = inspector.selected, - c = context, - render = engine.render, - options = render.options, - bounds; - - if (options.hasBounds) { - var boundsWidth = render.bounds.max.x - render.bounds.min.x, - boundsHeight = render.bounds.max.y - render.bounds.min.y, - boundsScaleX = boundsWidth / render.options.width, - boundsScaleY = boundsHeight / render.options.height; - - context.scale(1 / boundsScaleX, 1 / boundsScaleY); - context.translate(-render.bounds.min.x, -render.bounds.min.y); - } - - for (var i = 0; i < selected.length; i++) { - var item = selected[i].data; - - context.translate(0.5, 0.5); - context.lineWidth = 1; - context.strokeStyle = 'rgba(255,165,0,0.9)'; - context.setLineDash([1,2]); - - switch (item.type) { - - case 'body': - - // render body selections - bounds = item.bounds; - context.beginPath(); - context.rect(Math.floor(bounds.min.x - 3), Math.floor(bounds.min.y - 3), - Math.floor(bounds.max.x - bounds.min.x + 6), Math.floor(bounds.max.y - bounds.min.y + 6)); - context.closePath(); - context.stroke(); - - break; - - case 'constraint': - - // render constraint selections - var point = item.pointA; - if (item.bodyA) - point = item.pointB; - context.beginPath(); - context.arc(point.x, point.y, 10, 0, 2 * Math.PI); - context.closePath(); - context.stroke(); - - break; - - } - - context.setLineDash([0]); - context.translate(-0.5, -0.5); - } - - // render selection region - if (inspector.selectStart !== null) { - context.translate(0.5, 0.5); - context.lineWidth = 1; - context.strokeStyle = 'rgba(255,165,0,0.6)'; - context.fillStyle = 'rgba(255,165,0,0.1)'; - bounds = inspector.selectBounds; - context.beginPath(); - context.rect(Math.floor(bounds.min.x), Math.floor(bounds.min.y), - Math.floor(bounds.max.x - bounds.min.x), Math.floor(bounds.max.y - bounds.min.y)); - context.closePath(); - context.stroke(); - context.fill(); - context.translate(-0.5, -0.5); - } - - if (options.hasBounds) - context.setTransform(1, 0, 0, 1, 0, 0); - }; - - /** - * Description - * @method _createCanvas - * @private - * @param {} width - * @param {} height - * @return canvas - */ - var _createCanvas = function(width, height) { - var canvas = document.createElement('canvas'); - canvas.width = width; - canvas.height = height; - canvas.oncontextmenu = function() { return false; }; - canvas.onselectstart = function() { return false; }; - return canvas; - }; - - /** - * Gets the requested texture (an Image) via its path - * @method _getTexture - * @private - * @param {render} render - * @param {string} imagePath - * @return {Image} texture - */ - var _getTexture = function(render, imagePath) { - var image = render.textures[imagePath]; - - if (image) - return image; - - image = render.textures[imagePath] = new Image(); - image.src = imagePath; - - return image; - }; - -})(); - -; // End src/render/Render.js - - -// Begin src/render/RenderPixi.js - -/** -* See [Demo.js](https://github.com/liabru/matter-js/blob/master/demo/js/Demo.js) -* and [DemoMobile.js](https://github.com/liabru/matter-js/blob/master/demo/js/DemoMobile.js) for usage examples. -* -* @class RenderPixi -*/ - -var RenderPixi = {}; - -(function() { - - /** - * Creates a new Pixi.js WebGL renderer - * @method create - * @param {object} options - * @return {RenderPixi} A new renderer - */ - RenderPixi.create = function(options) { - var defaults = { - controller: RenderPixi, - element: null, - canvas: null, - options: { - width: 800, - height: 600, - background: '#fafafa', - wireframeBackground: '#222', - enabled: true, - wireframes: true, - showSleeping: true, - showDebug: false, - showBroadphase: false, - showBounds: false, - showVelocity: false, - showCollisions: false, - showAxes: false, - showPositions: false, - showAngleIndicator: false, - showIds: false, - showShadows: false - } - }; - - var render = Common.extend(defaults, options); - - // init pixi - render.context = new PIXI.WebGLRenderer(800, 600, render.canvas, false, true); - render.canvas = render.context.view; - render.stage = new PIXI.Stage(); - - // caches - render.textures = {}; - render.sprites = {}; - render.primitives = {}; - - // use a sprite batch for performance - render.spriteBatch = new PIXI.SpriteBatch(); - render.stage.addChild(render.spriteBatch); - - // insert canvas - if (Common.isElement(render.element)) { - render.element.appendChild(render.canvas); - } else { - Common.log('No "render.element" passed, "render.canvas" was not inserted into document.', 'warn'); - } - - // prevent menus on canvas - render.canvas.oncontextmenu = function() { return false; }; - render.canvas.onselectstart = function() { return false; }; - - return render; - }; - - /** - * Clears the scene graph - * @method clear - * @param {RenderPixi} render - */ - RenderPixi.clear = function(render) { - var stage = render.stage, - spriteBatch = render.spriteBatch; - - // clear stage - while (stage.children[0]) { - stage.removeChild(stage.children[0]); - } - - // clear sprite batch - while (spriteBatch.children[0]) { - spriteBatch.removeChild(spriteBatch.children[0]); - } - - var bgSprite = render.sprites['bg-0']; - - // clear caches - render.textures = {}; - render.sprites = {}; - render.primitives = {}; - - // set background sprite - render.sprites['bg-0'] = bgSprite; - if (bgSprite) - spriteBatch.addChildAt(bgSprite, 0); - - // add sprite batch back into stage - render.stage.addChild(render.spriteBatch); - - // reset background state - render.currentBackground = null; - }; - - /** - * Sets the background of the canvas - * @method setBackground - * @param {RenderPixi} render - * @param {string} background - */ - RenderPixi.setBackground = function(render, background) { - if (render.currentBackground !== background) { - var isColor = background.indexOf && background.indexOf('#') !== -1, - bgSprite = render.sprites['bg-0']; - - if (isColor) { - // if solid background color - var color = Common.colorToNumber(background); - render.stage.setBackgroundColor(color); - - // remove background sprite if existing - if (bgSprite) - render.spriteBatch.removeChild(bgSprite); - } else { - // initialise background sprite if needed - if (!bgSprite) { - var texture = _getTexture(render, background); - - bgSprite = render.sprites['bg-0'] = new PIXI.Sprite(texture); - bgSprite.position.x = 0; - bgSprite.position.y = 0; - render.spriteBatch.addChildAt(bgSprite, 0); - } - } - - render.currentBackground = background; - } - }; - - /** - * Description - * @method world - * @param {engine} engine - */ - RenderPixi.world = function(engine) { - var render = engine.render, - world = engine.world, - context = render.context, - stage = render.stage, - options = render.options, - bodies = Composite.allBodies(world), - constraints = Composite.allConstraints(world), - i; - - if (options.wireframes) { - RenderPixi.setBackground(render, options.wireframeBackground); - } else { - RenderPixi.setBackground(render, options.background); - } - - for (i = 0; i < bodies.length; i++) - RenderPixi.body(engine, bodies[i]); - - for (i = 0; i < constraints.length; i++) - RenderPixi.constraint(engine, constraints[i]); - - context.render(stage); - }; - - - /** - * Description - * @method constraint - * @param {engine} engine - * @param {constraint} constraint - */ - RenderPixi.constraint = function(engine, constraint) { - var render = engine.render, - bodyA = constraint.bodyA, - bodyB = constraint.bodyB, - pointA = constraint.pointA, - pointB = constraint.pointB, - stage = render.stage, - constraintRender = constraint.render, - primitiveId = 'c-' + constraint.id, - primitive = render.primitives[primitiveId]; - - // initialise constraint primitive if not existing - if (!primitive) - primitive = render.primitives[primitiveId] = new PIXI.Graphics(); - - // don't render if constraint does not have two end points - if (!constraintRender.visible || !constraint.pointA || !constraint.pointB) { - primitive.clear(); - return; - } - - // add to scene graph if not already there - if (stage.children.indexOf(primitive) === -1) - stage.addChild(primitive); - - // render the constraint on every update, since they can change dynamically - primitive.clear(); - primitive.beginFill(0, 0); - primitive.lineStyle(constraintRender.lineWidth, Common.colorToNumber(constraintRender.strokeStyle), 1); - - if (bodyA) { - primitive.moveTo(bodyA.position.x + pointA.x, bodyA.position.y + pointA.y); - } else { - primitive.moveTo(pointA.x, pointA.y); - } - - if (bodyB) { - primitive.lineTo(bodyB.position.x + pointB.x, bodyB.position.y + pointB.y); - } else { - primitive.lineTo(pointB.x, pointB.y); - } - - primitive.endFill(); - }; - - /** - * Description - * @method body - * @param {engine} engine - * @param {body} body - */ - RenderPixi.body = function(engine, body) { - var render = engine.render, - bodyRender = body.render; - - if (!bodyRender.visible) - return; - - if (bodyRender.sprite && bodyRender.sprite.texture) { - var spriteId = 'b-' + body.id, - sprite = render.sprites[spriteId], - spriteBatch = render.spriteBatch; - - // initialise body sprite if not existing - if (!sprite) - sprite = render.sprites[spriteId] = _createBodySprite(render, body); - - // add to scene graph if not already there - if (spriteBatch.children.indexOf(sprite) === -1) - spriteBatch.addChild(sprite); - - // update body sprite - sprite.position.x = body.position.x; - sprite.position.y = body.position.y; - sprite.rotation = body.angle; - } else { - var primitiveId = 'b-' + body.id, - primitive = render.primitives[primitiveId], - stage = render.stage; - - // initialise body primitive if not existing - if (!primitive) { - primitive = render.primitives[primitiveId] = _createBodyPrimitive(render, body); - primitive.initialAngle = body.angle; - } - - // add to scene graph if not already there - if (stage.children.indexOf(primitive) === -1) - stage.addChild(primitive); - - // update body primitive - primitive.position.x = body.position.x; - primitive.position.y = body.position.y; - primitive.rotation = body.angle - primitive.initialAngle; - } - }; - - /** - * Creates a body sprite - * @method _createBodySprite - * @private - * @param {RenderPixi} render - * @param {body} body - * @return {PIXI.Sprite} sprite - */ - var _createBodySprite = function(render, body) { - var bodyRender = body.render, - texturePath = bodyRender.sprite.texture, - texture = _getTexture(render, texturePath), - sprite = new PIXI.Sprite(texture); - - sprite.anchor.x = 0.5; - sprite.anchor.y = 0.5; - - return sprite; - }; - - /** - * Creates a body primitive - * @method _createBodyPrimitive - * @private - * @param {RenderPixi} render - * @param {body} body - * @return {PIXI.Graphics} graphics - */ - var _createBodyPrimitive = function(render, body) { - var bodyRender = body.render, - options = render.options, - primitive = new PIXI.Graphics(); - - primitive.clear(); - - if (!options.wireframes) { - primitive.beginFill(Common.colorToNumber(bodyRender.fillStyle), 1); - primitive.lineStyle(body.render.lineWidth, Common.colorToNumber(bodyRender.strokeStyle), 1); - } else { - primitive.beginFill(0, 0); - primitive.lineStyle(1, Common.colorToNumber('#bbb'), 1); - } - - primitive.moveTo(body.vertices[0].x - body.position.x, body.vertices[0].y - body.position.y); - - for (var j = 1; j < body.vertices.length; j++) { - primitive.lineTo(body.vertices[j].x - body.position.x, body.vertices[j].y - body.position.y); - } - - primitive.lineTo(body.vertices[0].x - body.position.x, body.vertices[0].y - body.position.y); - - primitive.endFill(); - - // angle indicator - if (options.showAngleIndicator || options.showAxes) { - primitive.beginFill(0, 0); - - if (options.wireframes) { - primitive.lineStyle(1, Common.colorToNumber('#CD5C5C'), 1); - } else { - primitive.lineStyle(1, Common.colorToNumber(body.render.strokeStyle)); - } - - primitive.moveTo(0, 0); - primitive.lineTo(((body.vertices[0].x + body.vertices[body.vertices.length-1].x) / 2) - body.position.x, - ((body.vertices[0].y + body.vertices[body.vertices.length-1].y) / 2) - body.position.y); - - primitive.endFill(); - } - - return primitive; - }; - - /** - * Gets the requested texture (a PIXI.Texture) via its path - * @method _getTexture - * @private - * @param {RenderPixi} render - * @param {string} imagePath - * @return {PIXI.Texture} texture - */ - var _getTexture = function(render, imagePath) { - var texture = render.textures[imagePath]; - - if (!texture) - texture = render.textures[imagePath] = PIXI.Texture.fromImage(imagePath); - - return texture; - }; - -})(); - -; // End src/render/RenderPixi.js - - -// aliases - -World.add = Composite.add; -World.remove = Composite.remove; -World.addComposite = Composite.addComposite; -World.addBody = Composite.addBody; -World.addConstraint = Composite.addConstraint; -World.clear = Composite.clear; - -// exports - -Matter.Body = Body; -Matter.Composite = Composite; -Matter.World = World; -Matter.Contact = Contact; -Matter.Detector = Detector; -Matter.Grid = Grid; -Matter.Pairs = Pairs; -Matter.Pair = Pair; -Matter.Resolver = Resolver; -Matter.SAT = SAT; -Matter.Constraint = Constraint; -Matter.MouseConstraint = MouseConstraint; -Matter.Common = Common; -Matter.Engine = Engine; -Matter.Metrics = Metrics; -Matter.Mouse = Mouse; -Matter.Sleeping = Sleeping; -Matter.Bodies = Bodies; -Matter.Composites = Composites; -Matter.Axes = Axes; -Matter.Bounds = Bounds; -Matter.Vector = Vector; -Matter.Vertices = Vertices; -Matter.Render = Render; -Matter.RenderPixi = RenderPixi; -Matter.Events = Events; -Matter.Query = Query; - -// CommonJS module -if (typeof exports !== 'undefined') { - if (typeof module !== 'undefined' && module.exports) { - exports = module.exports = Matter; - } - exports.Matter = Matter; -} - -// AMD module -if (typeof define === 'function' && define.amd) { - define('Matter', [], function () { - return Matter; - }); -} - -// browser -if (typeof window === 'object' && typeof window.document === 'object') { - window.Matter = Matter; -} - -// End Matter namespace closure - -})(); \ No newline at end of file diff --git a/demo/js/lib/matter-tools/32px.png b/demo/js/lib/matter-tools/32px.png deleted file mode 100644 index 1532715..0000000 Binary files a/demo/js/lib/matter-tools/32px.png and /dev/null differ diff --git a/demo/js/lib/matter-tools/gif/gif.js b/demo/js/lib/matter-tools/gif/gif.js deleted file mode 100644 index ed0f168..0000000 --- a/demo/js/lib/matter-tools/gif/gif.js +++ /dev/null @@ -1,3 +0,0 @@ -(function(c){function a(b,d){if({}.hasOwnProperty.call(a.cache,b))return a.cache[b];var e=a.resolve(b);if(!e)throw new Error('Failed to resolve module '+b);var c={id:b,require:a,filename:b,exports:{},loaded:!1,parent:d,children:[]};d&&d.children.push(c);var f=b.slice(0,b.lastIndexOf('/')+1);return a.cache[b]=c.exports,e.call(c.exports,c,c.exports,f,b),c.loaded=!0,a.cache[b]=c.exports}a.modules={},a.cache={},a.resolve=function(b){return{}.hasOwnProperty.call(a.modules,b)?a.modules[b]:void 0},a.define=function(b,c){a.modules[b]=c};var b=function(a){return a='/',{title:'browser',version:'v0.10.26',browser:!0,env:{},argv:[],nextTick:c.setImmediate||function(a){setTimeout(a,0)},cwd:function(){return a},chdir:function(b){a=b}}}();a.define('/gif.coffee',function(d,m,l,k){function g(a,b){return{}.hasOwnProperty.call(a,b)}function j(d,b){for(var a=0,c=b.length;athis.frames.length;0<=this.frames.length?++a:--a)b.push(a);return b}.apply(this,arguments),a=0,e=b.length;aa;0<=a?++b:--b)c.push(b);return c}.apply(this,arguments),b=0,e=c.length;ba;this.freeWorkers.length<=a?++b:--b)c.push(b);return c}.apply(this,arguments).forEach(function(a){return function(c){var b;return console.log('spawning worker '+c),b=new Worker(a.options.workerScript),b.onmessage=function(a){return function(c){return a.activeWorkers.splice(a.activeWorkers.indexOf(b),1),a.freeWorkers.push(b),a.frameFinished(c.data)}}(a),a.freeWorkers.push(b)}}(this)),a},a.prototype.frameFinished=function(a){return console.log('frame '+a.index+' finished - '+this.activeWorkers.length+' active'),this.finishedFrames++,this.emit('progress',this.finishedFrames/this.frames.length),this.imageParts[a.index]=a,j(null,this.imageParts)?this.renderNextFrame():this.finishRendering()},a.prototype.finishRendering=function(){var e,a,k,m,b,d,h;b=0;for(var f=0,j=this.imageParts.length;f=this.frames.length?void 0:(c=this.frames[this.nextFrame++],b=this.freeWorkers.shift(),a=this.getTask(c),console.log('starting frame '+(a.index+1)+' of '+this.frames.length),this.activeWorkers.push(b),b.postMessage(a))},a.prototype.getContextData=function(a){return a.getImageData(0,0,this.options.width,this.options.height).data},a.prototype.getImageData=function(b){var a;return null!=this._canvas||(this._canvas=document.createElement('canvas'),this._canvas.width=this.options.width,this._canvas.height=this.options.height),a=this._canvas.getContext('2d'),a.setFill=this.options.background,a.fillRect(0,0,this.options.width,this.options.height),a.drawImage(b,0,0),this.getContextData(a)},a.prototype.getTask=function(a){var c,b;if(c=this.frames.indexOf(a),b={index:c,last:c===this.frames.length-1,delay:a.delay,transparent:a.transparent,width:this.options.width,height:this.options.height,quality:this.options.quality,repeat:this.options.repeat,canTransfer:h.name==='chrome'},null!=a.data)b.data=a.data;else if(null!=a.context)b.data=this.getContextData(a.context);else if(null!=a.image)b.data=this.getImageData(a.image);else throw new Error('Invalid frame');return b},a}(f),d.exports=e}),a.define('/browser.coffee',function(f,g,h,i){var a,d,e,c,b;c=navigator.userAgent.toLowerCase(),e=navigator.platform.toLowerCase(),b=c.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/)||[null,'unknown',0],d=b[1]==='ie'&&document.documentMode,a={name:b[1]==='version'?b[3]:b[1],version:d||parseFloat(b[1]==='opera'&&b[4]?b[4]:b[2]),platform:{name:c.match(/ip(?:ad|od|hone)/)?'ios':(c.match(/(?:webos|android)/)||e.match(/mac|win|linux/)||['other'])[0]}},a[a.name]=!0,a[a.name+parseInt(a.version,10)]=!0,a.platform[a.platform.name]=!0,f.exports=a}),a.define('events',function(f,e,g,h){b.EventEmitter||(b.EventEmitter=function(){});var a=e.EventEmitter=b.EventEmitter,c=typeof Array.isArray==='function'?Array.isArray:function(a){return Object.prototype.toString.call(a)==='[object Array]'},d=10;a.prototype.setMaxListeners=function(a){this._events||(this._events={}),this._events.maxListeners=a},a.prototype.emit=function(f){if(f==='error'&&(!(this._events&&this._events.error)||c(this._events.error)&&!this._events.error.length))throw arguments[1]instanceof Error?arguments[1]:new Error("Uncaught, unspecified 'error' event.");if(!this._events)return!1;var a=this._events[f];if(!a)return!1;if(!(typeof a=='function'))if(c(a)){var b=Array.prototype.slice.call(arguments,1),e=a.slice();for(var d=0,g=e.length;d0&&this._events[a].length>e&&(this._events[a].warned=!0,console.error('(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.',this._events[a].length),console.trace())}this._events[a].push(b)}else this._events[a]=[this._events[a],b];return this},a.prototype.on=a.prototype.addListener,a.prototype.once=function(b,c){var a=this;return a.on(b,function d(){a.removeListener(b,d),c.apply(this,arguments)}),this},a.prototype.removeListener=function(a,d){if('function'!==typeof d)throw new Error('removeListener only takes instances of Function');if(!(this._events&&this._events[a]))return this;var b=this._events[a];if(c(b)){var e=b.indexOf(d);if(e<0)return this;b.splice(e,1),b.length==0&&delete this._events[a]}else this._events[a]===d&&delete this._events[a];return this},a.prototype.removeAllListeners=function(a){return a&&this._events&&this._events[a]&&(this._events[a]=null),this},a.prototype.listeners=function(a){return this._events||(this._events={}),this._events[a]||(this._events[a]=[]),c(this._events[a])||(this._events[a]=[this._events[a]]),this._events[a]}}),c.GIF=a('/gif.coffee')}.call(this,this)) -//# sourceMappingURL=gif.js.map -// gif.js 0.1.6 - https://github.com/jnordberg/gif.js diff --git a/demo/js/lib/matter-tools/gif/gif.js.map b/demo/js/lib/matter-tools/gif/gif.js.map deleted file mode 100644 index 83a4998..0000000 --- a/demo/js/lib/matter-tools/gif/gif.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["/gif.coffee","/browser.coffee","events"],"names":["h","c","f","b","e","a","d","ImageData","CanvasRenderingContext2D","WebGLRenderingContext","Error","console","Math","Worker","Uint8Array","k","m","Blob","document","navigator","parseFloat","parseInt","EventEmitter","Array","isArray","Object","prototype","toString","call","setMaxListeners","_events","maxListeners","emit","error","length","arguments","slice","g","apply","addListener","warned","undefined","trace","push","on","once","removeListener","indexOf","splice","removeAllListeners","listeners"],"mappings":"gjCACAA,C,CAIEC,C,CALDC,C,CAeCC,C,CAZIC,C,CAHLF,CAAD,CAAiBG,C,0BACjBL,CAAA,CAAUK,C,sBAEJD,CAAN,C,WAEE,CAcA,S,CAAA,CAAcE,CAAd,CACE,C,QAAA,K,OAAA,CAAW,E,CAEX,K,OAAA,CAAW,E,CACX,K,MAAA,CAAU,E,CAEV,K,WAAA,CAAe,E,CACf,K,aAAA,CAAiB,E,CAEjB,K,UAAA,CAAYA,CAAZ,C,CACA,IAAID,CAAJ,IAAkBJ,CAAlB,CAASE,C,CAASF,C,CAAdI,C,QACF,K,OAAQ,CAACA,CAAD,CAAR,M,OAAQ,CAACA,CAAD,CAAR,M,OAAQ,CAACA,CAAD,C,CAASF,CAVnB,C,cAfFF,CAAA,CACE,C,YAAA,CAAc,eAAd,C,OACA,CAAS,CADT,C,MAEA,CAAQ,CAFR,C,UAGA,CAAY,MAHZ,C,OAIA,CAAS,EAJT,C,KAKA,CAAO,IALP,C,MAMA,CAAQ,IANR,C,WAOA,CAAa,IAPb,C,CASFE,CAAA,CACE,C,KAAA,CAAO,GAAP,C,IACA,CAAM,EADN,C,sBAgBF,CAAW,SAACE,CAAD,CAAMF,CAAN,C,QACT,K,OAAQ,CAACE,CAAD,CAAR,CAAgBF,C,KACb,O,OAAA,E,CAAcE,C,GAAQ,O,EAARA,C,GAAiB,Q,EAChC,K,OAAQ,CAACA,CAAD,CAAR,CAAgBF,C,+BAEpB,CAAY,SAACA,CAAD,C,4BACV,IAA8BE,CAA9B,IAA4CF,CAA5C,C,OAA4CA,C,CAAdE,C,WAAKJ,C,CAASE,C,CAAdE,C,SAA9B,K,SAAA,CAAWA,CAAX,CAAgBJ,CAAhB,C,+CAEF,CAAU,SAACI,CAAD,CAAQC,CAAR,C,eAAQA,C,GAAAA,C,CAAQ,E,EACxBL,CAAA,CAAQ,E,CACRA,CAAK,C,WAAL,CAAoB,K,OAAA,C,YACpB,IAAIG,CAAJ,IAAWD,CAAX,CACEF,CAAK,CAACG,CAAD,CAAL,CAAaE,CAAA,CAAQF,CAAR,GAAgBD,CAAA,CAAcC,CAAd,CAA7B,CAMF,G,IAHuC,O,OAAQ,C,KAA/C,O,SAAA,CAAW,OAAX,CAAoBC,CAAA,C,KAApB,C,KACyC,O,OAAQ,C,MAAjD,O,SAAA,CAAW,QAAX,CAAqBA,CAAA,C,MAArB,C,sBAEGE,SAAA,E,MAAAA,SAAA,EAAeF,C,YAAiBE,SAAnC,CACGN,CAAK,C,IAAL,CAAaI,CAAA,C,IAAb,CADH,KAEK,G,qBAAIG,wBAAA,E,MAAAA,wBAAD,EAA+BH,C,YAAiBG,wBAAhD,E,qBAA8EC,qBAAA,E,MAAAA,qBAAD,EAA4BJ,C,YAAiBI,qBAA7H,CACAH,CAAA,C,IAAH,CACEL,CAAK,C,IAAL,CAAa,K,cAAA,CAAgBI,CAAhB,CADf,CAGEJ,CAAK,C,OAAL,CAAgBI,CAHlB,CADG,KAKA,G,IAAG,EAAAA,CAAK,C,UAAR,CACAC,CAAA,C,IAAH,CACEL,CAAK,C,IAAL,CAAa,K,YAAA,CAAcI,CAAd,CADf,CAGEJ,CAAK,C,KAAL,CAAcI,CAHhB,CADG,KAMH,MAAM,IAAIK,KAAJ,CAAU,eAAV,CAAN,C,OAEF,K,MAAO,C,IAAP,CAAaT,CAAb,C,oBAEF,CAAQ,U,SACN,GAAqC,K,OAArC,OAAM,IAAIS,KAAJ,CAAU,iBAAV,CAAN,CAEA,GAAG,E,IAAI,O,OAAQ,C,KAAZ,E,IAA2B,O,OAAQ,C,MAAnC,CAAH,CACE,MAAM,IAAIA,KAAJ,CAAU,iDAAV,CAAN,CAEF,K,OAAA,CAAW,E,CACX,K,SAAA,CAAa,C,CACb,K,cAAA,CAAkB,C,CAElB,K,UAAA,C,YAAc,I,sCAAgB,C,CAAA,C,EAAI,K,MAAA,C,SAAA,K,MAAA,C,SAAA,K,MAAA,C,OAAJ,C,EAAI,K,MAAA,C,wCAAL,C,IAAA,C,SAAA,C,mBAAf,C,GAAA,CAAUJ,C,aAAT,I,0BACfD,CAAA,CAAa,K,YAAA,E,CACb,I,sCAA6B,C,CAAA,C,EAAIA,C,GAAAA,C,GAAAA,C,CAAJ,C,EAAIA,C,kCAAL,C,IAAA,C,SAAA,C,mBAA5B,C,GAAA,CAAuBC,C,MAAvB,K,eAAA,E,QAEA,K,IAAA,CAAM,OAAN,C,CACA,K,IAAA,CAAM,UAAN,CAAkB,CAAlB,C,mBAEF,CAAO,U,OACL,M,EAAA,CACE,CACA,GADAD,CAAA,CAAS,K,aAAc,C,KAAd,E,EACI,C,IAAA,EAAAA,CAAA,CAAb,OACAM,OAAO,C,GAAP,CAAY,uBAAZ,C,CACAN,CAAM,C,SAAN,EAHA,C,OAIF,K,OAAA,CAAW,E,CACX,K,IAAA,CAAM,OAAN,C,0BAIF,CAAc,U,OAUZ,OATAA,CAAA,CAAaO,IAAI,C,GAAJ,CAAS,K,OAAA,C,OAAT,CAA2B,K,MAAA,C,MAA3B,C,iCACZ,K,WAAA,C,OAAA,K,WAAA,C,QAAsBP,C,GAAAA,C,GAAAA,C,CAAtB,K,WAAA,C,QAAsBA,C,kCAAvB,C,IAAA,C,SAAA,CAAkC,C,OAAlC,C,4BAA4CJ,C,eAC1CU,OAAO,C,GAAP,CAAa,kBAAD,CAAoBV,CAAhC,C,CACAE,CAAA,CAAS,IAAIU,MAAJ,C,CAAW,C,OAAA,C,YAAX,C,CACTV,CAAM,C,SAAN,C,4BAAoBF,C,UAClB,C,aAAc,C,MAAd,C,CAAsB,C,aAAc,C,OAAd,CAAuBE,CAAvB,CAAtB,CAAsD,CAAtD,C,EACA,C,WAAY,C,IAAZ,CAAkBA,CAAlB,C,EACA,C,aAAA,CAAeF,CAAA,C,IAAf,C,EAHiB,C,CAAA,C,EAInB,C,WAAY,C,IAAZ,CAAkBE,CAAlB,C,EAPyC,C,IAAA,CAA3C,C,CAQOE,C,2BAET,CAAe,SAACA,CAAD,C,QACbM,OAAO,C,GAAP,CAAa,Q,CAASN,CAAA,C,MAAa,c,CAAe,K,aAAA,C,MAAtC,CAA6D,SAAzE,C,CACA,K,cAAA,E,CACA,K,IAAA,CAAM,UAAN,CAAkB,K,cAAA,CAAkB,K,MAAA,C,MAApC,C,CACA,K,UAAW,CAACA,CAAA,C,KAAD,CAAX,CAA2BA,C,EACxB,MAAQ,K,UAAR,C,CACD,K,eAAA,E,CAEA,K,eAAA,E,6BAEJ,CAAiB,U,mBACfF,CAAA,CAAM,C,CACN,I,UAAa,K,qBAAb,C,GAAA,CAAIE,C,CAAS,K,cACXF,CAAA,EAAO,CAACE,CAAK,C,IAAL,C,MAAD,CAAqB,CAArB,C,CAA0BA,CAAA,C,QAA1B,CAA2CA,CAAA,C,MAAlD,CACFF,CAAA,EAAOE,CAAA,C,QAAA,CAAiBA,CAAA,C,OACxBM,OAAO,C,GAAP,CAAa,gC,CAAiCC,IAAI,C,KAAJ,CAAWT,CAAA,CAAM,GAAjB,CAAlC,CAA0D,IAAtE,C,CACAC,CAAA,CAAO,IAAIU,UAAJ,CAAeX,CAAf,C,CACPG,CAAA,CAAS,C,CACT,I,UAAa,K,qBAAb,C,GAAA,C,CAAID,C,CAAS,K,cACX,I,UAAeA,CAAA,C,eAAf,C,GAAA,CAAIL,C,CAAWK,CAAA,C,QAALU,C,GACRX,CAAI,C,GAAJ,CAASJ,CAAT,CAAeM,CAAf,C,CACGS,CAAA,GAAKV,CAAK,C,IAAL,C,OAAoB,CAA5B,CACEC,CAAA,EAAUD,CAAA,C,MADZ,CAGEC,CAAA,EAAUD,CAAA,C,gBAEhBW,CAAA,CAAQ,IAAIC,IAAJ,CAAS,CAACb,CAAD,CAAT,CACN,C,IAAA,CAAM,WAAN,CADM,C,CAGR,K,IAAA,CAAM,UAAN,CAAkBY,CAAlB,CAAyBZ,CAAzB,C,6BAEF,CAAiB,U,WACf,GAAqC,K,WAAA,C,MAAA,GAAuB,CAA5D,OAAM,IAAIM,KAAJ,CAAU,iBAAV,CAAN,CACA,OAAU,K,SAAA,EAAc,K,MAAA,C,eAExBT,CAAA,CAAQ,K,MAAA,CAAQ,K,SAAA,EAAR,C,CACRE,CAAA,CAAS,K,WAAY,C,KAAZ,E,CACTE,CAAA,CAAO,K,OAAA,CAASJ,CAAT,C,CAEPU,OAAO,C,GAAP,CAAa,iB,CAAkB,CAAAN,CAAA,C,KAAA,CAAa,CAAb,C,CAAgB,MAAnC,CAA0C,K,MAAA,C,MAAtD,C,CACA,K,aAAc,C,IAAd,CAAoBF,CAApB,C,CACAA,CAAM,C,WAAN,CAAmBE,CAAnB,C,6BAEF,CAAgB,SAACA,CAAD,C,CACd,OAAOA,CAAG,C,YAAa,CAAC,CAAD,CAAI,CAAJ,CAAO,K,OAAA,C,KAAP,CAAuB,K,OAAA,C,MAAvB,CAAhB,C,8BAET,CAAc,SAACF,CAAD,C,OAWZ,O,IAVO,O,OAAP,E,CACE,K,OAAA,CAAWe,QAAQ,C,aAAR,CAAuB,QAAvB,C,CACX,K,OAAQ,C,KAAR,CAAiB,K,OAAA,C,MACjB,K,OAAQ,C,MAAR,CAAkB,K,OAAA,C,QAEpBb,CAAA,CAAM,K,OAAQ,C,UAAR,CAAoB,IAApB,C,CACNA,CAAG,C,OAAH,CAAc,K,OAAA,C,WACdA,CAAG,C,QAAH,CAAa,CAAb,CAAgB,CAAhB,CAAmB,K,OAAA,C,KAAnB,CAAmC,K,OAAA,C,MAAnC,C,CACAA,CAAG,C,SAAH,CAAcF,CAAd,CAAqB,CAArB,CAAwB,CAAxB,C,CAEO,K,cAAA,CAAgBE,CAAhB,C,qBAET,CAAS,SAACA,CAAD,C,SAaP,GAZAJ,CAAA,CAAQ,K,MAAO,C,OAAP,CAAgBI,CAAhB,C,CACRF,CAAA,CACE,C,KAAA,CAAOF,CAAP,C,IACA,CAAMA,CAAA,GAAU,K,MAAA,C,MAAD,CAAkB,CADjC,C,KAEA,CAAOI,CAAA,C,KAFP,C,WAGA,CAAaA,CAAA,C,WAHb,C,KAIA,CAAO,K,OAAA,C,KAJP,C,MAKA,CAAQ,K,OAAA,C,MALR,C,OAMA,CAAS,K,OAAA,C,OANT,C,MAOA,CAAQ,K,OAAA,C,MAPR,C,WAQA,CAAcL,CAAA,C,IAAD,GAAiB,QAR9B,C,KAUC,EAAAK,CAAK,C,IAAR,CACEF,CAAI,C,IAAJ,CAAYE,CAAA,C,IAAZ,CADF,KAEK,G,IAAG,EAAAA,CAAK,C,OAAR,CACHF,CAAI,C,IAAJ,CAAY,K,cAAA,CAAgBE,CAAA,C,OAAhB,CAAZ,CADG,KAEA,G,IAAG,EAAAA,CAAK,C,KAAR,CACHF,CAAI,C,IAAJ,CAAY,K,YAAA,CAAcE,CAAA,C,KAAd,CAAZ,CADG,KAGH,MAAM,IAAIK,KAAJ,CAAU,eAAV,CAAN,CAEF,OAAOP,C,GAvLT,C,CAFgBD,C,EA2LlBI,CAAM,C,OAAN,CAAiBF,C,oDCvLjBC,C,CAFAC,C,CAFAF,C,CADAH,C,CAEAE,C,CAFAF,CAAA,CAAKkB,SAAS,C,SAAU,C,WAAnB,E,CACLf,CAAA,CAAWe,SAAS,C,QAAS,C,WAAlB,E,CACXhB,CAAA,CAAKF,CAAE,C,KAAF,CAAS,6FAAT,GAA2G,CAAC,IAAD,CAAO,SAAP,CAAkB,CAAlB,C,CAChHK,CAAA,CAAOH,CAAA,CAAG,CAAH,C,GAAS,IAAT,EAAiBe,QAAA,C,aAExBb,CAAA,CACE,C,IAAA,CAASF,CAAA,CAAG,CAAH,IAAS,S,CAAeA,CAAA,CAAG,CAAH,C,CAAWA,CAAA,CAAG,CAAH,CAA5C,C,OACA,CAASG,CAAA,EAAQc,UAAA,CAAcjB,CAAA,CAAG,CAAH,C,GAAS,OAAT,EAAoBA,CAAA,CAAG,CAAH,C,CAAWA,CAAA,CAAG,CAAH,C,CAAWA,CAAA,CAAG,CAAH,CAAxD,CADjB,C,QAGA,CACE,C,IAAA,CAASF,CAAE,C,KAAF,CAAS,kBAAT,C,CAAkC,K,CAAY,CAAAA,CAAE,C,KAAF,CAAS,mBAAT,C,EAAiCG,CAAQ,C,KAAR,CAAe,eAAf,CAAjC,EAAoE,CAAC,OAAD,CAApE,CAAD,CAAgF,CAAhF,CAAtD,CAJF,C,CAMFC,CAAO,CAACA,CAAA,C,IAAD,CAAP,CAAwB,E,CACxBA,CAAO,CAACA,CAAA,C,IAAA,CAAegB,QAAA,CAAShB,CAAA,C,OAAT,CAA0B,EAA1B,CAAhB,CAAP,CAAwD,E,CACxDA,CAAO,C,QAAS,CAACA,CAAO,C,QAAP,C,IAAD,CAAhB,CAA0C,E,CAE1CH,CAAM,C,OAAN,CAAiBG,C,uCClBZF,CAAA,CAAQmB,YAAb,EAA2B,CAAAnB,CAAA,CAAQmB,YAAR,CAAuB,UAAY,EAAnC,CAA3B,CAEA,IAAIjB,CAAA,CAAeD,CAAA,CAAQkB,YAAR,CAAuBnB,CAAA,CAAQmB,YAAlD,CACIrB,CAAA,CAAU,OAAOsB,KAAA,CAAMC,OAAb,GAAyB,UAAzB,CACRD,KAAA,CAAMC,OADE,CAER,SAAUnB,CAAV,CAAc,CACZ,OAAOoB,MAAA,CAAOC,SAAP,CAAiBC,QAAjB,CAA0BC,IAA1B,CAA+BvB,CAA/B,IAAuC,gBADlC,CAHpB,CAcIC,CAAA,CAAsB,EAd1B,CAeAD,CAAA,CAAaqB,SAAb,CAAuBG,eAAvB,CAAyC,SAASxB,CAAT,CAAY,CAC9C,KAAKyB,OAAV,EAAmB,MAAKA,OAAL,CAAe,EAAf,C,CACnB,KAAKA,OAAL,CAAaC,YAAb,CAA4B1B,CAFuB,C,CAMrDA,CAAA,CAAaqB,SAAb,CAAuBM,IAAvB,CAA8B,SAAS9B,CAAT,CAAe,CAE3C,GAAIA,CAAA,GAAS,O,EACP,GAAC,KAAK4B,OAAN,EAAkB,KAAKA,OAAL,CAAaG,KAA/B,GACChC,CAAA,CAAQ,KAAK6B,OAAL,CAAaG,KAArB,GAA+B,CAAC,KAAKH,OAAL,CAAaG,KAAb,CAAmBC,MADpD,CADN,CAII,MAAIC,SAAA,CAAU,CAAV,YAAwBzB,KAA5B,CACQyB,SAAA,CAAU,CAAV,CADR,CAGQ,IAAIzB,KAAJ,CAAU,sCAAV,CAHR,CASJ,GAAI,CAAC,KAAKoB,OAAV,CAAmB,MAAO,EAAP,CACnB,IAAIzB,CAAA,CAAU,KAAKyB,OAAL,CAAa5B,CAAb,CAAd,CACA,GAAI,CAACG,CAAL,CAAc,MAAO,EAAP,CAEd,GAAI,SAAOA,CAAP,EAAkB,UAAlB,CAAJ,CAmBO,GAAIJ,CAAA,CAAQI,CAAR,CAAJ,CAAsB,CAC3B,IAAIF,CAAA,CAAOoB,KAAA,CAAMG,SAAN,CAAgBU,KAAhB,CAAsBR,IAAtB,CAA2BO,SAA3B,CAAsC,CAAtC,CAAX,CAEI/B,CAAA,CAAYC,CAAA,CAAQ+B,KAAR,EAFhB,CAGA,IAAK,IAAI9B,CAAA,CAAI,CAAR,CAAW+B,CAAA,CAAIjC,CAAA,CAAU8B,MAAzB,CAAiC5B,CAAA,CAAI+B,CAA1C,CAA6C/B,CAAA,EAA7C,CACEF,CAAA,CAAUE,CAAV,EAAagC,KAAb,CAAmB,IAAnB,CAAyBnC,CAAzB,EAEF,MAAO,EAPoB,CAAtB,KAUL,MAAO,EAAP,CA5BA,OAAQgC,SAAA,CAAUD,MAAlB,EAEE,KAAK,CAAL,CACE7B,CAAA,CAAQuB,IAAR,CAAa,IAAb,EACA,MACF,KAAK,CAAL,CACEvB,CAAA,CAAQuB,IAAR,CAAa,IAAb,CAAmBO,SAAA,CAAU,CAAV,CAAnB,EACA,MACF,KAAK,CAAL,CACE9B,CAAA,CAAQuB,IAAR,CAAa,IAAb,CAAmBO,SAAA,CAAU,CAAV,CAAnB,CAAiCA,SAAA,CAAU,CAAV,CAAjC,EACA,MAEF,QACE,IAAIhC,CAAA,CAAOoB,KAAA,CAAMG,SAAN,CAAgBU,KAAhB,CAAsBR,IAAtB,CAA2BO,SAA3B,CAAsC,CAAtC,CAAX,CACA9B,CAAA,CAAQiC,KAAR,CAAc,IAAd,CAAoBnC,CAApB,CAdJ,CAgBA,MAAO,EApCkC,C,CAsD7CE,CAAA,CAAaqB,SAAb,CAAuBa,WAAvB,CAAqC,SAASlC,CAAT,CAAeF,CAAf,CAAyB,CAC5D,GAAI,aAAe,OAAOA,CAA1B,CACE,MAAM,IAAIO,KAAJ,CAAU,8CAAV,CAAN,CASF,GANK,KAAKoB,OAAV,EAAmB,MAAKA,OAAL,CAAe,EAAf,C,CAInB,KAAKE,IAAL,CAAU,aAAV,CAAyB3B,CAAzB,CAA+BF,CAA/B,C,CAEI,CAAC,KAAK2B,OAAL,CAAazB,CAAb,CAAL,CAEE,KAAKyB,OAAL,CAAazB,CAAb,EAAqBF,CAArB,CAFF,KAGO,GAAIF,CAAA,CAAQ,KAAK6B,OAAL,CAAazB,CAAb,CAAR,CAAJ,CAAiC,CAGtC,GAAI,CAAC,KAAKyB,OAAL,CAAazB,CAAb,EAAmBmC,MAAxB,CAAgC,CAC9B,IAAIpC,CAAJ,CACI,KAAK0B,OAAL,CAAaC,YAAb,GAA8BU,SAAlC,CACErC,CAAA,CAAI,KAAK0B,OAAL,CAAaC,YADnB,CAGE3B,CAAA,CAAIE,C,CAGFF,CAAA,EAAKA,CAAA,CAAI,CAAT,EAAc,KAAK0B,OAAL,CAAazB,CAAb,EAAmB6B,MAAnB,CAA4B9B,CAA9C,E,CACE,KAAK0B,OAAL,CAAazB,CAAb,EAAmBmC,MAAnB,CAA4B,E,CAC5B7B,OAAA,CAAQsB,KAAR,CAAc,kIAAd,CAGc,KAAKH,OAAL,CAAazB,CAAb,EAAmB6B,MAHjC,C,CAIAvB,OAAA,CAAQ+B,KAAR,E,CAd4B,CAmBhC,KAAKZ,OAAL,CAAazB,CAAb,EAAmBsC,IAAnB,CAAwBxC,CAAxB,CAtBsC,CAAjC,KAyBL,KAAK2B,OAAL,CAAazB,CAAb,EAAqB,CAAC,KAAKyB,OAAL,CAAazB,CAAb,CAAD,CAAqBF,CAArB,CAArB,CAGF,OAAO,IA1CqD,C,CA6C9DE,CAAA,CAAaqB,SAAb,CAAuBkB,EAAvB,CAA4BvC,CAAA,CAAaqB,SAAb,CAAuBa,W,CAEnDlC,CAAA,CAAaqB,SAAb,CAAuBmB,IAAvB,CAA8B,SAAS1C,CAAT,CAAeF,CAAf,CAAyB,CACrD,IAAII,CAAA,CAAO,IAAX,CAMA,OALAA,CAAA,CAAKuC,EAAL,CAAQzC,CAAR,CAAc,SAASG,CAAT,EAAa,CACzBD,CAAA,CAAKyC,cAAL,CAAoB3C,CAApB,CAA0BG,CAA1B,C,CACAL,CAAA,CAASqC,KAAT,CAAe,IAAf,CAAqBH,SAArB,CAFyB,CAA3B,C,CAKO,IAP8C,C,CAUvD9B,CAAA,CAAaqB,SAAb,CAAuBoB,cAAvB,CAAwC,SAASzC,CAAT,CAAeC,CAAf,CAAyB,CAC/D,GAAI,aAAe,OAAOA,CAA1B,CACE,MAAM,IAAII,KAAJ,CAAU,iDAAV,CAAN,CAIF,GAAI,EAAC,KAAKoB,OAAN,EAAkB,KAAKA,OAAL,CAAazB,CAAb,CAAlB,CAAJ,CAA0C,OAAO,IAAP,CAE1C,IAAIF,CAAA,CAAO,KAAK2B,OAAL,CAAazB,CAAb,CAAX,CAEA,GAAIJ,CAAA,CAAQE,CAAR,CAAJ,CAAmB,CACjB,IAAIC,CAAA,CAAID,CAAA,CAAK4C,OAAL,CAAazC,CAAb,CAAR,CACA,GAAIF,CAAA,CAAI,CAAR,CAAW,OAAO,IAAP,CACXD,CAAA,CAAK6C,MAAL,CAAY5C,CAAZ,CAAe,CAAf,C,CACID,CAAA,CAAK+B,MAAL,EAAe,CAAnB,EACE,OAAO,KAAKJ,OAAL,CAAazB,CAAb,CALQ,CAAnB,KAMW,KAAKyB,OAAL,CAAazB,CAAb,IAAuBC,CAA3B,EACL,OAAO,KAAKwB,OAAL,CAAazB,CAAb,CADF,CAIP,OAAO,IApBwD,C,CAuBjEA,CAAA,CAAaqB,SAAb,CAAuBuB,kBAAvB,CAA4C,SAAS5C,CAAT,CAAe,CAGzD,OADIA,CAAA,EAAQ,KAAKyB,OAAb,EAAwB,KAAKA,OAAL,CAAazB,CAAb,CAA5B,EAAgD,MAAKyB,OAAL,CAAazB,CAAb,EAAqB,IAArB,C,CACzC,IAHkD,C,CAM3DA,CAAA,CAAaqB,SAAb,CAAuBwB,SAAvB,CAAmC,SAAS7C,CAAT,CAAe,CAMhD,OALK,KAAKyB,OAAV,EAAmB,MAAKA,OAAL,CAAe,EAAf,C,CACd,KAAKA,OAAL,CAAazB,CAAb,CAAL,EAAyB,MAAKyB,OAAL,CAAazB,CAAb,EAAqB,EAArB,C,CACpBJ,CAAA,CAAQ,KAAK6B,OAAL,CAAazB,CAAb,CAAR,CAAL,EACE,MAAKyB,OAAL,CAAazB,CAAb,EAAqB,CAAC,KAAKyB,OAAL,CAAazB,CAAb,CAAD,CAArB,C,CAEK,KAAKyB,OAAL,CAAazB,CAAb,CANyC,C","sourceRoot":"../src","sourcesContent":["{EventEmitter} = require 'events'\nbrowser = require './browser.coffee'\n\nclass GIF extends EventEmitter\n\n defaults =\n workerScript: 'gif.worker.js'\n workers: 2\n repeat: 0 # repeat forever, -1 = repeat once\n background: '#fff'\n quality: 10 # pixel sample interval, lower is better\n width: null # size derermined from first frame if possible\n height: null\n transparent: null\n\n frameDefaults =\n delay: 500 # ms\n copy: false\n\n constructor: (options) ->\n @running = false\n\n @options = {}\n @frames = []\n\n @freeWorkers = []\n @activeWorkers = []\n\n @setOptions options\n for key, value of defaults\n @options[key] ?= value\n\n setOption: (key, value) ->\n @options[key] = value\n if @_canvas? and key in ['width', 'height']\n @_canvas[key] = value\n\n setOptions: (options) ->\n @setOption key, value for own key, value of options\n\n addFrame: (image, options={}) ->\n frame = {}\n frame.transparent = @options.transparent\n for key of frameDefaults\n frame[key] = options[key] or frameDefaults[key]\n\n # use the images width and height for options unless already set\n @setOption 'width', image.width unless @options.width?\n @setOption 'height', image.height unless @options.height?\n\n if ImageData? and image instanceof ImageData\n frame.data = image.data\n else if (CanvasRenderingContext2D? and image instanceof CanvasRenderingContext2D) or (WebGLRenderingContext? and image instanceof WebGLRenderingContext)\n if options.copy\n frame.data = @getContextData image\n else\n frame.context = image\n else if image.childNodes?\n if options.copy\n frame.data = @getImageData image\n else\n frame.image = image\n else\n throw new Error 'Invalid image'\n\n @frames.push frame\n\n render: ->\n throw new Error 'Already running' if @running\n\n if not @options.width? or not @options.height?\n throw new Error 'Width and height must be set prior to rendering'\n\n @running = true\n @nextFrame = 0\n @finishedFrames = 0\n\n @imageParts = (null for i in [0...@frames.length])\n numWorkers = @spawnWorkers()\n @renderNextFrame() for i in [0...numWorkers]\n\n @emit 'start'\n @emit 'progress', 0\n\n abort: ->\n loop\n worker = @activeWorkers.shift()\n break unless worker?\n console.log \"killing active worker\"\n worker.terminate()\n @running = false\n @emit 'abort'\n\n # private\n\n spawnWorkers: ->\n numWorkers = Math.min(@options.workers, @frames.length)\n [@freeWorkers.length...numWorkers].forEach (i) =>\n console.log \"spawning worker #{ i }\"\n worker = new Worker @options.workerScript\n worker.onmessage = (event) =>\n @activeWorkers.splice @activeWorkers.indexOf(worker), 1\n @freeWorkers.push worker\n @frameFinished event.data\n @freeWorkers.push worker\n return numWorkers\n\n frameFinished: (frame) ->\n console.log \"frame #{ frame.index } finished - #{ @activeWorkers.length } active\"\n @finishedFrames++\n @emit 'progress', @finishedFrames / @frames.length\n @imageParts[frame.index] = frame\n if null in @imageParts\n @renderNextFrame()\n else\n @finishRendering()\n\n finishRendering: ->\n len = 0\n for frame in @imageParts\n len += (frame.data.length - 1) * frame.pageSize + frame.cursor\n len += frame.pageSize - frame.cursor\n console.log \"rendering finished - filesize #{ Math.round(len / 1000) }kb\"\n data = new Uint8Array len\n offset = 0\n for frame in @imageParts\n for page, i in frame.data\n data.set page, offset\n if i is frame.data.length - 1\n offset += frame.cursor\n else\n offset += frame.pageSize\n\n image = new Blob [data],\n type: 'image/gif'\n\n @emit 'finished', image, data\n\n renderNextFrame: ->\n throw new Error 'No free workers' if @freeWorkers.length is 0\n return if @nextFrame >= @frames.length # no new frame to render\n\n frame = @frames[@nextFrame++]\n worker = @freeWorkers.shift()\n task = @getTask frame\n\n console.log \"starting frame #{ task.index + 1 } of #{ @frames.length }\"\n @activeWorkers.push worker\n worker.postMessage task#, [task.data.buffer]\n\n getContextData: (ctx) ->\n return ctx.getImageData(0, 0, @options.width, @options.height).data\n\n getImageData: (image) ->\n if not @_canvas?\n @_canvas = document.createElement 'canvas'\n @_canvas.width = @options.width\n @_canvas.height = @options.height\n\n ctx = @_canvas.getContext '2d'\n ctx.setFill = @options.background\n ctx.fillRect 0, 0, @options.width, @options.height\n ctx.drawImage image, 0, 0\n\n return @getContextData ctx\n\n getTask: (frame) ->\n index = @frames.indexOf frame\n task =\n index: index\n last: index is (@frames.length - 1)\n delay: frame.delay\n transparent: frame.transparent\n width: @options.width\n height: @options.height\n quality: @options.quality\n repeat: @options.repeat\n canTransfer: (browser.name is 'chrome')\n\n if frame.data?\n task.data = frame.data\n else if frame.context?\n task.data = @getContextData frame.context\n else if frame.image?\n task.data = @getImageData frame.image\n else\n throw new Error 'Invalid frame'\n\n return task\n\nmodule.exports = GIF\n","### CoffeeScript version of the browser detection from MooTools ###\n\nua = navigator.userAgent.toLowerCase()\nplatform = navigator.platform.toLowerCase()\nUA = ua.match(/(opera|ie|firefox|chrome|version)[\\s\\/:]([\\w\\d\\.]+)?.*?(safari|version[\\s\\/:]([\\w\\d\\.]+)|$)/) or [null, 'unknown', 0]\nmode = UA[1] == 'ie' && document.documentMode\n\nbrowser =\n name: if UA[1] is 'version' then UA[3] else UA[1]\n version: mode or parseFloat(if UA[1] is 'opera' && UA[4] then UA[4] else UA[2])\n\n platform:\n name: if ua.match(/ip(?:ad|od|hone)/) then 'ios' else (ua.match(/(?:webos|android)/) or platform.match(/mac|win|linux/) or ['other'])[0]\n\nbrowser[browser.name] = true\nbrowser[browser.name + parseInt(browser.version, 10)] = true\nbrowser.platform[browser.platform.name] = true\n\nmodule.exports = browser\n","if (!process.EventEmitter) process.EventEmitter = function () {};\n\nvar EventEmitter = exports.EventEmitter = process.EventEmitter;\nvar isArray = typeof Array.isArray === 'function'\n ? Array.isArray\n : function (xs) {\n return Object.prototype.toString.call(xs) === '[object Array]'\n }\n;\n\n// By default EventEmitters will print a warning if more than\n// 10 listeners are added to it. This is a useful default which\n// helps finding memory leaks.\n//\n// Obviously not all Emitters should be limited to 10. This function allows\n// that to be increased. Set to zero for unlimited.\nvar defaultMaxListeners = 10;\nEventEmitter.prototype.setMaxListeners = function(n) {\n if (!this._events) this._events = {};\n this._events.maxListeners = n;\n};\n\n\nEventEmitter.prototype.emit = function(type) {\n // If there is no 'error' event listener then throw.\n if (type === 'error') {\n if (!this._events || !this._events.error ||\n (isArray(this._events.error) && !this._events.error.length))\n {\n if (arguments[1] instanceof Error) {\n throw arguments[1]; // Unhandled 'error' event\n } else {\n throw new Error(\"Uncaught, unspecified 'error' event.\");\n }\n return false;\n }\n }\n\n if (!this._events) return false;\n var handler = this._events[type];\n if (!handler) return false;\n\n if (typeof handler == 'function') {\n switch (arguments.length) {\n // fast cases\n case 1:\n handler.call(this);\n break;\n case 2:\n handler.call(this, arguments[1]);\n break;\n case 3:\n handler.call(this, arguments[1], arguments[2]);\n break;\n // slower\n default:\n var args = Array.prototype.slice.call(arguments, 1);\n handler.apply(this, args);\n }\n return true;\n\n } else if (isArray(handler)) {\n var args = Array.prototype.slice.call(arguments, 1);\n\n var listeners = handler.slice();\n for (var i = 0, l = listeners.length; i < l; i++) {\n listeners[i].apply(this, args);\n }\n return true;\n\n } else {\n return false;\n }\n};\n\n// EventEmitter is defined in src/node_events.cc\n// EventEmitter.prototype.emit() is also defined there.\nEventEmitter.prototype.addListener = function(type, listener) {\n if ('function' !== typeof listener) {\n throw new Error('addListener only takes instances of Function');\n }\n\n if (!this._events) this._events = {};\n\n // To avoid recursion in the case that type == \"newListeners\"! Before\n // adding it to the listeners, first emit \"newListeners\".\n this.emit('newListener', type, listener);\n\n if (!this._events[type]) {\n // Optimize the case of one listener. Don't need the extra array object.\n this._events[type] = listener;\n } else if (isArray(this._events[type])) {\n\n // Check for listener leak\n if (!this._events[type].warned) {\n var m;\n if (this._events.maxListeners !== undefined) {\n m = this._events.maxListeners;\n } else {\n m = defaultMaxListeners;\n }\n\n if (m && m > 0 && this._events[type].length > m) {\n this._events[type].warned = true;\n console.error('(node) warning: possible EventEmitter memory ' +\n 'leak detected. %d listeners added. ' +\n 'Use emitter.setMaxListeners() to increase limit.',\n this._events[type].length);\n console.trace();\n }\n }\n\n // If we've already got an array, just append.\n this._events[type].push(listener);\n } else {\n // Adding the second element, need to change to array.\n this._events[type] = [this._events[type], listener];\n }\n\n return this;\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.once = function(type, listener) {\n var self = this;\n self.on(type, function g() {\n self.removeListener(type, g);\n listener.apply(this, arguments);\n });\n\n return this;\n};\n\nEventEmitter.prototype.removeListener = function(type, listener) {\n if ('function' !== typeof listener) {\n throw new Error('removeListener only takes instances of Function');\n }\n\n // does not use listeners(), so no side effect of creating _events[type]\n if (!this._events || !this._events[type]) return this;\n\n var list = this._events[type];\n\n if (isArray(list)) {\n var i = list.indexOf(listener);\n if (i < 0) return this;\n list.splice(i, 1);\n if (list.length == 0)\n delete this._events[type];\n } else if (this._events[type] === listener) {\n delete this._events[type];\n }\n\n return this;\n};\n\nEventEmitter.prototype.removeAllListeners = function(type) {\n // does not use listeners(), so no side effect of creating _events[type]\n if (type && this._events && this._events[type]) this._events[type] = null;\n return this;\n};\n\nEventEmitter.prototype.listeners = function(type) {\n if (!this._events) this._events = {};\n if (!this._events[type]) this._events[type] = [];\n if (!isArray(this._events[type])) {\n this._events[type] = [this._events[type]];\n }\n return this._events[type];\n};\n"]} \ No newline at end of file diff --git a/demo/js/lib/matter-tools/gif/gif.worker.js b/demo/js/lib/matter-tools/gif/gif.worker.js deleted file mode 100644 index 8098060..0000000 --- a/demo/js/lib/matter-tools/gif/gif.worker.js +++ /dev/null @@ -1,3 +0,0 @@ -(function(b){function a(b,d){if({}.hasOwnProperty.call(a.cache,b))return a.cache[b];var e=a.resolve(b);if(!e)throw new Error('Failed to resolve module '+b);var c={id:b,require:a,filename:b,exports:{},loaded:!1,parent:d,children:[]};d&&d.children.push(c);var f=b.slice(0,b.lastIndexOf('/')+1);return a.cache[b]=c.exports,e.call(c.exports,c,c.exports,f,b),c.loaded=!0,a.cache[b]=c.exports}a.modules={},a.cache={},a.resolve=function(b){return{}.hasOwnProperty.call(a.modules,b)?a.modules[b]:void 0},a.define=function(b,c){a.modules[b]=c},a.define('/gif.worker.coffee',function(d,e,f,g){var b,c;b=a('/GIFEncoder.js',d),c=function(a){var c,e,d,f;return c=new b(a.width,a.height),a.index===0?c.writeHeader():c.firstFrame=!1,c.setTransparent(a.transparent),c.setRepeat(a.repeat),c.setDelay(a.delay),c.setQuality(a.quality),c.addFrame(a.data),a.last&&c.finish(),d=c.stream(),a.data=d.pages,a.cursor=d.cursor,a.pageSize=d.constructor.pageSize,a.canTransfer?(f=function(c){for(var b=0,d=a.data.length;b=c.pageSize&&this.newPage(),this.pages[this.page][this.cursor++]=a},c.prototype.writeUTFBytes=function(b){for(var c=b.length,a=0;a=0&&(this.dispose=a)},b.prototype.setRepeat=function(a){this.repeat=a},b.prototype.setTransparent=function(a){this.transparent=a},b.prototype.addFrame=function(a){this.image=a,this.getImagePixels(),this.analyzePixels(),this.firstFrame&&(this.writeLSD(),this.writePalette(),this.repeat>=0&&this.writeNetscapeExt()),this.writeGraphicCtrlExt(),this.writeImageDesc(),this.firstFrame||this.writePalette(),this.writePixels(),this.firstFrame=!1},b.prototype.finish=function(){this.out.writeByte(59)},b.prototype.setQuality=function(a){a<1&&(a=1),this.sample=a},b.prototype.writeHeader=function(){this.out.writeUTFBytes('GIF89a')},b.prototype.analyzePixels=function(){var g=this.pixels.length,d=g/3;this.indexedPixels=new Uint8Array(d);var a=new f(this.pixels,this.sample);a.buildColormap(),this.colorTab=a.getColormap();var b=0;for(var c=0;c>16,l=(e&65280)>>8,m=e&255,c=0,d=16777216,j=this.colorTab.length;for(var a=0;a=0&&(a=dispose&7),a<<=2,this.out.writeByte(0|a|0|b),this.writeShort(this.delay),this.out.writeByte(this.transIndex),this.out.writeByte(0)},b.prototype.writeImageDesc=function(){this.out.writeByte(44),this.writeShort(0),this.writeShort(0),this.writeShort(this.width),this.writeShort(this.height),this.firstFrame?this.out.writeByte(0):this.out.writeByte(128|this.palSize)},b.prototype.writeLSD=function(){this.writeShort(this.width),this.writeShort(this.height),this.out.writeByte(240|this.palSize),this.out.writeByte(0),this.out.writeByte(0)},b.prototype.writeNetscapeExt=function(){this.out.writeByte(33),this.out.writeByte(255),this.out.writeByte(11),this.out.writeUTFBytes('NETSCAPE2.0'),this.out.writeByte(3),this.out.writeByte(1),this.writeShort(this.repeat),this.out.writeByte(0)},b.prototype.writePalette=function(){this.out.writeBytes(this.colorTab);var b=768-this.colorTab.length;for(var a=0;a>8&255)},b.prototype.writePixels=function(){var a=new g(this.width,this.height,this.indexedPixels,this.colorDepth);a.encode(this.out)},b.prototype.stream=function(){return this.out},e.exports=b}),a.define('/LZWEncoder.js',function(e,g,h,i){function f(y,D,C,B){function w(a,b){r[f++]=a,f>=254&&t(b)}function x(b){u(a),k=i+2,j=!0,l(i,b)}function u(b){for(var a=0;a=0){y=w-d,d===0&&(y=1);do if((d-=y)<0&&(d+=w),h[d]===g){e=n[d];continue a}while(h[d]>=0)}l(e,r),e=t,k<1<0&&(a.writeByte(f),a.writeBytes(r,0,f),f=0)}function p(a){return(1<0?g|=a<=8)w(g&255,c),g>>=8,e-=8;if((k>m||j)&&(j?(m=p(n_bits=q),j=!1):(++n_bits,n_bits==b?m=1<0)w(g&255,c),g>>=8,e-=8;t(c)}}var s=Math.max(2,B),r=new Uint8Array(256),h=new Int32Array(a),n=new Int32Array(a),g,e=0,f,k=0,m,j=!1,q,i,o;this.encode=z}var c=-1,b=12,a=5003,d=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535];e.exports=f}),a.define('/TypedNeuQuant.js',function(A,F,E,D){function C(A,B){function I(){o=[],q=new Int32Array(256),t=new Int32Array(a),y=new Int32Array(a),z=new Int32Array(a>>3);var c,d;for(c=0;c>=b,o[c][1]>>=b,o[c][2]>>=b,o[c][3]=c}function K(b,a,c,e,f){o[a][0]-=b*(o[a][0]-c)/d,o[a][1]-=b*(o[a][1]-e)/d,o[a][2]-=b*(o[a][2]-f)/d}function L(j,e,n,l,k){var h=Math.abs(e-j),i=Math.min(e+j,a),g=e+1,f=e-1,m=1,b,d;while(gh)d=z[m++],gh&&(b=o[f--],b[0]-=d*(b[0]-n)/c,b[1]-=d*(b[1]-l)/c,b[2]-=d*(b[2]-k)/c)}function C(p,s,q){var h=2147483647,k=h,d=-1,m=d,c,j,e,n,l;for(c=0;c>i-b),n>g,y[c]-=l,t[c]+=l<>1,b=f+1;b>1,b=f+1;b<256;b++)q[b]=n}function E(j,i,k){var b,d,c,e=1e3,h=-1,f=q[i],g=f-1;while(f=0)f=e?f=a:(f++,c<0&&(c=-c),b=d[0]-j,b<0&&(b=-b),c+=b,c=0&&(d=o[g],c=i-d[1],c>=e?g=-1:(g--,c<0&&(c=-c),b=d[0]-j,b<0&&(b=-b),c+=b,c>h;for(a<=1&&(a=0),c=0;c=f&&(g-=f),c++,q===0&&(q=1),c%q===0)for(n-=n/D,o-=o/v,a=o>>h,a<=1&&(a=0),e=0;e>g,r=e<>3,h=6,t=1<\n encoder = new GIFEncoder frame.width, frame.height\n\n if frame.index is 0\n encoder.writeHeader()\n else\n encoder.firstFrame = false\n\n encoder.setTransparent frame.transparent\n encoder.setRepeat frame.repeat\n encoder.setDelay frame.delay\n encoder.setQuality frame.quality\n encoder.addFrame frame.data\n encoder.finish() if frame.last\n\n stream = encoder.stream()\n frame.data = stream.pages\n frame.cursor = stream.cursor\n frame.pageSize = stream.constructor.pageSize\n\n if frame.canTransfer\n transfer = (page.buffer for page in frame.data)\n self.postMessage frame, transfer\n else\n self.postMessage frame\n\nself.onmessage = (event) -> renderFrame event.data\n","/*\n GIFEncoder.js\n\n Authors\n Kevin Weiner (original Java version - kweiner@fmsware.com)\n Thibault Imbert (AS3 version - bytearray.org)\n Johan Nordberg (JS version - code@johan-nordberg.com)\n*/\n\nvar NeuQuant = require('./TypedNeuQuant.js');\nvar LZWEncoder = require('./LZWEncoder.js');\n\nfunction ByteArray() {\n this.page = -1;\n this.pages = [];\n this.newPage();\n}\n\nByteArray.pageSize = 4096;\nByteArray.charMap = {};\n\nfor (var i = 0; i < 256; i++)\n ByteArray.charMap[i] = String.fromCharCode(i);\n\nByteArray.prototype.newPage = function() {\n this.pages[++this.page] = new Uint8Array(ByteArray.pageSize);\n this.cursor = 0;\n};\n\nByteArray.prototype.getData = function() {\n var rv = '';\n for (var p = 0; p < this.pages.length; p++) {\n for (var i = 0; i < ByteArray.pageSize; i++) {\n rv += ByteArray.charMap[this.pages[p][i]];\n }\n }\n return rv;\n};\n\nByteArray.prototype.writeByte = function(val) {\n if (this.cursor >= ByteArray.pageSize) this.newPage();\n this.pages[this.page][this.cursor++] = val;\n};\n\nByteArray.prototype.writeUTFBytes = function(string) {\n for (var l = string.length, i = 0; i < l; i++)\n this.writeByte(string.charCodeAt(i));\n};\n\nByteArray.prototype.writeBytes = function(array, offset, length) {\n for (var l = length || array.length, i = offset || 0; i < l; i++)\n this.writeByte(array[i]);\n};\n\nfunction GIFEncoder(width, height) {\n // image size\n this.width = ~~width;\n this.height = ~~height;\n\n // transparent color if given\n this.transparent = null;\n\n // transparent index in color table\n this.transIndex = 0;\n\n // -1 = no repeat, 0 = forever. anything else is repeat count\n this.repeat = -1;\n\n // frame delay (hundredths)\n this.delay = 0;\n\n this.image = null; // current frame\n this.pixels = null; // BGR byte array from frame\n this.indexedPixels = null; // converted frame indexed to palette\n this.colorDepth = null; // number of bit planes\n this.colorTab = null; // RGB palette\n this.usedEntry = new Array(); // active palette entries\n this.palSize = 7; // color table size (bits-1)\n this.dispose = -1; // disposal code (-1 = use default)\n this.firstFrame = true;\n this.sample = 10; // default sample interval for quantizer\n\n this.out = new ByteArray();\n}\n\n/*\n Sets the delay time between each frame, or changes it for subsequent frames\n (applies to last frame added)\n*/\nGIFEncoder.prototype.setDelay = function(milliseconds) {\n this.delay = Math.round(milliseconds / 10);\n};\n\n/*\n Sets frame rate in frames per second.\n*/\nGIFEncoder.prototype.setFrameRate = function(fps) {\n this.delay = Math.round(100 / fps);\n};\n\n/*\n Sets the GIF frame disposal code for the last added frame and any\n subsequent frames.\n\n Default is 0 if no transparent color has been set, otherwise 2.\n*/\nGIFEncoder.prototype.setDispose = function(disposalCode) {\n if (disposalCode >= 0) this.dispose = disposalCode;\n};\n\n/*\n Sets the number of times the set of GIF frames should be played.\n\n -1 = play once\n 0 = repeat indefinitely\n\n Default is -1\n\n Must be invoked before the first image is added\n*/\n\nGIFEncoder.prototype.setRepeat = function(repeat) {\n this.repeat = repeat;\n};\n\n/*\n Sets the transparent color for the last added frame and any subsequent\n frames. Since all colors are subject to modification in the quantization\n process, the color in the final palette for each frame closest to the given\n color becomes the transparent color for that frame. May be set to null to\n indicate no transparent color.\n*/\nGIFEncoder.prototype.setTransparent = function(color) {\n this.transparent = color;\n};\n\n/*\n Adds next GIF frame. The frame is not written immediately, but is\n actually deferred until the next frame is received so that timing\n data can be inserted. Invoking finish() flushes all frames.\n*/\nGIFEncoder.prototype.addFrame = function(imageData) {\n this.image = imageData;\n\n this.getImagePixels(); // convert to correct format if necessary\n this.analyzePixels(); // build color table & map pixels\n\n if (this.firstFrame) {\n this.writeLSD(); // logical screen descriptior\n this.writePalette(); // global color table\n if (this.repeat >= 0) {\n // use NS app extension to indicate reps\n this.writeNetscapeExt();\n }\n }\n\n this.writeGraphicCtrlExt(); // write graphic control extension\n this.writeImageDesc(); // image descriptor\n if (!this.firstFrame) this.writePalette(); // local color table\n this.writePixels(); // encode and write pixel data\n\n this.firstFrame = false;\n};\n\n/*\n Adds final trailer to the GIF stream, if you don't call the finish method\n the GIF stream will not be valid.\n*/\nGIFEncoder.prototype.finish = function() {\n this.out.writeByte(0x3b); // gif trailer\n};\n\n/*\n Sets quality of color quantization (conversion of images to the maximum 256\n colors allowed by the GIF specification). Lower values (minimum = 1)\n produce better colors, but slow processing significantly. 10 is the\n default, and produces good color mapping at reasonable speeds. Values\n greater than 20 do not yield significant improvements in speed.\n*/\nGIFEncoder.prototype.setQuality = function(quality) {\n if (quality < 1) quality = 1;\n this.sample = quality;\n};\n\n/*\n Writes GIF file header\n*/\nGIFEncoder.prototype.writeHeader = function() {\n this.out.writeUTFBytes(\"GIF89a\");\n};\n\n/*\n Analyzes current frame colors and creates color map.\n*/\nGIFEncoder.prototype.analyzePixels = function() {\n var len = this.pixels.length;\n var nPix = len / 3;\n\n this.indexedPixels = new Uint8Array(nPix);\n\n var imgq = new NeuQuant(this.pixels, this.sample);\n imgq.buildColormap(); // create reduced palette\n this.colorTab = imgq.getColormap();\n\n // map image pixels to new palette\n var k = 0;\n for (var j = 0; j < nPix; j++) {\n var index = imgq.lookupRGB(\n this.pixels[k++] & 0xff,\n this.pixels[k++] & 0xff,\n this.pixels[k++] & 0xff\n );\n this.usedEntry[index] = true;\n this.indexedPixels[j] = index;\n }\n\n this.pixels = null;\n this.colorDepth = 8;\n this.palSize = 7;\n\n // get closest match to transparent color if specified\n if (this.transparent !== null) {\n this.transIndex = this.findClosest(this.transparent);\n }\n};\n\n/*\n Returns index of palette color closest to c\n*/\nGIFEncoder.prototype.findClosest = function(c) {\n if (this.colorTab === null) return -1;\n\n var r = (c & 0xFF0000) >> 16;\n var g = (c & 0x00FF00) >> 8;\n var b = (c & 0x0000FF);\n var minpos = 0;\n var dmin = 256 * 256 * 256;\n var len = this.colorTab.length;\n\n for (var i = 0; i < len;) {\n var dr = r - (this.colorTab[i++] & 0xff);\n var dg = g - (this.colorTab[i++] & 0xff);\n var db = b - (this.colorTab[i] & 0xff);\n var d = dr * dr + dg * dg + db * db;\n var index = parseInt(i / 3);\n if (this.usedEntry[index] && (d < dmin)) {\n dmin = d;\n minpos = index;\n }\n i++;\n }\n\n return minpos;\n};\n\n/*\n Extracts image pixels into byte array pixels\n (removes alphachannel from canvas imagedata)\n*/\nGIFEncoder.prototype.getImagePixels = function() {\n var w = this.width;\n var h = this.height;\n this.pixels = new Uint8Array(w * h * 3);\n\n var data = this.image;\n var count = 0;\n\n for (var i = 0; i < h; i++) {\n for (var j = 0; j < w; j++) {\n var b = (i * w * 4) + j * 4;\n this.pixels[count++] = data[b];\n this.pixels[count++] = data[b+1];\n this.pixels[count++] = data[b+2];\n }\n }\n};\n\n/*\n Writes Graphic Control Extension\n*/\nGIFEncoder.prototype.writeGraphicCtrlExt = function() {\n this.out.writeByte(0x21); // extension introducer\n this.out.writeByte(0xf9); // GCE label\n this.out.writeByte(4); // data block size\n\n var transp, disp;\n if (this.transparent === null) {\n transp = 0;\n disp = 0; // dispose = no action\n } else {\n transp = 1;\n disp = 2; // force clear if using transparent color\n }\n\n if (this.dispose >= 0) {\n disp = dispose & 7; // user override\n }\n disp <<= 2;\n\n // packed fields\n this.out.writeByte(\n 0 | // 1:3 reserved\n disp | // 4:6 disposal\n 0 | // 7 user input - 0 = none\n transp // 8 transparency flag\n );\n\n this.writeShort(this.delay); // delay x 1/100 sec\n this.out.writeByte(this.transIndex); // transparent color index\n this.out.writeByte(0); // block terminator\n};\n\n/*\n Writes Image Descriptor\n*/\nGIFEncoder.prototype.writeImageDesc = function() {\n this.out.writeByte(0x2c); // image separator\n this.writeShort(0); // image position x,y = 0,0\n this.writeShort(0);\n this.writeShort(this.width); // image size\n this.writeShort(this.height);\n\n // packed fields\n if (this.firstFrame) {\n // no LCT - GCT is used for first (or only) frame\n this.out.writeByte(0);\n } else {\n // specify normal LCT\n this.out.writeByte(\n 0x80 | // 1 local color table 1=yes\n 0 | // 2 interlace - 0=no\n 0 | // 3 sorted - 0=no\n 0 | // 4-5 reserved\n this.palSize // 6-8 size of color table\n );\n }\n};\n\n/*\n Writes Logical Screen Descriptor\n*/\nGIFEncoder.prototype.writeLSD = function() {\n // logical screen size\n this.writeShort(this.width);\n this.writeShort(this.height);\n\n // packed fields\n this.out.writeByte(\n 0x80 | // 1 : global color table flag = 1 (gct used)\n 0x70 | // 2-4 : color resolution = 7\n 0x00 | // 5 : gct sort flag = 0\n this.palSize // 6-8 : gct size\n );\n\n this.out.writeByte(0); // background color index\n this.out.writeByte(0); // pixel aspect ratio - assume 1:1\n};\n\n/*\n Writes Netscape application extension to define repeat count.\n*/\nGIFEncoder.prototype.writeNetscapeExt = function() {\n this.out.writeByte(0x21); // extension introducer\n this.out.writeByte(0xff); // app extension label\n this.out.writeByte(11); // block size\n this.out.writeUTFBytes('NETSCAPE2.0'); // app id + auth code\n this.out.writeByte(3); // sub-block size\n this.out.writeByte(1); // loop sub-block id\n this.writeShort(this.repeat); // loop count (extra iterations, 0=repeat forever)\n this.out.writeByte(0); // block terminator\n};\n\n/*\n Writes color table\n*/\nGIFEncoder.prototype.writePalette = function() {\n this.out.writeBytes(this.colorTab);\n var n = (3 * 256) - this.colorTab.length;\n for (var i = 0; i < n; i++)\n this.out.writeByte(0);\n};\n\nGIFEncoder.prototype.writeShort = function(pValue) {\n this.out.writeByte(pValue & 0xFF);\n this.out.writeByte((pValue >> 8) & 0xFF);\n};\n\n/*\n Encodes and writes pixel data\n*/\nGIFEncoder.prototype.writePixels = function() {\n var enc = new LZWEncoder(this.width, this.height, this.indexedPixels, this.colorDepth);\n enc.encode(this.out);\n};\n\n/*\n Retrieves the GIF stream\n*/\nGIFEncoder.prototype.stream = function() {\n return this.out;\n};\n\nmodule.exports = GIFEncoder;\n","/*\n LZWEncoder.js\n\n Authors\n Kevin Weiner (original Java version - kweiner@fmsware.com)\n Thibault Imbert (AS3 version - bytearray.org)\n Johan Nordberg (JS version - code@johan-nordberg.com)\n\n Acknowledgements\n GIFCOMPR.C - GIF Image compression routines\n Lempel-Ziv compression based on 'compress'. GIF modifications by\n David Rowley (mgardi@watdcsu.waterloo.edu)\n GIF Image compression - modified 'compress'\n Based on: compress.c - File compression ala IEEE Computer, June 1984.\n By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)\n Jim McKie (decvax!mcvax!jim)\n Steve Davies (decvax!vax135!petsd!peora!srd)\n Ken Turkowski (decvax!decwrl!turtlevax!ken)\n James A. Woods (decvax!ihnp4!ames!jaw)\n Joe Orost (decvax!vax135!petsd!joe)\n*/\n\nvar EOF = -1;\nvar BITS = 12;\nvar HSIZE = 5003; // 80% occupancy\nvar masks = [0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F,\n 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF,\n 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF];\n\nfunction LZWEncoder(width, height, pixels, colorDepth) {\n var initCodeSize = Math.max(2, colorDepth);\n\n var accum = new Uint8Array(256);\n var htab = new Int32Array(HSIZE);\n var codetab = new Int32Array(HSIZE);\n\n var cur_accum, cur_bits = 0;\n var a_count;\n var free_ent = 0; // first unused entry\n var maxcode;\n\n // block compression parameters -- after all codes are used up,\n // and compression rate changes, start over.\n var clear_flg = false;\n\n // Algorithm: use open addressing double hashing (no chaining) on the\n // prefix code / next character combination. We do a variant of Knuth's\n // algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime\n // secondary probe. Here, the modular division first probe is gives way\n // to a faster exclusive-or manipulation. Also do block compression with\n // an adaptive reset, whereby the code table is cleared when the compression\n // ratio decreases, but after the table fills. The variable-length output\n // codes are re-sized at this point, and a special CLEAR code is generated\n // for the decompressor. Late addition: construct the table according to\n // file size for noticeable speed improvement on small files. Please direct\n // questions about this implementation to ames!jaw.\n var g_init_bits, ClearCode, EOFCode;\n\n // Add a character to the end of the current packet, and if it is 254\n // characters, flush the packet to disk.\n function char_out(c, outs) {\n accum[a_count++] = c;\n if (a_count >= 254) flush_char(outs);\n }\n\n // Clear out the hash table\n // table clear for block compress\n function cl_block(outs) {\n cl_hash(HSIZE);\n free_ent = ClearCode + 2;\n clear_flg = true;\n output(ClearCode, outs);\n }\n\n // Reset code table\n function cl_hash(hsize) {\n for (var i = 0; i < hsize; ++i) htab[i] = -1;\n }\n\n function compress(init_bits, outs) {\n var fcode, c, i, ent, disp, hsize_reg, hshift;\n\n // Set up the globals: g_init_bits - initial number of bits\n g_init_bits = init_bits;\n\n // Set up the necessary values\n clear_flg = false;\n n_bits = g_init_bits;\n maxcode = MAXCODE(n_bits);\n\n ClearCode = 1 << (init_bits - 1);\n EOFCode = ClearCode + 1;\n free_ent = ClearCode + 2;\n\n a_count = 0; // clear packet\n\n ent = nextPixel();\n\n hshift = 0;\n for (fcode = HSIZE; fcode < 65536; fcode *= 2) ++hshift;\n hshift = 8 - hshift; // set hash code range bound\n hsize_reg = HSIZE;\n cl_hash(hsize_reg); // clear hash table\n\n output(ClearCode, outs);\n\n outer_loop: while ((c = nextPixel()) != EOF) {\n fcode = (c << BITS) + ent;\n i = (c << hshift) ^ ent; // xor hashing\n if (htab[i] === fcode) {\n ent = codetab[i];\n continue;\n } else if (htab[i] >= 0) { // non-empty slot\n disp = hsize_reg - i; // secondary hash (after G. Knott)\n if (i === 0) disp = 1;\n do {\n if ((i -= disp) < 0) i += hsize_reg;\n if (htab[i] === fcode) {\n ent = codetab[i];\n continue outer_loop;\n }\n } while (htab[i] >= 0);\n }\n output(ent, outs);\n ent = c;\n if (free_ent < 1 << BITS) {\n codetab[i] = free_ent++; // code -> hashtable\n htab[i] = fcode;\n } else {\n cl_block(outs);\n }\n }\n\n // Put out the final code.\n output(ent, outs);\n output(EOFCode, outs);\n }\n\n function encode(outs) {\n outs.writeByte(initCodeSize); // write \"initial code size\" byte\n remaining = width * height; // reset navigation variables\n curPixel = 0;\n compress(initCodeSize + 1, outs); // compress and write the pixel data\n outs.writeByte(0); // write block terminator\n }\n\n // Flush the packet to disk, and reset the accumulator\n function flush_char(outs) {\n if (a_count > 0) {\n outs.writeByte(a_count);\n outs.writeBytes(accum, 0, a_count);\n a_count = 0;\n }\n }\n\n function MAXCODE(n_bits) {\n return (1 << n_bits) - 1;\n }\n\n // Return the next pixel from the image\n function nextPixel() {\n if (remaining === 0) return EOF;\n --remaining;\n var pix = pixels[curPixel++];\n return pix & 0xff;\n }\n\n function output(code, outs) {\n cur_accum &= masks[cur_bits];\n\n if (cur_bits > 0) cur_accum |= (code << cur_bits);\n else cur_accum = code;\n\n cur_bits += n_bits;\n\n while (cur_bits >= 8) {\n char_out((cur_accum & 0xff), outs);\n cur_accum >>= 8;\n cur_bits -= 8;\n }\n\n // If the next entry is going to be too big for the code size,\n // then increase it, if possible.\n if (free_ent > maxcode || clear_flg) {\n if (clear_flg) {\n maxcode = MAXCODE(n_bits = g_init_bits);\n clear_flg = false;\n } else {\n ++n_bits;\n if (n_bits == BITS) maxcode = 1 << BITS;\n else maxcode = MAXCODE(n_bits);\n }\n }\n\n if (code == EOFCode) {\n // At EOF, write the rest of the buffer.\n while (cur_bits > 0) {\n char_out((cur_accum & 0xff), outs);\n cur_accum >>= 8;\n cur_bits -= 8;\n }\n flush_char(outs);\n }\n }\n\n this.encode = encode;\n}\n\nmodule.exports = LZWEncoder;\n","/* NeuQuant Neural-Net Quantization Algorithm\n * ------------------------------------------\n *\n * Copyright (c) 1994 Anthony Dekker\n *\n * NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994.\n * See \"Kohonen neural networks for optimal colour quantization\"\n * in \"Network: Computation in Neural Systems\" Vol. 5 (1994) pp 351-367.\n * for a discussion of the algorithm.\n * See also http://members.ozemail.com.au/~dekker/NEUQUANT.HTML\n *\n * Any party obtaining a copy of these files from the author, directly or\n * indirectly, is granted, free of charge, a full and unrestricted irrevocable,\n * world-wide, paid up, royalty-free, nonexclusive right and license to deal\n * in this software and documentation files (the \"Software\"), including without\n * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,\n * and/or sell copies of the Software, and to permit persons who receive\n * copies from any such party to do so, with the only requirement being\n * that this copyright notice remain intact.\n *\n * (JavaScript port 2012 by Johan Nordberg)\n */\n\nvar ncycles = 100; // number of learning cycles\nvar netsize = 256; // number of colors used\nvar maxnetpos = netsize - 1;\n\n// defs for freq and bias\nvar netbiasshift = 4; // bias for colour values\nvar intbiasshift = 16; // bias for fractions\nvar intbias = (1 << intbiasshift);\nvar gammashift = 10;\nvar gamma = (1 << gammashift);\nvar betashift = 10;\nvar beta = (intbias >> betashift); /* beta = 1/1024 */\nvar betagamma = (intbias << (gammashift - betashift));\n\n// defs for decreasing radius factor\nvar initrad = (netsize >> 3); // for 256 cols, radius starts\nvar radiusbiasshift = 6; // at 32.0 biased by 6 bits\nvar radiusbias = (1 << radiusbiasshift);\nvar initradius = (initrad * radiusbias); //and decreases by a\nvar radiusdec = 30; // factor of 1/30 each cycle\n\n// defs for decreasing alpha factor\nvar alphabiasshift = 10; // alpha starts at 1.0\nvar initalpha = (1 << alphabiasshift);\nvar alphadec; // biased by 10 bits\n\n/* radbias and alpharadbias used for radpower calculation */\nvar radbiasshift = 8;\nvar radbias = (1 << radbiasshift);\nvar alpharadbshift = (alphabiasshift + radbiasshift);\nvar alpharadbias = (1 << alpharadbshift);\n\n// four primes near 500 - assume no image has a length so large that it is\n// divisible by all four primes\nvar prime1 = 499;\nvar prime2 = 491;\nvar prime3 = 487;\nvar prime4 = 503;\nvar minpicturebytes = (3 * prime4);\n\n/*\n Constructor: NeuQuant\n\n Arguments:\n\n pixels - array of pixels in RGB format\n samplefac - sampling factor 1 to 30 where lower is better quality\n\n >\n > pixels = [r, g, b, r, g, b, r, g, b, ..]\n >\n*/\nfunction NeuQuant(pixels, samplefac) {\n var network; // int[netsize][4]\n var netindex; // for network lookup - really 256\n\n // bias and freq arrays for learning\n var bias;\n var freq;\n var radpower;\n\n /*\n Private Method: init\n\n sets up arrays\n */\n function init() {\n network = [];\n netindex = new Int32Array(256);\n bias = new Int32Array(netsize);\n freq = new Int32Array(netsize);\n radpower = new Int32Array(netsize >> 3);\n\n var i, v;\n for (i = 0; i < netsize; i++) {\n v = (i << (netbiasshift + 8)) / netsize;\n network[i] = new Float64Array([v, v, v, 0]);\n //network[i] = [v, v, v, 0]\n freq[i] = intbias / netsize;\n bias[i] = 0;\n }\n }\n\n /*\n Private Method: unbiasnet\n\n unbiases network to give byte values 0..255 and record position i to prepare for sort\n */\n function unbiasnet() {\n for (var i = 0; i < netsize; i++) {\n network[i][0] >>= netbiasshift;\n network[i][1] >>= netbiasshift;\n network[i][2] >>= netbiasshift;\n network[i][3] = i; // record color number\n }\n }\n\n /*\n Private Method: altersingle\n\n moves neuron *i* towards biased (b,g,r) by factor *alpha*\n */\n function altersingle(alpha, i, b, g, r) {\n network[i][0] -= (alpha * (network[i][0] - b)) / initalpha;\n network[i][1] -= (alpha * (network[i][1] - g)) / initalpha;\n network[i][2] -= (alpha * (network[i][2] - r)) / initalpha;\n }\n\n /*\n Private Method: alterneigh\n\n moves neurons in *radius* around index *i* towards biased (b,g,r) by factor *alpha*\n */\n function alterneigh(radius, i, b, g, r) {\n var lo = Math.abs(i - radius);\n var hi = Math.min(i + radius, netsize);\n\n var j = i + 1;\n var k = i - 1;\n var m = 1;\n\n var p, a;\n while ((j < hi) || (k > lo)) {\n a = radpower[m++];\n\n if (j < hi) {\n p = network[j++];\n p[0] -= (a * (p[0] - b)) / alpharadbias;\n p[1] -= (a * (p[1] - g)) / alpharadbias;\n p[2] -= (a * (p[2] - r)) / alpharadbias;\n }\n\n if (k > lo) {\n p = network[k--];\n p[0] -= (a * (p[0] - b)) / alpharadbias;\n p[1] -= (a * (p[1] - g)) / alpharadbias;\n p[2] -= (a * (p[2] - r)) / alpharadbias;\n }\n }\n }\n\n /*\n Private Method: contest\n\n searches for biased BGR values\n */\n function contest(b, g, r) {\n /*\n finds closest neuron (min dist) and updates freq\n finds best neuron (min dist-bias) and returns position\n for frequently chosen neurons, freq[i] is high and bias[i] is negative\n bias[i] = gamma * ((1 / netsize) - freq[i])\n */\n\n var bestd = ~(1 << 31);\n var bestbiasd = bestd;\n var bestpos = -1;\n var bestbiaspos = bestpos;\n\n var i, n, dist, biasdist, betafreq;\n for (i = 0; i < netsize; i++) {\n n = network[i];\n\n dist = Math.abs(n[0] - b) + Math.abs(n[1] - g) + Math.abs(n[2] - r);\n if (dist < bestd) {\n bestd = dist;\n bestpos = i;\n }\n\n biasdist = dist - ((bias[i]) >> (intbiasshift - netbiasshift));\n if (biasdist < bestbiasd) {\n bestbiasd = biasdist;\n bestbiaspos = i;\n }\n\n betafreq = (freq[i] >> betashift);\n freq[i] -= betafreq;\n bias[i] += (betafreq << gammashift);\n }\n\n freq[bestpos] += beta;\n bias[bestpos] -= betagamma;\n\n return bestbiaspos;\n }\n\n /*\n Private Method: inxbuild\n\n sorts network and builds netindex[0..255]\n */\n function inxbuild() {\n var i, j, p, q, smallpos, smallval, previouscol = 0, startpos = 0;\n for (i = 0; i < netsize; i++) {\n p = network[i];\n smallpos = i;\n smallval = p[1]; // index on g\n // find smallest in i..netsize-1\n for (j = i + 1; j < netsize; j++) {\n q = network[j];\n if (q[1] < smallval) { // index on g\n smallpos = j;\n smallval = q[1]; // index on g\n }\n }\n q = network[smallpos];\n // swap p (i) and q (smallpos) entries\n if (i != smallpos) {\n j = q[0]; q[0] = p[0]; p[0] = j;\n j = q[1]; q[1] = p[1]; p[1] = j;\n j = q[2]; q[2] = p[2]; p[2] = j;\n j = q[3]; q[3] = p[3]; p[3] = j;\n }\n // smallval entry is now in position i\n\n if (smallval != previouscol) {\n netindex[previouscol] = (startpos + i) >> 1;\n for (j = previouscol + 1; j < smallval; j++)\n netindex[j] = i;\n previouscol = smallval;\n startpos = i;\n }\n }\n netindex[previouscol] = (startpos + maxnetpos) >> 1;\n for (j = previouscol + 1; j < 256; j++)\n netindex[j] = maxnetpos; // really 256\n }\n\n /*\n Private Method: inxsearch\n\n searches for BGR values 0..255 and returns a color index\n */\n function inxsearch(b, g, r) {\n var a, p, dist;\n\n var bestd = 1000; // biggest possible dist is 256*3\n var best = -1;\n\n var i = netindex[g]; // index on g\n var j = i - 1; // start at netindex[g] and work outwards\n\n while ((i < netsize) || (j >= 0)) {\n if (i < netsize) {\n p = network[i];\n dist = p[1] - g; // inx key\n if (dist >= bestd) i = netsize; // stop iter\n else {\n i++;\n if (dist < 0) dist = -dist;\n a = p[0] - b; if (a < 0) a = -a;\n dist += a;\n if (dist < bestd) {\n a = p[2] - r; if (a < 0) a = -a;\n dist += a;\n if (dist < bestd) {\n bestd = dist;\n best = p[3];\n }\n }\n }\n }\n if (j >= 0) {\n p = network[j];\n dist = g - p[1]; // inx key - reverse dif\n if (dist >= bestd) j = -1; // stop iter\n else {\n j--;\n if (dist < 0) dist = -dist;\n a = p[0] - b; if (a < 0) a = -a;\n dist += a;\n if (dist < bestd) {\n a = p[2] - r; if (a < 0) a = -a;\n dist += a;\n if (dist < bestd) {\n bestd = dist;\n best = p[3];\n }\n }\n }\n }\n }\n\n return best;\n }\n\n /*\n Private Method: learn\n\n \"Main Learning Loop\"\n */\n function learn() {\n var i;\n\n var lengthcount = pixels.length;\n var alphadec = 30 + ((samplefac - 1) / 3);\n var samplepixels = lengthcount / (3 * samplefac);\n var delta = ~~(samplepixels / ncycles);\n var alpha = initalpha;\n var radius = initradius;\n\n var rad = radius >> radiusbiasshift;\n\n if (rad <= 1) rad = 0;\n for (i = 0; i < rad; i++)\n radpower[i] = alpha * (((rad * rad - i * i) * radbias) / (rad * rad));\n\n var step;\n if (lengthcount < minpicturebytes) {\n samplefac = 1;\n step = 3;\n } else if ((lengthcount % prime1) !== 0) {\n step = 3 * prime1;\n } else if ((lengthcount % prime2) !== 0) {\n step = 3 * prime2;\n } else if ((lengthcount % prime3) !== 0) {\n step = 3 * prime3;\n } else {\n step = 3 * prime4;\n }\n\n var b, g, r, j;\n var pix = 0; // current pixel\n\n i = 0;\n while (i < samplepixels) {\n b = (pixels[pix] & 0xff) << netbiasshift;\n g = (pixels[pix + 1] & 0xff) << netbiasshift;\n r = (pixels[pix + 2] & 0xff) << netbiasshift;\n\n j = contest(b, g, r);\n\n altersingle(alpha, j, b, g, r);\n if (rad !== 0) alterneigh(rad, j, b, g, r); // alter neighbours\n\n pix += step;\n if (pix >= lengthcount) pix -= lengthcount;\n\n i++;\n\n if (delta === 0) delta = 1;\n if (i % delta === 0) {\n alpha -= alpha / alphadec;\n radius -= radius / radiusdec;\n rad = radius >> radiusbiasshift;\n\n if (rad <= 1) rad = 0;\n for (j = 0; j < rad; j++)\n radpower[j] = alpha * (((rad * rad - j * j) * radbias) / (rad * rad));\n }\n }\n }\n\n /*\n Method: buildColormap\n\n 1. initializes network\n 2. trains it\n 3. removes misconceptions\n 4. builds colorindex\n */\n function buildColormap() {\n init();\n learn();\n unbiasnet();\n inxbuild();\n }\n this.buildColormap = buildColormap;\n\n /*\n Method: getColormap\n\n builds colormap from the index\n\n returns array in the format:\n\n >\n > [r, g, b, r, g, b, r, g, b, ..]\n >\n */\n function getColormap() {\n var map = [];\n var index = [];\n\n for (var i = 0; i < netsize; i++)\n index[network[i][3]] = i;\n\n var k = 0;\n for (var l = 0; l < netsize; l++) {\n var j = index[l];\n map[k++] = (network[j][0]);\n map[k++] = (network[j][1]);\n map[k++] = (network[j][2]);\n }\n return map;\n }\n this.getColormap = getColormap;\n\n /*\n Method: lookupRGB\n\n looks for the closest *r*, *g*, *b* color in the map and\n returns its index\n */\n this.lookupRGB = inxsearch;\n}\n\nmodule.exports = NeuQuant;\n"]} \ No newline at end of file diff --git a/demo/js/lib/matter-tools/matter-tools-dev.js b/demo/js/lib/matter-tools/matter-tools-dev.js deleted file mode 100644 index e6e4c8b..0000000 --- a/demo/js/lib/matter-tools/matter-tools-dev.js +++ /dev/null @@ -1,5834 +0,0 @@ -/** -* matter-tools-dev.min.js 0.5.0-dev 2016-04-26 -* https://github.com/liabru/matter-tools -* License: MIT -*/ - -(function() { - var MatterTools = {}; - var Engine = Matter.Engine, World = Matter.World, Bodies = Matter.Bodies, Body = Matter.Body, Composite = Matter.Composite, Composites = Matter.Composites, Common = Matter.Common, Constraint = Matter.Constraint, Events = Matter.Events, Bounds = Matter.Bounds, Vector = Matter.Vector, Vertices = Matter.Vertices, MouseConstraint = Matter.MouseConstraint, Render = Matter.Render, RenderPixi = Matter.RenderPixi, Mouse = Matter.Mouse, Query = Matter.Query, Grid = Matter.Grid, Detector = Matter.Detector; - var Gui = {}; - (function() { - var _isWebkit = "WebkitAppearance" in document.documentElement.style; - Gui.create = function(engine, runner, render, options) { - var _datGuiSupported = window.dat && window.localStorage; - if (!_datGuiSupported) { - console.log("Could not create GUI. Check dat.gui library is loaded first."); - return; - } - var datGui = new dat.GUI(options); - var gui = { - engine:engine, - runner:runner, - render:render, - datGui:datGui, - broadphase:"grid", - broadphaseCache:{ - grid:engine.broadphase.controller === Grid ? engine.broadphase :Grid.create(), - bruteForce:{ - detector:Detector.bruteForce - } - }, - amount:1, - size:40, - sides:4, - density:.001, - restitution:0, - friction:.1, - frictionStatic:.5, - frictionAir:.01, - offset:{ - x:0, - y:0 - }, - renderer:"canvas", - chamfer:0, - isRecording:false - }; - if (Resurrect) { - gui.serializer = new Resurrect({ - prefix:"$", - cleanup:true - }); - gui.serializer.parse = gui.serializer.resurrect; - } - _initDatGui(gui); - _initGif(gui); - return gui; - }; - Gui.update = function(gui, datGui) { - var i; - datGui = datGui || gui.datGui; - for (i in datGui.__folders) { - Gui.update(gui, datGui.__folders[i]); - } - for (i in datGui.__controllers) { - var controller = datGui.__controllers[i]; - if (controller.updateDisplay) controller.updateDisplay(); - } - }; - Gui.closeAll = function(gui) { - var datGui = gui.datGui; - for (var i in datGui.__folders) { - datGui.__folders[i].close(); - } - }; - Gui.saveState = function(serializer, engine, key) { - if (localStorage && serializer) localStorage.setItem(key, Gui.serialise(serializer, engine.world)); - }; - Gui.loadState = function(serializer, engine, key) { - var loadedWorld; - if (localStorage && serializer) loadedWorld = serializer.parse(localStorage.getItem(key)); - if (loadedWorld) Engine.merge(engine, { - world:loadedWorld - }); - }; - Gui.serialise = function(serializer, object, indent) { - indent = indent || 0; - return serializer.stringify(object, function(key, value) { - if (!/^#/.exec(key) && typeof value === "number") { - var fixed = parseFloat(value.toFixed(3)); - if (fixed === 0 && value !== 0) return value; - return fixed; - } - return value; - }, indent); - }; - Gui.clone = function(serializer, object) { - var clone = serializer.parse(Gui.serialise(serializer, object)); - clone.id = Common.nextId(); - return clone; - }; - var _initDatGui = function(gui) { - var engine = gui.engine, runner = gui.runner, datGui = gui.datGui; - var funcs = { - addBody:function() { - _addBody(gui); - }, - clear:function() { - _clear(gui); - }, - save:function() { - Gui.saveState(gui.serializer, engine, "guiState"); - Events.trigger(gui, "save"); - }, - load:function() { - Gui.loadState(gui.serializer, engine, "guiState"); - Events.trigger(gui, "load"); - }, - inspect:function() { - if (!Inspector.instance) gui.inspector = Inspector.create(gui.engine, gui.runner, gui.render); - }, - recordGif:function() { - if (!gui.isRecording) { - gui.gif = new GIF({ - workers:5, - quality:100, - width:800, - height:600 - }); - gui.gif.on("finished", function(blob) { - if (_isWebkit) { - var anchor = document.createElement("a"); - anchor.download = "matter-tools-gif.gif"; - anchor.href = (window.webkitURL || window.URL).createObjectURL(blob); - anchor.dataset.downloadurl = [ "image/gif", anchor.download, anchor.href ].join(":"); - anchor.click(); - } else { - window.open(URL.createObjectURL(blob)); - } - }); - gui.isRecording = true; - } else { - if (!gui.gif.running) { - gui.isRecording = false; - gui.gif.render(); - } - } - setTimeout(function() { - if (gui.isRecording && !gui.gif.running) { - gui.gif.render(); - } - gui.isRecording = false; - }, 5e3); - } - }; - var metrics = datGui.addFolder("Metrics"); - metrics.add(runner, "fps").listen(); - if (engine.metrics.extended) { - metrics.add(runner, "delta").listen(); - metrics.add(runner, "correction").listen(); - metrics.add(engine.metrics, "bodies").listen(); - metrics.add(engine.metrics, "collisions").listen(); - metrics.add(engine.metrics, "pairs").listen(); - metrics.add(engine.metrics, "broadEff").listen(); - metrics.add(engine.metrics, "midEff").listen(); - metrics.add(engine.metrics, "narrowEff").listen(); - metrics.add(engine.metrics, "narrowReuse").listen(); - metrics.close(); - } else { - metrics.open(); - } - var controls = datGui.addFolder("Add Body"); - controls.add(gui, "amount", 1, 5).step(1); - controls.add(gui, "size", 5, 150).step(1); - controls.add(gui, "sides", 1, 8).step(1); - controls.add(gui, "density", 1e-4, .01).step(.001); - controls.add(gui, "friction", 0, 1).step(.05); - controls.add(gui, "frictionStatic", 0, 10).step(.1); - controls.add(gui, "frictionAir", 0, gui.frictionAir * 10).step(gui.frictionAir / 10); - controls.add(gui, "restitution", 0, 1).step(.1); - controls.add(gui, "chamfer", 0, 30).step(2); - controls.add(funcs, "addBody"); - controls.open(); - var worldGui = datGui.addFolder("World"); - worldGui.add(funcs, "load"); - worldGui.add(funcs, "save"); - worldGui.add(funcs, "clear"); - worldGui.open(); - var toolsGui = datGui.addFolder("Tools"); - toolsGui.add(funcs, "inspect"); - if (window.GIF) toolsGui.add(funcs, "recordGif"); - toolsGui.open(); - var gravity = worldGui.addFolder("Gravity"); - gravity.add(engine.world.gravity, "x", -1, 1).step(.01); - gravity.add(engine.world.gravity, "y", -1, 1).step(.01); - gravity.open(); - var physics = datGui.addFolder("Engine"); - physics.add(engine, "enableSleeping"); - physics.add(engine.timing, "timeScale", 0, 1.2).step(.05).listen(); - physics.add(engine, "velocityIterations", 1, 10).step(1); - physics.add(engine, "positionIterations", 1, 10).step(1); - physics.add(runner, "enabled"); - physics.open(); - var render = datGui.addFolder("Render"); - render.add(gui.render.options, "wireframes"); - render.add(gui.render.options, "showDebug"); - render.add(gui.render.options, "showPositions"); - render.add(gui.render.options, "showBroadphase"); - render.add(gui.render.options, "showBounds"); - render.add(gui.render.options, "showVelocity"); - render.add(gui.render.options, "showCollisions"); - render.add(gui.render.options, "showSeparations"); - render.add(gui.render.options, "showAxes"); - render.add(gui.render.options, "showAngleIndicator"); - render.add(gui.render.options, "showSleeping"); - render.add(gui.render.options, "showIds"); - render.add(gui.render.options, "showVertexNumbers"); - render.add(gui.render.options, "showConvexHulls"); - render.add(gui.render.options, "showInternalEdges"); - render.add(gui.render.options, "enabled"); - render.open(); - }; - var _addBody = function(gui) { - var engine = gui.engine; - var options = { - density:gui.density, - friction:gui.friction, - frictionStatic:gui.frictionStatic, - frictionAir:gui.frictionAir, - restitution:gui.restitution - }; - if (gui.chamfer && gui.sides > 2) { - options.chamfer = { - radius:gui.chamfer - }; - } - for (var i = 0; i < gui.amount; i++) { - World.add(engine.world, Bodies.polygon(gui.offset.x + 120 + i * gui.size + i * 50, gui.offset.y + 200, gui.sides, gui.size, options)); - } - }; - var _clear = function(gui) { - var engine = gui.engine; - World.clear(engine.world, true); - Engine.clear(engine); - var renderController = gui.render.controller; - if (renderController.clear) renderController.clear(gui.render); - Events.trigger(gui, "clear"); - }; - var _initGif = function(gui) { - if (!window.GIF) { - return; - } - var engine = gui.engine, skipFrame = false; - Matter.Events.on(gui.runner, "beforeTick", function(event) { - if (gui.isRecording && !skipFrame) { - gui.gif.addFrame(gui.render.context, { - copy:true, - delay:25 - }); - } - skipFrame = !skipFrame; - }); - }; - })(); - var Inspector = {}; - (function() { - var _key, _isWebkit = "WebkitAppearance" in document.documentElement.style, $body; - Inspector.create = function(engine, runner, render, options) { - if (!jQuery || !$.fn.jstree || !window.key) { - console.log("Could not create inspector. Check keymaster, jQuery, jsTree libraries are loaded first."); - return; - } - var inspector = { - engine:null, - runner:null, - render:null, - isPaused:false, - selected:[], - selectStart:null, - selectEnd:null, - selectBounds:Bounds.create(), - mousePrevPosition:{ - x:0, - y:0 - }, - offset:{ - x:0, - y:0 - }, - autoHide:true, - autoRewind:true, - hasTransitions:_isWebkit ? true :false, - bodyClass:"", - exportIndent:0, - clipboard:[], - controls:{ - container:null, - worldTree:null - }, - root:Composite.create({ - label:"Root" - }) - }; - inspector = Common.extend(inspector, options); - Inspector.instance = inspector; - inspector.engine = engine; - inspector.runner = runner; - inspector.render = render; - inspector.mouse = Mouse.create(inspector.render.canvas); - inspector.mouseConstraint = MouseConstraint.create(engine, { - mouse:inspector.mouse - }); - inspector.serializer = new Resurrect({ - prefix:"$", - cleanup:true - }); - inspector.serializer.parse = inspector.serializer.resurrect; - localStorage.removeItem("pauseState"); - $body = $("body"); - $body.toggleClass("ins-auto-hide gui-auto-hide", inspector.autoHide); - $body.toggleClass("ins-transitions gui-transitions", inspector.hasTransitions); - Composite.add(inspector.root, engine.world); - engine.world.isModified = true; - engine.world.parent = null; - _key = window.key; - _initControls(inspector); - _initEngineEvents(inspector); - _initTree(inspector); - _initKeybinds(inspector); - return inspector; - }; - var _initControls = function(inspector) { - var engine = inspector.engine, controls = inspector.controls; - var $inspectorContainer = $('
'), $buttonGroup = $('
'), $searchBox = $(''), $importButton = $(''), $exportButton = $(''), $pauseButton = $(''), $helpButton = $(''), $addCompositeButton = $(''); - $buttonGroup.append($pauseButton, $importButton, $exportButton, $helpButton); - $inspectorContainer.prepend($buttonGroup, $searchBox, $addCompositeButton); - $body.prepend($inspectorContainer); - controls.pauseButton = $pauseButton; - controls.importButton = $importButton; - controls.exportButton = $exportButton; - controls.helpButton = $helpButton; - controls.searchBox = $searchBox; - controls.container = $inspectorContainer; - controls.addCompositeButton = $addCompositeButton; - controls.pauseButton.click(function() { - _setPaused(inspector, !inspector.isPaused); - }); - controls.exportButton.click(function() { - _exportFile(inspector); - }); - controls.importButton.click(function() { - _importFile(inspector); - }); - controls.helpButton.click(function() { - _showHelp(inspector); - }); - controls.addCompositeButton.click(function() { - _addNewComposite(inspector); - }); - var searchTimeout; - controls.searchBox.keyup(function() { - clearTimeout(searchTimeout); - searchTimeout = setTimeout(function() { - var value = controls.searchBox.val(), worldTree = controls.worldTree.data("jstree"); - worldTree.search(value); - }, 250); - }); - }; - var _showHelp = function(inspector) { - var help = "Matter Tools\n\n"; - help += "Drag nodes in the tree to move them between composites.\n"; - help += "Use browser's developer console to inspect selected objects.\n"; - help += "Note: selections only render if renderer supports it.\n\n"; - help += "[shift + space] pause or play simulation.\n"; - help += "[right click] and drag on empty space to select a region.\n"; - help += "[right click] and drag on an object to move it.\n"; - help += "[right click + shift] and drag to move whole selection.\n\n"; - help += "[ctrl-c] to copy selected world objects.\n"; - help += "[ctrl-v] to paste copied world objects to mouse position.\n"; - help += "[del] or [backspace] delete selected objects.\n\n"; - help += "[shift + s] scale-xy selected objects with mouse or arrows.\n"; - help += "[shift + s + d] scale-x selected objects with mouse or arrows.\n"; - help += "[shift + s + f] scale-y selected objects with mouse or arrows.\n"; - help += "[shift + r] rotate selected objects with mouse or arrows.\n\n"; - help += "[shift + q] set selected objects as static (can't be undone).\n"; - help += "[shift + i] import objects.\n"; - help += "[shift + o] export selected objects.\n"; - help += "[shift + h] toggle Matter.Gui.\n"; - help += "[shift + y] toggle auto-hide.\n"; - help += "[shift + r] toggle auto-rewind on play/pause.\n\n"; - help += "[shift + j] show this help message."; - alert(help); - }; - var _initKeybinds = function(inspector) { - var engine = inspector.engine, controls = inspector.controls; - _key("shift+space", function() { - _setPaused(inspector, !inspector.isPaused); - }); - _key("shift+o", function() { - _exportFile(inspector); - }); - _key("shift+i", function() { - _importFile(inspector); - }); - _key("shift+j", function() { - _showHelp(inspector); - }); - _key("shift+y", function() { - inspector.autoHide = !inspector.autoHide; - $body.toggleClass("ins-auto-hide gui-auto-hide", inspector.autoHide); - }); - _key("shift+r", function() { - inspector.autoRewind = !inspector.autoRewind; - if (!inspector.autoRewind) localStorage.removeItem("pauseState"); - }); - _key("shift+q", function() { - var worldTree = inspector.controls.worldTree.data("jstree"); - for (var i = 0; i < inspector.selected.length; i++) { - var object = inspector.selected[i].data; - if (object.type === "body" && !object.isStatic) Body.setStatic(object, true); - } - }); - _key("del", function() { - _deleteSelectedObjects(inspector); - }); - _key("backspace", function() { - _deleteSelectedObjects(inspector); - }); - _key("ctrl+c", function() { - _copySelectedObjects(inspector); - }); - _key("ctrl+v", function() { - _pasteSelectedObjects(inspector); - }); - $(document).unbind("keydown").bind("keydown", function(event) { - var doPrevent = false; - if (event.keyCode === 8) { - var d = event.srcElement || event.target; - if (d.tagName.toUpperCase() === "INPUT" && (d.type.toUpperCase() === "TEXT" || d.type.toUpperCase() === "PASSWORD" || d.type.toUpperCase() === "FILE" || d.type.toUpperCase() === "EMAIL" || d.type.toUpperCase() === "SEARCH") || d.tagName.toUpperCase() === "TEXTAREA") { - doPrevent = d.readOnly || d.disabled; - } else { - doPrevent = true; - } - } - if (doPrevent) { - event.preventDefault(); - } - }); - }; - var _initTree = function(inspector) { - var engine = inspector.engine, controls = inspector.controls, deferTimeout; - var worldTreeOptions = { - core:{ - check_callback:true - }, - dnd:{ - copy:false - }, - search:{ - show_only_matches:true, - fuzzy:false - }, - types:{ - "#":{ - valid_children:[] - }, - body:{ - valid_children:[] - }, - constraint:{ - valid_children:[] - }, - composite:{ - valid_children:[] - }, - bodies:{ - valid_children:[ "body" ] - }, - constraints:{ - valid_children:[ "constraint" ] - }, - composites:{ - valid_children:[ "composite" ] - } - }, - plugins:[ "dnd", "types", "unique", "search" ] - }; - controls.worldTree = $('
').jstree(worldTreeOptions); - controls.container.prepend(controls.worldTree); - controls.worldTree.on("changed.jstree", function(event, data) { - var selected = [], worldTree = controls.worldTree.data("jstree"); - if (data.action !== "select_node") return; - clearTimeout(deferTimeout); - deferTimeout = setTimeout(function() { - data.selected = worldTree.get_selected(); - for (var i = 0; i < data.selected.length; i++) { - var nodeId = data.selected[i], objectType = nodeId.split("_")[0], objectId = nodeId.split("_")[1], worldObject = Composite.get(engine.world, objectId, objectType); - switch (objectType) { - case "body": - case "constraint": - case "composite": - selected.push(worldObject); - break; - } - } - _setSelectedObjects(inspector, selected); - }, 1); - }); - $(document).on("dnd_stop.vakata", function(event, data) { - var worldTree = controls.worldTree.data("jstree"), nodes = data.data.nodes; - for (var i = 0; i < nodes.length; i++) { - var node = worldTree.get_node(nodes[i]), parentNode = worldTree.get_node(worldTree.get_parent(nodes[i])), prevCompositeId = node.data.compositeId, newCompositeId = parentNode.data.compositeId; - if (prevCompositeId === newCompositeId) continue; - var nodeId = nodes[i], objectType = nodeId.split("_")[0], objectId = nodeId.split("_")[1], worldObject = Composite.get(inspector.root, objectId, objectType), prevComposite = Composite.get(inspector.root, prevCompositeId, "composite"), newComposite = Composite.get(inspector.root, newCompositeId, "composite"); - Composite.move(prevComposite, worldObject, newComposite); - } - }); - controls.worldTree.on("dblclick.jstree", function(event, data) { - var worldTree = controls.worldTree.data("jstree"), selected = worldTree.get_selected(); - for (var i = 0; i < selected.length; i++) { - var nodeId = selected[i], objectType = nodeId.split("_")[0], objectId = nodeId.split("_")[1], worldObject = Composite.get(engine.world, objectId, objectType); - switch (objectType) { - case "composite": - case "composites": - case "bodies": - case "constraints": - var node = worldTree.get_node(nodeId), children = worldTree.get_node(nodeId).children; - for (var j = 0; j < children.length; j++) worldTree.select_node(children[j], false); - break; - } - } - }); - }; - var _addBodyClass = function(inspector, classNames) { - if (inspector.bodyClass.indexOf(" " + classNames) === -1) { - $body.addClass(classNames); - inspector.bodyClass = " " + $body.attr("class"); - } - }; - var _removeBodyClass = function(inspector, classNames) { - var updateRequired = false, classes = classNames.split(" "); - for (var i = 0; i < classes.length; i++) { - updateRequired = inspector.bodyClass.indexOf(" " + classes[i]) !== -1; - if (updateRequired) break; - } - if (updateRequired) { - $body.removeClass(classNames); - inspector.bodyClass = " " + $body.attr("class"); - } - }; - var _getMousePosition = function(inspector) { - return Vector.add(inspector.mouse.position, inspector.offset); - }; - var _initEngineEvents = function(inspector) { - var engine = inspector.engine, mouse = inspector.mouse, mousePosition = _getMousePosition(inspector), controls = inspector.controls; - Events.on(inspector.engine, "beforeUpdate", function() { - mousePosition = _getMousePosition(inspector); - var mouseDelta = mousePosition.x - inspector.mousePrevPosition.x, keyDelta = _key.isPressed("up") + _key.isPressed("right") - _key.isPressed("down") - _key.isPressed("left"), delta = mouseDelta + keyDelta; - if (engine.world.isModified) { - var data = _generateCompositeTreeNode(inspector.root, null, true); - _updateTree(controls.worldTree.data("jstree"), data); - _setSelectedObjects(inspector, []); - } - if (inspector.selectStart !== null) { - inspector.selectEnd.x = mousePosition.x; - inspector.selectEnd.y = mousePosition.y; - Bounds.update(inspector.selectBounds, [ inspector.selectStart, inspector.selectEnd ]); - } - if (_key.shift && _key.isPressed("r")) { - var rotateSpeed = .03, angle = Math.max(-2, Math.min(2, delta)) * rotateSpeed; - _addBodyClass(inspector, "ins-cursor-rotate"); - _rotateSelectedObjects(inspector, angle); - } else { - _removeBodyClass(inspector, "ins-cursor-rotate"); - } - if (_key.shift && _key.isPressed("s")) { - var scaleSpeed = .02, scale = 1 + Math.max(-2, Math.min(2, delta)) * scaleSpeed; - _addBodyClass(inspector, "ins-cursor-scale"); - if (_key.isPressed("d")) { - scaleX = scale; - scaleY = 1; - } else if (_key.isPressed("f")) { - scaleX = 1; - scaleY = scale; - } else { - scaleX = scaleY = scale; - } - _scaleSelectedObjects(inspector, scaleX, scaleY); - } else { - _removeBodyClass(inspector, "ins-cursor-scale"); - } - if (mouse.button === 2) { - _addBodyClass(inspector, "ins-cursor-move"); - _moveSelectedObjects(inspector, mousePosition.x, mousePosition.y); - } else { - _removeBodyClass(inspector, "ins-cursor-move"); - } - inspector.mousePrevPosition = Common.clone(mousePosition); - }); - Events.on(inspector.mouseConstraint, "mouseup", function(event) { - if (inspector.selectStart !== null) { - var selected = Query.region(Composite.allBodies(engine.world), inspector.selectBounds); - _setSelectedObjects(inspector, selected); - } - inspector.selectStart = null; - inspector.selectEnd = null; - Events.trigger(inspector, "selectEnd"); - }); - Events.on(inspector.mouseConstraint, "mousedown", function(event) { - var bodies = Composite.allBodies(engine.world), constraints = Composite.allConstraints(engine.world), isUnionSelect = _key.shift || _key.control, worldTree = inspector.controls.worldTree.data("jstree"), i; - if (mouse.button === 2) { - var hasSelected = false; - for (i = 0; i < bodies.length; i++) { - var body = bodies[i]; - if (Bounds.contains(body.bounds, mousePosition) && Vertices.contains(body.vertices, mousePosition)) { - if (isUnionSelect) { - _addSelectedObject(inspector, body); - } else { - _setSelectedObjects(inspector, [ body ]); - } - hasSelected = true; - break; - } - } - if (!hasSelected) { - for (i = 0; i < constraints.length; i++) { - var constraint = constraints[i], bodyA = constraint.bodyA, bodyB = constraint.bodyB; - if (constraint.label.indexOf("Mouse Constraint") !== -1) continue; - var pointAWorld = constraint.pointA, pointBWorld = constraint.pointB; - if (bodyA) pointAWorld = Vector.add(bodyA.position, constraint.pointA); - if (bodyB) pointBWorld = Vector.add(bodyB.position, constraint.pointB); - if (!pointAWorld || !pointBWorld) continue; - var distA = Vector.magnitudeSquared(Vector.sub(mousePosition, pointAWorld)), distB = Vector.magnitudeSquared(Vector.sub(mousePosition, pointBWorld)); - if (distA < 100 || distB < 100) { - if (isUnionSelect) { - _addSelectedObject(inspector, constraint); - } else { - _setSelectedObjects(inspector, [ constraint ]); - } - hasSelected = true; - break; - } - } - if (!hasSelected) { - worldTree.deselect_all(true); - _setSelectedObjects(inspector, []); - inspector.selectStart = Common.clone(mousePosition); - inspector.selectEnd = Common.clone(mousePosition); - Bounds.update(inspector.selectBounds, [ inspector.selectStart, inspector.selectEnd ]); - Events.trigger(inspector, "selectStart"); - } else { - inspector.selectStart = null; - inspector.selectEnd = null; - } - } - } - if (mouse.button === 2 && inspector.selected.length > 0) { - _addBodyClass(inspector, "ins-cursor-move"); - _updateSelectedMouseDownOffset(inspector); - } - }); - Events.on(inspector.render, "afterRender", function() { - var renderController = inspector.render.controller, context = inspector.render.context; - if (renderController.inspector) renderController.inspector(inspector, context); - }); - }; - var _deleteSelectedObjects = function(inspector) { - var objects = [], object, worldTree = inspector.controls.worldTree.data("jstree"), i; - for (i = 0; i < inspector.selected.length; i++) { - object = inspector.selected[i].data; - if (object !== inspector.engine.world) objects.push(object); - } - var selectedNodes = worldTree.get_selected(); - for (i = 0; i < selectedNodes.length; i++) { - var node = worldTree.get_node(selectedNodes[i]); - if (node.type === "composite") { - node = worldTree.get_node(node.children[0]); - if (node.data) { - var compositeId = node.data.compositeId; - object = Composite.get(inspector.root, compositeId, "composite"); - if (object && object !== inspector.engine.world) { - objects.push(object); - worldTree.delete_node(selectedNodes[i]); - } - } - } - } - Composite.remove(inspector.root, objects, true); - _setSelectedObjects(inspector, []); - }; - var _copySelectedObjects = function(inspector) { - inspector.clipboard.length = 0; - for (var i = 0; i < inspector.selected.length; i++) { - var object = inspector.selected[i].data; - if (object.type !== "body") continue; - inspector.clipboard.push(object); - } - }; - var _pasteSelectedObjects = function(inspector) { - var objects = [], worldTree = inspector.controls.worldTree.data("jstree"); - for (var i = 0; i < inspector.clipboard.length; i++) { - var object = inspector.clipboard[i], clone = Gui.clone(inspector.serializer, object); - Body.translate(clone, { - x:50, - y:50 - }); - var node = worldTree.get_node(object.type + "_" + object.id, false), compositeId = node.data.compositeId, composite = Composite.get(inspector.engine.world, compositeId, "composite"); - Composite.add(composite, clone); - objects.push(clone); - } - setTimeout(function() { - _setSelectedObjects(inspector, objects); - }, 200); - }; - var _updateSelectedMouseDownOffset = function(inspector) { - var selected = inspector.selected, mouse = inspector.mouse, mousePosition = _getMousePosition(inspector), item, data; - for (var i = 0; i < selected.length; i++) { - item = selected[i]; - data = item.data; - if (data.position) { - item.mousedownOffset = { - x:mousePosition.x - data.position.x, - y:mousePosition.y - data.position.y - }; - } else if (data.pointA && !data.bodyA) { - item.mousedownOffset = { - x:mousePosition.x - data.pointA.x, - y:mousePosition.y - data.pointA.y - }; - } else if (data.pointB && !data.bodyB) { - item.mousedownOffset = { - x:mousePosition.x - data.pointB.x, - y:mousePosition.y - data.pointB.y - }; - } - } - }; - var _moveSelectedObjects = function(inspector, x, y) { - var selected = inspector.selected, mouse = inspector.mouse, mousePosition = _getMousePosition(inspector), item, data; - for (var i = 0; i < selected.length; i++) { - item = selected[i]; - data = item.data; - if (!item.mousedownOffset) continue; - switch (data.type) { - case "body": - var delta = { - x:x - data.position.x - item.mousedownOffset.x, - y:y - data.position.y - item.mousedownOffset.y - }; - Body.translate(data, delta); - data.positionPrev.x = data.position.x; - data.positionPrev.y = data.position.y; - break; - - case "constraint": - var point = data.pointA; - if (data.bodyA) point = data.pointB; - point.x = x - item.mousedownOffset.x; - point.y = y - item.mousedownOffset.y; - var initialPointA = data.bodyA ? Vector.add(data.bodyA.position, data.pointA) :data.pointA, initialPointB = data.bodyB ? Vector.add(data.bodyB.position, data.pointB) :data.pointB; - data.length = Vector.magnitude(Vector.sub(initialPointA, initialPointB)); - break; - } - } - }; - var _scaleSelectedObjects = function(inspector, scaleX, scaleY) { - var selected = inspector.selected, item, data; - for (var i = 0; i < selected.length; i++) { - item = selected[i]; - data = item.data; - switch (data.type) { - case "body": - Body.scale(data, scaleX, scaleY, data.position); - if (data.circleRadius) data.circleRadius *= scaleX; - break; - } - } - }; - var _rotateSelectedObjects = function(inspector, angle) { - var selected = inspector.selected, item, data; - for (var i = 0; i < selected.length; i++) { - item = selected[i]; - data = item.data; - switch (data.type) { - case "body": - Body.rotate(data, angle); - break; - } - } - }; - var _setPaused = function(inspector, isPaused) { - if (isPaused) { - if (inspector.autoRewind) { - _setSelectedObjects(inspector, []); - Gui.loadState(inspector.serializer, inspector.engine, "pauseState"); - } - inspector.engine.timing.timeScale = 0; - inspector.isPaused = true; - inspector.controls.pauseButton.text("Play"); - Events.trigger(inspector, "paused"); - } else { - if (inspector.autoRewind) { - Gui.saveState(inspector.serializer, inspector.engine, "pauseState"); - } - inspector.engine.timing.timeScale = 1; - inspector.isPaused = false; - inspector.controls.pauseButton.text("Pause"); - Events.trigger(inspector, "play"); - } - }; - var _setSelectedObjects = function(inspector, objects) { - var worldTree = inspector.controls.worldTree.data("jstree"), selectedItems = [], data, i; - for (i = 0; i < inspector.selected.length; i++) { - data = inspector.selected[i].data; - worldTree.deselect_node(data.type + "_" + data.id, true); - } - inspector.selected = []; - console.clear(); - for (i = 0; i < objects.length; i++) { - data = objects[i]; - if (data) { - _addSelectedObject(inspector, data); - if (i < 5) { - console.log(data.label + " " + data.id + ": %O", data); - } else if (i === 6) { - console.warn("Omitted inspecting " + (objects.length - 5) + " more objects"); - } - } - } - }; - var _addSelectedObject = function(inspector, object) { - if (!object) return; - var worldTree = inspector.controls.worldTree.data("jstree"); - inspector.selected.push({ - data:object - }); - worldTree.select_node(object.type + "_" + object.id, true); - }; - var _updateTree = function(tree, data) { - data[0].state = data[0].state || { - opened:true - }; - tree.settings.core.data = data; - tree.refresh(-1); - }; - var _generateCompositeTreeNode = function(composite, compositeId, isRoot) { - var children = [], node = { - id:"composite_" + composite.id, - data:{ - compositeId:compositeId - }, - type:"composite", - text:(composite.label ? composite.label :"Composite") + " " + composite.id, - li_attr:{ - "class":"jstree-node-type-composite" - } - }; - var childNode = _generateCompositesTreeNode(composite.composites, composite.id); - childNode.id = "composites_" + composite.id; - children.push(childNode); - if (isRoot) return childNode.children; - childNode = _generateBodiesTreeNode(composite.bodies, composite.id); - childNode.id = "bodies_" + composite.id; - children.push(childNode); - childNode = _generateConstraintsTreeNode(composite.constraints, composite.id); - childNode.id = "constraints_" + composite.id; - children.push(childNode); - node.children = children; - return node; - }; - var _generateCompositesTreeNode = function(composites, compositeId) { - var node = { - type:"composites", - text:"Composites", - data:{ - compositeId:compositeId - }, - children:[], - li_attr:{ - "class":"jstree-node-type-composites" - } - }; - for (var i = 0; i < composites.length; i++) { - var composite = composites[i]; - node.children.push(_generateCompositeTreeNode(composite, compositeId)); - } - return node; - }; - var _generateBodiesTreeNode = function(bodies, compositeId) { - var node = { - type:"bodies", - text:"Bodies", - data:{ - compositeId:compositeId - }, - children:[], - li_attr:{ - "class":"jstree-node-type-bodies" - } - }; - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i]; - node.children.push({ - type:"body", - id:"body_" + body.id, - data:{ - compositeId:compositeId - }, - text:(body.label ? body.label :"Body") + " " + body.id, - li_attr:{ - "class":"jstree-node-type-body" - } - }); - } - return node; - }; - var _generateConstraintsTreeNode = function(constraints, compositeId) { - var node = { - type:"constraints", - text:"Constraints", - data:{ - compositeId:compositeId - }, - children:[], - li_attr:{ - "class":"jstree-node-type-constraints" - } - }; - for (var i = 0; i < constraints.length; i++) { - var constraint = constraints[i]; - node.children.push({ - type:"constraint", - id:"constraint_" + constraint.id, - data:{ - compositeId:compositeId - }, - text:(constraint.label ? constraint.label :"Constraint") + " " + constraint.id, - li_attr:{ - "class":"jstree-node-type-constraint" - } - }); - } - return node; - }; - var _addNewComposite = function(inspector) { - var newComposite = Composite.create(); - Composite.add(inspector.root, newComposite); - inspector.root.composites.splice(inspector.root.composites.length - 1, 1); - inspector.root.composites.unshift(newComposite); - Composite.setModified(inspector.engine.world, true, true, false); - }; - var _exportFile = function(inspector) { - var engine = inspector.engine, toExport = []; - if (inspector.selected.length === 0) { - alert("No objects were selected, so export could not be created. Can only export objects that are in the World composite."); - return; - } - var fileName = "export-objects", exportComposite = Composite.create({ - label:"Exported Objects" - }); - for (var i = 0; i < inspector.selected.length; i++) { - var object = inspector.selected[i].data; - if (Composite.get(exportComposite, object.id, object.type)) continue; - Composite.add(exportComposite, object); - if (inspector.selected.length === 1) fileName = "export-" + object.label + "-" + object.id; - } - fileName = fileName.toLowerCase().replace(/[^\w\-]/g, "") + ".json"; - var json = Gui.serialise(inspector.serializer, exportComposite, inspector.exportIndent); - if (_isWebkit) { - var blob = new Blob([ json ], { - type:"application/json" - }), anchor = document.createElement("a"); - anchor.download = fileName; - anchor.href = (window.webkitURL || window.URL).createObjectURL(blob); - anchor.dataset.downloadurl = [ "application/json", anchor.download, anchor.href ].join(":"); - anchor.click(); - } else { - window.open("data:application/json;charset=utf-8," + escape(json)); - } - Events.trigger(inspector, "export"); - }; - var _importFile = function(inspector) { - var engine = inspector.engine, element = document.createElement("div"), fileInput; - element.innerHTML = ''; - fileInput = element.firstChild; - fileInput.addEventListener("change", function(e) { - var file = fileInput.files[0]; - if (file.name.match(/\.(txt|json)$/)) { - var reader = new FileReader(); - reader.onload = function(e) { - var importedComposite = inspector.serializer.parse(reader.result); - if (importedComposite) { - importedComposite.label = "Imported Objects"; - Composite.rebase(importedComposite); - Composite.add(inspector.root, importedComposite); - inspector.root.composites.splice(inspector.root.composites.length - 1, 1); - inspector.root.composites.unshift(importedComposite); - var worldTree = inspector.controls.worldTree.data("jstree"), data = _generateCompositeTreeNode(inspector.root, null, true); - _updateTree(worldTree, data); - } - }; - reader.readAsText(file); - } else { - alert("File not supported, .json or .txt JSON files only"); - } - }); - fileInput.click(); - }; - })(); - MatterTools.Gui = Gui; - MatterTools.Inspector = Inspector; - if (typeof exports !== "undefined") { - if (typeof module !== "undefined" && module.exports) { - exports = module.exports = MatterTools; - } - exports.MatterTools = MatterTools; - } - if (typeof define === "function" && define.amd) { - define("MatterTools", [], function() { - return MatterTools; - }); - } - if (typeof window === "object" && typeof window.document === "object") { - window.MatterTools = MatterTools; - } -})(); - -var dat = dat || {}; - -dat.gui = dat.gui || {}; - -dat.utils = dat.utils || {}; - -dat.controllers = dat.controllers || {}; - -dat.dom = dat.dom || {}; - -dat.color = dat.color || {}; - -dat.utils.css = function() { - return { - load:function(url, doc) { - doc = doc || document; - var link = doc.createElement("link"); - link.type = "text/css"; - link.rel = "stylesheet"; - link.href = url; - doc.getElementsByTagName("head")[0].appendChild(link); - }, - inject:function(css, doc) { - doc = doc || document; - var injected = document.createElement("style"); - injected.type = "text/css"; - injected.innerHTML = css; - doc.getElementsByTagName("head")[0].appendChild(injected); - } - }; -}(); - -dat.utils.common = function() { - var ARR_EACH = Array.prototype.forEach; - var ARR_SLICE = Array.prototype.slice; - return { - BREAK:{}, - extend:function(target) { - this.each(ARR_SLICE.call(arguments, 1), function(obj) { - for (var key in obj) if (!this.isUndefined(obj[key])) target[key] = obj[key]; - }, this); - return target; - }, - defaults:function(target) { - this.each(ARR_SLICE.call(arguments, 1), function(obj) { - for (var key in obj) if (this.isUndefined(target[key])) target[key] = obj[key]; - }, this); - return target; - }, - compose:function() { - var toCall = ARR_SLICE.call(arguments); - return function() { - var args = ARR_SLICE.call(arguments); - for (var i = toCall.length - 1; i >= 0; i--) { - args = [ toCall[i].apply(this, args) ]; - } - return args[0]; - }; - }, - each:function(obj, itr, scope) { - if (!obj) return; - if (ARR_EACH && obj.forEach && obj.forEach === ARR_EACH) { - obj.forEach(itr, scope); - } else if (obj.length === obj.length + 0) { - for (var key = 0, l = obj.length; key < l; key++) if (key in obj && itr.call(scope, obj[key], key) === this.BREAK) return; - } else { - for (var key in obj) if (itr.call(scope, obj[key], key) === this.BREAK) return; - } - }, - defer:function(fnc) { - setTimeout(fnc, 0); - }, - toArray:function(obj) { - if (obj.toArray) return obj.toArray(); - return ARR_SLICE.call(obj); - }, - isUndefined:function(obj) { - return obj === undefined; - }, - isNull:function(obj) { - return obj === null; - }, - isNaN:function(obj) { - return obj !== obj; - }, - isArray:Array.isArray || function(obj) { - return obj.constructor === Array; - }, - isObject:function(obj) { - return obj === Object(obj); - }, - isNumber:function(obj) { - return obj === obj + 0; - }, - isString:function(obj) { - return obj === obj + ""; - }, - isBoolean:function(obj) { - return obj === false || obj === true; - }, - isFunction:function(obj) { - return Object.prototype.toString.call(obj) === "[object Function]"; - } - }; -}(); - -dat.controllers.Controller = function(common) { - var Controller = function(object, property) { - this.initialValue = object[property]; - this.domElement = document.createElement("div"); - this.object = object; - this.property = property; - this.__onChange = undefined; - this.__onFinishChange = undefined; - }; - common.extend(Controller.prototype, { - onChange:function(fnc) { - this.__onChange = fnc; - return this; - }, - onFinishChange:function(fnc) { - this.__onFinishChange = fnc; - return this; - }, - setValue:function(newValue) { - this.object[this.property] = newValue; - if (this.__onChange) { - this.__onChange.call(this, newValue); - } - this.updateDisplay(); - return this; - }, - getValue:function() { - return this.object[this.property]; - }, - updateDisplay:function() { - return this; - }, - isModified:function() { - return this.initialValue !== this.getValue(); - } - }); - return Controller; -}(dat.utils.common); - -dat.dom.dom = function(common) { - var EVENT_MAP = { - HTMLEvents:[ "change" ], - MouseEvents:[ "click", "mousemove", "mousedown", "mouseup", "mouseover" ], - KeyboardEvents:[ "keydown" ] - }; - var EVENT_MAP_INV = {}; - common.each(EVENT_MAP, function(v, k) { - common.each(v, function(e) { - EVENT_MAP_INV[e] = k; - }); - }); - var CSS_VALUE_PIXELS = /(\d+(\.\d+)?)px/; - function cssValueToPixels(val) { - if (val === "0" || common.isUndefined(val)) return 0; - var match = val.match(CSS_VALUE_PIXELS); - if (!common.isNull(match)) { - return parseFloat(match[1]); - } - return 0; - } - var dom = { - makeSelectable:function(elem, selectable) { - if (elem === undefined || elem.style === undefined) return; - elem.onselectstart = selectable ? function() { - return false; - } :function() {}; - elem.style.MozUserSelect = selectable ? "auto" :"none"; - elem.style.KhtmlUserSelect = selectable ? "auto" :"none"; - elem.unselectable = selectable ? "on" :"off"; - }, - makeFullscreen:function(elem, horizontal, vertical) { - if (common.isUndefined(horizontal)) horizontal = true; - if (common.isUndefined(vertical)) vertical = true; - elem.style.position = "absolute"; - if (horizontal) { - elem.style.left = 0; - elem.style.right = 0; - } - if (vertical) { - elem.style.top = 0; - elem.style.bottom = 0; - } - }, - fakeEvent:function(elem, eventType, params, aux) { - params = params || {}; - var className = EVENT_MAP_INV[eventType]; - if (!className) { - throw new Error("Event type " + eventType + " not supported."); - } - var evt = document.createEvent(className); - switch (className) { - case "MouseEvents": - var clientX = params.x || params.clientX || 0; - var clientY = params.y || params.clientY || 0; - evt.initMouseEvent(eventType, params.bubbles || false, params.cancelable || true, window, params.clickCount || 1, 0, 0, clientX, clientY, false, false, false, false, 0, null); - break; - - case "KeyboardEvents": - var init = evt.initKeyboardEvent || evt.initKeyEvent; - common.defaults(params, { - cancelable:true, - ctrlKey:false, - altKey:false, - shiftKey:false, - metaKey:false, - keyCode:undefined, - charCode:undefined - }); - init(eventType, params.bubbles || false, params.cancelable, window, params.ctrlKey, params.altKey, params.shiftKey, params.metaKey, params.keyCode, params.charCode); - break; - - default: - evt.initEvent(eventType, params.bubbles || false, params.cancelable || true); - break; - } - common.defaults(evt, aux); - elem.dispatchEvent(evt); - }, - bind:function(elem, event, func, bool) { - bool = bool || false; - if (elem.addEventListener) elem.addEventListener(event, func, bool); else if (elem.attachEvent) elem.attachEvent("on" + event, func); - return dom; - }, - unbind:function(elem, event, func, bool) { - bool = bool || false; - if (elem.removeEventListener) elem.removeEventListener(event, func, bool); else if (elem.detachEvent) elem.detachEvent("on" + event, func); - return dom; - }, - addClass:function(elem, className) { - if (elem.className === undefined) { - elem.className = className; - } else if (elem.className !== className) { - var classes = elem.className.split(/ +/); - if (classes.indexOf(className) == -1) { - classes.push(className); - elem.className = classes.join(" ").replace(/^\s+/, "").replace(/\s+$/, ""); - } - } - return dom; - }, - removeClass:function(elem, className) { - if (className) { - if (elem.className === undefined) {} else if (elem.className === className) { - elem.removeAttribute("class"); - } else { - var classes = elem.className.split(/ +/); - var index = classes.indexOf(className); - if (index != -1) { - classes.splice(index, 1); - elem.className = classes.join(" "); - } - } - } else { - elem.className = undefined; - } - return dom; - }, - hasClass:function(elem, className) { - return new RegExp("(?:^|\\s+)" + className + "(?:\\s+|$)").test(elem.className) || false; - }, - getWidth:function(elem) { - var style = getComputedStyle(elem); - return cssValueToPixels(style["border-left-width"]) + cssValueToPixels(style["border-right-width"]) + cssValueToPixels(style["padding-left"]) + cssValueToPixels(style["padding-right"]) + cssValueToPixels(style["width"]); - }, - getHeight:function(elem) { - var style = getComputedStyle(elem); - return cssValueToPixels(style["border-top-width"]) + cssValueToPixels(style["border-bottom-width"]) + cssValueToPixels(style["padding-top"]) + cssValueToPixels(style["padding-bottom"]) + cssValueToPixels(style["height"]); - }, - getOffset:function(elem) { - var offset = { - left:0, - top:0 - }; - if (elem.offsetParent) { - do { - offset.left += elem.offsetLeft; - offset.top += elem.offsetTop; - } while (elem = elem.offsetParent); - } - return offset; - }, - isActive:function(elem) { - return elem === document.activeElement && (elem.type || elem.href); - } - }; - return dom; -}(dat.utils.common); - -dat.controllers.OptionController = function(Controller, dom, common) { - var OptionController = function(object, property, options) { - OptionController.superclass.call(this, object, property); - var _this = this; - this.__select = document.createElement("select"); - if (common.isArray(options)) { - var map = {}; - common.each(options, function(element) { - map[element] = element; - }); - options = map; - } - common.each(options, function(value, key) { - var opt = document.createElement("option"); - opt.innerHTML = key; - opt.setAttribute("value", value); - _this.__select.appendChild(opt); - }); - this.updateDisplay(); - dom.bind(this.__select, "change", function() { - var desiredValue = this.options[this.selectedIndex].value; - _this.setValue(desiredValue); - }); - this.domElement.appendChild(this.__select); - }; - OptionController.superclass = Controller; - common.extend(OptionController.prototype, Controller.prototype, { - setValue:function(v) { - var toReturn = OptionController.superclass.prototype.setValue.call(this, v); - if (this.__onFinishChange) { - this.__onFinishChange.call(this, this.getValue()); - } - return toReturn; - }, - updateDisplay:function() { - this.__select.value = this.getValue(); - return OptionController.superclass.prototype.updateDisplay.call(this); - } - }); - return OptionController; -}(dat.controllers.Controller, dat.dom.dom, dat.utils.common); - -dat.controllers.NumberController = function(Controller, common) { - var NumberController = function(object, property, params) { - NumberController.superclass.call(this, object, property); - params = params || {}; - this.__min = params.min; - this.__max = params.max; - this.__step = params.step; - if (common.isUndefined(this.__step)) { - if (this.initialValue == 0) { - this.__impliedStep = 1; - } else { - this.__impliedStep = Math.pow(10, Math.floor(Math.log(this.initialValue) / Math.LN10)) / 10; - } - } else { - this.__impliedStep = this.__step; - } - this.__precision = numDecimals(this.__impliedStep); - }; - NumberController.superclass = Controller; - common.extend(NumberController.prototype, Controller.prototype, { - setValue:function(v) { - if (this.__min !== undefined && v < this.__min) { - v = this.__min; - } else if (this.__max !== undefined && v > this.__max) { - v = this.__max; - } - if (this.__step !== undefined && v % this.__step != 0) { - v = Math.round(v / this.__step) * this.__step; - } - return NumberController.superclass.prototype.setValue.call(this, v); - }, - min:function(v) { - this.__min = v; - return this; - }, - max:function(v) { - this.__max = v; - return this; - }, - step:function(v) { - this.__step = v; - this.__impliedStep = v; - this.__precision = numDecimals(v); - return this; - } - }); - function numDecimals(x) { - x = x.toString(); - if (x.indexOf(".") > -1) { - return x.length - x.indexOf(".") - 1; - } else { - return 0; - } - } - return NumberController; -}(dat.controllers.Controller, dat.utils.common); - -dat.controllers.NumberControllerBox = function(NumberController, dom, common) { - var NumberControllerBox = function(object, property, params) { - this.__truncationSuspended = false; - NumberControllerBox.superclass.call(this, object, property, params); - var _this = this; - var prev_y; - this.__input = document.createElement("input"); - this.__input.setAttribute("type", "text"); - dom.bind(this.__input, "change", onChange); - dom.bind(this.__input, "blur", onBlur); - dom.bind(this.__input, "mousedown", onMouseDown); - dom.bind(this.__input, "keydown", function(e) { - if (e.keyCode === 13) { - _this.__truncationSuspended = true; - this.blur(); - _this.__truncationSuspended = false; - } - }); - function onChange() { - var attempted = parseFloat(_this.__input.value); - if (!common.isNaN(attempted)) _this.setValue(attempted); - } - function onBlur() { - onChange(); - if (_this.__onFinishChange) { - _this.__onFinishChange.call(_this, _this.getValue()); - } - } - function onMouseDown(e) { - dom.bind(window, "mousemove", onMouseDrag); - dom.bind(window, "mouseup", onMouseUp); - prev_y = e.clientY; - } - function onMouseDrag(e) { - var diff = prev_y - e.clientY; - _this.setValue(_this.getValue() + diff * _this.__impliedStep); - prev_y = e.clientY; - } - function onMouseUp() { - dom.unbind(window, "mousemove", onMouseDrag); - dom.unbind(window, "mouseup", onMouseUp); - } - this.updateDisplay(); - this.domElement.appendChild(this.__input); - }; - NumberControllerBox.superclass = NumberController; - common.extend(NumberControllerBox.prototype, NumberController.prototype, { - updateDisplay:function() { - this.__input.value = this.__truncationSuspended ? this.getValue() :roundToDecimal(this.getValue(), this.__precision); - return NumberControllerBox.superclass.prototype.updateDisplay.call(this); - } - }); - function roundToDecimal(value, decimals) { - var tenTo = Math.pow(10, decimals); - return Math.round(value * tenTo) / tenTo; - } - return NumberControllerBox; -}(dat.controllers.NumberController, dat.dom.dom, dat.utils.common); - -dat.controllers.NumberControllerSlider = function(NumberController, dom, css, common, styleSheet) { - var NumberControllerSlider = function(object, property, min, max, step) { - NumberControllerSlider.superclass.call(this, object, property, { - min:min, - max:max, - step:step - }); - var _this = this; - this.__background = document.createElement("div"); - this.__foreground = document.createElement("div"); - dom.bind(this.__background, "mousedown", onMouseDown); - dom.addClass(this.__background, "slider"); - dom.addClass(this.__foreground, "slider-fg"); - function onMouseDown(e) { - dom.bind(window, "mousemove", onMouseDrag); - dom.bind(window, "mouseup", onMouseUp); - onMouseDrag(e); - } - function onMouseDrag(e) { - e.preventDefault(); - var offset = dom.getOffset(_this.__background); - var width = dom.getWidth(_this.__background); - _this.setValue(map(e.clientX, offset.left, offset.left + width, _this.__min, _this.__max)); - return false; - } - function onMouseUp() { - dom.unbind(window, "mousemove", onMouseDrag); - dom.unbind(window, "mouseup", onMouseUp); - if (_this.__onFinishChange) { - _this.__onFinishChange.call(_this, _this.getValue()); - } - } - this.updateDisplay(); - this.__background.appendChild(this.__foreground); - this.domElement.appendChild(this.__background); - }; - NumberControllerSlider.superclass = NumberController; - NumberControllerSlider.useDefaultStyles = function() { - css.inject(styleSheet); - }; - common.extend(NumberControllerSlider.prototype, NumberController.prototype, { - updateDisplay:function() { - var pct = (this.getValue() - this.__min) / (this.__max - this.__min); - this.__foreground.style.width = pct * 100 + "%"; - return NumberControllerSlider.superclass.prototype.updateDisplay.call(this); - } - }); - function map(v, i1, i2, o1, o2) { - return o1 + (o2 - o1) * ((v - i1) / (i2 - i1)); - } - return NumberControllerSlider; -}(dat.controllers.NumberController, dat.dom.dom, dat.utils.css, dat.utils.common, "/**\n * dat-gui JavaScript Controller Library\n * http://code.google.com/p/dat-gui\n *\n * Copyright 2011 Data Arts Team, Google Creative Lab\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n */\n\n.slider {\n box-shadow: inset 0 2px 4px rgba(0,0,0,0.15);\n height: 1em;\n border-radius: 1em;\n background-color: #eee;\n padding: 0 0.5em;\n overflow: hidden;\n}\n\n.slider-fg {\n padding: 1px 0 2px 0;\n background-color: #aaa;\n height: 1em;\n margin-left: -0.5em;\n padding-right: 0.5em;\n border-radius: 1em 0 0 1em;\n}\n\n.slider-fg:after {\n display: inline-block;\n border-radius: 1em;\n background-color: #fff;\n border: 1px solid #aaa;\n content: '';\n float: right;\n margin-right: -1em;\n margin-top: -1px;\n height: 0.9em;\n width: 0.9em;\n}"); - -dat.controllers.FunctionController = function(Controller, dom, common) { - var FunctionController = function(object, property, text) { - FunctionController.superclass.call(this, object, property); - var _this = this; - this.__button = document.createElement("div"); - this.__button.innerHTML = text === undefined ? "Fire" :text; - dom.bind(this.__button, "click", function(e) { - e.preventDefault(); - _this.fire(); - return false; - }); - dom.addClass(this.__button, "button"); - this.domElement.appendChild(this.__button); - }; - FunctionController.superclass = Controller; - common.extend(FunctionController.prototype, Controller.prototype, { - fire:function() { - if (this.__onChange) { - this.__onChange.call(this); - } - if (this.__onFinishChange) { - this.__onFinishChange.call(this, this.getValue()); - } - this.getValue().call(this.object); - } - }); - return FunctionController; -}(dat.controllers.Controller, dat.dom.dom, dat.utils.common); - -dat.controllers.BooleanController = function(Controller, dom, common) { - var BooleanController = function(object, property) { - BooleanController.superclass.call(this, object, property); - var _this = this; - this.__prev = this.getValue(); - this.__checkbox = document.createElement("input"); - this.__checkbox.setAttribute("type", "checkbox"); - dom.bind(this.__checkbox, "change", onChange, false); - this.domElement.appendChild(this.__checkbox); - this.updateDisplay(); - function onChange() { - _this.setValue(!_this.__prev); - } - }; - BooleanController.superclass = Controller; - common.extend(BooleanController.prototype, Controller.prototype, { - setValue:function(v) { - var toReturn = BooleanController.superclass.prototype.setValue.call(this, v); - if (this.__onFinishChange) { - this.__onFinishChange.call(this, this.getValue()); - } - this.__prev = this.getValue(); - return toReturn; - }, - updateDisplay:function() { - if (this.getValue() === true) { - this.__checkbox.setAttribute("checked", "checked"); - this.__checkbox.checked = true; - } else { - this.__checkbox.checked = false; - } - return BooleanController.superclass.prototype.updateDisplay.call(this); - } - }); - return BooleanController; -}(dat.controllers.Controller, dat.dom.dom, dat.utils.common); - -dat.color.toString = function(common) { - return function(color) { - if (color.a == 1 || common.isUndefined(color.a)) { - var s = color.hex.toString(16); - while (s.length < 6) { - s = "0" + s; - } - return "#" + s; - } else { - return "rgba(" + Math.round(color.r) + "," + Math.round(color.g) + "," + Math.round(color.b) + "," + color.a + ")"; - } - }; -}(dat.utils.common); - -dat.color.interpret = function(toString, common) { - var result, toReturn; - var interpret = function() { - toReturn = false; - var original = arguments.length > 1 ? common.toArray(arguments) :arguments[0]; - common.each(INTERPRETATIONS, function(family) { - if (family.litmus(original)) { - common.each(family.conversions, function(conversion, conversionName) { - result = conversion.read(original); - if (toReturn === false && result !== false) { - toReturn = result; - result.conversionName = conversionName; - result.conversion = conversion; - return common.BREAK; - } - }); - return common.BREAK; - } - }); - return toReturn; - }; - var INTERPRETATIONS = [ { - litmus:common.isString, - conversions:{ - THREE_CHAR_HEX:{ - read:function(original) { - var test = original.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i); - if (test === null) return false; - return { - space:"HEX", - hex:parseInt("0x" + test[1].toString() + test[1].toString() + test[2].toString() + test[2].toString() + test[3].toString() + test[3].toString()) - }; - }, - write:toString - }, - SIX_CHAR_HEX:{ - read:function(original) { - var test = original.match(/^#([A-F0-9]{6})$/i); - if (test === null) return false; - return { - space:"HEX", - hex:parseInt("0x" + test[1].toString()) - }; - }, - write:toString - }, - CSS_RGB:{ - read:function(original) { - var test = original.match(/^rgb\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/); - if (test === null) return false; - return { - space:"RGB", - r:parseFloat(test[1]), - g:parseFloat(test[2]), - b:parseFloat(test[3]) - }; - }, - write:toString - }, - CSS_RGBA:{ - read:function(original) { - var test = original.match(/^rgba\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\,\s*(.+)\s*\)/); - if (test === null) return false; - return { - space:"RGB", - r:parseFloat(test[1]), - g:parseFloat(test[2]), - b:parseFloat(test[3]), - a:parseFloat(test[4]) - }; - }, - write:toString - } - } - }, { - litmus:common.isNumber, - conversions:{ - HEX:{ - read:function(original) { - return { - space:"HEX", - hex:original, - conversionName:"HEX" - }; - }, - write:function(color) { - return color.hex; - } - } - } - }, { - litmus:common.isArray, - conversions:{ - RGB_ARRAY:{ - read:function(original) { - if (original.length != 3) return false; - return { - space:"RGB", - r:original[0], - g:original[1], - b:original[2] - }; - }, - write:function(color) { - return [ color.r, color.g, color.b ]; - } - }, - RGBA_ARRAY:{ - read:function(original) { - if (original.length != 4) return false; - return { - space:"RGB", - r:original[0], - g:original[1], - b:original[2], - a:original[3] - }; - }, - write:function(color) { - return [ color.r, color.g, color.b, color.a ]; - } - } - } - }, { - litmus:common.isObject, - conversions:{ - RGBA_OBJ:{ - read:function(original) { - if (common.isNumber(original.r) && common.isNumber(original.g) && common.isNumber(original.b) && common.isNumber(original.a)) { - return { - space:"RGB", - r:original.r, - g:original.g, - b:original.b, - a:original.a - }; - } - return false; - }, - write:function(color) { - return { - r:color.r, - g:color.g, - b:color.b, - a:color.a - }; - } - }, - RGB_OBJ:{ - read:function(original) { - if (common.isNumber(original.r) && common.isNumber(original.g) && common.isNumber(original.b)) { - return { - space:"RGB", - r:original.r, - g:original.g, - b:original.b - }; - } - return false; - }, - write:function(color) { - return { - r:color.r, - g:color.g, - b:color.b - }; - } - }, - HSVA_OBJ:{ - read:function(original) { - if (common.isNumber(original.h) && common.isNumber(original.s) && common.isNumber(original.v) && common.isNumber(original.a)) { - return { - space:"HSV", - h:original.h, - s:original.s, - v:original.v, - a:original.a - }; - } - return false; - }, - write:function(color) { - return { - h:color.h, - s:color.s, - v:color.v, - a:color.a - }; - } - }, - HSV_OBJ:{ - read:function(original) { - if (common.isNumber(original.h) && common.isNumber(original.s) && common.isNumber(original.v)) { - return { - space:"HSV", - h:original.h, - s:original.s, - v:original.v - }; - } - return false; - }, - write:function(color) { - return { - h:color.h, - s:color.s, - v:color.v - }; - } - } - } - } ]; - return interpret; -}(dat.color.toString, dat.utils.common); - -dat.GUI = dat.gui.GUI = function(css, saveDialogueContents, styleSheet, controllerFactory, Controller, BooleanController, FunctionController, NumberControllerBox, NumberControllerSlider, OptionController, ColorController, requestAnimationFrame, CenteredDiv, dom, common) { - css.inject(styleSheet); - var CSS_NAMESPACE = "dg"; - var HIDE_KEY_CODE = 72; - var CLOSE_BUTTON_HEIGHT = 20; - var DEFAULT_DEFAULT_PRESET_NAME = "Default"; - var SUPPORTS_LOCAL_STORAGE = function() { - try { - return "localStorage" in window && window["localStorage"] !== null; - } catch (e) { - return false; - } - }(); - var SAVE_DIALOGUE; - var auto_place_virgin = true; - var auto_place_container; - var hide = false; - var hideable_guis = []; - var GUI = function(params) { - var _this = this; - this.domElement = document.createElement("div"); - this.__ul = document.createElement("ul"); - this.domElement.appendChild(this.__ul); - dom.addClass(this.domElement, CSS_NAMESPACE); - this.__folders = {}; - this.__controllers = []; - this.__rememberedObjects = []; - this.__rememberedObjectIndecesToControllers = []; - this.__listening = []; - params = params || {}; - params = common.defaults(params, { - autoPlace:true, - width:GUI.DEFAULT_WIDTH - }); - params = common.defaults(params, { - resizable:params.autoPlace, - hideable:params.autoPlace - }); - if (!common.isUndefined(params.load)) { - if (params.preset) params.load.preset = params.preset; - } else { - params.load = { - preset:DEFAULT_DEFAULT_PRESET_NAME - }; - } - if (common.isUndefined(params.parent) && params.hideable) { - hideable_guis.push(this); - } - params.resizable = common.isUndefined(params.parent) && params.resizable; - if (params.autoPlace && common.isUndefined(params.scrollable)) { - params.scrollable = true; - } - var use_local_storage = SUPPORTS_LOCAL_STORAGE && localStorage.getItem(getLocalStorageHash(this, "isLocal")) === "true"; - var saveToLocalStorage; - Object.defineProperties(this, { - parent:{ - get:function() { - return params.parent; - } - }, - scrollable:{ - get:function() { - return params.scrollable; - } - }, - autoPlace:{ - get:function() { - return params.autoPlace; - } - }, - preset:{ - get:function() { - if (_this.parent) { - return _this.getRoot().preset; - } else { - return params.load.preset; - } - }, - set:function(v) { - if (_this.parent) { - _this.getRoot().preset = v; - } else { - params.load.preset = v; - } - setPresetSelectIndex(this); - _this.revert(); - } - }, - width:{ - get:function() { - return params.width; - }, - set:function(v) { - params.width = v; - setWidth(_this, v); - } - }, - name:{ - get:function() { - return params.name; - }, - set:function(v) { - params.name = v; - if (title_row_name) { - title_row_name.innerHTML = params.name; - } - } - }, - closed:{ - get:function() { - return params.closed; - }, - set:function(v) { - params.closed = v; - if (params.closed) { - dom.addClass(_this.__ul, GUI.CLASS_CLOSED); - } else { - dom.removeClass(_this.__ul, GUI.CLASS_CLOSED); - } - this.onResize(); - if (_this.__closeButton) { - _this.__closeButton.innerHTML = v ? GUI.TEXT_OPEN :GUI.TEXT_CLOSED; - } - } - }, - load:{ - get:function() { - return params.load; - } - }, - useLocalStorage:{ - get:function() { - return use_local_storage; - }, - set:function(bool) { - if (SUPPORTS_LOCAL_STORAGE) { - use_local_storage = bool; - if (bool) { - dom.bind(window, "unload", saveToLocalStorage); - } else { - dom.unbind(window, "unload", saveToLocalStorage); - } - localStorage.setItem(getLocalStorageHash(_this, "isLocal"), bool); - } - } - } - }); - if (common.isUndefined(params.parent)) { - params.closed = false; - dom.addClass(this.domElement, GUI.CLASS_MAIN); - dom.makeSelectable(this.domElement, false); - if (SUPPORTS_LOCAL_STORAGE) { - if (use_local_storage) { - _this.useLocalStorage = true; - var saved_gui = localStorage.getItem(getLocalStorageHash(this, "gui")); - if (saved_gui) { - params.load = JSON.parse(saved_gui); - } - } - } - this.__closeButton = document.createElement("div"); - this.__closeButton.innerHTML = GUI.TEXT_CLOSED; - dom.addClass(this.__closeButton, GUI.CLASS_CLOSE_BUTTON); - this.domElement.appendChild(this.__closeButton); - dom.bind(this.__closeButton, "click", function() { - _this.closed = !_this.closed; - }); - } else { - if (params.closed === undefined) { - params.closed = true; - } - var title_row_name = document.createTextNode(params.name); - dom.addClass(title_row_name, "controller-name"); - var title_row = addRow(_this, title_row_name); - var on_click_title = function(e) { - e.preventDefault(); - _this.closed = !_this.closed; - return false; - }; - dom.addClass(this.__ul, GUI.CLASS_CLOSED); - dom.addClass(title_row, "title"); - dom.bind(title_row, "click", on_click_title); - if (!params.closed) { - this.closed = false; - } - } - if (params.autoPlace) { - if (common.isUndefined(params.parent)) { - if (auto_place_virgin) { - auto_place_container = document.createElement("div"); - dom.addClass(auto_place_container, CSS_NAMESPACE); - dom.addClass(auto_place_container, GUI.CLASS_AUTO_PLACE_CONTAINER); - document.body.appendChild(auto_place_container); - auto_place_virgin = false; - } - auto_place_container.appendChild(this.domElement); - dom.addClass(this.domElement, GUI.CLASS_AUTO_PLACE); - } - if (!this.parent) setWidth(_this, params.width); - } - dom.bind(window, "resize", function() { - _this.onResize(); - }); - dom.bind(this.__ul, "webkitTransitionEnd", function() { - _this.onResize(); - }); - dom.bind(this.__ul, "transitionend", function() { - _this.onResize(); - }); - dom.bind(this.__ul, "oTransitionEnd", function() { - _this.onResize(); - }); - this.onResize(); - if (params.resizable) { - addResizeHandle(this); - } - saveToLocalStorage = function() { - if (SUPPORTS_LOCAL_STORAGE && localStorage.getItem(getLocalStorageHash(_this, "isLocal")) === "true") { - localStorage.setItem(getLocalStorageHash(_this, "gui"), JSON.stringify(_this.getSaveObject())); - } - }; - this.saveToLocalStorageIfPossible = saveToLocalStorage; - var root = _this.getRoot(); - function resetWidth() { - var root = _this.getRoot(); - root.width += 1; - common.defer(function() { - root.width -= 1; - }); - } - if (!params.parent) { - resetWidth(); - } - }; - GUI.toggleHide = function() { - hide = !hide; - common.each(hideable_guis, function(gui) { - gui.domElement.style.zIndex = hide ? -999 :999; - gui.domElement.style.opacity = hide ? 0 :1; - }); - }; - GUI.CLASS_AUTO_PLACE = "a"; - GUI.CLASS_AUTO_PLACE_CONTAINER = "ac"; - GUI.CLASS_MAIN = "main"; - GUI.CLASS_CONTROLLER_ROW = "cr"; - GUI.CLASS_TOO_TALL = "taller-than-window"; - GUI.CLASS_CLOSED = "closed"; - GUI.CLASS_CLOSE_BUTTON = "close-button"; - GUI.CLASS_DRAG = "drag"; - GUI.DEFAULT_WIDTH = 245; - GUI.TEXT_CLOSED = "Close Controls"; - GUI.TEXT_OPEN = "Open Controls"; - dom.bind(window, "keydown", function(e) { - if (document.activeElement.type !== "text" && (e.which === HIDE_KEY_CODE || e.keyCode == HIDE_KEY_CODE)) { - GUI.toggleHide(); - } - }, false); - common.extend(GUI.prototype, { - add:function(object, property) { - return add(this, object, property, { - factoryArgs:Array.prototype.slice.call(arguments, 2) - }); - }, - addColor:function(object, property) { - return add(this, object, property, { - color:true - }); - }, - remove:function(controller) { - this.__ul.removeChild(controller.__li); - this.__controllers.slice(this.__controllers.indexOf(controller), 1); - var _this = this; - common.defer(function() { - _this.onResize(); - }); - }, - destroy:function() { - if (this.autoPlace) { - auto_place_container.removeChild(this.domElement); - } - }, - addFolder:function(name) { - if (this.__folders[name] !== undefined) { - throw new Error("You already have a folder in this GUI by the" + ' name "' + name + '"'); - } - var new_gui_params = { - name:name, - parent:this - }; - new_gui_params.autoPlace = this.autoPlace; - if (this.load && this.load.folders && this.load.folders[name]) { - new_gui_params.closed = this.load.folders[name].closed; - new_gui_params.load = this.load.folders[name]; - } - var gui = new GUI(new_gui_params); - this.__folders[name] = gui; - var li = addRow(this, gui.domElement); - dom.addClass(li, "folder"); - return gui; - }, - open:function() { - this.closed = false; - }, - close:function() { - this.closed = true; - }, - onResize:function() { - var root = this.getRoot(); - if (root.scrollable) { - var top = dom.getOffset(root.__ul).top; - var h = 0; - common.each(root.__ul.childNodes, function(node) { - if (!(root.autoPlace && node === root.__save_row)) h += dom.getHeight(node); - }); - if (window.innerHeight - top - CLOSE_BUTTON_HEIGHT < h) { - dom.addClass(root.domElement, GUI.CLASS_TOO_TALL); - root.__ul.style.height = window.innerHeight - top - CLOSE_BUTTON_HEIGHT + "px"; - } else { - dom.removeClass(root.domElement, GUI.CLASS_TOO_TALL); - root.__ul.style.height = "auto"; - } - } - if (root.__resize_handle) { - common.defer(function() { - root.__resize_handle.style.height = root.__ul.offsetHeight + "px"; - }); - } - if (root.__closeButton) { - root.__closeButton.style.width = root.width + "px"; - } - }, - remember:function() { - if (common.isUndefined(SAVE_DIALOGUE)) { - SAVE_DIALOGUE = new CenteredDiv(); - SAVE_DIALOGUE.domElement.innerHTML = saveDialogueContents; - } - if (this.parent) { - throw new Error("You can only call remember on a top level GUI."); - } - var _this = this; - common.each(Array.prototype.slice.call(arguments), function(object) { - if (_this.__rememberedObjects.length == 0) { - addSaveMenu(_this); - } - if (_this.__rememberedObjects.indexOf(object) == -1) { - _this.__rememberedObjects.push(object); - } - }); - if (this.autoPlace) { - setWidth(this, this.width); - } - }, - getRoot:function() { - var gui = this; - while (gui.parent) { - gui = gui.parent; - } - return gui; - }, - getSaveObject:function() { - var toReturn = this.load; - toReturn.closed = this.closed; - if (this.__rememberedObjects.length > 0) { - toReturn.preset = this.preset; - if (!toReturn.remembered) { - toReturn.remembered = {}; - } - toReturn.remembered[this.preset] = getCurrentPreset(this); - } - toReturn.folders = {}; - common.each(this.__folders, function(element, key) { - toReturn.folders[key] = element.getSaveObject(); - }); - return toReturn; - }, - save:function() { - if (!this.load.remembered) { - this.load.remembered = {}; - } - this.load.remembered[this.preset] = getCurrentPreset(this); - markPresetModified(this, false); - this.saveToLocalStorageIfPossible(); - }, - saveAs:function(presetName) { - if (!this.load.remembered) { - this.load.remembered = {}; - this.load.remembered[DEFAULT_DEFAULT_PRESET_NAME] = getCurrentPreset(this, true); - } - this.load.remembered[presetName] = getCurrentPreset(this); - this.preset = presetName; - addPresetOption(this, presetName, true); - this.saveToLocalStorageIfPossible(); - }, - revert:function(gui) { - common.each(this.__controllers, function(controller) { - if (!this.getRoot().load.remembered) { - controller.setValue(controller.initialValue); - } else { - recallSavedValue(gui || this.getRoot(), controller); - } - }, this); - common.each(this.__folders, function(folder) { - folder.revert(folder); - }); - if (!gui) { - markPresetModified(this.getRoot(), false); - } - }, - listen:function(controller) { - var init = this.__listening.length == 0; - this.__listening.push(controller); - if (init) updateDisplays(this.__listening); - } - }); - function add(gui, object, property, params) { - if (object[property] === undefined) { - throw new Error("Object " + object + ' has no property "' + property + '"'); - } - var controller; - if (params.color) { - controller = new ColorController(object, property); - } else { - var factoryArgs = [ object, property ].concat(params.factoryArgs); - controller = controllerFactory.apply(gui, factoryArgs); - } - if (params.before instanceof Controller) { - params.before = params.before.__li; - } - recallSavedValue(gui, controller); - dom.addClass(controller.domElement, "c"); - var name = document.createElement("span"); - dom.addClass(name, "property-name"); - name.innerHTML = controller.property; - var container = document.createElement("div"); - container.appendChild(name); - container.appendChild(controller.domElement); - var li = addRow(gui, container, params.before); - dom.addClass(li, GUI.CLASS_CONTROLLER_ROW); - dom.addClass(li, typeof controller.getValue()); - augmentController(gui, li, controller); - gui.__controllers.push(controller); - return controller; - } - function addRow(gui, dom, liBefore) { - var li = document.createElement("li"); - if (dom) li.appendChild(dom); - if (liBefore) { - gui.__ul.insertBefore(li, params.before); - } else { - gui.__ul.appendChild(li); - } - gui.onResize(); - return li; - } - function augmentController(gui, li, controller) { - controller.__li = li; - controller.__gui = gui; - common.extend(controller, { - options:function(options) { - if (arguments.length > 1) { - controller.remove(); - return add(gui, controller.object, controller.property, { - before:controller.__li.nextElementSibling, - factoryArgs:[ common.toArray(arguments) ] - }); - } - if (common.isArray(options) || common.isObject(options)) { - controller.remove(); - return add(gui, controller.object, controller.property, { - before:controller.__li.nextElementSibling, - factoryArgs:[ options ] - }); - } - }, - name:function(v) { - controller.__li.firstElementChild.firstElementChild.innerHTML = v; - return controller; - }, - listen:function() { - controller.__gui.listen(controller); - return controller; - }, - remove:function() { - controller.__gui.remove(controller); - return controller; - } - }); - if (controller instanceof NumberControllerSlider) { - var box = new NumberControllerBox(controller.object, controller.property, { - min:controller.__min, - max:controller.__max, - step:controller.__step - }); - common.each([ "updateDisplay", "onChange", "onFinishChange" ], function(method) { - var pc = controller[method]; - var pb = box[method]; - controller[method] = box[method] = function() { - var args = Array.prototype.slice.call(arguments); - pc.apply(controller, args); - return pb.apply(box, args); - }; - }); - dom.addClass(li, "has-slider"); - controller.domElement.insertBefore(box.domElement, controller.domElement.firstElementChild); - } else if (controller instanceof NumberControllerBox) { - var r = function(returned) { - if (common.isNumber(controller.__min) && common.isNumber(controller.__max)) { - controller.remove(); - return add(gui, controller.object, controller.property, { - before:controller.__li.nextElementSibling, - factoryArgs:[ controller.__min, controller.__max, controller.__step ] - }); - } - return returned; - }; - controller.min = common.compose(r, controller.min); - controller.max = common.compose(r, controller.max); - } else if (controller instanceof BooleanController) { - dom.bind(li, "click", function() { - dom.fakeEvent(controller.__checkbox, "click"); - }); - dom.bind(controller.__checkbox, "click", function(e) { - e.stopPropagation(); - }); - } else if (controller instanceof FunctionController) { - dom.bind(li, "click", function() { - dom.fakeEvent(controller.__button, "click"); - }); - dom.bind(li, "mouseover", function() { - dom.addClass(controller.__button, "hover"); - }); - dom.bind(li, "mouseout", function() { - dom.removeClass(controller.__button, "hover"); - }); - } else if (controller instanceof ColorController) { - dom.addClass(li, "color"); - controller.updateDisplay = common.compose(function(r) { - li.style.borderLeftColor = controller.__color.toString(); - return r; - }, controller.updateDisplay); - controller.updateDisplay(); - } - controller.setValue = common.compose(function(r) { - if (gui.getRoot().__preset_select && controller.isModified()) { - markPresetModified(gui.getRoot(), true); - } - return r; - }, controller.setValue); - } - function recallSavedValue(gui, controller) { - var root = gui.getRoot(); - var matched_index = root.__rememberedObjects.indexOf(controller.object); - if (matched_index != -1) { - var controller_map = root.__rememberedObjectIndecesToControllers[matched_index]; - if (controller_map === undefined) { - controller_map = {}; - root.__rememberedObjectIndecesToControllers[matched_index] = controller_map; - } - controller_map[controller.property] = controller; - if (root.load && root.load.remembered) { - var preset_map = root.load.remembered; - var preset; - if (preset_map[gui.preset]) { - preset = preset_map[gui.preset]; - } else if (preset_map[DEFAULT_DEFAULT_PRESET_NAME]) { - preset = preset_map[DEFAULT_DEFAULT_PRESET_NAME]; - } else { - return; - } - if (preset[matched_index] && preset[matched_index][controller.property] !== undefined) { - var value = preset[matched_index][controller.property]; - controller.initialValue = value; - controller.setValue(value); - } - } - } - } - function getLocalStorageHash(gui, key) { - return document.location.href + "." + key; - } - function addSaveMenu(gui) { - var div = gui.__save_row = document.createElement("li"); - dom.addClass(gui.domElement, "has-save"); - gui.__ul.insertBefore(div, gui.__ul.firstChild); - dom.addClass(div, "save-row"); - var gears = document.createElement("span"); - gears.innerHTML = " "; - dom.addClass(gears, "button gears"); - var button = document.createElement("span"); - button.innerHTML = "Save"; - dom.addClass(button, "button"); - dom.addClass(button, "save"); - var button2 = document.createElement("span"); - button2.innerHTML = "New"; - dom.addClass(button2, "button"); - dom.addClass(button2, "save-as"); - var button3 = document.createElement("span"); - button3.innerHTML = "Revert"; - dom.addClass(button3, "button"); - dom.addClass(button3, "revert"); - var select = gui.__preset_select = document.createElement("select"); - if (gui.load && gui.load.remembered) { - common.each(gui.load.remembered, function(value, key) { - addPresetOption(gui, key, key == gui.preset); - }); - } else { - addPresetOption(gui, DEFAULT_DEFAULT_PRESET_NAME, false); - } - dom.bind(select, "change", function() { - for (var index = 0; index < gui.__preset_select.length; index++) { - gui.__preset_select[index].innerHTML = gui.__preset_select[index].value; - } - gui.preset = this.value; - }); - div.appendChild(select); - div.appendChild(gears); - div.appendChild(button); - div.appendChild(button2); - div.appendChild(button3); - if (SUPPORTS_LOCAL_STORAGE) { - var saveLocally = document.getElementById("dg-save-locally"); - var explain = document.getElementById("dg-local-explain"); - saveLocally.style.display = "block"; - var localStorageCheckBox = document.getElementById("dg-local-storage"); - if (localStorage.getItem(getLocalStorageHash(gui, "isLocal")) === "true") { - localStorageCheckBox.setAttribute("checked", "checked"); - } - function showHideExplain() { - explain.style.display = gui.useLocalStorage ? "block" :"none"; - } - showHideExplain(); - dom.bind(localStorageCheckBox, "change", function() { - gui.useLocalStorage = !gui.useLocalStorage; - showHideExplain(); - }); - } - var newConstructorTextArea = document.getElementById("dg-new-constructor"); - dom.bind(newConstructorTextArea, "keydown", function(e) { - if (e.metaKey && (e.which === 67 || e.keyCode == 67)) { - SAVE_DIALOGUE.hide(); - } - }); - dom.bind(gears, "click", function() { - newConstructorTextArea.innerHTML = JSON.stringify(gui.getSaveObject(), undefined, 2); - SAVE_DIALOGUE.show(); - newConstructorTextArea.focus(); - newConstructorTextArea.select(); - }); - dom.bind(button, "click", function() { - gui.save(); - }); - dom.bind(button2, "click", function() { - var presetName = prompt("Enter a new preset name."); - if (presetName) gui.saveAs(presetName); - }); - dom.bind(button3, "click", function() { - gui.revert(); - }); - } - function addResizeHandle(gui) { - gui.__resize_handle = document.createElement("div"); - common.extend(gui.__resize_handle.style, { - width:"6px", - marginLeft:"-3px", - height:"200px", - cursor:"ew-resize", - position:"absolute" - }); - var pmouseX; - dom.bind(gui.__resize_handle, "mousedown", dragStart); - dom.bind(gui.__closeButton, "mousedown", dragStart); - gui.domElement.insertBefore(gui.__resize_handle, gui.domElement.firstElementChild); - function dragStart(e) { - e.preventDefault(); - pmouseX = e.clientX; - dom.addClass(gui.__closeButton, GUI.CLASS_DRAG); - dom.bind(window, "mousemove", drag); - dom.bind(window, "mouseup", dragStop); - return false; - } - function drag(e) { - e.preventDefault(); - gui.width += pmouseX - e.clientX; - gui.onResize(); - pmouseX = e.clientX; - return false; - } - function dragStop() { - dom.removeClass(gui.__closeButton, GUI.CLASS_DRAG); - dom.unbind(window, "mousemove", drag); - dom.unbind(window, "mouseup", dragStop); - } - } - function setWidth(gui, w) { - gui.domElement.style.width = w + "px"; - if (gui.__save_row && gui.autoPlace) { - gui.__save_row.style.width = w + "px"; - } - if (gui.__closeButton) { - gui.__closeButton.style.width = w + "px"; - } - } - function getCurrentPreset(gui, useInitialValues) { - var toReturn = {}; - common.each(gui.__rememberedObjects, function(val, index) { - var saved_values = {}; - var controller_map = gui.__rememberedObjectIndecesToControllers[index]; - common.each(controller_map, function(controller, property) { - saved_values[property] = useInitialValues ? controller.initialValue :controller.getValue(); - }); - toReturn[index] = saved_values; - }); - return toReturn; - } - function addPresetOption(gui, name, setSelected) { - var opt = document.createElement("option"); - opt.innerHTML = name; - opt.value = name; - gui.__preset_select.appendChild(opt); - if (setSelected) { - gui.__preset_select.selectedIndex = gui.__preset_select.length - 1; - } - } - function setPresetSelectIndex(gui) { - for (var index = 0; index < gui.__preset_select.length; index++) { - if (gui.__preset_select[index].value == gui.preset) { - gui.__preset_select.selectedIndex = index; - } - } - } - function markPresetModified(gui, modified) { - var opt = gui.__preset_select[gui.__preset_select.selectedIndex]; - if (modified) { - opt.innerHTML = opt.value + "*"; - } else { - opt.innerHTML = opt.value; - } - } - function updateDisplays(controllerArray) { - if (controllerArray.length != 0) { - requestAnimationFrame(function() { - updateDisplays(controllerArray); - }); - } - common.each(controllerArray, function(c) { - c.updateDisplay(); - }); - } - return GUI; -}(dat.utils.css, '
\n\n Here\'s the new load parameter for your GUI\'s constructor:\n\n \n\n
\n\n Automatically save\n values to localStorage on exit.\n\n
The values saved to localStorage will\n override those passed to dat.GUI\'s constructor. This makes it\n easier to work incrementally, but localStorage is fragile,\n and your friends may not see the same values you do.\n \n
\n \n
\n\n
', ".dg {\n /** Clear list styles */\n /* Auto-place container */\n /* Auto-placed GUI's */\n /* Line items that don't contain folders. */\n /** Folder names */\n /** Hides closed items */\n /** Controller row */\n /** Name-half (left) */\n /** Controller-half (right) */\n /** Controller placement */\n /** Shorter number boxes when slider is present. */\n /** Ensure the entire boolean and function row shows a hand */ }\n .dg ul {\n list-style: none;\n margin: 0;\n padding: 0;\n width: 100%;\n clear: both; }\n .dg.ac {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n height: 0;\n z-index: 0; }\n .dg:not(.ac) .main {\n /** Exclude mains in ac so that we don't hide close button */\n overflow: hidden; }\n .dg.main {\n -webkit-transition: opacity 0.1s linear;\n -o-transition: opacity 0.1s linear;\n -moz-transition: opacity 0.1s linear;\n transition: opacity 0.1s linear; }\n .dg.main.taller-than-window {\n overflow-y: auto; }\n .dg.main.taller-than-window .close-button {\n opacity: 1;\n /* TODO, these are style notes */\n margin-top: -1px;\n border-top: 1px solid #2c2c2c; }\n .dg.main ul.closed .close-button {\n opacity: 1 !important; }\n .dg.main:hover .close-button,\n .dg.main .close-button.drag {\n opacity: 1; }\n .dg.main .close-button {\n /*opacity: 0;*/\n -webkit-transition: opacity 0.1s linear;\n -o-transition: opacity 0.1s linear;\n -moz-transition: opacity 0.1s linear;\n transition: opacity 0.1s linear;\n border: 0;\n position: absolute;\n line-height: 19px;\n height: 20px;\n /* TODO, these are style notes */\n cursor: pointer;\n text-align: center;\n background-color: #000; }\n .dg.main .close-button:hover {\n background-color: #111; }\n .dg.a {\n float: right;\n margin-right: 15px;\n overflow-x: hidden; }\n .dg.a.has-save > ul {\n margin-top: 27px; }\n .dg.a.has-save > ul.closed {\n margin-top: 0; }\n .dg.a .save-row {\n position: fixed;\n top: 0;\n z-index: 1002; }\n .dg li {\n -webkit-transition: height 0.1s ease-out;\n -o-transition: height 0.1s ease-out;\n -moz-transition: height 0.1s ease-out;\n transition: height 0.1s ease-out; }\n .dg li:not(.folder) {\n cursor: auto;\n height: 27px;\n line-height: 27px;\n overflow: hidden;\n padding: 0 4px 0 5px; }\n .dg li.folder {\n padding: 0;\n border-left: 4px solid rgba(0, 0, 0, 0); }\n .dg li.title {\n cursor: pointer;\n margin-left: -4px; }\n .dg .closed li:not(.title),\n .dg .closed ul li,\n .dg .closed ul li > * {\n height: 0;\n overflow: hidden;\n border: 0; }\n .dg .cr {\n clear: both;\n padding-left: 3px;\n height: 27px; }\n .dg .property-name {\n cursor: default;\n float: left;\n clear: left;\n width: 40%;\n overflow: hidden;\n text-overflow: ellipsis; }\n .dg .c {\n float: left;\n width: 60%; }\n .dg .c input[type=text] {\n border: 0;\n margin-top: 4px;\n padding: 3px;\n width: 100%;\n float: right; }\n .dg .has-slider input[type=text] {\n width: 30%;\n /*display: none;*/\n margin-left: 0; }\n .dg .slider {\n float: left;\n width: 66%;\n margin-left: -5px;\n margin-right: 0;\n height: 19px;\n margin-top: 4px; }\n .dg .slider-fg {\n height: 100%; }\n .dg .c input[type=checkbox] {\n margin-top: 9px; }\n .dg .c select {\n margin-top: 5px; }\n .dg .cr.function,\n .dg .cr.function .property-name,\n .dg .cr.function *,\n .dg .cr.boolean,\n .dg .cr.boolean * {\n cursor: pointer; }\n .dg .selector {\n display: none;\n position: absolute;\n margin-left: -9px;\n margin-top: 23px;\n z-index: 10; }\n .dg .c:hover .selector,\n .dg .selector.drag {\n display: block; }\n .dg li.save-row {\n padding: 0; }\n .dg li.save-row .button {\n display: inline-block;\n padding: 0px 6px; }\n .dg.dialogue {\n background-color: #222;\n width: 460px;\n padding: 15px;\n font-size: 13px;\n line-height: 15px; }\n\n/* TODO Separate style and structure */\n#dg-new-constructor {\n padding: 10px;\n color: #222;\n font-family: Monaco, monospace;\n font-size: 10px;\n border: 0;\n resize: none;\n box-shadow: inset 1px 1px 1px #888;\n word-wrap: break-word;\n margin: 12px 0;\n display: block;\n width: 440px;\n overflow-y: scroll;\n height: 100px;\n position: relative; }\n\n#dg-local-explain {\n display: none;\n font-size: 11px;\n line-height: 17px;\n border-radius: 3px;\n background-color: #333;\n padding: 8px;\n margin-top: 10px; }\n #dg-local-explain code {\n font-size: 10px; }\n\n#dat-gui-save-locally {\n display: none; }\n\n/** Main type */\n.dg {\n color: #eee;\n font: 11px 'Lucida Grande', sans-serif;\n text-shadow: 0 -1px 0 #111;\n /** Auto place */\n /* Controller row,
  • */\n /** Controllers */ }\n .dg.main {\n /** Scrollbar */ }\n .dg.main::-webkit-scrollbar {\n width: 5px;\n background: #1a1a1a; }\n .dg.main::-webkit-scrollbar-corner {\n height: 0;\n display: none; }\n .dg.main::-webkit-scrollbar-thumb {\n border-radius: 5px;\n background: #676767; }\n .dg li:not(.folder) {\n background: #1a1a1a;\n border-bottom: 1px solid #2c2c2c; }\n .dg li.save-row {\n line-height: 25px;\n background: #dad5cb;\n border: 0; }\n .dg li.save-row select {\n margin-left: 5px;\n width: 108px; }\n .dg li.save-row .button {\n margin-left: 5px;\n margin-top: 1px;\n border-radius: 2px;\n font-size: 9px;\n line-height: 7px;\n padding: 4px 4px 5px 4px;\n background: #c5bdad;\n color: #fff;\n text-shadow: 0 1px 0 #b0a58f;\n box-shadow: 0 -1px 0 #b0a58f;\n cursor: pointer; }\n .dg li.save-row .button.gears {\n background: #c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;\n height: 7px;\n width: 8px; }\n .dg li.save-row .button:hover {\n background-color: #bab19e;\n box-shadow: 0 -1px 0 #b0a58f; }\n .dg li.folder {\n border-bottom: 0; }\n .dg li.title {\n padding-left: 16px;\n background: black url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;\n cursor: pointer;\n border-bottom: 1px solid rgba(255, 255, 255, 0.2); }\n .dg .closed li.title {\n background-image: url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==); }\n .dg .cr.boolean {\n border-left: 3px solid #806787; }\n .dg .cr.function {\n border-left: 3px solid #e61d5f; }\n .dg .cr.number {\n border-left: 3px solid #2fa1d6; }\n .dg .cr.number input[type=text] {\n color: #2fa1d6; }\n .dg .cr.string {\n border-left: 3px solid #1ed36f; }\n .dg .cr.string input[type=text] {\n color: #1ed36f; }\n .dg .cr.function:hover, .dg .cr.boolean:hover {\n background: #111; }\n .dg .c input[type=text] {\n background: #303030;\n outline: none; }\n .dg .c input[type=text]:hover {\n background: #3c3c3c; }\n .dg .c input[type=text]:focus {\n background: #494949;\n color: #fff; }\n .dg .c .slider {\n background: #303030;\n cursor: ew-resize; }\n .dg .c .slider-fg {\n background: #2fa1d6; }\n .dg .c .slider:hover {\n background: #3c3c3c; }\n .dg .c .slider:hover .slider-fg {\n background: #44abda; }\n", dat.controllers.factory = function(OptionController, NumberControllerBox, NumberControllerSlider, StringController, FunctionController, BooleanController, common) { - return function(object, property) { - var initialValue = object[property]; - if (common.isArray(arguments[2]) || common.isObject(arguments[2])) { - return new OptionController(object, property, arguments[2]); - } - if (common.isNumber(initialValue)) { - if (common.isNumber(arguments[2]) && common.isNumber(arguments[3])) { - return new NumberControllerSlider(object, property, arguments[2], arguments[3]); - } else { - return new NumberControllerBox(object, property, { - min:arguments[2], - max:arguments[3] - }); - } - } - if (common.isString(initialValue)) { - return new StringController(object, property); - } - if (common.isFunction(initialValue)) { - return new FunctionController(object, property, ""); - } - if (common.isBoolean(initialValue)) { - return new BooleanController(object, property); - } - }; -}(dat.controllers.OptionController, dat.controllers.NumberControllerBox, dat.controllers.NumberControllerSlider, dat.controllers.StringController = function(Controller, dom, common) { - var StringController = function(object, property) { - StringController.superclass.call(this, object, property); - var _this = this; - this.__input = document.createElement("input"); - this.__input.setAttribute("type", "text"); - dom.bind(this.__input, "keyup", onChange); - dom.bind(this.__input, "change", onChange); - dom.bind(this.__input, "blur", onBlur); - dom.bind(this.__input, "keydown", function(e) { - if (e.keyCode === 13) { - this.blur(); - } - }); - function onChange() { - _this.setValue(_this.__input.value); - } - function onBlur() { - if (_this.__onFinishChange) { - _this.__onFinishChange.call(_this, _this.getValue()); - } - } - this.updateDisplay(); - this.domElement.appendChild(this.__input); - }; - StringController.superclass = Controller; - common.extend(StringController.prototype, Controller.prototype, { - updateDisplay:function() { - if (!dom.isActive(this.__input)) { - this.__input.value = this.getValue(); - } - return StringController.superclass.prototype.updateDisplay.call(this); - } - }); - return StringController; -}(dat.controllers.Controller, dat.dom.dom, dat.utils.common), dat.controllers.FunctionController, dat.controllers.BooleanController, dat.utils.common), dat.controllers.Controller, dat.controllers.BooleanController, dat.controllers.FunctionController, dat.controllers.NumberControllerBox, dat.controllers.NumberControllerSlider, dat.controllers.OptionController, dat.controllers.ColorController = function(Controller, dom, Color, interpret, common) { - var ColorController = function(object, property) { - ColorController.superclass.call(this, object, property); - this.__color = new Color(this.getValue()); - this.__temp = new Color(0); - var _this = this; - this.domElement = document.createElement("div"); - dom.makeSelectable(this.domElement, false); - this.__selector = document.createElement("div"); - this.__selector.className = "selector"; - this.__saturation_field = document.createElement("div"); - this.__saturation_field.className = "saturation-field"; - this.__field_knob = document.createElement("div"); - this.__field_knob.className = "field-knob"; - this.__field_knob_border = "2px solid "; - this.__hue_knob = document.createElement("div"); - this.__hue_knob.className = "hue-knob"; - this.__hue_field = document.createElement("div"); - this.__hue_field.className = "hue-field"; - this.__input = document.createElement("input"); - this.__input.type = "text"; - this.__input_textShadow = "0 1px 1px "; - dom.bind(this.__input, "keydown", function(e) { - if (e.keyCode === 13) { - onBlur.call(this); - } - }); - dom.bind(this.__input, "blur", onBlur); - dom.bind(this.__selector, "mousedown", function(e) { - dom.addClass(this, "drag").bind(window, "mouseup", function(e) { - dom.removeClass(_this.__selector, "drag"); - }); - }); - var value_field = document.createElement("div"); - common.extend(this.__selector.style, { - width:"122px", - height:"102px", - padding:"3px", - backgroundColor:"#222", - boxShadow:"0px 1px 3px rgba(0,0,0,0.3)" - }); - common.extend(this.__field_knob.style, { - position:"absolute", - width:"12px", - height:"12px", - border:this.__field_knob_border + (this.__color.v < .5 ? "#fff" :"#000"), - boxShadow:"0px 1px 3px rgba(0,0,0,0.5)", - borderRadius:"12px", - zIndex:1 - }); - common.extend(this.__hue_knob.style, { - position:"absolute", - width:"15px", - height:"2px", - borderRight:"4px solid #fff", - zIndex:1 - }); - common.extend(this.__saturation_field.style, { - width:"100px", - height:"100px", - border:"1px solid #555", - marginRight:"3px", - display:"inline-block", - cursor:"pointer" - }); - common.extend(value_field.style, { - width:"100%", - height:"100%", - background:"none" - }); - linearGradient(value_field, "top", "rgba(0,0,0,0)", "#000"); - common.extend(this.__hue_field.style, { - width:"15px", - height:"100px", - display:"inline-block", - border:"1px solid #555", - cursor:"ns-resize" - }); - hueGradient(this.__hue_field); - common.extend(this.__input.style, { - outline:"none", - textAlign:"center", - color:"#fff", - border:0, - fontWeight:"bold", - textShadow:this.__input_textShadow + "rgba(0,0,0,0.7)" - }); - dom.bind(this.__saturation_field, "mousedown", fieldDown); - dom.bind(this.__field_knob, "mousedown", fieldDown); - dom.bind(this.__hue_field, "mousedown", function(e) { - setH(e); - dom.bind(window, "mousemove", setH); - dom.bind(window, "mouseup", unbindH); - }); - function fieldDown(e) { - setSV(e); - dom.bind(window, "mousemove", setSV); - dom.bind(window, "mouseup", unbindSV); - } - function unbindSV() { - dom.unbind(window, "mousemove", setSV); - dom.unbind(window, "mouseup", unbindSV); - } - function onBlur() { - var i = interpret(this.value); - if (i !== false) { - _this.__color.__state = i; - _this.setValue(_this.__color.toOriginal()); - } else { - this.value = _this.__color.toString(); - } - } - function unbindH() { - dom.unbind(window, "mousemove", setH); - dom.unbind(window, "mouseup", unbindH); - } - this.__saturation_field.appendChild(value_field); - this.__selector.appendChild(this.__field_knob); - this.__selector.appendChild(this.__saturation_field); - this.__selector.appendChild(this.__hue_field); - this.__hue_field.appendChild(this.__hue_knob); - this.domElement.appendChild(this.__input); - this.domElement.appendChild(this.__selector); - this.updateDisplay(); - function setSV(e) { - e.preventDefault(); - var w = dom.getWidth(_this.__saturation_field); - var o = dom.getOffset(_this.__saturation_field); - var s = (e.clientX - o.left + document.body.scrollLeft) / w; - var v = 1 - (e.clientY - o.top + document.body.scrollTop) / w; - if (v > 1) v = 1; else if (v < 0) v = 0; - if (s > 1) s = 1; else if (s < 0) s = 0; - _this.__color.v = v; - _this.__color.s = s; - _this.setValue(_this.__color.toOriginal()); - return false; - } - function setH(e) { - e.preventDefault(); - var s = dom.getHeight(_this.__hue_field); - var o = dom.getOffset(_this.__hue_field); - var h = 1 - (e.clientY - o.top + document.body.scrollTop) / s; - if (h > 1) h = 1; else if (h < 0) h = 0; - _this.__color.h = h * 360; - _this.setValue(_this.__color.toOriginal()); - return false; - } - }; - ColorController.superclass = Controller; - common.extend(ColorController.prototype, Controller.prototype, { - updateDisplay:function() { - var i = interpret(this.getValue()); - if (i !== false) { - var mismatch = false; - common.each(Color.COMPONENTS, function(component) { - if (!common.isUndefined(i[component]) && !common.isUndefined(this.__color.__state[component]) && i[component] !== this.__color.__state[component]) { - mismatch = true; - return {}; - } - }, this); - if (mismatch) { - common.extend(this.__color.__state, i); - } - } - common.extend(this.__temp.__state, this.__color.__state); - this.__temp.a = 1; - var flip = this.__color.v < .5 || this.__color.s > .5 ? 255 :0; - var _flip = 255 - flip; - common.extend(this.__field_knob.style, { - marginLeft:100 * this.__color.s - 7 + "px", - marginTop:100 * (1 - this.__color.v) - 7 + "px", - backgroundColor:this.__temp.toString(), - border:this.__field_knob_border + "rgb(" + flip + "," + flip + "," + flip + ")" - }); - this.__hue_knob.style.marginTop = (1 - this.__color.h / 360) * 100 + "px"; - this.__temp.s = 1; - this.__temp.v = 1; - linearGradient(this.__saturation_field, "left", "#fff", this.__temp.toString()); - common.extend(this.__input.style, { - backgroundColor:this.__input.value = this.__color.toString(), - color:"rgb(" + flip + "," + flip + "," + flip + ")", - textShadow:this.__input_textShadow + "rgba(" + _flip + "," + _flip + "," + _flip + ",.7)" - }); - } - }); - var vendors = [ "-moz-", "-o-", "-webkit-", "-ms-", "" ]; - function linearGradient(elem, x, a, b) { - elem.style.background = ""; - common.each(vendors, function(vendor) { - elem.style.cssText += "background: " + vendor + "linear-gradient(" + x + ", " + a + " 0%, " + b + " 100%); "; - }); - } - function hueGradient(elem) { - elem.style.background = ""; - elem.style.cssText += "background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);"; - elem.style.cssText += "background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);"; - elem.style.cssText += "background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);"; - elem.style.cssText += "background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);"; - elem.style.cssText += "background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);"; - } - return ColorController; -}(dat.controllers.Controller, dat.dom.dom, dat.color.Color = function(interpret, math, toString, common) { - var Color = function() { - this.__state = interpret.apply(this, arguments); - if (this.__state === false) { - throw "Failed to interpret color arguments"; - } - this.__state.a = this.__state.a || 1; - }; - Color.COMPONENTS = [ "r", "g", "b", "h", "s", "v", "hex", "a" ]; - common.extend(Color.prototype, { - toString:function() { - return toString(this); - }, - toOriginal:function() { - return this.__state.conversion.write(this); - } - }); - defineRGBComponent(Color.prototype, "r", 2); - defineRGBComponent(Color.prototype, "g", 1); - defineRGBComponent(Color.prototype, "b", 0); - defineHSVComponent(Color.prototype, "h"); - defineHSVComponent(Color.prototype, "s"); - defineHSVComponent(Color.prototype, "v"); - Object.defineProperty(Color.prototype, "a", { - get:function() { - return this.__state.a; - }, - set:function(v) { - this.__state.a = v; - } - }); - Object.defineProperty(Color.prototype, "hex", { - get:function() { - if (!this.__state.space !== "HEX") { - this.__state.hex = math.rgb_to_hex(this.r, this.g, this.b); - } - return this.__state.hex; - }, - set:function(v) { - this.__state.space = "HEX"; - this.__state.hex = v; - } - }); - function defineRGBComponent(target, component, componentHexIndex) { - Object.defineProperty(target, component, { - get:function() { - if (this.__state.space === "RGB") { - return this.__state[component]; - } - recalculateRGB(this, component, componentHexIndex); - return this.__state[component]; - }, - set:function(v) { - if (this.__state.space !== "RGB") { - recalculateRGB(this, component, componentHexIndex); - this.__state.space = "RGB"; - } - this.__state[component] = v; - } - }); - } - function defineHSVComponent(target, component) { - Object.defineProperty(target, component, { - get:function() { - if (this.__state.space === "HSV") return this.__state[component]; - recalculateHSV(this); - return this.__state[component]; - }, - set:function(v) { - if (this.__state.space !== "HSV") { - recalculateHSV(this); - this.__state.space = "HSV"; - } - this.__state[component] = v; - } - }); - } - function recalculateRGB(color, component, componentHexIndex) { - if (color.__state.space === "HEX") { - color.__state[component] = math.component_from_hex(color.__state.hex, componentHexIndex); - } else if (color.__state.space === "HSV") { - common.extend(color.__state, math.hsv_to_rgb(color.__state.h, color.__state.s, color.__state.v)); - } else { - throw "Corrupted color state"; - } - } - function recalculateHSV(color) { - var result = math.rgb_to_hsv(color.r, color.g, color.b); - common.extend(color.__state, { - s:result.s, - v:result.v - }); - if (!common.isNaN(result.h)) { - color.__state.h = result.h; - } else if (common.isUndefined(color.__state.h)) { - color.__state.h = 0; - } - } - return Color; -}(dat.color.interpret, dat.color.math = function() { - var tmpComponent; - return { - hsv_to_rgb:function(h, s, v) { - var hi = Math.floor(h / 60) % 6; - var f = h / 60 - Math.floor(h / 60); - var p = v * (1 - s); - var q = v * (1 - f * s); - var t = v * (1 - (1 - f) * s); - var c = [ [ v, t, p ], [ q, v, p ], [ p, v, t ], [ p, q, v ], [ t, p, v ], [ v, p, q ] ][hi]; - return { - r:c[0] * 255, - g:c[1] * 255, - b:c[2] * 255 - }; - }, - rgb_to_hsv:function(r, g, b) { - var min = Math.min(r, g, b), max = Math.max(r, g, b), delta = max - min, h, s; - if (max != 0) { - s = delta / max; - } else { - return { - h:NaN, - s:0, - v:0 - }; - } - if (r == max) { - h = (g - b) / delta; - } else if (g == max) { - h = 2 + (b - r) / delta; - } else { - h = 4 + (r - g) / delta; - } - h /= 6; - if (h < 0) { - h += 1; - } - return { - h:h * 360, - s:s, - v:max / 255 - }; - }, - rgb_to_hex:function(r, g, b) { - var hex = this.hex_with_component(0, 2, r); - hex = this.hex_with_component(hex, 1, g); - hex = this.hex_with_component(hex, 0, b); - return hex; - }, - component_from_hex:function(hex, componentIndex) { - return hex >> componentIndex * 8 & 255; - }, - hex_with_component:function(hex, componentIndex, value) { - return value << (tmpComponent = componentIndex * 8) | hex & ~(255 << tmpComponent); - } - }; -}(), dat.color.toString, dat.utils.common), dat.color.interpret, dat.utils.common), dat.utils.requestAnimationFrame = function() { - return window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback, element) { - window.setTimeout(callback, 1e3 / 60); - }; -}(), dat.dom.CenteredDiv = function(dom, common) { - var CenteredDiv = function() { - this.backgroundElement = document.createElement("div"); - common.extend(this.backgroundElement.style, { - backgroundColor:"rgba(0,0,0,0.8)", - top:0, - left:0, - display:"none", - zIndex:"1000", - opacity:0, - WebkitTransition:"opacity 0.2s linear" - }); - dom.makeFullscreen(this.backgroundElement); - this.backgroundElement.style.position = "fixed"; - this.domElement = document.createElement("div"); - common.extend(this.domElement.style, { - position:"fixed", - display:"none", - zIndex:"1001", - opacity:0, - WebkitTransition:"-webkit-transform 0.2s ease-out, opacity 0.2s linear" - }); - document.body.appendChild(this.backgroundElement); - document.body.appendChild(this.domElement); - var _this = this; - dom.bind(this.backgroundElement, "click", function() { - _this.hide(); - }); - }; - CenteredDiv.prototype.show = function() { - var _this = this; - this.backgroundElement.style.display = "block"; - this.domElement.style.display = "block"; - this.domElement.style.opacity = 0; - this.domElement.style.webkitTransform = "scale(1.1)"; - this.layout(); - common.defer(function() { - _this.backgroundElement.style.opacity = 1; - _this.domElement.style.opacity = 1; - _this.domElement.style.webkitTransform = "scale(1)"; - }); - }; - CenteredDiv.prototype.hide = function() { - var _this = this; - var hide = function() { - _this.domElement.style.display = "none"; - _this.backgroundElement.style.display = "none"; - dom.unbind(_this.domElement, "webkitTransitionEnd", hide); - dom.unbind(_this.domElement, "transitionend", hide); - dom.unbind(_this.domElement, "oTransitionEnd", hide); - }; - dom.bind(this.domElement, "webkitTransitionEnd", hide); - dom.bind(this.domElement, "transitionend", hide); - dom.bind(this.domElement, "oTransitionEnd", hide); - this.backgroundElement.style.opacity = 0; - this.domElement.style.opacity = 0; - this.domElement.style.webkitTransform = "scale(1.1)"; - }; - CenteredDiv.prototype.layout = function() { - this.domElement.style.left = window.innerWidth / 2 - dom.getWidth(this.domElement) / 2 + "px"; - this.domElement.style.top = window.innerHeight / 2 - dom.getHeight(this.domElement) / 2 + "px"; - }; - function lockScroll(e) { - console.log(e); - } - return CenteredDiv; -}(dat.dom.dom, dat.utils.common), dat.dom.dom, dat.utils.common); - -(function(e) { - "use strict"; - "function" == typeof define && define.amd ? define([ "jquery" ], e) :"object" == typeof exports ? e(require("jquery")) :e(jQuery); -})(function(e, t) { - "use strict"; - if (!e.jstree) { - var i = 0, n = !1, r = !1, s = !1, a = [], o = e("script:last").attr("src"), d = document, l = d.createElement("LI"), c, h; - l.setAttribute("role", "treeitem"), c = d.createElement("I"), c.className = "jstree-icon jstree-ocl", l.appendChild(c), c = d.createElement("A"), c.className = "jstree-anchor", c.setAttribute("href", "#"), h = d.createElement("I"), h.className = "jstree-icon jstree-themeicon", c.appendChild(h), l.appendChild(c), c = h = null, e.jstree = { - version:"3.0.0", - defaults:{ - plugins:[] - }, - plugins:{}, - path:o && -1 !== o.indexOf("/") ? o.replace(/\/[^\/]+$/, "") :"", - idregex:/[\\:&'".,=\- \/]/g - }, e.jstree.create = function(t, n) { - var r = new e.jstree.core(++i), s = n; - return n = e.extend(!0, {}, e.jstree.defaults, n), s && s.plugins && (n.plugins = s.plugins), e.each(n.plugins, function(e, t) { - "core" !== e && (r = r.plugin(t, n[t])); - }), r.init(t, n), r; - }, e.jstree.core = function(e) { - this._id = e, this._cnt = 0, this._data = { - core:{ - themes:{ - name:!1, - dots:!1, - icons:!1 - }, - selected:[], - last_error:{} - } - }; - }, e.jstree.reference = function(i) { - var n = null, r = null; - if (i && i.id && (i = i.id), !r || !r.length) try { - r = e(i); - } catch (s) {} - if (!r || !r.length) try { - r = e("#" + i.replace(e.jstree.idregex, "\\$&")); - } catch (s) {} - return r && r.length && (r = r.closest(".jstree")).length && (r = r.data("jstree")) ? n = r :e(".jstree").each(function() { - var r = e(this).data("jstree"); - return r && r._model.data[i] ? (n = r, !1) :t; - }), n; - }, e.fn.jstree = function(i) { - var n = "string" == typeof i, r = Array.prototype.slice.call(arguments, 1), s = null; - return this.each(function() { - var a = e.jstree.reference(this), o = n && a ? a[i] :null; - return s = n && o ? o.apply(a, r) :null, a || n || i !== t && !e.isPlainObject(i) || e(this).data("jstree", new e.jstree.create(this, i)), (a && !n || i === !0) && (s = a || !1), null !== s && s !== t ? !1 :t; - }), null !== s && s !== t ? s :this; - }, e.expr[":"].jstree = e.expr.createPseudo(function(i) { - return function(i) { - return e(i).hasClass("jstree") && e(i).data("jstree") !== t; - }; - }), e.jstree.defaults.core = { - data:!1, - strings:!1, - check_callback:!1, - error:e.noop, - animation:200, - multiple:!0, - themes:{ - name:!1, - url:!1, - dir:!1, - dots:!0, - icons:!0, - stripes:!1, - variant:!1, - responsive:!0 - }, - expand_selected_onload:!0 - }, e.jstree.core.prototype = { - plugin:function(t, i) { - var n = e.jstree.plugins[t]; - return n ? (this._data[t] = {}, n.prototype = this, new n(i, this)) :this; - }, - init:function(t, i) { - this._model = { - data:{ - "#":{ - id:"#", - parent:null, - parents:[], - children:[], - children_d:[], - state:{ - loaded:!1 - } - } - }, - changed:[], - force_full_redraw:!1, - redraw_timeout:!1, - default_state:{ - loaded:!0, - opened:!1, - selected:!1, - disabled:!1 - } - }, this.element = e(t).addClass("jstree jstree-" + this._id), this.settings = i, this.element.bind("destroyed", e.proxy(this.teardown, this)), this._data.core.ready = !1, this._data.core.loaded = !1, this._data.core.rtl = "rtl" === this.element.css("direction"), this.element[this._data.core.rtl ? "addClass" :"removeClass"]("jstree-rtl"), this.element.attr("role", "tree"), this.bind(), this.trigger("init"), this._data.core.original_container_html = this.element.find(" > ul > li").clone(!0), this._data.core.original_container_html.find("li").addBack().contents().filter(function() { - return 3 === this.nodeType && (!this.nodeValue || /^\s+$/.test(this.nodeValue)); - }).remove(), this.element.html(""), this._data.core.li_height = this.get_container_ul().children("li:eq(0)").height() || 18, this.trigger("loading"), this.load_node("#"); - }, - destroy:function() { - this.element.unbind("destroyed", this.teardown), this.teardown(); - }, - teardown:function() { - this.unbind(), this.element.removeClass("jstree").removeData("jstree").find("[class^='jstree']").addBack().attr("class", function() { - return this.className.replace(/jstree[^ ]*|$/gi, ""); - }), this.element = null; - }, - bind:function() { - this.element.on("dblclick.jstree", function() { - if (document.selection && document.selection.empty) document.selection.empty(); else if (window.getSelection) { - var e = window.getSelection(); - try { - e.removeAllRanges(), e.collapse(); - } catch (t) {} - } - }).on("click.jstree", ".jstree-ocl", e.proxy(function(e) { - this.toggle_node(e.target); - }, this)).on("click.jstree", ".jstree-anchor", e.proxy(function(t) { - t.preventDefault(), e(t.currentTarget).focus(), this.activate_node(t.currentTarget, t); - }, this)).on("keydown.jstree", ".jstree-anchor", e.proxy(function(t) { - if ("INPUT" === t.target.tagName) return !0; - var i = null; - switch (t.which) { - case 13: - case 32: - t.type = "click", e(t.currentTarget).trigger(t); - break; - - case 37: - t.preventDefault(), this.is_open(t.currentTarget) ? this.close_node(t.currentTarget) :(i = this.get_prev_dom(t.currentTarget), i && i.length && i.children(".jstree-anchor").focus()); - break; - - case 38: - t.preventDefault(), i = this.get_prev_dom(t.currentTarget), i && i.length && i.children(".jstree-anchor").focus(); - break; - - case 39: - t.preventDefault(), this.is_closed(t.currentTarget) ? this.open_node(t.currentTarget, function(e) { - this.get_node(e, !0).children(".jstree-anchor").focus(); - }) :(i = this.get_next_dom(t.currentTarget), i && i.length && i.children(".jstree-anchor").focus()); - break; - - case 40: - t.preventDefault(), i = this.get_next_dom(t.currentTarget), i && i.length && i.children(".jstree-anchor").focus(); - break; - - case 46: - t.preventDefault(), i = this.get_node(t.currentTarget), i && i.id && "#" !== i.id && (i = this.is_selected(i) ? this.get_selected() :i); - break; - - case 113: - t.preventDefault(), i = this.get_node(t.currentTarget); - break; - - default: } - }, this)).on("load_node.jstree", e.proxy(function(t, i) { - if (i.status && ("#" !== i.node.id || this._data.core.loaded || (this._data.core.loaded = !0, this.trigger("loaded")), !this._data.core.ready && !this.get_container_ul().find(".jstree-loading:eq(0)").length)) { - if (this._data.core.ready = !0, this._data.core.selected.length) { - if (this.settings.core.expand_selected_onload) { - var n = [], r, s; - for (r = 0, s = this._data.core.selected.length; s > r; r++) n = n.concat(this._model.data[this._data.core.selected[r]].parents); - for (n = e.vakata.array_unique(n), r = 0, s = n.length; s > r; r++) this.open_node(n[r], !1, 0); - } - this.trigger("changed", { - action:"ready", - selected:this._data.core.selected - }); - } - setTimeout(e.proxy(function() { - this.trigger("ready"); - }, this), 0); - } - }, this)).on("init.jstree", e.proxy(function() { - var e = this.settings.core.themes; - this._data.core.themes.dots = e.dots, this._data.core.themes.stripes = e.stripes, this._data.core.themes.icons = e.icons, this.set_theme(e.name || "default", e.url), this.set_theme_variant(e.variant); - }, this)).on("loading.jstree", e.proxy(function() { - this[this._data.core.themes.dots ? "show_dots" :"hide_dots"](), this[this._data.core.themes.icons ? "show_icons" :"hide_icons"](), this[this._data.core.themes.stripes ? "show_stripes" :"hide_stripes"](); - }, this)).on("focus.jstree", ".jstree-anchor", e.proxy(function(t) { - this.element.find(".jstree-hovered").not(t.currentTarget).mouseleave(), e(t.currentTarget).mouseenter(); - }, this)).on("mouseenter.jstree", ".jstree-anchor", e.proxy(function(e) { - this.hover_node(e.currentTarget); - }, this)).on("mouseleave.jstree", ".jstree-anchor", e.proxy(function(e) { - this.dehover_node(e.currentTarget); - }, this)); - }, - unbind:function() { - this.element.off(".jstree"), e(document).off(".jstree-" + this._id); - }, - trigger:function(e, t) { - t || (t = {}), t.instance = this, this.element.triggerHandler(e.replace(".jstree", "") + ".jstree", t); - }, - get_container:function() { - return this.element; - }, - get_container_ul:function() { - return this.element.children("ul:eq(0)"); - }, - get_string:function(t) { - var i = this.settings.core.strings; - return e.isFunction(i) ? i.call(this, t) :i && i[t] ? i[t] :t; - }, - _firstChild:function(e) { - e = e ? e.firstChild :null; - while (null !== e && 1 !== e.nodeType) e = e.nextSibling; - return e; - }, - _nextSibling:function(e) { - e = e ? e.nextSibling :null; - while (null !== e && 1 !== e.nodeType) e = e.nextSibling; - return e; - }, - _previousSibling:function(e) { - e = e ? e.previousSibling :null; - while (null !== e && 1 !== e.nodeType) e = e.previousSibling; - return e; - }, - get_node:function(t, i) { - t && t.id && (t = t.id); - var n; - try { - if (this._model.data[t]) t = this._model.data[t]; else if (((n = e(t, this.element)).length || (n = e("#" + t.replace(e.jstree.idregex, "\\$&"), this.element)).length) && this._model.data[n.closest("li").attr("id")]) t = this._model.data[n.closest("li").attr("id")]; else { - if (!(n = e(t, this.element)).length || !n.hasClass("jstree")) return !1; - t = this._model.data["#"]; - } - return i && (t = "#" === t.id ? this.element :e("#" + t.id.replace(e.jstree.idregex, "\\$&"), this.element)), t; - } catch (r) { - return !1; - } - }, - get_path:function(e, t, i) { - if (e = e.parents ? e :this.get_node(e), !e || "#" === e.id || !e.parents) return !1; - var n, r, s = []; - for (s.push(i ? e.id :e.text), n = 0, r = e.parents.length; r > n; n++) s.push(i ? e.parents[n] :this.get_text(e.parents[n])); - return s = s.reverse().slice(1), t ? s.join(t) :s; - }, - get_next_dom:function(t, i) { - var n; - return t = this.get_node(t, !0), t[0] === this.element[0] ? (n = this._firstChild(this.get_container_ul()[0]), n ? e(n) :!1) :t && t.length ? i ? (n = this._nextSibling(t[0]), n ? e(n) :!1) :t.hasClass("jstree-open") ? (n = this._firstChild(t.children("ul")[0]), n ? e(n) :!1) :null !== (n = this._nextSibling(t[0])) ? e(n) :t.parentsUntil(".jstree", "li").next("li").eq(0) :!1; - }, - get_prev_dom:function(t, i) { - var n; - if (t = this.get_node(t, !0), t[0] === this.element[0]) return n = this.get_container_ul()[0].lastChild, n ? e(n) :!1; - if (!t || !t.length) return !1; - if (i) return n = this._previousSibling(t[0]), n ? e(n) :!1; - if (null !== (n = this._previousSibling(t[0]))) { - t = e(n); - while (t.hasClass("jstree-open")) t = t.children("ul:eq(0)").children("li:last"); - return t; - } - return n = t[0].parentNode.parentNode, n && "LI" === n.tagName ? e(n) :!1; - }, - get_parent:function(e) { - return e = this.get_node(e), e && "#" !== e.id ? e.parent :!1; - }, - get_children_dom:function(e) { - return e = this.get_node(e, !0), e[0] === this.element[0] ? this.get_container_ul().children("li") :e && e.length ? e.children("ul").children("li") :!1; - }, - is_parent:function(e) { - return e = this.get_node(e), e && (e.state.loaded === !1 || e.children.length > 0); - }, - is_loaded:function(e) { - return e = this.get_node(e), e && e.state.loaded; - }, - is_loading:function(e) { - return e = this.get_node(e), e && e.state && e.state.loading; - }, - is_open:function(e) { - return e = this.get_node(e), e && e.state.opened; - }, - is_closed:function(e) { - return e = this.get_node(e), e && this.is_parent(e) && !e.state.opened; - }, - is_leaf:function(e) { - return !this.is_parent(e); - }, - load_node:function(t, i) { - var n, r, s, a, o, d, l; - if (e.isArray(t)) { - for (t = t.slice(), n = 0, r = t.length; r > n; n++) this.load_node(t[n], i); - return !0; - } - if (t = this.get_node(t), !t) return i && i.call(this, t, !1), !1; - if (t.state.loaded) { - for (t.state.loaded = !1, s = 0, a = t.children_d.length; a > s; s++) { - for (o = 0, d = t.parents.length; d > o; o++) this._model.data[t.parents[o]].children_d = e.vakata.array_remove_item(this._model.data[t.parents[o]].children_d, t.children_d[s]); - this._model.data[t.children_d[s]].state.selected && (l = !0, this._data.core.selected = e.vakata.array_remove_item(this._data.core.selected, t.children_d[s])), delete this._model.data[t.children_d[s]]; - } - t.children = [], t.children_d = [], l && this.trigger("changed", { - action:"load_node", - node:t, - selected:this._data.core.selected - }); - } - return t.state.loading = !0, this.get_node(t, !0).addClass("jstree-loading"), this._load_node(t, e.proxy(function(e) { - t.state.loading = !1, t.state.loaded = e; - var n = this.get_node(t, !0); - t.state.loaded && !t.children.length && n && n.length && !n.hasClass("jstree-leaf") && n.removeClass("jstree-closed jstree-open").addClass("jstree-leaf"), n.removeClass("jstree-loading"), this.trigger("load_node", { - node:t, - status:e - }), i && i.call(this, t, e); - }, this)), !0; - }, - _load_nodes:function(e, t, i) { - var n = !0, r = function() { - this._load_nodes(e, t, !0); - }, s = this._model.data, a, o; - for (a = 0, o = e.length; o > a; a++) !s[e[a]] || s[e[a]].state.loaded && i || (this.is_loading(e[a]) || this.load_node(e[a], r), n = !1); - n && (t.done || (t.call(this, e), t.done = !0)); - }, - _load_node:function(t, i) { - var n = this.settings.core.data, r; - return n ? e.isFunction(n) ? n.call(this, t, e.proxy(function(n) { - return n === !1 ? i.call(this, !1) :i.call(this, this["string" == typeof n ? "_append_html_data" :"_append_json_data"](t, "string" == typeof n ? e(n) :n)); - }, this)) :"object" == typeof n ? n.url ? (n = e.extend(!0, {}, n), e.isFunction(n.url) && (n.url = n.url.call(this, t)), e.isFunction(n.data) && (n.data = n.data.call(this, t)), e.ajax(n).done(e.proxy(function(n, r, s) { - var a = s.getResponseHeader("Content-Type"); - return -1 !== a.indexOf("json") || "object" == typeof n ? i.call(this, this._append_json_data(t, n)) :-1 !== a.indexOf("html") || "string" == typeof n ? i.call(this, this._append_html_data(t, e(n))) :(this._data.core.last_error = { - error:"ajax", - plugin:"core", - id:"core_04", - reason:"Could not load node", - data:JSON.stringify({ - id:t.id, - xhr:s - }) - }, i.call(this, !1)); - }, this)).fail(e.proxy(function(e) { - i.call(this, !1), this._data.core.last_error = { - error:"ajax", - plugin:"core", - id:"core_04", - reason:"Could not load node", - data:JSON.stringify({ - id:t.id, - xhr:e - }) - }, this.settings.core.error.call(this, this._data.core.last_error); - }, this))) :(r = e.isArray(n) || e.isPlainObject(n) ? JSON.parse(JSON.stringify(n)) :n, "#" !== t.id && (this._data.core.last_error = { - error:"nodata", - plugin:"core", - id:"core_05", - reason:"Could not load node", - data:JSON.stringify({ - id:t.id - }) - }), i.call(this, "#" === t.id ? this._append_json_data(t, r) :!1)) :"string" == typeof n ? ("#" !== t.id && (this._data.core.last_error = { - error:"nodata", - plugin:"core", - id:"core_06", - reason:"Could not load node", - data:JSON.stringify({ - id:t.id - }) - }), i.call(this, "#" === t.id ? this._append_html_data(t, e(n)) :!1)) :i.call(this, !1) :i.call(this, "#" === t.id ? this._append_html_data(t, this._data.core.original_container_html.clone(!0)) :!1); - }, - _node_changed:function(e) { - e = this.get_node(e), e && this._model.changed.push(e.id); - }, - _append_html_data:function(t, i) { - t = this.get_node(t), t.children = [], t.children_d = []; - var n = i.is("ul") ? i.children() :i, r = t.id, s = [], a = [], o = this._model.data, d = o[r], l = this._data.core.selected.length, c, h, _; - for (n.each(e.proxy(function(t, i) { - c = this._parse_model_from_html(e(i), r, d.parents.concat()), c && (s.push(c), a.push(c), o[c].children_d.length && (a = a.concat(o[c].children_d))); - }, this)), d.children = s, d.children_d = a, h = 0, _ = d.parents.length; _ > h; h++) o[d.parents[h]].children_d = o[d.parents[h]].children_d.concat(a); - return this.trigger("model", { - nodes:a, - parent:r - }), "#" !== r ? (this._node_changed(r), this.redraw()) :(this.get_container_ul().children(".jstree-initial-node").remove(), this.redraw(!0)), this._data.core.selected.length !== l && this.trigger("changed", { - action:"model", - selected:this._data.core.selected - }), !0; - }, - _append_json_data:function(i, n) { - i = this.get_node(i), i.children = [], i.children_d = []; - var r = n, s = i.id, a = [], o = [], d = this._model.data, l = d[s], c = this._data.core.selected.length, h, _, u; - if (r.d && (r = r.d, "string" == typeof r && (r = JSON.parse(r))), e.isArray(r) || (r = [ r ]), r.length && r[0].id !== t && r[0].parent !== t) { - for (_ = 0, u = r.length; u > _; _++) r[_].children || (r[_].children = []), d["" + r[_].id] = r[_]; - for (_ = 0, u = r.length; u > _; _++) d["" + r[_].parent].children.push("" + r[_].id), l.children_d.push("" + r[_].id); - for (_ = 0, u = l.children.length; u > _; _++) h = this._parse_model_from_flat_json(d[l.children[_]], s, l.parents.concat()), o.push(h), d[h].children_d.length && (o = o.concat(d[h].children_d)); - } else { - for (_ = 0, u = r.length; u > _; _++) h = this._parse_model_from_json(r[_], s, l.parents.concat()), h && (a.push(h), o.push(h), d[h].children_d.length && (o = o.concat(d[h].children_d))); - for (l.children = a, l.children_d = o, _ = 0, u = l.parents.length; u > _; _++) d[l.parents[_]].children_d = d[l.parents[_]].children_d.concat(o); - } - return this.trigger("model", { - nodes:o, - parent:s - }), "#" !== s ? (this._node_changed(s), this.redraw()) :this.redraw(!0), this._data.core.selected.length !== c && this.trigger("changed", { - action:"model", - selected:this._data.core.selected - }), !0; - }, - _parse_model_from_html:function(i, n, r) { - r = r ? [].concat(r) :[], n && r.unshift(n); - var s, a, o = this._model.data, d = { - id:!1, - text:!1, - icon:!0, - parent:n, - parents:r, - children:[], - children_d:[], - data:null, - state:{}, - li_attr:{ - id:!1 - }, - a_attr:{ - href:"#" - }, - original:!1 - }, l, c, h; - for (l in this._model.default_state) this._model.default_state.hasOwnProperty(l) && (d.state[l] = this._model.default_state[l]); - if (c = e.vakata.attributes(i, !0), e.each(c, function(i, n) { - return n = e.trim(n), n.length ? (d.li_attr[i] = n, "id" === i && (d.id = "" + n), t) :!0; - }), c = i.children("a").eq(0), c.length && (c = e.vakata.attributes(c, !0), e.each(c, function(t, i) { - i = e.trim(i), i.length && (d.a_attr[t] = i); - })), c = i.children("a:eq(0)").length ? i.children("a:eq(0)").clone() :i.clone(), c.children("ins, i, ul").remove(), c = c.html(), c = e("
    ").html(c), d.text = c.html(), c = i.data(), d.data = c ? e.extend(!0, {}, c) :null, d.state.opened = i.hasClass("jstree-open"), d.state.selected = i.children("a").hasClass("jstree-clicked"), d.state.disabled = i.children("a").hasClass("jstree-disabled"), d.data && d.data.jstree) for (l in d.data.jstree) d.data.jstree.hasOwnProperty(l) && (d.state[l] = d.data.jstree[l]); - c = i.children("a").children(".jstree-themeicon"), c.length && (d.icon = c.hasClass("jstree-themeicon-hidden") ? !1 :c.attr("rel")), d.state.icon && (d.icon = d.state.icon), c = i.children("ul").children("li"); - do h = "j" + this._id + "_" + ++this._cnt; while (o[h]); - return d.id = d.li_attr.id ? "" + d.li_attr.id :h, c.length ? (c.each(e.proxy(function(t, i) { - s = this._parse_model_from_html(e(i), d.id, r), a = this._model.data[s], d.children.push(s), a.children_d.length && (d.children_d = d.children_d.concat(a.children_d)); - }, this)), d.children_d = d.children_d.concat(d.children)) :i.hasClass("jstree-closed") && (d.state.loaded = !1), d.li_attr["class"] && (d.li_attr["class"] = d.li_attr["class"].replace("jstree-closed", "").replace("jstree-open", "")), d.a_attr["class"] && (d.a_attr["class"] = d.a_attr["class"].replace("jstree-clicked", "").replace("jstree-disabled", "")), o[d.id] = d, d.state.selected && this._data.core.selected.push(d.id), d.id; - }, - _parse_model_from_flat_json:function(e, i, n) { - n = n ? n.concat() :[], i && n.unshift(i); - var r = "" + e.id, s = this._model.data, a = this._model.default_state, o, d, l, c, h = { - id:r, - text:e.text || "", - icon:e.icon !== t ? e.icon :!0, - parent:i, - parents:n, - children:e.children || [], - children_d:e.children_d || [], - data:e.data, - state:{}, - li_attr:{ - id:!1 - }, - a_attr:{ - href:"#" - }, - original:!1 - }; - for (o in a) a.hasOwnProperty(o) && (h.state[o] = a[o]); - if (e && e.data && e.data.jstree && e.data.jstree.icon && (h.icon = e.data.jstree.icon), e && e.data && (h.data = e.data, e.data.jstree)) for (o in e.data.jstree) e.data.jstree.hasOwnProperty(o) && (h.state[o] = e.data.jstree[o]); - if (e && "object" == typeof e.state) for (o in e.state) e.state.hasOwnProperty(o) && (h.state[o] = e.state[o]); - if (e && "object" == typeof e.li_attr) for (o in e.li_attr) e.li_attr.hasOwnProperty(o) && (h.li_attr[o] = e.li_attr[o]); - if (h.li_attr.id || (h.li_attr.id = r), e && "object" == typeof e.a_attr) for (o in e.a_attr) e.a_attr.hasOwnProperty(o) && (h.a_attr[o] = e.a_attr[o]); - for (e && e.children && e.children === !0 && (h.state.loaded = !1, h.children = [], h.children_d = []), s[h.id] = h, o = 0, d = h.children.length; d > o; o++) l = this._parse_model_from_flat_json(s[h.children[o]], h.id, n), c = s[l], h.children_d.push(l), c.children_d.length && (h.children_d = h.children_d.concat(c.children_d)); - return delete e.data, delete e.children, s[h.id].original = e, h.state.selected && this._data.core.selected.push(h.id), h.id; - }, - _parse_model_from_json:function(e, i, n) { - n = n ? n.concat() :[], i && n.unshift(i); - var r = !1, s, a, o, d, l = this._model.data, c = this._model.default_state, h; - do r = "j" + this._id + "_" + ++this._cnt; while (l[r]); - h = { - id:!1, - text:"string" == typeof e ? e :"", - icon:"object" == typeof e && e.icon !== t ? e.icon :!0, - parent:i, - parents:n, - children:[], - children_d:[], - data:null, - state:{}, - li_attr:{ - id:!1 - }, - a_attr:{ - href:"#" - }, - original:!1 - }; - for (s in c) c.hasOwnProperty(s) && (h.state[s] = c[s]); - if (e && e.id && (h.id = "" + e.id), e && e.text && (h.text = e.text), e && e.data && e.data.jstree && e.data.jstree.icon && (h.icon = e.data.jstree.icon), e && e.data && (h.data = e.data, e.data.jstree)) for (s in e.data.jstree) e.data.jstree.hasOwnProperty(s) && (h.state[s] = e.data.jstree[s]); - if (e && "object" == typeof e.state) for (s in e.state) e.state.hasOwnProperty(s) && (h.state[s] = e.state[s]); - if (e && "object" == typeof e.li_attr) for (s in e.li_attr) e.li_attr.hasOwnProperty(s) && (h.li_attr[s] = e.li_attr[s]); - if (h.li_attr.id && !h.id && (h.id = "" + h.li_attr.id), h.id || (h.id = r), h.li_attr.id || (h.li_attr.id = h.id), e && "object" == typeof e.a_attr) for (s in e.a_attr) e.a_attr.hasOwnProperty(s) && (h.a_attr[s] = e.a_attr[s]); - if (e && e.children && e.children.length) { - for (s = 0, a = e.children.length; a > s; s++) o = this._parse_model_from_json(e.children[s], h.id, n), d = l[o], h.children.push(o), d.children_d.length && (h.children_d = h.children_d.concat(d.children_d)); - h.children_d = h.children_d.concat(h.children); - } - return e && e.children && e.children === !0 && (h.state.loaded = !1, h.children = [], h.children_d = []), delete e.data, delete e.children, h.original = e, l[h.id] = h, h.state.selected && this._data.core.selected.push(h.id), h.id; - }, - _redraw:function() { - var e = this._model.force_full_redraw ? this._model.data["#"].children.concat([]) :this._model.changed.concat([]), t = document.createElement("UL"), i, n, r; - for (n = 0, r = e.length; r > n; n++) i = this.redraw_node(e[n], !0, this._model.force_full_redraw), i && this._model.force_full_redraw && t.appendChild(i); - this._model.force_full_redraw && (t.className = this.get_container_ul()[0].className, this.element.empty().append(t)), this._model.force_full_redraw = !1, this._model.changed = [], this.trigger("redraw", { - nodes:e - }); - }, - redraw:function(e) { - e && (this._model.force_full_redraw = !0), this._redraw(); - }, - redraw_node:function(t, i, n) { - var r = this.get_node(t), s = !1, a = !1, o = !1, d = !1, c = !1, h = !1, _ = "", u = document, g = this._model.data, f = !1, p = !1; - if (!r) return !1; - if ("#" === r.id) return this.redraw(!0); - if (i = i || 0 === r.children.length, t = document.querySelector ? this.element[0].querySelector("#" + (-1 !== "0123456789".indexOf(r.id[0]) ? "\\3" + r.id[0] + " " + r.id.substr(1).replace(e.jstree.idregex, "\\$&") :r.id.replace(e.jstree.idregex, "\\$&"))) :document.getElementById(r.id)) t = e(t), n || (s = t.parent().parent()[0], s === this.element[0] && (s = null), a = t.index()), i || !r.children.length || t.children("ul").length || (i = !0), i || (o = t.children("UL")[0]), p = t.attr("aria-selected"), f = t.children(".jstree-anchor")[0] === document.activeElement, t.remove(); else if (i = !0, !n) { - if (s = "#" !== r.parent ? e("#" + r.parent.replace(e.jstree.idregex, "\\$&"), this.element)[0] :null, !(null === s || s && g[r.parent].state.opened)) return !1; - a = e.inArray(r.id, null === s ? g["#"].children :g[r.parent].children); - } - t = l.cloneNode(!0), _ = "jstree-node "; - for (d in r.li_attr) if (r.li_attr.hasOwnProperty(d)) { - if ("id" === d) continue; - "class" !== d ? t.setAttribute(d, r.li_attr[d]) :_ += r.li_attr[d]; - } - p && "false" !== p && t.setAttribute("aria-selected", !0), r.state.loaded && !r.children.length ? _ += " jstree-leaf" :(_ += r.state.opened && r.state.loaded ? " jstree-open" :" jstree-closed", t.setAttribute("aria-expanded", r.state.opened && r.state.loaded)), null !== r.parent && g[r.parent].children[g[r.parent].children.length - 1] === r.id && (_ += " jstree-last"), t.id = r.id, t.className = _, _ = (r.state.selected ? " jstree-clicked" :"") + (r.state.disabled ? " jstree-disabled" :""); - for (c in r.a_attr) if (r.a_attr.hasOwnProperty(c)) { - if ("href" === c && "#" === r.a_attr[c]) continue; - "class" !== c ? t.childNodes[1].setAttribute(c, r.a_attr[c]) :_ += " " + r.a_attr[c]; - } - if (_.length && (t.childNodes[1].className = "jstree-anchor " + _), (r.icon && r.icon !== !0 || r.icon === !1) && (r.icon === !1 ? t.childNodes[1].childNodes[0].className += " jstree-themeicon-hidden" :-1 === r.icon.indexOf("/") && -1 === r.icon.indexOf(".") ? t.childNodes[1].childNodes[0].className += " " + r.icon + " jstree-themeicon-custom" :(t.childNodes[1].childNodes[0].style.backgroundImage = "url(" + r.icon + ")", t.childNodes[1].childNodes[0].style.backgroundPosition = "center center", t.childNodes[1].childNodes[0].style.backgroundSize = "auto", t.childNodes[1].childNodes[0].className += " jstree-themeicon-custom")), t.childNodes[1].innerHTML += r.text, i && r.children.length && r.state.opened && r.state.loaded) { - for (h = u.createElement("UL"), h.setAttribute("role", "group"), h.className = "jstree-children", d = 0, c = r.children.length; c > d; d++) h.appendChild(this.redraw_node(r.children[d], i, !0)); - t.appendChild(h); - } - return o && t.appendChild(o), n || (s || (s = this.element[0]), s.getElementsByTagName("UL").length ? s = s.getElementsByTagName("UL")[0] :(d = u.createElement("UL"), d.setAttribute("role", "group"), d.className = "jstree-children", s.appendChild(d), s = d), s.childNodes.length > a ? s.insertBefore(t, s.childNodes[a]) :s.appendChild(t), f && t.childNodes[1].focus()), r.state.opened && !r.state.loaded && (r.state.opened = !1, setTimeout(e.proxy(function() { - this.open_node(r.id, !1, 0); - }, this), 0)), t; - }, - open_node:function(i, n, r) { - var s, a, o, d; - if (e.isArray(i)) { - for (i = i.slice(), s = 0, a = i.length; a > s; s++) this.open_node(i[s], n, r); - return !0; - } - if (i = this.get_node(i), !i || "#" === i.id) return !1; - if (r = r === t ? this.settings.core.animation :r, !this.is_closed(i)) return n && n.call(this, i, !1), !1; - if (this.is_loaded(i)) o = this.get_node(i, !0), d = this, o.length && (i.children.length && !this._firstChild(o.children("ul")[0]) && (i.state.opened = !0, this.redraw_node(i, !0), o = this.get_node(i, !0)), r ? (this.trigger("before_open", { - node:i - }), o.children("ul").css("display", "none").end().removeClass("jstree-closed").addClass("jstree-open").attr("aria-expanded", !0).children("ul").stop(!0, !0).slideDown(r, function() { - this.style.display = "", d.trigger("after_open", { - node:i - }); - })) :(this.trigger("before_open", { - node:i - }), o[0].className = o[0].className.replace("jstree-closed", "jstree-open"), o[0].setAttribute("aria-expanded", !0))), i.state.opened = !0, n && n.call(this, i, !0), o.length || this.trigger("before_open", { - node:i - }), this.trigger("open_node", { - node:i - }), r && o.length || this.trigger("after_open", { - node:i - }); else { - if (this.is_loading(i)) return setTimeout(e.proxy(function() { - this.open_node(i, n, r); - }, this), 500); - this.load_node(i, function(e, t) { - return t ? this.open_node(e, n, r) :n ? n.call(this, e, !1) :!1; - }); - } - }, - _open_to:function(t) { - if (t = this.get_node(t), !t || "#" === t.id) return !1; - var i, n, r = t.parents; - for (i = 0, n = r.length; n > i; i += 1) "#" !== i && this.open_node(r[i], !1, 0); - return e("#" + t.id.replace(e.jstree.idregex, "\\$&"), this.element); - }, - close_node:function(i, n) { - var r, s, a, o; - if (e.isArray(i)) { - for (i = i.slice(), r = 0, s = i.length; s > r; r++) this.close_node(i[r], n); - return !0; - } - return i = this.get_node(i), i && "#" !== i.id ? this.is_closed(i) ? !1 :(n = n === t ? this.settings.core.animation :n, a = this, o = this.get_node(i, !0), o.length && (n ? o.children("ul").attr("style", "display:block !important").end().removeClass("jstree-open").addClass("jstree-closed").attr("aria-expanded", !1).children("ul").stop(!0, !0).slideUp(n, function() { - this.style.display = "", o.children("ul").remove(), a.trigger("after_close", { - node:i - }); - }) :(o[0].className = o[0].className.replace("jstree-open", "jstree-closed"), o.attr("aria-expanded", !1).children("ul").remove())), i.state.opened = !1, this.trigger("close_node", { - node:i - }), n && o.length || this.trigger("after_close", { - node:i - }), t) :!1; - }, - toggle_node:function(i) { - var n, r; - if (e.isArray(i)) { - for (i = i.slice(), n = 0, r = i.length; r > n; n++) this.toggle_node(i[n]); - return !0; - } - return this.is_closed(i) ? this.open_node(i) :this.is_open(i) ? this.close_node(i) :t; - }, - open_all:function(e, t, i) { - if (e || (e = "#"), e = this.get_node(e), !e) return !1; - var n = "#" === e.id ? this.get_container_ul() :this.get_node(e, !0), r, s, a; - if (!n.length) { - for (r = 0, s = e.children_d.length; s > r; r++) this.is_closed(this._model.data[e.children_d[r]]) && (this._model.data[e.children_d[r]].state.opened = !0); - return this.trigger("open_all", { - node:e - }); - } - i = i || n, a = this, n = this.is_closed(e) ? n.find("li.jstree-closed").addBack() :n.find("li.jstree-closed"), n.each(function() { - a.open_node(this, function(e, n) { - n && this.is_parent(e) && this.open_all(e, t, i); - }, t || 0); - }), 0 === i.find("li.jstree-closed").length && this.trigger("open_all", { - node:this.get_node(i) - }); - }, - close_all:function(t, i) { - if (t || (t = "#"), t = this.get_node(t), !t) return !1; - var n = "#" === t.id ? this.get_container_ul() :this.get_node(t, !0), r = this, s, a; - if (!n.length) { - for (s = 0, a = t.children_d.length; a > s; s++) this._model.data[t.children_d[s]].state.opened = !1; - return this.trigger("close_all", { - node:t - }); - } - n = this.is_open(t) ? n.find("li.jstree-open").addBack() :n.find("li.jstree-open"), e(n.get().reverse()).each(function() { - r.close_node(this, i || 0); - }), this.trigger("close_all", { - node:t - }); - }, - is_disabled:function(e) { - return e = this.get_node(e), e && e.state && e.state.disabled; - }, - enable_node:function(i) { - var n, r; - if (e.isArray(i)) { - for (i = i.slice(), n = 0, r = i.length; r > n; n++) this.enable_node(i[n]); - return !0; - } - return i = this.get_node(i), i && "#" !== i.id ? (i.state.disabled = !1, this.get_node(i, !0).children(".jstree-anchor").removeClass("jstree-disabled"), this.trigger("enable_node", { - node:i - }), t) :!1; - }, - disable_node:function(i) { - var n, r; - if (e.isArray(i)) { - for (i = i.slice(), n = 0, r = i.length; r > n; n++) this.disable_node(i[n]); - return !0; - } - return i = this.get_node(i), i && "#" !== i.id ? (i.state.disabled = !0, this.get_node(i, !0).children(".jstree-anchor").addClass("jstree-disabled"), this.trigger("disable_node", { - node:i - }), t) :!1; - }, - activate_node:function(e, i) { - if (this.is_disabled(e)) return !1; - if (this._data.core.last_clicked = this._data.core.last_clicked && this._data.core.last_clicked.id !== t ? this.get_node(this._data.core.last_clicked.id) :null, this._data.core.last_clicked && !this._data.core.last_clicked.state.selected && (this._data.core.last_clicked = null), !this._data.core.last_clicked && this._data.core.selected.length && (this._data.core.last_clicked = this.get_node(this._data.core.selected[this._data.core.selected.length - 1])), this.settings.core.multiple && (i.metaKey || i.ctrlKey || i.shiftKey) && (!i.shiftKey || this._data.core.last_clicked && this.get_parent(e) && this.get_parent(e) === this._data.core.last_clicked.parent)) if (i.shiftKey) { - var n = this.get_node(e).id, r = this._data.core.last_clicked.id, s = this.get_node(this._data.core.last_clicked.parent).children, a = !1, o, d; - for (o = 0, d = s.length; d > o; o += 1) s[o] === n && (a = !a), s[o] === r && (a = !a), a || s[o] === n || s[o] === r ? this.select_node(s[o], !1, !1, i) :this.deselect_node(s[o], !1, !1, i); - } else this.is_selected(e) ? this.deselect_node(e, !1, !1, i) :this.select_node(e, !1, !1, i); else !this.settings.core.multiple && (i.metaKey || i.ctrlKey || i.shiftKey) && this.is_selected(e) ? this.deselect_node(e, !1, !1, i) :(this.deselect_all(!0), this.select_node(e, !1, !1, i), this._data.core.last_clicked = this.get_node(e)); - this.trigger("activate_node", { - node:this.get_node(e) - }); - }, - hover_node:function(e) { - if (e = this.get_node(e, !0), !e || !e.length || e.children(".jstree-hovered").length) return !1; - var t = this.element.find(".jstree-hovered"), i = this.element; - t && t.length && this.dehover_node(t), e.children(".jstree-anchor").addClass("jstree-hovered"), this.trigger("hover_node", { - node:this.get_node(e) - }), setTimeout(function() { - i.attr("aria-activedescendant", e[0].id), e.attr("aria-selected", !0); - }, 0); - }, - dehover_node:function(e) { - return e = this.get_node(e, !0), e && e.length && e.children(".jstree-hovered").length ? (e.attr("aria-selected", !1).children(".jstree-anchor").removeClass("jstree-hovered"), this.trigger("dehover_node", { - node:this.get_node(e) - }), t) :!1; - }, - select_node:function(i, n, r, s) { - var a, o, d, l; - if (e.isArray(i)) { - for (i = i.slice(), o = 0, d = i.length; d > o; o++) this.select_node(i[o], n, r, s); - return !0; - } - return i = this.get_node(i), i && "#" !== i.id ? (a = this.get_node(i, !0), i.state.selected || (i.state.selected = !0, this._data.core.selected.push(i.id), r || (a = this._open_to(i)), a && a.length && a.children(".jstree-anchor").addClass("jstree-clicked"), this.trigger("select_node", { - node:i, - selected:this._data.core.selected, - event:s - }), n || this.trigger("changed", { - action:"select_node", - node:i, - selected:this._data.core.selected, - event:s - })), t) :!1; - }, - deselect_node:function(i, n, r) { - var s, a, o; - if (e.isArray(i)) { - for (i = i.slice(), s = 0, a = i.length; a > s; s++) this.deselect_node(i[s], n, r); - return !0; - } - return i = this.get_node(i), i && "#" !== i.id ? (o = this.get_node(i, !0), i.state.selected && (i.state.selected = !1, this._data.core.selected = e.vakata.array_remove_item(this._data.core.selected, i.id), o.length && o.children(".jstree-anchor").removeClass("jstree-clicked"), this.trigger("deselect_node", { - node:i, - selected:this._data.core.selected, - event:r - }), n || this.trigger("changed", { - action:"deselect_node", - node:i, - selected:this._data.core.selected, - event:r - })), t) :!1; - }, - select_all:function(e) { - var t = this._data.core.selected.concat([]), i, n; - for (this._data.core.selected = this._model.data["#"].children_d.concat(), i = 0, n = this._data.core.selected.length; n > i; i++) this._model.data[this._data.core.selected[i]] && (this._model.data[this._data.core.selected[i]].state.selected = !0); - this.redraw(!0), this.trigger("select_all", { - selected:this._data.core.selected - }), e || this.trigger("changed", { - action:"select_all", - selected:this._data.core.selected, - old_selection:t - }); - }, - deselect_all:function(e) { - var t = this._data.core.selected.concat([]), i, n; - for (i = 0, n = this._data.core.selected.length; n > i; i++) this._model.data[this._data.core.selected[i]] && (this._model.data[this._data.core.selected[i]].state.selected = !1); - this._data.core.selected = [], this.element.find(".jstree-clicked").removeClass("jstree-clicked"), this.trigger("deselect_all", { - selected:this._data.core.selected, - node:t - }), e || this.trigger("changed", { - action:"deselect_all", - selected:this._data.core.selected, - old_selection:t - }); - }, - is_selected:function(e) { - return e = this.get_node(e), e && "#" !== e.id ? e.state.selected :!1; - }, - get_selected:function(t) { - return t ? e.map(this._data.core.selected, e.proxy(function(e) { - return this.get_node(e); - }, this)) :this._data.core.selected; - }, - get_top_selected:function(t) { - var i = this.get_selected(!0), n = {}, r, s, a, o; - for (r = 0, s = i.length; s > r; r++) n[i[r].id] = i[r]; - for (r = 0, s = i.length; s > r; r++) for (a = 0, o = i[r].children_d.length; o > a; a++) n[i[r].children_d[a]] && delete n[i[r].children_d[a]]; - i = []; - for (r in n) n.hasOwnProperty(r) && i.push(r); - return t ? e.map(i, e.proxy(function(e) { - return this.get_node(e); - }, this)) :i; - }, - get_bottom_selected:function(t) { - var i = this.get_selected(!0), n = [], r, s; - for (r = 0, s = i.length; s > r; r++) i[r].children.length || n.push(i[r].id); - return t ? e.map(n, e.proxy(function(e) { - return this.get_node(e); - }, this)) :n; - }, - get_state:function() { - var e = { - core:{ - open:[], - scroll:{ - left:this.element.scrollLeft(), - top:this.element.scrollTop() - }, - selected:[] - } - }, t; - for (t in this._model.data) this._model.data.hasOwnProperty(t) && "#" !== t && (this._model.data[t].state.opened && e.core.open.push(t), this._model.data[t].state.selected && e.core.selected.push(t)); - return e; - }, - set_state:function(i, n) { - if (i) { - if (i.core) { - var r, s, a, o; - if (i.core.open) return e.isArray(i.core.open) ? (r = !0, s = !1, a = this, e.each(i.core.open.concat([]), function(t, o) { - s = a.get_node(o), s && (a.is_loaded(o) ? (a.is_closed(o) && a.open_node(o, !1, 0), i && i.core && i.core.open && e.vakata.array_remove_item(i.core.open, o)) :(a.is_loading(o) || a.open_node(o, e.proxy(function(t, r) { - !r && i && i.core && i.core.open && e.vakata.array_remove_item(i.core.open, t.id), this.set_state(i, n); - }, a), 0), r = !1)); - }), r && (delete i.core.open, this.set_state(i, n)), !1) :(delete i.core.open, this.set_state(i, n), !1); - if (i.core.scroll) return i.core.scroll && i.core.scroll.left !== t && this.element.scrollLeft(i.core.scroll.left), i.core.scroll && i.core.scroll.top !== t && this.element.scrollTop(i.core.scroll.top), delete i.core.scroll, this.set_state(i, n), !1; - if (i.core.selected) return o = this, this.deselect_all(), e.each(i.core.selected, function(e, t) { - o.select_node(t); - }), delete i.core.selected, this.set_state(i, n), !1; - if (e.isEmptyObject(i.core)) return delete i.core, this.set_state(i, n), !1; - } - return e.isEmptyObject(i) ? (i = null, n && n.call(this), this.trigger("set_state"), !1) :!0; - } - return !1; - }, - refresh:function(t) { - this._data.core.state = this.get_state(), this._cnt = 0, this._model.data = { - "#":{ - id:"#", - parent:null, - parents:[], - children:[], - children_d:[], - state:{ - loaded:!1 - } - } - }; - var i = this.get_container_ul()[0].className; - t || this.element.html(""), this.load_node("#", function(t, n) { - n && (this.get_container_ul()[0].className = i, this.set_state(e.extend(!0, {}, this._data.core.state), function() { - this.trigger("refresh"); - })), this._data.core.state = null; - }); - }, - refresh_node:function(t) { - if (t = this.get_node(t), !t || "#" === t.id) return !1; - var i = [], n = this._data.core.selected.concat([]); - t.state.opened === !0 && i.push(t.id), this.get_node(t, !0).find(".jstree-open").each(function() { - i.push(this.id); - }), this._load_nodes(i, e.proxy(function(e) { - this.open_node(e, !1, 0), this.select_node(this._data.core.selected), this.trigger("refresh_node", { - node:t, - nodes:e - }); - }, this)); - }, - set_id:function(t, i) { - if (t = this.get_node(t), !t || "#" === t.id) return !1; - var n, r, s = this._model.data; - for (i = "" + i, s[t.parent].children[e.inArray(t.id, s[t.parent].children)] = i, n = 0, r = t.parents.length; r > n; n++) s[t.parents[n]].children_d[e.inArray(t.id, s[t.parents[n]].children_d)] = i; - for (n = 0, r = t.children.length; r > n; n++) s[t.children[n]].parent = i; - for (n = 0, r = t.children_d.length; r > n; n++) s[t.children_d[n]].parents[e.inArray(t.id, s[t.children_d[n]].parents)] = i; - return n = e.inArray(t.id, this._data.core.selected), -1 !== n && (this._data.core.selected[n] = i), n = this.get_node(t.id, !0), n && n.attr("id", i), delete s[t.id], t.id = i, s[i] = t, !0; - }, - get_text:function(e) { - return e = this.get_node(e), e && "#" !== e.id ? e.text :!1; - }, - set_text:function(t, i) { - var n, r, s, a; - if (e.isArray(t)) { - for (t = t.slice(), n = 0, r = t.length; r > n; n++) this.set_text(t[n], i); - return !0; - } - return t = this.get_node(t), t && "#" !== t.id ? (t.text = i, s = this.get_node(t, !0), s.length && (s = s.children(".jstree-anchor:eq(0)"), a = s.children("I").clone(), s.html(i).prepend(a), this.trigger("set_text", { - obj:t, - text:i - })), !0) :!1; - }, - get_json:function(e, t, i) { - if (e = this.get_node(e || "#"), !e) return !1; - t && t.flat && !i && (i = []); - var n = { - id:e.id, - text:e.text, - icon:this.get_icon(e), - li_attr:e.li_attr, - a_attr:e.a_attr, - state:{}, - data:t && t.no_data ? !1 :e.data - }, r, s; - if (t && t.flat ? n.parent = e.parent :n.children = [], !t || !t.no_state) for (r in e.state) e.state.hasOwnProperty(r) && (n.state[r] = e.state[r]); - if (t && t.no_id && (delete n.id, n.li_attr && n.li_attr.id && delete n.li_attr.id), t && t.flat && "#" !== e.id && i.push(n), !t || !t.no_children) for (r = 0, s = e.children.length; s > r; r++) t && t.flat ? this.get_json(e.children[r], t, i) :n.children.push(this.get_json(e.children[r], t)); - return t && t.flat ? i :"#" === e.id ? n.children :n; - }, - create_node:function(i, n, r, s, a) { - if (null === i && (i = "#"), i = this.get_node(i), !i) return !1; - if (r = r === t ? "last" :r, !("" + r).match(/^(before|after)$/) && !a && !this.is_loaded(i)) return this.load_node(i, function() { - this.create_node(i, n, r, s, !0); - }); - n || (n = { - text:this.get_string("New node") - }), n.text === t && (n.text = this.get_string("New node")); - var o, d, l, c; - switch ("#" === i.id && ("before" === r && (r = "first"), "after" === r && (r = "last")), r) { - case "before": - o = this.get_node(i.parent), r = e.inArray(i.id, o.children), i = o; - break; - - case "after": - o = this.get_node(i.parent), r = e.inArray(i.id, o.children) + 1, i = o; - break; - - case "inside": - case "first": - r = 0; - break; - - case "last": - r = i.children.length; - break; - - default: - r || (r = 0); - } - if (r > i.children.length && (r = i.children.length), n.id || (n.id = !0), !this.check("create_node", n, i, r)) return this.settings.core.error.call(this, this._data.core.last_error), !1; - if (n.id === !0 && delete n.id, n = this._parse_model_from_json(n, i.id, i.parents.concat()), !n) return !1; - for (o = this.get_node(n), d = [], d.push(n), d = d.concat(o.children_d), this.trigger("model", { - nodes:d, - parent:i.id - }), i.children_d = i.children_d.concat(d), l = 0, c = i.parents.length; c > l; l++) this._model.data[i.parents[l]].children_d = this._model.data[i.parents[l]].children_d.concat(d); - for (n = o, o = [], l = 0, c = i.children.length; c > l; l++) o[l >= r ? l + 1 :l] = i.children[l]; - return o[r] = n.id, i.children = o, this.redraw_node(i, !0), s && s.call(this, this.get_node(n)), this.trigger("create_node", { - node:this.get_node(n), - parent:i.id, - position:r - }), n.id; - }, - rename_node:function(t, i) { - var n, r, s; - if (e.isArray(t)) { - for (t = t.slice(), n = 0, r = t.length; r > n; n++) this.rename_node(t[n], i); - return !0; - } - return t = this.get_node(t), t && "#" !== t.id ? (s = t.text, this.check("rename_node", t, this.get_parent(t), i) ? (this.set_text(t, i), this.trigger("rename_node", { - node:t, - text:i, - old:s - }), !0) :(this.settings.core.error.call(this, this._data.core.last_error), !1)) :!1; - }, - delete_node:function(t) { - var i, n, r, s, a, o, d, l, c, h; - if (e.isArray(t)) { - for (t = t.slice(), i = 0, n = t.length; n > i; i++) this.delete_node(t[i]); - return !0; - } - if (t = this.get_node(t), !t || "#" === t.id) return !1; - if (r = this.get_node(t.parent), s = e.inArray(t.id, r.children), h = !1, !this.check("delete_node", t, r, s)) return this.settings.core.error.call(this, this._data.core.last_error), !1; - for (-1 !== s && (r.children = e.vakata.array_remove(r.children, s)), a = t.children_d.concat([]), a.push(t.id), l = 0, c = a.length; c > l; l++) { - for (o = 0, d = t.parents.length; d > o; o++) s = e.inArray(a[l], this._model.data[t.parents[o]].children_d), -1 !== s && (this._model.data[t.parents[o]].children_d = e.vakata.array_remove(this._model.data[t.parents[o]].children_d, s)); - this._model.data[a[l]].state.selected && (h = !0, s = e.inArray(a[l], this._data.core.selected), -1 !== s && (this._data.core.selected = e.vakata.array_remove(this._data.core.selected, s))); - } - for (this.trigger("delete_node", { - node:t, - parent:r.id - }), h && this.trigger("changed", { - action:"delete_node", - node:t, - selected:this._data.core.selected, - parent:r.id - }), l = 0, c = a.length; c > l; l++) delete this._model.data[a[l]]; - return this.redraw_node(r, !0), !0; - }, - check:function(t, i, n, r, s) { - i = i && i.id ? i :this.get_node(i), n = n && n.id ? n :this.get_node(n); - var a = t.match(/^move_node|copy_node|create_node$/i) ? n :i, o = this.settings.core.check_callback; - return "move_node" !== t && "copy_node" !== t || s && s.is_multi || i.id !== n.id && e.inArray(i.id, n.children) !== r && -1 === e.inArray(n.id, i.children_d) ? (a && a.data && (a = a.data), a && a.functions && (a.functions[t] === !1 || a.functions[t] === !0) ? (a.functions[t] === !1 && (this._data.core.last_error = { - error:"check", - plugin:"core", - id:"core_02", - reason:"Node data prevents function: " + t, - data:JSON.stringify({ - chk:t, - pos:r, - obj:i && i.id ? i.id :!1, - par:n && n.id ? n.id :!1 - }) - }), a.functions[t]) :o === !1 || e.isFunction(o) && o.call(this, t, i, n, r, s) === !1 || o && o[t] === !1 ? (this._data.core.last_error = { - error:"check", - plugin:"core", - id:"core_03", - reason:"User config for core.check_callback prevents function: " + t, - data:JSON.stringify({ - chk:t, - pos:r, - obj:i && i.id ? i.id :!1, - par:n && n.id ? n.id :!1 - }) - }, !1) :!0) :(this._data.core.last_error = { - error:"check", - plugin:"core", - id:"core_01", - reason:"Moving parent inside child", - data:JSON.stringify({ - chk:t, - pos:r, - obj:i && i.id ? i.id :!1, - par:n && n.id ? n.id :!1 - }) - }, !1); - }, - last_error:function() { - return this._data.core.last_error; - }, - move_node:function(i, n, r, s, a) { - var o, d, l, c, h, _, u, g, f, p, m, v, y; - if (e.isArray(i)) { - for (i = i.reverse().slice(), o = 0, d = i.length; d > o; o++) this.move_node(i[o], n, r, s, a); - return !0; - } - if (i = i && i.id ? i :this.get_node(i), n = this.get_node(n), r = r === t ? 0 :r, !n || !i || "#" === i.id) return !1; - if (!("" + r).match(/^(before|after)$/) && !a && !this.is_loaded(n)) return this.load_node(n, function() { - this.move_node(i, n, r, s, !0); - }); - if (l = "" + (i.parent || "#"), c = ("" + r).match(/^(before|after)$/) && "#" !== n.id ? this.get_node(n.parent) :n, h = i.instance ? i.instance :this._model.data[i.id] ? this :e.jstree.reference(i.id), _ = !h || !h._id || this._id !== h._id) return this.copy_node(i, n, r, s, a) ? (h && h.delete_node(i), !0) :!1; - switch ("#" === c.id && ("before" === r && (r = "first"), "after" === r && (r = "last")), r) { - case "before": - r = e.inArray(n.id, c.children); - break; - - case "after": - r = e.inArray(n.id, c.children) + 1; - break; - - case "inside": - case "first": - r = 0; - break; - - case "last": - r = c.children.length; - break; - - default: - r || (r = 0); - } - if (r > c.children.length && (r = c.children.length), !this.check("move_node", i, c, r, { - core:!0, - is_multi:h && h._id && h._id !== this._id, - is_foreign:!h || !h._id - })) return this.settings.core.error.call(this, this._data.core.last_error), !1; - if (i.parent === c.id) { - for (u = c.children.concat(), g = e.inArray(i.id, u), -1 !== g && (u = e.vakata.array_remove(u, g), r > g && r--), g = [], f = 0, p = u.length; p > f; f++) g[f >= r ? f + 1 :f] = u[f]; - g[r] = i.id, c.children = g, this._node_changed(c.id), this.redraw("#" === c.id); - } else { - for (g = i.children_d.concat(), g.push(i.id), f = 0, p = i.parents.length; p > f; f++) { - for (u = [], y = h._model.data[i.parents[f]].children_d, m = 0, v = y.length; v > m; m++) -1 === e.inArray(y[m], g) && u.push(y[m]); - h._model.data[i.parents[f]].children_d = u; - } - for (h._model.data[l].children = e.vakata.array_remove_item(h._model.data[l].children, i.id), f = 0, p = c.parents.length; p > f; f++) this._model.data[c.parents[f]].children_d = this._model.data[c.parents[f]].children_d.concat(g); - for (u = [], f = 0, p = c.children.length; p > f; f++) u[f >= r ? f + 1 :f] = c.children[f]; - for (u[r] = i.id, c.children = u, c.children_d.push(i.id), c.children_d = c.children_d.concat(i.children_d), i.parent = c.id, g = c.parents.concat(), g.unshift(c.id), y = i.parents.length, i.parents = g, g = g.concat(), f = 0, p = i.children_d.length; p > f; f++) this._model.data[i.children_d[f]].parents = this._model.data[i.children_d[f]].parents.slice(0, -1 * y), Array.prototype.push.apply(this._model.data[i.children_d[f]].parents, g); - this._node_changed(l), this._node_changed(c.id), this.redraw("#" === l || "#" === c.id); - } - return s && s.call(this, i, c, r), this.trigger("move_node", { - node:i, - parent:c.id, - position:r, - old_parent:l, - is_multi:h && h._id && h._id !== this._id, - is_foreign:!h || !h._id, - old_instance:h, - new_instance:this - }), !0; - }, - copy_node:function(i, n, r, s, a) { - var o, d, l, c, h, _, u, g, f, p, m; - if (e.isArray(i)) { - for (i = i.reverse().slice(), o = 0, d = i.length; d > o; o++) this.copy_node(i[o], n, r, s, a); - return !0; - } - if (i = i && i.id ? i :this.get_node(i), n = this.get_node(n), r = r === t ? 0 :r, !n || !i || "#" === i.id) return !1; - if (!("" + r).match(/^(before|after)$/) && !a && !this.is_loaded(n)) return this.load_node(n, function() { - this.copy_node(i, n, r, s, !0); - }); - switch (g = "" + (i.parent || "#"), f = ("" + r).match(/^(before|after)$/) && "#" !== n.id ? this.get_node(n.parent) :n, p = i.instance ? i.instance :this._model.data[i.id] ? this :e.jstree.reference(i.id), m = !p || !p._id || this._id !== p._id, "#" === f.id && ("before" === r && (r = "first"), "after" === r && (r = "last")), r) { - case "before": - r = e.inArray(n.id, f.children); - break; - - case "after": - r = e.inArray(n.id, f.children) + 1; - break; - - case "inside": - case "first": - r = 0; - break; - - case "last": - r = f.children.length; - break; - - default: - r || (r = 0); - } - if (r > f.children.length && (r = f.children.length), !this.check("copy_node", i, f, r, { - core:!0, - is_multi:p && p._id && p._id !== this._id, - is_foreign:!p || !p._id - })) return this.settings.core.error.call(this, this._data.core.last_error), !1; - if (u = p ? p.get_json(i, { - no_id:!0, - no_data:!0, - no_state:!0 - }) :i, !u) return !1; - if (u.id === !0 && delete u.id, u = this._parse_model_from_json(u, f.id, f.parents.concat()), !u) return !1; - for (c = this.get_node(u), i && i.state && i.state.loaded === !1 && (c.state.loaded = !1), l = [], l.push(u), l = l.concat(c.children_d), this.trigger("model", { - nodes:l, - parent:f.id - }), h = 0, _ = f.parents.length; _ > h; h++) this._model.data[f.parents[h]].children_d = this._model.data[f.parents[h]].children_d.concat(l); - for (l = [], h = 0, _ = f.children.length; _ > h; h++) l[h >= r ? h + 1 :h] = f.children[h]; - return l[r] = c.id, f.children = l, f.children_d.push(c.id), f.children_d = f.children_d.concat(c.children_d), this._node_changed(f.id), this.redraw("#" === f.id), s && s.call(this, c, f, r), this.trigger("copy_node", { - node:c, - original:i, - parent:f.id, - position:r, - old_parent:g, - is_multi:p && p._id && p._id !== this._id, - is_foreign:!p || !p._id, - old_instance:p, - new_instance:this - }), c.id; - }, - cut:function(i) { - if (i || (i = this._data.core.selected.concat()), e.isArray(i) || (i = [ i ]), !i.length) return !1; - var a = [], o, d, l; - for (d = 0, l = i.length; l > d; d++) o = this.get_node(i[d]), o && o.id && "#" !== o.id && a.push(o); - return a.length ? (n = a, s = this, r = "move_node", this.trigger("cut", { - node:i - }), t) :!1; - }, - copy:function(i) { - if (i || (i = this._data.core.selected.concat()), e.isArray(i) || (i = [ i ]), !i.length) return !1; - var a = [], o, d, l; - for (d = 0, l = i.length; l > d; d++) o = this.get_node(i[d]), o && o.id && "#" !== o.id && a.push(o); - return a.length ? (n = a, s = this, r = "copy_node", this.trigger("copy", { - node:i - }), t) :!1; - }, - get_buffer:function() { - return { - mode:r, - node:n, - inst:s - }; - }, - can_paste:function() { - return r !== !1 && n !== !1; - }, - paste:function(e, i) { - return e = this.get_node(e), e && r && r.match(/^(copy_node|move_node)$/) && n ? (this[r](n, e, i) && this.trigger("paste", { - parent:e.id, - node:n, - mode:r - }), n = !1, r = !1, s = !1, t) :!1; - }, - edit:function(i, n) { - if (i = this._open_to(i), !i || !i.length) return !1; - var r = this._data.core.rtl, s = this.element.width(), a = i.children(".jstree-anchor"), o = e(""), d = "string" == typeof n ? n :this.get_text(i), l = e("
    ", { - css:{ - position:"absolute", - top:"-200px", - left:r ? "0px" :"-1000px", - visibility:"hidden" - } - }).appendTo("body"), c = e("", { - value:d, - "class":"jstree-rename-input", - css:{ - padding:"0", - border:"1px solid silver", - "box-sizing":"border-box", - display:"inline-block", - height:this._data.core.li_height + "px", - lineHeight:this._data.core.li_height + "px", - width:"150px" - }, - blur:e.proxy(function() { - var e = o.children(".jstree-rename-input"), t = e.val(); - "" === t && (t = d), l.remove(), o.replaceWith(a), o.remove(), this.set_text(i, d), this.rename_node(i, t) === !1 && this.set_text(i, d); - }, this), - keydown:function(e) { - var t = e.which; - 27 === t && (this.value = d), (27 === t || 13 === t || 37 === t || 38 === t || 39 === t || 40 === t || 32 === t) && e.stopImmediatePropagation(), (27 === t || 13 === t) && (e.preventDefault(), this.blur()); - }, - click:function(e) { - e.stopImmediatePropagation(); - }, - mousedown:function(e) { - e.stopImmediatePropagation(); - }, - keyup:function(e) { - c.width(Math.min(l.text("pW" + this.value).width(), s)); - }, - keypress:function(e) { - return 13 === e.which ? !1 :t; - } - }), h = { - fontFamily:a.css("fontFamily") || "", - fontSize:a.css("fontSize") || "", - fontWeight:a.css("fontWeight") || "", - fontStyle:a.css("fontStyle") || "", - fontStretch:a.css("fontStretch") || "", - fontVariant:a.css("fontVariant") || "", - letterSpacing:a.css("letterSpacing") || "", - wordSpacing:a.css("wordSpacing") || "" - }; - this.set_text(i, ""), o.attr("class", a.attr("class")).append(a.contents().clone()).append(c), a.replaceWith(o), l.css(h), c.css(h).width(Math.min(l.text("pW" + c[0].value).width(), s))[0].select(); - }, - set_theme:function(t, i) { - if (!t) return !1; - if (i === !0) { - var n = this.settings.core.themes.dir; - n || (n = e.jstree.path + "/themes"), i = n + "/" + t + "/style.css"; - } - i && -1 === e.inArray(i, a) && (e("head").append(''), a.push(i)), this._data.core.themes.name && this.element.removeClass("jstree-" + this._data.core.themes.name), this._data.core.themes.name = t, this.element.addClass("jstree-" + t), this.element[this.settings.core.themes.responsive ? "addClass" :"removeClass"]("jstree-" + t + "-responsive"), this.trigger("set_theme", { - theme:t - }); - }, - get_theme:function() { - return this._data.core.themes.name; - }, - set_theme_variant:function(e) { - this._data.core.themes.variant && this.element.removeClass("jstree-" + this._data.core.themes.name + "-" + this._data.core.themes.variant), this._data.core.themes.variant = e, e && this.element.addClass("jstree-" + this._data.core.themes.name + "-" + this._data.core.themes.variant); - }, - get_theme_variant:function() { - return this._data.core.themes.variant; - }, - show_stripes:function() { - this._data.core.themes.stripes = !0, this.get_container_ul().addClass("jstree-striped"); - }, - hide_stripes:function() { - this._data.core.themes.stripes = !1, this.get_container_ul().removeClass("jstree-striped"); - }, - toggle_stripes:function() { - this._data.core.themes.stripes ? this.hide_stripes() :this.show_stripes(); - }, - show_dots:function() { - this._data.core.themes.dots = !0, this.get_container_ul().removeClass("jstree-no-dots"); - }, - hide_dots:function() { - this._data.core.themes.dots = !1, this.get_container_ul().addClass("jstree-no-dots"); - }, - toggle_dots:function() { - this._data.core.themes.dots ? this.hide_dots() :this.show_dots(); - }, - show_icons:function() { - this._data.core.themes.icons = !0, this.get_container_ul().removeClass("jstree-no-icons"); - }, - hide_icons:function() { - this._data.core.themes.icons = !1, this.get_container_ul().addClass("jstree-no-icons"); - }, - toggle_icons:function() { - this._data.core.themes.icons ? this.hide_icons() :this.show_icons(); - }, - set_icon:function(t, i) { - var n, r, s, a; - if (e.isArray(t)) { - for (t = t.slice(), n = 0, r = t.length; r > n; n++) this.set_icon(t[n], i); - return !0; - } - return t = this.get_node(t), t && "#" !== t.id ? (a = t.icon, t.icon = i, s = this.get_node(t, !0).children(".jstree-anchor").children(".jstree-themeicon"), i === !1 ? this.hide_icon(t) :i === !0 ? s.removeClass("jstree-themeicon-custom " + a).css("background", "").removeAttr("rel") :-1 === i.indexOf("/") && -1 === i.indexOf(".") ? (s.removeClass(a).css("background", ""), s.addClass(i + " jstree-themeicon-custom").attr("rel", i)) :(s.removeClass(a).css("background", ""), s.addClass("jstree-themeicon-custom").css("background", "url('" + i + "') center center no-repeat").attr("rel", i)), !0) :!1; - }, - get_icon:function(e) { - return e = this.get_node(e), e && "#" !== e.id ? e.icon :!1; - }, - hide_icon:function(t) { - var i, n; - if (e.isArray(t)) { - for (t = t.slice(), i = 0, n = t.length; n > i; i++) this.hide_icon(t[i]); - return !0; - } - return t = this.get_node(t), t && "#" !== t ? (t.icon = !1, this.get_node(t, !0).children("a").children(".jstree-themeicon").addClass("jstree-themeicon-hidden"), !0) :!1; - }, - show_icon:function(t) { - var i, n, r; - if (e.isArray(t)) { - for (t = t.slice(), i = 0, n = t.length; n > i; i++) this.show_icon(t[i]); - return !0; - } - return t = this.get_node(t), t && "#" !== t ? (r = this.get_node(t, !0), t.icon = r.length ? r.children("a").children(".jstree-themeicon").attr("rel") :!0, t.icon || (t.icon = !0), r.children("a").children(".jstree-themeicon").removeClass("jstree-themeicon-hidden"), !0) :!1; - } - }, e.vakata = {}, e.vakata.attributes = function(t, i) { - t = e(t)[0]; - var n = i ? {} :[]; - return t && t.attributes && e.each(t.attributes, function(t, r) { - -1 === e.inArray(r.nodeName.toLowerCase(), [ "style", "contenteditable", "hasfocus", "tabindex" ]) && null !== r.nodeValue && "" !== e.trim(r.nodeValue) && (i ? n[r.nodeName] = r.nodeValue :n.push(r.nodeName)); - }), n; - }, e.vakata.array_unique = function(e) { - var t = [], i, n, r; - for (i = 0, r = e.length; r > i; i++) { - for (n = 0; i >= n; n++) if (e[i] === e[n]) break; - n === i && t.push(e[i]); - } - return t; - }, e.vakata.array_remove = function(e, t, i) { - var n = e.slice((i || t) + 1 || e.length); - return e.length = 0 > t ? e.length + t :t, e.push.apply(e, n), e; - }, e.vakata.array_remove_item = function(t, i) { - var n = e.inArray(i, t); - return -1 !== n ? e.vakata.array_remove(t, n) :t; - }, function() { - var t = {}, i = function(e) { - e = e.toLowerCase(); - var t = /(chrome)[ \/]([\w.]+)/.exec(e) || /(webkit)[ \/]([\w.]+)/.exec(e) || /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e) || /(msie) ([\w.]+)/.exec(e) || 0 > e.indexOf("compatible") && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e) || []; - return { - browser:t[1] || "", - version:t[2] || "0" - }; - }, n = i(window.navigator.userAgent); - n.browser && (t[n.browser] = !0, t.version = n.version), t.chrome ? t.webkit = !0 :t.webkit && (t.safari = !0), e.vakata.browser = t; - }(), e.vakata.browser.msie && 8 > e.vakata.browser.version && (e.jstree.defaults.core.animation = 0); - var _ = document.createElement("I"); - _.className = "jstree-icon jstree-checkbox", e.jstree.defaults.checkbox = { - visible:!0, - three_state:!0, - whole_node:!0, - keep_selected_style:!0 - }, e.jstree.plugins.checkbox = function(t, i) { - this.bind = function() { - i.bind.call(this), this._data.checkbox.uto = !1, this.element.on("init.jstree", e.proxy(function() { - this._data.checkbox.visible = this.settings.checkbox.visible, this.settings.checkbox.keep_selected_style || this.element.addClass("jstree-checkbox-no-clicked"); - }, this)).on("loading.jstree", e.proxy(function() { - this[this._data.checkbox.visible ? "show_checkboxes" :"hide_checkboxes"](); - }, this)), this.settings.checkbox.three_state && this.element.on("changed.jstree move_node.jstree copy_node.jstree redraw.jstree open_node.jstree", e.proxy(function() { - this._data.checkbox.uto && clearTimeout(this._data.checkbox.uto), this._data.checkbox.uto = setTimeout(e.proxy(this._undetermined, this), 50); - }, this)).on("model.jstree", e.proxy(function(t, i) { - var n = this._model.data, r = n[i.parent], s = i.nodes, a = [], o, d, l, c, h, _; - if (r.state.selected) { - for (d = 0, l = s.length; l > d; d++) n[s[d]].state.selected = !0; - this._data.core.selected = this._data.core.selected.concat(s); - } else for (d = 0, l = s.length; l > d; d++) if (n[s[d]].state.selected) { - for (c = 0, h = n[s[d]].children_d.length; h > c; c++) n[n[s[d]].children_d[c]].state.selected = !0; - this._data.core.selected = this._data.core.selected.concat(n[s[d]].children_d); - } - for (d = 0, l = r.children_d.length; l > d; d++) n[r.children_d[d]].children.length || a.push(n[r.children_d[d]].parent); - for (a = e.vakata.array_unique(a), c = 0, h = a.length; h > c; c++) { - r = n[a[c]]; - while (r && "#" !== r.id) { - for (o = 0, d = 0, l = r.children.length; l > d; d++) o += n[r.children[d]].state.selected; - if (o !== l) break; - r.state.selected = !0, this._data.core.selected.push(r.id), _ = this.get_node(r, !0), _ && _.length && _.children(".jstree-anchor").addClass("jstree-clicked"), r = this.get_node(r.parent); - } - } - this._data.core.selected = e.vakata.array_unique(this._data.core.selected); - }, this)).on("select_node.jstree", e.proxy(function(t, i) { - var n = i.node, r = this._model.data, s = this.get_node(n.parent), a = this.get_node(n, !0), o, d, l, c; - for (this._data.core.selected = e.vakata.array_unique(this._data.core.selected.concat(n.children_d)), o = 0, d = n.children_d.length; d > o; o++) c = r[n.children_d[o]], c.state.selected = !0, c && c.original && c.original.state && c.original.state.undetermined && (c.original.state.undetermined = !1); - while (s && "#" !== s.id) { - for (l = 0, o = 0, d = s.children.length; d > o; o++) l += r[s.children[o]].state.selected; - if (l !== d) break; - s.state.selected = !0, this._data.core.selected.push(s.id), c = this.get_node(s, !0), c && c.length && c.children(".jstree-anchor").addClass("jstree-clicked"), s = this.get_node(s.parent); - } - a.length && a.find(".jstree-anchor").addClass("jstree-clicked"); - }, this)).on("deselect_all.jstree", e.proxy(function(e, t) { - var i = this.get_node("#"), n = this._model.data, r, s, a; - for (r = 0, s = i.children_d.length; s > r; r++) a = n[i.children_d[r]], a && a.original && a.original.state && a.original.state.undetermined && (a.original.state.undetermined = !1); - }, this)).on("deselect_node.jstree", e.proxy(function(t, i) { - var n = i.node, r = this.get_node(n, !0), s, a, o; - for (n && n.original && n.original.state && n.original.state.undetermined && (n.original.state.undetermined = !1), s = 0, a = n.children_d.length; a > s; s++) o = this._model.data[n.children_d[s]], o.state.selected = !1, o && o.original && o.original.state && o.original.state.undetermined && (o.original.state.undetermined = !1); - for (s = 0, a = n.parents.length; a > s; s++) o = this._model.data[n.parents[s]], o.state.selected = !1, o && o.original && o.original.state && o.original.state.undetermined && (o.original.state.undetermined = !1), o = this.get_node(n.parents[s], !0), o && o.length && o.children(".jstree-anchor").removeClass("jstree-clicked"); - for (o = [], s = 0, a = this._data.core.selected.length; a > s; s++) -1 === e.inArray(this._data.core.selected[s], n.children_d) && -1 === e.inArray(this._data.core.selected[s], n.parents) && o.push(this._data.core.selected[s]); - this._data.core.selected = e.vakata.array_unique(o), r.length && r.find(".jstree-anchor").removeClass("jstree-clicked"); - }, this)).on("delete_node.jstree", e.proxy(function(e, t) { - var i = this.get_node(t.parent), n = this._model.data, r, s, a, o; - while (i && "#" !== i.id) { - for (a = 0, r = 0, s = i.children.length; s > r; r++) a += n[i.children[r]].state.selected; - if (a !== s) break; - i.state.selected = !0, this._data.core.selected.push(i.id), o = this.get_node(i, !0), o && o.length && o.children(".jstree-anchor").addClass("jstree-clicked"), i = this.get_node(i.parent); - } - }, this)).on("move_node.jstree", e.proxy(function(t, i) { - var n = i.is_multi, r = i.old_parent, s = this.get_node(i.parent), a = this._model.data, o, d, l, c, h; - if (!n) { - o = this.get_node(r); - while (o && "#" !== o.id) { - for (d = 0, l = 0, c = o.children.length; c > l; l++) d += a[o.children[l]].state.selected; - if (d !== c) break; - o.state.selected = !0, this._data.core.selected.push(o.id), h = this.get_node(o, !0), h && h.length && h.children(".jstree-anchor").addClass("jstree-clicked"), o = this.get_node(o.parent); - } - } - o = s; - while (o && "#" !== o.id) { - for (d = 0, l = 0, c = o.children.length; c > l; l++) d += a[o.children[l]].state.selected; - if (d === c) o.state.selected || (o.state.selected = !0, this._data.core.selected.push(o.id), h = this.get_node(o, !0), h && h.length && h.children(".jstree-anchor").addClass("jstree-clicked")); else { - if (!o.state.selected) break; - o.state.selected = !1, this._data.core.selected = e.vakata.array_remove_item(this._data.core.selected, o.id), h = this.get_node(o, !0), h && h.length && h.children(".jstree-anchor").removeClass("jstree-clicked"); - } - o = this.get_node(o.parent); - } - }, this)); - }, this._undetermined = function() { - var t, i, n = this._model.data, r = this._data.core.selected, s = [], a = this; - for (t = 0, i = r.length; i > t; t++) n[r[t]] && n[r[t]].parents && (s = s.concat(n[r[t]].parents)); - for (this.element.find(".jstree-closed").not(":has(ul)").each(function() { - var e = a.get_node(this), r; - if (e.state.loaded) for (t = 0, i = e.children_d.length; i > t; t++) r = n[e.children_d[t]], !r.state.loaded && r.original && r.original.state && r.original.state.undetermined && r.original.state.undetermined === !0 && (s.push(r.id), s = s.concat(r.parents)); else e.original && e.original.state && e.original.state.undetermined && e.original.state.undetermined === !0 && (s.push(e.id), s = s.concat(e.parents)); - }), s = e.vakata.array_unique(s), s = e.vakata.array_remove_item(s, "#"), this.element.find(".jstree-undetermined").removeClass("jstree-undetermined"), t = 0, i = s.length; i > t; t++) n[s[t]].state.selected || (r = this.get_node(s[t], !0), r && r.length && r.children("a").children(".jstree-checkbox").addClass("jstree-undetermined")); - }, this.redraw_node = function(t, n, r) { - if (t = i.redraw_node.call(this, t, n, r)) { - var s = t.getElementsByTagName("A")[0]; - s.insertBefore(_.cloneNode(!1), s.childNodes[0]); - } - return !r && this.settings.checkbox.three_state && (this._data.checkbox.uto && clearTimeout(this._data.checkbox.uto), this._data.checkbox.uto = setTimeout(e.proxy(this._undetermined, this), 50)), t; - }, this.activate_node = function(t, n) { - return (this.settings.checkbox.whole_node || e(n.target).hasClass("jstree-checkbox")) && (n.ctrlKey = !0), i.activate_node.call(this, t, n); - }, this.show_checkboxes = function() { - this._data.core.themes.checkboxes = !0, this.element.children("ul").removeClass("jstree-no-checkboxes"); - }, this.hide_checkboxes = function() { - this._data.core.themes.checkboxes = !1, this.element.children("ul").addClass("jstree-no-checkboxes"); - }, this.toggle_checkboxes = function() { - this._data.core.themes.checkboxes ? this.hide_checkboxes() :this.show_checkboxes(); - }; - }, e.jstree.defaults.contextmenu = { - select_node:!0, - show_at_node:!0, - items:function(t, i) { - return { - create:{ - separator_before:!1, - separator_after:!0, - _disabled:!1, - label:"Create", - action:function(t) { - var i = e.jstree.reference(t.reference), n = i.get_node(t.reference); - i.create_node(n, {}, "last", function(e) { - setTimeout(function() { - i.edit(e); - }, 0); - }); - } - }, - rename:{ - separator_before:!1, - separator_after:!1, - _disabled:!1, - label:"Rename", - action:function(t) { - var i = e.jstree.reference(t.reference), n = i.get_node(t.reference); - i.edit(n); - } - }, - remove:{ - separator_before:!1, - icon:!1, - separator_after:!1, - _disabled:!1, - label:"Delete", - action:function(t) { - var i = e.jstree.reference(t.reference), n = i.get_node(t.reference); - i.is_selected(n) ? i.delete_node(i.get_selected()) :i.delete_node(n); - } - }, - ccp:{ - separator_before:!0, - icon:!1, - separator_after:!1, - label:"Edit", - action:!1, - submenu:{ - cut:{ - separator_before:!1, - separator_after:!1, - label:"Cut", - action:function(t) { - var i = e.jstree.reference(t.reference), n = i.get_node(t.reference); - i.is_selected(n) ? i.cut(i.get_selected()) :i.cut(n); - } - }, - copy:{ - separator_before:!1, - icon:!1, - separator_after:!1, - label:"Copy", - action:function(t) { - var i = e.jstree.reference(t.reference), n = i.get_node(t.reference); - i.is_selected(n) ? i.copy(i.get_selected()) :i.copy(n); - } - }, - paste:{ - separator_before:!1, - icon:!1, - _disabled:function(t) { - return !e.jstree.reference(t.reference).can_paste(); - }, - separator_after:!1, - label:"Paste", - action:function(t) { - var i = e.jstree.reference(t.reference), n = i.get_node(t.reference); - i.paste(n); - } - } - } - } - }; - } - }, e.jstree.plugins.contextmenu = function(i, n) { - this.bind = function() { - n.bind.call(this); - var t = 0; - this.element.on("contextmenu.jstree", ".jstree-anchor", e.proxy(function(e) { - e.preventDefault(), t = e.ctrlKey ? e.timeStamp :0, this.is_loading(e.currentTarget) || this.show_contextmenu(e.currentTarget, e.pageX, e.pageY, e); - }, this)).on("click.jstree", ".jstree-anchor", e.proxy(function(i) { - this._data.contextmenu.visible && (!t || i.timeStamp - t > 250) && e.vakata.context.hide(); - }, this)), e(document).on("context_hide.vakata", e.proxy(function() { - this._data.contextmenu.visible = !1; - }, this)); - }, this.teardown = function() { - this._data.contextmenu.visible && e.vakata.context.hide(), n.teardown.call(this); - }, this.show_contextmenu = function(i, n, r, s) { - if (i = this.get_node(i), !i || "#" === i.id) return !1; - var a = this.settings.contextmenu, o = this.get_node(i, !0), d = o.children(".jstree-anchor"), l = !1, c = !1; - (a.show_at_node || n === t || r === t) && (l = d.offset(), n = l.left, r = l.top + this._data.core.li_height), this.settings.contextmenu.select_node && !this.is_selected(i) && (this.deselect_all(), this.select_node(i, !1, !1, s)), c = a.items, e.isFunction(c) && (c = c.call(this, i, e.proxy(function(e) { - this._show_contextmenu(i, n, r, e); - }, this))), e.isPlainObject(c) && this._show_contextmenu(i, n, r, c); - }, this._show_contextmenu = function(t, i, n, r) { - var s = this.get_node(t, !0), a = s.children(".jstree-anchor"); - e(document).one("context_show.vakata", e.proxy(function(t, i) { - var n = "jstree-contextmenu jstree-" + this.get_theme() + "-contextmenu"; - e(i.element).addClass(n); - }, this)), this._data.contextmenu.visible = !0, e.vakata.context.show(a, { - x:i, - y:n - }, r), this.trigger("show_contextmenu", { - node:t, - x:i, - y:n - }); - }; - }, function(e) { - var i = !1, n = { - element:!1, - reference:!1, - position_x:0, - position_y:0, - items:[], - html:"", - is_visible:!1 - }; - e.vakata.context = { - settings:{ - hide_onmouseleave:0, - icons:!0 - }, - _trigger:function(t) { - e(document).triggerHandler("context_" + t + ".vakata", { - reference:n.reference, - element:n.element, - position:{ - x:n.position_x, - y:n.position_y - } - }); - }, - _execute:function(t) { - return t = n.items[t], t && (!t._disabled || e.isFunction(t._disabled) && !t._disabled({ - item:t, - reference:n.reference, - element:n.element - })) && t.action ? t.action.call(null, { - item:t, - reference:n.reference, - element:n.element, - position:{ - x:n.position_x, - y:n.position_y - } - }) :!1; - }, - _parse:function(i, r) { - if (!i) return !1; - r || (n.html = "", n.items = []); - var s = "", a = !1, o; - return r && (s += ""), r || (n.html = s, e.vakata.context._trigger("parse")), s.length > 10 ? s :!1; - }, - _show_submenu:function(t) { - if (t = e(t), t.length && t.children("ul").length) { - var n = t.children("ul"), r = t.offset().left + t.outerWidth(), s = t.offset().top, a = n.width(), o = n.height(), d = e(window).width() + e(window).scrollLeft(), l = e(window).height() + e(window).scrollTop(); - i ? t[0 > r - (a + 10 + t.outerWidth()) ? "addClass" :"removeClass"]("vakata-context-left") :t[r + a + 10 > d ? "addClass" :"removeClass"]("vakata-context-right"), s + o + 10 > l && n.css("bottom", "-1px"), n.show(); - } - }, - show:function(t, r, s) { - var a, o, d, l, c, h, _, u, g = !0; - switch (n.element && n.element.length && n.element.width(""), g) { - case !r && !t: - return !1; - - case !!r && !!t: - n.reference = t, n.position_x = r.x, n.position_y = r.y; - break; - - case !r && !!t: - n.reference = t, a = t.offset(), n.position_x = a.left + t.outerHeight(), n.position_y = a.top; - break; - - case !!r && !t: - n.position_x = r.x, n.position_y = r.y; - } - t && !s && e(t).data("vakata_contextmenu") && (s = e(t).data("vakata_contextmenu")), e.vakata.context._parse(s) && n.element.html(n.html), n.items.length && (o = n.element, d = n.position_x, l = n.position_y, c = o.width(), h = o.height(), _ = e(window).width() + e(window).scrollLeft(), u = e(window).height() + e(window).scrollTop(), i && (d -= o.outerWidth(), e(window).scrollLeft() + 20 > d && (d = e(window).scrollLeft() + 20)), d + c + 20 > _ && (d = _ - (c + 20)), l + h + 20 > u && (l = u - (h + 20)), n.element.css({ - left:d, - top:l - }).show().find("a:eq(0)").focus().parent().addClass("vakata-context-hover"), n.is_visible = !0, e.vakata.context._trigger("show")); - }, - hide:function() { - n.is_visible && (n.element.hide().find("ul").hide().end().find(":focus").blur(), n.is_visible = !1, e.vakata.context._trigger("hide")); - } - }, e(function() { - i = "rtl" === e("body").css("direction"); - var t = !1; - n.element = e("
      "), n.element.on("mouseenter", "li", function(i) { - i.stopImmediatePropagation(), e.contains(this, i.relatedTarget) || (t && clearTimeout(t), n.element.find(".vakata-context-hover").removeClass("vakata-context-hover").end(), e(this).siblings().find("ul").hide().end().end().parentsUntil(".vakata-context", "li").addBack().addClass("vakata-context-hover"), e.vakata.context._show_submenu(this)); - }).on("mouseleave", "li", function(t) { - e.contains(this, t.relatedTarget) || e(this).find(".vakata-context-hover").addBack().removeClass("vakata-context-hover"); - }).on("mouseleave", function(i) { - e(this).find(".vakata-context-hover").removeClass("vakata-context-hover"), e.vakata.context.settings.hide_onmouseleave && (t = setTimeout(function(t) { - return function() { - e.vakata.context.hide(); - }; - }(this), e.vakata.context.settings.hide_onmouseleave)); - }).on("click", "a", function(e) { - e.preventDefault(); - }).on("mouseup", "a", function(t) { - e(this).blur().parent().hasClass("vakata-context-disabled") || e.vakata.context._execute(e(this).attr("rel")) === !1 || e.vakata.context.hide(); - }).on("keydown", "a", function(t) { - var i = null; - switch (t.which) { - case 13: - case 32: - t.type = "mouseup", t.preventDefault(), e(t.currentTarget).trigger(t); - break; - - case 37: - n.is_visible && (n.element.find(".vakata-context-hover").last().parents("li:eq(0)").find("ul").hide().find(".vakata-context-hover").removeClass("vakata-context-hover").end().end().children("a").focus(), t.stopImmediatePropagation(), t.preventDefault()); - break; - - case 38: - n.is_visible && (i = n.element.find("ul:visible").addBack().last().children(".vakata-context-hover").removeClass("vakata-context-hover").prevAll("li:not(.vakata-context-separator)").first(), i.length || (i = n.element.find("ul:visible").addBack().last().children("li:not(.vakata-context-separator)").last()), i.addClass("vakata-context-hover").children("a").focus(), t.stopImmediatePropagation(), t.preventDefault()); - break; - - case 39: - n.is_visible && (n.element.find(".vakata-context-hover").last().children("ul").show().children("li:not(.vakata-context-separator)").removeClass("vakata-context-hover").first().addClass("vakata-context-hover").children("a").focus(), t.stopImmediatePropagation(), t.preventDefault()); - break; - - case 40: - n.is_visible && (i = n.element.find("ul:visible").addBack().last().children(".vakata-context-hover").removeClass("vakata-context-hover").nextAll("li:not(.vakata-context-separator)").first(), i.length || (i = n.element.find("ul:visible").addBack().last().children("li:not(.vakata-context-separator)").first()), i.addClass("vakata-context-hover").children("a").focus(), t.stopImmediatePropagation(), t.preventDefault()); - break; - - case 27: - e.vakata.context.hide(), t.preventDefault(); - break; - - default: } - }).on("keydown", function(e) { - e.preventDefault(); - var t = n.element.find(".vakata-contextmenu-shortcut-" + e.which).parent(); - t.parent().not(".vakata-context-disabled") && t.mouseup(); - }).appendTo("body"), e(document).on("mousedown", function(t) { - n.is_visible && !e.contains(n.element[0], t.target) && e.vakata.context.hide(); - }).on("context_show.vakata", function(e, t) { - n.element.find("li:has(ul)").children("a").addClass("vakata-context-parent"), i && n.element.addClass("vakata-context-rtl").css("direction", "rtl"), n.element.find("ul").hide().end(); - }); - }); - }(e), e.jstree.defaults.dnd = { - copy:!0, - open_timeout:500, - is_draggable:!0, - check_while_dragging:!0, - always_copy:!1 - }, e.jstree.plugins.dnd = function(i, n) { - this.bind = function() { - n.bind.call(this), this.element.on("mousedown.jstree touchstart.jstree", ".jstree-anchor", e.proxy(function(i) { - var n = this.get_node(i.target), r = this.is_selected(n) ? this.get_selected().length :1; - return n && n.id && "#" !== n.id && (1 === i.which || "touchstart" === i.type) && (this.settings.dnd.is_draggable === !0 || e.isFunction(this.settings.dnd.is_draggable) && this.settings.dnd.is_draggable.call(this, r > 1 ? this.get_selected(!0) :[ n ])) ? (this.element.trigger("mousedown.jstree"), e.vakata.dnd.start(i, { - jstree:!0, - origin:this, - obj:this.get_node(n, !0), - nodes:r > 1 ? this.get_selected() :[ n.id ] - }, '
      ' + (r > 1 ? r + " " + this.get_string("nodes") :this.get_text(i.currentTarget, !0)) + '
      ')) :t; - }, this)); - }; - }, e(function() { - var i = !1, n = !1, r = !1, s = e('
       
      ').hide().appendTo("body"); - e(document).bind("dnd_start.vakata", function(e, t) { - i = !1; - }).bind("dnd_move.vakata", function(a, o) { - if (r && clearTimeout(r), o.data.jstree && (!o.event.target.id || "jstree-marker" !== o.event.target.id)) { - var d = e.jstree.reference(o.event.target), l = !1, c = !1, h = !1, _, u, g, f, p, m, v, y, j, x, k, b; - if (d && d._data && d._data.dnd) if (s.attr("class", "jstree-" + d.get_theme()), o.helper.children().attr("class", "jstree-" + d.get_theme()).find(".jstree-copy:eq(0)")[o.data.origin && (o.data.origin.settings.dnd.always_copy || o.data.origin.settings.dnd.copy && (o.event.metaKey || o.event.ctrlKey)) ? "show" :"hide"](), o.event.target !== d.element[0] && o.event.target !== d.get_container_ul()[0] || 0 !== d.get_container_ul().children().length) { - if (l = e(o.event.target).closest("a"), l && l.length && l.parent().is(".jstree-closed, .jstree-open, .jstree-leaf") && (c = l.offset(), h = o.event.pageY - c.top, g = l.height(), m = g / 3 > h ? [ "b", "i", "a" ] :h > g - g / 3 ? [ "a", "i", "b" ] :h > g / 2 ? [ "i", "a", "b" ] :[ "i", "b", "a" ], e.each(m, function(a, h) { - switch (h) { - case "b": - _ = c.left - 6, u = c.top - 5, f = d.get_parent(l), p = l.parent().index(); - break; - - case "i": - _ = c.left - 2, u = c.top - 5 + g / 2 + 1, f = d.get_node(l.parent()).id, p = 0; - break; - - case "a": - _ = c.left - 6, u = c.top - 5 + g, f = d.get_parent(l), p = l.parent().index() + 1; - } - for (v = !0, y = 0, j = o.data.nodes.length; j > y; y++) if (x = o.data.origin && (o.data.origin.settings.dnd.always_copy || o.data.origin.settings.dnd.copy && (o.event.metaKey || o.event.ctrlKey)) ? "copy_node" :"move_node", k = p, "move_node" === x && "a" === h && o.data.origin && o.data.origin === d && f === d.get_parent(o.data.nodes[y]) && (b = d.get_node(f), k > e.inArray(o.data.nodes[y], b.children) && (k -= 1)), v = v && (d && d.settings && d.settings.dnd && d.settings.dnd.check_while_dragging === !1 || d.check(x, o.data.origin && o.data.origin !== d ? o.data.origin.get_node(o.data.nodes[y]) :o.data.nodes[y], f, k, { - dnd:!0, - ref:d.get_node(l.parent()), - pos:h, - is_multi:o.data.origin && o.data.origin !== d, - is_foreign:!o.data.origin - })), !v) { - d && d.last_error && (n = d.last_error()); - break; - } - return v ? ("i" === h && l.parent().is(".jstree-closed") && d.settings.dnd.open_timeout && (r = setTimeout(function(e, t) { - return function() { - e.open_node(t); - }; - }(d, l), d.settings.dnd.open_timeout)), i = { - ins:d, - par:f, - pos:p - }, s.css({ - left:_ + "px", - top:u + "px" - }).show(), o.helper.find(".jstree-icon:eq(0)").removeClass("jstree-er").addClass("jstree-ok"), n = {}, m = !0, !1) :t; - }), m === !0)) return; - } else { - for (v = !0, y = 0, j = o.data.nodes.length; j > y; y++) if (v = v && d.check(o.data.origin && (o.data.origin.settings.dnd.always_copy || o.data.origin.settings.dnd.copy && (o.event.metaKey || o.event.ctrlKey)) ? "copy_node" :"move_node", o.data.origin && o.data.origin !== d ? o.data.origin.get_node(o.data.nodes[y]) :o.data.nodes[y], "#", "last", { - dnd:!0, - ref:d.get_node("#"), - pos:"i", - is_multi:o.data.origin && o.data.origin !== d, - is_foreign:!o.data.origin - }), !v) break; - if (v) return i = { - ins:d, - par:"#", - pos:"last" - }, s.hide(), o.helper.find(".jstree-icon:eq(0)").removeClass("jstree-er").addClass("jstree-ok"), t; - } - i = !1, o.helper.find(".jstree-icon").removeClass("jstree-ok").addClass("jstree-er"), s.hide(); - } - }).bind("dnd_scroll.vakata", function(e, t) { - t.data.jstree && (s.hide(), i = !1, t.helper.find(".jstree-icon:eq(0)").removeClass("jstree-ok").addClass("jstree-er")); - }).bind("dnd_stop.vakata", function(t, a) { - if (r && clearTimeout(r), a.data.jstree) { - s.hide(); - var o, d, l = []; - if (i) { - for (o = 0, d = a.data.nodes.length; d > o; o++) l[o] = a.data.origin ? a.data.origin.get_node(a.data.nodes[o]) :a.data.nodes[o], a.data.origin && (l[o].instance = a.data.origin); - i.ins[a.data.origin && (a.data.origin.settings.dnd.always_copy || a.data.origin.settings.dnd.copy && (a.event.metaKey || a.event.ctrlKey)) ? "copy_node" :"move_node"](l, i.par, i.pos); - } else o = e(a.event.target).closest(".jstree"), o.length && n && n.error && "check" === n.error && (o = o.jstree(!0), o && o.settings.core.error.call(this, n)); - } - }).bind("keyup keydown", function(t, i) { - i = e.vakata.dnd._get(), i.data && i.data.jstree && i.helper.find(".jstree-copy:eq(0)")[i.data.origin && (i.data.origin.settings.dnd.always_copy || i.data.origin.settings.dnd.copy && (t.metaKey || t.ctrlKey)) ? "show" :"hide"](); - }); - }), function(e) { - var i = { - element:!1, - is_down:!1, - is_drag:!1, - helper:!1, - helper_w:0, - data:!1, - init_x:0, - init_y:0, - scroll_l:0, - scroll_t:0, - scroll_e:!1, - scroll_i:!1 - }; - e.vakata.dnd = { - settings:{ - scroll_speed:10, - scroll_proximity:20, - helper_left:5, - helper_top:10, - threshold:5 - }, - _trigger:function(t, i) { - var n = e.vakata.dnd._get(); - n.event = i, e(document).triggerHandler("dnd_" + t + ".vakata", n); - }, - _get:function() { - return { - data:i.data, - element:i.element, - helper:i.helper - }; - }, - _clean:function() { - i.helper && i.helper.remove(), i.scroll_i && (clearInterval(i.scroll_i), i.scroll_i = !1), i = { - element:!1, - is_down:!1, - is_drag:!1, - helper:!1, - helper_w:0, - data:!1, - init_x:0, - init_y:0, - scroll_l:0, - scroll_t:0, - scroll_e:!1, - scroll_i:!1 - }, e(document).off("mousemove touchmove", e.vakata.dnd.drag), e(document).off("mouseup touchend", e.vakata.dnd.stop); - }, - _scroll:function(t) { - if (!i.scroll_e || !i.scroll_l && !i.scroll_t) return i.scroll_i && (clearInterval(i.scroll_i), i.scroll_i = !1), !1; - if (!i.scroll_i) return i.scroll_i = setInterval(e.vakata.dnd._scroll, 100), !1; - if (t === !0) return !1; - var n = i.scroll_e.scrollTop(), r = i.scroll_e.scrollLeft(); - i.scroll_e.scrollTop(n + i.scroll_t * e.vakata.dnd.settings.scroll_speed), i.scroll_e.scrollLeft(r + i.scroll_l * e.vakata.dnd.settings.scroll_speed), (n !== i.scroll_e.scrollTop() || r !== i.scroll_e.scrollLeft()) && e.vakata.dnd._trigger("scroll", i.scroll_e); - }, - start:function(t, n, r) { - "touchstart" === t.type && t.originalEvent && t.originalEvent.changedTouches && t.originalEvent.changedTouches[0] && (t.pageX = t.originalEvent.changedTouches[0].pageX, t.pageY = t.originalEvent.changedTouches[0].pageY, t.target = document.elementFromPoint(t.originalEvent.changedTouches[0].pageX - window.pageXOffset, t.originalEvent.changedTouches[0].pageY - window.pageYOffset)), i.is_drag && e.vakata.dnd.stop({}); - try { - t.currentTarget.unselectable = "on", t.currentTarget.onselectstart = function() { - return !1; - }, t.currentTarget.style && (t.currentTarget.style.MozUserSelect = "none"); - } catch (s) {} - return i.init_x = t.pageX, i.init_y = t.pageY, i.data = n, i.is_down = !0, i.element = t.currentTarget, r !== !1 && (i.helper = e("
      ").html(r).css({ - display:"block", - margin:"0", - padding:"0", - position:"absolute", - top:"-2000px", - lineHeight:"16px", - zIndex:"10000" - })), e(document).bind("mousemove touchmove", e.vakata.dnd.drag), e(document).bind("mouseup touchend", e.vakata.dnd.stop), !1; - }, - drag:function(n) { - if ("touchmove" === n.type && n.originalEvent && n.originalEvent.changedTouches && n.originalEvent.changedTouches[0] && (n.pageX = n.originalEvent.changedTouches[0].pageX, n.pageY = n.originalEvent.changedTouches[0].pageY, n.target = document.elementFromPoint(n.originalEvent.changedTouches[0].pageX - window.pageXOffset, n.originalEvent.changedTouches[0].pageY - window.pageYOffset)), i.is_down) { - if (!i.is_drag) { - if (!(Math.abs(n.pageX - i.init_x) > e.vakata.dnd.settings.threshold || Math.abs(n.pageY - i.init_y) > e.vakata.dnd.settings.threshold)) return; - i.helper && (i.helper.appendTo("body"), i.helper_w = i.helper.outerWidth()), i.is_drag = !0, e.vakata.dnd._trigger("start", n); - } - var r = !1, s = !1, a = !1, o = !1, d = !1, l = !1, c = !1, h = !1, _ = !1, u = !1; - i.scroll_t = 0, i.scroll_l = 0, i.scroll_e = !1, e(e(n.target).parentsUntil("body").addBack().get().reverse()).filter(function() { - return /^auto|scroll$/.test(e(this).css("overflow")) && (this.scrollHeight > this.offsetHeight || this.scrollWidth > this.offsetWidth); - }).each(function() { - var r = e(this), s = r.offset(); - return this.scrollHeight > this.offsetHeight && (s.top + r.height() - n.pageY < e.vakata.dnd.settings.scroll_proximity && (i.scroll_t = 1), n.pageY - s.top < e.vakata.dnd.settings.scroll_proximity && (i.scroll_t = -1)), this.scrollWidth > this.offsetWidth && (s.left + r.width() - n.pageX < e.vakata.dnd.settings.scroll_proximity && (i.scroll_l = 1), n.pageX - s.left < e.vakata.dnd.settings.scroll_proximity && (i.scroll_l = -1)), i.scroll_t || i.scroll_l ? (i.scroll_e = e(this), !1) :t; - }), i.scroll_e || (r = e(document), s = e(window), a = r.height(), o = s.height(), d = r.width(), l = s.width(), c = r.scrollTop(), h = r.scrollLeft(), a > o && n.pageY - c < e.vakata.dnd.settings.scroll_proximity && (i.scroll_t = -1), a > o && o - (n.pageY - c) < e.vakata.dnd.settings.scroll_proximity && (i.scroll_t = 1), d > l && n.pageX - h < e.vakata.dnd.settings.scroll_proximity && (i.scroll_l = -1), d > l && l - (n.pageX - h) < e.vakata.dnd.settings.scroll_proximity && (i.scroll_l = 1), (i.scroll_t || i.scroll_l) && (i.scroll_e = r)), i.scroll_e && e.vakata.dnd._scroll(!0), i.helper && (_ = parseInt(n.pageY + e.vakata.dnd.settings.helper_top, 10), u = parseInt(n.pageX + e.vakata.dnd.settings.helper_left, 10), a && _ + 25 > a && (_ = a - 50), d && u + i.helper_w > d && (u = d - (i.helper_w + 2)), i.helper.css({ - left:u + "px", - top:_ + "px" - })), e.vakata.dnd._trigger("move", n); - } - }, - stop:function(t) { - "touchend" === t.type && t.originalEvent && t.originalEvent.changedTouches && t.originalEvent.changedTouches[0] && (t.pageX = t.originalEvent.changedTouches[0].pageX, t.pageY = t.originalEvent.changedTouches[0].pageY, t.target = document.elementFromPoint(t.originalEvent.changedTouches[0].pageX - window.pageXOffset, t.originalEvent.changedTouches[0].pageY - window.pageYOffset)), i.is_drag && e.vakata.dnd._trigger("stop", t), e.vakata.dnd._clean(); - } - }; - }(jQuery), e.jstree.defaults.search = { - ajax:!1, - fuzzy:!0, - case_sensitive:!1, - show_only_matches:!1, - close_opened_onclear:!0, - search_leaves_only:!1 - }, e.jstree.plugins.search = function(t, i) { - this.bind = function() { - i.bind.call(this), this._data.search.str = "", this._data.search.dom = e(), this._data.search.res = [], this._data.search.opn = [], this.element.on("before_open.jstree", e.proxy(function(t, i) { - var n, r, s, a = this._data.search.res, o = [], d = e(); - if (a && a.length) { - for (this._data.search.dom = e(), n = 0, r = a.length; r > n; n++) o = o.concat(this.get_node(a[n]).parents), s = this.get_node(a[n], !0), s && (this._data.search.dom = this._data.search.dom.add(s)); - for (o = e.vakata.array_unique(o), n = 0, r = o.length; r > n; n++) "#" !== o[n] && (s = this.get_node(o[n], !0), s && (d = d.add(s))); - this._data.search.dom.children(".jstree-anchor").addClass("jstree-search"), this.settings.search.show_only_matches && this._data.search.res.length && (this.element.find("li").hide().filter(".jstree-last").filter(function() { - return this.nextSibling; - }).removeClass("jstree-last"), d = d.add(this._data.search.dom), d.parentsUntil(".jstree").addBack().show().filter("ul").each(function() { - e(this).children("li:visible").eq(-1).addClass("jstree-last"); - })); - } - }, this)), this.settings.search.show_only_matches && this.element.on("search.jstree", function(t, i) { - i.nodes.length && (e(this).find("li").hide().filter(".jstree-last").filter(function() { - return this.nextSibling; - }).removeClass("jstree-last"), i.nodes.parentsUntil(".jstree").addBack().show().filter("ul").each(function() { - e(this).children("li:visible").eq(-1).addClass("jstree-last"); - })); - }).on("clear_search.jstree", function(t, i) { - i.nodes.length && e(this).find("li").css("display", "").filter(".jstree-last").filter(function() { - return this.nextSibling; - }).removeClass("jstree-last"); - }); - }, this.search = function(t, i) { - if (t === !1 || "" === e.trim(t)) return this.clear_search(); - var n = this.settings.search, r = n.ajax ? n.ajax :!1, s = null, a = [], o = [], d, l; - if (this._data.search.res.length && this.clear_search(), !i && r !== !1) return e.isFunction(r) ? r.call(this, t, e.proxy(function(i) { - i && i.d && (i = i.d), this._load_nodes(e.isArray(i) ? i :[], function() { - this.search(t, !0); - }); - }, this)) :(r = e.extend({}, r), r.data || (r.data = {}), r.data.str = t, e.ajax(r).fail(e.proxy(function() { - this._data.core.last_error = { - error:"ajax", - plugin:"search", - id:"search_01", - reason:"Could not load search parents", - data:JSON.stringify(r) - }, this.settings.core.error.call(this, this._data.core.last_error); - }, this)).done(e.proxy(function(i) { - i && i.d && (i = i.d), this._load_nodes(e.isArray(i) ? i :[], function() { - this.search(t, !0); - }); - }, this))); - if (this._data.search.str = t, this._data.search.dom = e(), this._data.search.res = [], this._data.search.opn = [], s = new e.vakata.search(t, !0, { - caseSensitive:n.case_sensitive, - fuzzy:n.fuzzy - }), e.each(this._model.data, function(e, t) { - t.text && s.search(t.text).isMatch && (!n.search_leaves_only || t.state.loaded && 0 === t.children.length) && (a.push(e), o = o.concat(t.parents)); - }), a.length) { - for (o = e.vakata.array_unique(o), this._search_open(o), d = 0, l = a.length; l > d; d++) s = this.get_node(a[d], !0), s && (this._data.search.dom = this._data.search.dom.add(s)); - this._data.search.res = a, this._data.search.dom.children(".jstree-anchor").addClass("jstree-search"); - } - this.trigger("search", { - nodes:this._data.search.dom, - str:t, - res:this._data.search.res - }); - }, this.clear_search = function() { - this._data.search.dom.children(".jstree-anchor").removeClass("jstree-search"), this.settings.search.close_opened_onclear && this.close_node(this._data.search.opn, 0), this.trigger("clear_search", { - nodes:this._data.search.dom, - str:this._data.search.str, - res:this._data.search.res - }), this._data.search.str = "", this._data.search.res = [], this._data.search.opn = [], this._data.search.dom = e(); - }, this._search_open = function(t) { - var i = this; - e.each(t.concat([]), function(n, r) { - if ("#" === r) return !0; - try { - r = e("#" + r.replace(e.jstree.idregex, "\\$&"), i.element); - } catch (s) {} - r && r.length && i.is_closed(r) && (i._data.search.opn.push(r[0].id), i.open_node(r, function() { - i._search_open(t); - }, 0)); - }); - }; - }, function(e) { - e.vakata.search = function(e, t, i) { - i = i || {}, i.fuzzy !== !1 && (i.fuzzy = !0), e = i.caseSensitive ? e :e.toLowerCase(); - var n = i.location || 0, r = i.distance || 100, s = i.threshold || .6, a = e.length, o, d, l, c; - return a > 32 && (i.fuzzy = !1), i.fuzzy && (o = 1 << a - 1, d = function() { - var t = {}, i = 0; - for (i = 0; a > i; i++) t[e.charAt(i)] = 0; - for (i = 0; a > i; i++) t[e.charAt(i)] |= 1 << a - i - 1; - return t; - }(), l = function(e, t) { - var i = e / a, s = Math.abs(n - t); - return r ? i + s / r :s ? 1 :i; - }), c = function(t) { - if (t = i.caseSensitive ? t :t.toLowerCase(), e === t || -1 !== t.indexOf(e)) return { - isMatch:!0, - score:0 - }; - if (!i.fuzzy) return { - isMatch:!1, - score:1 - }; - var r, c, h = t.length, _ = s, u = t.indexOf(e, n), g, f, p = a + h, m, v, y, j, x, k = 1, b = []; - for (-1 !== u && (_ = Math.min(l(0, u), _), u = t.lastIndexOf(e, n + a), -1 !== u && (_ = Math.min(l(0, u), _))), u = -1, r = 0; a > r; r++) { - g = 0, f = p; - while (f > g) _ >= l(r, n + f) ? g = f :p = f, f = Math.floor((p - g) / 2 + g); - for (p = f, v = Math.max(1, n - f + 1), y = Math.min(n + f, h) + a, j = Array(y + 2), j[y + 1] = (1 << r) - 1, c = y; c >= v; c--) if (x = d[t.charAt(c - 1)], j[c] = 0 === r ? (1 | j[c + 1] << 1) & x :(1 | j[c + 1] << 1) & x | (1 | (m[c + 1] | m[c]) << 1) | m[c + 1], j[c] & o && (k = l(r, c - 1), _ >= k)) { - if (_ = k, u = c - 1, b.push(u), !(u > n)) break; - v = Math.max(1, 2 * n - u); - } - if (l(r + 1, n) > _) break; - m = j; - } - return { - isMatch:u >= 0, - score:k - }; - }, t === !0 ? { - search:c - } :c(t); - }; - }(jQuery), e.jstree.defaults.sort = function(e, t) { - return this.get_text(e) > this.get_text(t) ? 1 :-1; - }, e.jstree.plugins.sort = function(t, i) { - this.bind = function() { - i.bind.call(this), this.element.on("model.jstree", e.proxy(function(e, t) { - this.sort(t.parent, !0); - }, this)).on("rename_node.jstree create_node.jstree", e.proxy(function(e, t) { - this.sort(t.parent || t.node.parent, !1), this.redraw_node(t.parent || t.node.parent, !0); - }, this)).on("move_node.jstree copy_node.jstree", e.proxy(function(e, t) { - this.sort(t.parent, !1), this.redraw_node(t.parent, !0); - }, this)); - }, this.sort = function(t, i) { - var n, r; - if (t = this.get_node(t), t && t.children && t.children.length && (t.children.sort(e.proxy(this.settings.sort, this)), i)) for (n = 0, r = t.children_d.length; r > n; n++) this.sort(t.children_d[n], !1); - }; - }; - var u = !1; - e.jstree.defaults.state = { - key:"jstree", - events:"changed.jstree open_node.jstree close_node.jstree", - ttl:!1, - filter:!1 - }, e.jstree.plugins.state = function(t, i) { - this.bind = function() { - i.bind.call(this); - var t = e.proxy(function() { - this.element.on(this.settings.state.events, e.proxy(function() { - u && clearTimeout(u), u = setTimeout(e.proxy(function() { - this.save_state(); - }, this), 100); - }, this)); - }, this); - this.element.on("ready.jstree", e.proxy(function(e, i) { - this.element.one("restore_state.jstree", t), this.restore_state() || t(); - }, this)); - }, this.save_state = function() { - var t = { - state:this.get_state(), - ttl:this.settings.state.ttl, - sec:+new Date() - }; - e.vakata.storage.set(this.settings.state.key, JSON.stringify(t)); - }, this.restore_state = function() { - var t = e.vakata.storage.get(this.settings.state.key); - if (t) try { - t = JSON.parse(t); - } catch (i) { - return !1; - } - return t && t.ttl && t.sec && +new Date() - t.sec > t.ttl ? !1 :(t && t.state && (t = t.state), t && e.isFunction(this.settings.state.filter) && (t = this.settings.state.filter.call(this, t)), t ? (this.element.one("set_state.jstree", function(i, n) { - n.instance.trigger("restore_state", { - state:e.extend(!0, {}, t) - }); - }), this.set_state(t), !0) :!1); - }, this.clear_state = function() { - return e.vakata.storage.del(this.settings.state.key); - }; - }, function(e, t) { - e.vakata.storage = { - set:function(e, t) { - return window.localStorage.setItem(e, t); - }, - get:function(e) { - return window.localStorage.getItem(e); - }, - del:function(e) { - return window.localStorage.removeItem(e); - } - }; - }(jQuery), e.jstree.defaults.types = { - "#":{}, - "default":{} - }, e.jstree.plugins.types = function(i, n) { - this.init = function(e, i) { - var r, s; - if (i && i.types && i.types["default"]) for (r in i.types) if ("default" !== r && "#" !== r && i.types.hasOwnProperty(r)) for (s in i.types["default"]) i.types["default"].hasOwnProperty(s) && i.types[r][s] === t && (i.types[r][s] = i.types["default"][s]); - n.init.call(this, e, i), this._model.data["#"].type = "#"; - }, this.refresh = function(e) { - n.refresh.call(this, e), this._model.data["#"].type = "#"; - }, this.bind = function() { - this.element.on("model.jstree", e.proxy(function(e, i) { - var n = this._model.data, r = i.nodes, s = this.settings.types, a, o, d = "default"; - for (a = 0, o = r.length; o > a; a++) d = "default", n[r[a]].original && n[r[a]].original.type && s[n[r[a]].original.type] && (d = n[r[a]].original.type), n[r[a]].data && n[r[a]].data.jstree && n[r[a]].data.jstree.type && s[n[r[a]].data.jstree.type] && (d = n[r[a]].data.jstree.type), n[r[a]].type = d, n[r[a]].icon === !0 && s[d].icon !== t && (n[r[a]].icon = s[d].icon); - }, this)), n.bind.call(this); - }, this.get_json = function(t, i, r) { - var s, a, o = this._model.data, d = i ? e.extend(!0, {}, i, { - no_id:!1 - }) :{}, l = n.get_json.call(this, t, d, r); - if (l === !1) return !1; - if (e.isArray(l)) for (s = 0, a = l.length; a > s; s++) l[s].type = l[s].id && o[l[s].id] && o[l[s].id].type ? o[l[s].id].type :"default", i && i.no_id && (delete l[s].id, l[s].li_attr && l[s].li_attr.id && delete l[s].li_attr.id); else l.type = l.id && o[l.id] && o[l.id].type ? o[l.id].type :"default", i && i.no_id && (l = this._delete_ids(l)); - return l; - }, this._delete_ids = function(t) { - if (e.isArray(t)) { - for (var i = 0, n = t.length; n > i; i++) t[i] = this._delete_ids(t[i]); - return t; - } - return delete t.id, t.li_attr && t.li_attr.id && delete t.li_attr.id, t.children && e.isArray(t.children) && (t.children = this._delete_ids(t.children)), t; - }, this.check = function(i, r, s, a, o) { - if (n.check.call(this, i, r, s, a, o) === !1) return !1; - r = r && r.id ? r :this.get_node(r), s = s && s.id ? s :this.get_node(s); - var d = r && r.id ? e.jstree.reference(r.id) :null, l, c, h, _; - switch (d = d && d._model && d._model.data ? d._model.data :null, i) { - case "create_node": - case "move_node": - case "copy_node": - if ("move_node" !== i || -1 === e.inArray(r.id, s.children)) { - if (l = this.get_rules(s), l.max_children !== t && -1 !== l.max_children && l.max_children === s.children.length) return this._data.core.last_error = { - error:"check", - plugin:"types", - id:"types_01", - reason:"max_children prevents function: " + i, - data:JSON.stringify({ - chk:i, - pos:a, - obj:r && r.id ? r.id :!1, - par:s && s.id ? s.id :!1 - }) - }, !1; - if (l.valid_children !== t && -1 !== l.valid_children && -1 === e.inArray(r.type, l.valid_children)) return this._data.core.last_error = { - error:"check", - plugin:"types", - id:"types_02", - reason:"valid_children prevents function: " + i, - data:JSON.stringify({ - chk:i, - pos:a, - obj:r && r.id ? r.id :!1, - par:s && s.id ? s.id :!1 - }) - }, !1; - if (d && r.children_d && r.parents) { - for (c = 0, h = 0, _ = r.children_d.length; _ > h; h++) c = Math.max(c, d[r.children_d[h]].parents.length); - c = c - r.parents.length + 1; - } - (0 >= c || c === t) && (c = 1); - do { - if (l.max_depth !== t && -1 !== l.max_depth && c > l.max_depth) return this._data.core.last_error = { - error:"check", - plugin:"types", - id:"types_03", - reason:"max_depth prevents function: " + i, - data:JSON.stringify({ - chk:i, - pos:a, - obj:r && r.id ? r.id :!1, - par:s && s.id ? s.id :!1 - }) - }, !1; - s = this.get_node(s.parent), l = this.get_rules(s), c++; - } while (s); - } - } - return !0; - }, this.get_rules = function(e) { - if (e = this.get_node(e), !e) return !1; - var i = this.get_type(e, !0); - return i.max_depth === t && (i.max_depth = -1), i.max_children === t && (i.max_children = -1), i.valid_children === t && (i.valid_children = -1), i; - }, this.get_type = function(t, i) { - return t = this.get_node(t), t ? i ? e.extend({ - type:t.type - }, this.settings.types[t.type]) :t.type :!1; - }, this.set_type = function(i, n) { - var r, s, a, o, d; - if (e.isArray(i)) { - for (i = i.slice(), s = 0, a = i.length; a > s; s++) this.set_type(i[s], n); - return !0; - } - return r = this.settings.types, i = this.get_node(i), r[n] && i ? (o = i.type, d = this.get_icon(i), i.type = n, (d === !0 || r[o] && r[o].icon && d === r[o].icon) && this.set_icon(i, r[n].icon !== t ? r[n].icon :!0), !0) :!1; - }; - }, e.jstree.plugins.unique = function(t, i) { - this.check = function(t, n, r, s, a) { - if (i.check.call(this, t, n, r, s, a) === !1) return !1; - if (n = n && n.id ? n :this.get_node(n), r = r && r.id ? r :this.get_node(r), !r || !r.children) return !0; - var o = "rename_node" === t ? s :n.text, d = [], l = this._model.data, c, h; - for (c = 0, h = r.children.length; h > c; c++) d.push(l[r.children[c]].text); - switch (t) { - case "delete_node": - return !0; - - case "rename_node": - case "copy_node": - return c = -1 === e.inArray(o, d), c || (this._data.core.last_error = { - error:"check", - plugin:"unique", - id:"unique_01", - reason:"Child with name " + o + " already exists. Preventing: " + t, - data:JSON.stringify({ - chk:t, - pos:s, - obj:n && n.id ? n.id :!1, - par:r && r.id ? r.id :!1 - }) - }), c; - - case "move_node": - return c = n.parent === r.id || -1 === e.inArray(o, d), c || (this._data.core.last_error = { - error:"check", - plugin:"unique", - id:"unique_01", - reason:"Child with name " + o + " already exists. Preventing: " + t, - data:JSON.stringify({ - chk:t, - pos:s, - obj:n && n.id ? n.id :!1, - par:r && r.id ? r.id :!1 - }) - }), c; - } - return !0; - }; - }; - var g = document.createElement("DIV"); - g.setAttribute("unselectable", "on"), g.className = "jstree-wholerow", g.innerHTML = " ", e.jstree.plugins.wholerow = function(t, i) { - this.bind = function() { - i.bind.call(this), this.element.on("loading", e.proxy(function() { - g.style.height = this._data.core.li_height + "px"; - }, this)).on("ready.jstree set_state.jstree", e.proxy(function() { - this.hide_dots(); - }, this)).on("ready.jstree", e.proxy(function() { - this.get_container_ul().addClass("jstree-wholerow-ul"); - }, this)).on("deselect_all.jstree", e.proxy(function(e, t) { - this.element.find(".jstree-wholerow-clicked").removeClass("jstree-wholerow-clicked"); - }, this)).on("changed.jstree", e.proxy(function(e, t) { - this.element.find(".jstree-wholerow-clicked").removeClass("jstree-wholerow-clicked"); - var i = !1, n, r; - for (n = 0, r = t.selected.length; r > n; n++) i = this.get_node(t.selected[n], !0), i && i.length && i.children(".jstree-wholerow").addClass("jstree-wholerow-clicked"); - }, this)).on("open_node.jstree", e.proxy(function(e, t) { - this.get_node(t.node, !0).find(".jstree-clicked").parent().children(".jstree-wholerow").addClass("jstree-wholerow-clicked"); - }, this)).on("hover_node.jstree dehover_node.jstree", e.proxy(function(e, t) { - this.get_node(t.node, !0).children(".jstree-wholerow")["hover_node" === e.type ? "addClass" :"removeClass"]("jstree-wholerow-hovered"); - }, this)).on("contextmenu.jstree", ".jstree-wholerow", e.proxy(function(t) { - t.preventDefault(); - var i = e.Event("contextmenu", { - metaKey:t.metaKey, - ctrlKey:t.ctrlKey, - altKey:t.altKey, - shiftKey:t.shiftKey, - pageX:t.pageX, - pageY:t.pageY - }); - e(t.currentTarget).closest("li").children("a:eq(0)").trigger(i); - }, this)).on("click.jstree", ".jstree-wholerow", function(t) { - t.stopImmediatePropagation(); - var i = e.Event("click", { - metaKey:t.metaKey, - ctrlKey:t.ctrlKey, - altKey:t.altKey, - shiftKey:t.shiftKey - }); - e(t.currentTarget).closest("li").children("a:eq(0)").trigger(i).focus(); - }).on("click.jstree", ".jstree-leaf > .jstree-ocl", e.proxy(function(t) { - t.stopImmediatePropagation(); - var i = e.Event("click", { - metaKey:t.metaKey, - ctrlKey:t.ctrlKey, - altKey:t.altKey, - shiftKey:t.shiftKey - }); - e(t.currentTarget).closest("li").children("a:eq(0)").trigger(i).focus(); - }, this)).on("mouseover.jstree", ".jstree-wholerow, .jstree-icon", e.proxy(function(e) { - return e.stopImmediatePropagation(), this.hover_node(e.currentTarget), !1; - }, this)).on("mouseleave.jstree", ".jstree-node", e.proxy(function(e) { - this.dehover_node(e.currentTarget); - }, this)); - }, this.teardown = function() { - this.settings.wholerow && this.element.find(".jstree-wholerow").remove(), i.teardown.call(this); - }, this.redraw_node = function(t, n, r) { - if (t = i.redraw_node.call(this, t, n, r)) { - var s = g.cloneNode(!0); - -1 !== e.inArray(t.id, this._data.core.selected) && (s.className += " jstree-wholerow-clicked"), t.insertBefore(s, t.childNodes[0]); - } - return t; - }; - }; - } -}); - -(function(global) { - var k, _handlers = {}, _mods = { - 16:false, - 18:false, - 17:false, - 91:false - }, _scope = "all", _MODIFIERS = { - "⇧":16, - shift:16, - "⌥":18, - alt:18, - option:18, - "⌃":17, - ctrl:17, - control:17, - "⌘":91, - command:91 - }, _MAP = { - backspace:8, - tab:9, - clear:12, - enter:13, - "return":13, - esc:27, - escape:27, - space:32, - left:37, - up:38, - right:39, - down:40, - del:46, - "delete":46, - home:36, - end:35, - pageup:33, - pagedown:34, - ",":188, - ".":190, - "/":191, - "`":192, - "-":189, - "=":187, - ";":186, - "'":222, - "[":219, - "]":221, - "\\":220 - }, code = function(x) { - return _MAP[x] || x.toUpperCase().charCodeAt(0); - }, _downKeys = []; - for (k = 1; k < 20; k++) _MAP["f" + k] = 111 + k; - function index(array, item) { - var i = array.length; - while (i--) if (array[i] === item) return i; - return -1; - } - function compareArray(a1, a2) { - if (a1.length != a2.length) return false; - for (var i = 0; i < a1.length; i++) { - if (a1[i] !== a2[i]) return false; - } - return true; - } - var modifierMap = { - 16:"shiftKey", - 18:"altKey", - 17:"ctrlKey", - 91:"metaKey" - }; - function updateModifierKey(event) { - for (k in _mods) _mods[k] = event[modifierMap[k]]; - } - function dispatch(event) { - var key, handler, k, i, modifiersMatch, scope; - key = event.keyCode; - if (index(_downKeys, key) == -1) { - _downKeys.push(key); - } - if (key == 93 || key == 224) key = 91; - if (key in _mods) { - _mods[key] = true; - for (k in _MODIFIERS) if (_MODIFIERS[k] == key) assignKey[k] = true; - return; - } - updateModifierKey(event); - if (!assignKey.filter.call(this, event)) return; - if (!(key in _handlers)) return; - scope = getScope(); - for (i = 0; i < _handlers[key].length; i++) { - handler = _handlers[key][i]; - if (handler.scope == scope || handler.scope == "all") { - modifiersMatch = handler.mods.length > 0; - for (k in _mods) if (!_mods[k] && index(handler.mods, +k) > -1 || _mods[k] && index(handler.mods, +k) == -1) modifiersMatch = false; - if (handler.mods.length == 0 && !_mods[16] && !_mods[18] && !_mods[17] && !_mods[91] || modifiersMatch) { - if (handler.method(event, handler) === false) { - if (event.preventDefault) event.preventDefault(); else event.returnValue = false; - if (event.stopPropagation) event.stopPropagation(); - if (event.cancelBubble) event.cancelBubble = true; - } - } - } - } - } - function clearModifier(event) { - var key = event.keyCode, k, i = index(_downKeys, key); - if (i >= 0) { - _downKeys.splice(i, 1); - } - if (key == 93 || key == 224) key = 91; - if (key in _mods) { - _mods[key] = false; - for (k in _MODIFIERS) if (_MODIFIERS[k] == key) assignKey[k] = false; - } - } - function resetModifiers() { - for (k in _mods) _mods[k] = false; - for (k in _MODIFIERS) assignKey[k] = false; - } - function assignKey(key, scope, method) { - var keys, mods; - keys = getKeys(key); - if (method === undefined) { - method = scope; - scope = "all"; - } - for (var i = 0; i < keys.length; i++) { - mods = []; - key = keys[i].split("+"); - if (key.length > 1) { - mods = getMods(key); - key = [ key[key.length - 1] ]; - } - key = key[0]; - key = code(key); - if (!(key in _handlers)) _handlers[key] = []; - _handlers[key].push({ - shortcut:keys[i], - scope:scope, - method:method, - key:keys[i], - mods:mods - }); - } - } - function unbindKey(key, scope) { - var multipleKeys, keys, mods = [], i, j, obj; - multipleKeys = getKeys(key); - for (j = 0; j < multipleKeys.length; j++) { - keys = multipleKeys[j].split("+"); - if (keys.length > 1) { - mods = getMods(keys); - key = keys[keys.length - 1]; - } - key = code(key); - if (scope === undefined) { - scope = getScope(); - } - if (!_handlers[key]) { - return; - } - for (i = 0; i < _handlers[key].length; i++) { - obj = _handlers[key][i]; - if (obj.scope === scope && compareArray(obj.mods, mods)) { - _handlers[key][i] = {}; - } - } - } - } - function isPressed(keyCode) { - if (typeof keyCode == "string") { - keyCode = code(keyCode); - } - return index(_downKeys, keyCode) != -1; - } - function getPressedKeyCodes() { - return _downKeys.slice(0); - } - function filter(event) { - var tagName = (event.target || event.srcElement).tagName; - return !(tagName == "INPUT" || tagName == "SELECT" || tagName == "TEXTAREA"); - } - for (k in _MODIFIERS) assignKey[k] = false; - function setScope(scope) { - _scope = scope || "all"; - } - function getScope() { - return _scope || "all"; - } - function deleteScope(scope) { - var key, handlers, i; - for (key in _handlers) { - handlers = _handlers[key]; - for (i = 0; i < handlers.length; ) { - if (handlers[i].scope === scope) handlers.splice(i, 1); else i++; - } - } - } - function getKeys(key) { - var keys; - key = key.replace(/\s/g, ""); - keys = key.split(","); - if (keys[keys.length - 1] == "") { - keys[keys.length - 2] += ","; - } - return keys; - } - function getMods(key) { - var mods = key.slice(0, key.length - 1); - for (var mi = 0; mi < mods.length; mi++) mods[mi] = _MODIFIERS[mods[mi]]; - return mods; - } - function addEvent(object, event, method) { - if (object.addEventListener) object.addEventListener(event, method, false); else if (object.attachEvent) object.attachEvent("on" + event, function() { - method(window.event); - }); - } - addEvent(document, "keydown", function(event) { - dispatch(event); - }); - addEvent(document, "keyup", clearModifier); - addEvent(window, "focus", resetModifiers); - var previousKey = global.key; - function noConflict() { - var k = global.key; - global.key = previousKey; - return k; - } - global.key = assignKey; - global.key.setScope = setScope; - global.key.getScope = getScope; - global.key.deleteScope = deleteScope; - global.key.filter = filter; - global.key.isPressed = isPressed; - global.key.getPressedKeyCodes = getPressedKeyCodes; - global.key.noConflict = noConflict; - global.key.unbind = unbindKey; - if (typeof module !== "undefined") module.exports = key; -})(this); - -function Resurrect(options) { - this.table = null; - this.prefix = "#"; - this.cleanup = false; - this.revive = true; - for (var option in options) { - if (options.hasOwnProperty(option)) { - this[option] = options[option]; - } - } - this.refcode = this.prefix + "id"; - this.origcode = this.prefix + "original"; - this.buildcode = this.prefix + "."; - this.valuecode = this.prefix + "v"; -} - -Resurrect.GLOBAL = (0, eval)("this"); - -Resurrect.escapeRegExp = function(string) { - return string.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); -}; - -Resurrect.prototype.Error = function ResurrectError(message) { - this.message = message || ""; - this.stack = new Error().stack; -}; - -Resurrect.prototype.Error.prototype = Object.create(Error.prototype); - -Resurrect.prototype.Error.prototype.name = "ResurrectError"; - -Resurrect.NamespaceResolver = function(scope) { - this.scope = scope; -}; - -Resurrect.NamespaceResolver.prototype.getPrototype = function(name) { - var constructor = this.scope[name]; - if (constructor) { - return constructor.prototype; - } else { - throw new Resurrect.prototype.Error("Unknown constructor: " + name); - } -}; - -Resurrect.NamespaceResolver.prototype.getName = function(object) { - var constructor = object.constructor.name; - if (constructor == null) { - var funcPattern = /^\s*function\s*([A-Za-z0-9_$]*)/; - constructor = funcPattern.exec(object.constructor)[1]; - } - if (constructor === "") { - var msg = "Can't serialize objects with anonymous constructors."; - throw new Resurrect.prototype.Error(msg); - } else if (constructor === "Object" || constructor === "Array") { - return null; - } else { - return constructor; - } -}; - -Resurrect.prototype.resolver = new Resurrect.NamespaceResolver(Resurrect.GLOBAL); - -Resurrect.Node = function(html) { - var div = document.createElement("div"); - div.innerHTML = html; - return div.firstChild; -}; - -Resurrect.is = function(type) { - var string = "[object " + type + "]"; - return function(object) { - return Object.prototype.toString.call(object) === string; - }; -}; - -Resurrect.isArray = Resurrect.is("Array"); - -Resurrect.isString = Resurrect.is("String"); - -Resurrect.isBoolean = Resurrect.is("Boolean"); - -Resurrect.isNumber = Resurrect.is("Number"); - -Resurrect.isFunction = Resurrect.is("Function"); - -Resurrect.isDate = Resurrect.is("Date"); - -Resurrect.isRegExp = Resurrect.is("RegExp"); - -Resurrect.isObject = Resurrect.is("Object"); - -Resurrect.isAtom = function(object) { - return !Resurrect.isObject(object) && !Resurrect.isArray(object); -}; - -Resurrect.isPrimitive = function(object) { - return object == null || Resurrect.isNumber(object) || Resurrect.isString(object) || Resurrect.isBoolean(object); -}; - -Resurrect.prototype.ref = function(object) { - var ref = {}; - if (object === undefined) { - ref[this.prefix] = -1; - } else { - ref[this.prefix] = object[this.refcode]; - } - return ref; -}; - -Resurrect.prototype.deref = function(ref) { - return this.table[ref[this.prefix]]; -}; - -Resurrect.prototype.tag = function(object) { - if (this.revive) { - var constructor = this.resolver.getName(object); - if (constructor) { - var proto = Object.getPrototypeOf(object); - if (this.resolver.getPrototype(constructor) !== proto) { - throw new this.Error("Constructor mismatch!"); - } else { - object[this.prefix] = constructor; - } - } - } - object[this.refcode] = this.table.length; - this.table.push(object); - return object[this.refcode]; -}; - -Resurrect.prototype.builder = function(name, value) { - var builder = {}; - builder[this.buildcode] = name; - builder[this.valuecode] = value; - return builder; -}; - -Resurrect.prototype.build = function(ref) { - var type = ref[this.buildcode].split(/\./).reduce(function(object, name) { - return object[name]; - }, Resurrect.GLOBAL); - var args = [ null ].concat(ref[this.valuecode]); - var factory = type.bind.apply(type, args); - var result = new factory(); - if (Resurrect.isPrimitive(result)) { - return result.valueOf(); - } else { - return result; - } -}; - -Resurrect.prototype.decode = function(ref) { - if (this.prefix in ref) { - return this.deref(ref); - } else if (this.buildcode in ref) { - return this.build(ref); - } else { - throw new this.Error("Unknown encoding."); - } -}; - -Resurrect.prototype.isTagged = function(object) { - return this.refcode in object && object[this.refcode] != null; -}; - -Resurrect.prototype.visit = function(root, f) { - if (Resurrect.isAtom(root)) { - return f(root); - } else if (!this.isTagged(root)) { - var copy = null; - if (Resurrect.isArray(root)) { - copy = []; - root[this.refcode] = this.tag(copy); - for (var i = 0; i < root.length; i++) { - copy.push(this.visit(root[i], f)); - } - } else { - copy = Object.create(Object.getPrototypeOf(root)); - root[this.refcode] = this.tag(copy); - for (var key in root) { - if (root.hasOwnProperty(key)) { - copy[key] = this.visit(root[key], f); - } - } - } - copy[this.origcode] = root; - return this.ref(copy); - } else { - return this.ref(root); - } -}; - -Resurrect.prototype.handleAtom = function(atom) { - var Node = Resurrect.GLOBAL.Node || function() {}; - if (Resurrect.isFunction(atom)) { - throw new this.Error("Can't serialize functions."); - } else if (atom instanceof Node) { - var xmls = new XMLSerializer(); - return this.builder("Resurrect.Node", [ xmls.serializeToString(atom) ]); - } else if (Resurrect.isDate(atom)) { - return this.builder("Date", [ atom.toISOString() ]); - } else if (Resurrect.isRegExp(atom)) { - var args = atom.toString().match(/\/(.+)\/([gimy]*)/).slice(1); - return this.builder("RegExp", args); - } else if (atom === undefined) { - return this.ref(undefined); - } else if (Resurrect.isNumber(atom) && (isNaN(atom) || !isFinite(atom))) { - return this.builder("Number", [ atom.toString() ]); - } else { - return atom; - } -}; - -Resurrect.prototype.replacerWrapper = function(replacer) { - var skip = new RegExp("^" + Resurrect.escapeRegExp(this.prefix)); - return function(k, v) { - if (skip.test(k)) { - return v; - } else { - return replacer(k, v); - } - }; -}; - -Resurrect.prototype.stringify = function(object, replacer, space) { - if (Resurrect.isFunction(replacer)) { - replacer = this.replacerWrapper(replacer); - } else if (Resurrect.isArray(replacer)) { - var codes = [ this.prefix, this.refcode, this.origcode, this.buildcode, this.valuecode ]; - replacer = codes.concat(replacer); - } - if (Resurrect.isAtom(object)) { - return JSON.stringify(this.handleAtom(object), replacer, space); - } else { - this.table = []; - this.visit(object, this.handleAtom.bind(this)); - for (var i = 0; i < this.table.length; i++) { - if (this.cleanup) { - delete this.table[i][this.origcode][this.refcode]; - } else { - this.table[i][this.origcode][this.refcode] = null; - } - delete this.table[i][this.refcode]; - delete this.table[i][this.origcode]; - } - var table = this.table; - this.table = null; - return JSON.stringify(table, replacer, space); - } -}; - -Resurrect.prototype.fixPrototype = function(object) { - if (this.prefix in object) { - var name = object[this.prefix]; - var prototype = this.resolver.getPrototype(name); - if ("__proto__" in object) { - object.__proto__ = prototype; - if (this.cleanup) { - delete object[this.prefix]; - } - return object; - } else { - var copy = Object.create(prototype); - for (var key in object) { - if (object.hasOwnProperty(key) && key !== this.prefix) { - copy[key] = object[key]; - } - } - return copy; - } - } else { - return object; - } -}; - -Resurrect.prototype.resurrect = function(string) { - var result = null; - var data = JSON.parse(string); - if (Resurrect.isArray(data)) { - this.table = data; - if (this.revive) { - for (var i = 0; i < this.table.length; i++) { - this.table[i] = this.fixPrototype(this.table[i]); - } - } - for (i = 0; i < this.table.length; i++) { - var object = this.table[i]; - for (var key in object) { - if (object.hasOwnProperty(key)) { - if (!Resurrect.isAtom(object[key])) { - object[key] = this.decode(object[key]); - } - } - } - } - result = this.table[0]; - } else if (Resurrect.isObject(data)) { - this.table = []; - result = this.decode(data); - } else { - result = data; - } - this.table = null; - return result; -}; \ No newline at end of file diff --git a/demo/js/lib/matter-tools/matter-tools.css b/demo/js/lib/matter-tools/matter-tools.css deleted file mode 100644 index b144016..0000000 --- a/demo/js/lib/matter-tools/matter-tools.css +++ /dev/null @@ -1,518 +0,0 @@ -.jstree-node,.jstree-children,.jstree-container-ul{display:block;margin:0;padding:0;list-style-type:none;list-style-image:none}.jstree-node{white-space:nowrap}.jstree-anchor{display:inline-block;color:#000;white-space:nowrap;padding:0 4px 0 1px;margin:0;vertical-align:top}.jstree-anchor:focus{outline:0}.jstree-anchor,.jstree-anchor:link,.jstree-anchor:visited,.jstree-anchor:hover,.jstree-anchor:active{text-decoration:none;color:inherit}.jstree-icon{display:inline-block;text-decoration:none;margin:0;padding:0;vertical-align:top;text-align:center}.jstree-icon:empty{display:inline-block;text-decoration:none;margin:0;padding:0;vertical-align:top;text-align:center}.jstree-ocl{cursor:pointer}.jstree-leaf>.jstree-ocl{cursor:default}.jstree .jstree-open>.jstree-children{display:block}.jstree .jstree-closed>.jstree-children,.jstree .jstree-leaf>.jstree-children{display:none}.jstree-anchor>.jstree-themeicon{margin-right:2px}.jstree-no-icons .jstree-themeicon,.jstree-anchor>.jstree-themeicon-hidden{display:none}.jstree-rtl .jstree-anchor{padding:0 1px 0 4px}.jstree-rtl .jstree-anchor>.jstree-themeicon{margin-left:2px;margin-right:0}.jstree-rtl .jstree-node{margin-left:0}.jstree-rtl .jstree-container-ul>.jstree-node{margin-right:0}.jstree-wholerow-ul{position:relative;display:inline-block;min-width:100%}.jstree-wholerow-ul .jstree-leaf>.jstree-ocl{cursor:pointer}.jstree-wholerow-ul .jstree-anchor,.jstree-wholerow-ul .jstree-icon{position:relative}.jstree-wholerow-ul .jstree-wholerow{width:100%;cursor:pointer;position:absolute;left:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.vakata-context{display:none}.vakata-context,.vakata-context ul{margin:0;padding:2px;position:absolute;background:#f5f5f5;border:1px solid #979797;-moz-box-shadow:5px 5px 4px -4px #666;-webkit-box-shadow:2px 2px 2px #999;box-shadow:2px 2px 2px #999}.vakata-context ul{list-style:none;left:100%;margin-top:-2.7em;margin-left:-4px}.vakata-context .vakata-context-right ul{left:auto;right:100%;margin-left:auto;margin-right:-4px}.vakata-context li{list-style:none;display:inline}.vakata-context li>a{display:block;padding:0 2em;text-decoration:none;width:auto;color:#000;white-space:nowrap;line-height:2.4em;-moz-text-shadow:1px 1px 0 #fff;-webkit-text-shadow:1px 1px 0 #fff;text-shadow:1px 1px 0 #fff;-moz-border-radius:1px;-webkit-border-radius:1px;border-radius:1px}.vakata-context li>a:hover{position:relative;background-color:#e8eff7;-moz-box-shadow:0 0 2px #0a6aa1;-webkit-box-shadow:0 0 2px #0a6aa1;box-shadow:0 0 2px #0a6aa1}.vakata-context li>a.vakata-context-parent{background-image:url(data:image/gif;base64,R0lGODlhCwAHAIAAACgoKP///yH5BAEAAAEALAAAAAALAAcAAAIORI4JlrqN1oMSnmmZDQUAOw==);background-position:right center;background-repeat:no-repeat}.vakata-context li>a:focus{outline:0}.vakata-context .vakata-context-hover>a{position:relative;background-color:#e8eff7;-moz-box-shadow:0 0 2px #0a6aa1;-webkit-box-shadow:0 0 2px #0a6aa1;box-shadow:0 0 2px #0a6aa1}.vakata-context .vakata-context-separator a,.vakata-context .vakata-context-separator a:hover{background:#fff;border:0;border-top:1px solid #e2e3e3;height:1px;min-height:1px;max-height:1px;padding:0;margin:0 0 0 2.4em;border-left:1px solid #e0e0e0;-moz-text-shadow:0 0 0 transparent;-webkit-text-shadow:0 0 0 transparent;text-shadow:0 0 0 transparent;-moz-box-shadow:0 0 0 transparent;-webkit-box-shadow:0 0 0 transparent;box-shadow:0 0 0 transparent;-moz-border-radius:0;-webkit-border-radius:0;border-radius:0}.vakata-context .vakata-contextmenu-disabled a,.vakata-context .vakata-contextmenu-disabled a:hover{color:silver;background-color:transparent;border:0;box-shadow:0 0 0}.vakata-context li>a>i{text-decoration:none;display:inline-block;width:2.4em;height:2.4em;background:0 0;margin:0 0 0 -2em;vertical-align:top;text-align:center;line-height:2.4em}.vakata-context li>a>i:empty{width:2.4em;line-height:2.4em}.vakata-context li>a .vakata-contextmenu-sep{display:inline-block;width:1px;height:2.4em;background:#fff;margin:0 .5em 0 0;border-left:1px solid #e2e3e3}.vakata-context .vakata-contextmenu-shortcut{font-size:.8em;color:silver;opacity:.5;display:none}.vakata-context-rtl ul{left:auto;right:100%;margin-left:auto;margin-right:-4px}.vakata-context-rtl li>a.vakata-context-parent{background-image:url(data:image/gif;base64,R0lGODlhCwAHAIAAACgoKP///yH5BAEAAAEALAAAAAALAAcAAAINjI+AC7rWHIsPtmoxLAA7);background-position:left center;background-repeat:no-repeat}.vakata-context-rtl .vakata-context-separator>a{margin:0 2.4em 0 0;border-left:0;border-right:1px solid #e2e3e3}.vakata-context-rtl .vakata-context-left ul{right:auto;left:100%;margin-left:-4px;margin-right:auto}.vakata-context-rtl li>a>i{margin:0 -2em 0 0}.vakata-context-rtl li>a .vakata-contextmenu-sep{margin:0 0 0 .5em;border-left-color:#fff;background:#e2e3e3}#jstree-marker{position:absolute;top:0;left:0;margin:0;padding:0;border-right:0;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid;width:0;height:0;font-size:0;line-height:0}#jstree-dnd{line-height:16px;margin:0;padding:4px}#jstree-dnd .jstree-icon,#jstree-dnd .jstree-copy{display:inline-block;text-decoration:none;margin:0 2px 0 0;padding:0;width:16px;height:16px}#jstree-dnd .jstree-ok{background:green}#jstree-dnd .jstree-er{background:red}#jstree-dnd .jstree-copy{margin:0 2px}.jstree-default .jstree-node,.jstree-default .jstree-icon{background-repeat:no-repeat;background-color:transparent}.jstree-default .jstree-anchor,.jstree-default .jstree-wholerow{transition:background-color .15s,box-shadow .15s}.jstree-default .jstree-hovered{background:#e7f4f9;border-radius:2px;box-shadow:inset 0 0 1px #ccc}.jstree-default .jstree-clicked{background:#beebff;border-radius:2px;box-shadow:inset 0 0 1px #999}.jstree-default .jstree-no-icons .jstree-anchor>.jstree-themeicon{display:none}.jstree-default .jstree-disabled{background:0 0;color:#666}.jstree-default .jstree-disabled.jstree-hovered{background:0 0;box-shadow:none}.jstree-default .jstree-disabled.jstree-clicked{background:#efefef}.jstree-default .jstree-disabled>.jstree-icon{opacity:.8;filter:url("data:image/svg+xml;utf8,#jstree-grayscale");filter:gray;-webkit-filter:grayscale(100%)}.jstree-default .jstree-search{font-style:italic;color:#8b0000;font-weight:700}.jstree-default .jstree-no-checkboxes .jstree-checkbox{display:none!important}.jstree-default.jstree-checkbox-no-clicked .jstree-clicked{background:0 0;box-shadow:none}.jstree-default.jstree-checkbox-no-clicked .jstree-clicked.jstree-hovered{background:#e7f4f9}.jstree-default.jstree-checkbox-no-clicked>.jstree-wholerow-ul .jstree-wholerow-clicked{background:0 0}.jstree-default.jstree-checkbox-no-clicked>.jstree-wholerow-ul .jstree-wholerow-clicked.jstree-wholerow-hovered{background:#e7f4f9}#jstree-dnd.jstree-default .jstree-ok,#jstree-dnd.jstree-default .jstree-er{background-image:url(32px.png);background-repeat:no-repeat;background-color:transparent}#jstree-dnd.jstree-default i{background:0 0;width:16px;height:16px}#jstree-dnd.jstree-default .jstree-ok{background-position:-9px -71px}#jstree-dnd.jstree-default .jstree-er{background-position:-39px -71px}.jstree-default>.jstree-striped{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAkCAMAAAB/qqA+AAAABlBMVEUAAAAAAAClZ7nPAAAAAnRSTlMNAMM9s3UAAAAXSURBVHjajcEBAQAAAIKg/H/aCQZ70AUBjAATb6YPDgAAAABJRU5ErkJggg==) left top repeat}.jstree-default>.jstree-wholerow-ul .jstree-hovered,.jstree-default>.jstree-wholerow-ul .jstree-clicked{background:0 0;box-shadow:none;border-radius:0}.jstree-default .jstree-wholerow{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.jstree-default .jstree-wholerow-hovered{background:#e7f4f9}.jstree-default .jstree-wholerow-clicked{background:#beebff;background:-moz-linear-gradient(top,#beebff 0,#a8e4ff 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0,#beebff),color-stop(100%,#a8e4ff));background:-webkit-linear-gradient(top,#beebff 0,#a8e4ff 100%);background:-o-linear-gradient(top,#beebff 0,#a8e4ff 100%);background:-ms-linear-gradient(top,#beebff 0,#a8e4ff 100%);background:linear-gradient(to bottom,#beebff 0,#a8e4ff 100%)}.jstree-default .jstree-node{min-height:24px;line-height:24px;margin-left:24px;min-width:24px}.jstree-default .jstree-anchor{line-height:24px;height:24px}.jstree-default .jstree-icon{width:24px;height:24px;line-height:24px}.jstree-default .jstree-icon:empty{width:24px;height:24px;line-height:24px}.jstree-default.jstree-rtl .jstree-node{margin-right:24px}.jstree-default .jstree-wholerow{height:24px}.jstree-default .jstree-node,.jstree-default .jstree-icon{background-image:url(32px.png)}.jstree-default .jstree-node{background-position:-292px -4px;background-repeat:repeat-y}.jstree-default .jstree-last{background:0 0}.jstree-default .jstree-open>.jstree-ocl{background-position:-132px -4px}.jstree-default .jstree-closed>.jstree-ocl{background-position:-100px -4px}.jstree-default .jstree-leaf>.jstree-ocl{background-position:-68px -4px}.jstree-default .jstree-themeicon{background-position:-260px -4px}.jstree-default>.jstree-no-dots .jstree-node,.jstree-default>.jstree-no-dots .jstree-leaf>.jstree-ocl{background:0 0}.jstree-default>.jstree-no-dots .jstree-open>.jstree-ocl{background-position:-36px -4px}.jstree-default>.jstree-no-dots .jstree-closed>.jstree-ocl{background-position:-4px -4px}.jstree-default .jstree-disabled{background:0 0}.jstree-default .jstree-disabled.jstree-hovered{background:0 0}.jstree-default .jstree-disabled.jstree-clicked{background:#efefef}.jstree-default .jstree-checkbox{background-position:-164px -4px}.jstree-default .jstree-checkbox:hover{background-position:-164px -36px}.jstree-default .jstree-clicked>.jstree-checkbox{background-position:-228px -4px}.jstree-default .jstree-clicked>.jstree-checkbox:hover{background-position:-228px -36px}.jstree-default .jstree-anchor>.jstree-undetermined{background-position:-196px -4px}.jstree-default .jstree-anchor>.jstree-undetermined:hover{background-position:-196px -36px}.jstree-default>.jstree-striped{background-size:auto 48px}.jstree-default.jstree-rtl .jstree-node{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==);background-position:100% 1px;background-repeat:repeat-y}.jstree-default.jstree-rtl .jstree-last{background:0 0}.jstree-default.jstree-rtl .jstree-open>.jstree-ocl{background-position:-132px -36px}.jstree-default.jstree-rtl .jstree-closed>.jstree-ocl{background-position:-100px -36px}.jstree-default.jstree-rtl .jstree-leaf>.jstree-ocl{background-position:-68px -36px}.jstree-default.jstree-rtl>.jstree-no-dots .jstree-node,.jstree-default.jstree-rtl>.jstree-no-dots .jstree-leaf>.jstree-ocl{background:0 0}.jstree-default.jstree-rtl>.jstree-no-dots .jstree-open>.jstree-ocl{background-position:-36px -36px}.jstree-default.jstree-rtl>.jstree-no-dots .jstree-closed>.jstree-ocl{background-position:-4px -36px}.jstree-default .jstree-themeicon-custom{background-color:transparent;background-image:none;background-position:0 0}.jstree-default>.jstree-container-ul .jstree-loading>.jstree-ocl{background:url(throbber.gif) center center no-repeat}.jstree-default .jstree-file{background:url(32px.png) -100px -68px no-repeat}.jstree-default .jstree-folder{background:url(32px.png) -260px -4px no-repeat}.jstree-default.jstree-rtl .jstree-node{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==)}.jstree-default.jstree-rtl .jstree-last{background:0 0}.jstree-default-small .jstree-node{min-height:18px;line-height:18px;margin-left:18px;min-width:18px}.jstree-default-small .jstree-anchor{line-height:18px;height:18px}.jstree-default-small .jstree-icon{width:18px;height:18px;line-height:18px}.jstree-default-small .jstree-icon:empty{width:18px;height:18px;line-height:18px}.jstree-default-small.jstree-rtl .jstree-node{margin-right:18px}.jstree-default-small .jstree-wholerow{height:18px}.jstree-default-small .jstree-node,.jstree-default-small .jstree-icon{background-image:url(32px.png)}.jstree-default-small .jstree-node{background-position:-295px -7px;background-repeat:repeat-y}.jstree-default-small .jstree-last{background:0 0}.jstree-default-small .jstree-open>.jstree-ocl{background-position:-135px -7px}.jstree-default-small .jstree-closed>.jstree-ocl{background-position:-103px -7px}.jstree-default-small .jstree-leaf>.jstree-ocl{background-position:-71px -7px}.jstree-default-small .jstree-themeicon{background-position:-263px -7px}.jstree-default-small>.jstree-no-dots .jstree-node,.jstree-default-small>.jstree-no-dots .jstree-leaf>.jstree-ocl{background:0 0}.jstree-default-small>.jstree-no-dots .jstree-open>.jstree-ocl{background-position:-39px -7px}.jstree-default-small>.jstree-no-dots .jstree-closed>.jstree-ocl{background-position:-7px -7px}.jstree-default-small .jstree-disabled{background:0 0}.jstree-default-small .jstree-disabled.jstree-hovered{background:0 0}.jstree-default-small .jstree-disabled.jstree-clicked{background:#efefef}.jstree-default-small .jstree-checkbox{background-position:-167px -7px}.jstree-default-small .jstree-checkbox:hover{background-position:-167px -39px}.jstree-default-small .jstree-clicked>.jstree-checkbox{background-position:-231px -7px}.jstree-default-small .jstree-clicked>.jstree-checkbox:hover{background-position:-231px -39px}.jstree-default-small .jstree-anchor>.jstree-undetermined{background-position:-199px -7px}.jstree-default-small .jstree-anchor>.jstree-undetermined:hover{background-position:-199px -39px}.jstree-default-small>.jstree-striped{background-size:auto 36px}.jstree-default-small.jstree-rtl .jstree-node{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==);background-position:100% 1px;background-repeat:repeat-y}.jstree-default-small.jstree-rtl .jstree-last{background:0 0}.jstree-default-small.jstree-rtl .jstree-open>.jstree-ocl{background-position:-135px -39px}.jstree-default-small.jstree-rtl .jstree-closed>.jstree-ocl{background-position:-103px -39px}.jstree-default-small.jstree-rtl .jstree-leaf>.jstree-ocl{background-position:-71px -39px}.jstree-default-small.jstree-rtl>.jstree-no-dots .jstree-node,.jstree-default-small.jstree-rtl>.jstree-no-dots .jstree-leaf>.jstree-ocl{background:0 0}.jstree-default-small.jstree-rtl>.jstree-no-dots .jstree-open>.jstree-ocl{background-position:-39px -39px}.jstree-default-small.jstree-rtl>.jstree-no-dots .jstree-closed>.jstree-ocl{background-position:-7px -39px}.jstree-default-small .jstree-themeicon-custom{background-color:transparent;background-image:none;background-position:0 0}.jstree-default-small>.jstree-container-ul .jstree-loading>.jstree-ocl{background:url(throbber.gif) center center no-repeat}.jstree-default-small .jstree-file{background:url(32px.png) -103px -71px no-repeat}.jstree-default-small .jstree-folder{background:url(32px.png) -263px -7px no-repeat}.jstree-default-small.jstree-rtl .jstree-node{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAACAQMAAABv1h6PAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMHBgAAiABBI4gz9AAAAABJRU5ErkJggg==)}.jstree-default-small.jstree-rtl .jstree-last{background:0 0}.jstree-default-large .jstree-node{min-height:32px;line-height:32px;margin-left:32px;min-width:32px}.jstree-default-large .jstree-anchor{line-height:32px;height:32px}.jstree-default-large .jstree-icon{width:32px;height:32px;line-height:32px}.jstree-default-large .jstree-icon:empty{width:32px;height:32px;line-height:32px}.jstree-default-large.jstree-rtl .jstree-node{margin-right:32px}.jstree-default-large .jstree-wholerow{height:32px}.jstree-default-large .jstree-node,.jstree-default-large .jstree-icon{background-image:url(32px.png)}.jstree-default-large .jstree-node{background-position:-288px 0;background-repeat:repeat-y}.jstree-default-large .jstree-last{background:0 0}.jstree-default-large .jstree-open>.jstree-ocl{background-position:-128px 0}.jstree-default-large .jstree-closed>.jstree-ocl{background-position:-96px 0}.jstree-default-large .jstree-leaf>.jstree-ocl{background-position:-64px 0}.jstree-default-large .jstree-themeicon{background-position:-256px 0}.jstree-default-large>.jstree-no-dots .jstree-node,.jstree-default-large>.jstree-no-dots .jstree-leaf>.jstree-ocl{background:0 0}.jstree-default-large>.jstree-no-dots .jstree-open>.jstree-ocl{background-position:-32px 0}.jstree-default-large>.jstree-no-dots .jstree-closed>.jstree-ocl{background-position:0 0}.jstree-default-large .jstree-disabled{background:0 0}.jstree-default-large .jstree-disabled.jstree-hovered{background:0 0}.jstree-default-large .jstree-disabled.jstree-clicked{background:#efefef}.jstree-default-large .jstree-checkbox{background-position:-160px 0}.jstree-default-large .jstree-checkbox:hover{background-position:-160px -32px}.jstree-default-large .jstree-clicked>.jstree-checkbox{background-position:-224px 0}.jstree-default-large .jstree-clicked>.jstree-checkbox:hover{background-position:-224px -32px}.jstree-default-large .jstree-anchor>.jstree-undetermined{background-position:-192px 0}.jstree-default-large .jstree-anchor>.jstree-undetermined:hover{background-position:-192px -32px}.jstree-default-large>.jstree-striped{background-size:auto 64px}.jstree-default-large.jstree-rtl .jstree-node{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAACAQMAAAB49I5GAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjAAMOBgAAGAAJMwQHdQAAAABJRU5ErkJggg==);background-position:100% 1px;background-repeat:repeat-y}.jstree-default-large.jstree-rtl .jstree-last{background:0 0}.jstree-default-large.jstree-rtl .jstree-open>.jstree-ocl{background-position:-128px -32px}.jstree-default-large.jstree-rtl .jstree-closed>.jstree-ocl{background-position:-96px -32px}.jstree-default-large.jstree-rtl .jstree-leaf>.jstree-ocl{background-position:-64px -32px}.jstree-default-large.jstree-rtl>.jstree-no-dots .jstree-node,.jstree-default-large.jstree-rtl>.jstree-no-dots .jstree-leaf>.jstree-ocl{background:0 0}.jstree-default-large.jstree-rtl>.jstree-no-dots .jstree-open>.jstree-ocl{background-position:-32px -32px}.jstree-default-large.jstree-rtl>.jstree-no-dots .jstree-closed>.jstree-ocl{background-position:0 -32px}.jstree-default-large .jstree-themeicon-custom{background-color:transparent;background-image:none;background-position:0 0}.jstree-default-large>.jstree-container-ul .jstree-loading>.jstree-ocl{background:url(throbber.gif) center center no-repeat}.jstree-default-large .jstree-file{background:url(32px.png) -96px -64px no-repeat}.jstree-default-large .jstree-folder{background:url(32px.png) -256px 0 no-repeat}.jstree-default-large.jstree-rtl .jstree-node{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAACAQMAAAAD0EyKAAAABlBMVEUAAAAdHRvEkCwcAAAAAXRSTlMAQObYZgAAAAxJREFUCNdjgIIGBgABCgCBvVLXcAAAAABJRU5ErkJggg==)}.jstree-default-large.jstree-rtl .jstree-last{background:0 0}@media (max-width:768px){.jstree-default-responsive .jstree-icon{background-image:url(40px.png)}.jstree-default-responsive .jstree-node,.jstree-default-responsive .jstree-leaf>.jstree-ocl{background:0 0}.jstree-default-responsive .jstree-node{min-height:40px;line-height:40px;margin-left:40px;min-width:40px;white-space:nowrap}.jstree-default-responsive .jstree-anchor{line-height:40px;height:40px}.jstree-default-responsive .jstree-icon,.jstree-default-responsive .jstree-icon:empty{width:40px;height:40px;line-height:40px}.jstree-default-responsive>.jstree-container-ul>.jstree-node{margin-left:0}.jstree-default-responsive.jstree-rtl .jstree-node{margin-left:0;margin-right:40px}.jstree-default-responsive.jstree-rtl .jstree-container-ul>.jstree-node{margin-right:0}.jstree-default-responsive .jstree-ocl,.jstree-default-responsive .jstree-themeicon,.jstree-default-responsive .jstree-checkbox{background-size:120px 200px}.jstree-default-responsive .jstree-leaf>.jstree-ocl{background:0 0}.jstree-default-responsive .jstree-open>.jstree-ocl{background-position:0 0!important}.jstree-default-responsive .jstree-closed>.jstree-ocl{background-position:0 -40px!important}.jstree-default-responsive.jstree-rtl .jstree-closed>.jstree-ocl{background-position:-40px 0!important}.jstree-default-responsive .jstree-themeicon{background-position:-40px -40px}.jstree-default-responsive .jstree-checkbox,.jstree-default-responsive .jstree-checkbox:hover{background-position:-40px -80px}.jstree-default-responsive .jstree-clicked>.jstree-checkbox,.jstree-default-responsive .jstree-clicked>.jstree-checkbox:hover{background-position:0 -80px}.jstree-default-responsive .jstree-anchor>.jstree-undetermined,.jstree-default-responsive .jstree-anchor>.jstree-undetermined:hover{background-position:0 -120px}.jstree-default-responsive .jstree-anchor{font-weight:700;font-size:1.1em;text-shadow:1px 1px #fff}.jstree-default-responsive>.jstree-striped{background:0 0}.jstree-default-responsive .jstree-wholerow{border-top:1px solid rgba(255,255,255,.7);border-bottom:1px solid rgba(64,64,64,.2);background:#ebebeb;height:40px}.jstree-default-responsive .jstree-wholerow-hovered{background:#e7f4f9}.jstree-default-responsive .jstree-wholerow-clicked{background:#beebff}.jstree-default-responsive .jstree-children .jstree-last>.jstree-wholerow{box-shadow:inset 0 -6px 3px -5px #666}.jstree-default-responsive .jstree-children .jstree-open>.jstree-wholerow{box-shadow:inset 0 6px 3px -5px #666;border-top:0}.jstree-default-responsive .jstree-children .jstree-open+.jstree-open{box-shadow:none}.jstree-default-responsive .jstree-node,.jstree-default-responsive .jstree-icon,.jstree-default-responsive .jstree-node>.jstree-ocl,.jstree-default-responsive .jstree-themeicon,.jstree-default-responsive .jstree-checkbox{background-image:url(40px.png);background-size:120px 200px}.jstree-default-responsive .jstree-node{background-position:-80px 0;background-repeat:repeat-y}.jstree-default-responsive .jstree-last{background:0 0}.jstree-default-responsive .jstree-leaf>.jstree-ocl{background-position:-40px -120px}.jstree-default-responsive .jstree-last>.jstree-ocl{background-position:-40px -160px}.jstree-default-responsive .jstree-themeicon-custom{background-color:transparent;background-image:none;background-position:0 0}.jstree-default-responsive .jstree-file{background:url(40px.png) 0 -160px no-repeat;background-size:120px 200px}.jstree-default-responsive .jstree-folder{background:url(40px.png) -40px -40px no-repeat;background-size:120px 200px}}.jstree-default>.jstree-container-ul>.jstree-node{margin-left:0;margin-right:0} -/* -* Shared -*/ - -.ins-container, -.jstree, -body .dg .c, -body .dg .cr.function, -body .dg .c select, -body .dg .property-name, -body .dg .title { - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -/* -* Matter.Gui -*/ - -body .dg.main { - box-shadow: 0 0 8px rgba(0,0,0,0.7); -} - -@media only screen and (max-width : 1350px) { - body.gui-auto-hide .dg.ac { - right: -233px; - } - - body .dg.ac:hover, - body.gui-show .dg.ac { - right: 0px; - } - - body.gui-auto-hide.gui-transitions .dg.ac { - -webkit-transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); - -moz-transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); - -o-transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); - transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); - - -webkit-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); - -moz-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); - -o-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); - transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); - - transition-delay: 3s; - -webkit-transition-delay: 3s; - } - - body.gui-transitions .dg.ac:hover, - body.gui-show.gui-transitions .dg.ac { - -webkit-transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); - -moz-transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); - -o-transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); - transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); - - -webkit-transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); - -moz-transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); - -o-transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); - transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); - - transition-delay: 0; - -webkit-transition-delay: 0; - } -} - -body .dg.main.taller-than-window .close-button { - border-top: 1px solid #444; - border-right: 4px solid #444; -} - -body .dg.main .close-button { - background-color: #444; -} - -body .dg.main .close-button:hover { - background-color: #555; -} - -body .dg.main::-webkit-scrollbar { - background: #3d3d3d; - width: 9px; -} - -body .dg.main::-webkit-scrollbar-thumb { - background: transparent; - width: 5px; - border-left: 5px solid #3d3d3d; - border-right: 6px solid rgba(0,0,0,0.2); - border-radius: 0; -} - -body .dg { - color: #aaa; - text-shadow: none !important; -} - -body .dg li:not(.folder) { - background: #3d3d3d; - border-bottom: 0px; - padding: 0 0 0 12px; -} - -body .dg li.save-row .button { - text-shadow: none !important; -} - -body .dg li.title { - padding-left: 22px; - border-bottom: 1px solid #555; - background: #444 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 10px 10px no-repeat; -} - -body .dg .cr.boolean:hover { - background: #3d3d3d; -} - -body .dg .cr.function { - border-top: 1px solid #444; - background: #333; - color: #aaa; - border-bottom: 1px solid #333; -} - -body .dg .cr.function:hover { - background: #3a3a3a; - border-bottom: 1px solid #2fa1d6; -} - -body .dg .cr.function:active { - border-top: 2px solid #444; - border-bottom: 0; - background: #2e2e2e; -} - -body .dg .c select { - margin-top: 2px; - margin-left: -5px; - padding: 3px 5px; -} - -body .dg .c select, -body .dg .c input[type=text], -body .dg .cr.number input[type=text] { - background: #333; - color: #999; - border: 0; - font-size: 10px; -} - -body .dg .c select, -body .dg .c select:focus { - width: 88px; - outline: 0; -} - -body .dg .c input[type=text]:hover { - background: #444; -} - -body .dg .c input[type=text]:focus { - background: #444; - color: #fff; -} - -body .dg .c .slider { - background: #555; -} - -body .dg .c .slider:hover { - background: #666; -} - -body .dg .c .slider-fg { - background: #777; -} - -body .dg .c .slider:hover .slider-fg { - background: #999; -} - -body .dg li.folder { - border-left: 0; -} - -body .dg.a { - border-right:4px solid #3d3d3d; -} - -/* -* Matter.Inspector -*/ - -.ins-cursor-move canvas { - cursor: move !important; -} - -.ins-cursor-rotate canvas { - cursor: ew-resize !important; -} - -.ins-cursor-scale canvas { - cursor: nwse-resize !important; -} - -.ins-container { - position: fixed; - overflow: auto; - width: 260px; - bottom: 0; - top: 0; - left: 0; - background: #3d3d3d; - padding: 0; - font-family: Arial; - font-size: 12px; - color: #aaa; - border-right: 2px solid #3d3d3d; - box-shadow: 0 0 8px rgba(0,0,0,0.7); -} - -@media only screen and (max-width : 1350px) { - .ins-auto-hide .ins-container { - left: -245px; - border-right: 1px dotted #888; - } - - .ins-container:hover, - .ins-show .ins-container { - left: 0px; - border-right: 0px dotted #888; - } - - .ins-transitions .ins-container { - -webkit-transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); - -moz-transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); - -o-transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); - transition: all 500ms cubic-bezier(0.965, 0.025, 0.735, 0.415); - - -webkit-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); - -moz-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); - -o-transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); - transition-timing-function: cubic-bezier(0.965, 0.025, 0.735, 0.415); - - transition-delay: 3s; - -webkit-transition-delay: 3s; - } - - .ins-transitions .ins-container:hover, - .ins-transitions.ins-show .ins-container { - -webkit-transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); - -moz-transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); - -o-transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); - transition: all 500ms cubic-bezier(0.095, 0.665, 0.400, 0.835); - - -webkit-transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); - -moz-transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); - -o-transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); - transition-timing-function: cubic-bezier(0.095, 0.665, 0.400, 0.835); - - transition-delay: 0; - -webkit-transition-delay: 0; - } -} - -.ins-add-button.ins-button { - float: right; - width: auto; - height: auto; - padding: 2px 5px; - margin: 2px 29px; - min-width: 0; - position: relative; - z-index: 100; -} - -.ins-search-box { - margin: 14px 23px; - border: 0; - padding: 7px 8px; - font-size: 12px; - width: 80%; - box-sizing: border-box; - border-radius: 3px; - background: #444; - border: 1px solid #444; - color: #999; -} - -.ins-search-box:focus { - background: #484848; - color: #aaa; - border: 1px solid rgba(255,255,255,0.1); - outline: 0; -} - -.ins-search-box::-webkit-search-cancel-button { - -webkit-appearance: none; - height: 15px; - width: 8px; - cursor: pointer; -} - -.ins-search-box::-webkit-search-cancel-button:before { - height: 10px; - width: 10px; - content: 'x'; - font-family: Arial; - line-height: 0; - font-size: 13px; - color: #999; - font-weight: bold; - cursor: pointer; -} - -.ins-search-box::-webkit-input-placeholder { - color: #777; -} - -.ins-search-box:-moz-placeholder { - color: #777; -} - -.ins-search-box::-moz-placeholder { - color: #777; -} - -.ins-search-box:-ms-input-placeholder { - color: #777; -} - -.ins-world-tree { - overflow: auto; - position: absolute; - left: 0; - right: 0; - top: 110px; - bottom: 8px; -} - -.ins-control-group { - display: block; - clear: both; - overflow: hidden; - padding: 14px 20px 12px 20px; - background: #444; - border-bottom: 1px solid #555; -} - -.ins-button { - display: block; - float: left; - margin: 0 2px; - font-size: 11px; - line-height: 1; - padding: 6px 8px; - min-width: 49px; - text-align: center; - background: #333; - border: 0; - color: #aaa; - border-radius: 2px; - border-bottom: 2px solid #2e2e2e; - box-sizing: border-box; - outline: none; -} - -.ins-button:hover { - background: #3a3a3a; - border-bottom: 2px solid #2fa1d6; -} - -.ins-button:active { - border-top: 2px solid #444; - border-bottom: 0; - background: #2e2e2e; -} - -.jstree-default .jstree-search { - font-style: italic; - color: #aaa; - font-weight: normal; -} - -.jstree-default .jstree-wholerow-hovered, -.jstree-default .jstree-hovered { - background: transparent; - border-radius: 0; - box-shadow: none; -} - -.jstree-default .jstree-wholerow { - height: 26px; -} - -.jstree-default .jstree-wholerow-clicked, -.jstree-default .jstree-clicked { - background: transparent; - border-radius: 0; - box-shadow: none; - transition: none; -} - -.jstree-default .jstree-leaf .jstree-clicked { - color: #bbb !important; - - -webkit-transition: color 100ms linear; - -moz-transition: color 100ms linear; - -o-transition: color 100ms linear; - transition: color 100ms linear; -} - -.jstree-default .jstree-anchor { - line-height: 27px; -} - -.jstree-default .jstree-container-ul> .jstree-node > .jstree-anchor:before, -.jstree-default .jstree-open > .jstree-children > .jstree-node > .jstree-anchor:before { - content: ''; - display: block; - position: absolute; - left: 0; - right: 1px; - height: 26px; - background: transparent; - border-radius: 0; - box-shadow: none; - border-right: none; - pointer-events: none; - background: rgba(0,0,0,0); - - -webkit-transition: background 100ms linear; - -moz-transition: background 100ms linear; - -o-transition: background 100ms linear; - transition: background 100ms linear; -} - -.jstree-default .jstree-anchor.jstree-clicked:before { - background: rgba(0,0,0,0.1) !important; - - -webkit-transition: background 100ms linear; - -moz-transition: background 100ms linear; - -o-transition: background 100ms linear; - transition: background 100ms linear; -} - -.jstree-default .jstree-node-type-body > .jstree-anchor:before { - border-right: 3px solid #e1115f !important; -} - -.jstree-default .jstree-node-type-constraint > .jstree-anchor:before { - border-right: 3px solid #1ed36f !important; -} - -.jstree-default .jstree-node-type-composite > .jstree-anchor:before { - border-right: 3px solid #2fa1d6 !important; -} - -.jstree-default .jstree-node, -.jstree-default .jstree-leaf .jstree-ocl { - background: transparent; -} - -.jstree-default .jstree-open .jstree-ocl { - background-position: -38px -1px; -} - -.jstree-default .jstree-closed .jstree-ocl { - background-position: -4px -2px; -} - -.jstree-anchor { - padding: 1px 0; - transition: none; -} - -.jstree-anchor .jstree-icon { - display: none; -} - -.jstree-node-type-bodies > .jstree-anchor, -.jstree-node-type-constraints > .jstree-anchor, -.jstree-node-type-composites > .jstree-anchor { - color: #888; - font-weight: bold; -} - -.ins-container *::-webkit-scrollbar { - width: 10px; - height: 10px; -} - -.ins-container *::-webkit-scrollbar-thumb:vertical { - border-left: 3px solid #3d3d3d; - background: rgba(0,0,0,0.2); - width: 10px; -} - -.ins-container *::-webkit-scrollbar-thumb:horizontal { - border-top: 3px solid #3d3d3d; - background: rgba(0,0,0,0.2); - height: 10px; -} - -.ins-container *::-webkit-scrollbar-track, -.ins-container *::-webkit-scrollbar-corner { - background: transparent; -} - -#vakata-dnd { - font-family: Arial; - font-size: 12px; - color: #aaa; -} \ No newline at end of file diff --git a/demo/js/lib/pixi.js b/demo/js/lib/pixi.js deleted file mode 100644 index 199a329..0000000 --- a/demo/js/lib/pixi.js +++ /dev/null @@ -1,27293 +0,0 @@ -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.PIXI = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= arr.length) { - callback(); - } - } - } - }; - async.forEach = async.each; - - async.eachSeries = function (arr, iterator, callback) { - callback = callback || function () {}; - if (!arr.length) { - return callback(); - } - var completed = 0; - var iterate = function () { - iterator(arr[completed], function (err) { - if (err) { - callback(err); - callback = function () {}; - } - else { - completed += 1; - if (completed >= arr.length) { - callback(); - } - else { - iterate(); - } - } - }); - }; - iterate(); - }; - async.forEachSeries = async.eachSeries; - - async.eachLimit = function (arr, limit, iterator, callback) { - var fn = _eachLimit(limit); - fn.apply(null, [arr, iterator, callback]); - }; - async.forEachLimit = async.eachLimit; - - var _eachLimit = function (limit) { - - return function (arr, iterator, callback) { - callback = callback || function () {}; - if (!arr.length || limit <= 0) { - return callback(); - } - var completed = 0; - var started = 0; - var running = 0; - - (function replenish () { - if (completed >= arr.length) { - return callback(); - } - - while (running < limit && started < arr.length) { - started += 1; - running += 1; - iterator(arr[started - 1], function (err) { - if (err) { - callback(err); - callback = function () {}; - } - else { - completed += 1; - running -= 1; - if (completed >= arr.length) { - callback(); - } - else { - replenish(); - } - } - }); - } - })(); - }; - }; - - - var doParallel = function (fn) { - return function () { - var args = Array.prototype.slice.call(arguments); - return fn.apply(null, [async.each].concat(args)); - }; - }; - var doParallelLimit = function(limit, fn) { - return function () { - var args = Array.prototype.slice.call(arguments); - return fn.apply(null, [_eachLimit(limit)].concat(args)); - }; - }; - var doSeries = function (fn) { - return function () { - var args = Array.prototype.slice.call(arguments); - return fn.apply(null, [async.eachSeries].concat(args)); - }; - }; - - - var _asyncMap = function (eachfn, arr, iterator, callback) { - arr = _map(arr, function (x, i) { - return {index: i, value: x}; - }); - if (!callback) { - eachfn(arr, function (x, callback) { - iterator(x.value, function (err) { - callback(err); - }); - }); - } else { - var results = []; - eachfn(arr, function (x, callback) { - iterator(x.value, function (err, v) { - results[x.index] = v; - callback(err); - }); - }, function (err) { - callback(err, results); - }); - } - }; - async.map = doParallel(_asyncMap); - async.mapSeries = doSeries(_asyncMap); - async.mapLimit = function (arr, limit, iterator, callback) { - return _mapLimit(limit)(arr, iterator, callback); - }; - - var _mapLimit = function(limit) { - return doParallelLimit(limit, _asyncMap); - }; - - // reduce only has a series version, as doing reduce in parallel won't - // work in many situations. - async.reduce = function (arr, memo, iterator, callback) { - async.eachSeries(arr, function (x, callback) { - iterator(memo, x, function (err, v) { - memo = v; - callback(err); - }); - }, function (err) { - callback(err, memo); - }); - }; - // inject alias - async.inject = async.reduce; - // foldl alias - async.foldl = async.reduce; - - async.reduceRight = function (arr, memo, iterator, callback) { - var reversed = _map(arr, function (x) { - return x; - }).reverse(); - async.reduce(reversed, memo, iterator, callback); - }; - // foldr alias - async.foldr = async.reduceRight; - - var _filter = function (eachfn, arr, iterator, callback) { - var results = []; - arr = _map(arr, function (x, i) { - return {index: i, value: x}; - }); - eachfn(arr, function (x, callback) { - iterator(x.value, function (v) { - if (v) { - results.push(x); - } - callback(); - }); - }, function (err) { - callback(_map(results.sort(function (a, b) { - return a.index - b.index; - }), function (x) { - return x.value; - })); - }); - }; - async.filter = doParallel(_filter); - async.filterSeries = doSeries(_filter); - // select alias - async.select = async.filter; - async.selectSeries = async.filterSeries; - - var _reject = function (eachfn, arr, iterator, callback) { - var results = []; - arr = _map(arr, function (x, i) { - return {index: i, value: x}; - }); - eachfn(arr, function (x, callback) { - iterator(x.value, function (v) { - if (!v) { - results.push(x); - } - callback(); - }); - }, function (err) { - callback(_map(results.sort(function (a, b) { - return a.index - b.index; - }), function (x) { - return x.value; - })); - }); - }; - async.reject = doParallel(_reject); - async.rejectSeries = doSeries(_reject); - - var _detect = function (eachfn, arr, iterator, main_callback) { - eachfn(arr, function (x, callback) { - iterator(x, function (result) { - if (result) { - main_callback(x); - main_callback = function () {}; - } - else { - callback(); - } - }); - }, function (err) { - main_callback(); - }); - }; - async.detect = doParallel(_detect); - async.detectSeries = doSeries(_detect); - - async.some = function (arr, iterator, main_callback) { - async.each(arr, function (x, callback) { - iterator(x, function (v) { - if (v) { - main_callback(true); - main_callback = function () {}; - } - callback(); - }); - }, function (err) { - main_callback(false); - }); - }; - // any alias - async.any = async.some; - - async.every = function (arr, iterator, main_callback) { - async.each(arr, function (x, callback) { - iterator(x, function (v) { - if (!v) { - main_callback(false); - main_callback = function () {}; - } - callback(); - }); - }, function (err) { - main_callback(true); - }); - }; - // all alias - async.all = async.every; - - async.sortBy = function (arr, iterator, callback) { - async.map(arr, function (x, callback) { - iterator(x, function (err, criteria) { - if (err) { - callback(err); - } - else { - callback(null, {value: x, criteria: criteria}); - } - }); - }, function (err, results) { - if (err) { - return callback(err); - } - else { - var fn = function (left, right) { - var a = left.criteria, b = right.criteria; - return a < b ? -1 : a > b ? 1 : 0; - }; - callback(null, _map(results.sort(fn), function (x) { - return x.value; - })); - } - }); - }; - - async.auto = function (tasks, callback) { - callback = callback || function () {}; - var keys = _keys(tasks); - var remainingTasks = keys.length - if (!remainingTasks) { - return callback(); - } - - var results = {}; - - var listeners = []; - var addListener = function (fn) { - listeners.unshift(fn); - }; - var removeListener = function (fn) { - for (var i = 0; i < listeners.length; i += 1) { - if (listeners[i] === fn) { - listeners.splice(i, 1); - return; - } - } - }; - var taskComplete = function () { - remainingTasks-- - _each(listeners.slice(0), function (fn) { - fn(); - }); - }; - - addListener(function () { - if (!remainingTasks) { - var theCallback = callback; - // prevent final callback from calling itself if it errors - callback = function () {}; - - theCallback(null, results); - } - }); - - _each(keys, function (k) { - var task = _isArray(tasks[k]) ? tasks[k]: [tasks[k]]; - var taskCallback = function (err) { - var args = Array.prototype.slice.call(arguments, 1); - if (args.length <= 1) { - args = args[0]; - } - if (err) { - var safeResults = {}; - _each(_keys(results), function(rkey) { - safeResults[rkey] = results[rkey]; - }); - safeResults[k] = args; - callback(err, safeResults); - // stop subsequent errors hitting callback multiple times - callback = function () {}; - } - else { - results[k] = args; - async.setImmediate(taskComplete); - } - }; - var requires = task.slice(0, Math.abs(task.length - 1)) || []; - var ready = function () { - return _reduce(requires, function (a, x) { - return (a && results.hasOwnProperty(x)); - }, true) && !results.hasOwnProperty(k); - }; - if (ready()) { - task[task.length - 1](taskCallback, results); - } - else { - var listener = function () { - if (ready()) { - removeListener(listener); - task[task.length - 1](taskCallback, results); - } - }; - addListener(listener); - } - }); - }; - - async.retry = function(times, task, callback) { - var DEFAULT_TIMES = 5; - var attempts = []; - // Use defaults if times not passed - if (typeof times === 'function') { - callback = task; - task = times; - times = DEFAULT_TIMES; - } - // Make sure times is a number - times = parseInt(times, 10) || DEFAULT_TIMES; - var wrappedTask = function(wrappedCallback, wrappedResults) { - var retryAttempt = function(task, finalAttempt) { - return function(seriesCallback) { - task(function(err, result){ - seriesCallback(!err || finalAttempt, {err: err, result: result}); - }, wrappedResults); - }; - }; - while (times) { - attempts.push(retryAttempt(task, !(times-=1))); - } - async.series(attempts, function(done, data){ - data = data[data.length - 1]; - (wrappedCallback || callback)(data.err, data.result); - }); - } - // If a callback is passed, run this as a controll flow - return callback ? wrappedTask() : wrappedTask - }; - - async.waterfall = function (tasks, callback) { - callback = callback || function () {}; - if (!_isArray(tasks)) { - var err = new Error('First argument to waterfall must be an array of functions'); - return callback(err); - } - if (!tasks.length) { - return callback(); - } - var wrapIterator = function (iterator) { - return function (err) { - if (err) { - callback.apply(null, arguments); - callback = function () {}; - } - else { - var args = Array.prototype.slice.call(arguments, 1); - var next = iterator.next(); - if (next) { - args.push(wrapIterator(next)); - } - else { - args.push(callback); - } - async.setImmediate(function () { - iterator.apply(null, args); - }); - } - }; - }; - wrapIterator(async.iterator(tasks))(); - }; - - var _parallel = function(eachfn, tasks, callback) { - callback = callback || function () {}; - if (_isArray(tasks)) { - eachfn.map(tasks, function (fn, callback) { - if (fn) { - fn(function (err) { - var args = Array.prototype.slice.call(arguments, 1); - if (args.length <= 1) { - args = args[0]; - } - callback.call(null, err, args); - }); - } - }, callback); - } - else { - var results = {}; - eachfn.each(_keys(tasks), function (k, callback) { - tasks[k](function (err) { - var args = Array.prototype.slice.call(arguments, 1); - if (args.length <= 1) { - args = args[0]; - } - results[k] = args; - callback(err); - }); - }, function (err) { - callback(err, results); - }); - } - }; - - async.parallel = function (tasks, callback) { - _parallel({ map: async.map, each: async.each }, tasks, callback); - }; - - async.parallelLimit = function(tasks, limit, callback) { - _parallel({ map: _mapLimit(limit), each: _eachLimit(limit) }, tasks, callback); - }; - - async.series = function (tasks, callback) { - callback = callback || function () {}; - if (_isArray(tasks)) { - async.mapSeries(tasks, function (fn, callback) { - if (fn) { - fn(function (err) { - var args = Array.prototype.slice.call(arguments, 1); - if (args.length <= 1) { - args = args[0]; - } - callback.call(null, err, args); - }); - } - }, callback); - } - else { - var results = {}; - async.eachSeries(_keys(tasks), function (k, callback) { - tasks[k](function (err) { - var args = Array.prototype.slice.call(arguments, 1); - if (args.length <= 1) { - args = args[0]; - } - results[k] = args; - callback(err); - }); - }, function (err) { - callback(err, results); - }); - } - }; - - async.iterator = function (tasks) { - var makeCallback = function (index) { - var fn = function () { - if (tasks.length) { - tasks[index].apply(null, arguments); - } - return fn.next(); - }; - fn.next = function () { - return (index < tasks.length - 1) ? makeCallback(index + 1): null; - }; - return fn; - }; - return makeCallback(0); - }; - - async.apply = function (fn) { - var args = Array.prototype.slice.call(arguments, 1); - return function () { - return fn.apply( - null, args.concat(Array.prototype.slice.call(arguments)) - ); - }; - }; - - var _concat = function (eachfn, arr, fn, callback) { - var r = []; - eachfn(arr, function (x, cb) { - fn(x, function (err, y) { - r = r.concat(y || []); - cb(err); - }); - }, function (err) { - callback(err, r); - }); - }; - async.concat = doParallel(_concat); - async.concatSeries = doSeries(_concat); - - async.whilst = function (test, iterator, callback) { - if (test()) { - iterator(function (err) { - if (err) { - return callback(err); - } - async.whilst(test, iterator, callback); - }); - } - else { - callback(); - } - }; - - async.doWhilst = function (iterator, test, callback) { - iterator(function (err) { - if (err) { - return callback(err); - } - var args = Array.prototype.slice.call(arguments, 1); - if (test.apply(null, args)) { - async.doWhilst(iterator, test, callback); - } - else { - callback(); - } - }); - }; - - async.until = function (test, iterator, callback) { - if (!test()) { - iterator(function (err) { - if (err) { - return callback(err); - } - async.until(test, iterator, callback); - }); - } - else { - callback(); - } - }; - - async.doUntil = function (iterator, test, callback) { - iterator(function (err) { - if (err) { - return callback(err); - } - var args = Array.prototype.slice.call(arguments, 1); - if (!test.apply(null, args)) { - async.doUntil(iterator, test, callback); - } - else { - callback(); - } - }); - }; - - async.queue = function (worker, concurrency) { - if (concurrency === undefined) { - concurrency = 1; - } - function _insert(q, data, pos, callback) { - if (!q.started){ - q.started = true; - } - if (!_isArray(data)) { - data = [data]; - } - if(data.length == 0) { - // call drain immediately if there are no tasks - return async.setImmediate(function() { - if (q.drain) { - q.drain(); - } - }); - } - _each(data, function(task) { - var item = { - data: task, - callback: typeof callback === 'function' ? callback : null - }; - - if (pos) { - q.tasks.unshift(item); - } else { - q.tasks.push(item); - } - - if (q.saturated && q.tasks.length === q.concurrency) { - q.saturated(); - } - async.setImmediate(q.process); - }); - } - - var workers = 0; - var q = { - tasks: [], - concurrency: concurrency, - saturated: null, - empty: null, - drain: null, - started: false, - paused: false, - push: function (data, callback) { - _insert(q, data, false, callback); - }, - kill: function () { - q.drain = null; - q.tasks = []; - }, - unshift: function (data, callback) { - _insert(q, data, true, callback); - }, - process: function () { - if (!q.paused && workers < q.concurrency && q.tasks.length) { - var task = q.tasks.shift(); - if (q.empty && q.tasks.length === 0) { - q.empty(); - } - workers += 1; - var next = function () { - workers -= 1; - if (task.callback) { - task.callback.apply(task, arguments); - } - if (q.drain && q.tasks.length + workers === 0) { - q.drain(); - } - q.process(); - }; - var cb = only_once(next); - worker(task.data, cb); - } - }, - length: function () { - return q.tasks.length; - }, - running: function () { - return workers; - }, - idle: function() { - return q.tasks.length + workers === 0; - }, - pause: function () { - if (q.paused === true) { return; } - q.paused = true; - q.process(); - }, - resume: function () { - if (q.paused === false) { return; } - q.paused = false; - q.process(); - } - }; - return q; - }; - - async.priorityQueue = function (worker, concurrency) { - - function _compareTasks(a, b){ - return a.priority - b.priority; - }; - - function _binarySearch(sequence, item, compare) { - var beg = -1, - end = sequence.length - 1; - while (beg < end) { - var mid = beg + ((end - beg + 1) >>> 1); - if (compare(item, sequence[mid]) >= 0) { - beg = mid; - } else { - end = mid - 1; - } - } - return beg; - } - - function _insert(q, data, priority, callback) { - if (!q.started){ - q.started = true; - } - if (!_isArray(data)) { - data = [data]; - } - if(data.length == 0) { - // call drain immediately if there are no tasks - return async.setImmediate(function() { - if (q.drain) { - q.drain(); - } - }); - } - _each(data, function(task) { - var item = { - data: task, - priority: priority, - callback: typeof callback === 'function' ? callback : null - }; - - q.tasks.splice(_binarySearch(q.tasks, item, _compareTasks) + 1, 0, item); - - if (q.saturated && q.tasks.length === q.concurrency) { - q.saturated(); - } - async.setImmediate(q.process); - }); - } - - // Start with a normal queue - var q = async.queue(worker, concurrency); - - // Override push to accept second parameter representing priority - q.push = function (data, priority, callback) { - _insert(q, data, priority, callback); - }; - - // Remove unshift function - delete q.unshift; - - return q; - }; - - async.cargo = function (worker, payload) { - var working = false, - tasks = []; - - var cargo = { - tasks: tasks, - payload: payload, - saturated: null, - empty: null, - drain: null, - drained: true, - push: function (data, callback) { - if (!_isArray(data)) { - data = [data]; - } - _each(data, function(task) { - tasks.push({ - data: task, - callback: typeof callback === 'function' ? callback : null - }); - cargo.drained = false; - if (cargo.saturated && tasks.length === payload) { - cargo.saturated(); - } - }); - async.setImmediate(cargo.process); - }, - process: function process() { - if (working) return; - if (tasks.length === 0) { - if(cargo.drain && !cargo.drained) cargo.drain(); - cargo.drained = true; - return; - } - - var ts = typeof payload === 'number' - ? tasks.splice(0, payload) - : tasks.splice(0, tasks.length); - - var ds = _map(ts, function (task) { - return task.data; - }); - - if(cargo.empty) cargo.empty(); - working = true; - worker(ds, function () { - working = false; - - var args = arguments; - _each(ts, function (data) { - if (data.callback) { - data.callback.apply(null, args); - } - }); - - process(); - }); - }, - length: function () { - return tasks.length; - }, - running: function () { - return working; - } - }; - return cargo; - }; - - var _console_fn = function (name) { - return function (fn) { - var args = Array.prototype.slice.call(arguments, 1); - fn.apply(null, args.concat([function (err) { - var args = Array.prototype.slice.call(arguments, 1); - if (typeof console !== 'undefined') { - if (err) { - if (console.error) { - console.error(err); - } - } - else if (console[name]) { - _each(args, function (x) { - console[name](x); - }); - } - } - }])); - }; - }; - async.log = _console_fn('log'); - async.dir = _console_fn('dir'); - /*async.info = _console_fn('info'); - async.warn = _console_fn('warn'); - async.error = _console_fn('error');*/ - - async.memoize = function (fn, hasher) { - var memo = {}; - var queues = {}; - hasher = hasher || function (x) { - return x; - }; - var memoized = function () { - var args = Array.prototype.slice.call(arguments); - var callback = args.pop(); - var key = hasher.apply(null, args); - if (key in memo) { - async.nextTick(function () { - callback.apply(null, memo[key]); - }); - } - else if (key in queues) { - queues[key].push(callback); - } - else { - queues[key] = [callback]; - fn.apply(null, args.concat([function () { - memo[key] = arguments; - var q = queues[key]; - delete queues[key]; - for (var i = 0, l = q.length; i < l; i++) { - q[i].apply(null, arguments); - } - }])); - } - }; - memoized.memo = memo; - memoized.unmemoized = fn; - return memoized; - }; - - async.unmemoize = function (fn) { - return function () { - return (fn.unmemoized || fn).apply(null, arguments); - }; - }; - - async.times = function (count, iterator, callback) { - var counter = []; - for (var i = 0; i < count; i++) { - counter.push(i); - } - return async.map(counter, iterator, callback); - }; - - async.timesSeries = function (count, iterator, callback) { - var counter = []; - for (var i = 0; i < count; i++) { - counter.push(i); - } - return async.mapSeries(counter, iterator, callback); - }; - - async.seq = function (/* functions... */) { - var fns = arguments; - return function () { - var that = this; - var args = Array.prototype.slice.call(arguments); - var callback = args.pop(); - async.reduce(fns, args, function (newargs, fn, cb) { - fn.apply(that, newargs.concat([function () { - var err = arguments[0]; - var nextargs = Array.prototype.slice.call(arguments, 1); - cb(err, nextargs); - }])) - }, - function (err, results) { - callback.apply(that, [err].concat(results)); - }); - }; - }; - - async.compose = function (/* functions... */) { - return async.seq.apply(null, Array.prototype.reverse.call(arguments)); - }; - - var _applyEach = function (eachfn, fns /*args...*/) { - var go = function () { - var that = this; - var args = Array.prototype.slice.call(arguments); - var callback = args.pop(); - return eachfn(fns, function (fn, cb) { - fn.apply(that, args.concat([cb])); - }, - callback); - }; - if (arguments.length > 2) { - var args = Array.prototype.slice.call(arguments, 2); - return go.apply(this, args); - } - else { - return go; - } - }; - async.applyEach = doParallel(_applyEach); - async.applyEachSeries = doSeries(_applyEach); - - async.forever = function (fn, callback) { - function next(err) { - if (err) { - if (callback) { - return callback(err); - } - throw err; - } - fn(next); - } - next(); - }; - - // Node.js - if (typeof module !== 'undefined' && module.exports) { - module.exports = async; - } - // AMD / RequireJS - else if (typeof define !== 'undefined' && define.amd) { - define([], function () { - return async; - }); - } - // included directly via - - - - - - Matter.js Physics Engine Mobile Demo - - -
      - - \ No newline at end of file diff --git a/examples/airFriction.js b/examples/airFriction.js index 268abee..5492933 100644 --- a/examples/airFriction.js +++ b/examples/airFriction.js @@ -1,31 +1,76 @@ -var _isBrowser = typeof window !== 'undefined' && window.location, - Matter = _isBrowser ? window.Matter : require('../../build/matter-dev.js'); +var Example = Example || {}; -var Example = {}; -Matter.Example = Example; - -if (!_isBrowser) { - module.exports = Example; -} - -(function() { - - var World = Matter.World, +Example.airFriction = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composite = Matter.Composite, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, Bodies = Matter.Bodies; - Example.airFriction = function(demo) { - var engine = demo.engine, - world = engine.world; - - World.add(world, [ - Bodies.rectangle(200, 100, 60, 60, { frictionAir: 0.001 }), - Bodies.rectangle(400, 100, 60, 60, { frictionAir: 0.05 }), - Bodies.rectangle(600, 100, 60, 60, { frictionAir: 0.1 }) - ]); + // create engine + var engine = Engine.create(), + world = engine.world; - var renderOptions = demo.render.options; - renderOptions.showAngleIndicator = false; - renderOptions.showVelocity = true; + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showVelocity: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + World.add(world, [ + // falling blocks + Bodies.rectangle(200, 100, 60, 60, { frictionAir: 0.001 }), + Bodies.rectangle(400, 100, 60, 60, { frictionAir: 0.05 }), + Bodies.rectangle(600, 100, 60, 60, { frictionAir: 0.1 }), + + // floor + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } }; - -})(); \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/attractors.js b/examples/attractors.js index 25a4d54..02c6422 100644 --- a/examples/attractors.js +++ b/examples/attractors.js @@ -1,50 +1,98 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.attractors = function() { + Matter.use( + 'matter-gravity', + 'matter-wrap' + ); + + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composite = Matter.Composite, Body = Matter.Body, - Common = Matter.Common; + Common = Matter.Common, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; - Example.attractors = function(demo) { - var engine = demo.engine, - world = engine.world; + // create engine + var engine = Engine.create(), + world = engine.world; - Matter.use( - 'matter-gravity', - 'matter-wrap' + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024) + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + world.bodies = []; + world.gravity.scale = 0; + + var G = 0.001; + + for (var i = 0; i < 200; i += 1) { + var body = Bodies.circle( + Common.random(10, render.options.width), + Common.random(10, render.options.height), + Common.random(4, 10), + { + mass: Common.random(10, 20), + gravity: G, + frictionAir: 0, + wrap: { + min: { x: 0, y: 0 }, + max: { x: render.options.width, y: render.options.height } + } + } ); - world.bodies = []; - world.gravity.scale = 0; + Body.setVelocity(body, { + x: Common.random(-2, 2), + y: Common.random(-2, 2) + }); - var G = 0.001; + World.add(world, body); + } - for (var i = 0; i < 200; i += 1) { - var body = Bodies.circle( - Common.random(10, 790), - Common.random(10, 590), - Common.random(4, 10), - { - mass: Common.random(10, 20), - gravity: G, - frictionAir: 0, - wrap: { - min: { x: 0, y: 0 }, - max: { x: 800, y: 600 } - } + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false } - ); + } + }); - Body.setVelocity(body, { - x: Common.random(-2, 2), - y: Common.random(-2, 2) - }); + World.add(world, mouseConstraint); - World.add(world, body); + // keep the mouse in sync with rendering + render.mouse = mouse; + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); } - - var renderOptions = demo.render.options; - renderOptions.showAngleIndicator = false; }; - -})(); \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/avalanche.js b/examples/avalanche.js index dd0e980..5645bd2 100644 --- a/examples/avalanche.js +++ b/examples/avalanche.js @@ -1,25 +1,92 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.avalanche = function() { + Matter.use( + 'matter-wrap' + ); + + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composite = Matter.Composite, Composites = Matter.Composites, - Common = Matter.Common; + Common = Matter.Common, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; - Example.avalanche = function(demo) { - var engine = demo.engine, - world = engine.world; + // create engine + var engine = Engine.create(), + world = engine.world; - var stack = Composites.stack(20, 20, 20, 5, 0, 0, function(x, y) { - return Bodies.circle(x, y, Common.random(10, 20), { friction: 0.00001, restitution: 0.5, density: 0.001 }); + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var stack = Composites.stack(20, 20, 20, 5, 0, 0, function(x, y) { + return Bodies.circle(x, y, Common.random(10, 20), { friction: 0.00001, restitution: 0.5, density: 0.001 }); + }); + + World.add(world, stack); + + World.add(world, [ + Bodies.rectangle(200, 150, 700, 20, { isStatic: true, angle: Math.PI * 0.06 }), + Bodies.rectangle(500, 350, 700, 20, { isStatic: true, angle: -Math.PI * 0.06 }), + Bodies.rectangle(340, 580, 700, 20, { isStatic: true, angle: Math.PI * 0.04 }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } }); - - World.add(world, stack); - - World.add(world, [ - Bodies.rectangle(200, 150, 700, 20, { isStatic: true, angle: Math.PI * 0.06 }), - Bodies.rectangle(500, 350, 700, 20, { isStatic: true, angle: -Math.PI * 0.06 }), - Bodies.rectangle(340, 580, 700, 20, { isStatic: true, angle: Math.PI * 0.04 }) - ]); - }; -})(); \ No newline at end of file + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // wrapping using matter-wrap plugin + for (var i = 0; i < stack.bodies.length; i += 1) { + stack.bodies[i].wrap = { + min: { x: render.bounds.min.x, y: render.bounds.min.y }, + max: { x: render.bounds.max.x, y: render.bounds.max.y } + }; + } + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; \ No newline at end of file diff --git a/examples/ballPool.js b/examples/ballPool.js index c619c47..0dcd750 100644 --- a/examples/ballPool.js +++ b/examples/ballPool.js @@ -1,24 +1,85 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.ballPool = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composite = Matter.Composite, Composites = Matter.Composites, - Common = Matter.Common; + Common = Matter.Common, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; - Example.ballPool = function(demo) { - var engine = demo.engine, - world = engine.world; + // create engine + var engine = Engine.create(), + world = engine.world; - var stack = Composites.stack(100, 50, 10, 15, 10, 10, function(x, y) { - return Bodies.circle(x, y, Common.random(15, 30), { restitution: 0.6, friction: 0.1 }); + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + World.add(world, [ + Bodies.rectangle(400, 600, 800, 50.5, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + var stack = Composites.stack(100, 50, 10, 8, 10, 10, function(x, y) { + return Bodies.circle(x, y, Common.random(15, 30), { restitution: 0.6, friction: 0.1 }); + }); + + World.add(world, [ + stack, + Bodies.polygon(200, 560, 3, 60), + Bodies.polygon(400, 560, 5, 60), + Bodies.rectangle(600, 560, 80, 80) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } }); - - World.add(world, [ - stack, - Bodies.polygon(200, 560, 3, 60), - Bodies.polygon(400, 560, 5, 60), - Bodies.rectangle(600, 560, 80, 80) - ]); - }; -})(); \ No newline at end of file + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; \ No newline at end of file diff --git a/examples/beachBalls.js b/examples/beachBalls.js deleted file mode 100644 index 2773173..0000000 --- a/examples/beachBalls.js +++ /dev/null @@ -1,18 +0,0 @@ -(function() { - - var World = Matter.World, - Bodies = Matter.Bodies, - Composites = Matter.Composites; - - Example.beachBalls = function(demo) { - var engine = demo.engine, - world = engine.world; - - var stack = Composites.stack(0, 100, 5, 1, 20, 0, function(x, y) { - return Bodies.circle(x, y, 75, { restitution: 0.9 }); - }); - - World.add(world, stack); - }; - -})(); \ No newline at end of file diff --git a/examples/bridge.js b/examples/bridge.js index caddbe6..2abc73a 100644 --- a/examples/bridge.js +++ b/examples/bridge.js @@ -1,35 +1,91 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.bridge = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, Body = Matter.Body, + Composite = Matter.Composite, Composites = Matter.Composites, Common = Matter.Common, - Constraint = Matter.Constraint; + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; - Example.bridge = function(demo) { - var engine = demo.engine, - world = engine.world, - group = Body.nextGroup(true); - - var bridge = Composites.stack(150, 300, 9, 1, 10, 10, function(x, y) { - return Bodies.rectangle(x, y, 50, 20, { collisionFilter: { group: group } }); - }); - - Composites.chain(bridge, 0.5, 0, -0.5, 0, { stiffness: 0.9 }); - - var stack = Composites.stack(200, 40, 6, 3, 0, 0, function(x, y) { - return Bodies.polygon(x, y, Math.round(Common.random(1, 8)), Common.random(20, 40)); - }); + // create engine + var engine = Engine.create(), + world = engine.world; - World.add(world, [ - bridge, - Bodies.rectangle(80, 440, 120, 280, { isStatic: true }), - Bodies.rectangle(720, 440, 120, 280, { isStatic: true }), - Constraint.create({ pointA: { x: 140, y: 300 }, bodyB: bridge.bodies[0], pointB: { x: -25, y: 0 } }), - Constraint.create({ pointA: { x: 660, y: 300 }, bodyB: bridge.bodies[8], pointB: { x: 25, y: 0 } }), - stack - ]); - }; + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var group = Body.nextGroup(true); + + var bridge = Composites.stack(150, 300, 9, 1, 10, 10, function(x, y) { + return Bodies.rectangle(x, y, 50, 20, { collisionFilter: { group: group } }); + }); -})(); \ No newline at end of file + Composites.chain(bridge, 0.5, 0, -0.5, 0, { stiffness: 0.9 }); + + var stack = Composites.stack(200, 40, 6, 3, 0, 0, function(x, y) { + return Bodies.polygon(x, y, Math.round(Common.random(1, 8)), Common.random(20, 40)); + }); + + World.add(world, [ + bridge, + Bodies.rectangle(80, 440, 120, 280, { isStatic: true }), + Bodies.rectangle(720, 440, 120, 280, { isStatic: true }), + Constraint.create({ pointA: { x: 140, y: 300 }, bodyB: bridge.bodies[0], pointB: { x: -25, y: 0 } }), + Constraint.create({ pointA: { x: 660, y: 300 }, bodyB: bridge.bodies[8], pointB: { x: 25, y: 0 } }), + stack + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; \ No newline at end of file diff --git a/examples/broadphase.js b/examples/broadphase.js index 552b1f0..4ac0c9a 100644 --- a/examples/broadphase.js +++ b/examples/broadphase.js @@ -1,34 +1,95 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.broadphase = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Composite = Matter.Composite, Composites = Matter.Composites, - Common = Matter.Common; + Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; - Example.broadphase = function(demo) { - var engine = demo.engine, - world = engine.world; + // create engine + var engine = Engine.create(), + world = engine.world; - var stack = Composites.stack(20, 20, 20, 5, 0, 0, function(x, y) { - switch (Math.round(Common.random(0, 1))) { + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showAngleIndicator: true, + showBroadphase: true + } + }); - case 0: - if (Common.random() < 0.8) { - return Bodies.rectangle(x, y, Common.random(20, 50), Common.random(20, 50)); - } else { - return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(20, 30)); + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + World.add(world, [ + Bodies.rectangle(400, 600, 800, 50.5, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + var stack = Composites.stack(20, 20, 12, 5, 0, 0, function(x, y) { + switch (Math.round(Common.random(0, 1))) { + + case 0: + if (Common.random() < 0.8) { + return Bodies.rectangle(x, y, Common.random(20, 50), Common.random(20, 50)); + } else { + return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(20, 30)); + } + break; + case 1: + return Bodies.polygon(x, y, Math.round(Common.random(1, 8)), Common.random(20, 50)); + + } + }); + + World.add(world, stack); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false } - break; - case 1: - return Bodies.polygon(x, y, Math.round(Common.random(1, 8)), Common.random(20, 50)); - } }); - - World.add(world, stack); - - var renderOptions = demo.render.options; - renderOptions.showBroadphase = true; + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } }; - -})(); \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/car.js b/examples/car.js index 12ed234..063dab6 100644 --- a/examples/car.js +++ b/examples/car.js @@ -1,29 +1,89 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, - Composites = Matter.Composites; +Example.car = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Composite = Matter.Composite, + Composites = Matter.Composites, + Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; - Example.car = function(demo) { - var engine = demo.engine, - world = engine.world, - scale; - - scale = 0.9; - World.add(world, Composites.car(150, 100, 100 * scale, 40 * scale, 30 * scale)); - - scale = 0.8; - World.add(world, Composites.car(350, 300, 100 * scale, 40 * scale, 30 * scale)); - - World.add(world, [ - Bodies.rectangle(200, 150, 650, 20, { isStatic: true, angle: Math.PI * 0.06 }), - Bodies.rectangle(500, 350, 650, 20, { isStatic: true, angle: -Math.PI * 0.06 }), - Bodies.rectangle(340, 580, 700, 20, { isStatic: true, angle: Math.PI * 0.04 }) - ]); - - var renderOptions = demo.render.options; - renderOptions.showAngleIndicator = true; - renderOptions.showCollisions = true; - }; + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showAngleIndicator: true, + showCollisions: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + World.add(world, [ + Bodies.rectangle(400, 600, 800, 50.5, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + var scale = 0.9; + World.add(world, Composites.car(150, 100, 100 * scale, 40 * scale, 30 * scale)); -})(); \ No newline at end of file + scale = 0.8; + World.add(world, Composites.car(350, 300, 100 * scale, 40 * scale, 30 * scale)); + + World.add(world, [ + Bodies.rectangle(200, 150, 400, 20, { isStatic: true, angle: Math.PI * 0.06 }), + Bodies.rectangle(500, 350, 650, 20, { isStatic: true, angle: -Math.PI * 0.06 }), + Bodies.rectangle(300, 560, 600, 20, { isStatic: true, angle: Math.PI * 0.04 }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; \ No newline at end of file diff --git a/examples/catapult.js b/examples/catapult.js index ac60e01..7198640 100644 --- a/examples/catapult.js +++ b/examples/catapult.js @@ -1,33 +1,88 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.catapult = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Composite = Matter.Composite, Composites = Matter.Composites, - Constraint = Matter.Constraint; + Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; - Example.catapult = function(demo) { - var engine = demo.engine, - world = engine.world; - - var stack = Composites.stack(250, 255, 1, 6, 0, 0, function(x, y) { - return Bodies.rectangle(x, y, 30, 30); + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showAngleIndicator: true, + showCollisions: true, + showVelocity: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var stack = Composites.stack(250, 255, 1, 6, 0, 0, function(x, y) { + return Bodies.rectangle(x, y, 30, 30); + }); + + var catapult = Bodies.rectangle(400, 520, 320, 20); + + World.add(world, [ + stack, + catapult, + Bodies.rectangle(400, 600, 800, 50.5, { isStatic: true }), + Bodies.rectangle(250, 555, 20, 50, { isStatic: true }), + Bodies.circle(560, 100, 50, { density: 0.005 }), + Constraint.create({ bodyA: catapult, pointB: { x: 390, y: 580 } }), + Constraint.create({ bodyA: catapult, pointB: { x: 410, y: 580 } }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } }); - var catapult = Bodies.rectangle(400, 520, 320, 20, { }); + World.add(world, mouseConstraint); - World.add(world, [ - stack, - catapult, - Bodies.rectangle(250, 555, 20, 50, { isStatic: true }), - Bodies.circle(560, 100, 50, { density: 0.005 }), - Constraint.create({ bodyA: catapult, pointB: { x: 390, y: 580 } }), - Constraint.create({ bodyA: catapult, pointB: { x: 410, y: 580 } }) - ]); - - var renderOptions = demo.render.options; - renderOptions.showCollisions = true; - renderOptions.showVelocity = true; - renderOptions.showAngleIndicator = true; + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } }; - -})(); \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/chains.js b/examples/chains.js index 272650c..0c0b799 100644 --- a/examples/chains.js +++ b/examples/chains.js @@ -1,46 +1,107 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.chains = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, Body = Matter.Body, Composite = Matter.Composite, Composites = Matter.Composites, - Constraint = Matter.Constraint; + Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; - Example.chains = function(demo) { - var engine = demo.engine, - world = engine.world, - group = Body.nextGroup(true); - - var ropeA = Composites.stack(200, 100, 5, 2, 10, 10, function(x, y) { - return Bodies.rectangle(x, y, 50, 20, { collisionFilter: { group: group } }); + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showAngleIndicator: true, + showCollisions: true, + showVelocity: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var group = Body.nextGroup(true); + + var ropeA = Composites.stack(200, 100, 4, 2, 10, 10, function(x, y) { + return Bodies.rectangle(x, y, 50, 20, { collisionFilter: { group: group } }); + }); + + Composites.chain(ropeA, 0.5, 0, -0.5, 0, { stiffness: 0.8, length: 2 }); + Composite.add(ropeA, Constraint.create({ + bodyB: ropeA.bodies[0], + pointB: { x: -25, y: 0 }, + pointA: { x: 200, y: 100 }, + stiffness: 0.5 + })); + + World.add(world, ropeA); + + group = Body.nextGroup(true); + + var ropeB = Composites.stack(500, 100, 5, 2, 10, 10, function(x, y) { + return Bodies.circle(x, y, 20, { collisionFilter: { group: group } }); + }); + + Composites.chain(ropeB, 0.5, 0, -0.5, 0, { stiffness: 0.8, length: 2 }); + Composite.add(ropeB, Constraint.create({ + bodyB: ropeB.bodies[0], + pointB: { x: -20, y: 0 }, + pointA: { x: 500, y: 100 }, + stiffness: 0.5 + })); + + World.add(world, ropeB); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } }); - - Composites.chain(ropeA, 0.5, 0, -0.5, 0, { stiffness: 0.8, length: 2 }); - Composite.add(ropeA, Constraint.create({ - bodyB: ropeA.bodies[0], - pointB: { x: -25, y: 0 }, - pointA: { x: 200, y: 100 }, - stiffness: 0.5 - })); - - World.add(world, ropeA); - - group = Body.nextGroup(true); - - var ropeB = Composites.stack(500, 100, 5, 2, 10, 10, function(x, y) { - return Bodies.circle(x, y, 20, { collisionFilter: { group: group } }); - }); - - Composites.chain(ropeB, 0.5, 0, -0.5, 0, { stiffness: 0.8, length: 2 }); - Composite.add(ropeB, Constraint.create({ - bodyB: ropeB.bodies[0], - pointB: { x: -20, y: 0 }, - pointA: { x: 500, y: 100 }, - stiffness: 0.5 - })); - - World.add(world, ropeB); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 700, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } }; - -})(); \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/circleStack.js b/examples/circleStack.js index 5b90094..bf6291a 100644 --- a/examples/circleStack.js +++ b/examples/circleStack.js @@ -1,18 +1,79 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, - Composites = Matter.Composites; +Example.circleStack = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Composite = Matter.Composite, + Composites = Matter.Composites, + Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; - Example.circleStack = function(demo) { - var engine = demo.engine, - world = engine.world; - - var stack = Composites.stack(100, 185, 10, 10, 20, 0, function(x, y) { - return Bodies.circle(x, y, 20); + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var stack = Composites.stack(100, 185, 10, 10, 20, 0, function(x, y) { + return Bodies.circle(x, y, 20); + }); + + World.add(world, [ + Bodies.rectangle(400, 600, 800, 50.5, { isStatic: true }), + stack + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } }); - - World.add(world, stack); - }; -})(); + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; \ No newline at end of file diff --git a/examples/cloth.js b/examples/cloth.js index 90b96bd..3d40238 100644 --- a/examples/cloth.js +++ b/examples/cloth.js @@ -1,27 +1,83 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.cloth = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, Body = Matter.Body, - Composites = Matter.Composites; + Composite = Matter.Composite, + Composites = Matter.Composites, + Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; - Example.cloth = function(demo) { - var engine = demo.engine, - world = engine.world; - - var group = Body.nextGroup(true), - particleOptions = { friction: 0.00001, collisionFilter: { group: group }, render: { visible: false }}, - cloth = Composites.softBody(200, 200, 20, 12, 5, 5, false, 8, particleOptions); + // create engine + var engine = Engine.create(), + world = engine.world; - for (var i = 0; i < 20; i++) { - cloth.bodies[i].isStatic = true; + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024) } + }); - World.add(world, [ - cloth, - Bodies.circle(300, 500, 80, { isStatic: true }), - Bodies.rectangle(500, 480, 80, 80, { isStatic: true }) - ]); + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var group = Body.nextGroup(true), + particleOptions = { friction: 0.00001, collisionFilter: { group: group }, render: { visible: false }}, + cloth = Composites.softBody(200, 200, 20, 12, 5, 5, false, 8, particleOptions); + + for (var i = 0; i < 20; i++) { + cloth.bodies[i].isStatic = true; + } + + World.add(world, [ + cloth, + Bodies.circle(300, 500, 80, { isStatic: true }), + Bodies.rectangle(500, 480, 80, 80, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.9 + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 700 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } }; - -})(); \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/collisionFiltering.js b/examples/collisionFiltering.js index 4f19555..f30dc17 100644 --- a/examples/collisionFiltering.js +++ b/examples/collisionFiltering.js @@ -1,97 +1,154 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.collisionFiltering = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composite = Matter.Composite, Composites = Matter.Composites, - Common = Matter.Common; + Common = Matter.Common, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; - Example.collisionFiltering = function(demo) { - var engine = demo.engine, - world = engine.world, - mouseConstraint = demo.mouseConstraint; + // create engine + var engine = Engine.create(), + world = engine.world; - // define our categories (as bit fields, there are up to 32 available) - var defaultCategory = 0x0001, - redCategory = 0x0002, - greenCategory = 0x0004, - blueCategory = 0x0008; + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + wireframes: false, + background: '#111' + } + }); - var redColor = '#C44D58', - blueColor = '#4ECDC4', - greenColor = '#C7F464'; + Render.run(render); - // create a stack with varying body categories (but these bodies can all collide with each other) - World.add(world, - Composites.stack(275, 150, 5, 10, 10, 10, function(x, y, column, row) { - var category = redCategory, - color = redColor; + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); - if (row > 5) { - category = blueCategory; - color = blueColor; - } else if (row > 2) { - category = greenCategory; - color = greenColor; - } + // define our categories (as bit fields, there are up to 32 available) + var defaultCategory = 0x0001, + redCategory = 0x0002, + greenCategory = 0x0004, + blueCategory = 0x0008; - return Bodies.circle(x, y, 20, { - collisionFilter: { - category: category - }, - render: { - strokeStyle: color, - fillStyle: 'transparent' - } - }); - }) - ); + var redColor = '#C44D58', + blueColor = '#4ECDC4', + greenColor = '#C7F464'; - // this body will only collide with the walls and the green bodies - World.add(world, - Bodies.circle(310, 40, 30, { + // add floor + World.add(world, Bodies.rectangle(400, 800, 900, 50, { + isStatic: true, + render: { + fillStyle: 'transparent' + } + })); + + // create a stack with varying body categories (but these bodies can all collide with each other) + World.add(world, + Composites.stack(275, 150, 5, 10, 10, 10, function(x, y, column, row) { + var category = redCategory, + color = redColor; + + if (row > 5) { + category = blueCategory; + color = blueColor; + } else if (row > 2) { + category = greenCategory; + color = greenColor; + } + + return Bodies.circle(x, y, 20, { collisionFilter: { - mask: defaultCategory | greenCategory + category: category }, render: { - strokeStyle: Common.shadeColor(greenColor, -20), - fillStyle: greenColor + strokeStyle: color, + fillStyle: 'transparent' } - }) - ); + }); + }) + ); - // this body will only collide with the walls and the red bodies - World.add(world, - Bodies.circle(400, 40, 30, { - collisionFilter: { - mask: defaultCategory | redCategory - }, + // this body will only collide with the walls and the green bodies + World.add(world, + Bodies.circle(310, 40, 30, { + collisionFilter: { + mask: defaultCategory | greenCategory + }, + render: { + strokeStyle: Common.shadeColor(greenColor, -20), + fillStyle: greenColor + } + }) + ); + + // this body will only collide with the walls and the red bodies + World.add(world, + Bodies.circle(400, 40, 30, { + collisionFilter: { + mask: defaultCategory | redCategory + }, + render: { + strokeStyle: Common.shadeColor(redColor, -20), + fillStyle: redColor + } + }) + ); + + // this body will only collide with the walls and the blue bodies + World.add(world, + Bodies.circle(480, 40, 30, { + collisionFilter: { + mask: defaultCategory | blueCategory + }, + render: { + strokeStyle: Common.shadeColor(blueColor, -20), + fillStyle: blueColor + } + }) + ); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, render: { - strokeStyle: Common.shadeColor(redColor, -20), - fillStyle: redColor + visible: false } - }) - ); + } + }); - // this body will only collide with the walls and the blue bodies - World.add(world, - Bodies.circle(480, 40, 30, { - collisionFilter: { - mask: defaultCategory | blueCategory - }, - render: { - strokeStyle: Common.shadeColor(blueColor, -20), - fillStyle: blueColor - } - }) - ); + World.add(world, mouseConstraint); - // red category objects should not be draggable with the mouse - mouseConstraint.collisionFilter.mask = defaultCategory | blueCategory | greenCategory; + // keep the mouse in sync with rendering + render.mouse = mouse; - var renderOptions = demo.render.options; - renderOptions.wireframes = false; - renderOptions.background = '#222'; - renderOptions.showAngleIndicator = false; + // red category objects should not be draggable with the mouse + mouseConstraint.collisionFilter.mask = defaultCategory | blueCategory | greenCategory; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } }; - -})(); \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/compositeManipulation.js b/examples/compositeManipulation.js index b8f0f56..38f638b 100644 --- a/examples/compositeManipulation.js +++ b/examples/compositeManipulation.js @@ -1,51 +1,106 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.compositeManipulation = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Events = Matter.Events, Composite = Matter.Composite, Composites = Matter.Composites, - Events = Matter.Events; + Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; - Example.compositeManipulation = function(demo) { - var engine = demo.engine, - world = engine.world, - sceneEvents = demo.sceneEvents; + // create engine + var engine = Engine.create(), + world = engine.world; - var stack = Composites.stack(200, 200, 4, 4, 0, 0, function(x, y) { - return Bodies.rectangle(x, y, 40, 40); + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + World.add(world, [ + Bodies.rectangle(400, 600, 800, 50.5, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + var stack = Composites.stack(200, 200, 4, 4, 0, 0, function(x, y) { + return Bodies.rectangle(x, y, 40, 40); + }); + + World.add(world, stack); + + world.gravity.y = 0; + + Events.on(engine, 'afterUpdate', function(event) { + var time = engine.timing.timestamp; + + Composite.translate(stack, { + x: Math.sin(time * 0.001) * 2, + y: 0 }); - World.add(world, stack); + Composite.rotate(stack, Math.sin(time * 0.001) * 0.01, { + x: 300, + y: 300 + }); - world.gravity.y = 0; + var scale = 1 + (Math.sin(time * 0.001) * 0.01); - sceneEvents.push( - Events.on(engine, 'afterUpdate', function(event) { - var time = engine.timing.timestamp; + Composite.scale(stack, scale, scale, { + x: 300, + y: 300 + }); + }); - Composite.translate(stack, { - x: Math.sin(time * 0.001) * 2, - y: 0 - }); + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); - Composite.rotate(stack, Math.sin(time * 0.001) * 0.01, { - x: 300, - y: 300 - }); + World.add(world, mouseConstraint); - var scale = 1 + (Math.sin(time * 0.001) * 0.01); + // keep the mouse in sync with rendering + render.mouse = mouse; - Composite.scale(stack, scale, scale, { - x: 300, - y: 300 - }); - }) - ); + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); - var renderOptions = demo.render.options; - renderOptions.wireframes = false; - renderOptions.showAxes = true; - renderOptions.showCollisions = true; + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } }; - -})(); \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/compound.js b/examples/compound.js index f01d6e5..473798b 100644 --- a/examples/compound.js +++ b/examples/compound.js @@ -1,49 +1,109 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.compound = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, Body = Matter.Body, - Constraint = Matter.Constraint; + Events = Matter.Events, + Composite = Matter.Composite, + Composites = Matter.Composites, + Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; - Example.compound = function(demo) { - var engine = demo.engine, - world = engine.world; + // create engine + var engine = Engine.create(), + world = engine.world; - var size = 200, - x = 200, - y = 200, - partA = Bodies.rectangle(x, y, size, size / 5), - partB = Bodies.rectangle(x, y, size / 5, size, { render: partA.render }); + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showAxes: true, + showPositions: true, + showConvexHulls: true + } + }); - var compoundBodyA = Body.create({ - parts: [partA, partB] + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var size = 200, + x = 200, + y = 200, + partA = Bodies.rectangle(x, y, size, size / 5), + partB = Bodies.rectangle(x, y, size / 5, size, { render: partA.render }); + + var compoundBodyA = Body.create({ + parts: [partA, partB] + }); + + size = 150; + x = 400; + y = 300; + + var partC = Bodies.circle(x, y, 30), + partD = Bodies.circle(x + size, y, 30), + partE = Bodies.circle(x + size, y + size, 30), + partF = Bodies.circle(x, y + size, 30); + + var compoundBodyB = Body.create({ + parts: [partC, partD, partE, partF] + }); + + var constraint = Constraint.create({ + pointA: { x: 400, y: 100 }, + bodyB: compoundBodyB, + pointB: { x: 0, y: -50 } + }); + + World.add(world, [ + compoundBodyA, + compoundBodyB, + constraint, + Bodies.rectangle(400, 600, 800, 50.5, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } }); - size = 150; - x = 400; - y = 300; + World.add(world, mouseConstraint); - var partC = Bodies.circle(x, y, 30), - partD = Bodies.circle(x + size, y, 30), - partE = Bodies.circle(x + size, y + size, 30), - partF = Bodies.circle(x, y + size, 30); + // keep the mouse in sync with rendering + render.mouse = mouse; - var compoundBodyB = Body.create({ - parts: [partC, partD, partE, partF] - }); + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); - var constraint = Constraint.create({ - pointA: { x: 400, y: 100 }, - bodyB: compoundBodyB, - pointB: { x: 0, y: -50 } - }); - - World.add(world, [compoundBodyA, compoundBodyB, constraint]); - - var renderOptions = demo.render.options; - renderOptions.showAxes = true; - renderOptions.showPositions = true; - renderOptions.showConvexHulls = true; + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } }; - -})(); \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/compoundStack.js b/examples/compoundStack.js index f850760..ddefac3 100644 --- a/examples/compoundStack.js +++ b/examples/compoundStack.js @@ -1,25 +1,87 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.compoundStack = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, Body = Matter.Body, - Composites = Matter.Composites; + Events = Matter.Events, + Composite = Matter.Composite, + Composites = Matter.Composites, + Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; - Example.compoundStack = function(demo) { - var engine = demo.engine, - world = engine.world, - size = 50; + // create engine + var engine = Engine.create(), + world = engine.world; - var stack = Composites.stack(100, 280, 12, 6, 0, 0, function(x, y) { - var partA = Bodies.rectangle(x, y, size, size / 5), - partB = Bodies.rectangle(x, y, size / 5, size, { render: partA.render }); + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showAngleIndicator: true + } + }); - return Body.create({ - parts: [partA, partB] - }); + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var size = 50; + + var stack = Composites.stack(100, 280, 12, 6, 0, 0, function(x, y) { + var partA = Bodies.rectangle(x, y, size, size / 5), + partB = Bodies.rectangle(x, y, size / 5, size, { render: partA.render }); + + return Body.create({ + parts: [partA, partB] + }); + }); + + World.add(world, [ + stack, + Bodies.rectangle(400, 620, 800, 50, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } }); - World.add(world, stack); - }; + World.add(world, mouseConstraint); -})(); + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; \ No newline at end of file diff --git a/examples/concave.js b/examples/concave.js index 89be2c6..9ffde46 100644 --- a/examples/concave.js +++ b/examples/concave.js @@ -1,34 +1,94 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.concave = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Events = Matter.Events, + Composite = Matter.Composite, Composites = Matter.Composites, Common = Matter.Common, - Vertices = Matter.Vertices; + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Vertices = Matter.Vertices, + Bodies = Matter.Bodies; - Example.concave = function(demo) { - var engine = demo.engine, - world = engine.world; + // create engine + var engine = Engine.create(), + world = engine.world; - var arrow = Vertices.fromPath('40 0 40 20 100 20 100 80 40 80 40 100 0 50'), - chevron = Vertices.fromPath('100 0 75 50 100 100 25 100 0 50 25 0'), - star = Vertices.fromPath('50 0 63 38 100 38 69 59 82 100 50 75 18 100 31 59 0 38 37 38'), - horseShoe = Vertices.fromPath('35 7 19 17 14 38 14 58 25 79 45 85 65 84 65 66 46 67 34 59 30 44 33 29 45 23 66 23 66 7 53 7'); + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024) + } + }); - var stack = Composites.stack(50, 50, 6, 4, 10, 10, function(x, y) { - var color = Common.choose(['#556270', '#4ECDC4', '#C7F464', '#FF6B6B', '#C44D58']); - return Bodies.fromVertices(x, y, Common.choose([arrow, chevron, star, horseShoe]), { + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + World.add(world, [ + Bodies.rectangle(400, 600, 800, 50.5, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + var arrow = Vertices.fromPath('40 0 40 20 100 20 100 80 40 80 40 100 0 50'), + chevron = Vertices.fromPath('100 0 75 50 100 100 25 100 0 50 25 0'), + star = Vertices.fromPath('50 0 63 38 100 38 69 59 82 100 50 75 18 100 31 59 0 38 37 38'), + horseShoe = Vertices.fromPath('35 7 19 17 14 38 14 58 25 79 45 85 65 84 65 66 46 67 34 59 30 44 33 29 45 23 66 23 66 7 53 7'); + + var stack = Composites.stack(50, 50, 6, 4, 10, 10, function(x, y) { + var color = Common.choose(['#556270', '#4ECDC4', '#C7F464', '#FF6B6B', '#C44D58']); + return Bodies.fromVertices(x, y, Common.choose([arrow, chevron, star, horseShoe]), { + render: { + fillStyle: color, + strokeStyle: color + } + }, true); + }); + + World.add(world, stack); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, render: { - fillStyle: color, - strokeStyle: color + visible: false } - }, true); + } }); - World.add(world, stack); + World.add(world, mouseConstraint); - var renderOptions = demo.render.options; - renderOptions.showAngleIndicator = false; + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } }; - -})(); \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/engine.js b/examples/engine.js deleted file mode 100644 index 078ec02..0000000 --- a/examples/engine.js +++ /dev/null @@ -1,17 +0,0 @@ -(function() { - - var Engine = Matter.Engine; - - Example.engine = function(demo) { - // some example engine options - var options = { - positionIterations: 6, - velocityIterations: 4, - enableSleeping: false, - metrics: { extended: true } - }; - - return Engine.create(options); - }; - -})(); \ No newline at end of file diff --git a/examples/events.js b/examples/events.js index 262bbc6..459de2c 100644 --- a/examples/events.js +++ b/examples/events.js @@ -1,159 +1,176 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.events = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, Body = Matter.Body, + Events = Matter.Events, Composite = Matter.Composite, Composites = Matter.Composites, Common = Matter.Common, - Events = Matter.Events; + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Vertices = Matter.Vertices, + Bodies = Matter.Bodies; - Example.events = function(demo) { - var engine = demo.engine, - world = engine.world, - mouseConstraint = demo.mouseConstraint, - sceneEvents = demo.sceneEvents; - - // bind events (sceneEvents is only used for this demo) + // create engine + var engine = Engine.create(), + world = engine.world; - sceneEvents.push( + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024) + } + }); - // an example of using composite events on the world - Events.on(world, 'afterAdd', function(event) { - console.log('added to world:', event.object); - }) + Render.run(render); - ); + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); - sceneEvents.push( + // an example of using composite events on the world + Events.on(world, 'afterAdd', function(event) { + console.log('added to world:', event.object); + }); - // an example of using beforeUpdate event on an engine - Events.on(engine, 'beforeUpdate', function(event) { - var engine = event.source; + // an example of using beforeUpdate event on an engine + Events.on(engine, 'beforeUpdate', function(event) { + var engine = event.source; - // apply random forces every 5 secs - if (event.timestamp % 5000 < 50) - shakeScene(engine); - }) + // apply random forces every 5 secs + if (event.timestamp % 5000 < 50) + shakeScene(engine); + }); - ); + // an example of using collisionStart event on an engine + Events.on(engine, 'collisionStart', function(event) { + var pairs = event.pairs; - sceneEvents.push( + // change object colours to show those starting a collision + for (var i = 0; i < pairs.length; i++) { + var pair = pairs[i]; + pair.bodyA.render.fillStyle = '#bbbbbb'; + pair.bodyB.render.fillStyle = '#bbbbbb'; + } + }); - // an example of using collisionStart event on an engine - Events.on(engine, 'collisionStart', function(event) { - var pairs = event.pairs; + // an example of using collisionActive event on an engine + Events.on(engine, 'collisionActive', function(event) { + var pairs = event.pairs; - // change object colours to show those starting a collision - for (var i = 0; i < pairs.length; i++) { - var pair = pairs[i]; - pair.bodyA.render.fillStyle = '#bbbbbb'; - pair.bodyB.render.fillStyle = '#bbbbbb'; - } - }) + // change object colours to show those in an active collision (e.g. resting contact) + for (var i = 0; i < pairs.length; i++) { + var pair = pairs[i]; + pair.bodyA.render.fillStyle = '#aaaaaa'; + pair.bodyB.render.fillStyle = '#aaaaaa'; + } + }); - ); + // an example of using collisionEnd event on an engine + Events.on(engine, 'collisionEnd', function(event) { + var pairs = event.pairs; - sceneEvents.push( + // change object colours to show those ending a collision + for (var i = 0; i < pairs.length; i++) { + var pair = pairs[i]; + pair.bodyA.render.fillStyle = '#999999'; + pair.bodyB.render.fillStyle = '#999999'; + } + }); - // an example of using collisionActive event on an engine - Events.on(engine, 'collisionActive', function(event) { - var pairs = event.pairs; + // scene code + World.add(world, [ + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); - // change object colours to show those in an active collision (e.g. resting contact) - for (var i = 0; i < pairs.length; i++) { - var pair = pairs[i]; - pair.bodyA.render.fillStyle = '#aaaaaa'; - pair.bodyB.render.fillStyle = '#aaaaaa'; - } - }) + var stack = Composites.stack(70, 100, 9, 4, 50, 50, function(x, y) { + return Bodies.circle(x, y, 15, { restitution: 1, render: { strokeStyle: '#777' } }); + }); + + World.add(world, stack); - ); + var shakeScene = function(engine) { + var bodies = Composite.allBodies(engine.world); - sceneEvents.push( + for (var i = 0; i < bodies.length; i++) { + var body = bodies[i]; - // an example of using collisionEnd event on an engine - Events.on(engine, 'collisionEnd', function(event) { - var pairs = event.pairs; + if (!body.isStatic && body.position.y >= 500) { + var forceMagnitude = 0.02 * body.mass; - // change object colours to show those ending a collision - for (var i = 0; i < pairs.length; i++) { - var pair = pairs[i]; - pair.bodyA.render.fillStyle = '#999999'; - pair.bodyB.render.fillStyle = '#999999'; - } - }) - - ); - - sceneEvents.push( - - // an example of using mouse events on a mouse - Events.on(mouseConstraint, 'mousedown', function(event) { - var mousePosition = event.mouse.position; - console.log('mousedown at ' + mousePosition.x + ' ' + mousePosition.y); - demo.render.options.background = 'cornsilk'; - shakeScene(engine); - }) - - ); - - sceneEvents.push( - - // an example of using mouse events on a mouse - Events.on(mouseConstraint, 'mouseup', function(event) { - var mousePosition = event.mouse.position; - demo.render.options.background = "white"; - console.log('mouseup at ' + mousePosition.x + ' ' + mousePosition.y); - }) - - ); - - sceneEvents.push( - - // an example of using mouse events on a mouse - Events.on(mouseConstraint, 'startdrag', function(event) { - console.log('startdrag', event); - }) - - ); - - sceneEvents.push( - - // an example of using mouse events on a mouse - Events.on(mouseConstraint, 'enddrag', function(event) { - console.log('enddrag', event); - }) - - ); - - // scene code - - var stack = Composites.stack(50, 100, 8, 4, 50, 50, function(x, y) { - return Bodies.circle(x, y, 15, { restitution: 1, render: { strokeStyle: '#777' } }); - }); - - World.add(world, stack); - - var renderOptions = demo.render.options; - renderOptions.wireframes = false; - - var shakeScene = function(engine) { - var bodies = Composite.allBodies(engine.world); - - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i]; - - if (!body.isStatic && body.position.y >= 500) { - var forceMagnitude = 0.01 * body.mass; - - Body.applyForce(body, { x: 0, y: 0 }, { - x: (forceMagnitude + Common.random() * forceMagnitude) * Common.choose([1, -1]), - y: -forceMagnitude + Common.random() * -forceMagnitude - }); - } + Body.applyForce(body, body.position, { + x: (forceMagnitude + Common.random() * forceMagnitude) * Common.choose([1, -1]), + y: -forceMagnitude + Common.random() * -forceMagnitude + }); } - }; + } }; -})(); \ No newline at end of file + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // an example of using mouse events on a mouse + Events.on(mouseConstraint, 'mousedown', function(event) { + var mousePosition = event.mouse.position; + console.log('mousedown at ' + mousePosition.x + ' ' + mousePosition.y); + render.options.background = 'cornsilk'; + shakeScene(engine); + }); + + // an example of using mouse events on a mouse + Events.on(mouseConstraint, 'mouseup', function(event) { + var mousePosition = event.mouse.position; + render.options.background = "white"; + console.log('mouseup at ' + mousePosition.x + ' ' + mousePosition.y); + }); + + // an example of using mouse events on a mouse + Events.on(mouseConstraint, 'startdrag', function(event) { + console.log('startdrag', event); + }); + + // an example of using mouse events on a mouse + Events.on(mouseConstraint, 'enddrag', function(event) { + console.log('enddrag', event); + }); + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; \ No newline at end of file diff --git a/examples/friction.js b/examples/friction.js index 2809799..fa6ff1e 100644 --- a/examples/friction.js +++ b/examples/friction.js @@ -1,30 +1,93 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, +Example.friction = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Events = Matter.Events, + Composite = Matter.Composite, + Composites = Matter.Composites, + Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Vertices = Matter.Vertices, Bodies = Matter.Bodies; - Example.friction = function(demo) { - var engine = demo.engine, - world = engine.world; - - World.add(world, [ - Bodies.rectangle(300, 180, 700, 20, { isStatic: true, angle: Math.PI * 0.06 }), - Bodies.rectangle(300, 70, 40, 40, { friction: 0.001 }) - ]); + // create engine + var engine = Engine.create(), + world = engine.world; - World.add(world, [ - Bodies.rectangle(300, 350, 700, 20, { isStatic: true, angle: Math.PI * 0.06 }), - Bodies.rectangle(300, 250, 40, 40, { friction: 0.0005 }) - ]); + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showVelocity: true + } + }); - World.add(world, [ - Bodies.rectangle(300, 520, 700, 20, { isStatic: true, angle: Math.PI * 0.06 }), - Bodies.rectangle(300, 430, 40, 40, { friction: 0 }) - ]); + Render.run(render); - var renderOptions = demo.render.options; - renderOptions.showAngleIndicator = false; - renderOptions.showVelocity = true; + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + World.add(world, [ + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + World.add(world, [ + Bodies.rectangle(300, 180, 700, 20, { isStatic: true, angle: Math.PI * 0.06 }), + Bodies.rectangle(300, 70, 40, 40, { friction: 0.001 }) + ]); + + World.add(world, [ + Bodies.rectangle(300, 350, 700, 20, { isStatic: true, angle: Math.PI * 0.06 }), + Bodies.rectangle(300, 250, 40, 40, { friction: 0.0005 }) + ]); + + World.add(world, [ + Bodies.rectangle(300, 520, 700, 20, { isStatic: true, angle: Math.PI * 0.06 }), + Bodies.rectangle(300, 430, 40, 40, { friction: 0 }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } }; - -})(); \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/gravity.js b/examples/gravity.js index edc39a2..aded9fe 100644 --- a/examples/gravity.js +++ b/examples/gravity.js @@ -1,33 +1,100 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.gravity = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Events = Matter.Events, + Composite = Matter.Composite, Composites = Matter.Composites, - Common = Matter.Common; + Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Vertices = Matter.Vertices, + Bodies = Matter.Bodies; - Example.gravity = function(demo) { - var engine = demo.engine, - world = engine.world; - - engine.world.gravity.y = -1; - - var stack = Composites.stack(20, 20, 20, 5, 0, 0, function(x, y) { - switch (Math.round(Common.random(0, 1))) { + // create engine + var engine = Engine.create(), + world = engine.world; - case 0: - if (Common.random() < 0.8) { - return Bodies.rectangle(x, y, Common.random(20, 50), Common.random(20, 50)); - } else { - return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(20, 30)); + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showVelocity: true, + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + World.add(world, [ + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50.5, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + engine.world.gravity.y = -1; + + var stack = Composites.stack(50, 120, 11, 5, 0, 0, function(x, y) { + switch (Math.round(Common.random(0, 1))) { + + case 0: + if (Common.random() < 0.8) { + return Bodies.rectangle(x, y, Common.random(20, 50), Common.random(20, 50)); + } else { + return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(20, 30)); + } + break; + case 1: + return Bodies.polygon(x, y, Math.round(Common.random(1, 8)), Common.random(20, 50)); + + } + }); + + World.add(world, stack); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false } - break; - case 1: - return Bodies.polygon(x, y, Math.round(Common.random(1, 8)), Common.random(20, 50)); - } }); - - World.add(world, stack); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } }; - -})(); \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/gyro.js b/examples/gyro.js new file mode 100644 index 0000000..6b2dc84 --- /dev/null +++ b/examples/gyro.js @@ -0,0 +1,129 @@ +var Example = Example || {}; + +Example.gyro = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Events = Matter.Events, + Composite = Matter.Composite, + Composites = Matter.Composites, + Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Vertices = Matter.Vertices, + Bodies = Matter.Bodies; + + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024) + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var stack = Composites.stack(20, 20, 10, 5, 0, 0, function(x, y) { + var sides = Math.round(Common.random(1, 8)); + + // triangles can be a little unstable, so avoid until fixed + sides = (sides === 3) ? 4 : sides; + + // round the edges of some bodies + var chamfer = null; + if (sides > 2 && Common.random() > 0.7) { + chamfer = { + radius: 10 + }; + } + + switch (Math.round(Common.random(0, 1))) { + case 0: + if (Common.random() < 0.8) { + return Bodies.rectangle(x, y, Common.random(25, 50), Common.random(25, 50), { chamfer: chamfer }); + } else { + return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(25, 30), { chamfer: chamfer }); + } + break; + case 1: + return Bodies.polygon(x, y, sides, Common.random(25, 50), { chamfer: chamfer }); + } + }); + + World.add(world, [ + stack, + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + // add gyro control + var updateGravity = function(event) { + var orientation = typeof window.orientation !== 'undefined' ? window.orientation : 0, + gravity = engine.world.gravity; + + if (orientation === 0) { + gravity.x = Common.clamp(event.gamma, -90, 90) / 90; + gravity.y = Common.clamp(event.beta, -90, 90) / 90; + } else if (orientation === 180) { + gravity.x = Common.clamp(event.gamma, -90, 90) / 90; + gravity.y = Common.clamp(-event.beta, -90, 90) / 90; + } else if (orientation === 90) { + gravity.x = Common.clamp(event.beta, -90, 90) / 90; + gravity.y = Common.clamp(-event.gamma, -90, 90) / 90; + } else if (orientation === -90) { + gravity.x = Common.clamp(-event.beta, -90, 90) / 90; + gravity.y = Common.clamp(event.gamma, -90, 90) / 90; + } + }; + + window.addEventListener('deviceorientation', updateGravity); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + window.removeEventListener('deviceorientation', updateGravity); + } + }; +}; \ No newline at end of file diff --git a/examples/manipulation.js b/examples/manipulation.js index 75f7f86..b579900 100644 --- a/examples/manipulation.js +++ b/examples/manipulation.js @@ -1,83 +1,141 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.manipulation = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, Body = Matter.Body, - Events = Matter.Events; + Events = Matter.Events, + Composite = Matter.Composite, + Composites = Matter.Composites, + Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Vertices = Matter.Vertices, + Bodies = Matter.Bodies; - Example.manipulation = function(demo) { - var engine = demo.engine, - world = engine.world, - sceneEvents = demo.sceneEvents; + // create engine + var engine = Engine.create(), + world = engine.world; - var bodyA = Bodies.rectangle(100, 200, 50, 50, { isStatic: true }), - bodyB = Bodies.rectangle(200, 200, 50, 50), - bodyC = Bodies.rectangle(300, 200, 50, 50), - bodyD = Bodies.rectangle(400, 200, 50, 50), - bodyE = Bodies.rectangle(550, 200, 50, 50), - bodyF = Bodies.rectangle(700, 200, 50, 50), - bodyG = Bodies.circle(400, 100, 25), - partA = Bodies.rectangle(600, 200, 120, 50), - partB = Bodies.rectangle(660, 200, 50, 190), - compound = Body.create({ - parts: [partA, partB], - isStatic: true - }); + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showAxes: true, + showCollisions: true, + showConvexHulls: true + } + }); - World.add(world, [bodyA, bodyB, bodyC, bodyD, bodyE, bodyF, bodyG, compound]); + Render.run(render); - var counter = 0, - scaleFactor = 1.01; + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); - sceneEvents.push( - Events.on(engine, 'beforeUpdate', function(event) { - counter += 1; + // add bodies + var bodyA = Bodies.rectangle(100, 200, 50, 50, { isStatic: true }), + bodyB = Bodies.rectangle(200, 200, 50, 50), + bodyC = Bodies.rectangle(300, 200, 50, 50), + bodyD = Bodies.rectangle(400, 200, 50, 50), + bodyE = Bodies.rectangle(550, 200, 50, 50), + bodyF = Bodies.rectangle(700, 200, 50, 50), + bodyG = Bodies.circle(400, 100, 25), + partA = Bodies.rectangle(600, 200, 120, 50), + partB = Bodies.rectangle(660, 200, 50, 190), + compound = Body.create({ + parts: [partA, partB], + isStatic: true + }); - if (counter === 40) - Body.setStatic(bodyG, true); + World.add(world, [bodyA, bodyB, bodyC, bodyD, bodyE, bodyF, bodyG, compound]); - if (scaleFactor > 1) { - Body.scale(bodyF, scaleFactor, scaleFactor); - Body.scale(compound, 0.995, 0.995); + World.add(world, [ + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); - // modify bodyE vertices - bodyE.vertices[0].x -= 0.2; - bodyE.vertices[0].y -= 0.2; - bodyE.vertices[1].x += 0.2; - bodyE.vertices[1].y -= 0.2; - Body.setVertices(bodyE, bodyE.vertices); + var counter = 0, + scaleFactor = 1.01; + + Events.on(engine, 'beforeUpdate', function(event) { + counter += 1; + + if (counter === 40) + Body.setStatic(bodyG, true); + + if (scaleFactor > 1) { + Body.scale(bodyF, scaleFactor, scaleFactor); + Body.scale(compound, 0.995, 0.995); + + // modify bodyE vertices + bodyE.vertices[0].x -= 0.2; + bodyE.vertices[0].y -= 0.2; + bodyE.vertices[1].x += 0.2; + bodyE.vertices[1].y -= 0.2; + Body.setVertices(bodyE, bodyE.vertices); + } + + // make bodyA move up and down + // body is static so must manually update velocity for friction to work + var py = 300 + 100 * Math.sin(engine.timing.timestamp * 0.002); + Body.setVelocity(bodyA, { x: 0, y: py - bodyA.position.y }); + Body.setPosition(bodyA, { x: 100, y: py }); + + // make compound body move up and down and rotate constantly + Body.setVelocity(compound, { x: 0, y: py - compound.position.y }); + Body.setAngularVelocity(compound, 0.02); + Body.setPosition(compound, { x: 600, y: py }); + Body.rotate(compound, 0.02); + + // every 1.5 sec + if (counter >= 60 * 1.5) { + Body.setVelocity(bodyB, { x: 0, y: -10 }); + Body.setAngle(bodyC, -Math.PI * 0.26); + Body.setAngularVelocity(bodyD, 0.2); + + // reset counter + counter = 0; + scaleFactor = 1; + } + }); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false } + } + }); - // make bodyA move up and down - // body is static so must manually update velocity for friction to work - var py = 300 + 100 * Math.sin(engine.timing.timestamp * 0.002); - Body.setVelocity(bodyA, { x: 0, y: py - bodyA.position.y }); - Body.setPosition(bodyA, { x: 100, y: py }); + World.add(world, mouseConstraint); - // make compound body move up and down and rotate constantly - Body.setVelocity(compound, { x: 0, y: py - compound.position.y }); - Body.setAngularVelocity(compound, 0.02); - Body.setPosition(compound, { x: 600, y: py }); - Body.rotate(compound, 0.02); + // keep the mouse in sync with rendering + render.mouse = mouse; - // every 1.5 sec - if (counter >= 60 * 1.5) { - Body.setVelocity(bodyB, { x: 0, y: -10 }); - Body.setAngle(bodyC, -Math.PI * 0.26); - Body.setAngularVelocity(bodyD, 0.2); + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); - // reset counter - counter = 0; - scaleFactor = 1; - } - }) - ); - - var renderOptions = demo.render.options; - renderOptions.showAxes = true; - renderOptions.showCollisions = true; - renderOptions.showPositions = true; - renderOptions.showConvexHulls = true; + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } }; - -})(); \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/mixed.js b/examples/mixed.js index 7be4fad..e992ada 100644 --- a/examples/mixed.js +++ b/examples/mixed.js @@ -1,42 +1,107 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.mixed = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Events = Matter.Events, + Composite = Matter.Composite, Composites = Matter.Composites, - Common = Matter.Common; + Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Vertices = Matter.Vertices, + Bodies = Matter.Bodies; - Example.mixed = function(demo) { - var engine = demo.engine, - world = engine.world; + // create engine + var engine = Engine.create(), + world = engine.world; - var stack = Composites.stack(20, 20, 15, 4, 0, 0, function(x, y) { - var sides = Math.round(Common.random(1, 8)); + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showAngleIndicator: true + } + }); - // triangles can be a little unstable, so avoid until fixed - sides = (sides === 3) ? 4 : sides; + Render.run(render); - // round the edges of some bodies - var chamfer = null; - if (sides > 2 && Common.random() > 0.7) { - chamfer = { - radius: 10 - }; + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var stack = Composites.stack(20, 20, 10, 5, 0, 0, function(x, y) { + var sides = Math.round(Common.random(1, 8)); + + // triangles can be a little unstable, so avoid until fixed + sides = (sides === 3) ? 4 : sides; + + // round the edges of some bodies + var chamfer = null; + if (sides > 2 && Common.random() > 0.7) { + chamfer = { + radius: 10 + }; + } + + switch (Math.round(Common.random(0, 1))) { + case 0: + if (Common.random() < 0.8) { + return Bodies.rectangle(x, y, Common.random(25, 50), Common.random(25, 50), { chamfer: chamfer }); + } else { + return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(25, 30), { chamfer: chamfer }); } + break; + case 1: + return Bodies.polygon(x, y, sides, Common.random(25, 50), { chamfer: chamfer }); + } + }); - switch (Math.round(Common.random(0, 1))) { - case 0: - if (Common.random() < 0.8) { - return Bodies.rectangle(x, y, Common.random(25, 50), Common.random(25, 50), { chamfer: chamfer }); - } else { - return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(25, 30), { chamfer: chamfer }); + World.add(world, stack); + + World.add(world, [ + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false } - break; - case 1: - return Bodies.polygon(x, y, sides, Common.random(25, 50), { chamfer: chamfer }); } }); - World.add(world, stack); + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } }; - -})(); \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/mixedSolid.js b/examples/mixedSolid.js deleted file mode 100644 index 7945ce8..0000000 --- a/examples/mixedSolid.js +++ /dev/null @@ -1,35 +0,0 @@ -(function() { - - var World = Matter.World, - Bodies = Matter.Bodies, - Composites = Matter.Composites, - Common = Matter.Common; - - Example.mixedSolid = function(demo) { - var engine = demo.engine, - world = engine.world; - - var stack = Composites.stack(50, 50, 12, 3, 0, 0, function(x, y) { - switch (Math.round(Common.random(0, 1))) { - - case 0: - if (Common.random() < 0.8) { - return Bodies.rectangle(x, y, Common.random(20, 50), Common.random(20, 50)); - } else { - return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(20, 30)); - } - break; - case 1: - return Bodies.polygon(x, y, Math.round(Common.random(1, 8)), Common.random(20, 50)); - - } - }); - - World.add(world, stack); - - var renderOptions = demo.render.options; - renderOptions.wireframes = false; - renderOptions.showAngleIndicator = false; - }; - -})(); \ No newline at end of file diff --git a/examples/newtonsCradle.js b/examples/newtonsCradle.js index b588021..40d491e 100644 --- a/examples/newtonsCradle.js +++ b/examples/newtonsCradle.js @@ -1,23 +1,81 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, +Example.newtonsCradle = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, Body = Matter.Body, - Composites = Matter.Composites; + Composite = Matter.Composite, + Composites = Matter.Composites, + Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; - Example.newtonsCradle = function(demo) { - var engine = demo.engine, - world = engine.world; - - var cradle = Composites.newtonsCradle(280, 100, 5, 30, 200); - World.add(world, cradle); - Body.translate(cradle.bodies[0], { x: -180, y: -100 }); - - cradle = Composites.newtonsCradle(280, 380, 7, 20, 140); - World.add(world, cradle); - Body.translate(cradle.bodies[0], { x: -140, y: -100 }); - - var renderOptions = demo.render.options; - renderOptions.showVelocity = true; + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showVelocity: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var cradle = Composites.newtonsCradle(280, 100, 5, 30, 200); + World.add(world, cradle); + Body.translate(cradle.bodies[0], { x: -180, y: -100 }); + + cradle = Composites.newtonsCradle(280, 380, 7, 20, 140); + World.add(world, cradle); + Body.translate(cradle.bodies[0], { x: -140, y: -100 }); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 700 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } }; - -})(); \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/pyramid.js b/examples/pyramid.js index ec3f3ba..6215910 100644 --- a/examples/pyramid.js +++ b/examples/pyramid.js @@ -1,18 +1,79 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, - Composites = Matter.Composites; +Example.pyramid = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Composite = Matter.Composite, + Composites = Matter.Composites, + Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; - Example.pyramid = function(demo) { - var engine = demo.engine, - world = engine.world; + // create engine + var engine = Engine.create(), + world = engine.world; - var stack = Composites.pyramid(100, 258, 15, 10, 0, 0, function(x, y) { - return Bodies.rectangle(x, y, 40, 40); + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var stack = Composites.pyramid(100, 258, 15, 10, 0, 0, function(x, y) { + return Bodies.rectangle(x, y, 40, 40); + }); + + World.add(world, [ + stack, + Bodies.rectangle(400, 620, 800, 50, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } }); - - World.add(world, stack); - }; -})(); \ No newline at end of file + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; \ No newline at end of file diff --git a/examples/raycasting.js b/examples/raycasting.js index 5d3f74c..5cc2008 100644 --- a/examples/raycasting.js +++ b/examples/raycasting.js @@ -1,72 +1,134 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.raycasting = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, Composite = Matter.Composite, Composites = Matter.Composites, Common = Matter.Common, + Query = Matter.Query, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, Events = Matter.Events, + World = Matter.World, Vertices = Matter.Vertices, - Query = Matter.Query; + Bodies = Matter.Bodies; - Example.raycasting = function(demo) { - var engine = demo.engine, - world = engine.world, - sceneEvents = demo.sceneEvents, - mouseConstraint = demo.mouseConstraint; - - var stack = Composites.stack(20, 20, 15, 4, 0, 0, function(x, y) { - switch (Math.round(Common.random(0, 1))) { + // create engine + var engine = Engine.create(), + world = engine.world; - case 0: - if (Common.random() < 0.8) { - return Bodies.rectangle(x, y, Common.random(20, 50), Common.random(20, 50)); - } else { - return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(20, 30)); + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var stack = Composites.stack(20, 20, 12, 4, 0, 0, function(x, y) { + switch (Math.round(Common.random(0, 1))) { + + case 0: + if (Common.random() < 0.8) { + return Bodies.rectangle(x, y, Common.random(20, 50), Common.random(20, 50)); + } else { + return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(20, 30)); + } + break; + case 1: + var sides = Math.round(Common.random(1, 8)); + sides = (sides === 3) ? 4 : sides; + return Bodies.polygon(x, y, sides, Common.random(20, 50)); + } + }); + + var star = Vertices.fromPath('50 0 63 38 100 38 69 59 82 100 50 75 18 100 31 59 0 38 37 38'), + concave = Bodies.fromVertices(200, 200, star); + + World.add(world, [ + stack, + concave, + Bodies.rectangle(400, 600, 800, 50.5, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + Events.on(render, 'afterRender', function() { + var mouse = mouseConstraint.mouse, + context = render.context, + bodies = Composite.allBodies(engine.world), + startPoint = { x: 400, y: 100 }, + endPoint = mouse.position; + + var collisions = Query.ray(bodies, startPoint, endPoint); + + Render.startViewTransform(render); + + context.beginPath(); + context.moveTo(startPoint.x, startPoint.y); + context.lineTo(endPoint.x, endPoint.y); + if (collisions.length > 0) { + context.strokeStyle = '#fff'; + } else { + context.strokeStyle = '#555'; + } + context.lineWidth = 0.5; + context.stroke(); + + for (var i = 0; i < collisions.length; i++) { + var collision = collisions[i]; + context.rect(collision.bodyA.position.x - 4.5, collision.bodyA.position.y - 4.5, 8, 8); + } + + context.fillStyle = 'rgba(255,165,0,0.7)'; + context.fill(); + + Render.endViewTransform(render); + }); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false } - break; - case 1: - var sides = Math.round(Common.random(1, 8)); - sides = (sides === 3) ? 4 : sides; - return Bodies.polygon(x, y, sides, Common.random(20, 50)); } }); - var star = Vertices.fromPath('50 0 63 38 100 38 69 59 82 100 50 75 18 100 31 59 0 38 37 38'), - concave = Bodies.fromVertices(200, 200, star); - - World.add(world, [stack, concave]); + World.add(world, mouseConstraint); - sceneEvents.push( - Events.on(demo.render, 'afterRender', function() { - var mouse = mouseConstraint.mouse, - context = demo.render.context, - bodies = Composite.allBodies(engine.world), - startPoint = { x: 400, y: 100 }, - endPoint = mouse.position; + // keep the mouse in sync with rendering + render.mouse = mouse; - var collisions = Query.ray(bodies, startPoint, endPoint); + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); - context.beginPath(); - context.moveTo(startPoint.x, startPoint.y); - context.lineTo(endPoint.x, endPoint.y); - if (collisions.length > 0) { - context.strokeStyle = '#fff'; - } else { - context.strokeStyle = '#555'; - } - context.lineWidth = 0.5; - context.stroke(); - - for (var i = 0; i < collisions.length; i++) { - var collision = collisions[i]; - context.rect(collision.bodyA.position.x - 4.5, collision.bodyA.position.y - 4.5, 8, 8); - } - - context.fillStyle = 'rgba(255,165,0,0.7)'; - context.fill(); - }) - ); + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } }; - -})(); \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/restitution.js b/examples/restitution.js index ff1a31a..239ccd9 100644 --- a/examples/restitution.js +++ b/examples/restitution.js @@ -1,27 +1,84 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, +Example.restitution = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Composite = Matter.Composite, + Composites = Matter.Composites, + Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, Bodies = Matter.Bodies; - Example.restitution = function(demo) { - var engine = demo.engine, - world = engine.world; - - var rest = 0.9, - space = 600 / 5; - - World.add(world, [ - Bodies.rectangle(100 + space * 0, 150, 50, 50, { restitution: rest }), - Bodies.rectangle(100 + space * 1, 150, 50, 50, { restitution: rest, angle: -Math.PI * 0.15 }), - Bodies.rectangle(100 + space * 2, 150, 50, 50, { restitution: rest, angle: -Math.PI * 0.25 }), - Bodies.circle(100 + space * 3, 150, 25, { restitution: rest }), - Bodies.rectangle(100 + space * 5, 150, 180, 20, { restitution: rest, angle: -Math.PI * 0.5 }) - ]); - - var renderOptions = demo.render.options; - renderOptions.showCollisions = true; - renderOptions.showVelocity = true; - renderOptions.showAngleIndicator = true; - }; + // create engine + var engine = Engine.create(), + world = engine.world; -})(); \ No newline at end of file + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showAngleIndicator: true, + showCollisions: true, + showVelocity: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var rest = 0.9, + space = 600 / 5; + + World.add(world, [ + Bodies.rectangle(100 + space * 0, 150, 50, 50, { restitution: rest }), + Bodies.rectangle(100 + space * 1, 150, 50, 50, { restitution: rest, angle: -Math.PI * 0.15 }), + Bodies.rectangle(100 + space * 2, 150, 50, 50, { restitution: rest, angle: -Math.PI * 0.25 }), + Bodies.circle(100 + space * 3, 150, 25, { restitution: rest }), + Bodies.rectangle(100 + space * 5, 150, 180, 20, { restitution: rest, angle: -Math.PI * 0.5 }), + Bodies.rectangle(400, 620, 800, 50, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; \ No newline at end of file diff --git a/examples/rounded.js b/examples/rounded.js index 79a085c..79d95b6 100644 --- a/examples/rounded.js +++ b/examples/rounded.js @@ -1,49 +1,108 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, +Example.rounded = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composite = Matter.Composite, + Composites = Matter.Composites, + Common = Matter.Common, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, Bodies = Matter.Bodies; - Example.rounded = function(demo) { - var engine = demo.engine, - world = engine.world; + // create engine + var engine = Engine.create(), + world = engine.world; - World.add(world, [ - Bodies.rectangle(200, 200, 100, 100, { - chamfer: { radius: 20 } - }), + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showAxes: true + } + }); - Bodies.rectangle(300, 200, 100, 100, { - chamfer: { radius: [90, 0, 0, 0] } - }), + Render.run(render); - Bodies.rectangle(400, 200, 200, 200, { - chamfer: { radius: [150, 20, 40, 20] } - }), + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); - Bodies.rectangle(200, 200, 200, 200, { - chamfer: { radius: [150, 20, 150, 20] } - }), + // add bodies + World.add(world, [ + Bodies.rectangle(400, 600, 800, 50.5, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); - Bodies.rectangle(300, 200, 200, 50, { - chamfer: { radius: [25, 25, 0, 0] } - }), + World.add(world, [ + Bodies.rectangle(200, 200, 100, 100, { + chamfer: { radius: 20 } + }), - Bodies.polygon(200, 100, 8, 80, { - chamfer: { radius: 30 } - }), + Bodies.rectangle(300, 200, 100, 100, { + chamfer: { radius: [90, 0, 0, 0] } + }), - Bodies.polygon(300, 100, 5, 80, { - chamfer: { radius: [10, 40, 20, 40, 10] } - }), + Bodies.rectangle(400, 200, 200, 200, { + chamfer: { radius: [150, 20, 40, 20] } + }), - Bodies.polygon(400, 200, 3, 50, { - chamfer: { radius: [20, 0, 20] } - }) - ]); + Bodies.rectangle(200, 200, 200, 200, { + chamfer: { radius: [150, 20, 150, 20] } + }), - var renderOptions = demo.render.options; - renderOptions.showAxes = true; - renderOptions.showCollisions = true; + Bodies.rectangle(300, 200, 200, 50, { + chamfer: { radius: [25, 25, 0, 0] } + }), + + Bodies.polygon(200, 100, 8, 80, { + chamfer: { radius: 30 } + }), + + Bodies.polygon(300, 100, 5, 80, { + chamfer: { radius: [10, 40, 20, 40, 10] } + }), + + Bodies.polygon(400, 200, 3, 50, { + chamfer: { radius: [20, 0, 20] } + }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } }; - -})(); \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/sensors.js b/examples/sensors.js index 127ec6a..fcfafb1 100644 --- a/examples/sensors.js +++ b/examples/sensors.js @@ -1,70 +1,131 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.sensors = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Composite = Matter.Composite, + Composites = Matter.Composites, Common = Matter.Common, - Events = Matter.Events; + Events = Matter.Events, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; - Example.sensors = function(demo) { - var engine = demo.engine, - world = engine.world, - sceneEvents = demo.sceneEvents; + // create engine + var engine = Engine.create(), + world = engine.world; - var redColor = '#C44D58', - greenColor = '#C7F464'; + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + wireframes: false, + background: '#111' + } + }); - var collider = Bodies.rectangle(400, 300, 500, 50, { - isSensor: true, + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var redColor = '#C44D58', + greenColor = '#C7F464'; + + var collider = Bodies.rectangle(400, 300, 500, 50, { + isSensor: true, + isStatic: true, + render: { + strokeStyle: redColor, + fillStyle: 'transparent' + } + }); + + World.add(world, [ + collider, + Bodies.rectangle(400, 620, 800, 50, { isStatic: true, render: { - strokeStyle: redColor, fillStyle: 'transparent' } + }) + ]); + + World.add(world, + Bodies.circle(400, 40, 30, { + render: { + strokeStyle: greenColor, + fillStyle: 'transparent' + } + }) + ); + + Events.on(engine, 'collisionStart', function(event) { + var pairs = event.pairs; + + for (var i = 0, j = pairs.length; i != j; ++i) { + var pair = pairs[i]; + + if (pair.bodyA === collider) { + pair.bodyB.render.strokeStyle = redColor; + } else if (pair.bodyB === collider) { + pair.bodyA.render.strokeStyle = redColor; + } + } + }); + + Events.on(engine, 'collisionEnd', function(event) { + var pairs = event.pairs; + + for (var i = 0, j = pairs.length; i != j; ++i) { + var pair = pairs[i]; + + if (pair.bodyA === collider) { + pair.bodyB.render.strokeStyle = greenColor; + } else if (pair.bodyB === collider) { + pair.bodyA.render.strokeStyle = greenColor; + } + } + }); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } }); - World.add(world, collider); + World.add(world, mouseConstraint); - World.add(world, - Bodies.circle(400, 40, 30, { - render: { - strokeStyle: greenColor, - fillStyle: 'transparent' - } - }) - ); + // keep the mouse in sync with rendering + render.mouse = mouse; - sceneEvents.push( - Events.on(engine, 'collisionStart', function(event) { - var pairs = event.pairs; - - for (var i = 0, j = pairs.length; i != j; ++i) { - var pair = pairs[i]; + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); - if (pair.bodyA === collider) { - pair.bodyB.render.strokeStyle = redColor; - } else if (pair.bodyB === collider) { - pair.bodyA.render.strokeStyle = redColor; - } - } - }), - Events.on(engine, 'collisionEnd', function(event) { - var pairs = event.pairs; - - for (var i = 0, j = pairs.length; i != j; ++i) { - var pair = pairs[i]; - - if (pair.bodyA === collider) { - pair.bodyB.render.strokeStyle = greenColor; - } else if (pair.bodyB === collider) { - pair.bodyA.render.strokeStyle = greenColor; - } - } - }) - ); - - var renderOptions = demo.render.options; - renderOptions.wireframes = false; - renderOptions.background = '#222'; - renderOptions.showAngleIndicator = false; + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } }; -})(); \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/sleeping.js b/examples/sleeping.js index 089a89f..596e464 100644 --- a/examples/sleeping.js +++ b/examples/sleeping.js @@ -1,41 +1,102 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.sleeping = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composite = Matter.Composite, Composites = Matter.Composites, Common = Matter.Common, - Events = Matter.Events; + Events = Matter.Events, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; - Example.sleeping = function(demo) { - var engine = demo.engine, - world = engine.world; - - var stack = Composites.stack(50, 50, 12, 3, 0, 0, function(x, y) { - switch (Math.round(Common.random(0, 1))) { + // create engine + var engine = Engine.create({ + enableSleeping: true + }), + world = engine.world; - case 0: - if (Common.random() < 0.8) { - return Bodies.rectangle(x, y, Common.random(20, 50), Common.random(20, 50)); - } else { - return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(20, 30)); + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + World.add(world, [ + Bodies.rectangle(400, 600, 800, 50.5, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + var stack = Composites.stack(50, 50, 12, 3, 0, 0, function(x, y) { + switch (Math.round(Common.random(0, 1))) { + + case 0: + if (Common.random() < 0.8) { + return Bodies.rectangle(x, y, Common.random(20, 50), Common.random(20, 50)); + } else { + return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(20, 30)); + } + break; + case 1: + return Bodies.polygon(x, y, Math.round(Common.random(1, 8)), Common.random(20, 50)); + + } + }); + + World.add(world, stack); + + for (var i = 0; i < stack.bodies.length; i++) { + Events.on(stack.bodies[i], 'sleepStart sleepEnd', function(event) { + var body = this; + console.log('body id', body.id, 'sleeping:', body.isSleeping); + }); + } + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false } - break; - case 1: - return Bodies.polygon(x, y, Math.round(Common.random(1, 8)), Common.random(20, 50)); - } }); - - World.add(world, stack); - for (var i = 0; i < stack.bodies.length; i++) { - Events.on(stack.bodies[i], 'sleepStart sleepEnd', function(event) { - var body = this; - console.log('body id', body.id, 'sleeping:', body.isSleeping); - }); + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); } - - engine.enableSleeping = true; }; - -})(); \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/slingshot.js b/examples/slingshot.js index 610eedc..947aac0 100644 --- a/examples/slingshot.js +++ b/examples/slingshot.js @@ -1,64 +1,104 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.slingshot = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Composite = Matter.Composite, Composites = Matter.Composites, + Events = Matter.Events, + Common = Matter.Common, Constraint = Matter.Constraint, - Events = Matter.Events; + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; - Example.slingshot = function(demo) { - var engine = demo.engine, - world = engine.world, - mouseConstraint = demo.mouseConstraint; + // create engine + var engine = Engine.create(), + world = engine.world; - world.bodies = []; + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showAngleIndicator: true + } + }); - var ground = Bodies.rectangle(395, 600, 815, 50, { isStatic: true, render: { visible: false } }), - rockOptions = { density: 0.004, render: { sprite: { texture: './img/rock.png' } } }, - rock = Bodies.polygon(170, 450, 8, 20, rockOptions), - anchor = { x: 170, y: 450 }, - elastic = Constraint.create({ - pointA: anchor, - bodyB: rock, - stiffness: 0.05, - render: { - lineWidth: 5, - strokeStyle: '#dfa417' - } - }); + Render.run(render); - var pyramid = Composites.pyramid(500, 300, 9, 10, 0, 0, function(x, y, column) { - var texture = column % 2 === 0 ? './img/block.png' : './img/block-2.png'; - return Bodies.rectangle(x, y, 25, 40, { render: { sprite: { texture: texture } } }); + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var ground = Bodies.rectangle(395, 600, 815, 50, { isStatic: true }), + rockOptions = { density: 0.004 }, + rock = Bodies.polygon(170, 450, 8, 20, rockOptions), + anchor = { x: 170, y: 450 }, + elastic = Constraint.create({ + pointA: anchor, + bodyB: rock, + stiffness: 0.05 }); - var ground2 = Bodies.rectangle(610, 250, 200, 20, { - isStatic: true, - render: { - fillStyle: '#edc51e', - strokeStyle: '#b5a91c' - } - }); + var pyramid = Composites.pyramid(500, 300, 9, 10, 0, 0, function(x, y) { + return Bodies.rectangle(x, y, 25, 40); + }); - var pyramid2 = Composites.pyramid(550, 0, 5, 10, 0, 0, function(x, y, column) { - var texture = column % 2 === 0 ? './img/block.png' : './img/block-2.png'; - return Bodies.rectangle(x, y, 25, 40, { render: { sprite: { texture: texture } } }); - }); + var ground2 = Bodies.rectangle(610, 250, 200, 20, { isStatic: true }); - World.add(engine.world, [ground, pyramid, ground2, pyramid2, rock, elastic]); + var pyramid2 = Composites.pyramid(550, 0, 5, 10, 0, 0, function(x, y) { + return Bodies.rectangle(x, y, 25, 40); + }); - Events.on(engine, 'afterUpdate', function() { - if (mouseConstraint.mouse.button === -1 && (rock.position.x > 190 || rock.position.y < 430)) { - rock = Bodies.polygon(170, 450, 7, 20, rockOptions); - World.add(engine.world, rock); - elastic.bodyB = rock; + World.add(engine.world, [ground, pyramid, ground2, pyramid2, rock, elastic]); + + Events.on(engine, 'afterUpdate', function() { + if (mouseConstraint.mouse.button === -1 && (rock.position.x > 190 || rock.position.y < 430)) { + rock = Bodies.polygon(170, 450, 7, 20, rockOptions); + World.add(engine.world, rock); + elastic.bodyB = rock; + } + }); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } } }); - - var renderOptions = demo.render.options; - renderOptions.wireframes = false; - renderOptions.showAngleIndicator = false; - renderOptions.background = './img/background.png'; - }; -})(); \ No newline at end of file + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; \ No newline at end of file diff --git a/examples/softBody.js b/examples/softBody.js index 7ab95e0..7b30520 100644 --- a/examples/softBody.js +++ b/examples/softBody.js @@ -1,26 +1,83 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Composites = Matter.Composites; +Example.softBody = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Composite = Matter.Composite, + Composites = Matter.Composites, + Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; - Example.softBody = function(demo) { - var engine = demo.engine, - world = engine.world; - - var particleOptions = { - friction: 0.05, - frictionStatic: 0.1, - render: { visible: true } - }; + // create engine + var engine = Engine.create(), + world = engine.world; - World.add(world, [ - Composites.softBody(250, 100, 5, 5, 0, 0, true, 18, particleOptions), - Composites.softBody(400, 300, 8, 3, 0, 0, true, 15, particleOptions), - Composites.softBody(250, 400, 4, 4, 0, 0, true, 15, particleOptions) - ]); + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showAngleIndicator: false + } + }); - var renderOptions = demo.render.options; - renderOptions.showAngleIndicator = false; + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var particleOptions = { + friction: 0.05, + frictionStatic: 0.1, + render: { visible: true } }; -})(); + World.add(world, [ + Composites.softBody(250, 100, 5, 5, 0, 0, true, 18, particleOptions), + Composites.softBody(400, 300, 8, 3, 0, 0, true, 15, particleOptions), + Composites.softBody(250, 400, 4, 4, 0, 0, true, 15, particleOptions), + Bodies.rectangle(400, 620, 800, 50, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.9, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; \ No newline at end of file diff --git a/examples/sprites.js b/examples/sprites.js index 341332b..e355311 100644 --- a/examples/sprites.js +++ b/examples/sprites.js @@ -1,62 +1,118 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.sprites = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composite = Matter.Composite, Composites = Matter.Composites, - Common = Matter.Common; + Common = Matter.Common, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; - Example.sprites = function(demo) { - var engine = demo.engine, - world = engine.world, - offset = 10, - options = { - isStatic: true, + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + background: '#0f0f13', + showAngleIndicator: false, + wireframes: false + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var offset = 10, + options = { + isStatic: true, + render: { + visible: false + } + }; + + world.bodies = []; + + // these static walls will not be rendered in this sprites example, see options + World.add(world, [ + Bodies.rectangle(400, -offset, 800.5 + 2 * offset, 50.5, options), + Bodies.rectangle(400, 600 + offset, 800.5 + 2 * offset, 50.5, options), + Bodies.rectangle(800 + offset, 300, 50.5, 600.5 + 2 * offset, options), + Bodies.rectangle(-offset, 300, 50.5, 600.5 + 2 * offset, options) + ]); + + var stack = Composites.stack(20, 20, 10, 4, 0, 0, function(x, y) { + if (Common.random() > 0.35) { + return Bodies.rectangle(x, y, 64, 64, { + render: { + strokeStyle: '#ffffff', + sprite: { + texture: './img/box.png' + } + } + }); + } else { + return Bodies.circle(x, y, 46, { + density: 0.0005, + frictionAir: 0.06, + restitution: 0.3, + friction: 0.01, + render: { + sprite: { + texture: './img/ball.png' + } + } + }); + } + }); + + World.add(world, stack); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, render: { visible: false } - }; - - world.bodies = []; - - // these static walls will not be rendered in this sprites example, see options - World.add(world, [ - Bodies.rectangle(400, -offset, 800.5 + 2 * offset, 50.5, options), - Bodies.rectangle(400, 600 + offset, 800.5 + 2 * offset, 50.5, options), - Bodies.rectangle(800 + offset, 300, 50.5, 600.5 + 2 * offset, options), - Bodies.rectangle(-offset, 300, 50.5, 600.5 + 2 * offset, options) - ]); - - var stack = Composites.stack(20, 20, 10, 4, 0, 0, function(x, y) { - if (Common.random() > 0.35) { - return Bodies.rectangle(x, y, 64, 64, { - render: { - strokeStyle: '#ffffff', - sprite: { - texture: './img/box.png' - } - } - }); - } else { - return Bodies.circle(x, y, 46, { - density: 0.0005, - frictionAir: 0.06, - restitution: 0.3, - friction: 0.01, - render: { - sprite: { - texture: './img/ball.png' - } - } - }); } }); - World.add(world, stack); + World.add(world, mouseConstraint); - var renderOptions = demo.render.options; - renderOptions.background = './img/wall-bg.jpg'; - renderOptions.showAngleIndicator = false; - renderOptions.wireframes = false; + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } }; - -})(); \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/stack.js b/examples/stack.js index 8dcdfc7..734fb93 100644 --- a/examples/stack.js +++ b/examples/stack.js @@ -1,18 +1,81 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, - Composites = Matter.Composites; +Example.stack = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Events = Matter.Events, + Composite = Matter.Composite, + Composites = Matter.Composites, + Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Vertices = Matter.Vertices, + Bodies = Matter.Bodies; - Example.stack = function(demo) { - var engine = demo.engine, - world = engine.world; - - var stack = Composites.stack(100, 380, 10, 5, 0, 0, function(x, y) { - return Bodies.rectangle(x, y, 40, 40); + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var stack = Composites.stack(200, 380, 10, 5, 0, 0, function(x, y) { + return Bodies.rectangle(x, y, 40, 40); + }); + + World.add(world, [ + stack, + Bodies.rectangle(400, 600, 800, 50.5, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } }); - - World.add(world, stack); - }; -})(); + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; \ No newline at end of file diff --git a/examples/staticFriction.js b/examples/staticFriction.js index 755e0dc..53b9f58 100644 --- a/examples/staticFriction.js +++ b/examples/staticFriction.js @@ -1,49 +1,102 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.staticFriction = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, Body = Matter.Body, + Composite = Matter.Composite, Composites = Matter.Composites, - Events = Matter.Events; + Common = Matter.Common, + Constraint = Matter.Constraint, + Events = Matter.Events, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Bodies = Matter.Bodies; - Example.staticFriction = function(demo) { - var engine = demo.engine, - world = engine.world, - sceneEvents = demo.sceneEvents; + // create engine + var engine = Engine.create(), + world = engine.world; - var body = Bodies.rectangle(400, 500, 200, 60, { isStatic: true, chamfer: 10 }), - size = 50, - counter = -1; + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showVelocity: true + } + }); - var stack = Composites.stack(350, 470 - 6 * size, 1, 6, 0, 0, function(x, y) { - return Bodies.rectangle(x, y, size * 2, size, { - slop: 0.5, - friction: 1, - frictionStatic: Infinity - }); + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var body = Bodies.rectangle(400, 500, 200, 60, { isStatic: true, chamfer: 10 }), + size = 50, + counter = -1; + + var stack = Composites.stack(350, 470 - 6 * size, 1, 6, 0, 0, function(x, y) { + return Bodies.rectangle(x, y, size * 2, size, { + slop: 0.5, + friction: 1, + frictionStatic: Infinity }); - - World.add(world, [body, stack]); - - sceneEvents.push( - Events.on(engine, 'beforeUpdate', function(event) { - counter += 0.014; - - if (counter < 0) { - return; - } - - var px = 400 + 100 * Math.sin(counter); - - // body is static so must manually update velocity for friction to work - Body.setVelocity(body, { x: px - body.position.x, y: 0 }); - Body.setPosition(body, { x: px, y: body.position.y }); - }) - ); - - var renderOptions = demo.render.options; - renderOptions.showAngleIndicator = false; - renderOptions.showVelocity = true; - }; + }); -})(); \ No newline at end of file + World.add(world, [body, stack]); + + Events.on(engine, 'beforeUpdate', function(event) { + counter += 0.014; + + if (counter < 0) { + return; + } + + var px = 400 + 100 * Math.sin(counter); + + // body is static so must manually update velocity for friction to work + Body.setVelocity(body, { x: px - body.position.x, y: 0 }); + Body.setPosition(body, { x: px, y: body.position.y }); + }); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; \ No newline at end of file diff --git a/examples/stress.js b/examples/stress.js index 779a177..b7781e7 100644 --- a/examples/stress.js +++ b/examples/stress.js @@ -1,21 +1,83 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, - Composites = Matter.Composites; +Example.stress = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Events = Matter.Events, + Composite = Matter.Composite, + Composites = Matter.Composites, + Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Vertices = Matter.Vertices, + Bodies = Matter.Bodies; - Example.stress = function(demo) { - var engine = demo.engine, - world = engine.world; - - var stack = Composites.stack(90, 50, 18, 15, 0, 0, function(x, y) { - return Bodies.rectangle(x, y, 35, 35); + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024) + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // scene code + var stack = Composites.stack(90, 50, 18, 15, 0, 0, function(x, y) { + return Bodies.rectangle(x, y, 35, 35); + }); + + World.add(world, [ + stack, + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } }); - - World.add(world, stack); - var renderOptions = demo.render.options; - renderOptions.showAngleIndicator = false; + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } }; - -})(); \ No newline at end of file +}; \ No newline at end of file diff --git a/examples/stress2.js b/examples/stress2.js index 5a42e87..0263e66 100644 --- a/examples/stress2.js +++ b/examples/stress2.js @@ -1,21 +1,81 @@ -(function() { +Example.stress2 = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Events = Matter.Events, + Composite = Matter.Composite, + Composites = Matter.Composites, + Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Vertices = Matter.Vertices, + Bodies = Matter.Bodies; - var World = Matter.World, - Bodies = Matter.Bodies, - Composites = Matter.Composites; + // create engine + var engine = Engine.create(), + world = engine.world; - Example.stress2 = function(demo) { - var engine = demo.engine, - world = engine.world; - - var stack = Composites.stack(100, 120, 25, 18, 0, 0, function(x, y) { - return Bodies.rectangle(x, y, 25, 25); + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024) + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // scene code + var stack = Composites.stack(100, 120, 25, 18, 0, 0, function(x, y) { + return Bodies.rectangle(x, y, 25, 25); + }); + + World.add(world, [ + stack, + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } }); - - World.add(world, stack); - - var renderOptions = demo.render.options; - renderOptions.showAngleIndicator = false; - }; -})(); \ No newline at end of file + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; \ No newline at end of file diff --git a/examples/svg.js b/examples/svg.js index dccd921..ffd682e 100644 --- a/examples/svg.js +++ b/examples/svg.js @@ -1,61 +1,123 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.svg = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Events = Matter.Events, + Composite = Matter.Composite, + Composites = Matter.Composites, Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, Vertices = Matter.Vertices, - Svg = Matter.Svg; + Svg = Matter.Svg, + Bodies = Matter.Bodies; - Example.svg = function(demo) { - var engine = demo.engine, - world = engine.world; + // create engine + var engine = Engine.create(), + world = engine.world; - var svgs = [ - 'iconmonstr-check-mark-8-icon', - 'iconmonstr-paperclip-2-icon', - 'iconmonstr-puzzle-icon', - 'iconmonstr-user-icon' - ]; - - for (var i = 0; i < svgs.length; i += 1) { - (function(i) { - $.get('./svg/' + svgs[i] + '.svg').done(function(data) { - var vertexSets = [], - color = Common.choose(['#556270', '#4ECDC4', '#C7F464', '#FF6B6B', '#C44D58']); - - $(data).find('path').each(function(i, path) { - var points = Svg.pathToVertices(path, 30); - vertexSets.push(Vertices.scale(points, 0.4, 0.4)); - }); - - World.add(world, Bodies.fromVertices(100 + i * 150, 200 + i * 50, vertexSets, { - render: { - fillStyle: color, - strokeStyle: color - } - }, true)); - }); - })(i); + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024) } + }); - $.get('./svg/svg.svg').done(function(data) { - var vertexSets = [], - color = Common.choose(['#556270', '#4ECDC4', '#C7F464', '#FF6B6B', '#C44D58']); + Render.run(render); - $(data).find('path').each(function(i, path) { - vertexSets.push(Svg.pathToVertices(path, 30)); + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var svgs = [ + 'iconmonstr-check-mark-8-icon', + 'iconmonstr-paperclip-2-icon', + 'iconmonstr-puzzle-icon', + 'iconmonstr-user-icon' + ]; + + for (var i = 0; i < svgs.length; i += 1) { + (function(i) { + $.get('./svg/' + svgs[i] + '.svg').done(function(data) { + var vertexSets = [], + color = Common.choose(['#556270', '#4ECDC4', '#C7F464', '#FF6B6B', '#C44D58']); + + $(data).find('path').each(function(i, path) { + var points = Svg.pathToVertices(path, 30); + vertexSets.push(Vertices.scale(points, 0.4, 0.4)); + }); + + World.add(world, Bodies.fromVertices(100 + i * 150, 200 + i * 50, vertexSets, { + render: { + fillStyle: color, + strokeStyle: color + } + }, true)); }); + })(i); + } - World.add(world, Bodies.fromVertices(400, 80, vertexSets, { - render: { - fillStyle: color, - strokeStyle: color - } - }, true)); + $.get('./svg/svg.svg').done(function(data) { + var vertexSets = [], + color = Common.choose(['#556270', '#4ECDC4', '#C7F464', '#FF6B6B', '#C44D58']); + + $(data).find('path').each(function(i, path) { + vertexSets.push(Svg.pathToVertices(path, 30)); }); - var renderOptions = demo.render.options; - renderOptions.showAngleIndicator = false; - }; + World.add(world, Bodies.fromVertices(400, 80, vertexSets, { + render: { + fillStyle: color, + strokeStyle: color + } + }, true)); + }); -})(); \ No newline at end of file + World.add(world, [ + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; \ No newline at end of file diff --git a/examples/terrain.js b/examples/terrain.js index 77f8c27..755a8f1 100644 --- a/examples/terrain.js +++ b/examples/terrain.js @@ -1,54 +1,109 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.terrain = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Events = Matter.Events, + Composite = Matter.Composite, Composites = Matter.Composites, Common = Matter.Common, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Vertices = Matter.Vertices, Query = Matter.Query, - Svg = Matter.Svg; + Svg = Matter.Svg, + Bodies = Matter.Bodies; - Example.terrain = function(demo) { - var engine = demo.engine, - world = engine.world; + // create engine + var engine = Engine.create(), + world = engine.world; - world.bodies = []; + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024) + } + }); - var terrain; + Render.run(render); - $.get('./svg/terrain.svg').done(function(data) { - var vertexSets = [], - color = Common.choose(['#556270', '#4ECDC4', '#C7F464', '#FF6B6B', '#C44D58']); + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); - $(data).find('path').each(function(i, path) { - vertexSets.push(Svg.pathToVertices(path, 30)); - }); + // add bodies + var terrain; - terrain = Bodies.fromVertices(400, 350, vertexSets, { - isStatic: true, - render: { - fillStyle: color, - strokeStyle: color - } - }, true); + $.get('./svg/terrain.svg').done(function(data) { + var vertexSets = [], + color = Common.choose(['#556270', '#4ECDC4', '#C7F464', '#FF6B6B', '#C44D58']); - World.add(world, terrain); - - var bodyOptions = { - frictionAir: 0, - friction: 0.0001, - restitution: 0.6 - }; - - World.add(world, Composites.stack(80, 100, 20, 20, 10, 10, function(x, y) { - if (Query.point([terrain], { x: x, y: y }).length === 0) { - return Bodies.polygon(x, y, 5, 12, bodyOptions); - } - })); + $(data).find('path').each(function(i, path) { + vertexSets.push(Svg.pathToVertices(path, 30)); }); - var renderOptions = demo.render.options; - renderOptions.showAngleIndicator = false; - renderOptions.showVelocity = true; - }; + terrain = Bodies.fromVertices(400, 350, vertexSets, { + isStatic: true, + render: { + fillStyle: color, + strokeStyle: color + } + }, true); -})(); \ No newline at end of file + World.add(world, terrain); + + var bodyOptions = { + frictionAir: 0, + friction: 0.0001, + restitution: 0.6 + }; + + World.add(world, Composites.stack(80, 100, 20, 20, 10, 10, function(x, y) { + if (Query.point([terrain], { x: x, y: y }).length === 0) { + return Bodies.polygon(x, y, 5, 12, bodyOptions); + } + })); + }); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; \ No newline at end of file diff --git a/examples/timescale.js b/examples/timescale.js index 6bf8b21..71f32f4 100644 --- a/examples/timescale.js +++ b/examples/timescale.js @@ -1,91 +1,157 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.timescale = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, Body = Matter.Body, + Events = Matter.Events, Composite = Matter.Composite, Composites = Matter.Composites, Common = Matter.Common, - Events = Matter.Events; + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Vertices = Matter.Vertices, + Query = Matter.Query, + Svg = Matter.Svg, + Bodies = Matter.Bodies; - Example.timescale = function(demo) { - var engine = demo.engine, - world = engine.world, - sceneEvents = demo.sceneEvents; - - var explosion = function(engine) { - var bodies = Composite.allBodies(engine.world); + // create engine + var engine = Engine.create(), + world = engine.world; - for (var i = 0; i < bodies.length; i++) { - var body = bodies[i]; + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showAngleIndicator: true + } + }); - if (!body.isStatic && body.position.y >= 500) { - var forceMagnitude = 0.05 * body.mass; + Render.run(render); - Body.applyForce(body, body.position, { - x: (forceMagnitude + Common.random() * forceMagnitude) * Common.choose([1, -1]), - y: -forceMagnitude + Common.random() * -forceMagnitude - }); - } + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + World.add(world, [ + Bodies.rectangle(400, 0, 800, 50, { isStatic: true }), + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + var explosion = function(engine) { + var bodies = Composite.allBodies(engine.world); + + for (var i = 0; i < bodies.length; i++) { + var body = bodies[i]; + + if (!body.isStatic && body.position.y >= 500) { + var forceMagnitude = 0.05 * body.mass; + + Body.applyForce(body, body.position, { + x: (forceMagnitude + Common.random() * forceMagnitude) * Common.choose([1, -1]), + y: -forceMagnitude + Common.random() * -forceMagnitude + }); } - }; - - var timeScaleTarget = 1, - counter = 0; - - sceneEvents.push( - Events.on(engine, 'afterUpdate', function(event) { - // tween the timescale for bullet time slow-mo - engine.timing.timeScale += (timeScaleTarget - engine.timing.timeScale) * 0.05; - - counter += 1; - - // every 1.5 sec - if (counter >= 60 * 1.5) { - - // flip the timescale - if (timeScaleTarget < 1) { - timeScaleTarget = 1; - } else { - timeScaleTarget = 0.05; - } - - // create some random forces - explosion(engine); - - // reset counter - counter = 0; - } - }) - ); - - var bodyOptions = { - frictionAir: 0, - friction: 0.0001, - restitution: 0.8 - }; - - // add some small bouncy circles... remember Swordfish? - World.add(world, Composites.stack(20, 100, 15, 3, 20, 40, function(x, y) { - return Bodies.circle(x, y, Common.random(10, 20), bodyOptions); - })); - - // add some larger random bouncy objects - World.add(world, Composites.stack(50, 50, 8, 3, 0, 0, function(x, y) { - switch (Math.round(Common.random(0, 1))) { - - case 0: - if (Common.random() < 0.8) { - return Bodies.rectangle(x, y, Common.random(20, 50), Common.random(20, 50), bodyOptions); - } else { - return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(20, 30), bodyOptions); - } - break; - case 1: - return Bodies.polygon(x, y, Math.round(Common.random(4, 8)), Common.random(20, 50), bodyOptions); - - } - })); + } }; -})(); + var timeScaleTarget = 1, + counter = 0; + + + Events.on(engine, 'afterUpdate', function(event) { + // tween the timescale for bullet time slow-mo + engine.timing.timeScale += (timeScaleTarget - engine.timing.timeScale) * 0.05; + + counter += 1; + + // every 1.5 sec + if (counter >= 60 * 1.5) { + + // flip the timescale + if (timeScaleTarget < 1) { + timeScaleTarget = 1; + } else { + timeScaleTarget = 0.05; + } + + // create some random forces + explosion(engine); + + // reset counter + counter = 0; + } + }); + + var bodyOptions = { + frictionAir: 0, + friction: 0.0001, + restitution: 0.8 + }; + + // add some small bouncy circles... remember Swordfish? + World.add(world, Composites.stack(20, 100, 15, 3, 20, 40, function(x, y) { + return Bodies.circle(x, y, Common.random(10, 20), bodyOptions); + })); + + // add some larger random bouncy objects + World.add(world, Composites.stack(50, 50, 8, 3, 0, 0, function(x, y) { + switch (Math.round(Common.random(0, 1))) { + + case 0: + if (Common.random() < 0.8) { + return Bodies.rectangle(x, y, Common.random(20, 50), Common.random(20, 50), bodyOptions); + } else { + return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(20, 30), bodyOptions); + } + break; + case 1: + return Bodies.polygon(x, y, Math.round(Common.random(4, 8)), Common.random(20, 50), bodyOptions); + + } + })); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } + }); + + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, { + min: { x: 0, y: 0 }, + max: { x: 800, y: 600 } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; \ No newline at end of file diff --git a/examples/views.js b/examples/views.js index 72bb7c8..30afb60 100644 --- a/examples/views.js +++ b/examples/views.js @@ -1,135 +1,186 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.views = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Body = Matter.Body, + Events = Matter.Events, + Composite = Matter.Composite, Composites = Matter.Composites, Common = Matter.Common, - Events = Matter.Events, - Bounds = Matter.Bounds, + Constraint = Matter.Constraint, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Vertices = Matter.Vertices, Vector = Matter.Vector, - Mouse = Matter.Mouse; + Bounds = Matter.Bounds, + Bodies = Matter.Bodies; - Example.views = function(demo) { - var engine = demo.engine, - world = engine.world, - sceneEvents = demo.sceneEvents, - mouseConstraint = demo.mouseConstraint; + // create engine + var engine = Engine.create(), + world = engine.world; - var stack = Composites.stack(20, 20, 15, 4, 0, 0, function(x, y) { - switch (Math.round(Common.random(0, 1))) { + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + hasBounds: true, + showAngleIndicator: true + } + }); - case 0: - if (Common.random() < 0.8) { - return Bodies.rectangle(x, y, Common.random(20, 50), Common.random(20, 50)); - } else { - return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(20, 30)); + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false } - break; - case 1: - var sides = Math.round(Common.random(1, 8)); - sides = (sides === 3) ? 4 : sides; - return Bodies.polygon(x, y, sides, Common.random(20, 50)); } }); - - World.add(world, stack); - // get the centre of the viewport - var viewportCentre = { - x: demo.render.options.width * 0.5, - y: demo.render.options.height * 0.5 - }; + World.add(world, mouseConstraint); - // make the world bounds a little bigger than the render bounds - world.bounds.min.x = -300; - world.bounds.min.y = -300; - world.bounds.max.x = 1100; - world.bounds.max.y = 900; + // keep the mouse in sync with rendering + render.mouse = mouse; - // keep track of current bounds scale (view zoom) - var boundsScaleTarget = 1, - boundsScale = { - x: 1, - y: 1 - }; + // add bodies + var stack = Composites.stack(20, 20, 15, 4, 0, 0, function(x, y) { + switch (Math.round(Common.random(0, 1))) { - // use the engine tick event to control our view - sceneEvents.push( - Events.on(engine, 'beforeTick', function() { - var world = engine.world, - mouse = mouseConstraint.mouse, - render = demo.render, - translate; + case 0: + if (Common.random() < 0.8) { + return Bodies.rectangle(x, y, Common.random(20, 50), Common.random(20, 50)); + } else { + return Bodies.rectangle(x, y, Common.random(80, 120), Common.random(20, 30)); + } + break; + case 1: + var sides = Math.round(Common.random(1, 8)); + sides = (sides === 3) ? 4 : sides; + return Bodies.polygon(x, y, sides, Common.random(20, 50)); + } + }); - // mouse wheel controls zoom - var scaleFactor = mouse.wheelDelta * -0.1; - if (scaleFactor !== 0) { - if ((scaleFactor < 0 && boundsScale.x >= 0.6) || (scaleFactor > 0 && boundsScale.x <= 1.4)) { - boundsScaleTarget += scaleFactor; - } - } - - // if scale has changed - if (Math.abs(boundsScale.x - boundsScaleTarget) > 0.01) { - // smoothly tween scale factor - scaleFactor = (boundsScaleTarget - boundsScale.x) * 0.2; - boundsScale.x += scaleFactor; - boundsScale.y += scaleFactor; - - // scale the render bounds - render.bounds.max.x = render.bounds.min.x + render.options.width * boundsScale.x; - render.bounds.max.y = render.bounds.min.y + render.options.height * boundsScale.y; - - // translate so zoom is from centre of view - translate = { - x: render.options.width * scaleFactor * -0.5, - y: render.options.height * scaleFactor * -0.5 - }; - - Bounds.translate(render.bounds, translate); - - // update mouse - Mouse.setScale(mouse, boundsScale); - Mouse.setOffset(mouse, render.bounds.min); - } - - // get vector from mouse relative to centre of viewport - var deltaCentre = Vector.sub(mouse.absolute, viewportCentre), - centreDist = Vector.magnitude(deltaCentre); - - // translate the view if mouse has moved over 50px from the centre of viewport - if (centreDist > 50) { - // create a vector to translate the view, allowing the user to control view speed - var direction = Vector.normalise(deltaCentre), - speed = Math.min(10, Math.pow(centreDist - 50, 2) * 0.0002); - - translate = Vector.mult(direction, speed); - - // prevent the view moving outside the world bounds - if (render.bounds.min.x + translate.x < world.bounds.min.x) - translate.x = world.bounds.min.x - render.bounds.min.x; - - if (render.bounds.max.x + translate.x > world.bounds.max.x) - translate.x = world.bounds.max.x - render.bounds.max.x; - - if (render.bounds.min.y + translate.y < world.bounds.min.y) - translate.y = world.bounds.min.y - render.bounds.min.y; - - if (render.bounds.max.y + translate.y > world.bounds.max.y) - translate.y = world.bounds.max.y - render.bounds.max.y; - - // move the view - Bounds.translate(render.bounds, translate); - - // we must update the mouse too - Mouse.setOffset(mouse, render.bounds.min); - } - }) - ); - - // must enable renderOptions.hasBounds for views to work - var renderOptions = demo.render.options; - renderOptions.hasBounds = true; + World.add(world, [ + stack, + Bodies.rectangle(400, 600, 800, 50, { isStatic: true }), + Bodies.rectangle(800, 300, 50, 600, { isStatic: true }), + Bodies.rectangle(0, 300, 50, 600, { isStatic: true }) + ]); + + // get the centre of the viewport + var viewportCentre = { + x: render.options.width * 0.5, + y: render.options.height * 0.5 }; -})(); \ No newline at end of file + // make the world bounds a little bigger than the render bounds + world.bounds.min.x = -300; + world.bounds.min.y = -300; + world.bounds.max.x = 1100; + world.bounds.max.y = 900; + + // keep track of current bounds scale (view zoom) + var boundsScaleTarget = 1, + boundsScale = { + x: 1, + y: 1 + }; + + // use the engine tick event to control our view + Events.on(engine, 'beforeTick', function() { + var world = engine.world, + mouse = mouseConstraint.mouse, + translate; + + // mouse wheel controls zoom + var scaleFactor = mouse.wheelDelta * -0.1; + if (scaleFactor !== 0) { + if ((scaleFactor < 0 && boundsScale.x >= 0.6) || (scaleFactor > 0 && boundsScale.x <= 1.4)) { + boundsScaleTarget += scaleFactor; + } + } + + // if scale has changed + if (Math.abs(boundsScale.x - boundsScaleTarget) > 0.01) { + // smoothly tween scale factor + scaleFactor = (boundsScaleTarget - boundsScale.x) * 0.2; + boundsScale.x += scaleFactor; + boundsScale.y += scaleFactor; + + // scale the render bounds + render.bounds.max.x = render.bounds.min.x + render.options.width * boundsScale.x; + render.bounds.max.y = render.bounds.min.y + render.options.height * boundsScale.y; + + // translate so zoom is from centre of view + translate = { + x: render.options.width * scaleFactor * -0.5, + y: render.options.height * scaleFactor * -0.5 + }; + + Bounds.translate(render.bounds, translate); + + // update mouse + Mouse.setScale(mouse, boundsScale); + Mouse.setOffset(mouse, render.bounds.min); + } + + // get vector from mouse relative to centre of viewport + var deltaCentre = Vector.sub(mouse.absolute, viewportCentre), + centreDist = Vector.magnitude(deltaCentre); + + // translate the view if mouse has moved over 50px from the centre of viewport + if (centreDist > 50) { + // create a vector to translate the view, allowing the user to control view speed + var direction = Vector.normalise(deltaCentre), + speed = Math.min(10, Math.pow(centreDist - 50, 2) * 0.0002); + + translate = Vector.mult(direction, speed); + + // prevent the view moving outside the world bounds + if (render.bounds.min.x + translate.x < world.bounds.min.x) + translate.x = world.bounds.min.x - render.bounds.min.x; + + if (render.bounds.max.x + translate.x > world.bounds.max.x) + translate.x = world.bounds.max.x - render.bounds.max.x; + + if (render.bounds.min.y + translate.y < world.bounds.min.y) + translate.y = world.bounds.min.y - render.bounds.min.y; + + if (render.bounds.max.y + translate.y > world.bounds.max.y) + translate.y = world.bounds.max.y - render.bounds.max.y; + + // move the view + Bounds.translate(render.bounds, translate); + + // we must update the mouse too + Mouse.setOffset(mouse, render.bounds.min); + } + }); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; \ No newline at end of file diff --git a/examples/wreckingBall.js b/examples/wreckingBall.js index 3221745..160ddf6 100644 --- a/examples/wreckingBall.js +++ b/examples/wreckingBall.js @@ -1,30 +1,89 @@ -(function() { +var Example = Example || {}; - var World = Matter.World, - Bodies = Matter.Bodies, +Example.wreckingBall = function() { + var Engine = Matter.Engine, + Render = Matter.Render, + Runner = Matter.Runner, + Composite = Matter.Composite, Composites = Matter.Composites, - Constraint = Matter.Constraint; + Common = Matter.Common, + MouseConstraint = Matter.MouseConstraint, + Mouse = Matter.Mouse, + World = Matter.World, + Constraint = Matter.Constraint, + Bodies = Matter.Bodies; - Example.wreckingBall = function(demo) { - var engine = demo.engine, - world = engine.world; - - var rows = 10, - yy = 600 - 21 - 40 * rows; - - var stack = Composites.stack(400, yy, 5, rows, 0, 0, function(x, y) { - return Bodies.rectangle(x, y, 40, 40); + // create engine + var engine = Engine.create(), + world = engine.world; + + // create renderer + var render = Render.create({ + element: document.body, + engine: engine, + options: { + width: Math.min(document.body.clientWidth, 1024), + height: Math.min(document.body.clientHeight, 1024), + showAngleIndicator: true + } + }); + + Render.run(render); + + // create runner + var runner = Runner.create(); + Runner.run(runner, engine); + + // add bodies + var rows = 10, + yy = 600 - 21 - 40 * rows; + + var stack = Composites.stack(400, yy, 5, rows, 0, 0, function(x, y) { + return Bodies.rectangle(x, y, 40, 40); + }); + + World.add(world, [ + stack, + Bodies.rectangle(400, 600, 800, 50.5, { isStatic: true }) + ]); + + var ball = Bodies.circle(100, 400, 50, { density: 0.04, frictionAir: 0.005}); + + World.add(world, ball); + World.add(world, Constraint.create({ + pointA: { x: 300, y: 100 }, + bodyB: ball + })); + + // add mouse control + var mouse = Mouse.create(render.canvas), + mouseConstraint = MouseConstraint.create(engine, { + mouse: mouse, + constraint: { + stiffness: 0.2, + render: { + visible: false + } + } }); - - World.add(world, stack); - - var ball = Bodies.circle(100, 400, 50, { density: 0.04, frictionAir: 0.005}); - - World.add(world, ball); - World.add(world, Constraint.create({ - pointA: { x: 300, y: 100 }, - bodyB: ball - })); - }; -})(); \ No newline at end of file + World.add(world, mouseConstraint); + + // keep the mouse in sync with rendering + render.mouse = mouse; + + // fit the render viewport to the scene + Render.lookAt(render, Composite.allBodies(world)); + + // context for MatterTools.Demo + return { + engine: engine, + runner: runner, + render: render, + canvas: render.canvas, + stop: function() { + Matter.Render.stop(render); + Matter.Runner.stop(runner); + } + }; +}; \ No newline at end of file diff --git a/src/render/Render.js b/src/render/Render.js index 7097dba..ae1f756 100644 --- a/src/render/Render.js +++ b/src/render/Render.js @@ -16,6 +16,7 @@ var Bounds = require('../geometry/Bounds'); var Events = require('../core/Events'); var Grid = require('../collision/Grid'); var Vector = require('../geometry/Vector'); +var Mouse = require('../core/Mouse'); (function() { @@ -52,7 +53,7 @@ var Vector = require('../geometry/Vector'); height: 600, pixelRatio: 1, background: '#fafafa', - wireframeBackground: '#222', + wireframeBackground: '#0f0f13', hasBounds: !!options.bounds, enabled: true, wireframes: true, @@ -173,8 +174,7 @@ var Vector = require('../geometry/Vector'); Render.lookAt = function(render, objects, padding, center) { center = typeof center !== 'undefined' ? center : true; objects = Common.isArray(objects) ? objects : [objects]; - - var padding = padding || { + padding = padding || { x: 0, y: 0 }; @@ -344,6 +344,16 @@ var Vector = require('../geometry/Vector'); // transform the view Render.startViewTransform(render); + + // update mouse + if (render.mouse) { + Mouse.setScale(render.mouse, { + x: (render.bounds.max.x - render.bounds.min.x) / render.canvas.width, + y: (render.bounds.max.y - render.bounds.min.y) / render.canvas.height + }); + + Mouse.setOffset(render.mouse, render.bounds.min); + } } else { constraints = allConstraints; bodies = allBodies;