jnschulze / flutter-webview-windows

A WebView2-powered Flutter WebView implementation for the Windows platform.
BSD 3-Clause "New" or "Revised" License
207 stars 120 forks source link

Scroll down and Up are not working. #28

Open toannguyendts opened 3 years ago

toannguyendts commented 3 years ago

I try to use mouse scroll . But It is not affected. I have tested it on WPF. It is working perfectly. Anh Touch support only click. Cannot move. Thank!

I tested it on https://joltfly.com/mouse-test/

Milesssssss commented 3 years ago

I have the same problem @jnschulze @toannguyendts

jnschulze commented 3 years ago

Scrolling works for me but in order to debug this, you can do a quick check if the problem is on the Dart or the native side.

This plugin uses the Listener widget on the Dart side for detecting scroll events. You might set up a Listener and see if it fires scroll events (using onPointerSignal).

toannguyendts commented 3 years ago

image @jnschulze you can move your mouse to this area and scroll it. It cannot scroll box inside. It is working only outside

tuantiensiu commented 3 years ago

Hi @toannguyendts, you can help me to setup this package in my project? You can provide your current version flutter. Because I have error in my project. You can show more error in this link: #41

angle222 commented 2 years ago

Scrolling works for me but in order to debug this, you can do a quick check if the problem is on the Dart or the native side.

This plugin uses the Listener widget on the Dart side for detecting scroll events. You might set up a Listener and see if it fires scroll events (using onPointerSignal).

I checked on my widget for using "onPointerSignal",the scroll events in widget worked,but in the webview's page,the scroll event doesn't worked

Ingenious-c0der commented 2 years ago

Scrolling works for me but in order to debug this, you can do a quick check if the problem is on the Dart or the native side.

This plugin uses the Listener widget on the Dart side for detecting scroll events. You might set up a Listener and see if it fires scroll events (using onPointerSignal).

So the scrolling does work, but the only places where it doesn't work (as expected) is when there are smaller containers in the webpage which are scrollable.

Expected Behaviour: When the mouse is placed on / hovered on the (webpage) container and scrolled, the scroll bar inside the smaller container should be considered and not the main page scroll bar (if it exists)

Current Behaviour: The mouse location doesn't really seem to matter, it will always interact with the main page (largest) scrollbar.

tashi146 commented 2 years ago

I am having the same issue with ESRI Map in webview, Zoom and zoom out by scrolling doesn't work. I am using the latest version. I can see code reach

return _methodChannel.invokeMethod('setScrollDelta', [dx, dy]);
But after that I believe we need to run in native to debug Any update on this? Update: I end up creating own Listener widget and update the same listener in web content as well.

incspitz commented 2 years ago

@tashi146 , could you describe exactly what you did to workaround the issue? I debugged the case and the line setScrollDelta is called when scrolling a small container with scrollbar. Which listener did you update in web content? Thanky you!

newproplus commented 1 year ago

any updates?

979liyang commented 1 year ago

Scrolling works for me but in order to debug this, you can do a quick check if the problem is on the Dart or the native side.

This plugin uses the Listener widget on the Dart side for detecting scroll events. You might set up a Listener and see if it fires scroll events (using onPointerSignal).

So the scrolling does work, but the only places where it doesn't work (as expected) is when there are smaller containers in the webpage which are scrollable.

Expected Behaviour: When the mouse is placed on / hovered on the (webpage) container and scrolled, the scroll bar inside the smaller container should be considered and not the main page scroll bar (if it exists)

Current Behaviour: The mouse location doesn't really seem to matter, it will always interact with the main page (largest) scrollbar.

Did you solve it.

aisams commented 1 year ago

同样的问题,无法与网页小滚动条交互,始终是与最外层的滚动条交互。有解决问题的麻烦回复我下谢谢,514435771@qq.com

toannguyendts commented 1 year ago

I have solution for this. You must custom onPointerSignal of lib. By my way, I dont use _controller._setScrollDelta . I will use postMessage to my web apps. Then my webapps can capture event scroll. Finally, you can control event scroll by your self.

*Flutter Side: Go to webview_windows.dart Add function below

String postMouseEvent(String mouseEvent,dynamic data)
  {
    return jsonEncode({"mouse_event" : mouseEvent,"data" : data});
  }

Then override onPotinerSignal

onPointerSignal: (signal) {
                        if (signal is PointerScrollEvent) {
                          String mouse_event = postMouseEvent("scroll",{"scroll_delta_dx":-signal.scrollDelta.dx,"scroll_delta_dy":-signal.scrollDelta.dy});
                          _controller.postWebMessage(mouse_event);
                          // _controller._setScrollDelta(
                          //     -signal.scrollDelta.dx, -signal.scrollDelta.dy);
                        }
                      },

handleMessage(message) { let direction = message.data.data.scroll_delta_dy > 0 ? -1 : 1; let distance = 40; if(this.getScrollDiv(this.element)) { let classList = this.getScrollDiv(this.element).classList; let queryString = ""; for(let i = 0; i < classList.length; i++) { queryString += ('.' + classList[i]); } let elems = document.querySelectorAll(queryString); if (elems && elems[0]) { elems.forEach((elem) => { elem.scrollTop += direction * distance; }); } } }, getScrollDiv(el) { while (el && el.parentNode) { if(el.style.overflow == "auto" || el.style.overflow == "scroll" || el.style.overflowY == "auto" || el.style.overflowY == "scroll") { return el; } el = el.parentNode; } return null; },

bvoq commented 1 year ago

We solved it in a similar fashion, here is the source code for reference:


  Future<void> scrollWebview(double mouseX, double mouseY, double dx, double dy) {
    return _windowsController.executeScript("""
            function eleCanScroll(ele) {
              if (ele.scrollTop > 0) { return ele; }
              else {
                ele.scrollTop++;
                const top = ele.scrollTop;
                top && (ele.scrollTop = 0);
                if(top > 0){
                  return ele;
                } else {
                  return eleCanScroll( ele.parentElement);
                }
              }
            }
            var el = document.elementFromPoint($mouseX,$mouseY);
            var el2 = eleCanScroll(el);
            el2.scrollBy($dx,$dy);
            """);
  }

// ... inside your body use:
return Listener(
        onPointerPanZoomUpdate: (event) {
          final Offset panDelta = event.panDelta;
          final Offset position = event.position;
          scrollWebview(position.dx, position.dy, panDelta.dx, panDelta.dy);
        },
        onPointerSignal: (signal) {
          if (signal is PointerScrollEvent) {
            final Offset scrollDelta = signal.scrollDelta;
            final Offset position = signal.position;
            scrollWebview(position.dx, position.dy, scrollDelta.dx, scrollDelta.dy);
          }
        },
        child: Stack(
          children: [
            webview_windows.Webview(
              _windowsController,
            ),
            StreamBuilder<webview_windows.LoadingState>(
              stream: _windowsController.loadingState,
              builder: (context, snapshot) {
                if (snapshot.hasData && snapshot.data == webview_windows.LoadingState.loading) {
                  return const LinearProgressIndicator();
                } else {
                  return const SizedBox();
                }
              },
            ),
          ],
        ),
      );
aisams commented 6 months ago

我们以类似的方式解决了这个问题,下面是源代码供参考:


  Future<void> scrollWebview(double mouseX, double mouseY, double dx, double dy) {
    return _windowsController.executeScript("""
            function eleCanScroll(ele) {
              if (ele.scrollTop > 0) { return ele; }
              else {
                ele.scrollTop++;
                const top = ele.scrollTop;
                top && (ele.scrollTop = 0);
                if(top > 0){
                  return ele;
                } else {
                  return eleCanScroll( ele.parentElement);
                }
              }
            }
            var el = document.elementFromPoint($mouseX,$mouseY);
            var el2 = eleCanScroll(el);
            el2.scrollBy($dx,$dy);
            """);
  }

// ... inside your body use:
return Listener(
        onPointerPanZoomUpdate: (event) {
          final Offset panDelta = event.panDelta;
          final Offset position = event.position;
          scrollWebview(position.dx, position.dy, panDelta.dx, panDelta.dy);
        },
        onPointerSignal: (signal) {
          if (signal is PointerScrollEvent) {
            final Offset scrollDelta = signal.scrollDelta;
            final Offset position = signal.position;
            scrollWebview(position.dx, position.dy, scrollDelta.dx, scrollDelta.dy);
          }
        },
        child: Stack(
          children: [
            webview_windows.Webview(
              _windowsController,
            ),
            StreamBuilder<webview_windows.LoadingState>(
              stream: _windowsController.loadingState,
              builder: (context, snapshot) {
                if (snapshot.hasData && snapshot.data == webview_windows.LoadingState.loading) {
                  return const LinearProgressIndicator();
                } else {
                  return const SizedBox();
                }
              },
            ),
          ],
        ),
      );

用了你的方法,发现能解决嵌套滚动的问题了,但鼠标放大的效果不起作用。请问中间有图表放大的问题如何解决呢? 例如以下网址图表需要滚动放大:https://ait0.goingmerry.hk/#/tradingview?symbol=W2405&resultSymbol=CBOT_W2405

brunobwn commented 6 months ago

We solved it in a similar fashion, here is the source code for reference:


  Future<void> scrollWebview(double mouseX, double mouseY, double dx, double dy) {
    return _windowsController.executeScript("""
            function eleCanScroll(ele) {
              if (ele.scrollTop > 0) { return ele; }
              else {
                ele.scrollTop++;
                const top = ele.scrollTop;
                top && (ele.scrollTop = 0);
                if(top > 0){
                  return ele;
                } else {
                  return eleCanScroll( ele.parentElement);
                }
              }
            }
            var el = document.elementFromPoint($mouseX,$mouseY);
            var el2 = eleCanScroll(el);
            el2.scrollBy($dx,$dy);
            """);
  }

// ... inside your body use:
return Listener(
        onPointerPanZoomUpdate: (event) {
          final Offset panDelta = event.panDelta;
          final Offset position = event.position;
          scrollWebview(position.dx, position.dy, panDelta.dx, panDelta.dy);
        },
        onPointerSignal: (signal) {
          if (signal is PointerScrollEvent) {
            final Offset scrollDelta = signal.scrollDelta;
            final Offset position = signal.position;
            scrollWebview(position.dx, position.dy, scrollDelta.dx, scrollDelta.dy);
          }
        },
        child: Stack(
          children: [
            webview_windows.Webview(
              _windowsController,
            ),
            StreamBuilder<webview_windows.LoadingState>(
              stream: _windowsController.loadingState,
              builder: (context, snapshot) {
                if (snapshot.hasData && snapshot.data == webview_windows.LoadingState.loading) {
                  return const LinearProgressIndicator();
                } else {
                  return const SizedBox();
                }
              },
            ),
          ],
        ),
      );

Thanks, this worked for me.

I only need to adjust the scrollWebview function because my webview isn't filling all the space on the view. So I need to convert the x and y mouse positions to the widget's correct size.

  Future<void> scrollWebview(
      double mouseX, double mouseY, double dx, double dy) {
    // get relative position from window
    final RenderBox renderBox = context.findRenderObject() as RenderBox;
    final Offset localOffset = renderBox.localToGlobal(Offset.zero);
    mouseX -= localOffset.dx;
    mouseY -= localOffset.dy;

    return _windowsController.executeScript("""
            function eleCanScroll(ele) {
              if (ele.scrollTop > 0) { return ele; }
              else {
                ele.scrollTop++;
                const top = ele.scrollTop;
                top && (ele.scrollTop = 0);
                if(top > 0){
                  return ele;
                } else {
                  return eleCanScroll( ele.parentElement);
                }
              }
            }
            var el = document.elementFromPoint($mouseX,$mouseY);
            var el2 = eleCanScroll(el);
            el2.scrollBy($dx,$dy);
            """);
  }
albe-jj commented 1 week ago

None of the solution mentioned above seem to allow to zoom in into an interactive plot like the one displayed in the html file below.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Bokeh Plot</title>
    <style>
      html, body {
        box-sizing: border-box;
        height: 100%;
        margin: 0;
        padding: 0;
      }
    </style>
    <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-3.1.0.min.js"></script>
    <script type="text/javascript">
        Bokeh.set_log_level("info");
    </script>
  </head>
  <body>
    <div id="f51afd3d-72f3-4292-9b9b-95295add4f5a" data-root-id="p1128" style="display: contents;"></div>

    <script type="application/json" id="p1257">
      {"e91e631c-e1f0-4cd3-8907-4f155d1fc643":{"version":"3.1.0","title":"Bokeh Application","defs":[],"roots":[{"type":"object","name":"Figure","id":"p1128","attributes":{"x_range":{"type":"object","name":"DataRange1d","id":"p1130"},"y_range":{"type":"object","name":"DataRange1d","id":"p1129"},"x_scale":{"type":"object","name":"LinearScale","id":"p1142"},"y_scale":{"type":"object","name":"LinearScale","id":"p1144"},"title":{"type":"object","name":"Title","id":"p1131","attributes":{"text":"Simple Line Plot"}},"renderers":[{"type":"object","name":"GlyphRenderer","id":"p1181","attributes":{"data_source":{"type":"object","name":"ColumnDataSource","id":"p1175","attributes":{"selected":{"type":"object","name":"Selection","id":"p1176","attributes":{"indices":[],"line_indices":[]}},"selection_policy":{"type":"object","name":"UnionRenderers","id":"p1177"},"data":{"type":"map","entries":[["x",[1,2,3,4]],["y",[4,7,2,5]]]}}},"view":{"type":"object","name":"CDSView","id":"p1182","attributes":{"filter":{"type":"object","name":"AllIndices","id":"p1183"}}},"glyph":{"type":"object","name":"Line","id":"p1178","attributes":{"x":{"type":"field","field":"x"},"y":{"type":"field","field":"y"},"line_color":"#1f77b4","line_width":2}},"nonselection_glyph":{"type":"object","name":"Line","id":"p1179","attributes":{"x":{"type":"field","field":"x"},"y":{"type":"field","field":"y"},"line_color":"#1f77b4","line_alpha":0.1,"line_width":2}},"muted_glyph":{"type":"object","name":"Line","id":"p1180","attributes":{"x":{"type":"field","field":"x"},"y":{"type":"field","field":"y"},"line_color":"#1f77b4","line_alpha":0.2,"line_width":2}}}}],"toolbar":{"type":"object","name":"Toolbar","id":"p1137","attributes":{"tools":[{"type":"object","name":"PanTool","id":"p1160"},{"type":"object","name":"WheelZoomTool","id":"p1161"},{"type":"object","name":"BoxZoomTool","id":"p1162","attributes":{"overlay":{"type":"object","name":"BoxAnnotation","id":"p1163","attributes":{"syncable":false,"level":"overlay","visible":false,"left_units":"canvas","right_units":"canvas","bottom_units":"canvas","top_units":"canvas","line_color":"black","line_alpha":1.0,"line_width":2,"line_dash":[4,4],"fill_color":"lightgrey","fill_alpha":0.5}}}},{"type":"object","name":"SaveTool","id":"p1164"},{"type":"object","name":"ResetTool","id":"p1165"},{"type":"object","name":"HelpTool","id":"p1166"},{"type":"object","name":"WheelZoomTool","id":"p1186"}],"active_scroll":{"id":"p1186"}}},"left":[{"type":"object","name":"LinearAxis","id":"p1153","attributes":{"ticker":{"type":"object","name":"BasicTicker","id":"p1156","attributes":{"mantissas":[1,2,5]}},"formatter":{"type":"object","name":"BasicTickFormatter","id":"p1154"},"axis_label":"y","major_label_policy":{"type":"object","name":"AllLabels","id":"p1155"}}}],"below":[{"type":"object","name":"LinearAxis","id":"p1146","attributes":{"ticker":{"type":"object","name":"BasicTicker","id":"p1149","attributes":{"mantissas":[1,2,5]}},"formatter":{"type":"object","name":"BasicTickFormatter","id":"p1147"},"axis_label":"x","major_label_policy":{"type":"object","name":"AllLabels","id":"p1148"}}}],"center":[{"type":"object","name":"Grid","id":"p1152","attributes":{"axis":{"id":"p1146"}}},{"type":"object","name":"Grid","id":"p1159","attributes":{"dimension":1,"axis":{"id":"p1153"}}},{"type":"object","name":"Legend","id":"p1184","attributes":{"items":[{"type":"object","name":"LegendItem","id":"p1185","attributes":{"label":{"type":"value","value":"Test"},"renderers":[{"id":"p1181"}]}}]}}]}}],"callbacks":{"type":"map"}}}
    </script>
    <script type="text/javascript">
      (function() {
        const fn = function() {
          Bokeh.safely(function() {
            (function(root) {
              function embed_document(root) {
              const docs_json = document.getElementById('p1257').textContent;
              const render_items = [{"docid":"e91e631c-e1f0-4cd3-8907-4f155d1fc643","roots":{"p1128":"f51afd3d-72f3-4292-9b9b-95295add4f5a"},"root_ids":["p1128"]}];
              root.Bokeh.embed.embed_items(docs_json, render_items);
              }
              if (root.Bokeh !== undefined) {
                embed_document(root);
              } else {
                let attempts = 0;
                const timer = setInterval(function(root) {
                  if (root.Bokeh !== undefined) {
                    clearInterval(timer);
                    embed_document(root);
                  } else {
                    attempts++;
                    if (attempts > 100) {
                      clearInterval(timer);
                      console.log("Bokeh: ERROR: Unable to run BokehJS code because BokehJS library is missing");
                    }
                  }
                }, 10, root)
              }
            })(window);
          });
        };
        if (document.readyState != "loading") fn();
        else document.addEventListener("DOMContentLoaded", fn);
      })();
    </script>
  </body>
</html>