|
@@ -3,7 +3,8 @@ from typing import Any, Callable, Dict, List, Optional, Union
|
|
|
|
|
|
from .. import binding, globals
|
|
from .. import binding, globals
|
|
from ..element import Element
|
|
from ..element import Element
|
|
-from ..events import GenericEventArguments, SceneClickEventArguments, SceneClickHit, handle_event
|
|
|
|
|
|
+from ..events import (GenericEventArguments, SceneClickEventArguments, SceneClickHit, SceneDragEventArguments,
|
|
|
|
+ handle_event)
|
|
from ..helpers import KWONLY_SLOTS
|
|
from ..helpers import KWONLY_SLOTS
|
|
from .scene_object3d import Object3D
|
|
from .scene_object3d import Object3D
|
|
|
|
|
|
@@ -33,6 +34,7 @@ class Scene(Element,
|
|
'lib/three/three.module.js',
|
|
'lib/three/three.module.js',
|
|
'lib/three/modules/CSS2DRenderer.js',
|
|
'lib/three/modules/CSS2DRenderer.js',
|
|
'lib/three/modules/CSS3DRenderer.js',
|
|
'lib/three/modules/CSS3DRenderer.js',
|
|
|
|
+ 'lib/three/modules/DragControls.js',
|
|
'lib/three/modules/OrbitControls.js',
|
|
'lib/three/modules/OrbitControls.js',
|
|
'lib/three/modules/STLLoader.js',
|
|
'lib/three/modules/STLLoader.js',
|
|
]):
|
|
]):
|
|
@@ -57,10 +59,13 @@ class Scene(Element,
|
|
height: int = 300,
|
|
height: int = 300,
|
|
grid: bool = True,
|
|
grid: bool = True,
|
|
on_click: Optional[Callable[..., Any]] = None,
|
|
on_click: Optional[Callable[..., Any]] = None,
|
|
|
|
+ on_drag_start: Optional[Callable[..., Any]] = None,
|
|
|
|
+ on_drag_end: Optional[Callable[..., Any]] = None,
|
|
|
|
+ drag_constraints: str = '',
|
|
) -> None:
|
|
) -> None:
|
|
"""3D Scene
|
|
"""3D Scene
|
|
|
|
|
|
- Display a 3d scene using `three.js <https://threejs.org/>`_.
|
|
|
|
|
|
+ Display a 3D scene using `three.js <https://threejs.org/>`_.
|
|
Currently NiceGUI supports boxes, spheres, cylinders/cones, extrusions, straight lines, curves and textured meshes.
|
|
Currently NiceGUI supports boxes, spheres, cylinders/cones, extrusions, straight lines, curves and textured meshes.
|
|
Objects can be translated, rotated and displayed with different color, opacity or as wireframes.
|
|
Objects can be translated, rotated and displayed with different color, opacity or as wireframes.
|
|
They can also be grouped to apply joint movements.
|
|
They can also be grouped to apply joint movements.
|
|
@@ -68,7 +73,10 @@ class Scene(Element,
|
|
:param width: width of the canvas
|
|
:param width: width of the canvas
|
|
:param height: height of the canvas
|
|
:param height: height of the canvas
|
|
:param grid: whether to display a grid
|
|
:param grid: whether to display a grid
|
|
- :param on_click: callback to execute when a 3d object is clicked
|
|
|
|
|
|
+ :param on_click: callback to execute when a 3D object is clicked
|
|
|
|
+ :param on_drag_start: callback to execute when a 3D object is dragged
|
|
|
|
+ :param on_drag_end: callback to execute when a 3D object is dropped
|
|
|
|
+ :param drag_constraints: comma-separated JavaScript expression for constraining positions of dragged objects (e.g. ``'x = 0, z = y / 2'``)
|
|
"""
|
|
"""
|
|
super().__init__()
|
|
super().__init__()
|
|
self._props['width'] = width
|
|
self._props['width'] = width
|
|
@@ -78,9 +86,14 @@ class Scene(Element,
|
|
self.stack: List[Union[Object3D, SceneObject]] = [SceneObject()]
|
|
self.stack: List[Union[Object3D, SceneObject]] = [SceneObject()]
|
|
self.camera: SceneCamera = SceneCamera()
|
|
self.camera: SceneCamera = SceneCamera()
|
|
self.on_click = on_click
|
|
self.on_click = on_click
|
|
|
|
+ self.on_drag_start = on_drag_start
|
|
|
|
+ self.on_drag_end = on_drag_end
|
|
self.is_initialized = False
|
|
self.is_initialized = False
|
|
self.on('init', self.handle_init)
|
|
self.on('init', self.handle_init)
|
|
self.on('click3d', self.handle_click)
|
|
self.on('click3d', self.handle_click)
|
|
|
|
+ self.on('dragstart', self.handle_drag)
|
|
|
|
+ self.on('dragend', self.handle_drag)
|
|
|
|
+ self._props['drag_constraints'] = drag_constraints
|
|
|
|
|
|
def __enter__(self) -> 'Scene':
|
|
def __enter__(self) -> 'Scene':
|
|
Object3D.current_scene = self
|
|
Object3D.current_scene = self
|
|
@@ -124,6 +137,21 @@ class Scene(Element,
|
|
)
|
|
)
|
|
handle_event(self.on_click, arguments)
|
|
handle_event(self.on_click, arguments)
|
|
|
|
|
|
|
|
+ def handle_drag(self, e: GenericEventArguments) -> None:
|
|
|
|
+ arguments = SceneDragEventArguments(
|
|
|
|
+ sender=self,
|
|
|
|
+ client=self.client,
|
|
|
|
+ type=e.args['type'],
|
|
|
|
+ object_id=e.args['object_id'],
|
|
|
|
+ object_name=e.args['object_name'],
|
|
|
|
+ x=e.args['x'],
|
|
|
|
+ y=e.args['y'],
|
|
|
|
+ z=e.args['z'],
|
|
|
|
+ )
|
|
|
|
+ if arguments.type == 'dragend':
|
|
|
|
+ self.objects[arguments.object_id].move(arguments.x, arguments.y, arguments.z)
|
|
|
|
+ handle_event(self.on_drag_start if arguments.type == 'dragstart' else self.on_drag_end, arguments)
|
|
|
|
+
|
|
def __len__(self) -> int:
|
|
def __len__(self) -> int:
|
|
return len(self.objects)
|
|
return len(self.objects)
|
|
|
|
|