Spaces:
Running
Running
Commit ·
ebbb798
1
Parent(s): 04168cd
Ejes: arreglar display de los selects; sección 6: pool de ligas
Browse files- Los <select> de componentes de eje mostraban siempre la primera opción (bug de
timing de x-model/:value con opciones dinámicas anidadas): ahora usan :selected por
opción, así reflejan el eje real (X=Elaboración, no "Verticalidad").
- Sección 6 (Variables): agregado "Pool: sumar liga" (además de sumar equipo), como en
Recursos; vsDraw maneja pool de ligas + equipos.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
src/racing_reports/web/templates/home.html
CHANGED
|
@@ -592,8 +592,8 @@
|
|
| 592 |
<label class="block text-xs text-gray-400 mb-1">Eje X (ejes × peso)</label>
|
| 593 |
<template x-for="(c,i) in ejXc" :key="'xc'+i">
|
| 594 |
<div class="flex gap-1 mb-1">
|
| 595 |
-
<select
|
| 596 |
-
<template x-for="(lbl,k) in ejLabels" :key="'x'+i+k"><option :value="k" x-text="lbl"></option></template>
|
| 597 |
</select>
|
| 598 |
<input type="number" min="0" max="9" step="1" x-model.number="c.w" @change="ejDraw()" title="peso" class="w-12 bg-ink-800 border border-ink-600 rounded-lg px-1.5 py-1.5 text-sm text-center">
|
| 599 |
<button @click="ejXc.splice(i,1); ejDraw()" x-show="ejXc.length>1" class="text-red-300 px-1.5">×</button>
|
|
@@ -605,8 +605,8 @@
|
|
| 605 |
<label class="block text-xs text-gray-400 mb-1">Eje Y (ejes × peso)</label>
|
| 606 |
<template x-for="(c,i) in ejYc" :key="'yc'+i">
|
| 607 |
<div class="flex gap-1 mb-1">
|
| 608 |
-
<select
|
| 609 |
-
<template x-for="(lbl,k) in ejLabels" :key="'y'+i+k"><option :value="k" x-text="lbl"></option></template>
|
| 610 |
</select>
|
| 611 |
<input type="number" min="0" max="9" step="1" x-model.number="c.w" @change="ejDraw()" title="peso" class="w-12 bg-ink-800 border border-ink-600 rounded-lg px-1.5 py-1.5 text-sm text-center">
|
| 612 |
<button @click="ejYc.splice(i,1); ejDraw()" x-show="ejYc.length>1" class="text-red-300 px-1.5">×</button>
|
|
@@ -867,6 +867,12 @@
|
|
| 867 |
</select>
|
| 868 |
</div>
|
| 869 |
<button @click="vsPinned={}; vsDraw()" class="text-xs text-gray-300 border border-ink-600 rounded-lg px-3 py-2 hover:bg-ink-600">Limpiar marcas</button>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 870 |
<div>
|
| 871 |
<label class="block text-xs text-gray-400 mb-1">Sumar y marcar equipo</label>
|
| 872 |
<input list="vsteamall" x-model="vsPoolTeamIn" @change="vsAddPoolTeam()" placeholder="Equipo (de cualquier liga)…"
|
|
@@ -895,16 +901,16 @@
|
|
| 895 |
<template x-if="ax==='B'"><label class="cursor-pointer inline-flex items-center gap-1.5"><input type="checkbox" x-model="vsB.on" @change="vsReload()"> Burbuja (tamaño)</label></template>
|
| 896 |
</div>
|
| 897 |
<div class="flex flex-col gap-2" :class="ax==='B'&&!vsB.on ? 'pointer-events-none':''">
|
| 898 |
-
<select
|
| 899 |
<template x-for="tp in vsTypeList" :key="'vsg'+ax+tp">
|
| 900 |
<optgroup :label="tp">
|
| 901 |
-
<template x-for="c in (vsTypeCols[tp]||[])" :key="'vso'+ax+c"><option :value="c" x-text="vsColLabel[c]||c"></option></template>
|
| 902 |
</optgroup>
|
| 903 |
</template>
|
| 904 |
</select>
|
| 905 |
-
<select
|
| 906 |
-
<option :value="1">Más es mejor (↑ arriba/derecha)</option>
|
| 907 |
-
<option :value="-1">Menos es mejor (↑ arriba/derecha)</option>
|
| 908 |
</select>
|
| 909 |
</div>
|
| 910 |
</div>
|
|
@@ -1181,7 +1187,7 @@
|
|
| 1181 |
vsLoaded:false, vsLeagueList:[], vsSeasons:{}, vsLeague:'__all__', vsSeason:'__all__',
|
| 1182 |
vsColLabel:{}, vsTypeCols:{}, vsTypeList:[], vsNeg:{},
|
| 1183 |
vsX:{var:'', dir:1}, vsY:{var:'', dir:1}, vsB:{on:false, var:'', dir:1},
|
| 1184 |
-
vsEscala:'liga', vsRows:[], vsError:'', vsPinned:{}, vsPool:[], vsPoolTeamIn:'', vsAllKeys:[],
|
| 1185 |
// Recursos
|
| 1186 |
lbLeagues: [], lbRecursos: {}, lbMetricas: {}, lbLeague: '__all__', lbRows: [], lbError: '', lbLoaded: false,
|
| 1187 |
lbBloques: {}, lbBloqSel: ['bajo','medio','alto'], lbSeason: '__all__',
|
|
@@ -1974,10 +1980,16 @@
|
|
| 1974 |
await this.$nextTick(); this.vsDraw();
|
| 1975 |
} catch(e){ this.vsError='Error: '+e; }
|
| 1976 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1977 |
vsAddPoolTeam(){
|
| 1978 |
const k=(this.vsPoolTeamIn||'').trim(); const m=k.match(/^(.*) \((.*)\)$/);
|
| 1979 |
-
if (m && this.vsAllKeys.includes(k) && !this.vsPool.some(p=>p.equipo===m[1]&&p.liga===m[2]))
|
| 1980 |
-
this.vsPool.push({equipo:m[1], liga:m[2], label:k});
|
| 1981 |
this.vsPoolTeamIn=''; this.vsDraw();
|
| 1982 |
},
|
| 1983 |
vsDraw(){
|
|
@@ -1985,12 +1997,15 @@
|
|
| 1985 |
if (!svg || !this.vsRows.length) return;
|
| 1986 |
svg.innerHTML='';
|
| 1987 |
const esc=this.vsEscala, xa=this.vsX, ya=this.vsY, ba=this.vsB;
|
| 1988 |
-
const
|
|
|
|
|
|
|
| 1989 |
let rows;
|
| 1990 |
-
if (this.
|
|
|
|
| 1991 |
else rows=this.vsRows;
|
| 1992 |
if (this.vsLeague!=='__all__' && this.vsSeason!=='__all__')
|
| 1993 |
-
rows=rows.filter(r=>String(r.temporada)===String(this.vsSeason) ||
|
| 1994 |
const std=(vals)=>{const v=vals.filter(x=>x!=null&&!isNaN(x)); if(v.length<2) return {m:0,s:1};
|
| 1995 |
const m=v.reduce((a,b)=>a+b,0)/v.length; const s=Math.sqrt(v.reduce((a,b)=>a+(b-m)*(b-m),0)/v.length)||1; return {m,s};};
|
| 1996 |
const ligaStats=(v)=>{const map={}; for(const r of this.vsRows){const x=r[v]; if(x==null||isNaN(x))continue;(map[r.liga]=map[r.liga]||[]).push(+x);} const o={}; for(const lg in map)o[lg]=std(map[lg]); return o;};
|
|
|
|
| 592 |
<label class="block text-xs text-gray-400 mb-1">Eje X (ejes × peso)</label>
|
| 593 |
<template x-for="(c,i) in ejXc" :key="'xc'+i">
|
| 594 |
<div class="flex gap-1 mb-1">
|
| 595 |
+
<select @change="c.eje=$event.target.value; ejDraw()" class="bg-ink-800 border border-ink-600 rounded-lg px-2 py-1.5 text-sm flex-1">
|
| 596 |
+
<template x-for="(lbl,k) in ejLabels" :key="'x'+i+k"><option :value="k" :selected="k===c.eje" x-text="lbl"></option></template>
|
| 597 |
</select>
|
| 598 |
<input type="number" min="0" max="9" step="1" x-model.number="c.w" @change="ejDraw()" title="peso" class="w-12 bg-ink-800 border border-ink-600 rounded-lg px-1.5 py-1.5 text-sm text-center">
|
| 599 |
<button @click="ejXc.splice(i,1); ejDraw()" x-show="ejXc.length>1" class="text-red-300 px-1.5">×</button>
|
|
|
|
| 605 |
<label class="block text-xs text-gray-400 mb-1">Eje Y (ejes × peso)</label>
|
| 606 |
<template x-for="(c,i) in ejYc" :key="'yc'+i">
|
| 607 |
<div class="flex gap-1 mb-1">
|
| 608 |
+
<select @change="c.eje=$event.target.value; ejDraw()" class="bg-ink-800 border border-ink-600 rounded-lg px-2 py-1.5 text-sm flex-1">
|
| 609 |
+
<template x-for="(lbl,k) in ejLabels" :key="'y'+i+k"><option :value="k" :selected="k===c.eje" x-text="lbl"></option></template>
|
| 610 |
</select>
|
| 611 |
<input type="number" min="0" max="9" step="1" x-model.number="c.w" @change="ejDraw()" title="peso" class="w-12 bg-ink-800 border border-ink-600 rounded-lg px-1.5 py-1.5 text-sm text-center">
|
| 612 |
<button @click="ejYc.splice(i,1); ejDraw()" x-show="ejYc.length>1" class="text-red-300 px-1.5">×</button>
|
|
|
|
| 867 |
</select>
|
| 868 |
</div>
|
| 869 |
<button @click="vsPinned={}; vsDraw()" class="text-xs text-gray-300 border border-ink-600 rounded-lg px-3 py-2 hover:bg-ink-600">Limpiar marcas</button>
|
| 870 |
+
<div>
|
| 871 |
+
<label class="block text-xs text-gray-400 mb-1">Pool: sumar liga</label>
|
| 872 |
+
<input list="vsligalist" x-model="vsPoolLigaIn" @change="vsAddPoolLiga()" placeholder="Liga…"
|
| 873 |
+
class="bg-ink-800 border border-ink-600 rounded-lg px-3 py-2 text-sm w-48">
|
| 874 |
+
<datalist id="vsligalist"><template x-for="l in vsLeagueList" :key="'vspl'+l"><option :value="l"></option></template></datalist>
|
| 875 |
+
</div>
|
| 876 |
<div>
|
| 877 |
<label class="block text-xs text-gray-400 mb-1">Sumar y marcar equipo</label>
|
| 878 |
<input list="vsteamall" x-model="vsPoolTeamIn" @change="vsAddPoolTeam()" placeholder="Equipo (de cualquier liga)…"
|
|
|
|
| 901 |
<template x-if="ax==='B'"><label class="cursor-pointer inline-flex items-center gap-1.5"><input type="checkbox" x-model="vsB.on" @change="vsReload()"> Burbuja (tamaño)</label></template>
|
| 902 |
</div>
|
| 903 |
<div class="flex flex-col gap-2" :class="ax==='B'&&!vsB.on ? 'pointer-events-none':''">
|
| 904 |
+
<select @change="vsAxis(ax).var=$event.target.value; vsReload()" class="bg-ink-800 border border-ink-600 rounded-lg px-2 py-1.5 text-sm">
|
| 905 |
<template x-for="tp in vsTypeList" :key="'vsg'+ax+tp">
|
| 906 |
<optgroup :label="tp">
|
| 907 |
+
<template x-for="c in (vsTypeCols[tp]||[])" :key="'vso'+ax+c"><option :value="c" :selected="c===vsAxis(ax).var" x-text="vsColLabel[c]||c"></option></template>
|
| 908 |
</optgroup>
|
| 909 |
</template>
|
| 910 |
</select>
|
| 911 |
+
<select @change="vsAxis(ax).dir=+$event.target.value; vsDraw()" class="bg-ink-800 border border-ink-600 rounded-lg px-2 py-1.5 text-sm">
|
| 912 |
+
<option :value="1" :selected="vsAxis(ax).dir===1">Más es mejor (↑ arriba/derecha)</option>
|
| 913 |
+
<option :value="-1" :selected="vsAxis(ax).dir===-1">Menos es mejor (↑ arriba/derecha)</option>
|
| 914 |
</select>
|
| 915 |
</div>
|
| 916 |
</div>
|
|
|
|
| 1187 |
vsLoaded:false, vsLeagueList:[], vsSeasons:{}, vsLeague:'__all__', vsSeason:'__all__',
|
| 1188 |
vsColLabel:{}, vsTypeCols:{}, vsTypeList:[], vsNeg:{},
|
| 1189 |
vsX:{var:'', dir:1}, vsY:{var:'', dir:1}, vsB:{on:false, var:'', dir:1},
|
| 1190 |
+
vsEscala:'liga', vsRows:[], vsError:'', vsPinned:{}, vsPool:[], vsPoolTeamIn:'', vsPoolLigaIn:'', vsAllKeys:[],
|
| 1191 |
// Recursos
|
| 1192 |
lbLeagues: [], lbRecursos: {}, lbMetricas: {}, lbLeague: '__all__', lbRows: [], lbError: '', lbLoaded: false,
|
| 1193 |
lbBloques: {}, lbBloqSel: ['bajo','medio','alto'], lbSeason: '__all__',
|
|
|
|
| 1980 |
await this.$nextTick(); this.vsDraw();
|
| 1981 |
} catch(e){ this.vsError='Error: '+e; }
|
| 1982 |
},
|
| 1983 |
+
vsAddPoolLiga(){
|
| 1984 |
+
const l=(this.vsPoolLigaIn||'').trim();
|
| 1985 |
+
if (l && this.vsLeagueList.includes(l) && !this.vsPool.some(p=>p.tipo==='liga'&&p.liga===l))
|
| 1986 |
+
this.vsPool.push({tipo:'liga', liga:l, label:'Liga: '+l});
|
| 1987 |
+
this.vsPoolLigaIn=''; this.vsDraw();
|
| 1988 |
+
},
|
| 1989 |
vsAddPoolTeam(){
|
| 1990 |
const k=(this.vsPoolTeamIn||'').trim(); const m=k.match(/^(.*) \((.*)\)$/);
|
| 1991 |
+
if (m && this.vsAllKeys.includes(k) && !this.vsPool.some(p=>p.tipo==='equipo'&&p.equipo===m[1]&&p.liga===m[2]))
|
| 1992 |
+
this.vsPool.push({tipo:'equipo', equipo:m[1], liga:m[2], label:k});
|
| 1993 |
this.vsPoolTeamIn=''; this.vsDraw();
|
| 1994 |
},
|
| 1995 |
vsDraw(){
|
|
|
|
| 1997 |
if (!svg || !this.vsRows.length) return;
|
| 1998 |
svg.innerHTML='';
|
| 1999 |
const esc=this.vsEscala, xa=this.vsX, ya=this.vsY, ba=this.vsB;
|
| 2000 |
+
const poolLigas=new Set(this.vsPool.filter(p=>p.tipo==='liga').map(p=>p.liga));
|
| 2001 |
+
const poolKeys=new Set(this.vsPool.filter(p=>p.tipo==='equipo').map(p=>p.liga+'|'+p.equipo));
|
| 2002 |
+
const inPool=r=>poolLigas.has(r.liga) || poolKeys.has(r.liga+'|'+r.equipo);
|
| 2003 |
let rows;
|
| 2004 |
+
if (this.vsPool.length) rows=this.vsRows.filter(r=>inPool(r) || (this.vsLeague!=='__all__' && r.liga===this.vsLeague));
|
| 2005 |
+
else if (this.vsLeague!=='__all__') rows=this.vsRows.filter(r=>r.liga===this.vsLeague);
|
| 2006 |
else rows=this.vsRows;
|
| 2007 |
if (this.vsLeague!=='__all__' && this.vsSeason!=='__all__')
|
| 2008 |
+
rows=rows.filter(r=>String(r.temporada)===String(this.vsSeason) || inPool(r));
|
| 2009 |
const std=(vals)=>{const v=vals.filter(x=>x!=null&&!isNaN(x)); if(v.length<2) return {m:0,s:1};
|
| 2010 |
const m=v.reduce((a,b)=>a+b,0)/v.length; const s=Math.sqrt(v.reduce((a,b)=>a+(b-m)*(b-m),0)/v.length)||1; return {m,s};};
|
| 2011 |
const ligaStats=(v)=>{const map={}; for(const r of this.vsRows){const x=r[v]; if(x==null||isNaN(x))continue;(map[r.liga]=map[r.liga]||[]).push(+x);} const o={}; for(const lg in map)o[lg]=std(map[lg]); return o;};
|