User Tools

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
lxplan [2026/01/19 19:26] – removed sxh ssm2017lxplan [2026/01/27 12:47] (current) – [js version] ssm2017
Line 1914: Line 1914:
     app = XMLExtractorApp(root)     app = XMLExtractorApp(root)
     root.mainloop()     root.mainloop()
 +</code>
 +
 +==== js version ====
 +<code javascript>
 +<!DOCTYPE html>
 +<html lang="fr">
 +
 +<head>
 +    <meta charset="UTF-8">
 +    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 +    <title>Lxplan lib builder</title>
 +    <style>
 +        body {
 +            font-family: Arial, sans-serif;
 +            margin: 20px;
 +            line-height: 1.6;
 +        }
 +
 +        textarea {
 +            width: 100%;
 +            height: 200px;
 +            margin: 10px 0;
 +        }
 +
 +        button {
 +            padding: 8px 16px;
 +            background-color: #007BFF;
 +            color: white;
 +            border: none;
 +            border-radius: 4px;
 +            cursor: pointer;
 +        }
 +
 +        button:hover {
 +            background-color: #0056b3;
 +        }
 +
 +        .test-result>span {
 +            font-weight: bold;
 +            padding: 5px;
 +        }
 +
 +        .valid {
 +            color: white;
 +            background-color: green;
 +        }
 +
 +        .invalid {
 +            color: white;
 +            background-color: red;
 +        }
 +
 +        .no-answer {
 +            color: black;
 +            background-color: white;
 +        }
 +
 +        .container {
 +            border: 1px solid black;
 +            border-radius: 5px;
 +            margin: 5px;
 +            padding: 10px;
 +        }
 +    </style>
 +</head>
 +
 +<body>
 +    <h1>Lxplan lib builder</h1>
 +    <div class="container">
 +        <details>
 +            <summary>Cliquer içi pour lire la doc</summary>
 +            <p>Pour créer une librairie, il faut : <br />
 +            <ul>
 +                <li>Dessiner le symbole dans lxplan</li>
 +                <li>Le symbole doit etre sur le premier layer</li>
 +                <li>Une fois fini, le symbole doit etre dans un groupe</li>
 +                <li>Enregistrer le projet dans un fichier .lxxplot</li>
 +                <li>Utiliser ce script en important le fichier lxxplot puis en remplissant les champs obligatoires et
 +                    les autres si besoin</li>
 +                <li>Sauvegarder le fichier qui va donner un fichier .lxkey qui sera à mettre dans le dossier de la
 +                    bibliotheque (voir l'onglet "library" dans les options de lxplan)</li>
 +            </ul>
 +            </p>
 +        </details>
 +    </div>
 +    <div class="container">
 +        <h2>Charger le fichier lxxplot</h2>
 +        <p>Sélectionnez un fichier llxplot sur votre appareil :</p>
 +        <input type="file" id="fileInput" accept=".lxxplot" onclick="resetChecks()" />
 +    </div>
 +    <div class="container">
 +        <h2>Tester le fichier lxxplot</h2>
 +        <div>Le fichier est il un lxxplot ? : <span id="isLxxplot" class="test-result">...</span></div>
 +        <div>Le fichier possede t il une shape sur le premier layer ? :<span id="hasShape"
 +                class="test-result">...</span></div>
 +        <div>La shape, commence t elle par un groupe ? :<span id="hasGroup" class="test-result">...</span></div>
 +        <button onclick="loadFile()">Tester le fichier</button>
 +    </div>
 +    <div id="dataFields" class="container" hidden>
 +        <h2>Données de la librairie</h2>
 +        <div class="form-section">
 +            <div id="mandatoryFields">
 +                <h3>Champs obligatoires</h3>
 +                <div>
 +                    <label for="name">Type</label>
 +                    <input type="text" id="name" name="name" required />
 +                </div>
 +                <div>
 +                    <label for="fname">Full Name</label>
 +                    <input type="text" id="fname" name="fname" required />
 +                </div>
 +                <div>
 +                    <label for="id">Id</label>
 +                    <input type="text" id="id" name="id" required />
 +                </div>
 +                <div>
 +                    <label for="dataType">Type d'appareil</label>
 +                    <select id="dataType">
 +                        <option value="">Sélectionner un type d'appareil</option>
 +                    </select>
 +                </div>
 +            </div>
 +            <div id="optionalFields">
 +                <h3>Champs optionnels</h3>
 +                <details>
 +                    <summary>
 +                        Cliquer içi pour editer les champs optionnels
 +                    </summary>
 +                    <div id="dynamicFields">Selectionner d'abord un type d'appareil</div>
 +                </details>
 +            </div>
 +            <button id="saveButton" onclick="buildOutput()">Créer la librairie</button>
 +        </div>
 +    </div>
 +
 +    <script>
 +        // declaration des variables
 +        var xmlInputContent = "";
 +        var xmlOutputContent = "";
 +        var shape = "";
 +        var isLxxplot = false;
 +        var hasShape = false;
 +        var hasGroup = false;
 +        var filledOptionalFields = undefined;
 +        var filledFields = [];
 +        var isLxxplotDiv = document.getElementById("isLxxplot");
 +        var hasShapeDiv = document.getElementById("hasShape");
 +        var hasGroupDiv = document.getElementById("hasGroup");
 +        var dataFields = document.getElementById("dataFields");
 +        var dataTypeSelect = document.getElementById('dataType');
 +        var dynamicFields = document.getElementById('dynamicFields');
 +
 +        // Tableau des options de la liste de sélection
 +        const selectOptions = [
 +            { id: "ers", label: "ERS", fields: "sid;have;lamp;watts;frame;beam;cd;abm;wt;note;d_mk;d_adj_x;d_adj_y;d_adj_z" },
 +            { id: "zers", label: "Zoom Leko / ERS", fields: "sid;have;lamp;watts;frame;bm_w;bm_t;cd_w;cd_t;abm_w;abm_t;wt;note;d_mk;d_adj_x;d_adj_y;d_adj_z" },
 +            { id: "fres", label: "Fresnel / PC", fields: "sid;have;lamp;watts;frame;bm_w;bm_t;cd_w;cd_t;abm_w;abm_t;wt;note;d_mk;d_adj_x;d_adj_y;d_adj_z" },
 +            { id: "par", label: "PAR", fields: "sid;have;lamp;watts;frame;bm_x;bm_y;cd;abm_x;abm_y;wt;note;d_mk;d_adj_x;d_adj_y;d_adj_z" },
 +            { id: "fl", label: "Flood", fields: "sid;have;lamp;watts;frame;beam;cd;abm;wt;note;d_mk;d_adj_x;d_adj_y;d_adj_z" },
 +            { id: "strip", label: "Striplight", fields: "sid;have;lamp;watts;frame;bm_x;bm_y;cd;abm_x;abm_y;wt;cpf;lpc;dbl;note;d_mk;d_adj_x;d_adj_y;d_adj_z" },
 +            { id: "scroll", label: "DMX Device", fields: "sid;have;note;scroll;dmode;d_mk;acc_loc" },
 +            { id: "mirror", label: "Mirror", fields: "sid;have;note;scroll;dmode;d_mk;acc_loc" },
 +            { id: "focus", label: "Focus Point", fields: "sid" },
 +            { id: "misc", label: "Other", fields: "sid;have;acc_loc" },
 +            { id: "mover", label: "Automated Fixture", fields: "sid;have;lamp;watts;frame;bm_w;bm_t;cd_w;cd_t;abm_w;abm_t;wt;note;scroll;dmode;d_mk;d_adj_x;d_adj_y;d_adj_z" },
 +            { id: "cmymvr", label: "Color Mixing Automated Fixture", fields: "sid;have;lamp;watts;frame;bm_w;bm_t;cd_w;cd_t;abm_w;abm_t;wt;note;scroll;dmode;mixtype;d_mk;d_adj_x;d_adj_y;d_adj_z" },
 +            { id: "rgb", label: "Color Mixing Rectangular Beam (obsolete rgb)", fields: "sid;have;lamp;watts;frame;bm_x;bm_y;cd;abm_x;abm_y;wt;note;scroll;dmode;mixtype;d_adj_x;d_adj_y;d_adj_z" },
 +            { id: "rgba", label: "Color Mixing Rectangular Beam (obsolete rgba)", fields: "sid;have;lamp;watts;frame;bm_x;bm_y;cd;abm_x;abm_y;wt;note;scroll;dmode;mixtype;d_adj_x;d_adj_y;d_adj_z" },
 +            { id: "led7", label: "Color Mixing Rectangular Beam", fields: "sid;have;lamp;watts;frame;bm_x;bm_y;cd;abm_x;abm_y;wt;note;scroll;dmode;mixtype;d_adj_x;d_adj_y;d_adj_z" },
 +            { id: "led7s", label: "Color Mixing Striplight", fields: "sid;have;lamp;watts;frame;bm_x;bm_y;cd;abm_x;abm_y;wt;cpf;lpc;dbl;note;scroll;dmode;mixtype;d_adj_x;d_adj_y;d_adj_z" },
 +            { id: "cmers", label: "Color Mixing Leko / ERS", fields: "sid;have;lamp;watts;frame;beam;cd;abm;wt;note;scroll;dmode;mixtype;d_mk;d_adj_x;d_adj_y;d_adj_z" },
 +            { id: "cmzers", label: "Color Mixing Zoom ERS", fields: "sid;have;lamp;watts;frame;bm_w;bm_t;cd_w;cd_t;abm_w;abm_t;wt;note;scroll;dmode;mixtype;d_mk;d_adj_x;d_adj_y;d_adj_z" },
 +            { id: "cmscroll", label: "Color Mixing DMX Device", fields: "sid;have;note;scroll;dmode;mixtype;d_mk" },
 +            { id: "netnode", label: "Network Device", fields: "sid;have;note;dmode" },
 +        ];
 +
 +        // Tableau des champs disponibles
 +        const availableFields = [
 +            { id: "name", label: "Type", type: "text" },
 +            { id: "fname", label: "Full Name", type: "text" },
 +            { id: "id", label: "ID", type: "text" },
 +            { id: "sid", label: "Symbol ID", type: "text" },
 +            { id: "have", label: "Inventory", type: "number" },
 +            { id: "balance", label: "Balance", type: "number" },
 +            { id: "lamp", label: "Lamp", type: "text" },
 +            { id: "watts", label: "Watts", type: "number" },
 +            { id: "frame", label: "Color Frame", type: "text" },
 +            { id: "beam", label: "Field Angle", type: "number" },
 +            { id: "bm_x", label: "Field X", type: "number" },
 +            { id: "bm_y", label: "Field Y", type: "number" },
 +            { id: "bm_w", label: "Field Wide", type: "number" },
 +            { id: "bm_t", label: "Field Tight", type: "number" },
 +            { id: "cd", label: "Candela", type: "number" },
 +            { id: "cd_w", label: "Candela Wide", type: "number" },
 +            { id: "cd_t", label: "Candela Tight", type: "number" },
 +            { id: "abm", label: "Beam Angle", type: "number" },
 +            { id: "abm_x", label: "Beam X", type: "number" },
 +            { id: "abm_y", label: "Beam Y", type: "number" },
 +            { id: "abm_w", label: "Beam Wide", type: "number" },
 +            { id: "abm_t", label: "Beam Tight", type: "number" },
 +            { id: "wt", label: "Weight", type: "number" },
 +            { id: "cpf", label: "Sections Per Fixture", type: "number" },
 +            { id: "lpc", label: "Lamps Per Circuit", type: "number" },
 +            { id: "dbl", label: "Distance Between Lamps", type: "number" },
 +            { id: "note", label: "More Info", type: "text" },
 +            { id: "scroll", label: "Device Params", type: "text" },
 +            { id: "dmode", label: "Mode", type: "text" },
 +            { id: "mixtype", label: "Mix Type", type: "text" },
 +            { id: "d_mk", label: "Default Mark", type: "text" },
 +            { id: "acc_loc", label: "Placement", type: "text" },
 +            { id: "d_adj_x", label: "Default X Offset", type: "number" },
 +            { id: "d_adj_y", label: "Default Y Offset", type: "number" },
 +            { id: "d_adj_z", label: "Default Z Offset", type: "number" },
 +        ];
 +
 +        // reinitialise les resultats du test de fichier
 +        function resetChecks() {
 +            let content = '<span class="no-answer">Sans avis</span>';
 +            isLxxplotDiv.innerHTML = content;
 +            hasShapeDiv.innerHTML = content;
 +            hasGroupDiv.innerHTML = content;
 +            dataFields.hidden = true;
 +        }
 +
 +        // action quand le document est bien chargé
 +        document.addEventListener('DOMContentLoaded', () => {
 +            resetChecks();
 +            fillSelectOptions();
 +        });
 +
 +        // Remplit la liste déroulante de type d'appareil
 +        function fillSelectOptions() {
 +            dataTypeSelect.innerHTML = '<option value="">Sélectionner un type d\'appareil</option>';
 +            selectOptions.forEach((option) => {
 +                const optElement = document.createElement("option");
 +                optElement.value = option.id;
 +                optElement.textContent = option.label;
 +                dataTypeSelect.appendChild(optElement);
 +            });
 +        }
 +
 +        // ecoute si le type d'appareil est changé
 +        dataTypeSelect.addEventListener("change", () => {
 +            const selectedOptionId = dataTypeSelect.value;
 +            displayDynamicFields(selectedOptionId);
 +        });
 +
 +        // Affiche les champs optionnels en fonction du type d'appareil sélectionné
 +        function displayDynamicFields(selectedOptionId) {
 +            dynamicFields.innerHTML = "";// Efface les champs précédents
 +
 +            // Trouve l'option sélectionnée
 +            const selectedOption = selectOptions.find((option) => option.id === selectedOptionId);
 +
 +            if (!selectedOption || !selectedOption.fields) return;
 +
 +            // Récupère les IDs des champs à afficher
 +            const fieldIds = selectedOption.fields.split(";");
 +
 +            // Affiche chaque champ
 +            fieldIds.forEach((fieldId) => {
 +
 +                const field = availableFields.find((f) => f.id === fieldId);
 +
 +                if (field) {
 +                    const fieldDiv = document.createElement("div");
 +                    fieldDiv.innerHTML = `
 +        <label for="${field.id}">${field.label}:</label>
 +        <input type="${field.type}" id="${field.id}" name="${field.id}" />
 +      `;
 +                    dynamicFields.appendChild(fieldDiv);
 +                }
 +            });
 +        }
 +
 +        // charge le fichier lxxplot
 +        function loadFile() {
 +            const fileInput = document.getElementById('fileInput');
 +            const file = fileInput.files[0];
 +            if (!file) {
 +                alert("Veuillez sélectionner un fichier lxxplot.");
 +                return;
 +            }
 +
 +            const reader = new FileReader();
 +            reader.onload = function (e) {
 +                xmlInputContent = e.target.result;
 +                dataFields.hidden = !runChecks();
 +            };
 +            reader.readAsText(file);
 +        }
 +
 +        // verifie le contenu du fichier lxxplot
 +        function runChecks() {
 +            isLxxplot = checkIfValidPath("/lxplot", 'isLxxplot');
 +            hasShape = checkIfValidPath("/lxplot/layers/layer/shape", 'hasShape');
 +            if (hasShape) {
 +                getShape();
 +            }
 +            hasGroup = checkIfValidPath("/lxplot/layers/layer/shape/class[text() = 'LXGroup']", 'hasGroup');
 +            return (isLxxplot && hasShape && hasGroup);
 +        }
 +
 +        // petit utilitaire pour tester le contenu du fichier lxxplot
 +        function checkIfValidPath(xpathQuery, resultDiv) {
 +            resultDiv = document.getElementById(resultDiv);
 +            let status = parseXml(xpathQuery).status;
 +            resultDiv.innerHTML = status ? '<span class="valid">oui</span>' : '<span class="invalid">non</span>';
 +            return status;
 +        }
 +
 +        // petit utilitaire permettant de tester le xml du fichier lxxplot
 +        function parseXml(xpathQuery) {
 +            try {
 +                // Parser le XML
 +                const parser = new DOMParser();
 +                const xmlDoc = parser.parseFromString(xmlInputContent, "text/xml");
 +
 +                // Exécuter la requête XPath
 +                const xpathResult = document.evaluate(
 +                    xpathQuery,
 +                    xmlDoc,
 +                    null,
 +                    XPathResult.ANY_TYPE,
 +                    null
 +                );
 +
 +                let result = [];
 +                let node = xpathResult.iterateNext();
 +                while (node) {
 +                    result.push(node.textContent);
 +                    node = xpathResult.iterateNext();
 +                }
 +
 +                // Afficher le résultat
 +                if (result.length > 0) {
 +                    return { "status": true, "data": result };
 +                } else {
 +                    return { "status": false, "data": "Not found" };
 +                }
 +            } catch (e) {
 +                console.error("error parsing xml", e.message);
 +                return { "status": false, "data": "Error : " + e.message };
 +            }
 +        }
 +
 +        // reuperer la shape depuis le fichier lxxplot
 +        function getShape() {
 +            try {
 +                // Parser le XML
 +                const parser = new DOMParser();
 +                const xmlDoc = parser.parseFromString(xmlInputContent, "text/xml");
 +
 +                // Exécuter la requête XPath
 +                const xpathResult = document.evaluate(
 +                    "/lxplot/layers/layer/shape",
 +                    xmlDoc,
 +                    null,
 +                    XPathResult.FIRST_ORDERED_NODE_TYPE,
 +                    null
 +                );
 +
 +                shape = xpathResult.singleNodeValue;
 +            } catch (e) {
 +                console.error("error parsing xml", e.message);
 +                return { "status": false, "data": "Error : " + e.message };
 +            }
 +        }
 +
 +        // action quand on appuie sur le bouton "creer la librairie"
 +        function buildOutput() {
 +            if (checkFilledFields()) {
 +                buildXmlOutput();
 +            }
 +        }
 +
 +        // verifier que les champs soient bien remplis
 +        function checkFilledFields() {
 +            filledFields = [];
 +            getFilledChildren('mandatoryFields');
 +            if (Object.keys(filledFields).length < 3 || dataTypeSelect.value === '') {
 +                alert("Les 4 champs obligatoires doivent être remplis.");
 +                return false;
 +            }
 +            getFilledChildren('dynamicFields');
 +            return true;
 +        }
 +
 +        function getFilledChildren(id) {
 +            // recupere les champs
 +            const divElement = document.getElementById(id);
 +            const inputNodes = divElement.getElementsByTagName('input');
 +
 +            // teste les champs un par un
 +            for (let i = 0; i < inputNodes.length; i++) {
 +                if (inputNodes[i].value.trim() !== '') {
 +                    filledFields.push({ "id": inputNodes[i].id, "value": inputNodes[i].value });
 +                }
 +            }
 +        }
 +
 +        // fabrique le fichier de sortie et l'envoie a l'utilisateur
 +        function buildXmlOutput() {
 +            // creation du document xml
 +            const xmlDoc = new DOMParser().parseFromString('<key></key>', 'application/xml');
 +            const root = xmlDoc.documentElement;
 +
 +            // creation des elements basiques
 +            const kentryElement = xmlDoc.createElement('kentry');
 +            const customElement = xmlDoc.createElement("custom");
 +            const symbolElement = xmlDoc.createElement("symbol");
 +            const groupElement = xmlDoc.createElement("group");
 +            const kindElement = xmlDoc.createElement("kind");
 +            kindElement.textContent = dataTypeSelect.value;
 +
 +            // ajout des elements basiques dans l'arbre xml
 +            groupElement.appendChild(shape);
 +            symbolElement.appendChild(groupElement);
 +            customElement.appendChild(symbolElement);
 +            kentryElement.appendChild(kindElement);
 +
 +            // ajout de chaque champ rempli
 +            filledFields.forEach((item) => {
 +                const newItem = xmlDoc.createElement(item.id);
 +                newItem.textContent = item.value;
 +                kentryElement.appendChild(newItem);
 +            });
 +
 +            kentryElement.appendChild(customElement);
 +            root.appendChild(kentryElement);
 +
 +            // conversion en chaine de characteres
 +            const xmlString = "<?xml version='1.0' encoding='utf-8'?>\n" + new XMLSerializer().serializeToString(xmlDoc);
 +            console.log(xmlString);
 +
 +            // creation fichier
 +            const blob = new Blob([xmlString], { type: 'application/xml;charset=utf-8' });
 +            const url = URL.createObjectURL(blob);
 +
 +            // envoi du fichier
 +            const a = document.createElement('a');
 +            a.href = url;
 +            a.download = 'mylib.lxkey';
 +            a.click();
 +
 +            // nettoyage
 +            URL.revokeObjectURL(url);
 +        }
 +    </script>
 +</body>
 +
 +</html>
 </code> </code>

This website uses cookies. By using the website, you agree with storing cookies on your computer. Also, you acknowledge that you have read and understand our Privacy Policy. If you do not agree, please leave the website.

More information