// 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;
}
}
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 mousewheel. Note that Example is also a practical example of the element geometry and CSS positioning techniques explained.
Be the first to comment
You can use [html][/html], [css][/css], [php][/php] and more to embed the code. Urls are automatically hyperlinked. Line breaks and paragraphs are automatically generated.