grid-apps-cmms/src/main/mesh.js

321 lines
9.1 KiB
JavaScript
Raw Normal View History

2021-12-27 10:14:21 -05:00
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
"use strict";
2021-12-26 13:59:02 -05:00
2021-12-26 20:01:56 -05:00
(function() {
let broker = gapp.broker;
2022-01-02 16:30:05 -05:00
let call = broker.send;
2021-12-26 20:01:56 -05:00
2021-12-26 13:59:02 -05:00
function init() {
2021-12-26 20:01:56 -05:00
let moto = self.moto,
api = mesh.api,
sky = false,
2021-12-26 13:59:02 -05:00
dark = false,
ortho = false,
zoomrev = true,
2021-12-26 13:59:02 -05:00
zoomspd = 1,
2021-12-26 20:01:56 -05:00
space = moto.Space,
platform = space.platform;
2021-12-26 13:59:02 -05:00
// setup default workspace
2022-01-01 22:39:49 -05:00
space.useDefaultKeys(false);
2021-12-28 13:02:01 -05:00
space.sky.set({
grid: sky,
color: dark ? 0 : 0xffffff
});
2021-12-26 20:01:56 -05:00
space.init($('container'), delta => { }, ortho);
2021-12-28 13:02:01 -05:00
platform.set({
volume: false,
round: false,
zOffset: 0.2,
opacity: 0.3,
color: 0xcccccc,
zoom: { reverse: true, speed: 1 },
size: { width: 300, depth: 300, height: 2.5, maxz: 2.5 },
grid: { major: 25, minor: 5, majorColor: 0x999999, minorColor: 0xcccccc },
2021-12-28 13:02:01 -05:00
});
2021-12-26 20:01:56 -05:00
space.view.setZoom(zoomrev, zoomspd);
2021-12-26 19:43:48 -05:00
// start worker
moto.client.start(`/code/mesh_work?${gapp.version}`);
2022-01-02 16:30:05 -05:00
// trigger space event binding
call.space_init({ space, platform });
// trigger ui building
call.ui_build();
// hide loading curtain
$d('curtain','none');
}
function ui_build() {
// set app version
$h('app-name', "Mesh:Tool");
$h('app-vers', gapp.version);
2022-01-02 16:30:05 -05:00
let bound = h.bind($('app-body'), [
h.div({id: 'grouplist'})
]);
let { grouplist } = bound;
let api = mesh.api;
let maker = {
update() {
clearTimeout(maker.timer);
maker.timer = setTimeout(maker.do, 10);
},
do() {
let groups = api.group.list()
// map groups to divs
.map(g => h.div([
h.button({
_: g.id,
class: [
"group",
api.selection.contains(g) ? 'selected' : undefined
],
onclick() { api.selection.toggle(g); }
}),
h.div({ class: "vsep" }),
h.div({ class: "models"},
// map models to buttons
g.models.map(m => h.button({
_: m.id,
class: api.selection.contains(m) ? [ 'selected' ] : [],
onclick() { api.selection.toggle(m); }
}))
)
]));
h.bind(grouplist, groups);
}
};
function update(object, topic) {
console.log({update: object, topic});
}
// listen for api calls
broker.listeners({
model_add: maker.update,
group_add: maker.update,
model_remove: maker.update,
group_remove: maker.update,
selection_update: maker.update,
})
}
// add space event bindings
2022-01-02 16:30:05 -05:00
function space_init(data) {
let { space, platform } = data;
let platcolor = 0x00ff00;
2021-12-31 14:12:42 -05:00
let api = mesh.api;
let { selection } = api;
// add file drop handler
space.event.addHandlers(self, [
'drop', (evt) => {
estop(evt);
platform.setColor(platcolor);
load.File.load([...evt.dataTransfer.files])
.then(data => {
2022-01-02 16:30:05 -05:00
call.space_load(data);
})
.catch(error => {
dbug.error(error);
})
.finally(() => {
// hide spinner
});
},
'dragover', evt => {
estop(evt);
evt.dataTransfer.dropEffect = 'copy';
let color = platform.setColor(0x00ff00);
if (color !== 0x00ff00) platcolor = color;
},
'dragleave', evt => {
platform.setColor(platcolor);
2021-12-31 14:12:42 -05:00
},
'keypress', evt => {
let { shiftKey, metaKey, ctrlKey, code } = evt;
switch (code) {
case 'KeyC':
selection.centerXY().focus();
break;
2021-12-31 16:59:38 -05:00
case 'KeyV':
selection.focus();
2021-12-31 16:59:38 -05:00
break;
case 'KeyW':
selection.wireframe({toggle:true});
break;
case 'KeyB':
selection.boundsBox({toggle:true});
break;
case 'KeyH':
space.view.home();
break;
case 'KeyF':
space.view.front();
break;
case 'KeyT':
space.view.top();
break;
case 'KeyZ':
space.view.reset();
break;
2021-12-31 16:59:38 -05:00
}
2021-12-31 14:12:42 -05:00
},
'keydown', evt => {
2021-12-31 16:59:38 -05:00
let rv = Math.PI / 16;
2022-01-01 17:28:47 -05:00
let { shiftKey, metaKey, ctrlKey, code } = evt;
switch (code) {
2022-01-01 15:28:59 -05:00
case 'KeyA':
2022-01-01 17:28:47 -05:00
if (metaKey || ctrlKey) {
selection.set(api.group.list());
2022-01-01 15:28:59 -05:00
estop(evt);
}
break;
2022-01-01 17:28:47 -05:00
case 'KeyD':
if (shiftKey) {
for (let m of selection.models()) {
m.debug();
}
} else {
2022-01-02 16:30:05 -05:00
call.space_debug();
}
2022-01-01 17:28:47 -05:00
break;
2022-01-01 15:28:59 -05:00
case 'Escape':
selection.clear();
2022-01-01 15:28:59 -05:00
estop(evt);
break;
case 'Backspace':
case 'Delete':
for (let s of selection.list()) {
s.showBounds(false);
s.remove();
}
2022-01-01 15:28:59 -05:00
estop(evt);
break;
2021-12-31 14:12:42 -05:00
case 'ArrowUp':
selection.rotate(-rv,0,0).floor();
2021-12-31 14:12:42 -05:00
break;
case 'ArrowDown':
selection.rotate(rv,0,0).floor();
2021-12-31 14:12:42 -05:00
break;
case 'ArrowLeft':
2022-01-01 17:28:47 -05:00
if (shiftKey) {
selection.rotate(0,-rv,0).floor();
2022-01-01 17:28:47 -05:00
} else {
selection.rotate(0,0,rv).floor();
2022-01-01 17:28:47 -05:00
}
2021-12-31 14:12:42 -05:00
break;
case 'ArrowRight':
2022-01-01 17:28:47 -05:00
if (shiftKey) {
selection.rotate(0,rv,0).floor();
2022-01-01 17:28:47 -05:00
} else {
selection.rotate(0,0,-rv).floor();
2022-01-01 17:28:47 -05:00
}
2021-12-31 14:12:42 -05:00
break;
}
}
]);
// mouse hover/click handlers
space.mouse.downSelect((int, event) => {
return api.objects();
});
space.mouse.upSelect((int, event) => {
if (event && event.target.nodeName === "CANVAS") {
let model = int && int.object.model ? int.object.model : undefined;
if (model) {
let group = model.group;
// lay flat with meta or ctrl clicking a selected face
if ((event.ctrlKey || event.metaKey)) {
let q = new THREE.Quaternion();
// find intersecting point, look "up" on Z and rotate to face that
q.setFromUnitVectors(int.face.normal, new THREE.Vector3(0,0,-1));
group.qrotation(q);
2022-01-01 10:44:06 -05:00
group.floor();
} else {
selection.toggle(model.group);
}
}
} else {
return api.objects();
}
});
space.mouse.onDrag((delta, offset, up = false) => {
if (delta) {
selection.move(delta.x, delta.y, 0);
} else {
return api.objects().length > 0;
}
});
2022-01-02 16:30:05 -05:00
}
// add object loader
2022-01-02 16:30:05 -05:00
function space_load(data) {
mesh.api.group.new(data.flat().map(el => new mesh.model(el)))
.centerModels()
.centerXY()
2021-12-31 16:59:38 -05:00
.floor()
.focus();
2022-01-02 16:30:05 -05:00
}
2021-12-26 13:59:02 -05:00
2022-01-01 17:28:47 -05:00
// on debug key press
2022-01-02 16:30:05 -05:00
function space_debug() {
2022-01-01 17:28:47 -05:00
for (let g of mesh.api.group.list()) {
let { center, size } = g.bounds();
console.group(g.id);
console.log({
2022-01-01 17:28:47 -05:00
center,
size,
pos: g.group.position
});
for (let m of g.models) {
console.log(m.id, {
2022-01-01 17:28:47 -05:00
box: m.mesh.getBoundingBox(),
pos: m.mesh.position
});
}
console.groupEnd();
}
moto.client.fn.debug();
2022-01-02 16:30:05 -05:00
}
// bind functions to topics
broker.listeners({
ui_build,
space_init,
space_load,
space_debug,
2022-01-01 17:28:47 -05:00
});
2021-12-26 20:01:56 -05:00
// remove version cache bust from url
window.history.replaceState({},'','/mesh/');
2021-12-26 20:01:56 -05:00
// setup init() trigger when dom + scripts complete
document.onreadystatechange = function() {
if (document.readyState === 'complete') {
2021-12-26 13:59:02 -05:00
init();
}
}
2021-12-26 20:01:56 -05:00
// finalize modules
gapp.finalize("main.mesh", [
"moto.license", // dep: moto.license
2021-12-29 12:55:45 -05:00
"moto.webui", // dep: moto.webui
2021-12-29 10:37:17 -05:00
"moto.client", // dep: moto.client
2021-12-29 07:54:16 -05:00
"moto.broker", // dep: moto.broker
"moto.space", // dep: moto.space
"mesh.api", // dep: mesh.api
"mesh.model", // dep: mesh.model
"load.file", // dep: load.file
]);
2021-12-26 20:01:56 -05:00
})();