WD-40

浮动点击的元素(致敬清华源23年愚人节彩蛋)>_<

// ==UserScript==
// @name         WD-40
// @namespace    http://tampermonkey.net/
// @version      0.3.1
// @description  浮动点击的元素(致敬清华源23年愚人节彩蛋)>_<
// @author       insorker
// @match        http://*/*
// @match        https://*/*
// @note         2023.04-09-V0.3.1 作为替换的空白元素不会发生WD-40效应
// @note         2023.04-09-V0.3.0 jQuery使用国内cdn
// @note         2023.04-05-V0.2.0 结构修改,不影响使用
// @note         2023.04-04-V0.1.0 堂堂完成!
// @grant        GM_addStyle
// @license      MIT
// @require      https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.min.js
// ==/UserScript==

(function () {
    'use strict';

    class WDComponent {
        reposition(replaceElem, parentElem) {
            replaceElem.attr("WD-40-disable", "true");
            this.elem.replaceWith(replaceElem);
            parentElem.append(this.elem);
        }
    }

    class WDBox extends WDComponent {
        constructor(elem) {
            super();
            const offset = elem.offset();
            const width = elem.width();
            const height = elem.height();
            this.body = Matter.Bodies.rectangle(offset.left + width / 2, (offset === null || offset === void 0 ? void 0 : offset.top) + height / 2, width, height);
            this.elem = elem;
            // restyle element with absolute position
            this.elem.css({
                'position': 'absolute',
                'top': offset.top,
                'left': offset.left,
                'width': width,
                'height': height,
                'background': 'hsl(0, 0%, 96%)',
                'border-radius': '4px',
                'box-shadow': '0px 0px 10px rgba(0, 0, 0, 25%)'
            });
            // replace the original element with empty div
            // move the original element to body
            let replaceElem = $('<div></div>').css({
                'width': width,
                'height': height,
            });
            let parentElem = $('body');
            this.reposition(replaceElem, parentElem);
        }
        render() {
            const { x, y } = this.body.position;
            const angle = this.body.angle;
            this.elem.css({
                'top': `${y - this.elem.height() / 2}px`,
                'left': `${x - this.elem.width() / 2}px`,
                'transform': `rotate(${angle}rad)`
            });
        }
    }

    class WD40 {
        constructor(config) {
            this.engine = config.engine;
            this.selector = config.selector;
            this.boxes = [];
            this.setup();
        }
        setup() {
            let engine = this.engine;
            let boxes = this.boxes;
            $('body').on('click', this.selector, function (event) {
                event.stopPropagation();
                // prevent multiple click on same element
                for (let box of boxes) {
                    if (box.elem[0] == this) {
                        return;
                    }
                }
                if ($(this).attr("WD-40-disable")) {
                    return;
                }
                let box = new WDBox($(this));
                Matter.Body.applyForce(box.body, { x: event.pageX, y: event.pageY }, { x: Math.random() / 20, y: Math.random() / 20 });
                boxes.push(box);
                Matter.Composite.add(engine.world, [box.body]);
            });
        }
        render() {
            for (let box of this.boxes) {
                box.render();
            }
        }
    }

    // module aliases
    var Engine = Matter.Engine, Render = Matter.Render, Runner = Matter.Runner, Composite = Matter.Composite;
    // create an engine
    var engine = Engine.create();
    engine.gravity.y = -0.04;
    // create a renderer
    let render = Render.create({
        // element: document.body,
        engine: engine,
        options: {
            width: $(window).width(),
            height: $(window).height(),
        }
    });
    // create WDBox
    let wd40 = new WD40({
        engine: engine,
        selector: 'div, li, td'
    });
    let ground = Matter.Bodies.rectangle($(window).width() / 2, -50, $(window).width(), 100, { isStatic: true });
    // add all of the bodies to the world
    Composite.add(engine.world, [ground]);
    // run the renderer
    Render.run(render);
    // create runner
    var runner = Runner.create();
    // run the engine
    Runner.run(runner, engine);
    function step() {
        wd40.render();
        requestAnimationFrame(step);
    }
    requestAnimationFrame(step);

})();