{"id":2642,"date":"2025-12-17T23:27:10","date_gmt":"2025-12-18T02:27:10","guid":{"rendered":"https:\/\/futbol360.online\/futbol-360\/?page_id=2642"},"modified":"2025-12-18T16:30:33","modified_gmt":"2025-12-18T19:30:33","slug":"metropolitan-f2","status":"publish","type":"page","link":"https:\/\/futbol360.online\/futbol-360\/metropolitan-f2\/","title":{"rendered":"Metropolitan F2"},"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 &#8211; F\u00fatbol 360<\/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        \n        .field-container {\n            flex: 1.2; min-width: 360px; max-width: 720px; background: #43b14e;\n            background-image: repeating-linear-gradient(90deg, #3fa64a 0, #3fa64a 20px, #43b14e 20px, #43b14e 40px);\n            border: 4px solid rgba(255,255,255,0.85); border-radius: 14px; position: relative;\n            aspect-ratio: 105\/68; overflow: hidden; box-shadow: inset 0 0 18px rgba(0,0,0,0.25); padding: 0;\n        }\n\n        .field-container::before { content:\"\"; position:absolute; left:50%; top:0; height:100%; width:2px; background:white; transform:translateX(-50%); z-index: 1; }\n        .field-container::after { content:\"\"; position:absolute; left:50%; top:50%; width:120px; height:120px; border:2px solid white; border-radius:50%; transform:translate(-50%, -50%); z-index: 1; }\n\n        .goal-left, .goal-right {\n            position:absolute; top:50%; width:3.5%; height:20%; border:3px solid #ffffff; border-radius:6px;\n            background:rgba(255,255,255,0.1); transform:translateY(-50%); z-index:1;\n        }\n        .goal-left { left:0; border-left:none; }\n        .goal-right { right:0; border-right:none; }\n\n        .player-dot {\n            position: absolute; width: 44px; height: 44px; background: #1e3a56; border: 2px solid white;\n            border-radius: 50%; display: flex; flex-direction: column; align-items: center; justify-content: center;\n            color: white; cursor: grab; transition: transform 0.15s ease, background 0.3s; z-index: 10;\n            box-shadow: 0 4px 6px rgba(0,0,0,0.3);\n        }\n        .player-dot:active { cursor: grabbing; }\n        .player-dot:hover { transform: scale(1.1); background: #2c5282; }\n        \n        .jersey-number { font-size: 0.9rem; font-weight: 800; line-height: 1; }\n        .player-name { \n            position: absolute; bottom: -20px; font-size: 0.65rem; font-weight: 700;\n            background: rgba(0,0,0,0.7); padding: 1px 5px; border-radius: 4px;\n            white-space: nowrap; text-shadow: none;\n        }\n\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; }\n        .player-input-group { display: grid; grid-template-columns: 36px 1fr 52px; align-items: center; gap: 8px; }\n        .player-input-group input { padding:8px; border:1px solid #d0d6db; border-radius:6px; font-size:0.9rem; }\n        .height-input { text-align:center; }\n\n        .buttons-group { display:flex; flex-wrap:wrap; gap:10px; margin-top:20px; justify-content:center; }\n        .action-button { padding:10px 18px; border:none; border-radius:8px; font-size:0.9rem; font-weight:600; cursor:pointer; transition:0.3s; color:white; }\n        .update { background:#4CAF50; } .reset { background:#f44336; }\n        .capture { background:#007bff; } .save { background:#6c757d; } .load { background:#ffc107; color:#333; }\n        .download { background:#28a745; margin-top: 10px; width: 100%; }\n        \n        .substitutes-section { margin-top:20px; padding-top:20px; border-top:1px solid #eee; }\n        .substitutes-list { display:flex; flex-wrap:wrap; gap:8px; justify-content:center; }\n        .substitute-player { background:#607D8B; color:white; padding:5px 12px; border-radius:15px; font-size:0.85rem; font-weight:500; }\n    <\/style>\n<\/head>\n<body>\n    <div class=\"app-container\">\n        <h1>Visualizador de Formaci\u00f3n de Equipo<\/h1>\n\n        <div style=\"width:100%; text-align:center; margin-bottom:15px;\">\n            <label 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\n        <div class=\"field-container\" id=\"footballField\">\n            <div class=\"goal-left\"><\/div>\n            <div class=\"goal-right\"><\/div>\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<\/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    \n    <script>\n\nconst partidoID = \"fecha_2\";\n        const tactics = {\n            '433': {'1':{l:'5%',t:'50%'},'4':{l:'28%',t:'20%'},'2':{l:'22%',t:'40%'},'6':{l:'22%',t:'60%'},'3':{l:'28%',t:'80%'},'5':{l:'45%',t:'50%'},'8':{l:'62%',t:'35%'},'10':{l:'62%',t:'65%'},'7':{l:'80%',t:'18%'},'11':{l:'80%',t:'82%'},'9':{l:'88%',t:'50%'}},\n            '442': {'1':{l:'5%',t:'50%'},'4':{l:'28%',t:'15%'},'2':{l:'22%',t:'38%'},'6':{l:'22%',t:'62%'},'3':{l:'28%',t:'85%'},'8':{l:'55%',t:'30%'},'5':{l:'55%',t:'45%'},'10':{l:'55%',t:'55%'},'11':{l:'55%',t:'70%'},'7':{l:'80%',t:'35%'},'9':{l:'80%',t:'65%'}},\n            '4231': {'1':{l:'5%',t:'50%'},'4':{l:'28%',t:'20%'},'2':{l:'22%',t:'38%'},'6':{l:'22%',t:'62%'},'3':{l:'28%',t:'80%'},'5':{l:'45%',t:'40%'},'8':{l:'45%',t:'60%'},'10':{l:'65%',t:'50%'},'7':{l:'78%',t:'18%'},'11':{l:'78%',t:'82%'},'9':{l:'88%',t:'50%'}},\n            '451': {'1':{l:'5%',t:'50%'},'4':{l:'28%',t:'15%'},'2':{l:'22%',t:'38%'},'6':{l:'22%',t:'62%'},'3':{l:'28%',t:'85%'},'5':{l:'45%',t:'50%'},'8':{l:'60%',t:'35%'},'10':{l:'60%',t:'65%'},'7':{l:'70%',t:'20%'},'11':{l:'70%',t:'80%'},'9':{l:'88%',t:'50%'}},\n            '352': {'1':{l:'5%',t:'50%'},'2':{l:'22%',t:'35%'},'5':{l:'18%',t:'50%'},'6':{l:'22%',t:'65%'},'4':{l:'45%',t:'15%'},'8':{l:'55%',t:'38%'},'10':{l:'55%',t:'62%'},'3':{l:'45%',t:'85%'},'7':{l:'70%',t:'50%'},'9':{l:'85%',t:'40%'},'11':{l:'85%',t:'60%'}},\n            '343': {'1':{l:'5%',t:'50%'},'2':{l:'22%',t:'35%'},'5':{l:'18%',t:'50%'},'6':{l:'22%',t:'65%'},'4':{l:'48%',t:'15%'},'8':{l:'50%',t:'40%'},'10':{l:'50%',t:'60%'},'3':{l:'48%',t:'85%'},'7':{l:'78%',t:'20%'},'11':{l:'78%',t:'80%'},'9':{l:'88%',t:'50%'}},\n            '532': {'1':{l:'5%',t:'50%'},'4':{l:'30%',t:'15%'},'2':{l:'22%',t:'35%'},'5':{l:'18%',t:'50%'},'6':{l:'22%',t:'65%'},'3':{l:'30%',t:'85%'},'8':{l:'55%',t:'35%'},'10':{l:'55%',t:'65%'},'7':{l:'52%',t:'50%'},'9':{l:'85%',t:'40%'},'11':{l:'85%',t:'60%'}},\n            '541': {'1':{l:'5%',t:'50%'},'4':{l:'30%',t:'15%'},'2':{l:'22%',t:'35%'},'5':{l:'18%',t:'50%'},'6':{l:'22%',t:'65%'},'3':{l:'30%',t:'85%'},'8':{l:'55%',t:'25%'},'7':{l:'55%',t:'42%'},'10':{l:'55%',t:'58%'},'11':{l:'55%',t:'75%'},'9':{l:'85%',t:'50%'}},\n            '4141': {'1':{l:'5%',t:'50%'},'4':{l:'28%',t:'15%'},'2':{l:'22%',t:'38%'},'6':{l:'22%',t:'62%'},'3':{l:'28%',t:'85%'},'5':{l:'42%',t:'50%'},'8':{l:'62%',t:'38%'},'10':{l:'62%',t:'62%'},'7':{l:'75%',t:'18%'},'11':{l:'75%',t:'82%'},'9':{l:'88%',t:'50%'}},\n            '4312': {'1':{l:'5%',t:'50%'},'4':{l:'28%',t:'20%'},'2':{l:'22%',t:'40%'},'6':{l:'22%',t:'60%'},'3':{l:'28%',t:'80%'},'5':{l:'45%',t:'50%'},'8':{l:'58%',t:'32%'},'10':{l:'58%',t:'68%'},'7':{l:'72%',t:'50%'},'9':{l:'85%',t:'40%'},'11':{l:'85%',t:'60%'}}\n        };\n\n        let currentTactic = '433';\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        let dragged = null;\n        let offsetX = 0, offsetY = 0;\n\n       function makeDraggable(dot) {\n            \/\/ Soporte para Mouse\n            dot.addEventListener('mousedown', startDragging);\n            \/\/ Soporte para Touch (M\u00f3vil)\n            dot.addEventListener('touchstart', startDragging, { passive: false });\n\n            function startDragging(e) {\n                dragged = dot;\n                const rect = dot.getBoundingClientRect();\n                const clientX = e.type.includes('touch') ? e.touches[0].clientX : e.clientX;\n                const clientY = e.type.includes('touch') ? e.touches[0].clientY : e.clientY;\n                \n                offsetX = clientX - rect.left - rect.width \/ 2;\n                offsetY = clientY - rect.top - rect.height \/ 2;\n                \n                \/\/ Evita que el celular haga scroll mientras mueves al jugador\n                if (e.type === 'touchstart') e.preventDefault();\n            }\n        }\n\n        \/\/ Movimiento (Mouse y Touch)\n        const moveHandler = e => {\n            if (dragged) {\n                \/\/ Evita el scroll en m\u00f3viles\n                if (e.type === 'touchmove') e.preventDefault();\n\n                const rect = footballField.getBoundingClientRect();\n                const clientX = e.type.includes('touch') ? e.touches[0].clientX : e.clientX;\n                const clientY = e.type.includes('touch') ? e.touches[0].clientY : e.clientY;\n                \n                let x = clientX - rect.left;\n                let y = clientY - rect.top;\n\n                \/\/ L\u00edmites para que no se salgan del campo\n                let posX = (x \/ rect.width * 100);\n                let posY = (y \/ rect.height * 100);\n\n                dragged.style.left = Math.max(0, Math.min(100, posX)) + '%';\n                dragged.style.top = Math.max(0, Math.min(100, posY)) + '%';\n            }\n        };\n\n        document.addEventListener('mousemove', moveHandler);\n        document.addEventListener('touchmove', moveHandler, { passive: false });\n\n        \/\/ Soltar (Mouse y Touch)\n        const endHandler = () => { dragged = null; };\n        document.addEventListener('mouseup', endHandler);\n        document.addEventListener('touchend', endHandler);\n\n        document.addEventListener('mouseup', () => { dragged = null; });\n\n        function generatePlayerInputs() {\n            playerInputList.innerHTML = '';\n            for (let i = 1; i <= 18; i++) {\n                const div = document.createElement('div');\n                div.className = 'player-input-group';\n                div.innerHTML = `<label>#${i}<\/label>\n                    <input type=\"text\" id=\"player${i}\" placeholder=\"Nombre\">\n                    <input type=\"number\" class=\"height-input\" id=\"height${i}\" placeholder=\"cm\">`;\n                playerInputList.appendChild(div);\n            }\n        }\n\n        function changeTactic() {\n            currentTactic = document.getElementById('tacticSelect').value;\n            updateFormation();\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][i];\n                    const dot = document.createElement('div');\n                    dot.className = 'player-dot';\n                    dot.style.left = pos.l;\n                    dot.style.top = pos.t;\n                    dot.style.transform = 'translate(-50%, -50%)';\n                    dot.innerHTML = `<span class=\"jersey-number\">${i}<\/span>\n                                     <span class=\"player-name\">${name || '---'}<\/span>\n                                     <span style=\"font-size:0.5rem; opacity:0.8\">${height ? height+'cm' : ''}<\/span>`;\n                    footballField.appendChild(dot);\n                    makeDraggable(dot);\n                } else if (name) {\n                    const sub = document.createElement('span');\n                    sub.className = 'substitute-player';\n                    sub.textContent = `#${i} ${name} ${height ? '('+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>Procesando imagen t\u00e1ctica...<\/p>';\n\n            html2canvas(footballField, {\n                scale: 2,\n                useCORS: true,\n                backgroundColor: '#43b14e',\n                logging: false\n            }).then(canvas => {\n                controls.style.display = 'flex';\n                const imgData = canvas.toDataURL('image\/png');\n                \n                \/\/ Mostrar vista previa\n                const img = document.createElement('img');\n                img.src = imgData;\n                img.style.maxWidth = '100%';\n                img.style.borderRadius = '8px';\n                img.style.boxShadow = '0 4px 10px rgba(0,0,0,0.2)';\n                \n                \/\/ Crear bot\u00f3n de descarga\n                const downloadBtn = document.createElement('button');\n                downloadBtn.className = 'action-button download';\n                downloadBtn.innerText = '\u2b07 Descargar Imagen';\n                downloadBtn.onclick = () => {\n                    const link = document.createElement('a');\n                    link.download = 'formacion-equipo.png';\n                    link.href = imgData;\n                    link.click();\n                };\n\n                capturedImageDisplay.innerHTML = '<h4>Imagen capturada:<\/h4>';\n                capturedImageDisplay.appendChild(img);\n                capturedImageDisplay.appendChild(downloadBtn);\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;\n                data['h'+i] = document.getElementById(`height${i}`).value;\n            }\n            \/\/ AQU\u00cd EL CAMBIO: Usamos partidoID para que la clave sea \u00fanica (ej: \"savedFormation_fecha_2\")\n            localStorage.setItem('savedFormation_' + partidoID, JSON.stringify(data));\n            alert('Formaci\u00f3n de ' + partidoID + ' guardada con \u00e9xito.');\n        }\n\n        function loadFormation() {\n            \/\/ AQU\u00cd EL CAMBIO: Leemos espec\u00edficamente la clave de este partido\n            const data = JSON.parse(localStorage.getItem('savedFormation_' + partidoID) || '{}');\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            if(confirm(\"\u00bfReiniciar toda la formaci\u00f3n de \" + partidoID + \"?\")){\n                for (let i = 1; i <= 18; i++) {\n                    document.getElementById(`player${i}`).value = '';\n                    document.getElementById(`height${i}`).value = '';\n                }\n                \/\/ Limpiamos tambi\u00e9n el almacenamiento de este ID espec\u00edfico\n                localStorage.removeItem('savedFormation_' + partidoID);\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","protected":false},"excerpt":{"rendered":"<p>Visualizador de Formaci\u00f3n de Equipo &#8211; F\u00fatbol 360 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 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-2642","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/futbol360.online\/futbol-360\/wp-json\/wp\/v2\/pages\/2642","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=2642"}],"version-history":[{"count":21,"href":"https:\/\/futbol360.online\/futbol-360\/wp-json\/wp\/v2\/pages\/2642\/revisions"}],"predecessor-version":[{"id":2695,"href":"https:\/\/futbol360.online\/futbol-360\/wp-json\/wp\/v2\/pages\/2642\/revisions\/2695"}],"wp:attachment":[{"href":"https:\/\/futbol360.online\/futbol-360\/wp-json\/wp\/v2\/media?parent=2642"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}