layout-umd

An improved UMD build of layout

Ten skrypt nie powinien być instalowany bezpośrednio. Jest to biblioteka dla innych skyptów do włączenia dyrektywą meta // @require https://update.greasyfork.org/scripts/527730/1541454/layout-umd.js

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Greasemonkey lub Violentmonkey.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana będzie instalacja rozszerzenia Tampermonkey lub Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, musisz zainstalować rozszerzenie menedżera skryptów użytkownika.

(Mam już menedżera skryptów użytkownika, pozwól mi to zainstalować!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Musisz zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

(Mam już menedżera stylów użytkownika, pozwól mi to zainstalować!)

(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
    typeof define === 'function' && define.amd ? define(factory) :
    (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.layout = factory());
})(this, (() => {
    const binpack = (() => {
        class GrowingPacker {
            constructor() { }
            fit(blocks) {
                var n, node, block, len = blocks.length, fit;
                var width = len > 0 ? blocks[0].width : 0;
                var height = len > 0 ? blocks[0].height : 0;
                this.root = { x: 0, y: 0, width: width, height: height };
                for (n = 0; n < len; n++) {
                    block = blocks[n];
                    if (node = this.findNode(this.root, block.width, block.height)) {
                        fit = this.splitNode(node, block.width, block.height);
                        block.x = fit.x;
                        block.y = fit.y;
                    }
                    else {
                        fit = this.growNode(block.width, block.height);
                        block.x = fit.x;
                        block.y = fit.y;
                    }
                }
            }
            findNode(root, width, height) {
                if (root.used)
                    return this.findNode(root.right, width, height) || this.findNode(root.down, width, height);
                else if ((width <= root.width) && (height <= root.height))
                    return root;
                else
                    return null;
            }
            splitNode(node, width, height) {
                node.used = true;
                node.down = { x: node.x, y: node.y + height, width: node.width, height: node.height - height };
                node.right = { x: node.x + width, y: node.y, width: node.width - width, height: height };
                return node;
            }
            growNode(width, height) {
                var canGrowDown = (width <= this.root.width);
                var canGrowRight = (height <= this.root.height);
                var shouldGrowRight = canGrowRight && (this.root.height >= (this.root.width + width)); // attempt to keep square-ish by growing right when height is much greater than width
                var shouldGrowDown = canGrowDown && (this.root.width >= (this.root.height + height)); // attempt to keep square-ish by growing down  when width  is much greater than height
                if (shouldGrowRight)
                    return this.growRight(width, height);
                else if (shouldGrowDown)
                    return this.growDown(width, height);
                else if (canGrowRight)
                    return this.growRight(width, height);
                else if (canGrowDown)
                    return this.growDown(width, height);
                else
                    return null; // need to ensure sensible root starting size to avoid this happening
            }
            growRight(width, height) {
                this.root = {
                    used: true,
                    x: 0,
                    y: 0,
                    width: this.root.width + width,
                    height: this.root.height,
                    down: this.root,
                    right: { x: this.root.width, y: 0, width: width, height: this.root.height }
                };
                var node;
                if (node = this.findNode(this.root, width, height))
                    return this.splitNode(node, width, height);
                else
                    return null;
            }
            growDown(width, height) {
                this.root = {
                    used: true,
                    x: 0,
                    y: 0,
                    width: this.root.width,
                    height: this.root.height + height,
                    down: { x: 0, y: this.root.height, width: this.root.width, height: height },
                    right: this.root
                };
                var node;
                if (node = this.findNode(this.root, width, height))
                    return this.splitNode(node, width, height);
                else
                    return null;
            }
        }
        return (items, options) => {
            options = options || {};
            var packer = new GrowingPacker();
            var inPlace = options.inPlace || false;
            var newItems = items.map(item => inPlace ? item : { width: item.width, height: item.height, item: item });
            newItems = newItems.toSorted((a, b) => (b.width * b.height) - (a.width * a.height));
            packer.fit(newItems);
            const ret = {
                width: newItems.reduce((curr, item) => Math.max(curr, item.x + item.width), 0),
                height: newItems.reduce((curr, item) => Math.max(curr, item.y + item.height), 0)
            };
            if (!inPlace) {
                ret.items = newItems;
            }
            return ret;
        };
    })();
    const algorithms = {
        'top-down': {
            sort: items => items.toSorted((a, b) => a.height - b.height),
            placeItems: items => {
                let y = 0;
                items.forEach(item => {
                    item.x = 0;
                    item.y = y;
                    y += item.height;
                });
                return items;
            }
        },
        'left-right': {
            sort: items => items.toSorted((a, b) => a.width - b.width),
            placeItems: items => {
                var x = 0;
                items.forEach(item => {
                    item.x = x;
                    item.y = 0;
                    x += item.width;
                });
                return items;
            }
        },
        diagonal: {
            sort: items => items.toSorted((a, b) => {
                const aDiag = Math.sqrt(Math.pow(a.height, 2) + Math.pow(a.width, 2));
                const bDiag = Math.sqrt(Math.pow(b.height, 2) + Math.pow(b.width, 2));
                return aDiag - bDiag;
            }),
            placeItems: items => {
                let x = 0;
                let y = 0;
                items.forEach(item => {
                    item.x = x;
                    item.y = y;
                    x += item.width;
                    y += item.height;
                });
            }
        },
        'alt-diagonal': {
            sort: items => items.toSorted((a, b) => {
                const aDiag = Math.sqrt(Math.pow(a.height, 2) + Math.pow(a.width, 2));
                const bDiag = Math.sqrt(Math.pow(b.height, 2) + Math.pow(b.width, 2));
                return aDiag - bDiag;
            }),
            placeItems: items => {
                let x = 0;
                let y = 0;
                items.forEach(item => {
                    item.x = x - item.width;
                    item.y = y;
                    x += item.width;
                    y += item.height;
                });
            }
        },
        'binary-tree': {
            sort: items => items,
            placeItems: items => {
                binpack(items, {inPlace: true});
                return items
            }
        }
    };
    class PackingSmith {
        constructor(algorithm, options) {
            this.items = [];
            this.algorithm = algorithm;
            options = options || {};
            var sort = options.sort !== undefined ? options.sort : true;
            this.sort = sort;
        }
        addItem(item) {
            this.items.push(item);
        }
        normalizeCoordinates() {
            var items = this.items;
            var minX = Infinity;
            var minY = Infinity;
            items.forEach(item => {
                var coords = item;
                minX = Math.min(minX, coords.x);
                minY = Math.min(minY, coords.y);
            });
            items.forEach(item => {
                var coords = item;
                coords.x -= minX;
                coords.y -= minY;
            });
        }
        getStats() {
            const { x, y } = this.items.reduce((acc, item) => {
                acc.x.min.push(item.x);
                acc.y.min.push(item.y);
                acc.x.max.push(item.x + item.width);
                acc.y.max.push(item.y + item.height);
                return acc;
            }, {
                x: { min: [], max: [] },
                y: { min: [], max: [] }
            });
            return {
                minX: Math.max(...x.min),
                maxX: Math.max(...x.max),
                maxY: Math.max(...y.max),
                minY: Math.max(...y.min)
            }
        }
        getItems() {
            return this.items;
        }
        processItems() {
            var items = this.items;
            if (this.sort) {
                items = this.algorithm.sort(items);
            }
            items = this.algorithm.placeItems(items);
            this.items = items;
            return items;
        }
        exportItems() {
            this.processItems();
            this.normalizeCoordinates();
            return this.items;
        }
        export() {
            var items = this.exportItems();
            var stats = this.getStats();
            var retObj = {
                'height': stats.maxY,
                'width': stats.maxX,
                'items': items
            };
            return retObj;
        }
    }
    function Layout(algorithmName, options) {
        var algorithm = algorithmName || 'top-down';
        if (typeof algorithm === 'string') {
            algorithm = algorithms[algorithmName];
        }
        var retSmith = new PackingSmith(algorithm, options);
        return retSmith;
    }
    Layout.PackingSmith = PackingSmith;
    function addAlgorithm(name, algorithm) {
        algorithms[name] = algorithm;
    }
    Layout.addAlgorithm = addAlgorithm;
    Layout.algorithms = algorithms;
    return Layout;
}));