Pixel Art Zoom

Add-on that allows the user to scroll images so they can view pixel art in browser

目前为 2018-03-03 提交的版本。查看 最新版本

// ==UserScript==
// @name         Pixel Art Zoom
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Add-on that allows the user to scroll images so they can view pixel art in browser
// @author       You
// @match        *://*/*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';
    // Add-on that allows the user to scroll images so they can view pixel art in browser
    var classes = {
        Pixelated: "25CVD21Z_2-pixelated"
    };
    var mouseDown = false;
    var target = undefined;
    var imgContainer = undefined;
    var originalWidth = 0;
    var originalHeight = 0;
    var originalX = 0;
    var originalY = 0;
    var zoom = 1;
    addCSSClasses();
    // Setup event handling for mouse+keyboard
    document.addEventListener("mousedown", function (e) {
        // Only active if the  ctlr key ispressed while clicking an img
        var targetElem = e.target.tagName;
        if ((e.ctrlKey && e.shiftKey) && targetElem === "IMG") {
            mouseDown = true;
            e.preventDefault();
            e.stopPropagation();
            createImgContainer(e);
            zoom += 1;
            resizeImg();
        }
    });
    document.addEventListener("mouseup", function (e) {
        if (mouseDown) {
            e.preventDefault();
            e.stopPropagation();
            mouseDown = false;
        }
    });
    document.addEventListener("wheel", function (e) {
        // check if user has scrolled the mouse wheel(while holding ctrl) over the zoomable image.
        if (e.ctrlKey && imgContainer && e.target.hasAttribute("data-open")) {
            e.preventDefault();
            e.stopPropagation();
            if (e.deltaY < 0) {
                zoom = Math.max(1, zoom - 1);
            }
            else if (e.deltaY > 0) {
                zoom = Math.min(10, zoom + 1);
            }
            resizeImg();
        }
    });
    function addCSSClasses() {
        var head = document.head;
        var newCss = document.createElement("style");
        newCss.type = "text/css";
        newCss.innerHTML = "\n." + classes.Pixelated + "{\n  image-rendering: -webkit-optimize-contrast; \n  image-rendering: -webkit-crisp-edges; \n  image-rendering: -moz-crisp-edges; \n  image-rendering: -o-crisp-edges; \n  image-rendering: pixelated; \n  -ms-interpolation-mode: nearest-neighbor; \n  position:absolute;\n  z-index: 1000000;\n  box-shadow: 0 19px 38px rgba(0, 0, 0, 0.6), 0 15px 12px rgba(0, 0, 0, 0.46);\n  background: #BBBC94;\n}\n";
        head.appendChild(newCss);
    }
    function resizeImg() {
        if (target === undefined || imgContainer === undefined)
            throw new Error("target or imageContainer were undefined");
        // set new image dimensions based on zoom level;
        var targetWidth = zoom * originalWidth;
        var targetHeight = zoom * originalHeight;
        target.style.width = targetWidth + "px";
        target.style.height = targetHeight + "px";
        // try to position the image nicely so it fits on screen without user needing to scroll.
        // Tries to center, but if that isn't possible, then just position at top-left corner
        if (originalX + targetWidth > window.scrollX + window.innerWidth) {
            imgContainer.style.left = window.scrollX + Math.max(0, Math.floor((window.innerWidth - targetWidth) / 2)) + "px";
        }
        else {
            imgContainer.style.left = Math.max(window.scrollX, originalX - (targetWidth - originalWidth) / 2) + "px";
        }
        if (originalY + targetHeight > window.scrollY + window.innerHeight) {
            imgContainer.style.top = window.scrollY + Math.max(0, Math.floor((window.innerHeight - targetHeight) / 2)) + "px";
        }
        else {
            imgContainer.style.top = Math.max(window.scrollY, originalY - (targetHeight - originalHeight) / 2) + "px";
        }
    }
    function createImgContainer(e) {
        if (imgContainer !== undefined)
            return; // avoid creating duplicates
        target = e.target;
        // create container for image that is absolutely positioned
        imgContainer = document.createElement("div");
        var offset = cumulativeOffset();
        imgContainer.style.top = offset.top + "px";
        imgContainer.style.left = offset.left + "px";
        imgContainer.className = classes.Pixelated; // sets rendering mode to crisp pixels.
        // created a copy of the image we want to scroll since we need to modify its properties for zooming.
        target = target.cloneNode(true);
        target.removeAttribute("style"); // remove any cruft that modifies the size, padding, etc.
        target.removeAttribute("class"); // same
        target.removeAttribute("height"); // same
        target.removeAttribute("width"); // same
        // Add a custom attribute so we can differentiate between events on the zoomable image and others
        target.setAttribute("data-open", "active");
        /// save some of the original image's properties
        originalWidth = target.width;
        originalHeight = target.height;
        originalX = offset.left;
        originalY = offset.top;
        // And now add the container and image to the DOM
        imgContainer.appendChild(target);
        // It doesn't matter that we insert it as the first element, but is easier for debugging.
        document.body.insertBefore(imgContainer, document.body.firstElementChild);
        // Focus the image and add event to clean up when user clicks away from image
        target.setAttribute("tabindex", "0"); // Needed so the image can be focused.
        target.addEventListener("blur", function () {
            destroyImgContainer();
        }, true);
        target.focus(); // Can only be called AFTER the img is added to the DOM
        /** Find the position of an element relative to the top-left corner of document */
        function cumulativeOffset() {
            var bbox = target.getBoundingClientRect();
            // damn margin
            var style = window.getComputedStyle(target);
            var marginLeft = parseInt(style.marginLeft.replace(" px", ""), 10);
            var marginTop = parseInt(style.marginTop.replace(" px", ""), 10);
            return {
                left: bbox.left + window.scrollX - marginLeft,
                top: bbox.top + window.scrollY - marginTop
            };
        }
    }
    function destroyImgContainer() {
        if (imgContainer === undefined)
            return;
        document.body.removeChild(imgContainer);
        // reset to initial state
        target = undefined;
        imgContainer = undefined;
        zoom = 1;
    }

})();