Skip to content

Commit

Permalink
Only show tab previews if mouse is moving slow enough
Browse files Browse the repository at this point in the history
- fixes brave#3271: Dont show tab preview unless mouse velocity is low enough
- tab preview requires that either:
  mouse be moving slower than a velocity threshold relative to tab size (so should be relative to resolution)
  mouse hover for longer than a new mouseover duration threshold (this may be unnecessary, velocity seems fine)
- 50% higher mouse velocity is tolerated if user is in "preview mode" (moving mouse from one tab to another, see issue brave#1434)
  to avoid flashing out when mousing from one tab preview to another
- velocity threshold is set in `constants/settings.js`: `tabs.tab-previews.mouse-velocity-threshold`
- mouseover duration threshold is set in `constants/settings.js`: `tabs.tab-previews.mouseover-duration-threshold-ms`
  • Loading branch information
Willy Bruns authored and lucidNTR committed Sep 30, 2016
1 parent 9e46456 commit 3d86adf
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 2 deletions.
81 changes: 79 additions & 2 deletions js/components/tab.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
const screen = require('electron').screen

const React = require('react')

Expand All @@ -16,6 +17,9 @@ const contextMenus = require('../contextMenus')
const dnd = require('../dnd')
const windowStore = require('../stores/windowStore')

const getSetting = require('../settings').getSetting
const settings = require('../constants/settings')

class Tab extends ImmutableComponent {
constructor () {
super()
Expand Down Expand Up @@ -122,13 +126,86 @@ class Tab extends ImmutableComponent {
onMouseEnter (e) {
// relatedTarget inside mouseenter checks which element before this event was the pointer on
// if this element has a tab-like class, then it's likely that the user was previewing
// a sequency of tabs. Called here as previewMode.
// a sequence of tabs. Called here as previewMode.
const previewMode = /tab(?!pages)/i.test(e.relatedTarget.classList)

// If user isn't in previewMode, we add a bit of delay to avoid tab from flashing out
// as reported here: https://github.com/brave/browser-laptop/issues/1434
let hoverTimeoutMs = 100
if (previewMode) {
hoverTimeoutMs = 0
}

let scalingFactor = { // scale by component dim so higher resolution displays don't feel different
x: e.target.clientWidth,
y: e.target.clientHeight
}

let getScaledCursorCoord = function () {
let cursorScreenPoint = screen.getCursorScreenPoint()
return {
x: (cursorScreenPoint.x / scalingFactor.x),
y: (cursorScreenPoint.y / scalingFactor.y),
timestamp: (new Date()).getTime()
}
}

let getMouseDelta = function (mouseCoordA, mouseCoordB) {
let delta = {
x: mouseCoordA.x - mouseCoordB.x,
y: mouseCoordA.y - mouseCoordB.y,
dt: (mouseCoordA.timestamp - mouseCoordB.timestamp) / 1000
}

delta.magnitude = Math.sqrt(delta.x * delta.x + delta.y * delta.y)
delta.velocity = delta.magnitude / delta.dt // relative coords / sec (if will leave in 1s, this would be 1)

return delta
}

this.mouseVecData = {
enterTimestamp: (new Date().getTime()),
lastVec: getScaledCursorCoord(),
delta: null
}

let hoverTimeoutFun = function () {
var curTimestamp = (new Date().getTime())

var mouseoverDuration = curTimestamp - this.mouseVecData.enterTimestamp

let lastVec = this.mouseVecData.lastVec
let curVec = getScaledCursorCoord()

let delta = getMouseDelta(curVec, lastVec)
let mouseVelocity = delta.velocity

this.mouseVecData.lastVec = curVec
this.mouseVecData.delta = delta

let TAB_PREVIEW_MOUSE_VELOCITY_THRESHOLD = getSetting(settings.TAB_PREVIEW_MOUSE_VELOCITY_THRESHOLD)
let TAB_PREVIEW_MOUSEOVER_DURATION_THRESHOLD = getSetting(settings.TAB_PREVIEW_MOUSEOVER_DURATION_THRESHOLD)

// If user is in "preview mode", let's increase the tolerated velocity by 50%
if (previewMode) {
TAB_PREVIEW_MOUSE_VELOCITY_THRESHOLD *= 1.5
}

let criterion = mouseVelocity < TAB_PREVIEW_MOUSE_VELOCITY_THRESHOLD || mouseoverDuration > TAB_PREVIEW_MOUSEOVER_DURATION_THRESHOLD

if (criterion) {
window.clearTimeout(this.hoverTimeout)
windowActions.setPreviewFrame(this.frame)

this.mouseVecData.enterTimestamp = null
this.mouseVecData.delta = null
} else {
this.hoverTimeout = window.setTimeout(hoverTimeoutFun, 100)
}
}.bind(this)

this.hoverTimeout =
window.setTimeout(windowActions.setPreviewFrame.bind(null, this.frame), previewMode ? 0 : 200)
window.setTimeout(hoverTimeoutFun, hoverTimeoutMs)
}

onClickTab (e) {
Expand Down
2 changes: 2 additions & 0 deletions js/constants/appConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ module.exports = {
'tabs.paint-tabs': true,
'tabs.tabs-per-page': 10,
'tabs.show-tab-previews': true,
'tabs.tab-previews.mouse-velocity-threshold': 0.5,
'tabs.tab-previews.mouseover-duration-threshold-ms': 1250,
'privacy.history-suggestions': true,
'privacy.bookmark-suggestions': true,
'privacy.opened-tab-suggestions': true,
Expand Down
2 changes: 2 additions & 0 deletions js/constants/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ const settings = {
PAINT_TABS: 'tabs.paint-tabs',
TABS_PER_PAGE: 'tabs.tabs-per-page',
SHOW_TAB_PREVIEWS: 'tabs.show-tab-previews',
TAB_PREVIEW_MOUSE_VELOCITY_THRESHOLD: 'tabs.tab-previews.mouse-velocity-threshold',
TAB_PREVIEW_MOUSEOVER_DURATION_THRESHOLD: 'tabs.tab-previews.mouseover-duration-threshold-ms',
// Privacy Tab
HISTORY_SUGGESTIONS: 'privacy.history-suggestions',
BOOKMARK_SUGGESTIONS: 'privacy.bookmark-suggestions',
Expand Down

0 comments on commit 3d86adf

Please sign in to comment.