path-data-parser-umd

UMD version of path-data-parser

Από την 18/03/2024. Δείτε την τελευταία έκδοση.

Αυτός ο κώδικας δεν πρέπει να εγκατασταθεί άμεσα. Είναι μια βιβλιοθήκη για άλλους κώδικες που περιλαμβάνεται μέσω της οδηγίας meta // @require https://update.greatest.deepsurf.us/scripts/490146/1344867/path-data-parser-umd.js

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey, το Greasemonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

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

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Userscripts για να εγκαταστήσετε αυτόν τον κώδικα.

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

Θα χρειαστεί να εγκαταστήσετε μια επέκταση διαχείρισης κώδικα χρήστη για να εγκαταστήσετε αυτόν τον κώδικα.

(Έχω ήδη έναν διαχειριστή κώδικα χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

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.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Έχω ήδη έναν διαχειριστή στυλ χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

(function (global, factory) {
    global = typeof globalThis !== 'undefined' ? globalThis : global || self;
    factory(global.pathDataParser = {});
})(this, (function (exports) { 'use strict';

    const COMMAND = 0;
    const NUMBER = 1;
    const EOD = 2;
    const PARAMS = {A: 7, a: 7, C: 6, c: 6, H: 1, h: 1, L: 2, l: 2, M: 2, m: 2, Q: 4, q: 4, S: 4, s: 4, T: 2, t: 2, V: 1, v: 1, Z: 0, z: 0};
    function tokenize(d) {
        const tokens = new Array();
        while (d !== "") {
            if (d.match(/^([ \t\r\n,]+)/)) {
                d = d.substr(RegExp.$1.length);
            } else if (d.match(/^([aAcChHlLmMqQsStTvVzZ])/)) {
                tokens[tokens.length] = {type: COMMAND, text: RegExp.$1};
                d = d.substr(RegExp.$1.length);
            } else if (d.match(/^(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)/)) {
                tokens[tokens.length] = {type: NUMBER, text: `${parseFloat(RegExp.$1)}`};
                d = d.substr(RegExp.$1.length);
            } else {
                return [];
            }
        }
        tokens[tokens.length] = {type: EOD, text: ""};
        return tokens;
    }
    function isType(token, type) {
        return token.type === type;
    }
    function parsePath(d) {
        const segments = [];
        const tokens = tokenize(d);
        let mode = "BOD";
        let index = 0;
        let token = tokens[index];
        while (!isType(token, EOD)) {
            let paramsCount = 0;
            const params = [];
            if (mode === "BOD") {
                if (token.text === "M" || token.text === "m") {
                    index++;
                    paramsCount = PARAMS[token.text];
                    mode = token.text;
                } else {
                    return parsePath("M0,0" + d);
                }
            } else if (isType(token, NUMBER)) {
                paramsCount = PARAMS[mode];
            } else {
                index++;
                paramsCount = PARAMS[token.text];
                mode = token.text;
            }
            if (index + paramsCount < tokens.length) {
                for (let i = index; i < index + paramsCount; i++) {
                    const numbeToken = tokens[i];
                    if (isType(numbeToken, NUMBER)) {
                        params[params.length] = +numbeToken.text;
                    } else {
                        throw new Error("Param not a number: " + mode + "," + numbeToken.text);
                    }
                }
                if (typeof PARAMS[mode] === "number") {
                    const segment = {key: mode, data: params};
                    segments.push(segment);
                    index += paramsCount;
                    token = tokens[index];
                    if (mode === "M")
                        mode = "L";
                    if (mode === "m")
                        mode = "l";
                } else {
                    throw new Error("Bad segment: " + mode);
                }
            } else {
                throw new Error("Path data ended short");
            }
        }
        return segments;
    }
    function serialize(segments) {
        const tokens = [];
        for (const {key, data} of segments) {
            tokens.push(key);
            switch (key) {
                case "C":
                case "c":
                    tokens.push(data[0], `${data[1]},`, data[2], `${data[3]},`, data[4], data[5]);
                    break;
                case "S":
                case "s":
                case "Q":
                case "q":
                    tokens.push(data[0], `${data[1]},`, data[2], data[3]);
                    break;
                default:
                    tokens.push(...data);
                    break;
            }
        }
        return tokens.join(" ");
    }
    function absolutize(segments) {
        let cx = 0, cy = 0;
        let subx = 0, suby = 0;
        const out = [];
        for (const {key, data} of segments) {
            switch (key) {
                case "M":
                    out.push({key: "M", data: [...data]});
                    [cx, cy] = data;
                    [subx, suby] = data;
                    break;
                case "m":
                    cx += data[0];
                    cy += data[1];
                    out.push({key: "M", data: [cx, cy]});
                    subx = cx;
                    suby = cy;
                    break;
                case "L":
                    out.push({key: "L", data: [...data]});
                    [cx, cy] = data;
                    break;
                case "l":
                    cx += data[0];
                    cy += data[1];
                    out.push({key: "L", data: [cx, cy]});
                    break;
                case "C":
                    out.push({key: "C", data: [...data]});
                    cx = data[4];
                    cy = data[5];
                    break;
                case "c": {
                    const newdata = data.map((d, i) => i % 2 ? d + cy : d + cx);
                    out.push({key: "C", data: newdata});
                    cx = newdata[4];
                    cy = newdata[5];
                    break;
                }
                case "Q":
                    out.push({key: "Q", data: [...data]});
                    cx = data[2];
                    cy = data[3];
                    break;
                case "q": {
                    const newdata = data.map((d, i) => i % 2 ? d + cy : d + cx);
                    out.push({key: "Q", data: newdata});
                    cx = newdata[2];
                    cy = newdata[3];
                    break;
                }
                case "A":
                    out.push({key: "A", data: [...data]});
                    cx = data[5];
                    cy = data[6];
                    break;
                case "a":
                    cx += data[5];
                    cy += data[6];
                    out.push({key: "A", data: [data[0], data[1], data[2], data[3], data[4], cx, cy]});
                    break;
                case "H":
                    out.push({key: "H", data: [...data]});
                    cx = data[0];
                    break;
                case "h":
                    cx += data[0];
                    out.push({key: "H", data: [cx]});
                    break;
                case "V":
                    out.push({key: "V", data: [...data]});
                    cy = data[0];
                    break;
                case "v":
                    cy += data[0];
                    out.push({key: "V", data: [cy]});
                    break;
                case "S":
                    out.push({key: "S", data: [...data]});
                    cx = data[2];
                    cy = data[3];
                    break;
                case "s": {
                    const newdata = data.map((d, i) => i % 2 ? d + cy : d + cx);
                    out.push({key: "S", data: newdata});
                    cx = newdata[2];
                    cy = newdata[3];
                    break;
                }
                case "T":
                    out.push({key: "T", data: [...data]});
                    cx = data[0];
                    cy = data[1];
                    break;
                case "t":
                    cx += data[0];
                    cy += data[1];
                    out.push({key: "T", data: [cx, cy]});
                    break;
                case "Z":
                case "z":
                    out.push({key: "Z", data: []});
                    cx = subx;
                    cy = suby;
                    break;
            }
        }
        return out;
    }
    function normalize(segments) {
        const out = [];
        let lastType = "";
        let cx = 0, cy = 0;
        let subx = 0, suby = 0;
        let lcx = 0, lcy = 0;
        for (const {key, data} of segments) {
            switch (key) {
                case "M":
                    out.push({key: "M", data: [...data]});
                    [cx, cy] = data;
                    [subx, suby] = data;
                    break;
                case "C":
                    out.push({key: "C", data: [...data]});
                    cx = data[4];
                    cy = data[5];
                    lcx = data[2];
                    lcy = data[3];
                    break;
                case "L":
                    out.push({key: "L", data: [...data]});
                    [cx, cy] = data;
                    break;
                case "H":
                    cx = data[0];
                    out.push({key: "L", data: [cx, cy]});
                    break;
                case "V":
                    cy = data[0];
                    out.push({key: "L", data: [cx, cy]});
                    break;
                case "S": {
                    let cx1 = 0, cy1 = 0;
                    if (lastType === "C" || lastType === "S") {
                        cx1 = cx + (cx - lcx);
                        cy1 = cy + (cy - lcy);
                    } else {
                        cx1 = cx;
                        cy1 = cy;
                    }
                    out.push({key: "C", data: [cx1, cy1, ...data]});
                    lcx = data[0];
                    lcy = data[1];
                    cx = data[2];
                    cy = data[3];
                    break;
                }
                case "T": {
                    const [x, y] = data;
                    let x1 = 0, y1 = 0;
                    if (lastType === "Q" || lastType === "T") {
                        x1 = cx + (cx - lcx);
                        y1 = cy + (cy - lcy);
                    } else {
                        x1 = cx;
                        y1 = cy;
                    }
                    const cx1 = cx + 2 * (x1 - cx) / 3;
                    const cy1 = cy + 2 * (y1 - cy) / 3;
                    const cx2 = x + 2 * (x1 - x) / 3;
                    const cy2 = y + 2 * (y1 - y) / 3;
                    out.push({key: "C", data: [cx1, cy1, cx2, cy2, x, y]});
                    lcx = x1;
                    lcy = y1;
                    cx = x;
                    cy = y;
                    break;
                }
                case "Q": {
                    const [x1, y1, x, y] = data;
                    const cx1 = cx + 2 * (x1 - cx) / 3;
                    const cy1 = cy + 2 * (y1 - cy) / 3;
                    const cx2 = x + 2 * (x1 - x) / 3;
                    const cy2 = y + 2 * (y1 - y) / 3;
                    out.push({key: "C", data: [cx1, cy1, cx2, cy2, x, y]});
                    lcx = x1;
                    lcy = y1;
                    cx = x;
                    cy = y;
                    break;
                }
                case "A": {
                    const r1 = Math.abs(data[0]);
                    const r2 = Math.abs(data[1]);
                    const angle = data[2];
                    const largeArcFlag = data[3];
                    const sweepFlag = data[4];
                    const x = data[5];
                    const y = data[6];
                    if (r1 === 0 || r2 === 0) {
                        out.push({key: "C", data: [cx, cy, x, y, x, y]});
                        cx = x;
                        cy = y;
                    } else {
                        if (cx !== x || cy !== y) {
                            const curves = arcToCubicCurves(cx, cy, x, y, r1, r2, angle, largeArcFlag, sweepFlag);
                            curves.forEach(function(curve) {
                                out.push({key: "C", data: curve});
                            });
                            cx = x;
                            cy = y;
                        }
                    }
                    break;
                }
                case "Z":
                    out.push({key: "Z", data: []});
                    cx = subx;
                    cy = suby;
                    break;
            }
            lastType = key;
        }
        return out;
    }
    function degToRad(degrees) {
        return Math.PI * degrees / 180;
    }
    function rotate(x, y, angleRad) {
        const X = x * Math.cos(angleRad) - y * Math.sin(angleRad);
        const Y = x * Math.sin(angleRad) + y * Math.cos(angleRad);
        return [X, Y];
    }
    function arcToCubicCurves(x1, y1, x2, y2, r1, r2, angle, largeArcFlag, sweepFlag, recursive) {
        const angleRad = degToRad(angle);
        let params = [];
        let f1 = 0, f2 = 0, cx = 0, cy = 0;
        if (recursive) {
            [f1, f2, cx, cy] = recursive;
        } else {
            [x1, y1] = rotate(x1, y1, -angleRad);
            [x2, y2] = rotate(x2, y2, -angleRad);
            const x = (x1 - x2) / 2;
            const y = (y1 - y2) / 2;
            let h = x * x / (r1 * r1) + y * y / (r2 * r2);
            if (h > 1) {
                h = Math.sqrt(h);
                r1 = h * r1;
                r2 = h * r2;
            }
            const sign = largeArcFlag === sweepFlag ? -1 : 1;
            const r1Pow = r1 * r1;
            const r2Pow = r2 * r2;
            const left = r1Pow * r2Pow - r1Pow * y * y - r2Pow * x * x;
            const right = r1Pow * y * y + r2Pow * x * x;
            const k = sign * Math.sqrt(Math.abs(left / right));
            cx = k * r1 * y / r2 + (x1 + x2) / 2;
            cy = k * -r2 * x / r1 + (y1 + y2) / 2;
            f1 = Math.asin(parseFloat(((y1 - cy) / r2).toFixed(9)));
            f2 = Math.asin(parseFloat(((y2 - cy) / r2).toFixed(9)));
            if (x1 < cx) {
                f1 = Math.PI - f1;
            }
            if (x2 < cx) {
                f2 = Math.PI - f2;
            }
            if (f1 < 0) {
                f1 = Math.PI * 2 + f1;
            }
            if (f2 < 0) {
                f2 = Math.PI * 2 + f2;
            }
            if (sweepFlag && f1 > f2) {
                f1 = f1 - Math.PI * 2;
            }
            if (!sweepFlag && f2 > f1) {
                f2 = f2 - Math.PI * 2;
            }
        }
        let df = f2 - f1;
        if (Math.abs(df) > Math.PI * 120 / 180) {
            const f2old = f2;
            const x2old = x2;
            const y2old = y2;
            if (sweepFlag && f2 > f1) {
                f2 = f1 + Math.PI * 120 / 180 * 1;
            } else {
                f2 = f1 + Math.PI * 120 / 180 * -1;
            }
            x2 = cx + r1 * Math.cos(f2);
            y2 = cy + r2 * Math.sin(f2);
            params = arcToCubicCurves(x2, y2, x2old, y2old, r1, r2, angle, 0, sweepFlag, [f2, f2old, cx, cy]);
        }
        df = f2 - f1;
        const c1 = Math.cos(f1);
        const s1 = Math.sin(f1);
        const c2 = Math.cos(f2);
        const s2 = Math.sin(f2);
        const t = Math.tan(df / 4);
        const hx = 4 / 3 * r1 * t;
        const hy = 4 / 3 * r2 * t;
        const m1 = [x1, y1];
        const m2 = [x1 + hx * s1, y1 - hy * c1];
        const m3 = [x2 + hx * s2, y2 - hy * c2];
        const m4 = [x2, y2];
        m2[0] = 2 * m1[0] - m2[0];
        m2[1] = 2 * m1[1] - m2[1];
        if (recursive) {
            return [m2, m3, m4].concat(params);
        } else {
            params = [m2, m3, m4].concat(params);
            const curves = [];
            for (let i = 0; i < params.length; i += 3) {
                const r12 = rotate(params[i][0], params[i][1], angleRad);
                const r22 = rotate(params[i + 1][0], params[i + 1][1], angleRad);
                const r3 = rotate(params[i + 2][0], params[i + 2][1], angleRad);
                curves.push([r12[0], r12[1], r22[0], r22[1], r3[0], r3[1]]);
            }
            return curves;
        }
    }
    exports.absolutize = absolutize;
    exports.normalize = normalize;
    exports.parsePath = parsePath;
    exports.serialize = serialize;
}));