Skip to content

Instantly share code, notes, and snippets.

@luisenriquecorona
Created May 12, 2019 23:20
Show Gist options
  • Save luisenriquecorona/b10e162fea9e335fcde41ff98cd26a76 to your computer and use it in GitHub Desktop.
Save luisenriquecorona/b10e162fea9e335fcde41ff98cd26a76 to your computer and use it in GitHub Desktop.
In order to work correctly in all common browsers, Example must perform some browser testing. The example anticipates the DOM Level 3 Events specifi- cation and includes code to use the wheel event when browsers implement it.6 It also includes some future-proofing to stop using the DOMMouseScroll event when Firefox starts firing wheel or mousewh…
// Enclose the content element in a frame or viewport of the specified width
// and height (minimum 50x50). The optional contentX and contentY arguments
// specify the initial offset of the content relative to the frame. (If
// specified, they must be <= 0.) The frame has mousewheel event handlers that
// allow the user to pan the element, and to shrink or enlarge the frame.
function enclose(content, framewidth, frameheight, contentX, contentY) {
// These arguments aren't just the initial values: they maintain the
// current state and are used and modified by the mousewheel handler.
framewidth = Math.max(framewidth, 50);
frameheight = Math.max(frameheight, 50);
contentX = Math.min(contentX, 0) || 0;
contentY = Math.min(contentY, 0) || 0;
// Create the frame element and set a CSS classname and styles
var frame = document.createElement("div");
frame.className = "enclosure"; // So we can define styles in a stylesheet
frame.style.width = framewidth + "px"; // Set the frame size.
frame.style.height = frameheight + "px";
frame.style.overflow = "hidden"; // No scrollbars, no overflow
frame.style.boxSizing = "border-box"; // Border-box simplifies the
frame.style.webkitBoxSizing = "border-box"; // calculations for resizing
frame.style.MozBoxSizing = "border-box"; // the frame.
// Put the frame in the document and move the content elt into the frame.
content.parentNode.insertBefore(frame, content);
frame.appendChild(content);
// Position the element relative to the frame
content.style.position = "relative";
content.style.left = contentX + "px";
content.style.top = contentY + "px";
// We'll need to work around some browser-specific quirks below
var isMacWebkit = (navigator.userAgent.indexOf("Macintosh") !== -1 &&
navigator.userAgent.indexOf("WebKit") !== -1);
var isFirefox = (navigator.userAgent.indexOf("Gecko") !== -1);
// Register mousewheel event handlers.
frame.onwheel = wheelHandler; // Future browsers
frame.onmousewheel = wheelHandler; // Most current browsers
if (isFirefox) // Firefox only
frame.addEventListener("DOMMouseScroll", wheelHandler, false);
function wheelHandler(event) {
var e = event || window.event; // Standard or IE event object
// Extract the amount of rotation from the event object, looking
// for properties of a wheel event object, a mousewheel event object
// (in both its 2D and 1D forms), and the Firefox DOMMouseScroll event.
// Scale the deltas so that one "click" toward the screen is 30 pixels.
// If future browsers fire both "wheel" and "mousewheel" for the same
// event, we'll end up double-counting it here. Hopefully, however,
// cancelling the wheel event will prevent generation of mousewheel.
var deltaX = e.deltaX*-30 || // wheel event
e.wheelDeltaX/4 || // mousewheel
0; // property not defined
var deltaY = e.deltaY*-30 || // wheel event
e.wheelDeltaY/4 || // mousewheel event in Webkit
(e.wheelDeltaY===undefined && // if there is no 2D property then
e.wheelDelta/4) || // use the 1D wheel property
e.detail*-10 || // Firefox DOMMouseScroll event
0; // property not defined
// Most browsers generate one event with delta 120 per mousewheel click.
// On Macs, however, the mousewheels seem to be velocity-sensitive and
// the delta values are often larger multiples of 120, at
// least with the Apple Mouse. Use browser-testing to defeat this.
if (isMacWebkit) {
deltaX /= 30;
deltaY /= 30;
}
// If we ever get a mousewheel or wheel event in (a future version of)
// Firefox, then we don't need DOMMouseScroll anymore.
if (isFirefox && e.type !== "DOMMouseScroll")
frame.removeEventListener("DOMMouseScroll", wheelHandler, false);
// Get the current dimensions of the content element
var contentbox = content.getBoundingClientRect();
var contentwidth = contentbox.right - contentbox.left;
var contentheight = contentbox.bottom - contentbox.top;
if (e.altKey) { // If Alt key is held down, resize the frame
if (deltaX) {
framewidth -= deltaX; // New width, but not bigger than the
framewidth = Math.min(framwidth, contentwidth); // content
framewidth = Math.max(framewidth,50); // and no less than 50.
frame.style.width = framewidth + "px"; // Set it on frame
}
if (deltaY) {
frameheight -= deltaY; // Do the same for the frame height
frameheight = Math.min(frameheight, contentheight);
frameheight = Math.max(frameheight-deltaY, 50);
frame.style.height = frameheight + "px";
}
}
else { // Without the Alt modifier, pan the content within the frame
if (deltaX) {
// Don't scroll more than this
var minoffset = Math.min(framewidth-contentwidth, 0);
// Add deltaX to contentX, but don't go lower than minoffset
contentX = Math.max(contentX + deltaX, minoffset);
contentX = Math.min(contentX, 0); // or higher than 0
content.style.left = contentX + "px"; // Set new offset
}
if (deltaY) {
var minoffset = Math.min(frameheight - contentheight, 0);
// Add deltaY to contentY, but don't go lower than minoffset
contentY = Math.max(contentY + deltaY, minoffset);
contentY = Math.min(contentY, 0); // Or higher than 0
content.style.top = contentY + "px"; // Set the new offset.
}
}
// Don't let this event bubble. Prevent any default action.
// This stops the browser from using the mousewheel event to scroll
// the document. Hopefully calling preventDefault() on a wheel event
// will also prevent the generation of a mousewheel event for the
// same rotation.
if (e.preventDefault) e.preventDefault();
if (e.stopPropagation) e.stopPropagation();
e.cancelBubble = true; // IE events
e.returnValue = false; // IE events
return false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment