@wafertools/wafermap 0.30.4 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/AGENTS.md +21 -31
  2. package/CHANGELOG.md +265 -1
  3. package/README.md +3 -3
  4. package/dist/packages/canvas-adapter/charts/boxplot.js +1 -1
  5. package/dist/packages/canvas-adapter/charts/chartShell.d.ts +89 -6
  6. package/dist/packages/canvas-adapter/charts/chartShell.js +1 -1
  7. package/dist/packages/canvas-adapter/charts/histogram.js +1 -1
  8. package/dist/packages/canvas-adapter/charts/scatter.d.ts +11 -1
  9. package/dist/packages/canvas-adapter/charts/scatter.js +1 -1
  10. package/dist/packages/canvas-adapter/charts/trend.js +1 -1
  11. package/dist/packages/canvas-adapter/dieList.d.ts +1 -1
  12. package/dist/packages/canvas-adapter/dieList.js +7 -7
  13. package/dist/packages/canvas-adapter/drilldown.js +1 -1
  14. package/dist/packages/canvas-adapter/exportName.d.ts +1 -12
  15. package/dist/packages/canvas-adapter/exportName.js +1 -1
  16. package/dist/packages/canvas-adapter/index.d.ts +2 -3
  17. package/dist/packages/canvas-adapter/index.js +1 -1
  18. package/dist/packages/canvas-adapter/insightsTab.js +1 -1
  19. package/dist/packages/canvas-adapter/renderWaferGallery.d.ts +4 -7
  20. package/dist/packages/canvas-adapter/renderWaferGallery.js +1 -1
  21. package/dist/packages/canvas-adapter/renderWaferMap.d.ts +32 -34
  22. package/dist/packages/canvas-adapter/renderWaferMap.js +1 -1
  23. package/dist/packages/canvas-adapter/summaryPanel.js +3 -3
  24. package/dist/packages/canvas-adapter/toCanvas.d.ts +23 -2
  25. package/dist/packages/canvas-adapter/toCanvas.js +1 -1
  26. package/dist/packages/canvas-adapter/toolbar.js +2 -2
  27. package/dist/packages/canvas-adapter/userGuideHtml.d.ts +1 -1
  28. package/dist/packages/canvas-adapter/userGuideHtml.js +38 -24
  29. package/dist/packages/canvas-adapter/version.d.ts +2 -2
  30. package/dist/packages/canvas-adapter/version.js +1 -1
  31. package/dist/packages/core/aggregates.d.ts +0 -6
  32. package/dist/packages/core/aggregates.js +1 -1
  33. package/dist/packages/core/dieTable.d.ts +137 -0
  34. package/dist/packages/core/dieTable.js +1 -0
  35. package/dist/packages/core/dies.d.ts +22 -2
  36. package/dist/packages/core/dies.js +1 -1
  37. package/dist/packages/core/index.d.ts +8 -10
  38. package/dist/packages/core/index.js +1 -1
  39. package/dist/packages/core/stdf.d.ts +9 -0
  40. package/dist/packages/core/stdf.js +1 -0
  41. package/dist/packages/core/transforms.d.ts +0 -23
  42. package/dist/packages/core/transforms.js +1 -1
  43. package/dist/packages/core/utils.d.ts +14 -0
  44. package/dist/packages/core/utils.js +1 -1
  45. package/dist/packages/renderer/buildView.d.ts +4 -12
  46. package/dist/packages/renderer/buildView.js +1 -1
  47. package/dist/packages/renderer/buildWaferMap.d.ts +42 -32
  48. package/dist/packages/renderer/buildWaferMap.js +1 -1
  49. package/dist/packages/renderer/colorMap.d.ts +0 -2
  50. package/dist/packages/renderer/colorMap.js +1 -1
  51. package/dist/packages/renderer/columnarInput.d.ts +87 -0
  52. package/dist/packages/renderer/columnarInput.js +1 -0
  53. package/dist/packages/renderer/deprecate.d.ts +1 -1
  54. package/dist/packages/renderer/deprecate.js +1 -1
  55. package/dist/packages/renderer/derivedTests/apply.d.ts +8 -6
  56. package/dist/packages/renderer/derivedTests/apply.js +1 -1
  57. package/dist/packages/renderer/index.d.ts +7 -5
  58. package/dist/packages/renderer/index.js +1 -1
  59. package/dist/packages/renderer/spec.d.ts +3 -7
  60. package/dist/packages/renderer/spec.js +1 -1
  61. package/dist/packages/stats/analyzeWaferLot.js +1 -1
  62. package/dist/packages/stats/analyzeWaferMap.d.ts +134 -2
  63. package/dist/packages/stats/analyzeWaferMap.js +1 -1
  64. package/dist/packages/stats/boxplot.js +1 -1
  65. package/dist/packages/stats/capability.d.ts +7 -7
  66. package/dist/packages/stats/capability.js +1 -1
  67. package/dist/packages/stats/clusterDetection.d.ts +2 -1
  68. package/dist/packages/stats/clusterDetection.js +1 -1
  69. package/dist/packages/stats/connectedComponents.js +1 -1
  70. package/dist/packages/stats/correlation.js +1 -1
  71. package/dist/packages/stats/facets.d.ts +1 -1
  72. package/dist/packages/stats/filterFindings.d.ts +5 -0
  73. package/dist/packages/stats/filterFindings.js +1 -1
  74. package/dist/packages/stats/histogram.js +1 -1
  75. package/dist/packages/stats/index.d.ts +6 -16
  76. package/dist/packages/stats/index.js +1 -1
  77. package/dist/packages/stats/math.d.ts +22 -6
  78. package/dist/packages/stats/math.js +1 -1
  79. package/dist/packages/stats/normalizeInput.js +1 -1
  80. package/dist/packages/stats/patternClassification.d.ts +5 -4
  81. package/dist/packages/stats/patternClassification.js +1 -1
  82. package/dist/packages/stats/regions.d.ts +9 -1
  83. package/dist/packages/stats/regions.js +1 -1
  84. package/dist/packages/stats/renderFindingsReport.d.ts +0 -4
  85. package/dist/packages/stats/renderFindingsReport.js +1 -21
  86. package/dist/packages/stats/renderSummaryReport.js +18 -18
  87. package/dist/packages/stats/scatter.js +1 -1
  88. package/dist/packages/stats/sweep.js +1 -1
  89. package/dist/packages/stats/testPassRate.js +1 -1
  90. package/dist/packages/stats/trend.js +1 -1
  91. package/dist/packages/stats/types.d.ts +5 -0
  92. package/dist/packages/worker/index.js +1 -1
  93. package/dist/packages/worker/wafermap.worker.d.ts +3 -0
  94. package/dist/packages/worker/wafermap.worker.js +1 -1
  95. package/package.json +2 -2
  96. package/dist/packages/canvas-adapter/deprecated.d.ts +0 -7
  97. package/dist/packages/canvas-adapter/deprecated.js +0 -1
  98. package/dist/packages/core/deprecated.d.ts +0 -60
  99. package/dist/packages/core/deprecated.js +0 -1
  100. package/dist/packages/renderer/deprecated.d.ts +0 -45
  101. package/dist/packages/renderer/deprecated.js +0 -1
  102. package/dist/packages/stats/deprecated.d.ts +0 -85
  103. package/dist/packages/stats/deprecated.js +0 -1
@@ -1 +1 @@
1
- import{buildFacetTable as Ye,facetValueOf as Ge,FACET_NONE_VALUE as He}from"../stats/facets.js";import{mergeTestDefs as re}from"../stats/mergeTestDefs.js";import{isParametricTest as Fe}from"../renderer/buildWaferMap.js";import{waferDisplayLabel as Ne,waferIdentityLabel as Ve}from"../core/waferLabel.js";import{hasDrilldownTargets as ie,waferPopulation as _e}from"./chartPopulation.js";import{openDrilldownMenu as Ue}from"./drilldown.js";import{INPUT_DEFAULT_PASS_BINS as R,itemPassBins as ze,passBinsLabel as le}from"../core/passBins.js";import{NO_DATA_FILL as de}from"../renderer/colorMap.js";import{describeWaferPopulation as qe,populationStat as Qe}from"../stats/population.js";import{LEADING as ce,ALPHA as Ke,SPACE as x,EDGE_GUTTER as Z,FONT as W,CLR as k,RADIUS as pe,SHADOW as Xe,controlStyle as ue,wireControlHover as ee,wireTooltip as Je}from"./toolbar.js";import{ICONS as Ze}from"./icons.js";import{renderCapabilityPanel as et}from"./charts/capability.js";import{renderBoxplotPanel as tt}from"./charts/boxplot.js";import{renderTrendPanel as nt}from"./charts/trend.js";import{renderSweepPanel as at}from"./charts/sweep.js";import{sweepAppliesTo as ot}from"../stats/sweep.js";import{renderHistogramPanel as st}from"./charts/histogram.js";import{renderCorrelationPanel as rt}from"./charts/correlation.js";import{renderScatterPanel as it}from"./charts/scatter.js";import{renderBarPanel as fe}from"./charts/barPanel.js";import{renderBinClusterPanel as lt}from"./charts/binCluster.js";import{renderTestPassRatePanel as dt}from"./charts/testPassRate.js";import{QUANTITY as ct}from"./charts/palette.js";import{cardFrameStyle as pt,makeChartGridWrap as V,makeLabeledSelect as ut,makeLinkedGroupSelect as ft}from"./charts/chartShell.js";import{buildYieldData as _,buildYieldDataCombined as me}from"../stats/yield.js";import{buildBinParetoData as mt}from"../stats/binPareto.js";import{buildLotTestSection as bt,buildLotFunctionalSection as gt,buildMetadataStripBox as ht}from"./summaryPanel.js";import{buildRegionYieldData as be,buildRingRegions as yt,buildQuadrantRegions as wt}from"../stats/regions.js";import{renderRegionYieldDiagram as ge}from"./charts/regionYieldDiagram.js";const he=[{key:"overview",label:"Overview"},{key:"distributions",label:"Distributions"},{key:"correlation",label:"Correlation"}],Ct={key:"sweeps",label:"Sweeps"};export function createInsightsTab(v){const{getItems:ye,getLotStats:we,getBinColors:te,getRingCount:Ce,onSaveImage:T,onSaveText:U,openWafer:Y,focusTest:ne}=v,xe=v.showMetadataStrip??!0,j=v.contentInset??Z,p=v.ownerDocument??document,O=p.createElement("div");Object.assign(O.style,{display:"none",flexDirection:"column",width:"100%",paddingTop:"0"});const Se=Z,P=p.createElement("div");Object.assign(P.style,{paddingLeft:Se});const B=p.createElement("div");Object.assign(B.style,{display:"flex",gap:x.xs,alignItems:"center",background:k.menuBg,border:`1px solid ${k.menuBorder}`,borderRadius:pe.container,boxShadow:Xe.panel,padding:`0 ${x.lg}`,marginBottom:x.lg,marginLeft:j,marginRight:j}),B.setAttribute("role","tablist"),B.addEventListener("keydown",e=>{if(e.key!=="ArrowLeft"&&e.key!=="ArrowRight")return;const t=Array.from(B.querySelectorAll('[role="tab"]')),o=t.indexOf(p.activeElement);if(o===-1)return;e.preventDefault();const r=t[(o+(e.key==="ArrowRight"?1:-1)+t.length)%t.length];r.focus(),r.click()});const M=p.createElement("div");Object.assign(M.style,{display:"flex",flexDirection:"column",gap:x.lg,marginTop:"0",paddingLeft:j,paddingRight:j}),O.appendChild(P),O.appendChild(B),O.appendChild(M);const ae=(v.sweeps?.length??0)>0,ve=ae?[...he,Ct]:he;let L=v.defaultView==="sweeps"&&!ae?"overview":v.defaultView??"overview",A,$=null,E=null,G={includeLimits:void 0,clipOutliers:!1};const z=e=>{E!==e&&(E=e,F())};let H=new Map;function oe(){for(const e of H.values())e.destroy();H=new Map}function q(e,t,o){Y?.(e,t,o)}function Q(e){if(e.some(t=>ie(t.testDefs,v.sweeps)))return(t,o,r)=>{const i=e.find(f=>f.waferIndex===t);if(!i||!ie(i.testDefs,v.sweeps))return;r.preventDefault();const l=_e(i.dies,{waferLabel:i.identity,testDefs:i.testDefs,activeTest:o??$??void 0,waferIndex:t});Ue({x:r.clientX,y:r.clientY},r.target,l,{sweeps:v.sweeps,onSaveImage:T})}}function Te(e){return Y?{open:(t,o)=>q(t,`Wafer ${e.find(r=>r.waferIndex===t)?.label??t}`,o)}:ne&&e.length===1?{open:(t,o)=>ne(o),label:"show this test on the map"}:null}function ke(){return ye().map((e,t)=>e==null?null:{metadata:e.wafer.metadata??void 0,dies:e.dies,wafer:e.wafer,label:Ne(e,t),identity:Ve(e),waferIndex:t,passBins:ze(e),statsSummary:e.statsSummary,testDefs:e.testDefs}).filter(e=>e!=null)}function se(e,t){Object.assign(e.style,{background:"none",border:"none",borderBottom:t?`2px solid ${k.iconActive}`:"2px solid transparent",color:t?k.iconActive:k.label,fontWeight:t?"700":"500",fontSize:W.body,padding:`${x.sm} ${Z} ${x.md}`,cursor:"pointer",marginBottom:"-1px"})}function De(e,t){const o=p.createElement("button");o.type="button",o.textContent=t;const r=e===L;return se(o,r),o.dataset.on=r?"true":"false",ee(o,"bare"),o.dataset.wmapInsightsTab=e,o.setAttribute("role","tab"),o.setAttribute("aria-selected",r?"true":"false"),o.tabIndex=r?0:-1,o.addEventListener("click",()=>{L!==e&&(L=e,F({keepSections:!0}))}),o}function Be(e){const t=p.createElement("button");return t.type="button",t.textContent=`\u2039 ${e.label}`,se(t,!1),t.dataset.wmapInsightsBack="1",t.addEventListener("click",e.onBack),t}function $e(e,t,o,r=!0){const i=V(p),l=te();let f="label";const u=o??"group",m=le(e.map(c=>c.passBins)),d=we?.(),g=new Map(d?.lotYieldSeries.map(c=>[c.waferIndex,c.yieldPercent])),C=c=>({...c,label:c.label.replace(/\s*·\s*\d+(\.\d+)?%$/,""),yieldPercent:g.get(c.waferIndex),key:c.waferIndex}),b=e.map(C),h=t?.map(c=>({key:c.key,items:c.items.map(C)})),S=()=>h?me(h,R,f):_(b,R,f),w={title:t?`Yield by ${u} (pass: ${m})`:`Yield by wafer (pass: ${m})`,data:S(),selfControl:{current:f,options:[["yield","Sort: yield"],["label",t?`Sort: ${u}`:"Sort: wafer ID"]],onChange:c=>(f=c,{data:S()})},barColor:()=>ct,valueLabel:c=>`${c.percent.toFixed(1)}%`,reference:c=>{if(c.length<3)return null;const D=c.map(J=>J.percent).sort((J,Me)=>J-Me),I=D.length%2?D[(D.length-1)/2]:(D[D.length/2-1]+D[D.length/2])/2;return{value:I,label:`median ${I.toFixed(1)}%`}},drill:h?{onOpenGroup:c=>{const D=h.find(I=>I.key===c.label)?.items??[];return{data:_(D,R,f),title:`Yield by wafer \u2014 ${u}: ${c.label} (pass: ${m})`}},onBack:()=>({data:S(),title:`Yield by ${u} (pass: ${m})`}),groupLabelText:u}:void 0,onOpen:Y?c=>{typeof c.key=="number"&&q(c.key,`Wafer ${c.label}`)}:void 0,onWaferContextMenu:Q(e),ownerDocument:p};let n=null;if(r&&(n=fe(w,T),n.card.style.minHeight="360px",i.appendChild(n.card)),t){const c=lt({title:"Hard bin pareto",groups:t.map(D=>({key:D.key,items:D.items.map(I=>({dies:I.dies,hardBinCounts:I.statsSummary?.stats.hardBinCounts,softBinCounts:I.statsSummary?.stats.softBinCounts}))})),onSaveImage:T,ownerDocument:p});return c.card.style.minHeight="360px",i.appendChild(c.card),{card:i,destroy:()=>{n?.destroy(),c.destroy()}}}let a="hbin";const s=c=>c===void 0?de:(a==="hbin"?l.hard:l.soft).get(c)??de,y=e.map(c=>({dies:c.dies,hardBinCounts:c.statsSummary?.stats.hardBinCounts,softBinCounts:c.statsSummary?.stats.softBinCounts})),N=()=>mt(y,a),je={title:"Hard bin pareto",data:N(),selfControl:{current:a,options:[["hbin","Hard bins"],["sbin","Soft bins"]],onChange:c=>(a=c,{data:N(),title:`${a==="hbin"?"Hard":"Soft"} bin pareto`})},barColor:c=>s(c.binCode),ownerDocument:p},X=fe(je,T);return X.card.style.minHeight="360px",i.appendChild(X.card),{card:i,destroy:()=>{n?.destroy(),X.destroy()}}}function K(){const e=p.createElement("div");return e.dataset.wmapChartCard="1",Object.assign(e.style,{...pt(),display:"flex",flexDirection:"column",gap:x.lg,minWidth:"0"}),e}function Ee(e){if(P.innerHTML="",P.style.marginBottom="0",!xe)return;const t=ht(e.map(o=>({metadata:o.metadata})),void 0,{facetableOnly:!1});t&&(t.style.marginBottom="0",P.appendChild(t),P.style.marginBottom=x.xs)}function Le(e,t,o,r){if(!e.length)return{elements:[],testValuesCard:null,functionalCard:null,destroy:()=>{}};const i=e.map(s=>s.wafer),l=e.map(s=>s.dies),f=e.flatMap(s=>s.dies),u=e.map(s=>s.statsSummary),m=u.every(s=>s!==void 0)?u:void 0,d=Ce?.()??4,g=[],C=[],h=dt({groups:(r??[{key:"",items:e}]).map(s=>({key:s.key,items:s.items.map(y=>({dies:y.dies,testSpecYield:y.statsSummary?.stats.testSpecYield,functionalYield:y.statsSummary?.stats.functionalYield}))})),testDefs:o,onSaveImage:T,ownerDocument:p});h.card.style.minHeight="300px",g.push(h.card),C.push(h.destroy);const S=be(l,i,d,s=>e[s].passBins,yt);if(S.length){const s=ge({title:"Ring yield",mode:"ring",rows:S,onSaveImage:T,ownerDocument:p});g.push(s.card),C.push(s.destroy)}const w=be(l,i,d,s=>e[s].passBins,wt);if(w.length){const s=ge({title:"Quadrant yield",mode:"quadrant",rows:w,onSaveImage:T,ownerDocument:p});g.push(s.card),C.push(s.destroy)}let n=null;if(t.length){const s=bt(f,t,void 0,m,U,l.map(y=>({dies:y})),void 0,"full");if(s){const y=K();y.appendChild(s),n=y}}let a=null;if(o.length){const s=gt(f,o,m,U);if(s){const y=K();y.appendChild(s),a=y}}return{elements:g,testValuesCard:n,functionalCard:a,destroy:()=>{for(const s of C)s()}}}function Ie(e){const t=le(e.map(d=>d.passBins)),o=e.length===1,r=e[0],i=K();Object.assign(i.style,{flexDirection:"row",flexWrap:"wrap",gap:x.md});const l=d=>{const g=d.lastElementChild;return g&&Object.assign(g.style,{borderRight:"none",paddingRight:"0",marginRight:"0"}),d};function f(d,g,C){const b=p.createElement("div");Object.assign(b.style,{display:"flex",alignItems:"baseline",gap:x.sm,paddingRight:x.xxl,marginRight:x.md,borderRight:`1px solid ${k.menuBorder}`});const h=p.createElement("div");h.textContent=d,Object.assign(h.style,{fontSize:W.heading,fontWeight:"700",color:k.value,lineHeight:ce.tight});const S=p.createElement("div");if(S.textContent=g,Object.assign(S.style,{fontSize:W.body,color:k.label}),b.append(h,S),C){const w=p.createElement("div");w.textContent=C,Object.assign(w.style,{fontSize:W.meta,color:k.label,opacity:Ke.muted}),b.appendChild(w)}return b}if(o){const d=_([{...r,key:r.waferIndex}],R)[0]?.percent;return d!==void 0&&i.appendChild(f(`${d.toFixed(1)}%`,`Yield \xB7 pass: ${t}`)),i.appendChild(f(String(r.dies.length),"Total dies")),l(i)}i.appendChild(f(String(e.length),"Wafers"));const u=_(e.map(d=>({...d,key:d.waferIndex})),R).map(d=>d.percent).filter(d=>Number.isFinite(d));if(u.length){const d=u.reduce((b,h)=>b+h,0)/u.length,g=me([{key:"all",items:e.map(b=>({...b,key:b.waferIndex}))}],R)[0]?.percent,C=g!==void 0&&g.toFixed(1)!==d.toFixed(1);i.appendChild(f(`${d.toFixed(1)}%`,`Mean per-wafer yield \xB7 pass: ${t}`,C?`${g.toFixed(1)}% by dies`:void 0))}const m=e.map(d=>d.statsSummary);if(m.every(d=>d!==void 0)){const d=m.reduce((C,b)=>C+b.stats.analyzedDies,0),g=m.reduce((C,b)=>C+b.stats.excludedDies,0);i.appendChild(f(d.toLocaleString(),"Dies analysed",g?`${g.toLocaleString()} excluded`:void 0))}else i.appendChild(f(e.reduce((d,g)=>d+g.dies.length,0).toLocaleString(),"Total dies"));return l(i)}function Oe(e,t,o,r,i){const l=p.createElement("div");Object.assign(l.style,{display:"flex",flexDirection:"column",gap:x.lg});const f=e.length===1&&!r;e.length&&!r&&l.appendChild(Ie(e));const u=$e(e,r,i,!f);l.appendChild(u.card);const m=Le(e,t,o,r);for(const d of m.elements)u.card.appendChild(d);return m.testValuesCard&&l.appendChild(m.testValuesCard),m.functionalCard&&l.appendChild(m.functionalCard),{card:l,destroy:()=>{u.destroy(),m.destroy()}}}function Pe(e,t,o,r){const i=V(p),l=Te(e),f=a=>{G=a;for(const s of[b,h,S])s!==u&&s?.setAxisPrefs(a)};let u=null;const m=a=>s=>{u=a(),f(s),u=null},d=a=>({...a,testStats:a.statsSummary?.stats.perTestStats}),g=e.map(d),C=o?.map(a=>({key:a.key,items:a.items.map(d)})),b=tt({title:"Test value distribution",axisPrefs:G,onAxisPrefsChange:m(()=>b),onTestChange:a=>w(a),selectedTestNumber:$??void 0,items:g,testDefs:t,groups:C,groupLabelText:r,onSaveImage:T,onGroupChange:a=>z(a),onOpen:l?.open,openActionLabel:l?.label,onWaferContextMenu:Q(e),ownerDocument:p}),h=st({title:"Value histogram",axisPrefs:G,onAxisPrefsChange:m(()=>h),onTestChange:a=>w(a),selectedTestNumber:$??void 0,items:e,testDefs:t,groups:o,onGroupChange:a=>z(a),onSaveImage:T,ownerDocument:p}),S=nt({title:"Wafer-to-wafer trend",axisPrefs:G,onAxisPrefsChange:m(()=>S),onTestChange:a=>w(a),selectedTestNumber:$??void 0,items:e.map(a=>({label:a.label,key:a.waferIndex,dies:a.dies,testStats:a.statsSummary?.stats.perTestStats})),testDefs:t,onSaveImage:T,centreLabel:Qe(qe(e.map(a=>a.wafer.metadata)),"mean"),onOpen:Y?(a,s)=>q(a,`Wafer ${e.find(y=>y.waferIndex===a)?.label??a}`,s):void 0,onWaferContextMenu:Q(e),ownerDocument:p}),w=a=>{$=a,b.setTest(a),h.setTest(a),S.setTest(a),n.setTest(a)},n=et({title:"Process capability",items:e,testDefs:t,onSaveImage:T,selectedTestNumber:$??void 0,onSelectTest:a=>w(a),ownerDocument:p});return i.append(n.card,b.card,h.card,S.card),{card:i,destroy:()=>{n.destroy(),b.destroy(),h.destroy(),S.destroy()}}}function Ae(e){const t=V(p),o=re(e).defs,r=e.flatMap(u=>u.dies),i=v.sweeps??[],l=i.filter(u=>!ot(u,o));l.length>0&&t.appendChild(Re(l,i.length));const f=i.map(u=>at({spec:u,dies:r,testDefs:o,onSaveImage:T,ownerDocument:p}));for(const u of f)t.appendChild(u.card);return{card:t,destroy:()=>{for(const u of f)u.destroy()}}}function Re(e,t){const o=p.createElement("div");o.setAttribute("role","status"),Object.assign(o.style,{gridColumn:"1 / -1",display:"flex",flexWrap:"wrap",alignItems:"center",gap:x.md,padding:`${x.sm} ${x.md}`,background:k.warnBg,border:`1px solid ${k.warnBorder}`,borderRadius:pe.container,color:k.warnText,fontSize:W.body,lineHeight:ce.base});const r=e.length,i=p.createElement("span");if(i.style.flex="1 1 24ch",i.textContent=(r===t?r===1?"This sweep names no test in this data":"None of these sweeps names a test in this data":`${r} of ${t} sweeps name no test in this data: ${e.map(l=>l.title).join(", ")}`)+` \u2014 ${r===1?"it":"they"} may belong to another test program.`,o.appendChild(i),v.onRemoveSweeps){const l=p.createElement("button");l.type="button",Object.assign(l.style,ue("outlined")),l.textContent=r===1?"Remove this sweep":`Remove these ${r} sweeps`,ee(l);const f=e.map(u=>u.id);l.addEventListener("click",()=>v.onRemoveSweeps(f)),o.appendChild(l)}return o}function We(e,t,o){const r=V(p),i=it({title:"Test scatter",items:e,testDefs:t,groups:o,binColors:te().hard,onSaveImage:T,ownerDocument:p}),l=rt({title:"Test correlation matrix",items:e,testDefs:t,onSaveImage:T,onSaveText:U,onSelectPair:(f,u)=>i.setXY(f,u),ownerDocument:p});return r.append(l.card,i.card),{card:r,destroy:()=>{l.destroy(),i.destroy()}}}function F(e){e?.keepSections||oe(),M.innerHTML="",B.innerHTML="",v.backTab&&B.appendChild(Be(v.backTab));for(const n of ve)B.appendChild(De(n.key,n.label));const t=ke();Ee(t);const o=Ye(t,{facetableOnly:!0}).filter(n=>n.splittable),r=p.createElement("div");Object.assign(r.style,{display:"flex",gap:x.md,alignItems:"center",marginLeft:x.xxl,paddingBottom:x.xs});let i;o.length>0?(r.appendChild(ut("Group by:",[{value:"",label:"None"},...o.map(n=>({value:n.key,label:`${n.label} (${n.values.length})`}))],A??"",n=>{A=n||void 0,E=null,F()},{hook:"group-by",ownerDocument:p})),i=o.find(n=>n.key===A)?.label):A=void 0;let l;if(A){const n=new Map,a=[];for(const s of t){const y=Ge(s.metadata,A)??He;n.has(y)||(n.set(y,[]),a.push(y)),n.get(y).push(s)}l=a.map(s=>({key:s,items:n.get(s)}))}E!==null&&!l?.some(n=>n.key===E)&&(E=null),l&&l.length>0&&r.appendChild(ft(l.map(n=>n.key),"Show:",E,n=>z(n),{ownerDocument:p}).el);let f=null;if(v.onOpenGuide){const n=p.createElement("button");n.type="button",n.innerHTML=Ze.help,n.setAttribute("aria-label","User guide"),Object.assign(n.style,{...ue("bare"),display:"inline-flex",alignItems:"center",justifyContent:"center",width:"24px",height:"24px",flexShrink:"0"}),ee(n,"bare"),Je(n,"User guide"),n.addEventListener("click",()=>v.onOpenGuide()),Object.assign(n.style,{marginLeft:"auto"}),f=n}B.appendChild(r),f&&B.appendChild(f);const u=E!==null?l?.find(n=>n.key===E):void 0,m=u?.items??t,d=u?void 0:l,g=re(m),C=g.defs,b=C.filter(Fe);$!==null&&!b.some(n=>n.testNumber===$)&&($=null);const h=e?.keepSections?H.get(L):void 0,S=h??(L==="overview"?Oe(m,b,C,d,i):L==="distributions"?Pe(m,b,d,i):L==="sweeps"?Ae(m):We(m,b,d));h||H.set(L,S);const w=g.conflicts.filter(n=>n.excluded);if(w.length>0){const n=p.createElement("div");Object.assign(n.style,{color:k.label,fontSize:W.body,padding:`0 ${j} ${x.sm}`});const a=w.slice(0,6).map(N=>N.testNumber).join(", "),s=w.length>6?`, and ${w.length-6} more`:"",y=w.length===1?"it":"them";n.textContent=`${w.length} test ${w.length===1?"number is":"numbers are"} hidden (${a}${s}) \u2014 the wafers in view describe ${y} differently, so their values cannot be pooled. `+(l&&l.length>0?`Pick one ${i??"group"} under "Show:" to analyse ${y}.`:"Load one test program at a time to analyse them."),n.dataset.wmapWithheldTests=String(w.length),M.appendChild(n)}M.appendChild(S.card)}return{el:O,render:F,destroy:()=>{oe(),O.remove()}}}
1
+ import{buildFacetTable as He,facetValueOf as Fe,FACET_NONE_VALUE as Ne}from"../stats/facets.js";import{mergeTestDefs as de}from"../stats/mergeTestDefs.js";import{isParametricTest as Ve}from"../renderer/buildWaferMap.js";import{waferDisplayLabel as _e,waferIdentityLabel as ze}from"../core/waferLabel.js";import{hasDrilldownTargets as ce,waferPopulation as Ue}from"./chartPopulation.js";import{openDrilldownMenu as qe}from"./drilldown.js";import{INPUT_DEFAULT_PASS_BINS as M,itemPassBins as Qe,passBinsLabel as pe}from"../core/passBins.js";import{NO_DATA_FILL as ue}from"../renderer/colorMap.js";import{describeWaferPopulation as Ke,populationStat as Xe}from"../stats/population.js";import{LEADING as fe,ALPHA as Je,SPACE as w,EDGE_GUTTER as te,FONT as A,CLR as k,RADIUS as me,SHADOW as Ze,controlStyle as be,wireControlHover as ne,wireTooltip as et}from"./toolbar.js";import{ICONS as tt}from"./icons.js";import{renderCapabilityPanel as nt}from"./charts/capability.js";import{renderBoxplotPanel as at}from"./charts/boxplot.js";import{renderTrendPanel as ot}from"./charts/trend.js";import{renderSweepPanel as st}from"./charts/sweep.js";import{sweepAppliesTo as rt}from"../stats/sweep.js";import{renderHistogramPanel as it}from"./charts/histogram.js";import{renderCorrelationPanel as lt}from"./charts/correlation.js";import{renderScatterPanel as dt}from"./charts/scatter.js";import{renderBarPanel as ge}from"./charts/barPanel.js";import{renderBinClusterPanel as ct}from"./charts/binCluster.js";import{renderTestPassRatePanel as pt}from"./charts/testPassRate.js";import{QUANTITY as ut}from"./charts/palette.js";import{cardFrameStyle as ft,makeChartGridWrap as _,makeLabeledSelect as mt,makeLinkedGroupSelect as bt}from"./charts/chartShell.js";import{buildYieldData as z,buildYieldDataCombined as he}from"../stats/yield.js";import{buildBinParetoData as gt}from"../stats/binPareto.js";import{buildLotTestSectionSteps as ht,buildLotFunctionalSection as yt,buildMetadataStripBox as wt}from"./summaryPanel.js";import{runChunked as Ct}from"./chunked.js";import{buildRegionYieldData as ye,buildRingRegions as xt,buildQuadrantRegions as St}from"../stats/regions.js";import{renderRegionYieldDiagram as we}from"./charts/regionYieldDiagram.js";const Ce=[{key:"overview",label:"Overview"},{key:"distributions",label:"Distributions"},{key:"correlation",label:"Correlation"}],vt={key:"sweeps",label:"Sweeps"};export function createInsightsTab(x){const{getItems:xe,getLotStats:Se,getBinColors:ae,getRingCount:ve,onSaveImage:T,onSaveText:U,openWafer:F,focusTest:oe}=x,Te=x.showMetadataStrip??!0,Y=x.contentInset??te,p=x.ownerDocument??document,R=p.createElement("div");Object.assign(R.style,{display:"none",flexDirection:"column",width:"100%",paddingTop:"0"});const ke=te,W=p.createElement("div");Object.assign(W.style,{paddingLeft:ke});const $=p.createElement("div");Object.assign($.style,{display:"flex",gap:w.xs,alignItems:"center",background:k.menuBg,border:`1px solid ${k.menuBorder}`,borderRadius:me.container,boxShadow:Ze.panel,padding:`0 ${w.lg}`,marginBottom:w.lg,marginLeft:Y,marginRight:Y}),$.setAttribute("role","tablist"),$.addEventListener("keydown",e=>{if(e.key!=="ArrowLeft"&&e.key!=="ArrowRight")return;const t=Array.from($.querySelectorAll('[role="tab"]')),a=t.indexOf(p.activeElement);if(a===-1)return;e.preventDefault();const s=t[(a+(e.key==="ArrowRight"?1:-1)+t.length)%t.length];s.focus(),s.click()});const G=p.createElement("div");Object.assign(G.style,{display:"flex",flexDirection:"column",gap:w.lg,marginTop:"0",paddingLeft:Y,paddingRight:Y}),R.appendChild(W),R.appendChild($),R.appendChild(G);const se=(x.sweeps?.length??0)>0,De=se?[...Ce,vt]:Ce;let P=x.defaultView==="sweeps"&&!se?"overview":x.defaultView??"overview",j,E=null,L=null,H={includeLimits:void 0,clipOutliers:!1,limits:"both"};const q=new Map,re=(e,t)=>{H=e;for(const a of q.values())for(const s of a)s!==t&&s.setAxisPrefs(e)},Q=e=>{L!==e&&(L=e,V())};let N=new Map;function ie(){for(const e of N.values())e.destroy();N=new Map}function K(e,t,a){F?.(e,t,a)}function X(e){if(e.some(t=>ce(t.testDefs,x.sweeps)))return(t,a,s)=>{const r=e.find(u=>u.waferIndex===t);if(!r||!ce(r.testDefs,x.sweeps))return;s.preventDefault();const i=Ue(r.dies,{waferLabel:r.identity,testDefs:r.testDefs,activeTest:a??E??void 0,waferIndex:t});qe({x:s.clientX,y:s.clientY},s.target,i,{sweeps:x.sweeps,onSaveImage:T})}}function Be(e){return F?{open:(t,a)=>K(t,`Wafer ${e.find(s=>s.waferIndex===t)?.label??t}`,a)}:oe&&e.length===1?{open:(t,a)=>oe(a),label:"show this test on the map"}:null}function $e(){return xe().map((e,t)=>e==null?null:{metadata:e.wafer.metadata??void 0,dies:e.dies,wafer:e.wafer,label:_e(e,t),identity:ze(e),waferIndex:t,passBins:Qe(e),statsSummary:e.statsSummary,testDefs:e.testDefs}).filter(e=>e!=null)}function le(e,t){Object.assign(e.style,{background:"none",border:"none",borderBottom:t?`2px solid ${k.iconActive}`:"2px solid transparent",color:t?k.iconActive:k.label,fontWeight:t?"700":"500",fontSize:A.body,padding:`${w.sm} ${te} ${w.md}`,cursor:"pointer",marginBottom:"-1px"})}function Ee(e,t){const a=p.createElement("button");a.type="button",a.textContent=t;const s=e===P;return le(a,s),a.dataset.on=s?"true":"false",ne(a,"bare"),a.dataset.wmapInsightsTab=e,a.setAttribute("role","tab"),a.setAttribute("aria-selected",s?"true":"false"),a.tabIndex=s?0:-1,a.addEventListener("click",()=>{P!==e&&(P=e,V({keepSections:!0}))}),a}function Le(e){const t=p.createElement("button");return t.type="button",t.textContent=`\u2039 ${e.label}`,le(t,!1),t.dataset.wmapInsightsBack="1",t.addEventListener("click",e.onBack),t}function Pe(e,t,a,s=!0){const r=_(p),i=ae();let u="label";const f=a??"group",g=pe(e.map(d=>d.passBins)),c=Se?.(),m=new Map(c?.lotYieldSeries.map(d=>[d.waferIndex,d.yieldPercent])),h=d=>({...d,label:d.label.replace(/\s*·\s*\d+(\.\d+)?%$/,""),yieldPercent:m.get(d.waferIndex),key:d.waferIndex}),b=e.map(h),y=t?.map(d=>({key:d.key,items:d.items.map(h)})),S=()=>y?he(y,M,u):z(b,M,u),o={title:t?`Yield by ${f} (pass: ${g})`:`Yield by wafer (pass: ${g})`,data:S(),selfControl:{current:u,options:[["yield","Sort: yield"],["label",t?`Sort: ${f}`:"Sort: wafer ID"]],onChange:d=>(u=d,{data:S()})},barColor:()=>ut,valueLabel:d=>`${d.percent.toFixed(1)}%`,reference:d=>{if(d.length<3)return null;const D=d.map(ee=>ee.percent).sort((ee,Ge)=>ee-Ge),I=D.length%2?D[(D.length-1)/2]:(D[D.length/2-1]+D[D.length/2])/2;return{value:I,label:`median ${I.toFixed(1)}%`}},drill:y?{onOpenGroup:d=>{const D=y.find(I=>I.key===d.label)?.items??[];return{data:z(D,M,u),title:`Yield by wafer \u2014 ${f}: ${d.label} (pass: ${g})`}},onBack:()=>({data:S(),title:`Yield by ${f} (pass: ${g})`}),groupLabelText:f}:void 0,onOpen:F?d=>{typeof d.key=="number"&&K(d.key,`Wafer ${d.label}`)}:void 0,onWaferContextMenu:X(e),ownerDocument:p};let n=null;if(s&&(n=ge(o,T),n.card.style.minHeight="360px",r.appendChild(n.card)),t){const d=ct({title:"Hard bin pareto",groups:t.map(D=>({key:D.key,items:D.items.map(I=>({dies:I.dies,hardBinCounts:I.statsSummary?.stats.hardBinCounts,softBinCounts:I.statsSummary?.stats.softBinCounts}))})),onSaveImage:T,ownerDocument:p});return d.card.style.minHeight="360px",r.appendChild(d.card),{card:r,destroy:()=>{n?.destroy(),d.destroy()}}}let v="hbin";const l=d=>d===void 0?ue:(v==="hbin"?i.hard:i.soft).get(d)??ue,C=e.map(d=>({dies:d.dies,hardBinCounts:d.statsSummary?.stats.hardBinCounts,softBinCounts:d.statsSummary?.stats.softBinCounts})),O=()=>gt(C,v),B={title:"Hard bin pareto",data:O(),selfControl:{current:v,options:[["hbin","Hard bins"],["sbin","Soft bins"]],onChange:d=>(v=d,{data:O(),title:`${v==="hbin"?"Hard":"Soft"} bin pareto`})},barColor:d=>l(d.binCode),ownerDocument:p},Z=ge(B,T);return Z.card.style.minHeight="360px",r.appendChild(Z.card),{card:r,destroy:()=>{n?.destroy(),Z.destroy()}}}function J(){const e=p.createElement("div");return e.dataset.wmapChartCard="1",Object.assign(e.style,{...ft(),display:"flex",flexDirection:"column",gap:w.lg,minWidth:"0"}),e}function Ie(e){if(W.innerHTML="",W.style.marginBottom="0",!Te)return;const t=wt(e.map(a=>({metadata:a.metadata})),void 0,{facetableOnly:!1});t&&(t.style.marginBottom="0",W.appendChild(t),W.style.marginBottom=w.xs)}function Oe(e,t,a,s){if(!e.length)return{elements:[],testValuesCard:null,functionalCard:null,destroy:()=>{}};const r=e.map(l=>l.wafer),i=e.map(l=>l.dies),u=e.flatMap(l=>l.dies),f=e.map(l=>l.statsSummary),g=f.every(l=>l!==void 0)?f:void 0,c=ve?.()??4,m=[],h=[],y=pt({groups:(s??[{key:"",items:e}]).map(l=>({key:l.key,items:l.items.map(C=>({dies:C.dies,testSpecYield:C.statsSummary?.stats.testSpecYield,functionalYield:C.statsSummary?.stats.functionalYield}))})),testDefs:a,onSaveImage:T,ownerDocument:p});y.card.style.minHeight="300px",m.push(y.card),h.push(y.destroy);const S=ye(i,r,c,l=>e[l].passBins,xt);if(S.length){const l=we({title:"Ring yield",mode:"ring",rows:S,onSaveImage:T,ownerDocument:p});m.push(l.card),h.push(l.destroy)}const o=ye(i,r,c,l=>e[l].passBins,St);if(o.length){const l=we({title:"Quadrant yield",mode:"quadrant",rows:o,onSaveImage:T,ownerDocument:p});m.push(l.card),h.push(l.destroy)}let n=null;if(t.length){const l=J();let C=null;const O=Ct(ht(u,t,void 0,g,U,i.map(B=>({dies:B})),void 0,"full"),{onDone:B=>{C=B,l.removeAttribute("aria-busy"),B?l.replaceChildren(B):l.remove()}});if(O.done)C&&(n=l);else{const B=p.createElement("div");B.textContent="Computing test statistics\u2026",Object.assign(B.style,{color:k.label,fontSize:A.body}),l.setAttribute("aria-busy","true"),l.appendChild(B),n=l,h.push(()=>O.cancel())}}let v=null;if(a.length){const l=yt(u,a,g,U);if(l){const C=J();C.appendChild(l),v=C}}return{elements:m,testValuesCard:n,functionalCard:v,destroy:()=>{for(const l of h)l()}}}function Ae(e){const t=pe(e.map(c=>c.passBins)),a=e.length===1,s=e[0],r=J();Object.assign(r.style,{flexDirection:"row",flexWrap:"wrap",gap:w.md});const i=c=>{const m=c.lastElementChild;return m&&Object.assign(m.style,{borderRight:"none",paddingRight:"0",marginRight:"0"}),c};function u(c,m,h){const b=p.createElement("div");Object.assign(b.style,{display:"flex",alignItems:"baseline",gap:w.sm,paddingRight:w.xxl,marginRight:w.md,borderRight:`1px solid ${k.menuBorder}`});const y=p.createElement("div");y.textContent=c,Object.assign(y.style,{fontSize:A.heading,fontWeight:"700",color:k.value,lineHeight:fe.tight});const S=p.createElement("div");if(S.textContent=m,Object.assign(S.style,{fontSize:A.body,color:k.label}),b.append(y,S),h){const o=p.createElement("div");o.textContent=h,Object.assign(o.style,{fontSize:A.meta,color:k.label,opacity:Je.muted}),b.appendChild(o)}return b}if(a){const c=z([{...s,key:s.waferIndex}],M)[0]?.percent;return c!==void 0&&r.appendChild(u(`${c.toFixed(1)}%`,`Yield \xB7 pass: ${t}`)),r.appendChild(u(String(s.dies.length),"Total dies")),i(r)}r.appendChild(u(String(e.length),"Wafers"));const f=z(e.map(c=>({...c,key:c.waferIndex})),M).map(c=>c.percent).filter(c=>Number.isFinite(c));if(f.length){const c=f.reduce((b,y)=>b+y,0)/f.length,m=he([{key:"all",items:e.map(b=>({...b,key:b.waferIndex}))}],M)[0]?.percent,h=m!==void 0&&m.toFixed(1)!==c.toFixed(1);r.appendChild(u(`${c.toFixed(1)}%`,`Mean per-wafer yield \xB7 pass: ${t}`,h?`${m.toFixed(1)}% by dies`:void 0))}const g=e.map(c=>c.statsSummary);if(g.every(c=>c!==void 0)){const c=g.reduce((h,b)=>h+b.stats.analyzedDies,0),m=g.reduce((h,b)=>h+b.stats.excludedDies,0);r.appendChild(u(c.toLocaleString(),"Dies analysed",m?`${m.toLocaleString()} excluded`:void 0))}else r.appendChild(u(e.reduce((c,m)=>c+m.dies.length,0).toLocaleString(),"Total dies"));return i(r)}function Re(e,t,a,s,r){const i=p.createElement("div");Object.assign(i.style,{display:"flex",flexDirection:"column",gap:w.lg});const u=e.length===1&&!s;e.length&&!s&&i.appendChild(Ae(e));const f=Pe(e,s,r,!u);i.appendChild(f.card);const g=Oe(e,t,a,s);for(const c of g.elements)f.card.appendChild(c);return g.testValuesCard&&i.appendChild(g.testValuesCard),g.functionalCard&&i.appendChild(g.functionalCard),{card:i,destroy:()=>{f.destroy(),g.destroy()}}}function We(e,t,a,s){const r=_(p),i=Be(e),u=o=>n=>re(n,o()),f=o=>({...o,testStats:o.statsSummary?.stats.perTestStats}),g=e.map(f),c=a?.map(o=>({key:o.key,items:o.items.map(f)})),m=at({title:"Test value distribution",axisPrefs:H,onAxisPrefsChange:u(()=>m),onTestChange:o=>y(o),selectedTestNumber:E??void 0,items:g,testDefs:t,groups:c,groupLabelText:s,onSaveImage:T,onGroupChange:o=>Q(o),onOpen:i?.open,openActionLabel:i?.label,onWaferContextMenu:X(e),ownerDocument:p}),h=it({title:"Value histogram",axisPrefs:H,onAxisPrefsChange:u(()=>h),onTestChange:o=>y(o),selectedTestNumber:E??void 0,items:e,testDefs:t,groups:a,onGroupChange:o=>Q(o),onSaveImage:T,ownerDocument:p}),b=ot({title:"Wafer-to-wafer trend",axisPrefs:H,onAxisPrefsChange:u(()=>b),onTestChange:o=>y(o),selectedTestNumber:E??void 0,items:e.map(o=>({label:o.label,key:o.waferIndex,dies:o.dies,testStats:o.statsSummary?.stats.perTestStats})),testDefs:t,onSaveImage:T,centreLabel:Xe(Ke(e.map(o=>o.wafer.metadata)),"mean"),onOpen:F?(o,n)=>K(o,`Wafer ${e.find(v=>v.waferIndex===o)?.label??o}`,n):void 0,onWaferContextMenu:X(e),ownerDocument:p}),y=o=>{E=o,m.setTest(o),h.setTest(o),b.setTest(o),S.setTest(o)};q.set("distribution",[m,h,b]);const S=nt({title:"Process capability",items:e,testDefs:t,onSaveImage:T,selectedTestNumber:E??void 0,onSelectTest:o=>y(o),ownerDocument:p});return r.append(S.card,m.card,h.card,b.card),{card:r,destroy:()=>{S.destroy(),m.destroy(),h.destroy(),b.destroy()}}}function je(e){const t=_(p),a=de(e).defs,s=e.flatMap(f=>f.dies),r=x.sweeps??[],i=r.filter(f=>!rt(f,a));i.length>0&&t.appendChild(Me(i,r.length));const u=r.map(f=>st({spec:f,dies:s,testDefs:a,onSaveImage:T,ownerDocument:p}));for(const f of u)t.appendChild(f.card);return{card:t,destroy:()=>{for(const f of u)f.destroy()}}}function Me(e,t){const a=p.createElement("div");a.setAttribute("role","status"),Object.assign(a.style,{gridColumn:"1 / -1",display:"flex",flexWrap:"wrap",alignItems:"center",gap:w.md,padding:`${w.sm} ${w.md}`,background:k.warnBg,border:`1px solid ${k.warnBorder}`,borderRadius:me.container,color:k.warnText,fontSize:A.body,lineHeight:fe.base});const s=e.length,r=p.createElement("span");if(r.style.flex="1 1 24ch",r.textContent=(s===t?s===1?"This sweep names no test in this data":"None of these sweeps names a test in this data":`${s} of ${t} sweeps name no test in this data: ${e.map(i=>i.title).join(", ")}`)+` \u2014 ${s===1?"it":"they"} may belong to another test program.`,a.appendChild(r),x.onRemoveSweeps){const i=p.createElement("button");i.type="button",Object.assign(i.style,be("outlined")),i.textContent=s===1?"Remove this sweep":`Remove these ${s} sweeps`,ne(i);const u=e.map(f=>f.id);i.addEventListener("click",()=>x.onRemoveSweeps(u)),a.appendChild(i)}return a}function Ye(e,t,a){const s=_(p),r=dt({title:"Test scatter",items:e,testDefs:t,groups:a,binColors:ae().hard,onSaveImage:T,axisPrefs:H,onAxisPrefsChange:u=>re(u,r),ownerDocument:p});q.set("correlation",[r]);const i=lt({title:"Test correlation matrix",items:e,testDefs:t,onSaveImage:T,onSaveText:U,onSelectPair:(u,f)=>r.setXY(u,f),ownerDocument:p});return s.append(i.card,r.card),{card:s,destroy:()=>{i.destroy(),r.destroy()}}}function V(e){e?.keepSections||ie(),G.innerHTML="",$.innerHTML="",x.backTab&&$.appendChild(Le(x.backTab));for(const n of De)$.appendChild(Ee(n.key,n.label));const t=$e();Ie(t);const a=He(t,{facetableOnly:!0}).filter(n=>n.splittable),s=p.createElement("div");Object.assign(s.style,{display:"flex",gap:w.md,alignItems:"center",marginLeft:w.xxl,paddingBottom:w.xs});let r;a.length>0?(s.appendChild(mt("Group by:",[{value:"",label:"None"},...a.map(n=>({value:n.key,label:`${n.label} (${n.values.length})`}))],j??"",n=>{j=n||void 0,L=null,V()},{hook:"group-by",ownerDocument:p})),r=a.find(n=>n.key===j)?.label):j=void 0;let i;if(j){const n=new Map,v=[];for(const l of t){const C=Fe(l.metadata,j)??Ne;n.has(C)||(n.set(C,[]),v.push(C)),n.get(C).push(l)}i=v.map(l=>({key:l,items:n.get(l)}))}L!==null&&!i?.some(n=>n.key===L)&&(L=null),i&&i.length>0&&s.appendChild(bt(i.map(n=>n.key),"Show:",L,n=>Q(n),{ownerDocument:p}).el);let u=null;if(x.onOpenGuide){const n=p.createElement("button");n.type="button",n.innerHTML=tt.help,n.setAttribute("aria-label","User guide"),Object.assign(n.style,{...be("bare"),display:"inline-flex",alignItems:"center",justifyContent:"center",width:"24px",height:"24px",flexShrink:"0"}),ne(n,"bare"),et(n,"User guide"),n.addEventListener("click",()=>x.onOpenGuide()),Object.assign(n.style,{marginLeft:"auto"}),u=n}$.appendChild(s),u&&$.appendChild(u);const f=L!==null?i?.find(n=>n.key===L):void 0,g=f?.items??t,c=f?void 0:i,m=de(g),h=m.defs,b=h.filter(Ve);E!==null&&!b.some(n=>n.testNumber===E)&&(E=null);const y=e?.keepSections?N.get(P):void 0,S=y??(P==="overview"?Re(g,b,h,c,r):P==="distributions"?We(g,b,c,r):P==="sweeps"?je(g):Ye(g,b,c));y||N.set(P,S);const o=m.conflicts.filter(n=>n.excluded);if(o.length>0){const n=p.createElement("div");Object.assign(n.style,{color:k.label,fontSize:A.body,padding:`0 ${Y} ${w.sm}`});const v=o.slice(0,6).map(O=>O.testNumber).join(", "),l=o.length>6?`, and ${o.length-6} more`:"",C=o.length===1?"it":"them";n.textContent=`${o.length} test ${o.length===1?"number is":"numbers are"} hidden (${v}${l}) \u2014 the wafers in view describe ${C} differently, so their values cannot be pooled. `+(i&&i.length>0?`Pick one ${r??"group"} under "Show:" to analyse ${C}.`:"Load one test program at a time to analyse them."),n.dataset.wmapWithheldTests=String(o.length),G.appendChild(n)}G.appendChild(S.card)}return{el:R,render:V,destroy:()=>{ie(),R.remove()}}}
@@ -110,13 +110,10 @@ export interface GalleryOptions {
110
110
  */
111
111
  perCardLegend?: boolean;
112
112
  /**
113
- * Name for the composite gallery PNG, without extension. When omitted, it is
114
- * named for its lots, wafer count and plot mode
115
- * (`LOT123_25-wafers_gallery-hard-bin.png`); cards, CSV exports and charts are
116
- * always named that way. See docs/api.md §5.4.5.
117
- *
118
- * **Changes in 0.31.0:** this becomes a prefix for every file the gallery and
119
- * its cards save. Passing it logs a one-time notice.
113
+ * A prefix for every file the gallery, its cards and their detached windows
114
+ * save — PNGs and CSVs alike. The lots, wafer or wafer count, and content
115
+ * follow it (`<prefix>_25-wafers_gallery-hard-bin.png`), except any the prefix
116
+ * already names. See docs/api.md §5.4.5.
120
117
  */
121
118
  downloadFilename?: string;
122
119
  /**
@@ -1 +1 @@
1
- import{getUniqueTestNumbers as Do,resolveTestNumber as ko,findTestDef as Eo,collectMetadataValues as Bo}from"../renderer/buildView.js";import{metadataCategoricalValue as Oo}from"../core/metadata.js";import{resolveBinColorsForMaps as To,mergeBinDefs as Ye,binColorWarning as Lo,mixedPassBinsWarning as Ro,binColorsEqual as Io}from"../renderer/binColors.js";import{itemPassBins as Wo,INPUT_DEFAULT_PASS_BINS as $o}from"../core/passBins.js";import{NO_DATA_FILL as Ao}from"../renderer/colorMap.js";import{metadataValueColor as Po}from"../renderer/colorMap.js";import{resolveCanvasTheme as Fo}from"./canvasTheme.js";import{ICONS as We}from"./icons.js";import{SHADOW as $e,LEADING as Ze,TRACKING as Ho,controlStyle as jo,wireControlHover as xt,SPACE as w,EDGE_GUTTER as oe,MAP_CHROME_INSET as Vo,RADIUS as z,FONT as L,CLR as h,sevColor as gn,MODE_LABELS as No,BIN_LEGEND_MODES as hn,STACKED_MODES as be,Z_ABOVE as bn,applyOverlayZ as zo,getTooltip as _o,hideTooltip as yn,createToolbarHelpers as Go,buildModeMenuEl as Ko,openDetachWindow as qo,openFloatingWindow as Uo,openModal as Xo,openReportModal as Yo,copyWmapThemeTokens as Zo,syncWmapPopupTheme as Qo,openUserGuideWindow as Jo,makePaletteBtn as ei,makeLogScaleBtn as ti,makeLegendStyleBtn as ni,makeOverlaysBtn as oi,makeOrientationBtn as ii,menuLayerFor as wn,saveImageBlob as vn,markMenuTrigger as Ae,wireMenuA11y as xn,wireExpandToggle as Cn,wireTooltip as Sn,requestedPassFailDisplay as Mn,overlayMenuRows as ai,anyOverlayActive as li,logWmapVersionOnce as si,buildDataModeEntries as ri,metadataKeyHasData as di,metadataModeEntry as ci}from"./toolbar.js";import{waferDisplayLabel as Qe,waferIdentityLabel as Dn}from"../core/waferLabel.js";import{metadataDisplayValue as ui}from"../core/metadata.js";import{withExportContext as fi,noticeDownloadFilenameChange as pi}from"./exportName.js";import{sortBinsForDisplay as mi}from"../stats/binPareto.js";import{diePassStatus as gi}from"../core/dies.js";import{aggregateValues as hi,aggregateBinCounts as kn}from"../core/aggregates.js";import{renderWaferMap as bi,renderWaferMapCard as En,toPublicViewOptions as Bn}from"./renderWaferMap.js";import{hasDrilldownTargets as yi,waferPopulation as wi}from"./chartPopulation.js";import{classifyChanged as vi,COLOR_KEYS as xi}from"./renderWaferMap.js";import{buildWaferMap as Ci,getTestPassStatus as On,isParametricTest as Ct,getDieTestValue as Si}from"../renderer/buildWaferMap.js";import{analyzeWaferMap as Je}from"../stats/analyzeWaferMap.js";import{collectWarnings as Mi,buildWarningsMenuEl as Di,severityOf as ki}from"./warnings.js";import{compareNatural as St,arrayEqual as Tn}from"../core/utils.js";import{createSummaryPanelEl as Mt,buildMetadataStripRow as Ei,buildCompactMetadataRows as Ln,metadataEntries as Rn,renderLotSummaryContentSteps as Bi,reportMapsFromItems as Oi}from"./summaryPanel.js";import{renderLotReportHtml as Ti}from"../stats/renderSummaryReport.js";import{prettyKey as Li}from"../stats/facets.js";import{testLabel as Ri,markedTestLabel as Ii,derivedFields as Wi}from"../renderer/testLabel.js";import{mergeTestDefs as $i}from"../stats/mergeTestDefs.js";import{getDieKey as Ai,hasPosition as Pi}from"../core/dies.js";import{runChunked as Fi}from"./chunked.js";function In(f){if(typeof f!="number"||!Number.isFinite(f))return;const C=Math.round(f);return C>=1?C:void 0}const Dt=12;function Hi(f,C,p){let A=C;if(C.length>Dt){const E=C.slice(0,Dt-1),I=C.slice(Dt-1),H=I.reduce((X,ie)=>X+ie.count,0);A=[...E,{color:h.label,count:H,label:`Other (${I.length} bins)`}]}const k=f.createElement("div");Object.assign(k.style,{display:"flex",columnGap:"1px",width:"100%",height:"8px",borderRadius:z.control,overflow:"hidden",border:`1px solid ${h.menuBorder}`,boxSizing:"border-box",marginTop:w.xs,flexShrink:"0"}),k.setAttribute("role","img"),k.setAttribute("aria-label",`Population split: ${A.map(E=>`${E.label} ${et(E.count/p*100)}`).join(", ")}`);for(const E of A){const I=E.count/p*100,H=f.createElement("div");Object.assign(H.style,{flex:`${I} 1 0`,minWidth:I>0?"2px":"0",background:E.color}),Sn(H,`${E.label} \xB7 ${E.count.toLocaleString()} dies \xB7 ${et(I)}`),k.appendChild(H)}return k}function et(f){return f>0&&f<.1?"<0.1%":`${f.toFixed(1)}%`}function Wn(f,C,p){const A=new Map;let k=0,E=0;for(const I of f){const H=p?new Set(p(I)):void 0;for(const X of I.dies){if(X.partial||X.edgeExcluded)continue;const ie=C(X);ie!==void 0&&(A.set(ie,(A.get(ie)??0)+1),k++,H&&gi(X,H)&&E++)}}return{counts:A,total:k,pass:E}}function $n(f,C){const p=f.ownerDocument.createElement("div");Object.assign(p.style,{display:"flex",alignItems:"center",gap:"5px",cursor:"pointer",userSelect:"none",padding:`${w.xxs} ${w.xs}`,borderRadius:z.control});const A=f.ownerDocument.createElement("span");Object.assign(A.style,{display:"inline-block",width:"13px",height:"13px",flexShrink:"0",background:C.color,border:C.isActive?`2px solid ${h.iconActive}`:`1px solid ${h.menuBorder}`,borderRadius:z.control,boxSizing:"border-box"});const k=f.ownerDocument.createElement("span");if(k.textContent=C.label,Object.assign(k.style,{fontWeight:C.isActive?"700":"400",color:C.isActive?h.iconActive:h.text,whiteSpace:"nowrap"}),p.appendChild(A),p.appendChild(k),C.count!==void 0){const E=f.ownerDocument.createElement("span");if(E.textContent=C.count.toLocaleString(),Object.assign(E.style,{color:C.isActive?h.iconActive:h.text,fontWeight:C.isActive?"700":"400",whiteSpace:"nowrap"}),p.appendChild(E),C.percent!==void 0){const I=f.ownerDocument.createElement("span");I.textContent=et(C.percent),Object.assign(I.style,{color:h.label,whiteSpace:"nowrap"}),p.appendChild(I)}}p.setAttribute("role","button"),p.setAttribute("aria-pressed",C.isActive?"true":"false"),p.tabIndex=0,p.addEventListener("mouseenter",()=>{p.style.background=h.bgHover}),p.addEventListener("mouseleave",()=>{p.style.background="transparent"}),p.addEventListener("focus",()=>{p.style.background=h.bgHover}),p.addEventListener("blur",()=>{p.style.background="transparent"}),p.addEventListener("click",C.onClick),p.addEventListener("keydown",E=>{(E.key==="Enter"||E.key===" ")&&(E.preventDefault(),C.onClick())}),f.appendChild(p)}export function renderWaferGallery(f,C,p={}){si();const A=6;let k=In(p.columns);const E=p.showHelpButton??!1,I=p.userGuideExtension,H=p.insights?.enabled??!1,X=p.insights?.sweeps?{sweeps:p.insights.sweeps}:void 0,ie=zo(p.zIndex),re=p.summaryPanel,An=e=>[...Wo(e)],kt=()=>v.flatMap(e=>e?[e.ringCount??4]:[]),tt=()=>kt()[0]??4;function Pn(e){const t=[...new Set(e)].sort((n,o)=>n-o);return t.length<2?null:{code:"ring-count-mixed",severity:"warning",message:`These wafers were built with different ring counts (${t.join(", ")}). Each card and each wafer's findings use their own; the lot's ring yield in the Summary panel, report and Insights uses ${e[0]} rings.`}}let V=p.lotStatsSummary,ye=p.viewOptions?.legendPosition??"default",Pe=p.perCardLegend??!1;function we(){const e=c.plotMode??"hardBin";return hn.has(e)?null:c.colorbarRangeMode==="data"?"Each map has its own value range, so it keeps its own colour bar":"These wafers have no shared colour bar for value mode, so each map keeps its own"}function Et(){const e=Pe||we()!==null;for(const t of S)t&&t.setOptions({showLegend:e})}let c={plotMode:"hardBin",showDieLabels:!1,showRingBoundaries:!1,showQuadrantBoundaries:!1,rotation:0,flipX:!1,flipY:!1,...p.viewOptions},S=[],ae=[],de=[],R=[];const Fe=fi(()=>{const e=R.filter(n=>n!=null);return{lots:[...new Set(e.map(n=>ui(n.wafer.metadata?.lot)).filter(n=>n!==void 0))].sort(St),...e.length===1?{wafer:Dn(e[0])}:{waferCount:e.length}}},p.onSaveImage,p.onSaveText);pi(p.downloadFilename);let v=C.map(e=>typeof e=="function"?null:e);function Bt(){return $i(v)}function ve(){if(v.some(e=>e?.testDefs?.length))return Bt().defs}let xe=0,He=0;const _=new Map;let Fn=0,P=null,Ce=null,Ot=new Set,b=null,Hn={};function Tt(e){return v[e]?.statsSummary??V?.perWafer.find(t=>t.waferIndex===e)?.summary}function nt(){return!!(v.some(e=>e?.statsSummary?.findings.length)||V?.perWafer.some(e=>e.summary.findings.length))}const jn=_o(),ce=Go(jn),{makeBtn:Q,setActive:Se,makeSep:G,makeMenuRow:Vn,makeMenuSection:Nn,makeDropdown:Lt,closeOpenMenu:je,getOpenMenu:Me,setOpenMenu:De}=ce;f.ownerDocument.addEventListener("click",je,!0);const Rt=()=>yn();window.addEventListener("blur",Rt);let It=p.findingsNotice;function Wt(e){Ot=new Set(e);const t=[...$.querySelectorAll(".wmap-gallery-card")];let n;t.forEach((o,d)=>{const l=Ot.has(d);o.style.outline=l?`3px solid ${h.findingHighlight}`:"",o.style.outlineOffset=l?"-3px":"",l&&n===void 0&&(n=o)}),n?.scrollIntoView?.({behavior:"smooth",block:"nearest"})}function $t(){Wt([])}function At(){for(const e of S)e&&e.clearSelection()}function ot(e,t){const n=new Set(e),o=t??S.map((d,l)=>l);for(const d of o){const l=R[d],a=S[d];if(!l||!a)continue;const r=l.dies.filter(i=>n.has(Ai(i)));a.setSelection(r)}}function zn(){const e=[];for(let t=0;t<v.length;t++){const n=v[t];if(!n)continue;const o=Tt(t)?.findings??[];o.length&&e.push({index:t,item:n,unusualCount:o.filter(d=>d.severity==="unusual").length,notableCount:o.filter(d=>d.severity==="notable").length,totalCount:o.length})}return e}function _n(e){const t=R[e]??v[e];t&&Ie(e,t)}function Gn(e){const t=Tt(e)?.findings??[];if(t.length)return{total:t.length,unusual:t.filter(n=>n.severity==="unusual").length,notable:t.filter(n=>n.severity==="notable").length}}function Kn(){Yo(Ti(Oi(v,$o,tt())),{anchor:f})}function qn(){if(!b)return;b.innerHTML="";const e=zn();if(v.length>0){const n=f.ownerDocument.createElement("div"),o=e.length,d=v.filter(Boolean).length;n.textContent=o===0?`No findings on any of the ${d} wafers`:`${o} of ${d} wafer${d===1?"":"s"} with findings`,Object.assign(n.style,{fontSize:L.body,color:h.label,marginBottom:w.md}),b.appendChild(n)}if(e.length>0){const n=f.ownerDocument.createElement("button");n.type="button",n.textContent="Summary report",Object.assign(n.style,{...jo("outlined"),marginBottom:w.lg,display:"block",width:"100%",textAlign:"left"}),xt(n),n.addEventListener("click",Kn),b.appendChild(n)}if(e.length===0){const n=f.ownerDocument.createElement("div");Object.assign(n.style,{color:h.icon,fontSize:L.body,padding:"4px 0"}),n.textContent="No findings on any wafer.",b.appendChild(n)}else for(const{index:n,item:o,unusualCount:d,notableCount:l,totalCount:a}of e){const r=d?"unusual":l?"notable":"info",i=d+l||a,s=f.ownerDocument.createElement("button");s.type="button",Object.assign(s.style,{display:"flex",alignItems:"center",justifyContent:"space-between",width:"100%",padding:"5px 8px",marginBottom:w.xs,border:"none",borderLeft:`3px solid ${gn(r)}`,borderRadius:z.control,background:h.bgHover,cursor:"pointer",fontSize:L.body,textAlign:"left",boxSizing:"border-box"}),s.addEventListener("mouseover",()=>{s.style.background=h.bgActive}),s.addEventListener("mouseout",()=>{s.style.background=h.bgHover});const u=f.ownerDocument.createElement("span");u.textContent=Qe(o,n),Object.assign(u.style,{color:h.iconHover,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"});const m=f.ownerDocument.createElement("span");m.textContent=String(i),s.setAttribute("aria-label",`${Qe(o,n)} \u2014 ${i} finding${i===1?"":"s"}${d?`, ${d} unusual`:""} \u2014 view wafer`),Object.assign(m.style,{marginLeft:w.sm,flexShrink:"0",background:gn(r),color:"#fff",borderRadius:z.container,padding:"1px 5px",fontSize:L.body,fontWeight:"600"}),s.appendChild(u),s.appendChild(m),s.addEventListener("click",()=>Ie(n,o)),b.appendChild(s)}const t=f.ownerDocument.createElement("div");t.style.height="12px",b.appendChild(t)}let ue=null,ke=null;function N(){if(b)if(ue?.cancel(),ue=null,V){const e=Ye(v.map(n=>n?.hbinDefs)),t=Ye(v.map(n=>n?.sbinDefs));ue=Fi(Bi(b,{lotSummary:V,items:v,hbinDefs:e.length?e:void 0,sbinDefs:t.length?t:void 0,testDefs:ve(),ringCount:tt(),binColors:c.binColors,plotMode:c.plotMode??"hardBin",fallbackFormat:c.fallbackFormat,activeFindingId:Ce,warnings:p.warnings?.display??!0?J:[],findingsFilter:Hn,findingsNotice:It,onFindingsFilterChange:N,onSaveText:Fe.onSaveText,onFindingClick:(n,o)=>{Ce===n.id?it():Xn(n,o),N()},onWaferClick:_n,findingsFor:Gn,dieListOptions:p.dieList}),{onDone:()=>{const n=ke;ke=null,n?.()}})}else qn()}function Un(e){const t=e.highlight;return t?.kind==="wafer"&&t.waferIndices?.length?t.waferIndices:null}function Pt(e){return[e.variable.kind,e.variable.index??"",e.variable.bin??"",e.comparison.family,e.comparison.left,e.effect.direction].join("|")}let Ve=[];function Ft(){if(Ve.length!==0){for(const e of Ve)S[e]?.setOptions({plotMode:c.plotMode,activeTest:c.activeTest});Ve=[]}}function it(){Ce=null,$t(),At(),Ft(),T({highlightBin:void 0},{fireCallback:!1})}function Xn(e,t){if(Ce===e.id){it();return}Ce=e.id,t.style.background=h.bgActive,t.style.fontWeight="600",Ft();const{kind:n,index:o}=e.variable;if(n==="test"){const l=o??0,a=ve();if(a===void 0||a.some(i=>i.testNumber===l))T({plotMode:"value",activeTest:l,highlightBin:void 0},{fireCallback:!1});else{T({highlightBin:void 0},{fireCallback:!1});const s=be.has(c.plotMode??"hardBin")?null:Un(e);if(s){for(const u of s)S[u]?.setOptions({plotMode:"value",activeTest:l});Ve=[...s]}}}else n==="softBin"?T({plotMode:"softBin",highlightBin:void 0},{fireCallback:!1}):T({plotMode:"hardBin",highlightBin:void 0},{fireCallback:!1});$t(),At();const d=e.highlight;if(d.kind==="wafer"){Wt(d.waferIndices);const l=Pt(e);for(const a of d.waferIndices){const s=R[a]?.statsSummary?.findings.find(u=>Pt(u)===l)?.highlight?.dieKeys;s?.length&&ot(s,[a])}}else d.kind==="bin"?d.dieKeys?.length&&ot(d.dieKeys):(d.kind==="region"||d.kind==="dies")&&d.dieKeys?.length&&ot(d.dieKeys)}function le(){if(!P)return;const e=!!b;P.style.display=(V||nt())&&e&&!Te?"flex":"none";const t=b?b.style.display!=="none":!1;(V?.hasNotableFindings||v.some(o=>o?.statsSummary?.hasNotableFindings))&&!t?P.style.color=h.findingIndicator:P.dataset.active||(P.style.color=h.icon)}const W=f.ownerDocument.createElement("div");W.dataset.wmapToolbar="gallery",Object.assign(W.style,{flexShrink:"0",marginLeft:"auto",display:"inline-flex",flexDirection:"row",alignItems:"center",gap:"0",background:h.menuBg,border:`1px solid ${h.menuBorder}`,borderRadius:z.control,padding:"0",boxShadow:$e.panel,flexWrap:"wrap",minWidth:"0",overflowX:"auto"});const Ht=()=>{const e=Me();e&&(e.remove(),De(null)),Ae(Y,!1)},Y=Q("mode","Plot mode",()=>{if(Me()){Ht();return}const e=v.flatMap(y=>y?.dies??[]),t=ve(),{testEntries:n,binEntries:o,stackedEntries:d}=ri(e,t,{includeStacked:!0}),l=v.filter(Boolean).length,a=y=>{if(y===void 0)return l;let B=0;for(const j of v)j?.dies?.some(U=>On(U,y)!==void 0||U.testValues?.[y]!==void 0)&&B++;return B},r=l<2?n:n.map(y=>{const B=a(y.activeTest);return B===l?y:{...y,label:`${y.label} \u2014 ${B} of ${l} wafers`}}),i=c.plotMode??"hardBin",s=c.activeTest??0;function u(y){return y.plotMode!==i?!1:y.plotMode==="value"?s===(y.activeTest??0):y.plotMode==="metadata"?c.activeMetadataKey===y.activeMetadataKey:!0}function m(y,B){y.activeTest!==void 0?T({plotMode:"value",activeTest:y.activeTest,activeMetadataKey:void 0,logScale:y.logScale}):y.activeMetadataKey!==void 0?T({plotMode:y.plotMode,activeTest:void 0,activeMetadataKey:y.activeMetadataKey,passFailDisplay:"off"}):T({plotMode:y.plotMode,activeTest:void 0,activeMetadataKey:void 0,passFailDisplay:"off"}),B.remove(),De(null),Ae(Y,!1)}const M=new Set,D=v.flatMap(y=>y?.metadataFields??[]).filter(y=>!M.has(y.key)&&M.add(y.key)).filter(y=>di(e,y.key)).map(ci),x=Ko(Y.getBoundingClientRect(),r,o,d,u,m,{makeMenuRow:Vn,makeMenuSection:Nn},i,Y.ownerDocument.defaultView??window,D);wn(Y).appendChild(x),De(x),Ae(Y,!0),xn(x,Y,Ht)});Ae(Y,!1);const Yn=()=>R.flatMap(e=>e?[...e.hbinDefs??[],...e.sbinDefs??[]]:[]).some(e=>e.color),{btn:Zn,sync:jt}=ei(ce,()=>({...c,plotMode:c.plotMode??"hardBin"}),Yn,e=>T(e));jt();const Qn=C.some(e=>typeof e!="function"&&(e.reticles?.length??0)>0);function Ne(){const e=ve(),{testNumber:t}=ko(c.activeTest??0,e);return{testNumber:t,td:Eo(e,t)}}function Vt(){if((c.plotMode??"hardBin")!=="value")return!1;const{td:e}=Ne();return e!==void 0&&(e.limitLow!==void 0||e.limitHigh!==void 0)}function Ee(){if((c.plotMode??"hardBin")!=="value")return!1;const{td:e}=Ne();return e!==void 0&&!Ct(e)}function Jn(){if((c.plotMode??"hardBin")!=="value")return!1;const{testNumber:e,td:t}=Ne();return v.some(n=>n?.dies?.some(o=>On(o,e,t)!==void 0))}function eo(e,t){if(!t||!Ct(t))return;const n=t.limitLow!==void 0||t.limitHigh!==void 0;if((Mn(c)==="spec"&&n?"spec":c.colorbarRangeMode??"spec")==="spec"&&n)return;let l=1/0,a=-1/0;for(const r of v)if(r)for(const i of r.dies){const s=Si(i,e);s!==void 0&&(s<l&&(l=s),s>a&&(a=s))}if(isFinite(l))return l===a?[l,l+1]:[l,a]}function at(e,t,n){const o=c[e];if(o===t||o!=null&&t!=null&&n(o,t))return!1;c={...c,[e]:t};for(const d of S)d&&d.setOptions({[e]:t});return!0}function Nt(){if((c.plotMode??"hardBin")!=="metadata")return;const e=c.activeMetadataKey;if(!e)return;const t=new Set;for(const n of v)if(n)for(const o of Bo(n.dies,e))t.add(o);return{key:e,values:[...t].sort(St)}}function lt(){at("metadataValueOrder",Nt(),(e,t)=>e.key===t.key&&Tn(e.values,t.values))}function st(){if((c.plotMode??"hardBin")!=="value")return;const{testNumber:e,td:t}=Ne(),n=eo(e,t);at("valueRange",n?{test:e,range:n}:void 0,(d,l)=>{const a=s=>Array.isArray(s)?{test:void 0,range:s}:{test:s.test,range:s.range},r=a(d),i=a(l);return r.test===i.test&&Tn(r.range,i.range)})}let rt=!1;function to(){if(rt)return;rt=!0,(f.ownerDocument.defaultView?.requestAnimationFrame??(t=>setTimeout(()=>t(0),0)))(()=>{rt=!1,st(),lt(),_t()})}let dt=!1;function no(){if(dt)return;dt=!0,(f.ownerDocument.defaultView?.requestAnimationFrame??(t=>setTimeout(()=>t(0),0)))(()=>{dt=!1,qe()})}let zt=[];function fe(){const{colors:e,mixedHardBins:t}=To(v.filter(n=>n!=null),{binColorScheme:c.binColorScheme,useDefinedBinColors:c.useDefinedBinColors});return zt=t,e}function _t(){at("binColors",fe(),Io),Be()}const oo=oi(ce,()=>ai(c,Qn,{functionalActive:Ee(),hasLimits:Vt()&&!Ee(),hasRecorded:Jn()&&!Ee(),binMode:(c.plotMode??"hardBin")==="hardBin"||(c.plotMode??"hardBin")==="softBin"},e=>T(e)),()=>li(c)),{btn:io,sync:Gt}=ni(ce,()=>({plotMode:c.plotMode,legendPosition:ye}),e=>{ye=e;for(const t of S)t&&t.setOptions({legendPosition:ye})},{get:()=>Pe,set:e=>{Pe=e,Et()},blockedReason:we});Gt();const ao=[{value:"mean",label:"Mean"},{value:"median",label:"Median"},{value:"stddev",label:"Std Dev"},{value:"min",label:"Min"},{value:"max",label:"Max"},{value:"count",label:"Count"}],Kt=Lt("aggr","Aggregation method",()=>ao,()=>c.aggregationMethod??"mean",e=>T({aggregationMethod:e}));function qt(){const e=c.plotMode==="stackedValues";Kt.style.display=e?"":"none"}qt();const{btn:lo,sync:Ut}=ti(ce,()=>({...c,functionalActive:Ee()}),e=>T(e));Ut();const ze=Q("specRange","Colorbar range: test limits",()=>{const e=c.colorbarRangeMode==="data"?"spec":"data";T({colorbarRangeMode:e})});function Xt(){const e=(c.plotMode??"hardBin")==="value"&&Vt()&&Mn(c)==="off"&&!Ee();ze.style.display=e?"":"none";const t=(c.colorbarRangeMode??"spec")==="spec";Se(ze,t),ze.ariaLabel=t?"Colorbar range: test limits (click for data range)":"Colorbar range: data range (click for test limits)"}Xt();const so=ii(ce,()=>c,e=>T(e)),ro=Q("downloadAll","Download gallery PNG",Co),co=Lt("columns","Columns",()=>[{value:"auto",label:"Auto"},{value:"1",label:"1 column"},{value:"2",label:"2 columns"},{value:"3",label:"3 columns"},{value:"4",label:"4 columns"},{value:"5",label:"5 columns"}],()=>k!=null?String(k):"auto",e=>ln(e==="auto"?void 0:Number(e))),O=f.ownerDocument.createElement("div");Object.assign(O.style,{display:"inline-flex",alignItems:"center",gap:"0"}),W.appendChild(O),O.appendChild(Y),O.appendChild(Zn),O.appendChild(Kt),O.appendChild(lo),O.appendChild(ze),O.appendChild(G()),O.appendChild(oo),O.appendChild(G()),O.appendChild(io),O.appendChild(G()),O.appendChild(so),O.appendChild(G()),O.appendChild(co),O.appendChild(G()),O.appendChild(ro),(V||nt())&&(P=Q("findings","Summary panel",()=>{if(!b)return;const e=b.style.display!=="none";e||N(),b.style.display=e?"none":"flex",Se(P,!e),le()}),W.appendChild(G()),W.appendChild(P));let K=null,_e=null,J=[],Yt=!1;function Be(){const e=Mi({lotStatsSummary:V,result:{warnings:[...v.flatMap(n=>n?.warnings??[]),...Bt().warnings]},extra:[c.binColors&&Lo(c.binColors,c.plotMode),Ro(zt),Pn(kt())].filter(n=>!!n)}),t=e.length!==J.length||e.some((n,o)=>n.code!==J[o]?.code||n.message!==J[o]?.message);J=e,(t||!Yt)&&(Yt=!0,p.warnings?.onWarning?.(e)),uo()}function uo(){if(!K||!_e)return;const e=J.length,t=e>0;if(K.style.display=t?"flex":"none",_e.style.display=t?"":"none",!t)return;const n=ki(J[0]),o=`${e} data ${e===1?"warning":"warnings"}`;K.style.color=n==="error"?h.errText:h.warnText,K.ariaLabel=n==="error"?`${o} \u2014 some wafers may be positionally wrong`:o}(p.warnings?.display??!0)&&(_e=G(),K=Q("warning","Data warnings",()=>{const e=Me();if(je(new MouseEvent("click")),e)return;const t=Di(K.getBoundingClientRect(),J,K.ownerDocument.defaultView??window);wn(f).appendChild(t),De(t),xn(t,K,()=>je(new MouseEvent("click")))}),Ae(K,!1),W.appendChild(_e),W.appendChild(K)),Be();let se=null;H&&(se=Q("analysis","Insights",()=>{Jt(!Te)}),se.dataset.wmapInsightsBtn="1",W.appendChild(G()),W.appendChild(se));function Zt(){import("./userGuideHtml.js").then(e=>Jo({buildWaferMap:Ci,renderWaferMap:bi,renderWaferGallery,analyzeWaferMap:Je},e.USER_GUIDE_HTML,I,f))}E&&(W.appendChild(G()),W.appendChild(Q("help","User guide",()=>Zt())));const pe=f.ownerDocument.createElement("div");pe.dataset.wmapGalleryMeta="1",Object.assign(pe.style,{flex:"1",minWidth:"0",overflow:"hidden",display:"flex",alignItems:"center",padding:`${w.sm} ${w.lg}`,fontSize:L.sub,lineHeight:Ze.none,boxSizing:"border-box"});const Ge=f.ownerDocument.createElement("div");Object.assign(Ge.style,{background:h.canvasBg,display:"flex",alignItems:"stretch",gap:w.lg,paddingBottom:w.lg,minWidth:"0"});const ee=f.ownerDocument.createElement("div");ee.dataset.wmapGalleryLegend="1",Object.assign(ee.style,{display:"flex",flexDirection:"column",gap:w.sm,background:h.menuBg,border:`1px solid ${h.menuBorder}`,borderRadius:z.container,padding:`${w.sm} ${w.lg}`,marginBottom:w.lg,boxShadow:$e.panel,fontSize:L.body,lineHeight:Ze.none,boxSizing:"border-box",width:"100%",minWidth:"0"});const q=f.ownerDocument.createElement("div");Object.assign(q.style,{display:"flex",flexDirection:"row",alignItems:"flex-start"});let me=null,Oe=null,Qt=null;function fo(){return H?me?Promise.resolve(me):(Qt??=import("./insightsTab.js").then(({createInsightsTab:e})=>(me=e({getItems:()=>v,getLotStats:()=>V,getBinColors:()=>c.binColors??fe(),getRingCount:tt,defaultView:p.insights?.defaultView,sweeps:p.insights?.sweeps,onRemoveSweeps:p.insights?.onRemoveSweeps,onOpenGuide:void 0,showMetadataStrip:!1,onSaveImage:Fe.onSaveImage,onSaveText:Fe.onSaveText,ownerDocument:f.ownerDocument,openWafer:(t,n,o)=>{const d=v[t];if(!d)return;let l=null;const a=Xo({title:n,onClose:()=>l?.destroy(),anchor:f});dn(a,n,d.wafer.metadata??void 0),l=ht(a.contentWrap,d,o)}}),Oe=me.el,Oe.style.display="none",f.appendChild(Oe),me)),Qt):Promise.resolve(null)}let Te=!1;function Jt(e){H&&(Te=e,Oe&&(Oe.style.display=e?"flex":"none"),q.style.display=e?"none":"flex",O.style.display=e?"none":"inline-flex",W.style.display="inline-flex",se&&(Se(se,e),se.innerHTML=e?We.wafer:We.analysis,se.ariaLabel=e?"Back to gallery view":"Insights"),le(),qe(),e&&fo().then(t=>{!t||!Te||(t.el.style.display="flex",t.render())}))}H&&p.insights?.defaultOpen&&queueMicrotask(()=>Jt(!0));const po=4,ct=240,en=480,mo=720,go=1.25;let ge=en;function tn(e){const t=A*2+110+2;let n=null;for(const o of e){if(o==null||!o.dies?.length)continue;const d=o.dies[0].width;if(!(d>0))continue;const l=o.wafer.radius*2*(po/d),a=Math.ceil(l+t);(n==null||a>n)&&(n=a)}return n}function ho(e){const t=tn(e);return t==null?ct:Math.min(ge,Math.max(ct,t))}function bo(e){const t=tn(e);if(t==null)return!1;const n=Math.min(mo,Math.max(en,t));return n<=ge?!1:(ge=n,!0)}function ut(){return k!=null?"none":`${ge}px`}function nn(){const e=ut();for(const t of Array.from($.children))t.classList.contains("wmap-gallery-card")&&(t.style.maxWidth=e,t.style.maxHeight=e)}let Ke=ct,on=0;function an(e){if(bo(e)&&nn(),k==null){const n=ho(e);n>Ke&&(Ke=n)}pt()}function ln(e){k=In(e),nn(),pt()}function ft(e){return`repeat(${e}, minmax(0, ${k!=null?"1fr":`${ge}px`}))`}function sn(e){$.style.gridTemplateColumns!==e&&($.style.gridTemplateColumns=e)}function pt(){if(k!=null){sn(ft(k));return}const e=Math.max(1,on),t=12,n=$.clientWidth||0,o=l=>(n-t*(l-1))/l;let d=Math.max(1,Math.ceil(Math.sqrt(e)));if(n>0){const l=Math.min(ge,Ke*go),a=r=>{let i=0;for(;i<e&&o(i+1)>=r;)i++;return i};d=a(l)||a(Ke)||1}sn(ft(d))}const $=f.ownerDocument.createElement("div");if(Object.assign($.style,{flex:"1 1 0",minWidth:"0",display:"grid",gridTemplateColumns:ft(1),gap:w.xl,paddingLeft:oe,paddingRight:oe,justifyContent:"start",alignContent:"start",isolation:"isolate"}),re?.placement){const e=re.placement;b=Mt(e,oe,f.ownerDocument),b.style.maxHeight="calc(100vh - 80px)",b.style.position="sticky",b.style.top="8px",b.style.display="flex",b.style.flexDirection="column"}else if(V||nt()){const e=!!re?.defaultOpen;b=Mt("right",oe,f.ownerDocument),b.style.maxHeight="calc(100vh - 80px)",b.style.position="sticky",b.style.top="8px",b.style.flexDirection="column",b.style.display=e?"flex":"none",N()}le(),b?.style.display!=="none"&&P&&Se(P,!0),(re?.placement??"right")==="left"?(b&&q.appendChild(b),q.appendChild($)):(q.appendChild($),b&&q.appendChild(b));const Le=f.ownerDocument.createElement("div");Object.assign(Le.style,{position:"sticky",top:"0",display:"flex",flexDirection:"column",paddingLeft:oe,paddingRight:oe,paddingTop:oe,zIndex:"1",background:h.menuBg}),Ge.appendChild(pe),Ge.appendChild(W),Le.appendChild(Ge),Le.appendChild(ee),f.appendChild(Le),f.appendChild(q);function qe(){ee.innerHTML="";const e=c.plotMode??"hardBin",t=!Te&&hn.has(e),n=R.filter(g=>g!=null),o=n.find(g=>g.isLotStack),d=Ei(n.map(g=>({metadata:g.wafer.metadata??void 0})),o?{lotSize:o.lotSize??n.length,aggrMethod:o.aggrMethod}:void 0),l=e==="metadata",a=c.activeMetadataKey,r=t&&!l?Wn(n,g=>(e==="softBin"?g.sbin:g.hbin)??void 0,An):{counts:new Map,total:0,pass:0},i=t&&!l?c.binColors??fe():void 0,s=i?e==="softBin"?i.pass.soft:i.pass.hard:new Set,u=mi(r.counts.entries(),s).map(([g])=>g),m=t&&l&&a?Wn(n,g=>Oo(g.metadata?.[a])):{counts:new Map,total:0,pass:0},M=l?Nt()?.values:void 0,D=t&&l?(M??[...m.counts.keys()].sort(St)).filter(g=>m.counts.has(g)):[];if(pe.innerHTML="",d&&pe.appendChild(d),pe.style.display=d?"flex":"none",!u.length&&!D.length){ee.style.display="none";return}ee.style.display="flex";const x=f.ownerDocument.createElement("div");Object.assign(x.style,{display:"flex",flexWrap:"wrap",alignItems:"center",gap:`${w.sm} ${w.xl}`,maxHeight:"86px",overflowY:"auto",overflowX:"hidden"}),ee.appendChild(x);const y=c.highlightBin,B=R.flatMap(g=>g?.metadataFields??[]).find(g=>g.key===a),j=l?B?.label??(a?Li(a):"Metadata"):No[e],U=f.ownerDocument.createElement("span");if(U.textContent=j,Object.assign(U.style,{fontSize:L.body,fontWeight:"700",letterSpacing:Ho,textTransform:"uppercase",color:h.label,flexShrink:"0"}),x.appendChild(U),!l&&r.total>0){const g=r.pass,F=g/r.total*100,te=f.ownerDocument.createElement("span");te.textContent=`Yield ${et(F)}`,Object.assign(te.style,{fontSize:L.body,fontWeight:"700",color:h.value,whiteSpace:"nowrap",flexShrink:"0"});const ne=f.ownerDocument.createElement("span");ne.textContent=`${g.toLocaleString()} / ${r.total.toLocaleString()} dies`,Object.assign(ne.style,{fontSize:L.body,color:h.label,whiteSpace:"nowrap",flexShrink:"0"}),x.appendChild(te),x.appendChild(ne)}if(l){const g=c.highlightMetadataValue;D.forEach((F,te)=>{const ne=g===F,Xe=B?.values?.find(vt=>vt.value===F),Mo=Xe?.color??Po(te),mn=m.counts.get(F)??0;$n(x,{color:Mo,isActive:ne,label:Xe?.label??F,count:mn,percent:m.total>0?mn/m.total*100:void 0,onClick:()=>{const vt=c.highlightMetadataValue===F?void 0:F;T({highlightMetadataValue:vt})}})});return}const bt=e==="softBin"?R.flatMap(g=>g?.sbinDefs??[]):R.flatMap(g=>g?.hbinDefs??[]),un=new Set,yt=[];for(const g of bt)un.has(g.bin)||(un.add(g.bin),yt.push(g));const wt=yt.length>0?new Map(yt.map(g=>[g.bin,g])):null,fn=i??c.binColors??fe(),So=e==="softBin"?fn.soft:fn.hard,pn=g=>So.get(g)??Ao;for(const g of u){const F=y===g,te=wt?.get(g),ne=r.counts.get(g)??0;$n(x,{color:pn(g),isActive:F,label:te?.name?`${g} \xB7 ${te.name}`:`Bin ${g}`,count:ne,percent:r.total>0?ne/r.total*100:void 0,onClick:()=>{const Xe=c.highlightBin===g?void 0:g;T({highlightBin:Xe})}})}r.total>0&&u.length>1&&ee.appendChild(Hi(f.ownerDocument,[...r.counts.entries()].sort(([,g],[,F])=>F-g).map(([g,F])=>({color:pn(g),count:F,label:wt?.get(g)?.name?`${g} \xB7 ${wt.get(g).name}`:`Bin ${g}`})),r.total))}function Re(e){const t=v.filter(r=>r!==null);if(!t.length)return[];const n=t.map(r=>r.dies.filter(Pi)),o=t[0].wafer,d=t.length,l=o.metadata?{...o,metadata:(({wafer:r,waferId:i,...s})=>s)(o.metadata)}:o;function a(r,i){return{...r,stats:{...r.stats,isLotStack:!0,aggregationMethod:i,lotSize:d}}}if(e==="stackedValues"){const r=ve();let i=r?.filter(Ct);if(r!==void 0&&i?.length===0)return[];if(r?.length||(i=Do(t.flatMap(m=>m.dies)).map(m=>({testNumber:m,name:Ri(void 0,m)}))),!i?.length)return[];const s=c.aggregationMethod??"mean";return i.map(u=>{const m=hi(n,s,u.testNumber),M={testNumber:0,name:u.name,unit:u.unit,...Wi(u)};return{wafer:l,dies:m,testDefs:[M],label:`${Ii(u,u.testNumber)} \xB7 ${s}`,isLotStack:!0,aggrMethod:s,lotSize:d,statsSummary:a(Je({wafer:l,dies:m,testDefs:[M]},{testNumbers:[0]}),s)}})}if(e==="stackedBins"){let r=Ye(t.map(i=>i?.hbinDefs));return(!r||r.length===0)&&(r=[...new Set(t.flatMap(s=>s.dies.map(u=>u.hbin).filter(u=>u!=null)))].sort((s,u)=>s-u).map(s=>({bin:s,name:`Bin ${s}`}))),r.map(i=>{const s=kn(n,i.bin,"hard"),u=[{bin:i.bin,name:i.name}];return{wafer:l,dies:s,hbinDefs:u,label:`${i.bin} \xB7 ${i.name}`,isLotStack:!0,aggrMethod:"countBin",lotSize:d,statsSummary:a(Je({wafer:l,dies:s,hbinDefs:u}),"countBin")}})}if(e==="stackedSoftBins"){let r=Ye(t.map(i=>i?.sbinDefs));return(!r||r.length===0)&&(r=[...new Set(t.flatMap(s=>s.dies.map(u=>u.sbin).filter(u=>u!=null)))].sort((s,u)=>s-u).map(s=>({bin:s,name:`Bin ${s}`}))),r.map(i=>{const s=kn(n,i.bin,"soft"),u=[{bin:i.bin,name:i.name}];return{wafer:l,dies:s,sbinDefs:u,label:`${i.bin} \xB7 ${i.name}`,isLotStack:!0,aggrMethod:"countBin",lotSize:d,statsSummary:a(Je({wafer:l,dies:s,sbinDefs:u}),"countBin")}})}return t}function mt(e){const t=v.length;return e==="stackedBins"||e==="stackedSoftBins"?{valueRange:[0,t],lotSize:t}:e==="stackedValues"?{aggregationMethod:c.aggregationMethod??"mean",valueRange:void 0,lotSize:void 0}:{}}function T(e,{fireCallback:t=!0}={}){const n=Object.keys(e),o=c.plotMode,d=we()!==null;c={...c,...e};const l=c.plotMode,a=be.has(l),r=o!==void 0&&be.has(o),i=He>0;if("binColorScheme"in e||"useDefinedBinColors"in e){const u=fe();c={...c,binColors:u},e={...e,binColors:u}}if(e.plotMode!==void 0)if(a){const u=mt(l);if(c={...c,...u},i)for(const m of S)m&&m.setOptions(e);else Z(Re(l))}else if(r){const{valueRange:u,lotSize:m,aggregationMethod:M,...D}=c;if(c=D,i)for(const x of S)x&&x.setOptions(e);else Z(v.filter(x=>x!==null))}else for(const u of S)u&&u.setOptions(e);else if(e.aggregationMethod!==void 0&&l==="stackedValues")if(i)for(const u of S)u&&u.setOptions(e);else Z(Re("stackedValues"));else for(const u of S)u&&u.setOptions(e);we()!==null!==d&&Et(),qe(),qt(),Gt(),jt();const s=e.plotMode!==void 0&&e.plotMode!==o;(xi.some(u=>u in e)||s)&&N(),Be(),Ut(),Xt(),st(),lt(),t&&p.onViewOptionsChange?.(Bn(c),n,vi(n))}function rn(e,t,n){const o=e.createElement("div");Object.assign(o.style,{display:"flex",alignItems:"center",gap:w.xs,flex:"1",minWidth:"0"});const d=e.createElement("span");d.textContent=t,Object.assign(d.style,{fontWeight:"700",fontSize:L.sub,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}),o.appendChild(d);const l=Rn(n??{});let a=null;if(l.length>0){const r=e.createElement("span");Object.assign(r.style,{fontSize:L.body,lineHeight:Ze.none,color:h.label,flexShrink:"0"}),r.textContent="\u25BE",o.appendChild(r),Object.assign(o.style,{cursor:"pointer",borderRadius:z.control}),o.addEventListener("mouseenter",()=>{o.style.background=h.bgHover}),o.addEventListener("mouseleave",()=>{o.style.background="none"}),a=e.createElement("div"),a.dataset.wmapCardMetaPanel="1",Object.assign(a.style,{position:"absolute",top:"0",left:"0",right:"0",zIndex:bn,background:h.menuBg,borderBottom:`1px solid ${h.menuBorder}`,boxShadow:$e.menu,padding:`${w.md} ${w.lg}`,fontSize:L.body,display:"none"});const i=Ln(n??{});i&&a.appendChild(i),o.setAttribute("aria-expanded","false"),o.setAttribute("aria-label",`Wafer info for ${t||"this card"}. Click to expand.`),Cn(o,s=>{r.textContent=s?"\u25B4":"\u25BE",o.setAttribute("aria-expanded",String(s)),a&&(a.style.display=s?"block":"none")})}return{wrap:o,metaPanel:a}}function dn(e,t,n){const o=e.box.querySelector("[data-wmap-window-title]"),d=Rn(n??{});if(!o||d.length===0)return;const l=o.parentElement,a=f.ownerDocument.createElement("div");Object.assign(a.style,{display:"flex",alignItems:"center",gap:w.xs,flex:"1",minWidth:"0",cursor:"pointer"}),xt(a,"bare"),l?.insertBefore(a,o),a.appendChild(o);const r=f.ownerDocument.createElement("span");Object.assign(r.style,{fontSize:L.body,lineHeight:Ze.none,color:h.label,flexShrink:"0"}),r.textContent="\u25BE",a.appendChild(r);const i=f.ownerDocument.createElement("div");i.dataset.wmapCardMetaPanel="1",Object.assign(i.style,{position:"absolute",top:"0",left:"0",right:"0",zIndex:bn,background:h.menuBg,borderBottom:`1px solid ${h.menuBorder}`,boxShadow:$e.menu,padding:`${w.md} ${w.lg}`,fontSize:L.body,display:"none"});const s=Ln(n??{});s&&i.appendChild(s),e.contentWrap.style.position="relative",e.contentWrap.appendChild(i),a.setAttribute("aria-expanded","false"),a.setAttribute("aria-label",`Wafer info for ${t}. Click to expand.`),Cn(a,u=>{r.textContent=u?"\u25B4":"\u25BE",a.setAttribute("aria-expanded",String(u)),i.style.display=u?"block":"none"})}function gt(e,t,n){const o=f.ownerDocument.createElement("div");o.className="wmap-gallery-card",Object.assign(o.style,{background:h.menuBg,border:`1px solid ${h.menuBorder}`,borderRadius:z.container,boxShadow:$e.panel,overflow:"hidden",display:"flex",flexDirection:"column",position:"relative",aspectRatio:"1",maxWidth:ut(),maxHeight:ut()});const d=f.ownerDocument.createElement("div");Object.assign(d.style,{display:"flex",alignItems:"center",padding:`${w.md} ${w.lg} ${w.sm}`,borderBottom:`1px solid ${h.menuBorder}`,flexShrink:"0",gap:w.sm});const{wrap:l,metaPanel:a}=rn(document,Qe(e,t),e.wafer.metadata??void 0);d.appendChild(l);const r=f.ownerDocument.createElement("button");r.dataset.wmapExpandBtn="1",r.setAttribute("aria-label","Open full view"),Sn(r),r.innerHTML=We.expand,Object.assign(r.style,{display:"flex",alignItems:"center",justifyContent:"center",border:`1px solid ${h.menuBorder}`,borderRadius:z.control,background:h.panelBg,color:h.label,padding:w.xxs,cursor:"pointer",flexShrink:"0",width:"22px",height:"22px"}),xt(r),d.appendChild(r),o.appendChild(d);const i=f.ownerDocument.createElement("div");Object.assign(i.style,{position:"relative",flex:"1",minHeight:"0",overflow:"hidden",display:"flex",flexDirection:"column"}),o.appendChild(i),a&&i.appendChild(a),$.appendChild(o),o.addEventListener("contextmenu",M=>{if(M.defaultPrevented)return;const D=p.insights?.sweeps;if(!yi(e.testDefs,D))return;M.preventDefault();const x=e.viewOptions?{...c,...e.viewOptions}:c,y=wi(e.dies,{waferLabel:Dn(e),testDefs:e.testDefs,isLotStack:e.isLotStack,activeTest:x.plotMode==="value"?x.activeTest:void 0,waferIndex:t}),B={x:M.clientX,y:M.clientY};import("./drilldown.js").then(({openDrilldownMenu:j})=>{o.isConnected&&j(B,o,y,{sweeps:D,onSaveImage:p.onSaveImage})})});const s=Pe||we()!==null,u=e.viewOptions?{...c,...e.viewOptions}:c,m=En(i,e,{viewOptions:{...u,showLegend:s,legendPosition:ye},showTooltip:!0,padding:A,statsSummary:e.statsSummary,onSaveImage:p.onSaveImage,onSaveText:p.onSaveText,onClick:e.onClick,onSelect:e.onSelect,insights:X,onExpand:()=>Ie(t,e),showIdentity:!1,chromeInset:Vo});return m.setViewControlsVisible(!1),m.setSummaryVisible(!1),r.onclick=()=>Ie(t,e),{card:o,ctrl:m,canvasWrapper:i,expandBtn:r}}function yo(e){const t=de[e];if(!t)return;const n=[..._.values()].find(o=>o.cardIndex===e);n?(t.innerHTML=We.minimize,t.setAttribute("aria-label","Reattach to gallery"),t.onclick=()=>vo(n.id)):(t.innerHTML=We.expand,t.setAttribute("aria-label","Open full view"),t.onclick=()=>Ie(e,R[e]))}function Z(e){xo(),Me()?.remove(),De(null),it(),R=[];for(const i of S)i&&i.destroy();S=[],ae=[],de=[],He=0,$.innerHTML="",on=e.length,an(e.map(i=>typeof i=="function"?null:i));const t=[];for(let i=0;i<e.length;i++){const s=e[i];if(typeof s=="function"){const u=f.ownerDocument.createElement("div");u.className="wmap-gallery-card",Object.assign(u.style,{background:h.menuBg,border:`1px solid ${h.menuBorder}`,borderRadius:z.container,aspectRatio:"1",display:"flex",alignItems:"center",justifyContent:"center"});const m=f.ownerDocument.createElement("span");m.textContent="\u2026",Object.assign(m.style,{color:h.label,fontSize:"18px"}),u.appendChild(m),$.appendChild(u),R.push(null),S.push(null),ae.push(null),de.push(null),t.push({index:i,factory:s,placeholder:u}),He++}else{const{ctrl:u,canvasWrapper:m,expandBtn:M}=gt(s,i,e.length);R.push(s),S.push(u),ae.push(m),de.push(M)}}_t(),qe(),st(),lt();const n=++xe,o=()=>{setTimeout(()=>{n===xe&&p.onItemsResolved?.()},0)},d=i=>{setTimeout(()=>{n===xe&&p.onItemResolved?.(i,e.length)},0)};let l=e.length-t.length;l>0&&d(l);let a=0;function r(){if(n!==xe)return;if(a>=t.length){if(be.has(c.plotMode)){const B=c.plotMode;Z(Re(B));return}ke=o,N(),ue||(ke=null,o());return}const{index:i,factory:s,placeholder:u}=t[a++],m=s();R[i]=m,v[i]=m,an([m]);const{card:M,ctrl:D,canvasWrapper:x,expandBtn:y}=gt(m,i,e.length);S[i]=D,ae[i]=x,de[i]=y,He--,u.replaceWith(M),d(++l),no(),to(),!b&&!re?.placement&&m.statsSummary?.findings.length&&(b=Mt("right",oe,f.ownerDocument),b.style.maxHeight="calc(100vh - 80px)",b.style.position="sticky",b.style.top="8px",b.style.flexDirection="column",b.style.display="none",(re?.placement??"right")==="left"?q.insertBefore(b,$):q.appendChild(b),N(),P||(P=Q("findings","Summary panel",()=>{if(!b)return;const j=b.style.display!=="none";j||N(),b.style.display=j?"none":"flex",Se(P,!j),le()}),W.appendChild(G()),W.appendChild(P)),le()),le(),setTimeout(r,0)}t.length>0?setTimeout(r,0):o()}if(be.has(c.plotMode)&&v.length>0){const e=mt(c.plotMode);c={...c,...e},Z(Re(c.plotMode))}else Z(C);Be();let he=0;const cn=new(f.ownerDocument.defaultView??window).ResizeObserver(()=>{if(he)return;he=(f.ownerDocument.defaultView??window).requestAnimationFrame(()=>{he=0,k==null&&pt()})});cn.observe($),b&&N();function wo(e,t){const n=ae[e];if(!n)return;n.innerHTML="",Object.assign(n.style,{alignItems:"center",justifyContent:"center"});const o=f.ownerDocument.createElement("span");o.textContent=t?"Opened in its own window":"Opened in the wafer viewer",Object.assign(o.style,{color:h.label,fontSize:L.body,textAlign:"center",padding:"0 12px"}),n.appendChild(o)}function Ie(e,t){for(const a of _.values())if(a.cardIndex===e)return;const n=Qe(t,e),o=Fn++,d=S[e]?.getOptions(),l=qo(n);if(l){const a=l.document;a.title=n,Object.assign(a.documentElement.style,{height:"100%"}),Object.assign(a.body.style,{margin:"0",height:"100vh",overflow:"hidden",display:"flex",flexDirection:"column",fontFamily:L.family}),Zo(f,a.documentElement);const r=Qo(f,a.documentElement,()=>x.setOptions({})),i=a.createElement("div");i.dataset.wmapWindowBanner="1",i.textContent=n,Object.assign(i.style,{display:"none",padding:`${w.sm} ${w.xl}`,fontSize:L.body,fontWeight:"700",background:h.warnBg,color:h.warnText,borderBottom:`1px solid ${h.warnBorder}`,flexShrink:"0"}),a.body.appendChild(i);const s=a.createElement("div");Object.assign(s.style,{flex:"1",minHeight:"0",display:"flex",flexDirection:"column"}),a.body.appendChild(s);const{wrap:u,metaPanel:m}=rn(a,n,t.wafer.metadata??void 0),M=a.createElement("div");Object.assign(M.style,{display:"flex",alignItems:"center",padding:`${w.md} ${w.lg} ${w.sm}`,borderBottom:`1px solid ${h.menuBorder}`,flexShrink:"0",gap:w.sm}),M.appendChild(u),s.appendChild(M);const D=a.createElement("div");Object.assign(D.style,{position:"relative",flex:"1",minHeight:"0",overflow:"hidden",display:"flex",flexDirection:"column"}),m&&D.appendChild(m),s.appendChild(D);const x=ht(D,t,void 0,d),y=setInterval(()=>{l.closed&&Ue(o)},400);l.addEventListener("pagehide",()=>Ue(o)),_.set(o,{id:o,ctrl:x,cardIndex:e,label:n,closePollId:y,stopThemeSync:r,close:()=>{l.closed||l.close()},setTitle:B=>{a.title=B,i.textContent=B,i.style.display="block"}})}else{const a=Uo({title:n,onClose:()=>Ue(o),anchor:f});a.contentWrap.style.flexDirection="column",dn(a,n,t.wafer.metadata??void 0);const r=ht(a.contentWrap,t,void 0,d);_.set(o,{id:o,ctrl:r,cardIndex:e,label:n,closePollId:null,close:()=>a.close(),setTitle:i=>{const s=a.box.querySelector("[data-wmap-window-title]");s&&(s.textContent=i,s.title=i)}})}S[e]?.destroy(),S[e]=null,wo(e,l!==null),yo(e)}function ht(e,t,n,o){const d=t.viewOptions?{...c,...t.viewOptions}:c,l=o?{...d,...o}:d,r={...n!==void 0?{...l,plotMode:"value",activeTest:n}:l,showLegend:!0,legendPosition:ye},i=En(e,t,{viewOptions:r,showTooltip:!0,padding:A,statsSummary:t.statsSummary,onSaveImage:p.onSaveImage,onSaveText:p.onSaveText,onClick:t.onClick,onSelect:t.onSelect,insights:X,showExpandButton:!1,showIdentity:!1});return i.setViewControlsVisible(!0),i.setSummaryVisible(!0),i.setExpandVisible(!1),i}function Ue(e){const t=_.get(e);if(!t||(_.delete(e),t.closePollId!=null&&clearInterval(t.closePollId),t.stopThemeSync?.(),t.ctrl.destroy(),t.cardIndex===null))return;const n=t.cardIndex,o=R[n];if(!o)return;const{card:d,ctrl:l,canvasWrapper:a,expandBtn:r}=gt(o,n,R.length);ae[n]?.parentElement?.replaceWith(d),S[n]=l,ae[n]=a,de[n]=r}function vo(e){const t=_.get(e);t&&(t.close(),Ue(e))}function xo(){for(const e of _.values())e.cardIndex!==null&&(e.cardIndex=null,e.setTitle(`${e.label} \u2014 unlinked from gallery`))}function Co(){const e=[...$.querySelectorAll("canvas")];if(!e.length)return;const t=e.length,n=Math.ceil(Math.sqrt(t)),o=Math.ceil(t/n),d=e[0].width,l=e[0].height,a=8,r=(f.ownerDocument.defaultView??window).devicePixelRatio||1,i=Math.round(26*r),s=Math.round(12*r),u=f.ownerDocument.createElement("canvas");u.width=n*d+(n-1)*a,u.height=o*(l+i)+(o-1)*a;const m=u.getContext("2d"),M=Fo($);m.fillStyle=M.background,m.fillRect(0,0,u.width,u.height),e.forEach((D,x)=>{const y=x%n,B=Math.floor(x/n),j=y*(d+a),U=B*(l+i+a),bt=D.closest(".wmap-gallery-card")?.querySelector("span")?.textContent??"";m.fillStyle=M.surface,m.fillRect(j,U,d,i),m.fillStyle=M.text,m.font=`700 ${s}px system-ui, sans-serif`,m.textAlign="left",m.textBaseline="middle",m.fillText(bt,j+Math.round(10*r),U+i/2,d-Math.round(20*r)),m.drawImage(D,j,U+i)}),u.toBlob(D=>{if(!D)return;if(p.downloadFilename!=null){vn(D,p.downloadFilename,p.onSaveImage);return}const x=S.find(y=>y!=null)?.getExportTitle();vn(D,["gallery",x].filter(Boolean).join(" "),Fe.onSaveImage)})}return{setItems(e){v=e.map(n=>typeof n=="function"?null:n);const t=c.plotMode;if(be.has(t))if(e.some(o=>typeof o=="function"))Z(e);else{const o=mt(t);c={...c,...o},Z(Re(t))}else Z(e)},setOptions(e){T(e,{fireCallback:!1})},getOptions(){return Bn(c)},setFindingsNotice(e){It=e,N()},setColumns(e){ln(e)},getBinColors(){return c.binColors??fe()},setLotStatsSummary(e){V=e,Be(),b&&N(),le()},openUserGuide:Zt,destroy(){xe++,ue?.cancel(),ue=null,ke=null;for(const e of[..._.values()])e.closePollId!=null&&clearInterval(e.closePollId),e.close(),e.ctrl.destroy();_.clear();for(const e of S)e&&e.destroy();S=[],Me()?.remove(),cn.disconnect(),he&&((f.ownerDocument.defaultView??window).cancelAnimationFrame(he),he=0),f.ownerDocument.removeEventListener("click",je,!0),window.removeEventListener("blur",Rt),ie(),yn(),Le.remove(),q.remove(),b?.remove(),me?.destroy()}}}
1
+ import{getUniqueTestNumbers as Ro,resolveTestNumber as Wo,findTestDef as Io,collectMetadataValues as $o}from"../renderer/buildView.js";import{metadataCategoricalValue as Ao}from"../core/metadata.js";import{resolveBinColorsForMaps as Po,mergeBinDefs as Ze,binColorWarning as Fo,mixedPassBinsWarning as Ho,binColorsEqual as jo}from"../renderer/binColors.js";import{itemPassBins as Vo,INPUT_DEFAULT_PASS_BINS as No}from"../core/passBins.js";import{NO_DATA_FILL as zo}from"../renderer/colorMap.js";import{metadataValueColor as _o}from"../renderer/colorMap.js";import{resolveCanvasTheme as Ko}from"./canvasTheme.js";import{ICONS as $e}from"./icons.js";import{SHADOW as Ae,LEADING as Qe,TRACKING as Go,controlStyle as qo,wireControlHover as Mt,SPACE as w,EDGE_GUTTER as oe,MAP_CHROME_INSET as Uo,RADIUS as z,FONT as T,CLR as g,sevColor as vn,MODE_LABELS as Xo,BIN_LEGEND_MODES as xn,STACKED_MODES as be,Z_ABOVE as Cn,applyOverlayZ as Yo,getTooltip as Zo,hideTooltip as Sn,createToolbarHelpers as Qo,buildModeMenuEl as Jo,openDetachWindow as ei,openFloatingWindow as ti,openModal as ni,openReportModal as oi,copyWmapThemeTokens as ii,syncWmapPopupTheme as li,openUserGuideWindow as si,makePaletteBtn as ai,makeLogScaleBtn as ri,makeLegendStyleBtn as di,makeOverlaysBtn as ci,makeOrientationBtn as ui,menuLayerFor as Mn,saveImageBlob as fi,markMenuTrigger as Pe,wireMenuA11y as Dn,wireExpandToggle as En,wireTooltip as kn,requestedPassFailDisplay as Bn,overlayMenuRows as pi,anyOverlayActive as mi,logWmapVersionOnce as gi,buildDataModeEntries as hi,metadataKeyHasData as yi,metadataModeEntry as bi}from"./toolbar.js";import{waferDisplayLabel as Je,waferIdentityLabel as On}from"../core/waferLabel.js";import{metadataDisplayValue as wi}from"../core/metadata.js";import{withExportContext as vi}from"./exportName.js";import{sortBinsForDisplay as xi}from"../stats/binPareto.js";import{diePassStatus as Ci}from"../core/dies.js";import{aggregateValues as Si,aggregateBinCounts as Tn}from"../core/aggregates.js";import{renderWaferMap as Mi,renderWaferMapCard as Ln,toPublicViewOptions as Rn}from"./renderWaferMap.js";import{hasDrilldownTargets as Di,waferPopulation as Ei}from"./chartPopulation.js";import{classifyChanged as ki,COLOR_KEYS as Bi,findingBin as Oi}from"./renderWaferMap.js";import{findingPatternKey as Wn}from"../stats/filterFindings.js";import{buildWaferMap as Ti,getTestPassStatus as In,isParametricTest as Dt,getDieTestValue as Li}from"../renderer/buildWaferMap.js";import{analyzeWaferMap as et}from"../stats/analyzeWaferMap.js";import{collectWarnings as Ri,buildWarningsMenuEl as Wi,severityOf as Ii}from"./warnings.js";import{asList as $n,compareNatural as Et,arrayEqual as An,toggleHighlight as Pn}from"../core/utils.js";import{createSummaryPanelEl as kt,buildMetadataStripRow as $i,buildCompactMetadataRows as Fn,metadataEntries as Hn,renderLotSummaryContentSteps as Ai,reportMapsFromItems as Pi}from"./summaryPanel.js";import{renderLotReportHtml as Fi}from"../stats/renderSummaryReport.js";import{prettyKey as Hi}from"../stats/facets.js";import{testLabel as ji,markedTestLabel as Vi,derivedFields as Ni}from"../renderer/testLabel.js";import{mergeTestDefs as zi}from"../stats/mergeTestDefs.js";import{getDieKey as _i,hasPosition as Ki}from"../core/dies.js";import{testValue as Gi}from"../core/dieTable.js";import{runChunked as qi}from"./chunked.js";function jn(f){if(typeof f!="number"||!Number.isFinite(f))return;const C=Math.round(f);return C>=1?C:void 0}const Bt=12;function Ui(f,C,p){let A=C;if(C.length>Bt){const S=C.slice(0,Bt-1),W=C.slice(Bt-1),F=W.reduce((X,ie)=>X+ie.count,0);A=[...S,{color:g.label,count:F,label:`Other (${W.length} bins)`}]}const E=f.createElement("div");Object.assign(E.style,{display:"flex",columnGap:"1px",width:"100%",height:"8px",borderRadius:z.control,overflow:"hidden",border:`1px solid ${g.menuBorder}`,boxSizing:"border-box",marginTop:w.xs,flexShrink:"0"}),E.setAttribute("role","img"),E.setAttribute("aria-label",`Population split: ${A.map(S=>`${S.label} ${tt(S.count/p*100)}`).join(", ")}`);for(const S of A){const W=S.count/p*100,F=f.createElement("div");Object.assign(F.style,{flex:`${W} 1 0`,minWidth:W>0?"2px":"0",background:S.color}),kn(F,`${S.label} \xB7 ${S.count.toLocaleString()} dies \xB7 ${tt(W)}`),E.appendChild(F)}return E}function tt(f){return f>0&&f<.1?"<0.1%":`${f.toFixed(1)}%`}function Vn(f,C,p){const A=new Map;let E=0,S=0;for(const W of f){const F=p?new Set(p(W)):void 0;for(const X of W.dies){if(X.partial||X.edgeExcluded)continue;const ie=C(X);ie!==void 0&&(A.set(ie,(A.get(ie)??0)+1),E++,F&&Ci(X,F)&&S++)}}return{counts:A,total:E,pass:S}}function Nn(f,C){const p=f.ownerDocument.createElement("div");Object.assign(p.style,{display:"flex",alignItems:"center",gap:"5px",cursor:"pointer",userSelect:"none",padding:`${w.xxs} ${w.xs}`,borderRadius:z.control});const A=f.ownerDocument.createElement("span");Object.assign(A.style,{display:"inline-block",width:"13px",height:"13px",flexShrink:"0",background:C.color,border:C.isActive?`2px solid ${g.iconActive}`:`1px solid ${g.menuBorder}`,borderRadius:z.control,boxSizing:"border-box"});const E=f.ownerDocument.createElement("span");if(E.textContent=C.label,Object.assign(E.style,{fontWeight:C.isActive?"700":"400",color:C.isActive?g.iconActive:g.text,whiteSpace:"nowrap"}),p.appendChild(A),p.appendChild(E),C.count!==void 0){const S=f.ownerDocument.createElement("span");if(S.textContent=C.count.toLocaleString(),Object.assign(S.style,{color:C.isActive?g.iconActive:g.text,fontWeight:C.isActive?"700":"400",whiteSpace:"nowrap"}),p.appendChild(S),C.percent!==void 0){const W=f.ownerDocument.createElement("span");W.textContent=tt(C.percent),Object.assign(W.style,{color:g.label,whiteSpace:"nowrap"}),p.appendChild(W)}}p.setAttribute("role","button"),p.setAttribute("aria-pressed",C.isActive?"true":"false"),p.tabIndex=0,p.addEventListener("mouseenter",()=>{p.style.background=g.bgHover}),p.addEventListener("mouseleave",()=>{p.style.background="transparent"}),p.addEventListener("focus",()=>{p.style.background=g.bgHover}),p.addEventListener("blur",()=>{p.style.background="transparent"}),p.addEventListener("click",S=>C.onClick(S.ctrlKey||S.metaKey)),p.addEventListener("keydown",S=>{(S.key==="Enter"||S.key===" ")&&(S.preventDefault(),C.onClick(S.ctrlKey||S.metaKey))}),f.appendChild(p)}export function renderWaferGallery(f,C,p={}){gi();const A=6;let E=jn(p.columns);const S=p.showHelpButton??!1,W=p.userGuideExtension,F=p.insights?.enabled??!1,X=p.insights?.sweeps?{sweeps:p.insights.sweeps}:void 0,ie=Yo(p.zIndex),de=p.summaryPanel,zn=e=>[...Vo(e)],Ot=()=>v.flatMap(e=>e?[e.ringCount??4]:[]),nt=()=>Ot()[0]??4;function _n(e){const t=[...new Set(e)].sort((n,o)=>n-o);return t.length<2?null:{code:"ring-count-mixed",severity:"warning",message:`These wafers were built with different ring counts (${t.join(", ")}). Each card and each wafer's findings use their own; the lot's ring yield in the Summary panel, report and Insights uses ${e[0]} rings.`}}let N=p.lotStatsSummary,we=p.viewOptions?.legendPosition??"default",Fe=p.perCardLegend??!1;function ve(){const e=c.plotMode??"hardBin";return xn.has(e)?null:c.colorbarRangeMode==="data"?"Each map has its own value range, so it keeps its own colour bar":"These wafers have no shared colour bar for value mode, so each map keeps its own"}function Tt(){const e=Fe||ve()!==null;for(const t of M)t&&t.setOptions({showLegend:e})}let c={plotMode:"hardBin",showDieLabels:!1,showRingBoundaries:!1,showQuadrantBoundaries:!1,rotation:0,flipX:!1,flipY:!1,...p.viewOptions},M=[],le=[],ce=[],L=[];const He=vi(()=>{const e=L.filter(n=>n!=null),t=[...new Set(e.map(n=>wi(n.wafer.metadata?.lot)).filter(n=>n!==void 0))].sort(Et);return{prefix:p.downloadFilename,lots:t,...e.length===1?{wafer:On(e[0])}:{waferCount:e.length}}},p.onSaveImage,p.onSaveText);let v=C.map(e=>typeof e=="function"?null:e);function Lt(){return zi(v)}function xe(){if(v.some(e=>e?.testDefs?.length))return Lt().defs}let Ce=0,je=0;const _=new Map;let Kn=0,P=null,se=null,Rt=new Set,y=null,Gn={};function Wt(e){return v[e]?.statsSummary??N?.perWafer.find(t=>t.waferIndex===e)?.summary}function ot(){return!!(v.some(e=>e?.statsSummary?.findings.length)||N?.perWafer.some(e=>e.summary.findings.length))}const qn=Zo(),ue=Qo(qn),{makeBtn:Q,setActive:Se,makeSep:K,makeMenuRow:Un,makeMenuSection:Xn,makeDropdown:It,closeOpenMenu:Ve,getOpenMenu:Me,setOpenMenu:De}=ue;f.ownerDocument.addEventListener("click",Ve,!0);const $t=()=>Sn();window.addEventListener("blur",$t);let At=p.findingsNotice;function Pt(e){Rt=new Set(e);const t=[...$.querySelectorAll(".wmap-gallery-card")];let n;t.forEach((o,d)=>{const s=Rt.has(d);o.style.outline=s?`3px solid ${g.findingHighlight}`:"",o.style.outlineOffset=s?"-3px":"",s&&n===void 0&&(n=o)}),n?.scrollIntoView?.({behavior:"smooth",block:"nearest"})}function Ft(){Pt([])}let it=!1;function Ht(){it=!0;for(const e of M)e&&e.clearSelection();it=!1}function jt(e){return t=>{!it&&se!==null&&(ke(),H()),e.onSelect?.(t)}}function lt(e,t){const n=new Set(e),o=t??M.map((d,s)=>s);for(const d of o){const s=L[d],l=M[d];if(!s||!l)continue;const a=s.dies.filter(i=>n.has(_i(i)));l.setSelection(a)}}function Yn(){const e=[];for(let t=0;t<v.length;t++){const n=v[t];if(!n)continue;const o=Wt(t)?.findings??[];o.length&&e.push({index:t,item:n,unusualCount:o.filter(d=>d.severity==="unusual").length,notableCount:o.filter(d=>d.severity==="notable").length,totalCount:o.length})}return e}function Zn(e){const t=L[e]??v[e];t&&Ie(e,t)}function Qn(e){const t=Wt(e)?.findings??[];if(t.length)return{total:t.length,unusual:t.filter(n=>n.severity==="unusual").length,notable:t.filter(n=>n.severity==="notable").length}}function Jn(){oi(Fi(Pi(v,No,nt())),{anchor:f})}function eo(){if(!y)return;y.innerHTML="";const e=Yn();if(v.length>0){const n=f.ownerDocument.createElement("div"),o=e.length,d=v.filter(Boolean).length;n.textContent=o===0?`No findings on any of the ${d} wafers`:`${o} of ${d} wafer${d===1?"":"s"} with findings`,Object.assign(n.style,{fontSize:T.body,color:g.label,marginBottom:w.md}),y.appendChild(n)}if(e.length>0){const n=f.ownerDocument.createElement("button");n.type="button",n.textContent="Summary report",Object.assign(n.style,{...qo("outlined"),marginBottom:w.lg,display:"block",width:"100%",textAlign:"left"}),Mt(n),n.addEventListener("click",Jn),y.appendChild(n)}if(e.length===0){const n=f.ownerDocument.createElement("div");Object.assign(n.style,{color:g.icon,fontSize:T.body,padding:"4px 0"}),n.textContent="No findings on any wafer.",y.appendChild(n)}else for(const{index:n,item:o,unusualCount:d,notableCount:s,totalCount:l}of e){const a=d?"unusual":s?"notable":"info",i=d+s||l,r=f.ownerDocument.createElement("button");r.type="button",Object.assign(r.style,{display:"flex",alignItems:"center",justifyContent:"space-between",width:"100%",padding:"5px 8px",marginBottom:w.xs,border:"none",borderLeft:`3px solid ${vn(a)}`,borderRadius:z.control,background:g.bgHover,cursor:"pointer",fontSize:T.body,textAlign:"left",boxSizing:"border-box"}),r.addEventListener("mouseover",()=>{r.style.background=g.bgActive}),r.addEventListener("mouseout",()=>{r.style.background=g.bgHover});const u=f.ownerDocument.createElement("span");u.textContent=Je(o,n),Object.assign(u.style,{color:g.iconHover,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"});const m=f.ownerDocument.createElement("span");m.textContent=String(i),r.setAttribute("aria-label",`${Je(o,n)} \u2014 ${i} finding${i===1?"":"s"}${d?`, ${d} unusual`:""} \u2014 view wafer`),Object.assign(m.style,{marginLeft:w.sm,flexShrink:"0",background:vn(a),color:"#fff",borderRadius:z.container,padding:"1px 5px",fontSize:T.body,fontWeight:"600"}),r.appendChild(u),r.appendChild(m),r.addEventListener("click",()=>Ie(n,o)),y.appendChild(r)}const t=f.ownerDocument.createElement("div");t.style.height="12px",y.appendChild(t)}let fe=null,Ee=null;function H(){if(y)if(fe?.cancel(),fe=null,N){const e=Ze(v.map(n=>n?.hbinDefs)),t=Ze(v.map(n=>n?.sbinDefs));fe=qi(Ai(y,{lotSummary:N,items:v,hbinDefs:e.length?e:void 0,sbinDefs:t.length?t:void 0,testDefs:xe(),ringCount:nt(),binColors:c.binColors,plotMode:c.plotMode??"hardBin",fallbackFormat:c.fallbackFormat,activeFindingId:se,warnings:p.warnings?.display??!0?J:[],findingsFilter:Gn,findingsNotice:At,onFindingsFilterChange:H,onSaveText:He.onSaveText,onFindingClick:(n,o)=>{se===n.id?ke():no(n,o),H()},onWaferClick:Zn,findingsFor:Qn,dieListOptions:p.dieList}),{onDone:()=>{const n=Ee;Ee=null,n?.()}})}else eo()}function to(e){const t=e.highlight;return t?.kind==="wafer"&&t.waferIndices?.length?t.waferIndices:null}let Ne=[];function Vt(){if(Ne.length!==0){for(const e of Ne)M[e]?.setOptions({plotMode:c.plotMode,activeTest:c.activeTest});Ne=[]}}function ke(){se=null,Ft(),Ht(),Vt(),R({highlightBin:void 0},{fireCallback:!1})}function Nt(){se!==null&&(ke(),H())}function no(e,t){if(se===e.id){ke();return}se=e.id,t.style.background=g.bgActive,t.style.fontWeight="600",Vt();const{kind:n,index:o}=e.variable;if(n==="test"){const s=o??0,l=xe();if(l===void 0||l.some(i=>i.testNumber===s))R({plotMode:"value",activeTest:s,highlightBin:void 0},{fireCallback:!1});else{R({highlightBin:void 0},{fireCallback:!1});const r=be.has(c.plotMode??"hardBin")?null:to(e);if(r){for(const u of r)M[u]?.setOptions({plotMode:"value",activeTest:s});Ne=[...r]}}}else R({plotMode:n==="softBin"?"softBin":"hardBin",highlightBin:Oi(e)},{fireCallback:!1});Ft(),Ht();const d=e.highlight;if(d.kind==="wafer"){Pt(d.waferIndices);const s=Wn(e);for(const l of d.waferIndices){const a=d.dieKeysByWafer?void 0:L[l]?.statsSummary?.findings.find(r=>Wn(r)===s),i=d.dieKeysByWafer?.[l]??a?.highlight?.dieKeys;i?.length&&lt(i,[l])}}else d.kind==="bin"?d.dieKeys?.length&&lt(d.dieKeys):(d.kind==="region"||d.kind==="dies")&&d.dieKeys?.length&&lt(d.dieKeys)}function ae(){if(!P)return;const e=!!y;P.style.display=(N||ot())&&e&&!Le?"flex":"none";const t=y?y.style.display!=="none":!1;(N?.hasNotableFindings||v.some(o=>o?.statsSummary?.hasNotableFindings))&&!t?P.style.color=g.findingIndicator:P.dataset.active||(P.style.color=g.icon)}const I=f.ownerDocument.createElement("div");I.dataset.wmapToolbar="gallery",Object.assign(I.style,{flexShrink:"0",marginLeft:"auto",display:"inline-flex",flexDirection:"row",alignItems:"center",gap:"0",background:g.menuBg,border:`1px solid ${g.menuBorder}`,borderRadius:z.control,padding:"0",boxShadow:Ae.panel,flexWrap:"wrap",minWidth:"0",overflowX:"auto"});const zt=()=>{const e=Me();e&&(e.remove(),De(null)),Pe(Y,!1)},Y=Q("mode","Plot mode",()=>{if(Me()){zt();return}const e=v.flatMap(b=>b?.dies??[]),t=xe(),{testEntries:n,binEntries:o,stackedEntries:d}=hi(e,t,{includeStacked:!0}),s=v.filter(Boolean).length,l=b=>{if(b===void 0)return s;let B=0;for(const j of v)j?.dies?.some(U=>In(U,b)!==void 0||Gi(U,b)!==void 0)&&B++;return B},a=s<2?n:n.map(b=>{const B=l(b.activeTest);return B===s?b:{...b,label:`${b.label} \u2014 ${B} of ${s} wafers`}}),i=c.plotMode??"hardBin",r=c.activeTest??0;function u(b){return b.plotMode!==i?!1:b.plotMode==="value"?r===(b.activeTest??0):b.plotMode==="metadata"?c.activeMetadataKey===b.activeMetadataKey:!0}function m(b,B){b.activeTest!==void 0?R({plotMode:"value",activeTest:b.activeTest,activeMetadataKey:void 0,logScale:b.logScale}):b.activeMetadataKey!==void 0?R({plotMode:b.plotMode,activeTest:void 0,activeMetadataKey:b.activeMetadataKey,passFailDisplay:"off"}):R({plotMode:b.plotMode,activeTest:void 0,activeMetadataKey:void 0,passFailDisplay:"off"}),B.remove(),De(null),Pe(Y,!1)}const D=new Set,k=v.flatMap(b=>b?.metadataFields??[]).filter(b=>!D.has(b.key)&&D.add(b.key)).filter(b=>yi(e,b.key)).map(bi),x=Jo(Y.getBoundingClientRect(),a,o,d,u,m,{makeMenuRow:Un,makeMenuSection:Xn},i,Y.ownerDocument.defaultView??window,k);Mn(Y).appendChild(x),De(x),Pe(Y,!0),Dn(x,Y,zt)});Pe(Y,!1);const oo=()=>L.flatMap(e=>e?[...e.hbinDefs??[],...e.sbinDefs??[]]:[]).some(e=>e.color),{btn:io,sync:_t}=ai(ue,()=>({...c,plotMode:c.plotMode??"hardBin"}),oo,e=>R(e));_t();const lo=C.some(e=>typeof e!="function"&&(e.reticles?.length??0)>0);function ze(){const e=xe(),{testNumber:t}=Wo(c.activeTest??0,e);return{testNumber:t,td:Io(e,t)}}function Kt(){if((c.plotMode??"hardBin")!=="value")return!1;const{td:e}=ze();return e!==void 0&&(e.limitLow!==void 0||e.limitHigh!==void 0)}function Be(){if((c.plotMode??"hardBin")!=="value")return!1;const{td:e}=ze();return e!==void 0&&!Dt(e)}function so(){if((c.plotMode??"hardBin")!=="value")return!1;const{testNumber:e,td:t}=ze();return v.some(n=>n?.dies?.some(o=>In(o,e,t)!==void 0))}function ao(e,t){if(!t||!Dt(t))return;const n=t.limitLow!==void 0||t.limitHigh!==void 0;if((Bn(c)==="spec"&&n?"spec":c.colorbarRangeMode??"spec")==="spec"&&n)return;let s=1/0,l=-1/0;for(const a of v)if(a)for(const i of a.dies){const r=Li(i,e);r!==void 0&&(r<s&&(s=r),r>l&&(l=r))}if(isFinite(s))return s===l?[s,s+1]:[s,l]}function st(e,t,n){const o=c[e];if(o===t||o!=null&&t!=null&&n(o,t))return!1;c={...c,[e]:t};for(const d of M)d&&d.setOptions({[e]:t});return!0}function Gt(){if((c.plotMode??"hardBin")!=="metadata")return;const e=c.activeMetadataKey;if(!e)return;const t=new Set;for(const n of v)if(n)for(const o of $o(n.dies,e))t.add(o);return{key:e,values:[...t].sort(Et)}}function at(){st("metadataValueOrder",Gt(),(e,t)=>e.key===t.key&&An(e.values,t.values))}function rt(){if((c.plotMode??"hardBin")!=="value")return;const{testNumber:e,td:t}=ze(),n=ao(e,t);st("valueRange",n?{test:e,range:n}:void 0,(d,s)=>{const l=r=>Array.isArray(r)?{test:void 0,range:r}:{test:r.test,range:r.range},a=l(d),i=l(s);return a.test===i.test&&An(a.range,i.range)})}let dt=!1;function ro(){if(dt)return;dt=!0,(f.ownerDocument.defaultView?.requestAnimationFrame??(t=>setTimeout(()=>t(0),0)))(()=>{dt=!1,rt(),at(),Ut()})}let ct=!1;function co(){if(ct)return;ct=!0,(f.ownerDocument.defaultView?.requestAnimationFrame??(t=>setTimeout(()=>t(0),0)))(()=>{ct=!1,Ue()})}let qt=[];function pe(){const{colors:e,mixedHardBins:t}=Po(v.filter(n=>n!=null),{binColorScheme:c.binColorScheme,useDefinedBinColors:c.useDefinedBinColors});return qt=t,e}function Ut(){st("binColors",pe(),jo),Oe()}const uo=ci(ue,()=>pi(c,lo,{functionalActive:Be(),hasLimits:Kt()&&!Be(),hasRecorded:so()&&!Be(),binMode:(c.plotMode??"hardBin")==="hardBin"||(c.plotMode??"hardBin")==="softBin"},e=>R(e)),()=>mi(c)),{btn:fo,sync:Xt}=di(ue,()=>({plotMode:c.plotMode,legendPosition:we}),e=>{we=e;for(const t of M)t&&t.setOptions({legendPosition:we})},{get:()=>Fe,set:e=>{Fe=e,Tt()},blockedReason:ve});Xt();const po=[{value:"mean",label:"Mean"},{value:"median",label:"Median"},{value:"stddev",label:"Std Dev"},{value:"min",label:"Min"},{value:"max",label:"Max"},{value:"count",label:"Count"}],Yt=It("aggr","Aggregation method",()=>po,()=>c.aggregationMethod??"mean",e=>R({aggregationMethod:e}));function Zt(){const e=c.plotMode==="stackedValues";Yt.style.display=e?"":"none"}Zt();const{btn:mo,sync:Qt}=ri(ue,()=>({...c,functionalActive:Be()}),e=>R(e));Qt();const _e=Q("specRange","Colorbar range: test limits",()=>{const e=c.colorbarRangeMode==="data"?"spec":"data";R({colorbarRangeMode:e})});function Jt(){const e=(c.plotMode??"hardBin")==="value"&&Kt()&&Bn(c)==="off"&&!Be();_e.style.display=e?"":"none";const t=(c.colorbarRangeMode??"spec")==="spec";Se(_e,t),_e.ariaLabel=t?"Colorbar range: test limits (click for data range)":"Colorbar range: data range (click for test limits)"}Jt();const go=ui(ue,()=>c,e=>R(e)),ho=Q("downloadAll","Download gallery PNG",Oo),yo=It("columns","Columns",()=>[{value:"auto",label:"Auto"},{value:"1",label:"1 column"},{value:"2",label:"2 columns"},{value:"3",label:"3 columns"},{value:"4",label:"4 columns"},{value:"5",label:"5 columns"}],()=>E!=null?String(E):"auto",e=>cn(e==="auto"?void 0:Number(e))),O=f.ownerDocument.createElement("div");Object.assign(O.style,{display:"inline-flex",alignItems:"center",gap:"0"}),I.appendChild(O),O.appendChild(Y),O.appendChild(io),O.appendChild(Yt),O.appendChild(mo),O.appendChild(_e),O.appendChild(K()),O.appendChild(uo),O.appendChild(K()),O.appendChild(fo),O.appendChild(K()),O.appendChild(go),O.appendChild(K()),O.appendChild(yo),O.appendChild(K()),O.appendChild(ho),(N||ot())&&(P=Q("findings","Summary panel",()=>{if(!y)return;const e=y.style.display!=="none";e||H(),y.style.display=e?"none":"flex",Se(P,!e),ae()}),I.appendChild(K()),I.appendChild(P));let G=null,Ke=null,J=[],en=!1;function Oe(){const e=Ri({lotStatsSummary:N,result:{warnings:[...v.flatMap(n=>n?.warnings??[]),...Lt().warnings]},extra:[c.binColors&&Fo(c.binColors,c.plotMode),Ho(qt),_n(Ot())].filter(n=>!!n)}),t=e.length!==J.length||e.some((n,o)=>n.code!==J[o]?.code||n.message!==J[o]?.message);J=e,(t||!en)&&(en=!0,p.warnings?.onWarning?.(e)),bo()}function bo(){if(!G||!Ke)return;const e=J.length,t=e>0;if(G.style.display=t?"flex":"none",Ke.style.display=t?"":"none",!t)return;const n=Ii(J[0]),o=`${e} data ${e===1?"warning":"warnings"}`;G.style.color=n==="error"?g.errText:g.warnText,G.ariaLabel=n==="error"?`${o} \u2014 some wafers may be positionally wrong`:o}(p.warnings?.display??!0)&&(Ke=K(),G=Q("warning","Data warnings",()=>{const e=Me();if(Ve(new MouseEvent("click")),e)return;const t=Wi(G.getBoundingClientRect(),J,G.ownerDocument.defaultView??window);Mn(f).appendChild(t),De(t),Dn(t,G,()=>Ve(new MouseEvent("click")))}),Pe(G,!1),I.appendChild(Ke),I.appendChild(G)),Oe();let re=null;F&&(re=Q("analysis","Insights",()=>{on(!Le)}),re.dataset.wmapInsightsBtn="1",I.appendChild(K()),I.appendChild(re));function tn(){import("./userGuideHtml.js").then(e=>si({buildWaferMap:Ti,renderWaferMap:Mi,renderWaferGallery,analyzeWaferMap:et},e.USER_GUIDE_HTML,W,f))}S&&(I.appendChild(K()),I.appendChild(Q("help","User guide",()=>tn())));const me=f.ownerDocument.createElement("div");me.dataset.wmapGalleryMeta="1",Object.assign(me.style,{flex:"1",minWidth:"0",overflow:"hidden",display:"flex",alignItems:"center",padding:`${w.sm} ${w.lg}`,fontSize:T.sub,lineHeight:Qe.none,boxSizing:"border-box"});const Ge=f.ownerDocument.createElement("div");Object.assign(Ge.style,{background:g.canvasBg,display:"flex",alignItems:"stretch",gap:w.lg,paddingBottom:w.lg,minWidth:"0"});const ee=f.ownerDocument.createElement("div");ee.dataset.wmapGalleryLegend="1",Object.assign(ee.style,{display:"flex",flexDirection:"column",gap:w.sm,background:g.menuBg,border:`1px solid ${g.menuBorder}`,borderRadius:z.container,padding:`${w.sm} ${w.lg}`,marginBottom:w.lg,boxShadow:Ae.panel,fontSize:T.body,lineHeight:Qe.none,boxSizing:"border-box",width:"100%",minWidth:"0"});const q=f.ownerDocument.createElement("div");Object.assign(q.style,{display:"flex",flexDirection:"row",alignItems:"flex-start"});let ge=null,Te=null,nn=null;function wo(){return F?ge?Promise.resolve(ge):(nn??=import("./insightsTab.js").then(({createInsightsTab:e})=>(ge=e({getItems:()=>v,getLotStats:()=>N,getBinColors:()=>c.binColors??pe(),getRingCount:nt,defaultView:p.insights?.defaultView,sweeps:p.insights?.sweeps,onRemoveSweeps:p.insights?.onRemoveSweeps,onOpenGuide:void 0,showMetadataStrip:!1,onSaveImage:He.onSaveImage,onSaveText:He.onSaveText,ownerDocument:f.ownerDocument,openWafer:(t,n,o)=>{const d=v[t];if(!d)return;let s=null;const l=ni({title:n,onClose:()=>s?.destroy(),anchor:f});pn(l,n,d.wafer.metadata??void 0),s=yt(l.contentWrap,d,o)}}),Te=ge.el,Te.style.display="none",f.appendChild(Te),ge)),nn):Promise.resolve(null)}let Le=!1;function on(e){F&&(Le=e,Te&&(Te.style.display=e?"flex":"none"),q.style.display=e?"none":"flex",O.style.display=e?"none":"inline-flex",I.style.display="inline-flex",re&&(Se(re,e),re.innerHTML=e?$e.wafer:$e.analysis,re.ariaLabel=e?"Back to gallery view":"Insights"),ae(),Ue(),e&&wo().then(t=>{!t||!Le||(t.el.style.display="flex",t.render())}))}F&&p.insights?.defaultOpen&&queueMicrotask(()=>on(!0));const vo=4,ut=240,ln=480,xo=720,Co=1.25;let he=ln;function sn(e){const t=A*2+110+2;let n=null;for(const o of e){if(o==null||!o.dies?.length)continue;const d=o.dies[0].width;if(!(d>0))continue;const s=o.wafer.radius*2*(vo/d),l=Math.ceil(s+t);(n==null||l>n)&&(n=l)}return n}function So(e){const t=sn(e);return t==null?ut:Math.min(he,Math.max(ut,t))}function Mo(e){const t=sn(e);if(t==null)return!1;const n=Math.min(xo,Math.max(ln,t));return n<=he?!1:(he=n,!0)}function ft(){return E!=null?"none":`${he}px`}function an(){const e=ft();for(const t of Array.from($.children))t.classList.contains("wmap-gallery-card")&&(t.style.maxWidth=e,t.style.maxHeight=e)}let qe=ut,rn=0;function dn(e){if(Mo(e)&&an(),E==null){const n=So(e);n>qe&&(qe=n)}mt()}function cn(e){E=jn(e),an(),mt()}function pt(e){return`repeat(${e}, minmax(0, ${E!=null?"1fr":`${he}px`}))`}function un(e){$.style.gridTemplateColumns!==e&&($.style.gridTemplateColumns=e)}function mt(){if(E!=null){un(pt(E));return}const e=Math.max(1,rn),t=12,n=$.clientWidth||0,o=s=>(n-t*(s-1))/s;let d=Math.max(1,Math.ceil(Math.sqrt(e)));if(n>0){const s=Math.min(he,qe*Co),l=a=>{let i=0;for(;i<e&&o(i+1)>=a;)i++;return i};d=l(s)||l(qe)||1}un(pt(d))}const $=f.ownerDocument.createElement("div");if(Object.assign($.style,{flex:"1 1 0",minWidth:"0",display:"grid",gridTemplateColumns:pt(1),gap:w.xl,paddingLeft:oe,paddingRight:oe,justifyContent:"start",alignContent:"start",isolation:"isolate"}),de?.placement){const e=de.placement;y=kt(e,oe,f.ownerDocument),y.style.maxHeight="calc(100vh - 80px)",y.style.position="sticky",y.style.top="8px",y.style.display="flex",y.style.flexDirection="column"}else if(N||ot()){const e=!!de?.defaultOpen;y=kt("right",oe,f.ownerDocument),y.style.maxHeight="calc(100vh - 80px)",y.style.position="sticky",y.style.top="8px",y.style.flexDirection="column",y.style.display=e?"flex":"none",H()}ae(),y?.style.display!=="none"&&P&&Se(P,!0),(de?.placement??"right")==="left"?(y&&q.appendChild(y),q.appendChild($)):(q.appendChild($),y&&q.appendChild(y));const Re=f.ownerDocument.createElement("div");Object.assign(Re.style,{position:"sticky",top:"0",display:"flex",flexDirection:"column",paddingLeft:oe,paddingRight:oe,paddingTop:oe,zIndex:"1",background:g.menuBg}),Ge.appendChild(me),Ge.appendChild(I),Re.appendChild(Ge),Re.appendChild(ee),f.appendChild(Re),f.appendChild(q);function Ue(){ee.innerHTML="";const e=c.plotMode??"hardBin",t=!Le&&xn.has(e),n=L.filter(h=>h!=null),o=n.find(h=>h.isLotStack),d=$i(n.map(h=>({metadata:h.wafer.metadata??void 0})),o?{lotSize:o.lotSize??n.length,aggrMethod:o.aggrMethod}:void 0),s=e==="metadata",l=c.activeMetadataKey,a=t&&!s?Vn(n,h=>(e==="softBin"?h.sbin:h.hbin)??void 0,zn):{counts:new Map,total:0,pass:0},i=t&&!s?c.binColors??pe():void 0,r=i?e==="softBin"?i.pass.soft:i.pass.hard:new Set,u=xi(a.counts.entries(),r).map(([h])=>h),m=t&&s&&l?Vn(n,h=>Ao(h.metadata?.[l])):{counts:new Map,total:0,pass:0},D=s?Gt()?.values:void 0,k=t&&s?(D??[...m.counts.keys()].sort(Et)).filter(h=>m.counts.has(h)):[];if(me.innerHTML="",d&&me.appendChild(d),me.style.display=d?"flex":"none",!u.length&&!k.length){ee.style.display="none";return}ee.style.display="flex";const x=f.ownerDocument.createElement("div");Object.assign(x.style,{display:"flex",flexWrap:"wrap",alignItems:"center",gap:`${w.sm} ${w.xl}`,maxHeight:"86px",overflowY:"auto",overflowX:"hidden"}),ee.appendChild(x);const b=$n(c.highlightBin),B=L.flatMap(h=>h?.metadataFields??[]).find(h=>h.key===l),j=s?B?.label??(l?Hi(l):"Metadata"):Xo[e],U=f.ownerDocument.createElement("span");if(U.textContent=j,Object.assign(U.style,{fontSize:T.body,fontWeight:"700",letterSpacing:Go,textTransform:"uppercase",color:g.label,flexShrink:"0"}),x.appendChild(U),!s&&a.total>0){const h=a.pass,V=h/a.total*100,te=f.ownerDocument.createElement("span");te.textContent=`Yield ${tt(V)}`,Object.assign(te.style,{fontSize:T.body,fontWeight:"700",color:g.value,whiteSpace:"nowrap",flexShrink:"0"});const ne=f.ownerDocument.createElement("span");ne.textContent=`${h.toLocaleString()} / ${a.total.toLocaleString()} dies`,Object.assign(ne.style,{fontSize:T.body,color:g.label,whiteSpace:"nowrap",flexShrink:"0"}),x.appendChild(te),x.appendChild(ne)}if(s){const h=$n(c.highlightMetadataValue);k.forEach((V,te)=>{const ne=h.includes(V),Ye=B?.values?.find(St=>St.value===V),Ct=Ye?.color??_o(te),wn=m.counts.get(V)??0;Nn(x,{color:Ct,isActive:ne,label:Ye?.label??V,count:wn,percent:m.total>0?wn/m.total*100:void 0,onClick:St=>{const Lo=Pn(c.highlightMetadataValue,V,St);Nt(),R({highlightMetadataValue:Lo})}})});return}const wt=e==="softBin"?L.flatMap(h=>h?.sbinDefs??[]):L.flatMap(h=>h?.hbinDefs??[]),hn=new Set,vt=[];for(const h of wt)hn.has(h.bin)||(hn.add(h.bin),vt.push(h));const xt=vt.length>0?new Map(vt.map(h=>[h.bin,h])):null,yn=i??c.binColors??pe(),To=e==="softBin"?yn.soft:yn.hard,bn=h=>To.get(h)??zo;for(const h of u){const V=b.includes(h),te=xt?.get(h),ne=a.counts.get(h)??0;Nn(x,{color:bn(h),isActive:V,label:te?.name?`${h} \xB7 ${te.name}`:`Bin ${h}`,count:ne,percent:a.total>0?ne/a.total*100:void 0,onClick:Ye=>{const Ct=Pn(c.highlightBin,h,Ye);Nt(),R({highlightBin:Ct})}})}a.total>0&&u.length>1&&ee.appendChild(Ui(f.ownerDocument,[...a.counts.entries()].sort(([,h],[,V])=>V-h).map(([h,V])=>({color:bn(h),count:V,label:xt?.get(h)?.name?`${h} \xB7 ${xt.get(h).name}`:`Bin ${h}`})),a.total))}function We(e){const t=v.filter(a=>a!==null);if(!t.length)return[];const n=t.map(a=>a.dies.filter(Ki)),o=t[0].wafer,d=t.length,s=o.metadata?{...o,metadata:(({wafer:a,waferId:i,...r})=>r)(o.metadata)}:o;function l(a,i){return{...a,stats:{...a.stats,isLotStack:!0,aggregationMethod:i,lotSize:d}}}if(e==="stackedValues"){const a=xe();let i=a?.filter(Dt);if(a!==void 0&&i?.length===0)return[];if(a?.length||(i=Ro(t.flatMap(m=>m.dies)).map(m=>({testNumber:m,name:ji(void 0,m)}))),!i?.length)return[];const r=c.aggregationMethod??"mean";return i.map(u=>{const m=Si(n,r,u.testNumber),D={testNumber:0,name:u.name,unit:u.unit,...Ni(u)};return{wafer:s,dies:m,testDefs:[D],label:`${Vi(u,u.testNumber)} \xB7 ${r}`,isLotStack:!0,aggrMethod:r,lotSize:d,statsSummary:l(et({wafer:s,dies:m,testDefs:[D]},{testNumbers:[0]}),r)}})}if(e==="stackedBins"){let a=Ze(t.map(i=>i?.hbinDefs));return(!a||a.length===0)&&(a=[...new Set(t.flatMap(r=>r.dies.map(u=>u.hbin).filter(u=>u!=null)))].sort((r,u)=>r-u).map(r=>({bin:r,name:`Bin ${r}`}))),a.map(i=>{const r=Tn(n,i.bin,"hard"),u=[{bin:i.bin,name:i.name}];return{wafer:s,dies:r,hbinDefs:u,label:`${i.bin} \xB7 ${i.name}`,isLotStack:!0,aggrMethod:"countBin",lotSize:d,statsSummary:l(et({wafer:s,dies:r,hbinDefs:u}),"countBin")}})}if(e==="stackedSoftBins"){let a=Ze(t.map(i=>i?.sbinDefs));return(!a||a.length===0)&&(a=[...new Set(t.flatMap(r=>r.dies.map(u=>u.sbin).filter(u=>u!=null)))].sort((r,u)=>r-u).map(r=>({bin:r,name:`Bin ${r}`}))),a.map(i=>{const r=Tn(n,i.bin,"soft"),u=[{bin:i.bin,name:i.name}];return{wafer:s,dies:r,sbinDefs:u,label:`${i.bin} \xB7 ${i.name}`,isLotStack:!0,aggrMethod:"countBin",lotSize:d,statsSummary:l(et({wafer:s,dies:r,sbinDefs:u}),"countBin")}})}return t}function gt(e){const t=v.length;return e==="stackedBins"||e==="stackedSoftBins"?{valueRange:[0,t],lotSize:t}:e==="stackedValues"?{aggregationMethod:c.aggregationMethod??"mean",valueRange:void 0,lotSize:void 0}:{}}function R(e,{fireCallback:t=!0}={}){const n=Object.keys(e),o=c.plotMode,d=ve()!==null;c={...c,...e};const s=c.plotMode,l=be.has(s),a=o!==void 0&&be.has(o),i=je>0;if("binColorScheme"in e||"useDefinedBinColors"in e){const u=pe();c={...c,binColors:u},e={...e,binColors:u}}if(e.plotMode!==void 0)if(l){const u=gt(s);if(c={...c,...u},i)for(const m of M)m&&m.setOptions(e);else Z(We(s))}else if(a){const{valueRange:u,lotSize:m,aggregationMethod:D,...k}=c;if(c=k,i)for(const x of M)x&&x.setOptions(e);else Z(v.filter(x=>x!==null))}else for(const u of M)u&&u.setOptions(e);else if(e.aggregationMethod!==void 0&&s==="stackedValues")if(i)for(const u of M)u&&u.setOptions(e);else Z(We("stackedValues"));else for(const u of M)u&&u.setOptions(e);ve()!==null!==d&&Tt(),Ue(),Zt(),Xt(),_t();const r=e.plotMode!==void 0&&e.plotMode!==o;(Bi.some(u=>u in e)||r)&&H(),Oe(),Qt(),Jt(),rt(),at(),t&&p.onViewOptionsChange?.(Rn(c),n,ki(n))}function fn(e,t,n){const o=e.createElement("div");Object.assign(o.style,{display:"flex",alignItems:"center",gap:w.xs,flex:"1",minWidth:"0"});const d=e.createElement("span");d.textContent=t,Object.assign(d.style,{fontWeight:"700",fontSize:T.sub,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}),o.appendChild(d);const s=Hn(n??{});let l=null;if(s.length>0){const a=e.createElement("span");Object.assign(a.style,{fontSize:T.body,lineHeight:Qe.none,color:g.label,flexShrink:"0"}),a.textContent="\u25BE",o.appendChild(a),Object.assign(o.style,{cursor:"pointer",borderRadius:z.control}),o.addEventListener("mouseenter",()=>{o.style.background=g.bgHover}),o.addEventListener("mouseleave",()=>{o.style.background="none"}),l=e.createElement("div"),l.dataset.wmapCardMetaPanel="1",Object.assign(l.style,{position:"absolute",top:"0",left:"0",right:"0",zIndex:Cn,background:g.menuBg,borderBottom:`1px solid ${g.menuBorder}`,boxShadow:Ae.menu,padding:`${w.md} ${w.lg}`,fontSize:T.body,display:"none"});const i=Fn(n??{});i&&l.appendChild(i),o.setAttribute("aria-expanded","false"),o.setAttribute("aria-label",`Wafer info for ${t||"this card"}. Click to expand.`),En(o,r=>{a.textContent=r?"\u25B4":"\u25BE",o.setAttribute("aria-expanded",String(r)),l&&(l.style.display=r?"block":"none")})}return{wrap:o,metaPanel:l}}function pn(e,t,n){const o=e.box.querySelector("[data-wmap-window-title]"),d=Hn(n??{});if(!o||d.length===0)return;const s=o.parentElement,l=f.ownerDocument.createElement("div");Object.assign(l.style,{display:"flex",alignItems:"center",gap:w.xs,flex:"1",minWidth:"0",cursor:"pointer"}),Mt(l,"bare"),s?.insertBefore(l,o),l.appendChild(o);const a=f.ownerDocument.createElement("span");Object.assign(a.style,{fontSize:T.body,lineHeight:Qe.none,color:g.label,flexShrink:"0"}),a.textContent="\u25BE",l.appendChild(a);const i=f.ownerDocument.createElement("div");i.dataset.wmapCardMetaPanel="1",Object.assign(i.style,{position:"absolute",top:"0",left:"0",right:"0",zIndex:Cn,background:g.menuBg,borderBottom:`1px solid ${g.menuBorder}`,boxShadow:Ae.menu,padding:`${w.md} ${w.lg}`,fontSize:T.body,display:"none"});const r=Fn(n??{});r&&i.appendChild(r),e.contentWrap.style.position="relative",e.contentWrap.appendChild(i),l.setAttribute("aria-expanded","false"),l.setAttribute("aria-label",`Wafer info for ${t}. Click to expand.`),En(l,u=>{a.textContent=u?"\u25B4":"\u25BE",l.setAttribute("aria-expanded",String(u)),i.style.display=u?"block":"none"})}function ht(e,t,n){const o=f.ownerDocument.createElement("div");o.className="wmap-gallery-card",Object.assign(o.style,{background:g.menuBg,border:`1px solid ${g.menuBorder}`,borderRadius:z.container,boxShadow:Ae.panel,overflow:"hidden",display:"flex",flexDirection:"column",position:"relative",aspectRatio:"1",maxWidth:ft(),maxHeight:ft()});const d=f.ownerDocument.createElement("div");Object.assign(d.style,{display:"flex",alignItems:"center",padding:`${w.md} ${w.lg} ${w.sm}`,borderBottom:`1px solid ${g.menuBorder}`,flexShrink:"0",gap:w.sm});const{wrap:s,metaPanel:l}=fn(document,Je(e,t),e.wafer.metadata??void 0);d.appendChild(s);const a=f.ownerDocument.createElement("button");a.dataset.wmapExpandBtn="1",a.setAttribute("aria-label","Open full view"),kn(a),a.innerHTML=$e.expand,Object.assign(a.style,{display:"flex",alignItems:"center",justifyContent:"center",border:`1px solid ${g.menuBorder}`,borderRadius:z.control,background:g.panelBg,color:g.label,padding:w.xxs,cursor:"pointer",flexShrink:"0",width:"22px",height:"22px"}),Mt(a),d.appendChild(a),o.appendChild(d);const i=f.ownerDocument.createElement("div");Object.assign(i.style,{position:"relative",flex:"1",minHeight:"0",overflow:"hidden",display:"flex",flexDirection:"column"}),o.appendChild(i),l&&i.appendChild(l),$.appendChild(o),o.addEventListener("contextmenu",D=>{if(D.defaultPrevented)return;const k=p.insights?.sweeps;if(!Di(e.testDefs,k))return;D.preventDefault();const x=e.viewOptions?{...c,...e.viewOptions}:c,b=Ei(e.dies,{waferLabel:On(e),testDefs:e.testDefs,isLotStack:e.isLotStack,activeTest:x.plotMode==="value"?x.activeTest:void 0,waferIndex:t}),B={x:D.clientX,y:D.clientY};import("./drilldown.js").then(({openDrilldownMenu:j})=>{o.isConnected&&j(B,o,b,{sweeps:k,onSaveImage:m.getSaveImageHook()})})});const r=Fe||ve()!==null,u=e.viewOptions?{...c,...e.viewOptions}:c,m=Ln(i,e,{viewOptions:{...u,showLegend:r,legendPosition:we},showTooltip:!0,padding:A,statsSummary:e.statsSummary,onSaveImage:p.onSaveImage,onSaveText:p.onSaveText,downloadFilename:p.downloadFilename,onClick:e.onClick,onSelect:jt(e),insights:X,onExpand:()=>Ie(t,e),showIdentity:!1,chromeInset:Uo,drawWhenVisible:!0});return m.setViewControlsVisible(!1),m.setSummaryVisible(!1),a.onclick=()=>Ie(t,e),{card:o,ctrl:m,canvasWrapper:i,expandBtn:a}}function Do(e){const t=ce[e];if(!t)return;const n=[..._.values()].find(o=>o.cardIndex===e);n?(t.innerHTML=$e.minimize,t.setAttribute("aria-label","Reattach to gallery"),t.onclick=()=>ko(n.id)):(t.innerHTML=$e.expand,t.setAttribute("aria-label","Open full view"),t.onclick=()=>Ie(e,L[e]))}function Z(e){Bo(),Me()?.remove(),De(null),ke(),L=[];for(const i of M)i&&i.destroy();M=[],le=[],ce=[],je=0,$.innerHTML="",rn=e.length,dn(e.map(i=>typeof i=="function"?null:i));const t=[];for(let i=0;i<e.length;i++){const r=e[i];if(typeof r=="function"){const u=f.ownerDocument.createElement("div");u.className="wmap-gallery-card",Object.assign(u.style,{background:g.menuBg,border:`1px solid ${g.menuBorder}`,borderRadius:z.container,aspectRatio:"1",display:"flex",alignItems:"center",justifyContent:"center"});const m=f.ownerDocument.createElement("span");m.textContent="\u2026",Object.assign(m.style,{color:g.label,fontSize:"18px"}),u.appendChild(m),$.appendChild(u),L.push(null),M.push(null),le.push(null),ce.push(null),t.push({index:i,factory:r,placeholder:u}),je++}else{const{ctrl:u,canvasWrapper:m,expandBtn:D}=ht(r,i,e.length);L.push(r),M.push(u),le.push(m),ce.push(D)}}Ut(),Ue(),rt(),at();const n=++Ce,o=()=>{setTimeout(()=>{n===Ce&&p.onItemsResolved?.()},0)},d=i=>{setTimeout(()=>{n===Ce&&p.onItemResolved?.(i,e.length)},0)};let s=e.length-t.length;s>0&&d(s);let l=0;function a(){if(n!==Ce)return;if(l>=t.length){if(be.has(c.plotMode)){const B=c.plotMode;Z(We(B));return}Ee=o,H(),fe||(Ee=null,o());return}const{index:i,factory:r,placeholder:u}=t[l++],m=r();L[i]=m,v[i]=m,dn([m]);const{card:D,ctrl:k,canvasWrapper:x,expandBtn:b}=ht(m,i,e.length);M[i]=k,le[i]=x,ce[i]=b,je--,u.replaceWith(D),d(++s),co(),ro(),!y&&!de?.placement&&m.statsSummary?.findings.length&&(y=kt("right",oe,f.ownerDocument),y.style.maxHeight="calc(100vh - 80px)",y.style.position="sticky",y.style.top="8px",y.style.flexDirection="column",y.style.display="none",(de?.placement??"right")==="left"?q.insertBefore(y,$):q.appendChild(y),H(),P||(P=Q("findings","Summary panel",()=>{if(!y)return;const j=y.style.display!=="none";j||H(),y.style.display=j?"none":"flex",Se(P,!j),ae()}),I.appendChild(K()),I.appendChild(P)),ae()),ae(),setTimeout(a,0)}t.length>0?setTimeout(a,0):o()}if(be.has(c.plotMode)&&v.length>0){const e=gt(c.plotMode);c={...c,...e},Z(We(c.plotMode))}else Z(C);Oe();let ye=0;const mn=new(f.ownerDocument.defaultView??window).ResizeObserver(()=>{if(ye)return;ye=(f.ownerDocument.defaultView??window).requestAnimationFrame(()=>{ye=0,E==null&&mt()})});mn.observe($),y&&H();function Eo(e,t){const n=le[e];if(!n)return;n.innerHTML="",Object.assign(n.style,{alignItems:"center",justifyContent:"center"});const o=f.ownerDocument.createElement("span");o.textContent=t?"Opened in its own window":"Opened in the wafer viewer",Object.assign(o.style,{color:g.label,fontSize:T.body,textAlign:"center",padding:"0 12px"}),n.appendChild(o)}function Ie(e,t){for(const l of _.values())if(l.cardIndex===e)return;const n=Je(t,e),o=Kn++,d=M[e]?.getOptions(),s=ei(n);if(s){const l=s.document;l.title=n,Object.assign(l.documentElement.style,{height:"100%"}),Object.assign(l.body.style,{margin:"0",height:"100vh",overflow:"hidden",display:"flex",flexDirection:"column",fontFamily:T.family}),ii(f,l.documentElement);const a=li(f,l.documentElement,()=>x.setOptions({})),i=l.createElement("div");i.dataset.wmapWindowBanner="1",i.textContent=n,Object.assign(i.style,{display:"none",padding:`${w.sm} ${w.xl}`,fontSize:T.body,fontWeight:"700",background:g.warnBg,color:g.warnText,borderBottom:`1px solid ${g.warnBorder}`,flexShrink:"0"}),l.body.appendChild(i);const r=l.createElement("div");Object.assign(r.style,{flex:"1",minHeight:"0",display:"flex",flexDirection:"column"}),l.body.appendChild(r);const{wrap:u,metaPanel:m}=fn(l,n,t.wafer.metadata??void 0),D=l.createElement("div");Object.assign(D.style,{display:"flex",alignItems:"center",padding:`${w.md} ${w.lg} ${w.sm}`,borderBottom:`1px solid ${g.menuBorder}`,flexShrink:"0",gap:w.sm}),D.appendChild(u),r.appendChild(D);const k=l.createElement("div");Object.assign(k.style,{position:"relative",flex:"1",minHeight:"0",overflow:"hidden",display:"flex",flexDirection:"column"}),m&&k.appendChild(m),r.appendChild(k);const x=yt(k,t,void 0,d),b=setInterval(()=>{s.closed&&Xe(o)},400);s.addEventListener("pagehide",()=>Xe(o)),_.set(o,{id:o,ctrl:x,cardIndex:e,label:n,closePollId:b,stopThemeSync:a,close:()=>{s.closed||s.close()},setTitle:B=>{l.title=B,i.textContent=B,i.style.display="block"}})}else{const l=ti({title:n,onClose:()=>Xe(o),anchor:f});l.contentWrap.style.flexDirection="column",pn(l,n,t.wafer.metadata??void 0);const a=yt(l.contentWrap,t,void 0,d);_.set(o,{id:o,ctrl:a,cardIndex:e,label:n,closePollId:null,close:()=>l.close(),setTitle:i=>{const r=l.box.querySelector("[data-wmap-window-title]");r&&(r.textContent=i,r.title=i)}})}M[e]?.destroy(),M[e]=null,Eo(e,s!==null),Do(e)}function yt(e,t,n,o){const d=t.viewOptions?{...c,...t.viewOptions}:c,s=o?{...d,...o}:d,a={...n!==void 0?{...s,plotMode:"value",activeTest:n}:s,showLegend:!0,legendPosition:we},i=Ln(e,t,{viewOptions:a,showTooltip:!0,padding:A,statsSummary:t.statsSummary,onSaveImage:p.onSaveImage,onSaveText:p.onSaveText,downloadFilename:p.downloadFilename,onClick:t.onClick,onSelect:jt(t),insights:X,showExpandButton:!1,showIdentity:!1});return i.setViewControlsVisible(!0),i.setSummaryVisible(!0),i.setExpandVisible(!1),i}function Xe(e){const t=_.get(e);if(!t||(_.delete(e),t.closePollId!=null&&clearInterval(t.closePollId),t.stopThemeSync?.(),t.ctrl.destroy(),t.cardIndex===null))return;const n=t.cardIndex,o=L[n];if(!o)return;const{card:d,ctrl:s,canvasWrapper:l,expandBtn:a}=ht(o,n,L.length);le[n]?.parentElement?.replaceWith(d),M[n]=s,le[n]=l,ce[n]=a}function ko(e){const t=_.get(e);t&&(t.close(),Xe(e))}function Bo(){for(const e of _.values())e.cardIndex!==null&&(e.cardIndex=null,e.setTitle(`${e.label} \u2014 unlinked from gallery`))}function bt(){for(const e of M)e?.drawPendingNow()}const gn=f.ownerDocument.defaultView??window;gn.addEventListener("beforeprint",bt);function Oo(){bt();const e=[...$.querySelectorAll("canvas")];if(!e.length)return;const t=e.length,n=Math.ceil(Math.sqrt(t)),o=Math.ceil(t/n),d=e[0].width,s=e[0].height,l=8,a=(f.ownerDocument.defaultView??window).devicePixelRatio||1,i=Math.round(26*a),r=Math.round(12*a),u=f.ownerDocument.createElement("canvas");u.width=n*d+(n-1)*l,u.height=o*(s+i)+(o-1)*l;const m=u.getContext("2d"),D=Ko($);m.fillStyle=D.background,m.fillRect(0,0,u.width,u.height),e.forEach((k,x)=>{const b=x%n,B=Math.floor(x/n),j=b*(d+l),U=B*(s+i+l),wt=k.closest(".wmap-gallery-card")?.querySelector("span")?.textContent??"";m.fillStyle=D.surface,m.fillRect(j,U,d,i),m.fillStyle=D.text,m.font=`700 ${r}px system-ui, sans-serif`,m.textAlign="left",m.textBaseline="middle",m.fillText(wt,j+Math.round(10*a),U+i/2,d-Math.round(20*a)),m.drawImage(k,j,U+i)}),u.toBlob(k=>{if(!k)return;const x=M.find(b=>b!=null)?.getExportTitle();fi(k,["gallery",x].filter(Boolean).join(" "),He.onSaveImage)})}return{setItems(e){v=e.map(n=>typeof n=="function"?null:n);const t=c.plotMode;if(be.has(t))if(e.some(o=>typeof o=="function"))Z(e);else{const o=gt(t);c={...c,...o},Z(We(t))}else Z(e)},setOptions(e){R(e,{fireCallback:!1})},getOptions(){return Rn(c)},setFindingsNotice(e){At=e,H()},setColumns(e){cn(e)},getBinColors(){return c.binColors??pe()},setLotStatsSummary(e){N=e,Oe(),y&&H(),ae()},openUserGuide:tn,destroy(){Ce++,gn.removeEventListener("beforeprint",bt),fe?.cancel(),fe=null,Ee=null;for(const e of[..._.values()])e.closePollId!=null&&clearInterval(e.closePollId),e.close(),e.ctrl.destroy();_.clear();for(const e of M)e&&e.destroy();M=[],Me()?.remove(),mn.disconnect(),ye&&((f.ownerDocument.defaultView??window).cancelAnimationFrame(ye),ye=0),f.ownerDocument.removeEventListener("click",Ve,!0),window.removeEventListener("blur",$t),ie(),Sn(),Re.remove(),q.remove(),y?.remove(),ge?.destroy()}}}
@@ -2,7 +2,7 @@ import type { PlotMode } from '../renderer/buildView.js';
2
2
  import type { Die } from '../core/dies.js';
3
3
  import { type ToCanvasOptions } from './toCanvas.js';
4
4
  import type { WaferMapResult } from '../renderer/buildWaferMap.js';
5
- import type { StatsSummary } from '../stats/types.js';
5
+ import type { StatsFinding, StatsSummary } from '../stats/types.js';
6
6
  import { type SaveImageHandler, type SaveTextHandler, type UserGuideExtension } from './toolbar.js';
7
7
  import type { SummaryPanelOptions, FindingsNotice } from './summaryPanel.js';
8
8
  import { type WarningsOptions } from './warnings.js';
@@ -91,12 +91,6 @@ export interface WaferPreferences {
91
91
  * `'data'`: colorbar spans actual data min/max; out-of-spec coloring still applies.
92
92
  */
93
93
  colorbarRangeMode?: 'spec' | 'data';
94
- /**
95
- * When true (default), partial (edge) dies are rendered in muted grey.
96
- * Set to false to hide them entirely, matching real prober behaviour where
97
- * positions outside the wafer circle are never tested.
98
- */
99
- showPartialDies?: boolean;
100
94
  }
101
95
  /**
102
96
  * Transient display state — describes the current view session, not worth persisting.
@@ -122,9 +116,9 @@ export interface WaferDisplayState {
122
116
  * when the result has `metadataFields`.
123
117
  */
124
118
  activeMetadataKey?: string;
125
- highlightBin?: number;
126
- /** Dim every die except this metadata value in `'metadata'` mode — the analogue of `highlightBin`. */
127
- highlightMetadataValue?: string;
119
+ highlightBin?: number | number[];
120
+ /** Dim every die except these metadata values in `'metadata'` mode — the analogue of `highlightBin`. */
121
+ highlightMetadataValue?: string | string[];
128
122
  /**
129
123
  * Explicit value colour normalization range.
130
124
  *
@@ -158,26 +152,18 @@ export interface WaferDisplayState {
158
152
  */
159
153
  export type WaferViewOptions = WaferPreferences & WaferDisplayState;
160
154
  /**
161
- * The drawing parameters `renderWaferMap` forwards to the canvas. Declared
162
- * explicitly rather than inherited from `ToCanvasOptions`, which is what this
163
- * interface used to do.
164
- *
165
- * That inheritance leaked 16 low-level fields onto the top-level render API, and
166
- * five of them were **accepted and silently ignored** — `renderWaferMap` computes
167
- * or overrides them on every draw (`topClearance` was always 0, and has since been removed from `toCanvas` too;
168
- * `minRightReserve` is derived from the legend, and `markFailingDies`/`activeBin`/
169
- * `hoverBin` are read from `viewOptions` and internal hover state instead). An
170
- * option that is typed, documented and ignored costs a caller a debugging session
171
- * to discover the API lied, so they are gone rather than merely undocumented.
155
+ * The drawing parameters `renderWaferMap` forwards to the canvas, listed
156
+ * explicitly rather than inherited from `ToCanvasOptions`.
172
157
  *
173
- * Listing the fields also stops future `ToCanvasOptions` additions arriving here
174
- * by accident: `toCanvas` is the low-level surface and is free to grow, and a
175
- * caller who genuinely needs that level of control should call it directly.
158
+ * `renderWaferMap` sets the rest of `ToCanvasOptions` itself on every draw
159
+ * (`markFailingDies`, `legendPosition` and `fallbackFormat` from `viewOptions`,
160
+ * `viewport` from zoom and pan, the bin definitions from the result), so
161
+ * exposing them here would type and document options that are ignored. Listing the fields also stops a
162
+ * future `ToCanvasOptions` addition arriving on the render API by accident.
176
163
  *
177
- * These stay at the top level of `RenderOptions` rather than moving under a
178
- * nested `draw` key. Grouping would read better, but it would break every caller
179
- * of the ten options that DO work in exchange for tidiness alone, and the defect
180
- * here was the five that don't.
164
+ * They stay at the top level of `RenderOptions` rather than under a nested
165
+ * `draw` key: grouping would read better, but would break every caller of the
166
+ * options that work, for tidiness alone.
181
167
  */
182
168
  type ForwardedDrawOptions = Pick<ToCanvasOptions, 'padding' | 'background' | 'showColorbar' | 'colorbarWidth' | 'showAxes' | 'showTitle' | 'legendOffset' | 'diePitchMm' | 'metadataFields'>;
183
169
  export interface RenderOptions extends ForwardedDrawOptions {
@@ -218,12 +204,9 @@ export interface RenderOptions extends ForwardedDrawOptions {
218
204
  /** Optional precomputed wafer-level stats summary. Enables the summary panel toggle button in the toolbar. */
219
205
  statsSummary?: StatsSummary;
220
206
  /**
221
- * Name for the map's PNG download, without extension. When omitted, the PNG
222
- * is named for its lot, wafer and map title (`LOT123_W05_hard-bin.png`); CSV
223
- * exports are always named that way. See docs/api.md §5.4.5.
224
- *
225
- * **Changes in 0.31.0:** this becomes a prefix for every file the map saves,
226
- * with the lot, wafer and content appended. Passing it logs a one-time notice.
207
+ * A prefix for every file the map saves — PNGs and CSVs alike. The lot,
208
+ * wafer and content follow it (`<prefix>_W05_hard-bin.png`), except any the
209
+ * prefix already names. See docs/api.md §5.4.5.
227
210
  */
228
211
  downloadFilename?: string;
229
212
  /**
@@ -448,6 +431,14 @@ export interface CardRenderOptions extends Omit<RenderOptions, 'viewOptions'> {
448
431
  chromeInset?: string;
449
432
  /** Replaces the expand action for both the expand button and the E key. */
450
433
  onExpand?: () => void;
434
+ /**
435
+ * Draw the canvas only while it is on screen (or near it). An off-screen card
436
+ * keeps its view up to date and is drawn when it scrolls into view, or by
437
+ * `drawPendingNow()` — which anything capturing the canvas (the gallery PNG,
438
+ * printing) must call first. For gallery grid cards: a large lot's gallery
439
+ * spent most of a mode switch drawing cards nobody could see.
440
+ */
441
+ drawWhenVisible?: boolean;
451
442
  }
452
443
  /** @internal */
453
444
  export interface CardController extends WaferMapController {
@@ -461,8 +452,15 @@ export interface CardController extends WaferMapController {
461
452
  setExpandVisible(visible: boolean): void;
462
453
  /** The map's title as a file-name content part — the gallery names its composite PNG by it. */
463
454
  getExportTitle(): string;
455
+ /** This map's save hook, naming files for its own wafer — for a save the gallery starts on a card's behalf. */
456
+ getSaveImageHook(): SaveImageHandler;
457
+ /** Draw now if a `drawWhenVisible` card skipped drawing while off screen. */
458
+ drawPendingNow(): void;
464
459
  }
465
460
  /** @internal The public view of a card's options: everything but the gallery's shared state. */
461
+ /** The bin a finding is about — what the legend filter shows while the finding
462
+ * is active — or `undefined` for a yield, test or functional finding. */
463
+ export declare function findingBin(finding: StatsFinding): number | undefined;
466
464
  export declare function toPublicViewOptions(opts: CardViewOptions): WaferViewOptions;
467
465
  export type RenderableWaferMap = Pick<WaferMapResult, 'wafer' | 'dies'> & Partial<Omit<WaferMapResult, 'wafer' | 'dies'>>;
468
466
  export declare function renderWaferMap(container: HTMLElement, result: RenderableWaferMap, options?: RenderOptions): WaferMapController;