-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
zoom is unusably faster in chrome than ff #4
Comments
better version
|
implemented as Mithril.js component: Components.PanZoom = {
LEFT_CLICK: 0,
MIDDLE_CLICK: 1,
RIGHT_CLICK: 2,
oninit(v) {
v.state.pointer = {};
v.state.translateX = 0;
v.state.translateY = 0;
v.state.scale = 1.0;
},
oncreate(v) {
const fn = Components.PanZoom.handleEvent.bind(null,v);
v.dom.addEventListener('mousemove', fn, { passive: true });
v.dom.addEventListener('mousedown', fn);
v.dom.addEventListener('mouseup', fn, { capture: true });
v.dom.addEventListener('wheel', fn, { capture: true });
v.dom.addEventListener('contextmenu', fn);
v.dom.addEventListener('touchmove', fn);
v.dom.addEventListener('touchstart', fn);
v.dom.addEventListener('touchend', fn, { passive: true });
},
handleEvent(v,e) {
if (true === v.attrs.debug && 'mousemove' !== e.type && 'touchmove' !== e.type) {
console.debug(`PanZoom debug ${e.type}`, e);
}
if ('mousemove' === e.type || 'mousedown' === e.type || 'touchmove' === e.type) {
let x,y;
if ('touchmove' === e.type) {
x = e.changedTouches[0].clientX;
y = e.changedTouches[0].clientY;
// prevent page drag
e.preventDefault();
}
else {
x = e.clientX;
y = e.clientY;
}
v.state.pointer.lastX = v.state.pointer.x;
v.state.pointer.lastY = v.state.pointer.y;
v.state.pointer.x = x;
v.state.pointer.y = y;
v.state.pointer.deltaX = v.state.pointer.x - v.state.pointer.lastX;
v.state.pointer.deltaY = v.state.pointer.y - v.state.pointer.lastY;
if (null != v.state.pointer.panningBy) {
v.state.translateX += (v.state.pointer.deltaX || 0);
v.state.translateY += (v.state.pointer.deltaY || 0);
Components.PanZoom.update(v);
}
else if (true === v.attrs.debug) {
m.redraw();
}
}
if (('mousedown' === e.type || 'touchstart' === e.type) && v.dom === e.target) {
v.state.pointer.button = e.button;
if (Components.PanZoom.LEFT_CLICK === e.button || Components.PanZoom.MIDDLE_CLICK === e.button || 'touchstart' === e.type) {
v.state.pointer.panningBy = e.type;
let x,y;
if ('touchstart' === e.type) {
x = e.changedTouches[0].clientX;
y = e.changedTouches[0].clientY;
}
else {
x = e.clientX;
y = e.clientY;
// prevent text selection
e.preventDefault();
}
v.state.pointer.lastX = x;
v.state.pointer.lastY = y;
v.state.pointer.x = x;
v.state.pointer.y = y;
v.state.pointer.deltaX = 0;
v.state.pointer.deltaY = 0;
Components.PanZoom.update(v);
}
}
else if ('mouseup' === e.type || 'touchend' === e.type) {
if ('mouseup' === e.type) {
v.state.pointer.button = undefined;
}
if (
('mouseup' === e.type && 'mousedown' === v.state.pointer.panningBy) ||
('touchend' === e.type && 'touchstart' === v.state.pointer.panningBy)
) {
v.state.pointer.panningBy = undefined;
}
}
else if ('wheel' === e.type) {
// prevent page scroll
e.preventDefault();
v.state.scale = Utils.clamp(v.state.scale + (
(
(e.wheelDelta ? e.wheelDelta : -e.deltaY) *
// Only Firefox seems to use the line unit (which we assume to be 25px),
// otherwise the delta is already measured in pixels.
(e.deltaMode === 1 ? 25 : 1)
) / 1000
), 0.2, 2);
Components.PanZoom.update(v);
}
else if ('contextmenu' === e.type && v.dom === e.target) {
// disable right-click menu
e.preventDefault();
}
},
update(v) {
v.state.lens.dom.style.transform =
`matrix(${v.state.scale}, 0, 0, ${v.state.scale}, ${v.state.translateX}, ${v.state.translateY})`;
},
view(v) {
return m('.pan-zoom-container', v.state.lens = m('.pan-zoom-lens',
(true === v.attrs.debug &&
m('pre.debug', JSON.stringify(_.pick(v.state, ['pointer','translateX','translateY','scale']), null, 2))),
v.children));
},
}; |
Thank you, this looks promising! I will take a look next week. |
If you'd like to see changes regarding the event handling and timing, feel free to create a separate issue for that. I am well aware of issues when heavy work is put on events rather than animation frames, but I'm not sure that's the case here so for the time being I'm ok with the event handling as-is. I've played with deltaMode a little and it's not entirely clear to me when the delta is supposed to be different. I've been able to reproduce the faster zoom on Firefox, but only when using a track pad to zoom, and not a scroll wheel. Is this the use case? A more concise example of the problem, e.g. on jsfiddle, would make your point much more understandable. |
Yes correct. Different input devices have different scale resolutions in different browsers. This is by design so any software not accounting for it is going to provide an experience that is not consistent for all users. It's not well documented but some googling regarding the purpose of |
It was also unusable for me on a trackpad in Safari without the fix mentioned above. |
nice lib.
here's my hack for trying to even out scroll speed between browsers when using touchpads:
you can probably make it cleaner. but its normalizing the scale between browsers by checking
WheelEvent.deltaMode
.see related:
weaveworks/scope#2788
https://github.com/weaveworks/scope/blob/d8ffea47815559ed908dd04f8593408ecb1e5b87/client/app/scripts/utils/zoom-utils.js
https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent/deltaMode
also you are doing event handling wrong.
in FF, events are emitted much less frequently than Chrome.
Chrome literally floods with events. You should be
_.debounce()
ing them.see also:
https://stackoverflow.com/a/25991510
http://demo.nimius.net/debounce_throttle/
also, you should not be doing the work inside the event callback. the callback should just be setting a few calculation values like delta, and you should have a separate function doing the work at a controlled (probably 12-24fps) frame rate (using
requestAnimationFrame()
, orsetTimeout
if you are a savage).sorry i don't have time to make a PR. hope this helps :)
The text was updated successfully, but these errors were encountered: