浏览代码

add crosshair and update documentation

Falko Schindler 3 年之前
父节点
当前提交
2e65c7ac55
共有 3 个文件被更改,包括 34 次插入5 次删除
  1. 10 2
      main.py
  2. 22 1
      nicegui/elements/annotation_tool.js
  3. 2 2
      nicegui/elements/annotation_tool.py

+ 10 - 2
main.py

@@ -132,8 +132,16 @@ with example(overlay):
         ui.svg(svg_content).style('background:transparent')
 
 with example(ui.annotation_tool):
-    ui.annotation_tool('http://placeimg.com/640/360/geometry',
-                       on_mouse=lambda e: ui.notify(f'{e.image_x:.1f}, {e.image_y:.1f}'))
+    from nicegui.events import MouseEventArguments
+
+    def mouse_handler(e: MouseEventArguments):
+        color = 'green' if e.type == 'mousedown' else 'red'
+        at.svg_content += f'<circle cx="{e.image_x}" cy="{e.image_y}" r="10" fill="{color}"/>'
+        ui.notify(f'{e.type} at ({e.image_x:.1f}, {e.image_y:.1f})')
+
+    at = ui.annotation_tool('http://placeimg.com/640/360/geometry',
+                            on_mouse=mouse_handler,
+                            events=['mousedown', 'mouseup'], cross=True)
 
 with example(ui.markdown):
     ui.markdown('### Headline\nWith hyperlink to [GitHub](https://github.com/zauberzeug/nicegui).')

+ 22 - 1
nicegui/elements/annotation_tool.js

@@ -2,15 +2,36 @@ Vue.component("annotation_tool", {
   template: `
     <div :id="jp_props.id" style="position:relative;display:inline-block">
       <img style="max-width:100%">
-      <svg style="position:absolute;top:0;left:0;pointer-events:none" v-html="jp_props.options.svg_content"></svg>
+      <svg style="position:absolute;top:0;left:0;pointer-events:none">
+        <g style="display:none">
+          <line x1="100" y1="0" x2="100" y2="100%" stroke="black" />
+          <line x1="0" y1="100" x2="100%" y2="100" stroke="black" />
+        </g>
+        <g v-html="jp_props.options.svg_content"></g>
+      </svg>
     </div>
   `,
   mounted() {
     const image = document.getElementById(this.$props.jp_props.id).firstChild;
     const svg = document.getElementById(this.$props.jp_props.id).lastChild;
+    const cross = svg.firstChild;
     image.ondragstart = () => false;
     if (this.$props.jp_props.options.cross) {
       image.style.cursor = "none";
+      image.addEventListener("mouseenter", (e) => {
+        cross.style.display = "block";
+      });
+      image.addEventListener("mouseleave", (e) => {
+        cross.style.display = "none";
+      });
+      image.addEventListener("mousemove", (e) => {
+        const x = (e.offsetX * e.target.naturalWidth) / e.target.clientWidth;
+        const y = (e.offsetY * e.target.naturalHeight) / e.target.clientHeight;
+        cross.firstChild.setAttribute("x1", x);
+        cross.firstChild.setAttribute("x2", x);
+        cross.lastChild.setAttribute("y1", y);
+        cross.lastChild.setAttribute("y2", y);
+      });
     }
     image.onload = (e) => {
       const viewBox = `0 0 ${image.naturalWidth} ${image.naturalHeight}`;

+ 2 - 2
nicegui/elements/annotation_tool.py

@@ -19,11 +19,11 @@ class AnnotationTool(Element):
     def __init__(self, source: str, on_mouse: Callable, *, events: list[str] = ['click'], cross: bool = False):
         """Annotation Tool
 
-        Create a special image that handles mouse clicks and yields image coordinates.
+        Create an image with an SVG overlay that handles mouse events and yields image coordinates.
 
         :param source: the source of the image; can be an url or a base64 string
         :param on_mouse: callback for mouse events (yields `type`, `image_x` and `image_y`)
-        :param events: list of JavaScript events to subscribe to
+        :param events: list of JavaScript events to subscribe to (default: `['click']`)
         :param cross: whether to show crosshairs (default: `False`)
         """
         self.mouse_handler = on_mouse