Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
adc825a
Ultra 6.0.0
vim-sroberge Jun 3, 2025
b149cbc
ultra update
vim-sroberge Jul 9, 2025
bba80f1
removed more node stuff
vim-sroberge Jul 9, 2025
f0edf45
renamed nodeState to visibility
vim-sroberge Jul 9, 2025
a328833
updated hitcheck
vim-sroberge Jul 11, 2025
446c98c
updating ultra node->elements
vim-sroberge Jul 11, 2025
55b8272
updated ultra core to match rpcs
vim-sroberge Jul 16, 2025
7f6294a
renames
vim-sroberge Jul 22, 2025
da4bec8
making ultra viewer api use three.color
vim-sroberge Jul 22, 2025
b20cc17
fixed colors
vim-sroberge Jul 23, 2025
88a4ffd
work for ultra
vim-sroberge Jul 25, 2025
5cda560
updated ultra to use remove overrides
vim-sroberge Jul 25, 2025
efab984
version": "0.5.0-dev.11
vim-sroberge Jul 25, 2025
71e2813
no longer double click if mouse moves
vim-sroberge Jul 29, 2025
999efea
webgl, frame all on double click void
vim-sroberge Jul 29, 2025
8f8e361
only one settings panel at a time
vim-sroberge Jul 29, 2025
f974c54
fixed ultra orbit/free toggle on space
vim-sroberge Jul 29, 2025
84a2f79
added support for minimize and icon to message box
vim-sroberge Jul 29, 2025
81dc5e7
version": "0.5.0-dev.13
vim-sroberge Jul 29, 2025
d16376d
version": "0.5.0-dev.13
vim-sroberge Jul 29, 2025
45d5270
fixed pointer override and context menu on mouse drag
vim-sroberge Jul 30, 2025
2a80358
Merge branch 'sroberge/ultra_update' of https://github.com/vimaec/vim…
vim-sroberge Jul 30, 2025
78a12e4
errors are not minimized by default, numpad +- buttons
vim-sroberge Jul 30, 2025
97823fa
"version": "0.5.0-dev.15",
vim-sroberge Jul 30, 2025
af5f611
types, scroll fix, message box props
vim-sroberge Oct 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
node_modules
dist
docs
docs2
src/pages/*.vim
13 changes: 6 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "vim-web",
"version": "0.4.1",
"version": "0.5.0-dev.17",
"description": "A demonstration app built on top of the vim-webgl-viewer",
"type": "module",
"files": [
Expand All @@ -23,13 +23,12 @@
"scripts": {
"dev": "vite",
"eslint": "eslint --ext .js,.ts,.tsx src --fix",
"documentation": "typedoc --entryPoints src/vim-web/index.ts --entryPointStrategy expand --out docs --excludeProtected --excludeExternals --excludePrivate",
"declarations": "tsc --project tsconfig.json --declaration --emitDeclarationOnly --outdir ./dist/types",
"build": "vite build --config vite.config.js && npm run declarations",
"package": "npm run build && npm publish",
"documentation": "typedoc --entryPoints src/vim-web/index.ts --entryPointStrategy expand --out docs2 --excludeProtected --excludeExternals --excludePrivate",
"declarations": "tsc -p tsconfig.types.json",
"build": "vite build && npm run declarations",
"publish:package": "npm run build && npm publish",
"publish:documentation": "npm run documentation && gh-pages -d docs",
"publish": "npm run publish:package && npm run publish:documentation"
"publish:documentation": "npm run documentation && gh-pages -d docs2",
"publish:both": "npm run publish:package && npm run publish:documentation"
},
"devDependencies": {
"@types/dom-webcodecs": "^0.1.13",
Expand Down
1 change: 1 addition & 0 deletions src/vim-web/core-viewers/shared/inputAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export interface IInputAdapter{
init: () => void

toggleOrthographic: () => void
toggleCameraOrbitMode: () => void
resetCamera: () => void
clearSelection: () => void
frameCamera: () => void
Expand Down
39 changes: 21 additions & 18 deletions src/vim-web/core-viewers/shared/inputHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,6 @@ export class InputHandler extends BaseInputHandler {
this.rotateSpeed = settings.rotateSpeed ?? 1
this.orbitSpeed = settings.orbitSpeed ?? 1

this.reg(document, 'contextmenu', (e: MouseEvent) => {
this._onContextMenu.dispatch(new THREE.Vector2(e.clientX, e.clientY))
e.preventDefault()
})
this.keyboard = new KeyboardHandler(canvas)
this.mouse = new MouseHandler(canvas)
this.touch = new TouchHandler(canvas)
Expand All @@ -76,13 +72,9 @@ export class InputHandler extends BaseInputHandler {
this.keyboard.onKeyUp = (key: string) => adapter.keyUp(key)

this.keyboard.registerKeyUp('KeyP', 'replace', () => adapter.toggleOrthographic());
this.keyboard.registerKeyUp('Equal', 'replace', () => this.moveSpeed++);
this.keyboard.registerKeyUp('Minus', 'replace', () => this.moveSpeed--);
this.keyboard.registerKeyUp('Space', 'replace', () => {
this._pointerActive = this._pointerActive === PointerMode.ORBIT ? PointerMode.LOOK : PointerMode.ORBIT;
this._pointerFallback = this._pointerActive;
this._onPointerModeChanged.dispatch();
});
this.keyboard.registerKeyUp(['Equal', 'NumpadAdd'], 'replace', () => this.moveSpeed++);
this.keyboard.registerKeyUp(['Minus', 'NumpadSubtract'], 'replace', () => this.moveSpeed--);
this.keyboard.registerKeyUp('Space', 'replace', () => adapter.toggleCameraOrbitMode());
this.keyboard.registerKeyUp('Home', 'replace', () => adapter.resetCamera());
this.keyboard.registerKeyUp('Escape', 'replace', () => adapter.clearSelection());
this.keyboard.registerKeyUp('KeyF', 'replace', () => {
Expand All @@ -95,18 +87,29 @@ export class InputHandler extends BaseInputHandler {
}

// Mouse controls
this.mouse.onContextMenu = (pos: THREE.Vector2) => this._onContextMenu.dispatch(pos);
this.mouse.onButtonDown = adapter.mouseDown
this.mouse.onMouseMove = adapter.mouseMove
this.mouse.onButtonUp = adapter.mouseUp
this.mouse.onButtonUp = (pos: THREE.Vector2, button: number) => {
this.pointerOverride = undefined
adapter.mouseUp(pos, button)
}
this.mouse.onDrag = (delta: THREE.Vector2, button: number) =>{
if(button === 0){
if(this._pointerActive === PointerMode.ORBIT) adapter.orbitCamera(toRotation(delta, this.orbitSpeed))
if(this._pointerActive === PointerMode.LOOK) adapter.rotateCamera(toRotation(delta, this.rotateSpeed))
if(this._pointerActive === PointerMode.PAN) adapter.panCamera(delta)
if(this._pointerActive === PointerMode.ZOOM) adapter.dollyCamera(delta)
if(this.pointerActive === PointerMode.ORBIT) adapter.orbitCamera(toRotation(delta, this.orbitSpeed))
if(this.pointerActive === PointerMode.LOOK) adapter.rotateCamera(toRotation(delta, this.rotateSpeed))
if(this.pointerActive === PointerMode.PAN) adapter.panCamera(delta)
if(this.pointerActive === PointerMode.ZOOM) adapter.dollyCamera(delta)
}
if(button === 2) adapter.rotateCamera(toRotation(delta,1))
if(button === 1) adapter.panCamera(delta)
if(button === 2){
this.pointerOverride = PointerMode.LOOK
adapter.rotateCamera(toRotation(delta,1))

}
if(button === 1){
this.pointerOverride = PointerMode.PAN
adapter.panCamera(delta)
}
}

this.mouse.onClick = (pos: THREE.Vector2, modif: boolean) => adapter.selectAtPointer(pos, modif)
Expand Down
8 changes: 6 additions & 2 deletions src/vim-web/core-viewers/shared/keyboardHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,12 @@ export class KeyboardHandler extends BaseInputHandler {
* @param code The event.code of the key.
* @param handler Callback invoked on key up.
*/
public registerKeyUp(code: string, mode: CallbackMode, handler: () => void): void {
this.registerKey(this.keyUpHandlers, code, mode, handler);
public registerKeyUp(code: string | string[], mode: CallbackMode, handler: () => void): void {
if (Array.isArray(code)) {
code.forEach(c => this.registerKey(this.keyUpHandlers, c, mode, handler));
} else {
this.registerKey(this.keyUpHandlers, code, mode, handler);
}
}

private registerKey(map: Map<string, () => void>, code: string, mode: CallbackMode, callback: () => void){
Expand Down
34 changes: 31 additions & 3 deletions src/vim-web/core-viewers/shared/mouseHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export class MouseHandler extends BaseInputHandler {
onClick: (position: THREE.Vector2, ctrl: boolean) => void;
onDoubleClick: (position: THREE.Vector2) => void;
onWheel: (value: number, ctrl: boolean) => void;
onContextMenu: (position: THREE.Vector2) => void;

constructor(canvas: HTMLCanvasElement) {
super(canvas);
Expand Down Expand Up @@ -64,6 +65,7 @@ export class MouseHandler extends BaseInputHandler {
this.handleDoubleClick(event);
}else{
this.handleMouseClick(event);
this.handleContextMenu(event);
}
event.preventDefault();
}
Expand All @@ -82,6 +84,20 @@ export class MouseHandler extends BaseInputHandler {
this.onClick?.(pos, modif);
}

private async handleContextMenu(event: PointerEvent): Promise<void> {
if (event.pointerType !== 'mouse') return;
if(event.button !== 2) return;

const pos = this.relativePosition(event);

if (!Utils.almostEqual(this._lastMouseDownPosition, pos, 0.01)) {
return;
}

this.onContextMenu?.(new THREE.Vector2(event.clientX, event.clientY));
}


private handlePointerMove(event: PointerEvent): void {
if (event.pointerType !== 'mouse') return;
this._canvas.focus();
Expand Down Expand Up @@ -143,13 +159,25 @@ class CaptureHandler {

class DoubleClickHandler {
private _lastClickTime: number = 0;
private _clickDelay: number = 300; // Delay in milliseconds to consider a double click
private _clickDelay: number = 300; // Max time between clicks for double-click
private _lastClickPosition: THREE.Vector2 | null = null;
private _positionThreshold: number = 5; // Max pixel distance between clicks

checkForDoubleClick(event: MouseEvent) {
checkForDoubleClick(event: MouseEvent): boolean {
const currentTime = Date.now();
const currentPosition = new THREE.Vector2(event.clientX, event.clientY);
const timeDiff = currentTime - this._lastClickTime;

const isClose =
this._lastClickPosition !== null &&
this._lastClickPosition.distanceTo(currentPosition) < this._positionThreshold;

const isWithinTime = timeDiff < this._clickDelay;

this._lastClickTime = currentTime;
return timeDiff < this._clickDelay;
this._lastClickPosition = currentPosition;

return isClose && isWithinTime;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/vim-web/core-viewers/shared/vim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export interface IVim<T extends IVimElement> {
* @param instance - The instance index of the of one of the instance included in the element.
* @returns The object corresponding to the instance, or undefined if not found.
*/
getElementFromInstanceIndex(instance: number): T | undefined
getElement(instance: number): T | undefined

/**
* Retrieves the element associated with the specified id.
Expand Down
23 changes: 12 additions & 11 deletions src/vim-web/core-viewers/ultra/camera.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,15 @@ export class Camera implements ICamera {
* @param segment - Optional segment to save as the camera position
*/
async save(segment?: Segment){
this._savedPosition = segment ?? await this._rpc.RPCGetCameraPosition()
this._savedPosition = segment ?? await this._rpc.RPCGetCameraView()
}

/**
* Resets the camera to the last saved position
*/
restoreSavedPosition(blendTime: number = this._defaultBlendTime){
if(!this._savedPosition) return
this._rpc.RPCSetCameraPosition(this._savedPosition, blendTime)
this._rpc.RPCSetCameraView(this._savedPosition, blendTime)
}

/**
Expand All @@ -102,7 +102,7 @@ export class Camera implements ICamera {
restoreLastPosition(blendTime: number = this._defaultBlendTime){
if(this._lastPosition?.isValid()){
console.log('Restoring camera position: ', this._lastPosition)
this._rpc.RPCSetCameraPosition(this._lastPosition, blendTime)
this._rpc.RPCSetCameraView(this._lastPosition, blendTime)
}
}

Expand All @@ -120,7 +120,7 @@ export class Camera implements ICamera {
}

set(position: THREE.Vector3, target: THREE.Vector3, blendTime: number = this._defaultBlendTime){
this._rpc.RPCSetCameraPosition(new Segment(position, target), blendTime)
this._rpc.RPCSetCameraView(new Segment(position, target), blendTime)
}

/**
Expand All @@ -137,7 +137,7 @@ export class Camera implements ICamera {
* @returns Promise that resolves when the framing animation is complete
*/
async frameAll (blendTime: number = this._defaultBlendTime): Promise<Segment | undefined> {
const segment = await this._rpc.RPCFrameAll(blendTime)
const segment = await this._rpc.RPCFrameScene(blendTime)
this._savedPosition = this._savedPosition ?? segment
return segment
}
Expand All @@ -148,31 +148,32 @@ export class Camera implements ICamera {
* @param blendTime - Duration of the camera animation in seconds (defaults to 0.5)
*/
async frameBox(box: THREE.Box3, blendTime: number = this._defaultBlendTime) : Promise<Segment | undefined> {
const segment = await this._rpc.RPCFrameBox(box, blendTime)

const segment = await this._rpc.RPCFrameAABB(box, blendTime)
this._savedPosition = this._savedPosition ?? segment
return segment
}

/**
* Frames specific nodes of a Vim model in the camera view
* @param vim - The Vim model containing the nodes to frame
* @param nodes - Array of node indices to frame, or 'all' to frame the entire model
* @param elements - Array of element indices to frame, or 'all' to frame the entire model
* @param blendTime - Duration of the camera animation in seconds (defaults to 0.5)
* @returns Promise that resolves when the framing animation is complete
*/
async frameVim(vim: Vim, nodes: number[] | 'all', blendTime: number = this._defaultBlendTime): Promise<Segment | undefined> {
async frameVim(vim: Vim, elements: number[] | 'all', blendTime: number = this._defaultBlendTime): Promise<Segment | undefined> {
let segment: Segment | undefined
if (nodes === 'all') {
if (elements === 'all') {
segment = await this._rpc.RPCFrameVim(vim.handle, blendTime);
} else {
segment = await this._rpc.RPCFrameInstances(vim.handle, nodes, blendTime);
segment = await this._rpc.RPCFrameElements(vim.handle, elements, blendTime);
}
this._savedPosition = this._savedPosition ?? segment
return segment
}

async frameObject(object: Element3D, blendTime: number = this._defaultBlendTime) : Promise<Segment | undefined> {
const segment = await this._rpc.RPCFrameInstances(object.vim.handle, [object.instance], blendTime)
const segment = await this._rpc.RPCFrameElements(object.vim.handle, [object.element], blendTime)
this._savedPosition = this._savedPosition ?? segment
return segment
}
Expand Down
Loading