Selaa lähdekoodia

integrate joystick

Falko Schindler 2 vuotta sitten
vanhempi
säilyke
2a50e13189

+ 29 - 0
nicegui/elements/joystick.py

@@ -0,0 +1,29 @@
+from typing import Any, Callable, Optional
+
+from .. import vue
+from ..element import Element
+
+vue.register_component('joystick', __file__, 'joystick.vue', ['lib/nipplejs.min.js'])
+
+
+class Joystick(Element):
+
+    def __init__(self, *,
+                 on_start: Optional[Callable] = None,
+                 on_move: Optional[Callable] = None,
+                 on_end: Optional[Callable] = None,
+                 **options: Any) -> None:
+        """Joystick
+
+        Create a joystick based on `nipple.js <https://yoannmoi.net/nipplejs/>`_.
+
+        :param on_start: callback for when the user touches the joystick
+        :param on_move: callback for when the user moves the joystick
+        :param on_end: callback for when the user releases the joystick
+        :param options: arguments like `color` which should be passed to the `underlying nipple.js library <https://github.com/yoannmoinet/nipplejs#options>`_
+        """
+        super().__init__('joystick')
+        self.on('start', on_start)
+        self.on('move', on_move, args=['data'])
+        self.on('end', on_end)
+        self._props['options'] = options

+ 31 - 0
nicegui/elements/joystick.vue

@@ -0,0 +1,31 @@
+<template>
+  <div class="joystick"></div>
+</template>
+
+<script>
+export default {
+  mounted() {
+    const joystick = nipplejs.create({
+      zone: document.querySelector(".joystick"),
+      position: { left: "50%", top: "50%" },
+      dynamicPage: true,
+      ...this.$props.options,
+    });
+    joystick.on("start", (e) => this.$emit("start", e));
+    joystick.on("move", (_, data) => this.$emit("move", { data }));
+    joystick.on("end", (e) => this.$emit("end", e));
+  },
+  props: {
+    options: Object,
+  },
+};
+</script>
+
+<style scoped>
+:scope {
+  background-color: AliceBlue;
+  position: relative;
+  width: 10em;
+  height: 10em;
+}
+</style>

+ 0 - 28
nicegui/elements/old/custom_view.py

@@ -1,28 +0,0 @@
-import justpy as jp
-
-
-class CustomView(jp.JustpyBaseComponent):
-
-    def __init__(self, vue_type, **options):
-        self.vue_type = vue_type
-
-        self.pages = {}
-        self.classes = ''
-        self.style = ''
-        self.options = jp.Dict(**options)
-        self.components = []
-
-        super().__init__(temp=False)
-
-    def react(self, _):
-        pass
-
-    def convert_object_to_dict(self):
-        return {
-            'vue_type': self.vue_type,
-            'id': self.id,
-            'show': True,
-            'classes': self.classes,
-            'style': self.style,
-            'options': self.options,
-        }

+ 0 - 47
nicegui/elements/old/joystick.js

@@ -1,47 +0,0 @@
-Vue.component("joystick", {
-  template: `
-  <div data-nicegui='joystick' v-bind:id="jp_props.id" :class="jp_props.classes" style="background-color:AliceBlue;position:relative;width:10em;height:10em" :style="jp_props.style"></div>
-    `,
-  mounted() {
-    const joystick = nipplejs.create({
-      zone: document.getElementById(this.$props.jp_props.id),
-      dynamicPage: true,
-      ...this.$props.jp_props.options,
-    });
-    joystick.on("start", () => {
-      const event = {
-        event_type: "onStart",
-        vue_type: this.$props.jp_props.vue_type,
-        id: this.$props.jp_props.id,
-        page_id: page_id,
-        websocket_id: websocket_id,
-      };
-      send_to_server(event, "event");
-    });
-    joystick.on("move", (_, data) => {
-      delete data.instance;
-      const event = {
-        event_type: "onMove",
-        vue_type: this.$props.jp_props.vue_type,
-        id: this.$props.jp_props.id,
-        page_id: page_id,
-        websocket_id: websocket_id,
-        data: data,
-      };
-      send_to_server(event, "event");
-    });
-    joystick.on("end", () => {
-      const event = {
-        event_type: "onEnd",
-        vue_type: this.$props.jp_props.vue_type,
-        id: this.$props.jp_props.id,
-        page_id: page_id,
-        websocket_id: websocket_id,
-      };
-      send_to_server(event, "event");
-    });
-  },
-  props: {
-    jp_props: Object,
-  },
-});

+ 0 - 60
nicegui/elements/old/joystick.py

@@ -1,60 +0,0 @@
-from typing import Any, Callable, Optional
-
-from ..routes import add_dependencies
-from .custom_view import CustomView
-from .element import Element
-
-add_dependencies(__file__, ['nipplejs.min.js'])
-
-
-class JoystickView(CustomView):
-
-    def __init__(self,
-                 on_start: Optional[Callable],
-                 on_move: Optional[Callable],
-                 on_end: Optional[Callable],
-                 **options: Any):
-        super().__init__('joystick', **options)
-
-        self.on_start = on_start
-        self.on_move = on_move
-        self.on_end = on_end
-        self.allowed_events = ['onStart', 'onMove', 'onEnd']
-        self.initialize(temp=False,
-                        onStart=self.handle_start,
-                        onMove=self.handle_move,
-                        onEnd=self.handle_end)
-
-    def handle_start(self, msg):
-        if self.on_start is not None:
-            return self.on_start(msg) or False
-        return False
-
-    def handle_move(self, msg):
-        if self.on_move is not None:
-            return self.on_move(msg) or False
-        return False
-
-    def handle_end(self, msg):
-        if self.on_end is not None:
-            return self.on_end(msg) or False
-        return False
-
-
-class Joystick(Element):
-
-    def __init__(self, *,
-                 on_start: Optional[Callable] = None,
-                 on_move: Optional[Callable] = None,
-                 on_end: Optional[Callable] = None,
-                 **options: Any):
-        """Joystick
-
-        Create a joystick based on `nipple.js <https://yoannmoi.net/nipplejs/>`_.
-
-        :param on_start: callback for when the user touches the joystick
-        :param on_move: callback for when the user moves the joystick
-        :param on_end: callback for when the user releases the joystick
-        :param options: arguments like `color` which should be passed to the `underlying nipple.js library <https://github.com/yoannmoinet/nipplejs#options>`_
-        """
-        super().__init__(JoystickView(on_start, on_move, on_end, **options))

+ 1 - 0
nicegui/ui.py

@@ -9,6 +9,7 @@ from .elements.column import Column as column
 from .elements.html import Html as html
 from .elements.icon import Icon as icon
 from .elements.image import Image as image
+from .elements.joystick import Joystick as joystick
 from .elements.label import Label as label
 from .elements.row import Row as row
 from .elements.separator import Separator as separator

+ 42 - 14
nicegui/vue.py

@@ -1,3 +1,6 @@
+from __future__ import annotations
+
+from dataclasses import dataclass
 from pathlib import Path
 from typing import Dict, List, Tuple
 
@@ -5,16 +8,27 @@ import vbuild
 from starlette.responses import FileResponse
 from starlette.routing import Route
 
-components: Dict[str, Path] = {}
+components: Dict[str, Component] = {}
+
 
+@dataclass
+class Component:
+    name: str
+    path: Path
+    dependencies: List[str]
 
-def register_component(name: str, py_filepath: str, component_filepath: str) -> None:
+
+def register_component(name: str, py_filepath: str, component_filepath: str, dependencies: List[str] = []) -> None:
     assert name not in components
-    components[name] = Path(py_filepath).parent / component_filepath
+    components[name] = Component(
+        name=name,
+        path=Path(py_filepath).parent / component_filepath,
+        dependencies=[Path(py_filepath).parent / dependency for dependency in dependencies],
+    )
 
 
 def generate_vue_content() -> Tuple[str]:
-    builds = [vbuild.VBuild(p.name, p.read_text()) for p in components.values() if p.suffix == '.vue']
+    builds = [vbuild.VBuild(c.name, c.path.read_text()) for c in components.values() if c.path.suffix == '.vue']
     return (
         '\n'.join(v.html for v in builds),
         '<style>' + '\n'.join(v.style for v in builds) + '</style>',
@@ -22,19 +36,33 @@ def generate_vue_content() -> Tuple[str]:
     )
 
 
-def get_js_components() -> Dict[str, str]:
-    return {name: filepath for name, filepath in components.items() if filepath.suffix == '.js'}
+def get_js_components() -> List[Component]:
+    return [c for c in components.values() if c.path.suffix == '.js']
 
 
 def generate_js_routes() -> List[Route]:
-    return [
-        Route(f'/_vue/{name}', lambda _, filepath=filepath: FileResponse(filepath, media_type='text/javascript'))
-        for name, filepath in get_js_components().items()
-    ]
+    routes: List[Route] = []
+    for component in components.values():
+        for dependency in component.dependencies:
+            print(dependency, flush=True)
+            routes.append(Route(f'/_vue/{component.name}/{dependency}',
+                                lambda _, path=dependency: FileResponse(path, media_type='text/javascript')))
+    for component in get_js_components():
+        routes.append(Route(f'/_vue/{component.name}',
+                            lambda _, path=component.path: FileResponse(path, media_type='text/javascript')))
+    return routes
 
 
 def generate_js_imports() -> str:
-    return '\n'.join(f'''
-        import {{ default as {name} }} from "/_vue/{name}";
-        app.component("{name}", {name});
-    ''' for name in get_js_components().keys())
+    result = ''
+    for component in components.values():
+        for dependency in component.dependencies:
+            result += f'''
+                import "/_vue/{component.name}/{dependency}";
+            '''
+    for component in get_js_components():
+        result += f'''
+            import {{ default as {component.name} }} from "/_vue/{component.name}";
+            app.component("{component.name}", {component.name});
+        '''
+    return result