{"id":583,"date":"2025-07-19T22:14:17","date_gmt":"2025-07-20T01:14:17","guid":{"rendered":"https:\/\/futbol360.online\/futbol-360\/?page_id=583"},"modified":"2025-12-01T14:45:46","modified_gmt":"2025-12-01T17:45:46","slug":"planificador-de-partido","status":"publish","type":"page","link":"https:\/\/futbol360.online\/futbol-360\/planificador-de-partido\/","title":{"rendered":"Planificador de Partido"},"content":{"rendered":"\n<!DOCTYPE html>\n<html lang=\"es\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Visualizador de Formaci\u00f3n de Equipo<\/title>\n    <link href=\"https:\/\/fonts.googleapis.com\/css2?family=Inter:wght@400;600;700;800&#038;display=swap\" rel=\"stylesheet\">\n    <style>\n        body { font-family: 'Inter', sans-serif; margin: 0; padding: 20px; background-color: #f0f2f5; color: #333; display: flex; flex-direction: column; align-items: center; min-height: 100vh; box-sizing: border-box; }\n        .app-container { background-color: #ffffff; border-radius: 15px; box-shadow: 0 10px 25px rgba(0,0,0,0.15); padding: 30px; max-width: 1200px; width: 100%; display: flex; flex-wrap: wrap; gap: 30px; box-sizing: border-box; }\n        h1 { width: 100%; text-align: center; color: #1a202c; font-size: 1.8rem; margin-bottom: 20px; font-weight: 700; }\n        .field-container {\n            flex: 1.2;\n            min-width: 360px;\n            max-width: 720px;\n            background: repeating-linear-gradient(90deg, #3fa64a 0, #3fa64a 20px, #43b14e 20px, #43b14e 40px);\n            border: 4px solid rgba(255,255,255,0.85);\n            border-radius: 14px;\n            position: relative;\n            aspect-ratio: 105\/68; \/* m\u00e1s rectangular y arm\u00f3nico *\/\n            overflow: hidden;\n            box-shadow: inset 0 0 18px rgba(0,0,0,0.25);\n            padding: 10px;\n        }\n        \/* L\u00ednea media *\/\n.field-container::before {\n    content:\"\";\n    position:absolute;\n    left:50%;\n    top:0;\n    height:100%;\n    width:2px;\n    background:white;\n    transform:translateX(-50%);\n}\n\n\/* C\u00edrculo central perfecto *\/\n.field-container::after {\n    content:\"\";\n    position:absolute;\n    left:50%;\n    top:50%;\n    width:120px;\n    height:120px;\n    border:2px solid white;\n    border-radius:50%;\n    transform:translate(-50%, -50%);\n}\n        \/* L\u00ednea media *\/\n.field-container::before {\n    content:\"\";\n    position:absolute;\n    left:50%;\n    top:0;\n    height:100%;\n    width:2px;\n    background:white;\n    transform:translateX(-50%);\n}\n\n\/* C\u00edrculo central perfecto *\/\n.field-container::after {\n    content:\"\";\n    position:absolute;\n    left:50%;\n    top:50%;\n    width:120px;\n    height:120px;\n    border:2px solid white;\n    border-radius:50%;\n    transform:translate(-50%, -50%);\n}\n        \/* Solo arcos visibles *\/\n\/* Arcos mejorados *\/\n.goal-left, .goal-right {\n  position:absolute;\n  top:50%;\n  width:3.5%;\n  height:20%;\n  border:3px solid #ffffff;\n  border-radius:6px;\n  background:rgba(255,255,255,0.05);\n  box-shadow:0 0 8px rgba(0,0,0,0.3);\n  transform:translateY(-50%);\n  z-index:3;\n}\n.goal-left { left:0; }\n.goal-right { right:0; }\n        .goal-left { left:0; } .goal-right { right:0; }\n        .player-dot {\n  position: absolute;\n  width: 42px;\n  height: 42px;\n  background: url('https:\/\/upload.wikimedia.org\/wikipedia\/commons\/5\/5f\/Football_pictogram.svg') center\/contain no-repeat;\n  border-radius: 0;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: flex-end;\n  color: white;\n  font-weight:700;\n  font-size:0.7rem;\n  text-align:center;\n  text-shadow: 1px 1px 2px black;\n  cursor:help;\n  transition: transform 0.15s ease;\n  z-index:3;\n}\n.player-dot:hover { transform:scale(1.1); }\n.player-dot .jersey-number { font-size:0.9rem; font-weight:800; line-height:1; margin-bottom:0px; }\n.player-dot .player-name { font-size:0.55rem; max-width:90%; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }\n        .player-dot:hover { transform:scale(1.1); background:#6D28D9; }\n        .jersey-number { font-size:1.2rem; font-weight:800; line-height:1; margin-bottom:2px; }\n        .player-name { font-size:0.7rem; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:90%; }\n        .control-panel { flex:1; min-width:300px; background:#f8f8f8; border-radius:10px; padding:25px; box-shadow:0 5px 15px rgba(0,0,0,0.1); display:flex; flex-direction:column; gap:15px; box-sizing:border-box; }\n        .control-panel h2 { text-align:center; color:#1a202c; font-size:1.8rem; margin-bottom:20px; }\n        .player-input-group {\n            display: grid;\n            grid-template-columns: 36px 1fr 52px;\n            align-items: center;\n            gap: 8px;\n        }\n        .player-input-group label { font-weight:600; width:auto; text-align:right; padding-right:4px; }\n        .player-input-group input { padding:8px; border:1px solid #d0d6db; border-radius:6px; font-size:0.95rem; box-sizing:border-box; }\n        .player-input-group .height-input { width:52px; padding:7px; text-align:center; }\n        .buttons-group { display:flex; flex-wrap:wrap; gap:10px; margin-top:20px; justify-content:center; }\n        .action-button { padding:12px 25px; border:none; border-radius:8px; font-size:1rem; font-weight:600; cursor:pointer; transition:0.3s; }\n        .update { background:#4CAF50; color:white; } .update:hover { background:#388E3C; transform:translateY(-2px); }\n        .reset { background:#f44336; color:white; } .reset:hover { background:#d32f2f; transform:translateY(-2px); }\n        .capture { background:#007bff; color:white; } .capture:hover { background:#0056b3; transform:translateY(-2px); }\n        .save { background:#6c757d; color:white; } .save:hover { background:#545b62; transform:translateY(-2px); }\n        .load { background:#ffc107; color:#333; } .load:hover { background:#e0a800; transform:translateY(-2px); }\n        .substitutes-section { margin-top:20px; padding-top:20px; border-top:1px solid #eee; }\n        .substitutes-list { display:flex; flex-wrap:wrap; gap:10px; justify-content:center; }\n        .substitute-player { background:#607D8B; color:white; padding:8px 12px; border-radius:20px; font-size:0.9rem; font-weight:500; box-shadow:0 1px 3px rgba(0,0,0,0.2); white-space:nowrap; }\n    <\/style>\n<\/head>\n<body>\n    <div class=\"app-container\">\n        <h1>Visualizador de Formaci\u00f3n de Equipo<\/h1>\n\n<!-- Selector de Sistemas T\u00e1cticos -->\n<div style=\"width:100%; text-align:center; margin-bottom:15px;\">\n    <label for=\"tacticSelect\" style=\"font-weight:600; margin-right:8px;\">Sistema t\u00e1ctico:<\/label>\n    <select id=\"tacticSelect\" onchange=\"changeTactic()\" style=\"padding:8px; font-size:1rem; border-radius:6px;\">\n        <option value=\"433\">4-3-3<\/option>\n        <option value=\"442\">4-4-2<\/option>\n        <option value=\"4231\">4-2-3-1<\/option>\n        <option value=\"451\">4-5-1<\/option>\n        <option value=\"352\">3-5-2<\/option>\n        <option value=\"343\">3-4-3<\/option>\n        <option value=\"532\">5-3-2<\/option>\n        <option value=\"541\">5-4-1<\/option>\n        <option value=\"4141\">4-1-4-1<\/option>\n        <option value=\"4312\">4-3-1-2<\/option>\n    <\/select>\n<\/div>\n        <div class=\"field-container\" id=\"footballField\">\n    <div class=\"goal-left\"><\/div>\n    <div class=\"goal-right\"><\/div>\n<\/div>\n        <\/div>\n        \n        <\/div>\n\n        <div class=\"control-panel\">\n            <h2>Ingresar Jugadores (1-18)<\/h2>\n            <div id=\"playerInputList\"><\/div>\n            <div class=\"buttons-group\">\n                <button class=\"action-button update\" onclick=\"updateFormation()\">Actualizar Formaci\u00f3n<\/button>\n                <button class=\"action-button reset\" onclick=\"resetFormation()\">Reiniciar<\/button>\n                <button class=\"action-button capture\" onclick=\"captureFormation()\">Capturar<\/button>\n                <button class=\"action-button save\" onclick=\"saveFormation()\">Guardar<\/button>\n                <button class=\"action-button load\" onclick=\"loadFormation()\">Cargar<\/button>\n            <\/div>\n            <div id=\"capturedImageDisplay\" style=\"margin-top:20px; text-align:center;\"><\/div>\n\n            <div class=\"substitutes-section\">\n                <h3>Suplentes (12-18)<\/h3>\n                <div class=\"substitutes-list\" id=\"substitutesDisplay\"><\/div>\n            <\/div>\n        <\/div>\n    <\/div>\n\n    <script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/html2canvas\/1.4.1\/html2canvas.min.js\"><\/script>\n    <script>\n\/\/ --- HABILITAR ARRASTRE MANUAL DE LOS JUGADORES ---\nlet dragged = null;\nlet offsetX = 0;\nlet offsetY = 0;\n\nfunction makeDraggable(dot){\n    dot.style.cursor = 'grab';\n    dot.addEventListener('mousedown', e => {\n        dragged = dot;\n        offsetX = e.offsetX;\n        offsetY = e.offsetY;\n        dot.style.cursor = 'grabbing';\n    });\n}\n\ndocument.addEventListener('mousemove', e => {\n    if(dragged){\n        const rect = footballField.getBoundingClientRect();\n        let x = e.clientX - rect.left - offsetX;\n        let y = e.clientY - rect.top - offsetY;\n        dragged.style.left = (x \/ rect.width * 100) + '%';\n        dragged.style.top = (y \/ rect.height * 100) + '%';\n    }\n});\n\ndocument.addEventListener('mouseup', () => { \n    if(dragged) dragged.style.cursor = 'grab';\n    dragged = null; \n});\n\/\/ --- FIN ARRASTRE ---\n    <\/script>\n    <script>\n        const tactics = {\n    '433': {\n        '1':{left:'5%',top:'50%'}, '2':{left:'25%',top:'25%'}, '3':{left:'25%',top:'75%'},\n        '4':{left:'40%',top:'40%'}, '5':{left:'40%',top:'60%'}, '6':{left:'55%',top:'50%'},\n        '7':{left:'70%',top:'20%'}, '8':{left:'70%',top:'80%'}, '9':{left:'85%',top:'50%'},\n        '10':{left:'60%',top:'35%'}, '11':{left:'60%',top:'65%'}\n    },\n    '442': {\n        '1':{left:'5%',top:'50%'}, '2':{left:'25%',top:'20%'}, '3':{left:'25%',top:'80%'},\n        '4':{left:'45%',top:'35%'}, '5':{left:'45%',top:'65%'}, '6':{left:'55%',top:'50%'},\n        '7':{left:'65%',top:'20%'}, '8':{left:'65%',top:'80%'}, '9':{left:'85%',top:'40%'},\n        '10':{left:'85%',top:'60%'}, '11':{left:'75%',top:'50%'}\n    },\n    '4231': {\n        '1':{left:'5%',top:'50%'}, '2':{left:'22%',top:'25%'}, '3':{left:'22%',top:'75%'},\n        '4':{left:'40%',top:'35%'}, '5':{left:'40%',top:'65%'}, '6':{left:'52%',top:'50%'},\n        '7':{left:'68%',top:'20%'}, '8':{left:'68%',top:'80%'}, '9':{left:'75%',top:'50%'},\n        '10':{left:'60%',top:'50%'}, '11':{left:'85%',top:'50%'}\n    }\n};\n\nlet currentTactic = '433';\n\nfunction changeTactic(){\n    currentTactic = document.getElementById('tacticSelect').value;\n    document.querySelector('h1').innerText = 'Visualizador de Formaci\u00f3n de Equipo (' + document.getElementById('tacticSelect').selectedOptions[0].text + ')';\n    updateFormation();\n}\n\n\n        const footballField = document.getElementById('footballField');\n        const playerInputList = document.getElementById('playerInputList');\n        const substitutesDisplay = document.getElementById('substitutesDisplay');\n        const capturedImageDisplay = document.getElementById('capturedImageDisplay');\n\n        function generatePlayerInputs() {\n            for (let i = 1; i <= 18; i++) {\n                const div = document.createElement('div');\n                div.className = 'player-input-group';\n                div.innerHTML = `\n                    <label>#${i}<\/label>\n                    <input type=\"text\" id=\"player${i}\" placeholder=\"Jugador\">\n                    <input type=\"number\" class=\"height-input\" id=\"height${i}\" placeholder=\"Alt.\">\n                `;\n                playerInputList.appendChild(div);\n            }\n        }\n\n        function updateFormation() {\n            footballField.querySelectorAll('.player-dot').forEach(e => e.remove());\n            substitutesDisplay.innerHTML = '';\n\n            for (let i = 1; i <= 18; i++) {\n                const name = document.getElementById(`player${i}`).value.trim();\n                const height = document.getElementById(`height${i}`).value.trim();\n\n                if (i <= 11) {\n                    const pos = tactics[currentTactic] ? tactics[currentTactic][i] : null;\n                    if (pos) {\n                        const dot = document.createElement('div');\n                        dot.className = 'player-dot';\n                        dot.style.left = pos.left;\n                        dot.style.top = pos.top;\n                        dot.style.transform = 'translate(-50%, -50%)';\n\n                        dot.innerHTML = `\n                            <span class=\"jersey-number\">${i}<\/span>\n                            <span class=\"player-name\">${name || 'Vac\u00edo'}<\/span>\n                            <span style=\"font-size:0.6rem;\">${height ? height + ' cm' : ''}<\/span>\n                        `;\n\n                        footballField.appendChild(dot);\n                        makeDraggable(dot);\n                    }\n                } else if (name) {\n                    const sub = document.createElement('span');\n                    sub.className = 'substitute-player';\n                    sub.textContent = `#${i} ${name} (${height || '?'} cm)`;\n                    substitutesDisplay.appendChild(sub);\n                }\n            }\n        }\n\n        function captureFormation() {\n            const controls = document.querySelector('.buttons-group');\n            controls.style.display = 'none';\n            capturedImageDisplay.innerHTML = '<p>Generando...<\/p>';\n\n            html2canvas(footballField, { scale:2 }).then(canvas => {\n                controls.style.display = 'flex';\n                const data = canvas.toDataURL('image\/png');\n                const img = document.createElement('img');\n                img.src = data;\n                img.style.maxWidth = '100%';\n                capturedImageDisplay.innerHTML = '';\n                capturedImageDisplay.appendChild(img);\n            });\n        }\n\n        function saveFormation() {\n            const data = {};\n            for (let i = 1; i <= 18; i++) {\n                data[i] = document.getElementById(`player${i}`).value.trim();\n                data['h'+i] = document.getElementById(`height${i}`).value.trim();\n            }\n            localStorage.setItem('savedFormation', JSON.stringify(data));\n            alert('Guardado');\n        }\n\n        function loadFormation() {\n            const data = JSON.parse(localStorage.getItem('savedFormation') || '{}');\n            for (let i = 1; i <= 18; i++) {\n                document.getElementById(`player${i}`).value = data[i] || '';\n                document.getElementById(`height${i}`).value = data['h'+i] || '';\n            }\n            updateFormation();\n        }\n\n        function resetFormation() {\n            for (let i = 1; i <= 18; i++) {\n                document.getElementById(`player${i}`).value = '';\n                document.getElementById(`height${i}`).value = '';\n            }\n            updateFormation();\n            capturedImageDisplay.innerHTML = '';\n        }\n\n        document.addEventListener('DOMContentLoaded', () => {\n            generatePlayerInputs();\n            loadFormation();\n            updateFormation();\n        });\n    <\/script>\n<\/body>\n<\/html>\n\n","protected":false},"excerpt":{"rendered":"<p>Visualizador de Formaci\u00f3n de Equipo Visualizador de Formaci\u00f3n de Equipo Sistema t\u00e1ctico: 4-3-34-4-24-2-3-14-5-13-5-23-4-35-3-25-4-14-1-4-14-3-1-2 Ingresar Jugadores (1-18) Actualizar Formaci\u00f3n Reiniciar Capturar Guardar Cargar Suplentes (12-18)<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_acf_changed":false,"footnotes":""},"class_list":["post-583","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/futbol360.online\/futbol-360\/wp-json\/wp\/v2\/pages\/583","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/futbol360.online\/futbol-360\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/futbol360.online\/futbol-360\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/futbol360.online\/futbol-360\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/futbol360.online\/futbol-360\/wp-json\/wp\/v2\/comments?post=583"}],"version-history":[{"count":8,"href":"https:\/\/futbol360.online\/futbol-360\/wp-json\/wp\/v2\/pages\/583\/revisions"}],"predecessor-version":[{"id":2219,"href":"https:\/\/futbol360.online\/futbol-360\/wp-json\/wp\/v2\/pages\/583\/revisions\/2219"}],"wp:attachment":[{"href":"https:\/\/futbol360.online\/futbol-360\/wp-json\/wp\/v2\/media?parent=583"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}