-
Notifications
You must be signed in to change notification settings - Fork 17k
Description
Problem
Hey Electron Community 👋
We're developing a tab-less browser that allows users to open sites in cards and align them as a grid on an infinite canvas.
Additionally, we intend to create a panoramic scrolling functionality, which allows users to navigate between cards by swiping left and right
The following GIF illustrates a simplified version of the layout and the horizontal scrolling experience:
We use BrowserViews for showing the content of the website.
- For creating layouts we combined
BrowserView.setBoundsAPI together with Facebook YOGA. - [Problem]: We want to create scroll functionality. It consists of 2 parts:
- Capture mouse events
- Move BrowserViews accordingly left and right, or up and down.
Existing Solution
To capture mouse events we inject custom scripts in the webContents.
It listens to the wheel event on the document and sends deltaX and deltaY to the main process.
On the other side, the main process receives delta value and recalculates the bounds of each BrowserView
// injected script
document.on('wheel', (e) => {
ipcRenderer.invoke('scroll', e.deltaX)
}, { passive: true })
// main
const views = [ /* collection of browserviews */]
ipcMain.handle('scroll', (e, deltaX) => {
views.forEach(view => {
const { x } = view.getBounds()
view.setBounds({ x: x + deltaX })
})
})This approach does not work because of the following reasons.
- Performance is not smooth enough, especially it suffers on Windows.
- (for trackpad users) while scrolling whenever the cursor jumps from one BrowserView to another, the document stops to receive wheel events and it gets stuck at the edge. You need to lift the finger from the trackpad and trigger the scroll again. There's no consistency, but it does happen very often. Check out the Demo
Demo
The following gist for the electron fiddle also demonstrates the same problem: https://gist.github.com/ddramone/305d9f8fe1a02851beecb407e8b876fb
Proposal
We would like to propose adding an experimental ScrollView and ContainerView APIs in the main process.
//main
const { BaseWindow, ContainerView, ScrollView, BrowserView } = require("electron");
const window = new BaseWindow({ width: 1400, height: 700 })
const scroll = new ScrollView()
scroll.setBounds({ width: 1400, height: 700, x: 0, y: 0 })
const scrollContent = new ContainerView()
let CONTENT_WIDTH = 0
[ /* ... list of cards ... */ ].forEach((card) => {
const { url, bounds } = card
const browserView = new BrowserView()
browserView.webContents.loadURL(url)
browserView.setBounds(bounds)
scrollContent.addBrowserView(browserView)
CONTENT_WIDTH += bounds.width
});
scrollContent.setBounds({ width: CONTENT_WIDTH, height: 700, x: 0, y: 0 })
scroll.setContentView(scrollContent);
win.setContainerView(scroll);This approach allows us to create a scrollable content container by using ContainerView and adding BrowserViews as its children.
Then we add ContainerView as a direct child of the ScrollView which is responsible to capture mouse events and scroll the content accordingly.
How:
In order to achieve the presented assumptions, we have implemented an API that allows building a hierarchy of various types of views. To improve the clarity of the API, We defined ContainerView and ScrollView which inherit from BaseView.
We tried to keep the consistent implementation across all platforms, which is compatible with the Electron architecture - On MacOS we used NSView to support draggable regions, on Windows and Linux we used Chromium's views :: View
We have this approach tested with positive results on both platforms.
Currently, @martin-world1977 is in the process of finalizing the API, testing, and cleaning up changes.
He's the person working on electron full-time.
While we’re preparing pull request, it would be great to hear your opinion.
Shortly About US:
We are Stack and we are building a browser that has focus, organization & collaboration at its core.
Why? Because 2.5b people every day are using a tool (conventional browsers) design of which hasn't changed for more than 20 years. Tab clutter slows us down and we believe the time has come to change that.
We already have a working product that is built using Electron <webview /> and is used by more than 15K people on daily basis. A few months ago, we came across unsolvable technical challenges and decided to rewrite Stack from scratch. After experimenting with various native technologies, we settled back to Electron by using BrowserViews instead of WebViews.
We are a young, growing company with a team of 20 based in Amsterdam, The Netherlands. (www.stackbrowser.com)
We're excited to contribute to the Electron ecosystem and make it even more powerful.

