pywebview icon indicating copy to clipboard operation
pywebview copied to clipboard

Drag and drop performance issue on more complex html pages.

Open Nexlab-One opened this issue 1 year ago • 4 comments

Specification

  • pywebview version: 5.1
  • operating system: Windows
  • web renderer: Default

Description

When a window contains too many elements, the drag and drop performace suffers greatly. It can take over 5 seconds to finally register a drop has occured.

For example in the following code, dropping is nearly instant, but change the rendered html to google.com for example, then after 10 seconds, the drop is finally registered:

from webview.dom import DOMEventHandler

import datetime

def on_drag(e):
    print(f"on_drag {datetime.datetime.now()}")
    pass

def on_drop(e):
    print(f"on_drop {datetime.datetime.now()}")
    files = e['dataTransfer']['files']
    if len(files) == 0:
        return
    print(f'Event: {e["type"]}. Dropped files:')
    for file in files:
        print(file.get('pywebviewFullPath'))

def bind(window):
    window.dom.document.events.dragenter += DOMEventHandler(on_drag, True, True)
    window.dom.document.events.dragstart += DOMEventHandler(on_drag, True, True)
    window.dom.document.events.dragover += DOMEventHandler(on_drag, True, True)
    window.dom.document.events.drop += DOMEventHandler(on_drop, True, True)

if __name__ == '__main__':
    window = webview.create_window(
        'Drag & drop example', html='''
        <html>
        <body style="height: 100vh;">
        <h1>Drag files here</h1>
        <div class="pywebview-drag-region">Drop zone</div>
        </body>
        </html>
        '''
    )
    webview.start(bind, window)

Practicalities

  • YES I am willing to work on this issue myself. (If I know what to fix)

  • NO I am prepared to support this issue financially.

Nexlab-One avatar May 29 '24 15:05 Nexlab-One

The logic for DOM events handling can be found in https://github.com/r0x0r/pywebview/blob/b1c0c1d6f225d31d4aeeabfde7a1682d1ee5b165/webview/util.py#L243

It launches a new thread for each event. This might be a reason for a lag.

r0x0r avatar May 29 '24 21:05 r0x0r

The logic for DOM events handling can be found in

https://github.com/r0x0r/pywebview/blob/b1c0c1d6f225d31d4aeeabfde7a1682d1ee5b165/webview/util.py#L243

It launches a new thread for each event. This might be a reason for a lag.

The issue is with these three lines:

    window.dom.document.events.dragenter += DOMEventHandler(on_drag, True, True)
    window.dom.document.events.dragstart += DOMEventHandler(on_drag, True, True)
    window.dom.document.events.dragover += DOMEventHandler(on_drag, True, True)

What handles the dragging functionality here?

Nexlab-One avatar May 30 '24 14:05 Nexlab-One

The logic for DOM events handling can be found in https://github.com/r0x0r/pywebview/blob/b1c0c1d6f225d31d4aeeabfde7a1682d1ee5b165/webview/util.py#L243

It launches a new thread for each event. This might be a reason for a lag.

The issue is with these three lines:

    window.dom.document.events.dragenter += DOMEventHandler(on_drag, True, True)
    window.dom.document.events.dragstart += DOMEventHandler(on_drag, True, True)
    window.dom.document.events.dragover += DOMEventHandler(on_drag, True, True)

What handles the dragging functionality here?

The reason is that the dragoover event is triggered too frequently, which is equivalent to constantly triggering when you drag and drop a file into it

I have tested dragging a file, and I triggered it 30 times here

Perhaps the one below is what you want

get full file path html

<div id="drag_zone"></div>

onMounted(() => {
    const element = document.getElementById('drag_zone');
    if (!element) return;
    element.addEventListener('dragover', (e) => {
        e.preventDefault();
    });

});

python

def on_drop(e):
    files = e['dataTransfer']['files']
    if len(files) == 0:
        return

    for file in files:
        print(file.get('pywebviewFullPath'))
drag_zone = window.dom.get_element('#drag_zone')
event = 'drop'
setattr(drag_zone.events, event, DOMEvent(event, drag_zone._window, drag_zone))
drag_zone.events.drop += DOMEventHandler(on_drop, True, True)

huan1936 avatar Jun 15 '24 16:06 huan1936

import webview
from webview.dom import DOMEventHandler

import datetime


def on_drag(e):
    print(f"on_drag {datetime.datetime.now()}")
    pass


def on_drop(e):
    print(f"on_drop {datetime.datetime.now()}")
    files = e['dataTransfer']['files']
    if len(files) == 0:
        return
    print(f'Event: {e["type"]}. Dropped files:')
    for file in files:
        print(file.get('pywebviewFullPath'))


def bind(window):
    window.dom.document.events.drop += DOMEventHandler(on_drop, True, True)


if __name__ == '__main__':
    window = webview.create_window(
        'Drag & drop example', html='''
        <html>
        <body style="height: 100vh;">
        <h1>Drag files here</h1>
        <div class="pywebview-drag-region">Drop zone</div>
        <script>
        document.addEventListener('dragover', function(event) {
            event.preventDefault();
        });
        </script>
        </body>
        </html>
        '''
    )
    webview.start(bind, window)

huan1936 avatar Jun 15 '24 17:06 huan1936

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

github-actions[bot] avatar Jul 16 '24 02:07 github-actions[bot]

The message to post on the issue when closing it. If none provided, will not comment when closing an issue.

github-actions[bot] avatar Jul 21 '24 02:07 github-actions[bot]