How to Scroll Frame Using Mouse Wheel & Adding Horizontal Scrollbar

How to do a horizontal scroll on mouse wheel scroll?

It looks like he's just mapping the mousewheel event to scrolling the area. In IE, this is really easy by just using the doScroll() method - this will scroll the horizontal bar by the amount the vertical bar would normally scroll by. Other browsers don't support the doScroll() method, so you have to live with scrolling by an arbitrary amount instead:

var mouseWheelEvt = function (event) {
if (document.body.doScroll)
document.body.doScroll(event.wheelDelta>0?"left":"right");
else if ((event.wheelDelta || event.detail) > 0)
document.body.scrollLeft -= 10;
else
document.body.scrollLeft += 10;

return false;
}
document.body.addEventListener("mousewheel", mouseWheelEvt);

tkinter: binding mousewheel to scrollbar

Perhaps the simplest solution is to make a global binding for the mousewheel. It will then fire no matter what widget is under the mouse or which widget has the keyboard focus. You can then unconditionally scroll the canvas, or you can be smart and figure out which of your windows should scroll.

For example, on windows you would do something like this:

self.canvas = Canvas(...)
self.canvas.bind_all("<MouseWheel>", self._on_mousewheel)
...
def _on_mousewheel(self, event):
self.canvas.yview_scroll(-1*(event.delta/120), "units")

Note that self.canvas.bind_all is a bit misleading -- you more correctly should call root.bind_all but I don't know what or how you define your root window. Regardless, the two calls are synonymous.

Platform differences:

  • On Windows, you bind to <MouseWheel> and you need to divide event.delta by 120 (or some other factor depending on how fast you want the scroll)
  • on OSX, you bind to <MouseWheel> and you need to use event.delta without modification
  • on X11 systems you need to bind to <Button-4> and <Button-5>, and you need to divide event.delta by 120 (or some other factor depending on how fast you want to scroll)

There are more refined solutions involving virtual events and determining which window has the focus or is under the mouse, or passing the canvas window reference through the binding, but hopefully this will get you started.

How to scroll the horizontal scrollbar in an iFrame from the parent frame?

There are at least two things wrong with your example:

if ("iframeWithWideContent" in document.body){
document.body.onmousewheel = mouseWheelEvt;
}else{
document.body.addEventListener("DOMMouseScroll", mouseWheelEvt);
}

Here you test for iframeWithWideContent being present in document.body and you rely on that condition to use either …onmousewheel or …addEventListener. These are completely unrelated. Moreover, addEventListener requires an extra argument.

As the answer you link to describes, Firefox doesn't support onmousewheel (it's non-standard anyway), so you should detect whether that property is present or not:

if ("onmousewheel" in document.body)
document.body.onmousewheel = mouseWheelEvt;
else
document.body.addEventListener("DOMMouseScroll", mouseWheelEvt, true);

Just in case you didn't know, this is (more or less) the right way of feature detection (in fact, I should have tested if DOMMouseScroll was available before applying it).

According to this answer, contentWindow is the iframe's window object.

Update: I made another test case and got it working in Firefox and Chrome (it probably works in other WebKit-based browsers, too).

iframescrolling.html:

<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<title><iframe> horizontal scrolling test</title>
<style>
* { padding: 0; margin: 0; border: 0 }
#large { background: #aaa; height: 5000px; width: 5000px }
</style>
</head>
<body>
<iframe id="iframeWithWideContent" src="iframecontent.html" width="500" height="300"></iframe>
<div id="large"></div>
<script>
var myIframe = document.getElementById("iframeWithWideContent");

myIframe.onload = function () {
var mouseWheelEvt = function (e) {
var event = e || window.event;

// the first is for Gecko, the second for Chrome/WebKit;
var scrEl = this.parentNode || event.target.parentNode;

if(event.wheelDelta)
var d = 60;
else
var d = -60;

if (document.body.doScroll)
document.body.doScroll(event.wheelDelta>0?"left":"right");
else if ((event.wheelDelta || event.detail) > 0)
scrEl.scrollLeft -= d;
else
scrEl.scrollLeft += d;

event.preventDefault();

return false;
};

if ("onmousewheel" in this.contentWindow.document)
this.contentWindow.document.onmousewheel = mouseWheelEvt;
else
this.contentWindow.document.body.addEventListener("DOMMouseScroll", mouseWheelEvt, true);
};
</script>
</body>
</html>

And iframecontent.html:

<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<title>iframe</title>
<style>
* { padding: 0; margin: 0; border: 0 }
#long { background: #ccc; height: 500px; width: 5000px }
</style>
</head>
<body>
<div id="long">long 5000px div</div>
</body>
</html>

I only tested this in Firefox 3.6.3 and Chromium 5.0.342.9, both running on Linux. To prevent errors in Chrome (about accessing iframes from a different domain or using a different protocol), you should upload these files or use a local test server (localhost).

One more side note: I highly doubt this will work in every (major) browser. At least it doesn't in (the highly standards compliant) Opera.

Update 2: On further testing the scrolling directions in Firefox and Chrome were opposite. I adjusted my code accordingly, using Mohammad's suggestions.

I also tested this in IE 7, but, although IE supports onmousewheel events, it didn't work properly. At this point I'm a little bored, so maybe I'll try to adapt the example to IE another time.

Horizontal Scrolling on React Component Using Vertical Mouse Wheel

Okay, so the issue seems to be that you only refer to the function event.preventDefault rather than invoking it.
Adding some brackets at the end to invoke it should do the trick:
event.preventDefault().

I however found this issue while looking for some simple code to use, so I will also leave the hook I made for this if others in the same situation:

import { useRef, useEffect } from "react";

export function useHorizontalScroll() {
const elRef = useRef();
useEffect(() => {
const el = elRef.current;
if (el) {
const onWheel = e => {
if (e.deltaY == 0) return;
e.preventDefault();
el.scrollTo({
left: el.scrollLeft + e.deltaY,
behavior: "smooth"
});
};
el.addEventListener("wheel", onWheel);
return () => el.removeEventListener("wheel", onWheel);
}
}, []);
return elRef;
}

Usage:

import React from "react";
import { useSideScroll } from "./useSideScroll";

export const SideScrollTest = () => {
const scrollRef = useHorizontalScroll();
return (
<div ref={scrollRef} style={{ width: 300, overflow: "auto" }}>
<div style={{ whiteSpace: "nowrap" }}>
I will definitely overflow due to the small width of my parent container
</div>
</div>
);
};

Note:
The scroll behavior "smooth" seems to be giving some trouble when trying to do continuous scrolling. This behavior can be omitted to have proper continuous scrolling, but it will look jerky.

As far as I know, there is no easy solution for this. I have however created a rather involved solution in my own project, so thought some people may appreciate that also: https://gist.github.com/TarVK/4cc89772e606e57f268d479605d7aded



Related Topics



Leave a reply



Submit