mirror of
https://github.com/liabru/matter-js.git
synced 2024-11-27 09:50:52 -05:00
further work on Matter.Inspector and Matter.Gui
This commit is contained in:
parent
3967608d7c
commit
5a72bf1cae
4 changed files with 590 additions and 387 deletions
|
@ -1,3 +1,22 @@
|
|||
/*
|
||||
* 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
|
||||
*/
|
||||
|
@ -6,44 +25,46 @@ body .dg.main {
|
|||
box-shadow: 0 0 8px rgba(0,0,0,0.7);
|
||||
}
|
||||
|
||||
body.gui-auto-hide .dg.ac {
|
||||
right: -233px;
|
||||
}
|
||||
@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 .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);
|
||||
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;
|
||||
}
|
||||
-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);
|
||||
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);
|
||||
-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;
|
||||
transition-delay: 0;
|
||||
-webkit-transition-delay: 0;
|
||||
}
|
||||
}
|
||||
|
||||
body .dg.main.taller-than-window .close-button {
|
||||
|
@ -82,10 +103,6 @@ body .dg li:not(.folder) {
|
|||
border-bottom: 0px;
|
||||
padding: 0 0 0 12px;
|
||||
}
|
||||
|
||||
body .dg .cr.function {
|
||||
border-top: 1px solid #444;
|
||||
}
|
||||
|
||||
body .dg li.save-row .button {
|
||||
text-shadow: none !important;
|
||||
|
@ -101,8 +118,22 @@ 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: #555;
|
||||
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 {
|
||||
|
@ -117,6 +148,13 @@ 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 {
|
||||
|
@ -184,46 +222,59 @@ body .dg.a {
|
|||
box-shadow: 0 0 8px rgba(0,0,0,0.7);
|
||||
}
|
||||
|
||||
.ins-auto-hide .ins-container {
|
||||
left: -245px;
|
||||
border-right: 1px dotted #888;
|
||||
@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-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 {
|
||||
|
@ -314,6 +365,7 @@ body .dg.a {
|
|||
border-radius: 2px;
|
||||
border-bottom: 2px solid #2e2e2e;
|
||||
box-sizing: border-box;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.ins-button:hover {
|
||||
|
@ -321,6 +373,12 @@ body .dg.a {
|
|||
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;
|
||||
|
@ -355,6 +413,7 @@ body .dg.a {
|
|||
transition: color 100ms linear;
|
||||
}
|
||||
|
||||
.jstree-default .jstree-container-ul> .jstree-node > .jstree-anchor:before,
|
||||
.jstree-default .jstree-open > .jstree-children > .jstree-node > .jstree-anchor:before {
|
||||
content: '';
|
||||
display: block;
|
||||
|
|
|
@ -400,8 +400,7 @@ Resurrect.prototype.handleAtom = function(atom) {
|
|||
return this.builder('RegExp', args);
|
||||
} else if (atom === undefined) {
|
||||
return this.ref(undefined);
|
||||
} else if (Resurrect.isNumber(atom) &&
|
||||
(Number.isNaN(atom) || !Number.isFinite(atom))) {
|
||||
} else if (Resurrect.isNumber(atom) && (isNaN(atom) || !isFinite(atom))) {
|
||||
return this.builder('Number', [atom.toString()]);
|
||||
} else {
|
||||
return atom;
|
||||
|
|
|
@ -84,6 +84,66 @@ var Gui = {};
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Saves world state to local storage
|
||||
* @method saveState
|
||||
* @param {object} serializer
|
||||
* @param {engine} engine
|
||||
* @param {string} key
|
||||
*/
|
||||
Gui.saveState = function(serializer, engine, key) {
|
||||
if (localStorage && serializer)
|
||||
localStorage.setItem(key, Gui.serialise(serializer, engine.world));
|
||||
};
|
||||
|
||||
/**
|
||||
* Loads world state from local storage
|
||||
* @method loadState
|
||||
* @param {object} serializer
|
||||
* @param {engine} engine
|
||||
* @param {string} key
|
||||
*/
|
||||
Gui.loadState = function(serializer, engine, key) {
|
||||
var loadedWorld;
|
||||
|
||||
if (localStorage && serializer)
|
||||
loadedWorld = serializer.parse(localStorage.getItem(key));
|
||||
|
||||
if (loadedWorld)
|
||||
Engine.merge(engine, { world: loadedWorld });
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialises the object using the given serializer and a Matter-specific replacer
|
||||
* @method serialise
|
||||
* @param {object} serializer
|
||||
* @param {object} object
|
||||
* @param {number} indent
|
||||
* @return {string} The serialised object
|
||||
*/
|
||||
Gui.serialise = function(serializer, object, indent) {
|
||||
indent = indent || 0;
|
||||
return serializer.stringify(object, function(key, value) {
|
||||
// skip non-required values
|
||||
if (key === 'path')
|
||||
return undefined;
|
||||
|
||||
// limit precision of floats
|
||||
if (!/^#/.exec(key) && typeof value === 'number') {
|
||||
var fixed = parseFloat(value.toFixed(3));
|
||||
|
||||
// do not limit if limiting will cause value to zero
|
||||
// TODO: this should ideally dynamically find the SF precision required
|
||||
if (fixed === 0 && value !== 0)
|
||||
return value;
|
||||
|
||||
return fixed;
|
||||
}
|
||||
|
||||
return value;
|
||||
}, indent);
|
||||
};
|
||||
|
||||
var _initDatGui = function(gui) {
|
||||
var engine = gui.engine,
|
||||
datGui = gui.datGui;
|
||||
|
@ -91,8 +151,12 @@ var Gui = {};
|
|||
var funcs = {
|
||||
addBody: function() { _addBody(gui); },
|
||||
clear: function() { _clear(gui); },
|
||||
save: function() { _save(gui); },
|
||||
load: function() { _load(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);
|
||||
}
|
||||
};
|
||||
|
||||
var metrics = datGui.addFolder('Metrics');
|
||||
|
@ -125,6 +189,7 @@ var Gui = {};
|
|||
controls.open();
|
||||
|
||||
var worldGui = datGui.addFolder('World');
|
||||
worldGui.add(funcs, 'inspect');
|
||||
worldGui.add(funcs, 'load');
|
||||
worldGui.add(funcs, 'save');
|
||||
worldGui.add(funcs, 'clear');
|
||||
|
@ -226,31 +291,6 @@ var Gui = {};
|
|||
Events.trigger(gui, 'clear');
|
||||
};
|
||||
|
||||
var _save = function(gui) {
|
||||
var engine = gui.engine;
|
||||
|
||||
if (localStorage && gui.serializer) {
|
||||
localStorage.setItem('world', gui.serializer.stringify(engine.world));
|
||||
}
|
||||
|
||||
Events.trigger(gui, 'save');
|
||||
};
|
||||
|
||||
var _load = function(gui) {
|
||||
var engine = gui.engine,
|
||||
loadedWorld;
|
||||
|
||||
if (localStorage && gui.serializer) {
|
||||
loadedWorld = gui.serializer.parse(localStorage.getItem('world'));
|
||||
}
|
||||
|
||||
if (loadedWorld) {
|
||||
Engine.merge(engine, { world: loadedWorld });
|
||||
}
|
||||
|
||||
Events.trigger(gui, 'load');
|
||||
};
|
||||
|
||||
/*
|
||||
*
|
||||
* Events Documentation
|
||||
|
|
|
@ -14,54 +14,56 @@ var Inspector = {};
|
|||
$body;
|
||||
|
||||
/**
|
||||
* Creates a new inspector tool and inserts it into the page. Requires jQuery and jsTree.
|
||||
* Creates a new inspector tool and inserts it into the page. Requires keymaster, jQuery, jsTree libraries.
|
||||
* @method create
|
||||
* @param {engine} engine
|
||||
* @param {object} options
|
||||
* @return {inspector} A container for a configured dat.inspector
|
||||
* @return {inspector} An inspector
|
||||
*/
|
||||
Inspector.create = function(engine, options) {
|
||||
if (!jQuery || !$.fn.jstree) {
|
||||
console.log('Could not create inspector. Check jQuery and jsTree libraries are loaded first.');
|
||||
if (!jQuery || !$.fn.jstree || !window.key) {
|
||||
console.log('Could not create inspector. Check keymaster, jQuery, jsTree libraries are loaded first.');
|
||||
return;
|
||||
}
|
||||
|
||||
var inspector = {
|
||||
controls: {
|
||||
container: null,
|
||||
worldTree: null
|
||||
},
|
||||
engine: engine,
|
||||
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,
|
||||
controls: {
|
||||
container: null,
|
||||
worldTree: null
|
||||
},
|
||||
root: Composite.create({
|
||||
label: 'Root'
|
||||
})
|
||||
};
|
||||
|
||||
inspector = Common.extend(inspector, options);
|
||||
|
||||
if (Resurrect) {
|
||||
inspector.serializer = new Resurrect({ prefix: '$', cleanup: true });
|
||||
inspector.serializer.parse = inspector.serializer.resurrect;
|
||||
} else {
|
||||
inspector.serializer = JSON;
|
||||
}
|
||||
|
||||
$body = $('body');
|
||||
_key = window.key || {};
|
||||
Inspector.instance = inspector;
|
||||
|
||||
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);
|
||||
|
@ -81,10 +83,11 @@ var Inspector = {};
|
|||
$importButton = $('<button class="ins-import-button ins-button">Import</button>'),
|
||||
$exportButton = $('<button class="ins-export-button ins-button">Export</button>'),
|
||||
$pauseButton = $('<button class="ins-pause-button ins-button">Pause</button>'),
|
||||
$helpButton = $('<button class="ins-help-button ins-button">Help</button>');
|
||||
$helpButton = $('<button class="ins-help-button ins-button">Help</button>'),
|
||||
$addCompositeButton = $('<button class="ins-add-button ins-button">+</button>');
|
||||
|
||||
$buttonGroup.append($pauseButton, $importButton, $exportButton, $helpButton);
|
||||
$inspectorContainer.prepend($buttonGroup, $searchBox);
|
||||
$inspectorContainer.prepend($buttonGroup, $searchBox, $addCompositeButton);
|
||||
$body.prepend($inspectorContainer);
|
||||
|
||||
controls.pauseButton = $pauseButton;
|
||||
|
@ -93,6 +96,7 @@ var Inspector = {};
|
|||
controls.helpButton = $helpButton;
|
||||
controls.searchBox = $searchBox;
|
||||
controls.container = $inspectorContainer;
|
||||
controls.addCompositeButton = $addCompositeButton;
|
||||
|
||||
controls.pauseButton.click(function() {
|
||||
_setPaused(inspector, !inspector.isPaused);
|
||||
|
@ -110,8 +114,11 @@ var Inspector = {};
|
|||
_showHelp(inspector);
|
||||
});
|
||||
|
||||
var searchTimeout;
|
||||
controls.addCompositeButton.click(function() {
|
||||
_addNewComposite(inspector);
|
||||
});
|
||||
|
||||
var searchTimeout;
|
||||
controls.searchBox.keyup(function () {
|
||||
clearTimeout(searchTimeout);
|
||||
searchTimeout = setTimeout(function () {
|
||||
|
@ -123,26 +130,29 @@ var Inspector = {};
|
|||
};
|
||||
|
||||
var _showHelp = function(inspector) {
|
||||
var help = "Matter Tools \n\n";
|
||||
var help = "Matter Tools\n\n";
|
||||
|
||||
help += "Drag nodes in the tree to move them between composites. \n\n";
|
||||
help += "Use browser's developer console to inspect selected objects. \n\n";
|
||||
help += "Note: selections only render if renderer supports it. \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 to select objects. \n";
|
||||
help += "[del] or [backspace] delete selected objects. \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";
|
||||
help += "[del] or [backspace] delete selected objects.\n\n";
|
||||
|
||||
help += "[shift + s] scale-xy selected objects with mouse. \n";
|
||||
help += "[shift + s + d] scale-x selected objects with mouse. \n";
|
||||
help += "[shift + s + f] scale-y selected objects with mouse. \n";
|
||||
help += "[shift + r] rotate selected objects with mouse. \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\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.";
|
||||
|
||||
|
@ -174,6 +184,12 @@ var Inspector = {};
|
|||
$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++) {
|
||||
|
@ -342,21 +358,108 @@ var Inspector = {};
|
|||
});
|
||||
};
|
||||
|
||||
var _addBodyClass = function(inspector, classNames) {
|
||||
// only apply changes to prevent DOM lag
|
||||
if (inspector.bodyClass.indexOf(' ' + classNames) === -1) {
|
||||
$body.addClass(classNames);
|
||||
inspector.bodyClass = ' ' + $body.attr('class');
|
||||
}
|
||||
};
|
||||
|
||||
var _removeBodyClass = function(inspector, classNames) {
|
||||
// only apply changes to prevent DOM lag
|
||||
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.engine.input.mouse.position, inspector.offset);
|
||||
};
|
||||
|
||||
var _initEngineEvents = function(inspector) {
|
||||
var engine = inspector.engine,
|
||||
mouse = engine.input.mouse,
|
||||
mousePosition = _getMousePosition(inspector),
|
||||
controls = inspector.controls;
|
||||
|
||||
Events.on(engine, 'tick', function() {
|
||||
// update mouse position reference
|
||||
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;
|
||||
|
||||
// update interface when world changes
|
||||
if (engine.world.isModified) {
|
||||
var data = _generateCompositeTreeNode(inspector.root, null, true);
|
||||
_updateTree(controls.worldTree.data('jstree'), data);
|
||||
_setSelectedObjects(inspector, []);
|
||||
}
|
||||
|
||||
// update region selection
|
||||
if (inspector.selectStart !== null) {
|
||||
inspector.selectEnd.x = mousePosition.x;
|
||||
inspector.selectEnd.y = mousePosition.y;
|
||||
Bounds.update(inspector.selectBounds, [inspector.selectStart, inspector.selectEnd]);
|
||||
}
|
||||
|
||||
// rotate mode
|
||||
if (_key.shift && _key.isPressed('r')) {
|
||||
var rotateSpeed = 0.03,
|
||||
angle = Math.max(-2, Math.min(2, delta)) * rotateSpeed;
|
||||
|
||||
_addBodyClass(inspector, 'ins-cursor-rotate');
|
||||
_rotateSelectedObjects(inspector, angle);
|
||||
} else {
|
||||
_removeBodyClass(inspector, 'ins-cursor-rotate');
|
||||
}
|
||||
|
||||
// scale mode
|
||||
if (_key.shift && _key.isPressed('s')) {
|
||||
var scaleSpeed = 0.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');
|
||||
}
|
||||
|
||||
// translate mode
|
||||
if (mouse.button === 2 && !mouse.sourceEvents.mousedown && !mouse.sourceEvents.mouseup) {
|
||||
_addBodyClass(inspector, 'ins-cursor-move');
|
||||
_moveSelectedObjects(inspector, mousePosition.x, mousePosition.y);
|
||||
} else {
|
||||
_removeBodyClass(inspector, 'ins-cursor-move');
|
||||
}
|
||||
|
||||
inspector.mousePrevPosition = Common.clone(mousePosition);
|
||||
});
|
||||
|
||||
Events.on(engine, 'mouseup', function(event) {
|
||||
$body.removeClass('ins-cursor-move');
|
||||
|
||||
// select objects in region if making a region selection
|
||||
if (inspector.selectStart !== null) {
|
||||
var selected = Query.region(Composite.allBodies(engine.world), inspector.selectBounds);
|
||||
|
@ -370,23 +473,20 @@ var Inspector = {};
|
|||
});
|
||||
|
||||
Events.on(engine, 'mousedown', function(event) {
|
||||
var mouse = event.mouse,
|
||||
engine = event.source,
|
||||
var engine = event.source,
|
||||
bodies = Composite.allBodies(engine.world),
|
||||
constraints = Composite.allConstraints(engine.world),
|
||||
isUnionSelect = _key.shift || _key.control,
|
||||
worldTree = inspector.controls.worldTree.data('jstree'),
|
||||
i;
|
||||
|
||||
$body.removeClass('ins-cursor-move ins-cursor-rotate ins-cursor-scale');
|
||||
|
||||
if (mouse.button === 2) {
|
||||
var hasSelected = false;
|
||||
|
||||
for (i = 0; i < bodies.length; i++) {
|
||||
var body = bodies[i];
|
||||
|
||||
if (Bounds.contains(body.bounds, mouse.position) && Vertices.contains(body.vertices, mouse.position)) {
|
||||
if (Bounds.contains(body.bounds, mousePosition) && Vertices.contains(body.vertices, mousePosition)) {
|
||||
|
||||
if (isUnionSelect) {
|
||||
_addSelectedObject(inspector, body);
|
||||
|
@ -417,8 +517,8 @@ var Inspector = {};
|
|||
if (!pointAWorld || !pointBWorld)
|
||||
continue;
|
||||
|
||||
var distA = Vector.magnitudeSquared(Vector.sub(mouse.position, pointAWorld)),
|
||||
distB = Vector.magnitudeSquared(Vector.sub(mouse.position, pointBWorld));
|
||||
var distA = Vector.magnitudeSquared(Vector.sub(mousePosition, pointAWorld)),
|
||||
distB = Vector.magnitudeSquared(Vector.sub(mousePosition, pointBWorld));
|
||||
|
||||
if (distA < 100 || distB < 100) {
|
||||
if (isUnionSelect) {
|
||||
|
@ -436,8 +536,8 @@ var Inspector = {};
|
|||
worldTree.deselect_all(true);
|
||||
_setSelectedObjects(inspector, []);
|
||||
|
||||
inspector.selectStart = Common.clone(mouse.position);
|
||||
inspector.selectEnd = Common.clone(mouse.position);
|
||||
inspector.selectStart = Common.clone(mousePosition);
|
||||
inspector.selectEnd = Common.clone(mousePosition);
|
||||
Bounds.update(inspector.selectBounds, [inspector.selectStart, inspector.selectEnd]);
|
||||
|
||||
Events.trigger(inspector, 'selectStart');
|
||||
|
@ -449,155 +549,9 @@ var Inspector = {};
|
|||
}
|
||||
|
||||
if (mouse.button === 2 && inspector.selected.length > 0) {
|
||||
$body.addClass('ins-cursor-move');
|
||||
_addBodyClass(inspector, 'ins-cursor-move');
|
||||
|
||||
for (i = 0; i < inspector.selected.length; i++) {
|
||||
var item = inspector.selected[i],
|
||||
data = item.data;
|
||||
|
||||
if (data.position) {
|
||||
item.mousedownOffset = {
|
||||
x: mouse.position.x - data.position.x,
|
||||
y: mouse.position.y - data.position.y
|
||||
};
|
||||
} else if (data.pointA && !data.bodyA) {
|
||||
item.mousedownOffset = {
|
||||
x: mouse.position.x - data.pointA.x,
|
||||
y: mouse.position.y - data.pointA.y
|
||||
};
|
||||
} else if (data.pointB && !data.bodyB) {
|
||||
item.mousedownOffset = {
|
||||
x: mouse.position.x - data.pointB.x,
|
||||
y: mouse.position.y - data.pointB.y
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var mousePrevPosition = { x: 0, y: 0 };
|
||||
|
||||
Events.on(engine, 'mousemove', function(event) {
|
||||
var mouse = event.mouse,
|
||||
selected = inspector.selected,
|
||||
item,
|
||||
data,
|
||||
i;
|
||||
|
||||
$body.removeClass('ins-cursor-move ins-cursor-rotate ins-cursor-scale');
|
||||
|
||||
if (_key.shift && _key.isPressed('r')) {
|
||||
$body.addClass('ins-cursor-rotate');
|
||||
|
||||
// roate mode
|
||||
for (i = 0; i < selected.length; i++) {
|
||||
item = selected[i];
|
||||
data = item.data;
|
||||
|
||||
switch (data.type) {
|
||||
|
||||
case 'body':
|
||||
|
||||
var angle = Common.sign(mouse.position.x - mousePrevPosition.x) * 0.05;
|
||||
Body.rotate(data, angle);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
mousePrevPosition = Common.clone(mouse.position);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_key.shift && _key.isPressed('s')) {
|
||||
$body.addClass('ins-cursor-scale');
|
||||
|
||||
// scale mode
|
||||
for (i = 0; i < selected.length; i++) {
|
||||
item = selected[i];
|
||||
data = item.data;
|
||||
|
||||
switch (data.type) {
|
||||
|
||||
case 'body':
|
||||
|
||||
var scale = 1 + Common.sign(mouse.position.x - mousePrevPosition.x) * 0.02;
|
||||
|
||||
if (_key.isPressed('d')) {
|
||||
scaleX = scale;
|
||||
scaleY = 1;
|
||||
} else if (_key.isPressed('f')) {
|
||||
scaleX = 1;
|
||||
scaleY = scale;
|
||||
} else {
|
||||
scaleX = scaleY = scale;
|
||||
}
|
||||
|
||||
Body.scale(data, scaleX, scaleY);
|
||||
|
||||
if (data.circleRadius)
|
||||
data.circleRadius *= scale;
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
mousePrevPosition = Common.clone(mouse.position);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mouse.button !== 2 || mouse.sourceEvents.mousedown || mouse.sourceEvents.mouseup)
|
||||
return;
|
||||
|
||||
// update region selection
|
||||
if (inspector.selectStart !== null) {
|
||||
inspector.selectEnd.x = mouse.position.x;
|
||||
inspector.selectEnd.y = mouse.position.y;
|
||||
Bounds.update(inspector.selectBounds, [inspector.selectStart, inspector.selectEnd]);
|
||||
return;
|
||||
}
|
||||
|
||||
$body.addClass('ins-cursor-move');
|
||||
|
||||
// translate mode
|
||||
for (i = 0; i < selected.length; i++) {
|
||||
item = selected[i];
|
||||
data = item.data;
|
||||
|
||||
switch (data.type) {
|
||||
|
||||
case 'body':
|
||||
|
||||
var delta = {
|
||||
x: mouse.position.x - data.position.x - item.mousedownOffset.x,
|
||||
y: mouse.position.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 = mouse.position.x - item.mousedownOffset.x;
|
||||
point.y = mouse.position.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;
|
||||
|
||||
}
|
||||
_updateSelectedMouseDownOffset(inspector);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -612,40 +566,185 @@ var Inspector = {};
|
|||
|
||||
var _deleteSelectedObjects = function(inspector) {
|
||||
var objects = [],
|
||||
worldTree = inspector.controls.worldTree.data('jstree');
|
||||
object,
|
||||
worldTree = inspector.controls.worldTree.data('jstree'),
|
||||
i;
|
||||
|
||||
for (var i = 0; i < inspector.selected.length; i++) {
|
||||
var object = inspector.selected[i].data;
|
||||
// delete objects in world
|
||||
for (i = 0; i < inspector.selected.length; i++) {
|
||||
object = inspector.selected[i].data;
|
||||
if (object !== inspector.engine.world)
|
||||
objects.push(object);
|
||||
}
|
||||
|
||||
if (object === inspector.engine.world)
|
||||
continue;
|
||||
|
||||
objects.push(object);
|
||||
worldTree.delete_node(object.type + '_' + object.id);
|
||||
// also delete non-world composites (selected only in the UI tree)
|
||||
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 _updateSelectedMouseDownOffset = function(inspector) {
|
||||
var selected = inspector.selected,
|
||||
mouse = inspector.engine.input.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.engine.input.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;
|
||||
data,
|
||||
i;
|
||||
|
||||
for (var i = 0; i < inspector.selected.length; i++) {
|
||||
for (i = 0; i < inspector.selected.length; i++) {
|
||||
data = inspector.selected[i].data;
|
||||
worldTree.deselect_node(data.type + '_' + data.id, true);
|
||||
}
|
||||
|
@ -656,17 +755,16 @@ var Inspector = {};
|
|||
for (i = 0; i < objects.length; i++) {
|
||||
data = objects[i];
|
||||
|
||||
if (!data)
|
||||
continue;
|
||||
if (data) {
|
||||
// add the object to the selection
|
||||
_addSelectedObject(inspector, data);
|
||||
|
||||
// add the object to the selection
|
||||
_addSelectedObject(inspector, data);
|
||||
|
||||
// log selected objects to console for property inspection
|
||||
if (i < 5) {
|
||||
console.log(data.label + ' ' + data.id + ': %O', data);
|
||||
} else if (i === 6) {
|
||||
console.warn('Omitted inspecting ' + (objects.length - 5) + ' more objects');
|
||||
// log selected objects to console for property inspection
|
||||
if (i < 5) {
|
||||
console.log(data.label + ' ' + data.id + ': %O', data);
|
||||
} else if (i === 6) {
|
||||
console.warn('Omitted inspecting ' + (objects.length - 5) + ' more objects');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -676,11 +774,7 @@ var Inspector = {};
|
|||
return;
|
||||
|
||||
var worldTree = inspector.controls.worldTree.data('jstree');
|
||||
|
||||
inspector.selected.push({
|
||||
data: object
|
||||
});
|
||||
|
||||
inspector.selected.push({ data: object });
|
||||
worldTree.select_node(object.type + '_' + object.id, true);
|
||||
};
|
||||
|
||||
|
@ -807,78 +901,76 @@ var Inspector = {};
|
|||
return node;
|
||||
};
|
||||
|
||||
var _addNewComposite = function(inspector) {
|
||||
var newComposite = Composite.create();
|
||||
|
||||
Composite.add(inspector.root, newComposite);
|
||||
|
||||
// move new composite to the start so that it appears top of tree
|
||||
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.serializer) {
|
||||
if (inspector.selected.length === 0) {
|
||||
alert('No objects were selected, so export could not be created.');
|
||||
return;
|
||||
}
|
||||
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'
|
||||
});
|
||||
|
||||
// add everything else, must be in top-down order
|
||||
for (var i = 0; i < inspector.selected.length; i++) {
|
||||
var object = inspector.selected[i].data;
|
||||
|
||||
// skip if it's already in the composite tree
|
||||
// this means orphans will be added in the root
|
||||
if (Composite.get(exportComposite, object.id, object.type))
|
||||
continue;
|
||||
|
||||
Composite.add(exportComposite, object);
|
||||
|
||||
// better filename for small exports
|
||||
if (inspector.selected.length === 1)
|
||||
fileName = 'export-' + object.label + '-' + object.id;
|
||||
}
|
||||
|
||||
// santise filename
|
||||
fileName = fileName.toLowerCase().replace(/[^\w\-]/g, '') + '.json';
|
||||
|
||||
var json = inspector.serializer.stringify(exportComposite, function(key, value) {
|
||||
// skip non-required values
|
||||
if (key === 'path')
|
||||
return undefined;
|
||||
|
||||
// limit precision of floats
|
||||
if (!/^#/.exec(key) && typeof value === 'number') {
|
||||
var fixed = parseFloat(value.toFixed(3));
|
||||
|
||||
// do not limit if limiting will cause value to zero
|
||||
// TODO: this should ideally dynamically find the SF precision required
|
||||
if (fixed === 0 && value !== 0)
|
||||
return value;
|
||||
|
||||
return fixed;
|
||||
}
|
||||
|
||||
return value;
|
||||
var fileName = 'export-objects',
|
||||
exportComposite = Composite.create({
|
||||
label: 'Exported Objects'
|
||||
});
|
||||
|
||||
// add everything else, must be in top-down order
|
||||
for (var i = 0; i < inspector.selected.length; i++) {
|
||||
var object = inspector.selected[i].data;
|
||||
|
||||
// skip if it's already in the composite tree
|
||||
// this means orphans will be added in the root
|
||||
if (Composite.get(exportComposite, object.id, object.type))
|
||||
continue;
|
||||
|
||||
Composite.add(exportComposite, object);
|
||||
|
||||
// better filename for small exports
|
||||
if (inspector.selected.length === 1)
|
||||
fileName = 'export-' + object.label + '-' + object.id;
|
||||
}
|
||||
|
||||
// santise filename
|
||||
fileName = fileName.toLowerCase().replace(/[^\w\-]/g, '') + '.json';
|
||||
|
||||
// serialise
|
||||
var json = Gui.serialise(inspector.serializer, exportComposite, inspector.exportIndent);
|
||||
|
||||
// launch export download
|
||||
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();
|
||||
|
||||
Events.trigger(inspector, 'export');
|
||||
} else {
|
||||
window.open('data:application/json;charset=utf-8,' + escape(json));
|
||||
}
|
||||
|
||||
Events.trigger(inspector, 'export');
|
||||
};
|
||||
|
||||
var _importFile = function(inspector) {
|
||||
var engine = inspector.engine;
|
||||
var engine = inspector.engine,
|
||||
element = document.createElement('div'),
|
||||
fileInput;
|
||||
|
||||
var element = document.createElement('div');
|
||||
element.innerHTML = '<input type="file">';
|
||||
var fileInput = element.firstChild;
|
||||
fileInput = element.firstChild;
|
||||
|
||||
fileInput.addEventListener('change', function(e) {
|
||||
var file = fileInput.files[0];
|
||||
|
@ -887,32 +979,27 @@ var Inspector = {};
|
|||
var reader = new FileReader();
|
||||
|
||||
reader.onload = function(e) {
|
||||
var importedComposite;
|
||||
|
||||
if (inspector.serializer)
|
||||
importedComposite = inspector.serializer.parse(reader.result);
|
||||
var importedComposite = inspector.serializer.parse(reader.result);
|
||||
|
||||
if (importedComposite) {
|
||||
Composite.rebase(importedComposite);
|
||||
importedComposite.label = 'Imported Objects';
|
||||
|
||||
Composite.rebase(importedComposite);
|
||||
Composite.add(inspector.root, importedComposite);
|
||||
|
||||
// move imported composite to the start
|
||||
// so that it appears top of tree
|
||||
// move imported composite to the start so that it appears top of tree
|
||||
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 text files only');
|
||||
alert('File not supported, .json or .txt JSON files only');
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -961,4 +1048,22 @@ var Inspector = {};
|
|||
* @param {} event.name The name of the event
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fired after the inspector is paused
|
||||
*
|
||||
* @event pause
|
||||
* @param {} event An event object
|
||||
* @param {} event.source The source object of the event
|
||||
* @param {} event.name The name of the event
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fired after the inspector is played
|
||||
*
|
||||
* @event play
|
||||
* @param {} event An event object
|
||||
* @param {} event.source The source object of the event
|
||||
* @param {} event.name The name of the event
|
||||
*/
|
||||
|
||||
})();
|
Loading…
Reference in a new issue