control/object3dManager/Object3dManagerDialog.tstypescript
import { Dialog, type IDialogParams, type DialogEventsList } from "../../ui/Dialog";
import { IObject3dItem, Object3dCollection } from "./Object3dCollection";
import { Button } from "../../ui/Button";
import { Object3dCollectionView } from "./Object3dCollectionView";
import { type EventsHandler, createEvents } from "../../Events";
import { type ViewEventsList } from "../../ui/View";
import { View } from "../../ui/View";
import { Object3d } from "../../Object3d";
type Object3dManagerDialogEvents = ["select"];
const EVENT_NAMES: Object3dManagerDialogEvents = ["select"];
const ICON_LOAD_BUTTON_SVG = `<svg class="svg-icon" style="vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><path d="M426.666667 170.666667H170.666667c-47.146667 0-84.906667 38.186667-84.906667 85.333333L85.333333 768c0 47.146667 38.186667 85.333333 85.333334 85.333333h682.666666c47.146667 0 85.333333-38.186667 85.333334-85.333333V341.333333c0-47.146667-38.186667-85.333333-85.333334-85.333333H512l-85.333333-85.333333z" /></svg>`;
interface IObject3dManagerDialogParams extends IDialogParams {
model: Object3dCollection;
}
type Object3dManagerDialogEventsExt = EventsHandler<Object3dManagerDialogEvents> &
EventsHandler<DialogEventsList> &
EventsHandler<ViewEventsList>;
export class Object3dManagerDialog extends Dialog<null> {
public override events: Object3dManagerDialogEventsExt;
protected _object3dCollectionView: Object3dCollectionView;
constructor(params: IObject3dManagerDialogParams) {
super({
classList: ["og-object3d-manager"],
title: "Object3D Collection",
visible: false,
resizable: true,
useHide: true,
top: 25,
right: 85,
width: 252,
height: 480,
minHeight: 100,
minWidth: 100
});
//@ts-ignore
this.events = createEvents<Object3dManagerDialogEventsExt>(EVENT_NAMES);
this._object3dCollectionView = new Object3dCollectionView({ model: params.model });
}
public override render(params: any): this {
super.render(params);
let $toolbar = document.createElement("div");
$toolbar.classList.add("og-editor_toolbar");
this.container?.appendChild($toolbar);
let loadBtn = new Button({
classList: ["og-editor_toolbar-button"],
icon: ICON_LOAD_BUTTON_SVG,
title: "Load 3D object"
});
loadBtn.appendTo($toolbar);
loadBtn.events.on("click", this._onLoadClick);
this._object3dCollectionView.appendTo(this.container!);
this._object3dCollectionView.events.on("select", (item: IObject3dItem): void => {
this.events.dispatch(this.events.select, item);
});
return this;
}
protected _onLoadClick = () => {
let fileInp = new View({
initRender: true,
template: `<input type="file" accept=".obj,.mtl" multiple />`
});
if (fileInp.el) {
fileInp.el.addEventListener("change", (e) => {
const target = e.target as HTMLInputElement;
if (target.files) {
const files = Array.from(target.files);
const objFile = files.find((file) => file.name.toLowerCase().endsWith(".obj"));
const mtlFile = files.find((file) => file.name.toLowerCase().endsWith(".mtl"));
if (objFile) {
loadObj(objFile, mtlFile).then(this._addObject);
}
}
});
fileInp.el.click();
}
};
protected _addObject = (item: { name: string; objects: Object3d[] }) => {
this._object3dCollectionView.model.addItem(item);
};
}
async function loadObj(objFile: File, mtlFile?: File): Promise<{ name: string; objects: Object3d[] }> {
return await Object3d.readFileObj(objFile, mtlFile).then((objects) => ({
name: objFile.name,
objects: mtlFile ? objects : [Object3d.merge(objects)]
}));
}