path-data-parser-umd

UMD version of path-data-parser

Ce script ne doit pas être installé directement. C'est une librairie destinée à être incluse dans d'autres scripts avec la méta-directive // @require https://update.greasyfork.org/scripts/490146/1344867/path-data-parser-umd.js

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

(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;
}));