@wafertools/wafermap 0.26.1 → 0.28.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 (109) hide show
  1. package/AGENTS.md +10 -2
  2. package/CHANGELOG.md +670 -0
  3. package/README.md +46 -3
  4. package/dist/packages/canvas-adapter/canvasTheme.d.ts +4 -0
  5. package/dist/packages/canvas-adapter/canvasTheme.js +1 -1
  6. package/dist/packages/canvas-adapter/charts/barPanel.d.ts +16 -0
  7. package/dist/packages/canvas-adapter/charts/barPanel.js +1 -1
  8. package/dist/packages/canvas-adapter/charts/binCluster.d.ts +0 -1
  9. package/dist/packages/canvas-adapter/charts/binCluster.js +1 -1
  10. package/dist/packages/canvas-adapter/charts/boxplot.d.ts +21 -2
  11. package/dist/packages/canvas-adapter/charts/boxplot.js +1 -1
  12. package/dist/packages/canvas-adapter/charts/capability.d.ts +10 -11
  13. package/dist/packages/canvas-adapter/charts/capability.js +1 -1
  14. package/dist/packages/canvas-adapter/charts/chartShell.d.ts +337 -3
  15. package/dist/packages/canvas-adapter/charts/chartShell.js +1 -1
  16. package/dist/packages/canvas-adapter/charts/correlation.d.ts +8 -10
  17. package/dist/packages/canvas-adapter/charts/correlation.js +2 -1
  18. package/dist/packages/canvas-adapter/charts/groupedBarPlot.d.ts +50 -0
  19. package/dist/packages/canvas-adapter/charts/groupedBarPlot.js +1 -0
  20. package/dist/packages/canvas-adapter/charts/histogram.d.ts +12 -2
  21. package/dist/packages/canvas-adapter/charts/histogram.js +1 -1
  22. package/dist/packages/canvas-adapter/charts/regionYieldDiagram.d.ts +0 -1
  23. package/dist/packages/canvas-adapter/charts/regionYieldDiagram.js +1 -1
  24. package/dist/packages/canvas-adapter/charts/scatter.d.ts +6 -1
  25. package/dist/packages/canvas-adapter/charts/scatter.js +1 -1
  26. package/dist/packages/canvas-adapter/charts/testPassRate.d.ts +20 -0
  27. package/dist/packages/canvas-adapter/charts/testPassRate.js +1 -0
  28. package/dist/packages/canvas-adapter/charts/trend.d.ts +37 -0
  29. package/dist/packages/canvas-adapter/charts/trend.js +1 -0
  30. package/dist/packages/canvas-adapter/dieList.js +7 -7
  31. package/dist/packages/canvas-adapter/hitGrid.d.ts +22 -0
  32. package/dist/packages/canvas-adapter/hitGrid.js +1 -0
  33. package/dist/packages/canvas-adapter/identityHeader.d.ts +46 -0
  34. package/dist/packages/canvas-adapter/identityHeader.js +1 -0
  35. package/dist/packages/canvas-adapter/index.d.ts +2 -1
  36. package/dist/packages/canvas-adapter/index.js +1 -1
  37. package/dist/packages/canvas-adapter/insightsTab.d.ts +51 -5
  38. package/dist/packages/canvas-adapter/insightsTab.js +1 -1
  39. package/dist/packages/canvas-adapter/maplessSummary.d.ts +5 -1
  40. package/dist/packages/canvas-adapter/maplessSummary.js +1 -1
  41. package/dist/packages/canvas-adapter/renderWaferGallery.d.ts +15 -2
  42. package/dist/packages/canvas-adapter/renderWaferGallery.js +1 -20
  43. package/dist/packages/canvas-adapter/renderWaferMap.d.ts +110 -18
  44. package/dist/packages/canvas-adapter/renderWaferMap.js +1 -1
  45. package/dist/packages/canvas-adapter/summaryPanel.d.ts +233 -37
  46. package/dist/packages/canvas-adapter/summaryPanel.js +3 -3
  47. package/dist/packages/canvas-adapter/toCanvas.d.ts +6 -0
  48. package/dist/packages/canvas-adapter/toCanvas.js +1 -1
  49. package/dist/packages/canvas-adapter/toolbar.d.ts +352 -15
  50. package/dist/packages/canvas-adapter/toolbar.js +2 -2
  51. package/dist/packages/canvas-adapter/userGuideHtml.d.ts +1 -1
  52. package/dist/packages/canvas-adapter/userGuideHtml.js +115 -41
  53. package/dist/packages/canvas-adapter/version.d.ts +2 -2
  54. package/dist/packages/canvas-adapter/version.js +1 -1
  55. package/dist/packages/canvas-adapter/warnings.d.ts +21 -0
  56. package/dist/packages/canvas-adapter/warnings.js +1 -1
  57. package/dist/packages/core/dies.d.ts +11 -0
  58. package/dist/packages/core/dies.js +1 -1
  59. package/dist/packages/core/utils.d.ts +11 -0
  60. package/dist/packages/core/utils.js +1 -1
  61. package/dist/packages/renderer/binColors.d.ts +80 -0
  62. package/dist/packages/renderer/binColors.js +1 -0
  63. package/dist/packages/renderer/buildView.d.ts +100 -6
  64. package/dist/packages/renderer/buildView.js +1 -1
  65. package/dist/packages/renderer/buildWaferMap.d.ts +112 -7
  66. package/dist/packages/renderer/buildWaferMap.js +1 -1
  67. package/dist/packages/renderer/colorMap.d.ts +16 -15
  68. package/dist/packages/renderer/colorMap.js +1 -1
  69. package/dist/packages/renderer/colorSchemes.d.ts +45 -26
  70. package/dist/packages/renderer/colorSchemes.js +1 -1
  71. package/dist/packages/renderer/index.d.ts +3 -1
  72. package/dist/packages/renderer/index.js +1 -1
  73. package/dist/packages/stats/analyzeWaferLot.js +1 -1
  74. package/dist/packages/stats/analyzeWaferMap.js +1 -1
  75. package/dist/packages/stats/binPareto.d.ts +15 -0
  76. package/dist/packages/stats/binPareto.js +1 -1
  77. package/dist/packages/stats/clusterDetection.js +1 -1
  78. package/dist/packages/stats/connectedComponents.d.ts +14 -0
  79. package/dist/packages/stats/connectedComponents.js +1 -0
  80. package/dist/packages/stats/correlation.d.ts +26 -0
  81. package/dist/packages/stats/correlation.js +1 -1
  82. package/dist/packages/stats/facets.js +1 -1
  83. package/dist/packages/stats/filterFindings.d.ts +18 -0
  84. package/dist/packages/stats/filterFindings.js +1 -1
  85. package/dist/packages/stats/findingsNarrative.js +1 -1
  86. package/dist/packages/stats/histogram.d.ts +47 -2
  87. package/dist/packages/stats/histogram.js +1 -1
  88. package/dist/packages/stats/index.d.ts +6 -0
  89. package/dist/packages/stats/index.js +1 -1
  90. package/dist/packages/stats/mergeTestDefs.d.ts +44 -0
  91. package/dist/packages/stats/mergeTestDefs.js +1 -0
  92. package/dist/packages/stats/metadataColumns.d.ts +20 -4
  93. package/dist/packages/stats/metadataColumns.js +1 -1
  94. package/dist/packages/stats/patternClassification.js +1 -1
  95. package/dist/packages/stats/population.d.ts +23 -0
  96. package/dist/packages/stats/population.js +1 -0
  97. package/dist/packages/stats/renderFindingsReport.js +15 -15
  98. package/dist/packages/stats/renderSummaryReport.js +35 -32
  99. package/dist/packages/stats/reportHtml.js +38 -13
  100. package/dist/packages/stats/testPassRate.d.ts +85 -0
  101. package/dist/packages/stats/testPassRate.js +1 -0
  102. package/dist/packages/stats/trend.d.ts +40 -0
  103. package/dist/packages/stats/trend.js +1 -0
  104. package/dist/packages/stats/types.d.ts +117 -6
  105. package/dist/packages/stats/yield.js +1 -1
  106. package/llms.txt +6 -0
  107. package/package.json +9 -5
  108. package/dist/packages/canvas-adapter/metadataBadge.d.ts +0 -30
  109. package/dist/packages/canvas-adapter/metadataBadge.js +0 -1
@@ -1 +1 @@
1
- import{buildFacetTable as ce,facetValueOf as pe,FACET_NONE_VALUE as ue}from"../stats/facets.js";import{isParametricTest as me}from"../renderer/buildWaferMap.js";import{getColorScheme as fe}from"../renderer/colorSchemes.js";import{CLR as x}from"./toolbar.js";import{renderCapabilityPanel as be}from"./charts/capability.js";import{renderBoxplotPanel as ye}from"./charts/boxplot.js";import{renderHistogramPanel as he}from"./charts/histogram.js";import{renderCorrelationPanel as ge}from"./charts/correlation.js";import{renderScatterPanel as Ce}from"./charts/scatter.js";import{renderBarPanel as N}from"./charts/barPanel.js";import{renderBinClusterPanel as xe}from"./charts/binCluster.js";import{QUANTITY as Se}from"./charts/palette.js";import{makeChartGridWrap as A,makeLabeledSelect as we}from"./charts/chartShell.js";import{buildYieldData as H,buildYieldDataCombined as Be}from"../stats/yield.js";import{buildBinParetoData as ke}from"../stats/binPareto.js";import{buildLotTestSection as ve,buildLotFunctionalSection as Te,buildMetadataStripBox as De}from"./summaryPanel.js";import{buildRegionYieldData as z,buildRingRegions as $e,buildQuadrantRegions as Ee}from"../stats/regions.js";import{renderRegionYieldDiagram as Q}from"./charts/regionYieldDiagram.js";const Oe=[{key:"overview",label:"Overview"},{key:"distributions",label:"Distributions"},{key:"correlation",label:"Correlation"}];export function createInsightsTab(w){const{getItems:M,getLotStats:K,getColorSchemeName:g,passBins:b,getRingCount:U,onSaveImage:h,onSaveText:V,openWafer:L}=w,_=w.showMetadataStrip??!0,i=w.ownerDocument??document,B=i.createElement("div");Object.assign(B.style,{display:"none",flexDirection:"column",gap:"10px",width:"100%"});const W=i.createElement("div"),S=i.createElement("div");Object.assign(S.style,{display:"flex",gap:"4px",borderBottom:`1px solid ${x.menuBorder}`,marginBottom:"2px"}),S.setAttribute("role","tablist"),S.addEventListener("keydown",e=>{if(e.key!=="ArrowLeft"&&e.key!=="ArrowRight")return;const t=Array.from(S.querySelectorAll('[role="tab"]')),o=t.indexOf(i.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 D=i.createElement("div");Object.assign(D.style,{display:"flex",flexDirection:"column",gap:"10px"}),B.appendChild(W),B.appendChild(S),B.appendChild(D);let $=w.defaultView??"overview",k,O=[];function F(e,t,o){L?.(e,t,o)}function X(){return M().map((e,t)=>e==null?null:{metadata:e.wafer.metadata??void 0,dies:e.dies,wafer:e.wafer,label:e.label??String(e.wafer.metadata?.waferId??""),waferIndex:t,statsSummary:e.statsSummary}).filter(e=>e!=null)}function G(e,t){Object.assign(e.style,{background:"none",border:"none",borderBottom:t?`2px solid ${x.iconActive}`:"2px solid transparent",color:t?x.iconActive:x.label,fontWeight:t?"700":"500",fontSize:"12px",padding:"6px 10px 8px",cursor:"pointer",marginBottom:"-1px"})}function J(e,t){const o=i.createElement("button");o.type="button",o.textContent=t;const r=e===$;return G(o,r),o.dataset.wmapInsightsTab=e,o.setAttribute("role","tab"),o.setAttribute("aria-selected",r?"true":"false"),o.tabIndex=r?0:-1,o.addEventListener("click",()=>{$!==e&&($=e,Y())}),o}function Z(e){const t=i.createElement("button");return t.type="button",t.textContent=`\u2039 ${e.label}`,G(t,!1),t.dataset.wmapInsightsBack="1",t.addEventListener("click",e.onBack),t}function ee(e,t,o,r=!0){const s=A(i),d=fe(g());let u="label";const c=o??"group",n=b.length===1?`bin ${b[0]}`:`bins ${b.join(", ")}`,m=K?.(),f=new Map(m?.lotYieldSeries.map(a=>[a.waferIndex,a.yieldPercent])),p=a=>({...a,label:a.label.replace(/\s*·\s*\d+(\.\d+)?%$/,""),yieldPercent:f.get(a.waferIndex),key:a.waferIndex}),v=e.map(p),C=t?.map(a=>({key:a.key,items:a.items.map(p)})),T=()=>C?Be(C,b,u):H(v,b,u),l={title:t?`Yield by ${c} (pass: ${n})`:`Yield by wafer (pass: ${n})`,data:T(),selfControl:{current:u,options:[["yield","Sort: yield"],["label",t?`Sort: ${c}`:"Sort: wafer ID"]],onChange:a=>(u=a,{data:T()})},barColor:()=>Se,valueLabel:a=>`${a.percent.toFixed(1)}%`,drill:C?{onOpenGroup:a=>{const P=C.find(E=>E.key===a.label)?.items??[];return{data:H(P,b,u),title:`Yield by wafer \u2014 ${c}: ${a.label} (pass: ${n})`}},onBack:()=>({data:T(),title:`Yield by ${c} (pass: ${n})`}),groupLabelText:c}:void 0,onOpen:L?a=>{typeof a.key=="number"&&F(a.key,`Wafer ${a.label}`)}:void 0,ownerDocument:i};let y=null;if(r&&(y=N(l,h),y.card.style.minHeight="360px",s.appendChild(y.card)),t){const a=xe({title:"Hard bin pareto",groups:t.map(P=>({key:P.key,items:P.items.map(E=>({dies:E.dies,hardBinCounts:E.statsSummary?.stats.hardBinCounts,softBinCounts:E.statsSummary?.stats.softBinCounts}))})),colorScheme:g(),onSaveImage:h,ownerDocument:i});return a.card.style.minHeight="360px",s.appendChild(a.card),{card:s,destroy:()=>{y?.destroy(),a.destroy()}}}let I="hbin";const le=d.forBin,se=e.map(a=>({dies:a.dies,hardBinCounts:a.statsSummary?.stats.hardBinCounts,softBinCounts:a.statsSummary?.stats.softBinCounts})),q=()=>ke(se,I),de={title:"Hard bin pareto",data:q(),selfControl:{current:I,options:[["hbin","Hard bins"],["sbin","Soft bins"]],onChange:a=>(I=a,{data:q(),title:`${I==="hbin"?"Hard":"Soft"} bin pareto`})},barColor:a=>le(a.binCode??0),ownerDocument:i},j=N(de,h);return j.card.style.minHeight="360px",s.appendChild(j.card),{card:s,destroy:()=>{y?.destroy(),j.destroy()}}}function R(){const e=i.createElement("div");return e.dataset.wmapChartCard="1",Object.assign(e.style,{display:"flex",flexDirection:"column",gap:"10px",minWidth:"0",background:x.menuBg,border:`1px solid ${x.menuBorder}`,borderRadius:"6px",padding:"12px"}),e}function te(e){if(W.innerHTML="",!_)return;const t=De(e.map(o=>({metadata:o.metadata})),void 0,{facetableOnly:!1});t&&(t.style.marginBottom="0",W.appendChild(t))}function ne(e,t,o){if(!e.length)return{elements:[],testValuesCard:null,functionalCard:null,destroy:()=>{}};const r=e.map(l=>l.wafer),s=e.map(l=>l.dies),d=e.flatMap(l=>l.dies),u=e.map(l=>l.statsSummary),c=u.every(l=>l!==void 0)?u:void 0,n=U?.()??4,m=[],f=[],p=z(s,r,n,b,$e);if(p.length){const l=Q({title:"Ring yield",mode:"ring",rows:p,colorScheme:g(),onSaveImage:h,ownerDocument:i});m.push(l.card),f.push(l.destroy)}const v=z(s,r,n,b,Ee);if(v.length){const l=Q({title:"Quadrant yield",mode:"quadrant",rows:v,colorScheme:g(),onSaveImage:h,ownerDocument:i});m.push(l.card),f.push(l.destroy)}let C=null;if(t.length){const l=ve(d,t,void 0,c,V);if(l){const y=R();y.appendChild(l),C=y}}let T=null;if(o.length){const l=Te(d,o,c,V);if(l){const y=R();y.appendChild(l),T=y}}return{elements:m,testValuesCard:C,functionalCard:T,destroy:()=>{for(const l of f)l()}}}function oe(e){const t=b.length===1?`bin ${b[0]}`:`bins ${b.join(", ")}`,o=H([{...e,key:e.waferIndex}],b)[0]?.percent,r=R();Object.assign(r.style,{flexDirection:"row",flexWrap:"wrap",gap:"8px"});function s(d,u){const c=i.createElement("div");Object.assign(c.style,{border:`1px solid ${x.menuBorder}`,borderRadius:"6px",padding:"8px 16px",textAlign:"center",minWidth:"110px"});const n=i.createElement("div");n.textContent=d,Object.assign(n.style,{fontSize:"20px",fontWeight:"700",color:x.value,lineHeight:"1.2"});const m=i.createElement("div");return m.textContent=u,Object.assign(m.style,{fontSize:"10px",color:x.label,marginTop:"2px"}),c.append(n,m),c}return o!==void 0&&r.appendChild(s(`${o.toFixed(1)}%`,`Yield \xB7 pass: ${t}`)),r.appendChild(s(String(e.dies.length),"Total dies")),r}function ae(e,t,o,r,s){const d=i.createElement("div");Object.assign(d.style,{display:"flex",flexDirection:"column",gap:"10px"});const u=e.length===1&&!r;u&&d.appendChild(oe(e[0]));const c=ee(e,r,s,!u);d.appendChild(c.card);const n=ne(e,t,o);for(const m of n.elements)c.card.appendChild(m);return n.testValuesCard&&d.appendChild(n.testValuesCard),n.functionalCard&&d.appendChild(n.functionalCard),{card:d,destroy:()=>{c.destroy(),n.destroy()}}}function re(e,t,o,r){const s=A(i),d=p=>({...p,testStats:p.statsSummary?.stats.perTestStats}),u=e.map(d),c=o?.map(p=>({key:p.key,items:p.items.map(d)})),n=ye({title:"Test value distribution",items:u,testDefs:t,groups:c,groupLabelText:r,colorScheme:g(),onSaveImage:h,onOpen:L?(p,v)=>F(p,`Wafer ${e.find(C=>C.waferIndex===p)?.label??p}`,v):void 0,ownerDocument:i}),m=he({title:"Value histogram",items:e,testDefs:t,groups:o,colorScheme:g(),onSaveImage:h,ownerDocument:i}),f=be({title:"Process capability",items:e,testDefs:t,groups:o,colorScheme:g(),onSaveImage:h,onSelectTest:p=>{n.setTest(p),m.setTest(p)},ownerDocument:i});return s.append(f.card,n.card,m.card),{card:s,destroy:()=>{f.destroy(),n.destroy(),m.destroy()}}}function ie(e,t,o){const r=A(i),s=Ce({title:"Test scatter",items:e,testDefs:t,groups:o,colorScheme:g(),onSaveImage:h,ownerDocument:i}),d=ge({title:"Test correlation matrix",items:e,testDefs:t,groups:o,colorScheme:g(),onSaveImage:h,onSelectPair:(u,c)=>s.setXY(u,c),ownerDocument:i});return r.append(d.card,s.card),{card:r,destroy:()=>{d.destroy(),s.destroy()}}}function Y(){for(const n of O)n.destroy();O=[],D.innerHTML="",S.innerHTML="",w.backTab&&S.appendChild(Z(w.backTab));for(const n of Oe)S.appendChild(J(n.key,n.label));const e=X();te(e);const t=ce(e,{facetableOnly:!0}).filter(n=>n.splittable),o=i.createElement("div");Object.assign(o.style,{display:"flex",gap:"8px",alignItems:"center"});let r;t.length>0?(o.appendChild(we("Group by:",[{value:"",label:"None"},...t.map(n=>({value:n.key,label:`${n.label} (${n.values.length})`}))],k??"",n=>{k=n||void 0,Y()},{hook:"group-by",ownerDocument:i})),r=t.find(n=>n.key===k)?.label):k=void 0,D.appendChild(o);const s=M().find(n=>n?.testDefs?.length)?.testDefs??[],d=s.filter(me);let u;if(k){const n=new Map,m=[];for(const f of e){const p=pe(f.metadata,k)??ue;n.has(p)||(n.set(p,[]),m.push(p)),n.get(p).push(f)}u=m.map(f=>({key:f,items:n.get(f)}))}const c=$==="overview"?ae(e,d,s,u,r):$==="distributions"?re(e,d,u,r):ie(e,d,u);O.push(c),D.appendChild(c.card)}return{el:B,render:Y,destroy:()=>{for(const e of O)e.destroy();B.remove()}}}
1
+ import{buildFacetTable as $e,facetValueOf as Be,FACET_NONE_VALUE as De}from"../stats/facets.js";import{mergeTestDefs as Le}from"../stats/mergeTestDefs.js";import{isParametricTest as Ie}from"../renderer/buildWaferMap.js";import{NO_DATA_FILL as ne}from"../renderer/colorMap.js";import{describeWaferPopulation as Oe,populationStat as Ee}from"../stats/population.js";import{LEADING as Pe,ALPHA as Ae,SPACE as w,EDGE_GUTTER as K,FONT as G,CLR as B,RADIUS as Re,SHADOW as je,controlStyle as We,wireControlHover as ae,wireTooltip as Ge}from"./toolbar.js";import{ICONS as He}from"./icons.js";import{renderCapabilityPanel as Ye}from"./charts/capability.js";import{renderBoxplotPanel as Fe}from"./charts/boxplot.js";import{renderTrendPanel as Me}from"./charts/trend.js";import{renderHistogramPanel as Ne}from"./charts/histogram.js";import{renderCorrelationPanel as Ve}from"./charts/correlation.js";import{renderScatterPanel as _e}from"./charts/scatter.js";import{renderBarPanel as oe}from"./charts/barPanel.js";import{renderBinClusterPanel as ze}from"./charts/binCluster.js";import{renderTestPassRatePanel as Ue}from"./charts/testPassRate.js";import{QUANTITY as qe}from"./charts/palette.js";import{cardFrameStyle as Qe,makeChartGridWrap as X,makeLabeledSelect as Ke,makeLinkedGroupSelect as Xe}from"./charts/chartShell.js";import{buildYieldData as N,buildYieldDataCombined as re}from"../stats/yield.js";import{buildBinParetoData as Je}from"../stats/binPareto.js";import{buildLotTestSection as Ze,buildLotFunctionalSection as et,buildMetadataStripBox as tt}from"./summaryPanel.js";import{buildRegionYieldData as ie,buildRingRegions as nt,buildQuadrantRegions as at}from"../stats/regions.js";import{renderRegionYieldDiagram as se}from"./charts/regionYieldDiagram.js";const ot=[{key:"overview",label:"Overview"},{key:"distributions",label:"Distributions"},{key:"correlation",label:"Correlation"}];export function createInsightsTab(D){const{getItems:le,getLotStats:de,getBinColors:J,passBins:T,getRingCount:ce,onSaveImage:v,onSaveText:V,openWafer:H,focusTest:Z}=D,pe=D.showMetadataStrip??!0,R=D.contentInset??K,d=D.ownerDocument??document,E=d.createElement("div");Object.assign(E.style,{display:"none",flexDirection:"column",width:"100%",paddingTop:"0"});const ue=K,P=d.createElement("div");Object.assign(P.style,{paddingLeft:ue});const $=d.createElement("div");Object.assign($.style,{display:"flex",gap:w.xs,alignItems:"center",background:B.menuBg,border:`1px solid ${B.menuBorder}`,borderRadius:Re.container,boxShadow:je.panel,padding:`0 ${w.lg}`,marginBottom:w.lg,marginLeft:R,marginRight:R}),$.setAttribute("role","tablist"),$.addEventListener("keydown",e=>{if(e.key!=="ArrowLeft"&&e.key!=="ArrowRight")return;const n=Array.from($.querySelectorAll('[role="tab"]')),o=n.indexOf(d.activeElement);if(o===-1)return;e.preventDefault();const c=n[(o+(e.key==="ArrowRight"?1:-1)+n.length)%n.length];c.focus(),c.click()});const j=d.createElement("div");Object.assign(j.style,{display:"flex",flexDirection:"column",gap:w.lg,marginTop:"0",paddingLeft:R,paddingRight:R}),E.appendChild(P),E.appendChild($),E.appendChild(j);let W=D.defaultView??"overview",A,I=null,L=null,Y={includeLimits:void 0,clipOutliers:!1};const _=e=>{L!==e&&(L=e,M())};let F=[];function z(e,n,o){H?.(e,n,o)}function fe(e){return H?{open:(n,o)=>z(n,`Wafer ${e.find(c=>c.waferIndex===n)?.label??n}`,o)}:Z&&e.length===1?{open:(n,o)=>Z(o),label:"show this test on the map"}:null}function me(){return le().map((e,n)=>e==null?null:{metadata:e.wafer.metadata??void 0,dies:e.dies,wafer:e.wafer,label:e.label??String(e.wafer.metadata?.waferId??""),waferIndex:n,statsSummary:e.statsSummary,testDefs:e.testDefs}).filter(e=>e!=null)}function ee(e,n){Object.assign(e.style,{background:"none",border:"none",borderBottom:n?`2px solid ${B.iconActive}`:"2px solid transparent",color:n?B.iconActive:B.label,fontWeight:n?"700":"500",fontSize:G.body,padding:`${w.sm} ${K} ${w.md}`,cursor:"pointer",marginBottom:"-1px"})}function be(e,n){const o=d.createElement("button");o.type="button",o.textContent=n;const c=e===W;return ee(o,c),o.dataset.on=c?"true":"false",ae(o,"bare"),o.dataset.wmapInsightsTab=e,o.setAttribute("role","tab"),o.setAttribute("aria-selected",c?"true":"false"),o.tabIndex=c?0:-1,o.addEventListener("click",()=>{W!==e&&(W=e,M())}),o}function ge(e){const n=d.createElement("button");return n.type="button",n.textContent=`\u2039 ${e.label}`,ee(n,!1),n.dataset.wmapInsightsBack="1",n.addEventListener("click",e.onBack),n}function ye(e,n,o,c=!0){const s=X(d),f=J();let y="label";const u=o??"group",m=T.length===1?`bin ${T[0]}`:`bins ${T.join(", ")}`,i=de?.(),b=new Map(i?.lotYieldSeries.map(r=>[r.waferIndex,r.yieldPercent])),h=r=>({...r,label:r.label.replace(/\s*·\s*\d+(\.\d+)?%$/,""),yieldPercent:b.get(r.waferIndex),key:r.waferIndex}),g=e.map(h),p=n?.map(r=>({key:r.key,items:r.items.map(h)})),t=()=>p?re(p,T,y):N(g,T,y),x={title:n?`Yield by ${u} (pass: ${m})`:`Yield by wafer (pass: ${m})`,data:t(),selfControl:{current:y,options:[["yield","Sort: yield"],["label",n?`Sort: ${u}`:"Sort: wafer ID"]],onChange:r=>(y=r,{data:t()})},barColor:()=>qe,valueLabel:r=>`${r.percent.toFixed(1)}%`,reference:r=>{if(r.length<3)return null;const k=r.map(Q=>Q.percent).sort((Q,ke)=>Q-ke),O=k.length%2?k[(k.length-1)/2]:(k[k.length/2-1]+k[k.length/2])/2;return{value:O,label:`median ${O.toFixed(1)}%`}},drill:p?{onOpenGroup:r=>{const k=p.find(O=>O.key===r.label)?.items??[];return{data:N(k,T,y),title:`Yield by wafer \u2014 ${u}: ${r.label} (pass: ${m})`}},onBack:()=>({data:t(),title:`Yield by ${u} (pass: ${m})`}),groupLabelText:u}:void 0,onOpen:H?r=>{typeof r.key=="number"&&z(r.key,`Wafer ${r.label}`)}:void 0,ownerDocument:d};let C=null;if(c&&(C=oe(x,v),C.card.style.minHeight="360px",s.appendChild(C.card)),n){const r=ze({title:"Hard bin pareto",groups:n.map(k=>({key:k.key,items:k.items.map(O=>({dies:O.dies,hardBinCounts:O.statsSummary?.stats.hardBinCounts,softBinCounts:O.statsSummary?.stats.softBinCounts}))})),onSaveImage:v,ownerDocument:d});return r.card.style.minHeight="360px",s.appendChild(r.card),{card:s,destroy:()=>{C?.destroy(),r.destroy()}}}let a="hbin";const l=r=>r===void 0?ne:(a==="hbin"?f.hard:f.soft).get(r)??ne,S=e.map(r=>({dies:r.dies,hardBinCounts:r.statsSummary?.stats.hardBinCounts,softBinCounts:r.statsSummary?.stats.softBinCounts})),te=()=>Je(S,a),ve={title:"Hard bin pareto",data:te(),selfControl:{current:a,options:[["hbin","Hard bins"],["sbin","Soft bins"]],onChange:r=>(a=r,{data:te(),title:`${a==="hbin"?"Hard":"Soft"} bin pareto`})},barColor:r=>l(r.binCode),ownerDocument:d},q=oe(ve,v);return q.card.style.minHeight="360px",s.appendChild(q.card),{card:s,destroy:()=>{C?.destroy(),q.destroy()}}}function U(){const e=d.createElement("div");return e.dataset.wmapChartCard="1",Object.assign(e.style,{...Qe(),display:"flex",flexDirection:"column",gap:w.lg,minWidth:"0"}),e}function he(e){if(P.innerHTML="",P.style.marginBottom="0",!pe)return;const n=tt(e.map(o=>({metadata:o.metadata})),void 0,{facetableOnly:!1});n&&(n.style.marginBottom="0",P.appendChild(n),P.style.marginBottom=w.xs)}function Ce(e,n,o,c){if(!e.length)return{elements:[],testValuesCard:null,functionalCard:null,destroy:()=>{}};const s=e.map(l=>l.wafer),f=e.map(l=>l.dies),y=e.flatMap(l=>l.dies),u=e.map(l=>l.statsSummary),m=u.every(l=>l!==void 0)?u:void 0,i=ce?.()??4,b=[],h=[],p=Ue({groups:(c??[{key:"",items:e}]).map(l=>({key:l.key,items:l.items.map(S=>({dies:S.dies,testSpecYield:S.statsSummary?.stats.testSpecYield,functionalYield:S.statsSummary?.stats.functionalYield}))})),testDefs:o,onSaveImage:v,ownerDocument:d});p.card.style.minHeight="300px",b.push(p.card),h.push(p.destroy);const t=ie(f,s,i,T,nt);if(t.length){const l=se({title:"Ring yield",mode:"ring",rows:t,onSaveImage:v,ownerDocument:d});b.push(l.card),h.push(l.destroy)}const x=ie(f,s,i,T,at);if(x.length){const l=se({title:"Quadrant yield",mode:"quadrant",rows:x,onSaveImage:v,ownerDocument:d});b.push(l.card),h.push(l.destroy)}let C=null;if(n.length){const l=Ze(y,n,void 0,m,V,f.map(S=>({dies:S})),void 0,"full");if(l){const S=U();S.appendChild(l),C=S}}let a=null;if(o.length){const l=et(y,o,m,V);if(l){const S=U();S.appendChild(l),a=S}}return{elements:b,testValuesCard:C,functionalCard:a,destroy:()=>{for(const l of h)l()}}}function xe(e){const n=T.length===1?`bin ${T[0]}`:`bins ${T.join(", ")}`,o=e.length===1,c=e[0],s=U();Object.assign(s.style,{flexDirection:"row",flexWrap:"wrap",gap:w.md});const f=i=>{const b=i.lastElementChild;return b&&Object.assign(b.style,{borderRight:"none",paddingRight:"0",marginRight:"0"}),i};function y(i,b,h){const g=d.createElement("div");Object.assign(g.style,{display:"flex",alignItems:"baseline",gap:w.sm,paddingRight:w.xxl,marginRight:w.md,borderRight:`1px solid ${B.menuBorder}`});const p=d.createElement("div");p.textContent=i,Object.assign(p.style,{fontSize:G.heading,fontWeight:"700",color:B.value,lineHeight:Pe.tight});const t=d.createElement("div");if(t.textContent=b,Object.assign(t.style,{fontSize:G.body,color:B.label}),g.append(p,t),h){const x=d.createElement("div");x.textContent=h,Object.assign(x.style,{fontSize:G.meta,color:B.label,opacity:Ae.muted}),g.appendChild(x)}return g}if(o){const i=N([{...c,key:c.waferIndex}],T)[0]?.percent;return i!==void 0&&s.appendChild(y(`${i.toFixed(1)}%`,`Yield \xB7 pass: ${n}`)),s.appendChild(y(String(c.dies.length),"Total dies")),f(s)}s.appendChild(y(String(e.length),"Wafers"));const u=N(e.map(i=>({...i,key:i.waferIndex})),T).map(i=>i.percent).filter(i=>Number.isFinite(i));if(u.length){const i=u.reduce((g,p)=>g+p,0)/u.length,b=re([{key:"all",items:e.map(g=>({...g,key:g.waferIndex}))}],T)[0]?.percent,h=b!==void 0&&b.toFixed(1)!==i.toFixed(1);s.appendChild(y(`${i.toFixed(1)}%`,`Mean per-wafer yield \xB7 pass: ${n}`,h?`${b.toFixed(1)}% by dies`:void 0))}const m=e.map(i=>i.statsSummary);if(m.every(i=>i!==void 0)){const i=m.reduce((h,g)=>h+g.stats.analyzedDies,0),b=m.reduce((h,g)=>h+g.stats.excludedDies,0);s.appendChild(y(i.toLocaleString(),"Dies analysed",b?`${b.toLocaleString()} excluded`:void 0))}else s.appendChild(y(e.reduce((i,b)=>i+b.dies.length,0).toLocaleString(),"Total dies"));return f(s)}function we(e,n,o,c,s){const f=d.createElement("div");Object.assign(f.style,{display:"flex",flexDirection:"column",gap:w.lg});const y=e.length===1&&!c;e.length&&!c&&f.appendChild(xe(e));const u=ye(e,c,s,!y);f.appendChild(u.card);const m=Ce(e,n,o,c);for(const i of m.elements)u.card.appendChild(i);return m.testValuesCard&&f.appendChild(m.testValuesCard),m.functionalCard&&f.appendChild(m.functionalCard),{card:f,destroy:()=>{u.destroy(),m.destroy()}}}function Se(e,n,o,c){const s=X(d),f=fe(e),y=a=>{Y=a;for(const l of[g,p,t])l!==u&&l?.setAxisPrefs(a)};let u=null;const m=a=>l=>{u=a(),y(l),u=null},i=a=>({...a,testStats:a.statsSummary?.stats.perTestStats}),b=e.map(i),h=o?.map(a=>({key:a.key,items:a.items.map(i)})),g=Fe({title:"Test value distribution",axisPrefs:Y,onAxisPrefsChange:m(()=>g),onTestChange:a=>x(a),selectedTestNumber:I??void 0,items:b,testDefs:n,groups:h,groupLabelText:c,onSaveImage:v,onGroupChange:a=>_(a),onOpen:f?.open,openActionLabel:f?.label,ownerDocument:d}),p=Ne({title:"Value histogram",axisPrefs:Y,onAxisPrefsChange:m(()=>p),onTestChange:a=>x(a),selectedTestNumber:I??void 0,items:e,testDefs:n,groups:o,onGroupChange:a=>_(a),onSaveImage:v,ownerDocument:d}),t=Me({title:"Wafer-to-wafer trend",axisPrefs:Y,onAxisPrefsChange:m(()=>t),onTestChange:a=>x(a),selectedTestNumber:I??void 0,items:e.map(a=>({label:a.label,key:a.waferIndex,dies:a.dies,testStats:a.statsSummary?.stats.perTestStats})),testDefs:n,onSaveImage:v,centreLabel:Ee(Oe(e.map(a=>a.wafer.metadata)),"mean"),onOpen:H?(a,l)=>z(a,`Wafer ${e.find(S=>S.waferIndex===a)?.label??a}`,l):void 0,ownerDocument:d}),x=a=>{I=a,g.setTest(a),p.setTest(a),t.setTest(a),C.setTest(a)},C=Ye({title:"Process capability",items:e,testDefs:n,onSaveImage:v,selectedTestNumber:I??void 0,onSelectTest:a=>x(a),ownerDocument:d});return s.append(C.card,g.card,p.card,t.card),{card:s,destroy:()=>{C.destroy(),g.destroy(),p.destroy(),t.destroy()}}}function Te(e,n,o){const c=X(d),s=_e({title:"Test scatter",items:e,testDefs:n,groups:o,binColors:J().hard,onSaveImage:v,ownerDocument:d}),f=Ve({title:"Test correlation matrix",items:e,testDefs:n,onSaveImage:v,onSaveText:V,onSelectPair:(y,u)=>s.setXY(y,u),ownerDocument:d});return c.append(f.card,s.card),{card:c,destroy:()=>{f.destroy(),s.destroy()}}}function M(){for(const t of F)t.destroy();F=[],j.innerHTML="",$.innerHTML="",D.backTab&&$.appendChild(ge(D.backTab));for(const t of ot)$.appendChild(be(t.key,t.label));const e=me();he(e);const n=$e(e,{facetableOnly:!0}).filter(t=>t.splittable),o=d.createElement("div");Object.assign(o.style,{display:"flex",gap:w.md,alignItems:"center",marginLeft:w.xxl,paddingBottom:w.xs});let c;n.length>0?(o.appendChild(Ke("Group by:",[{value:"",label:"None"},...n.map(t=>({value:t.key,label:`${t.label} (${t.values.length})`}))],A??"",t=>{A=t||void 0,L=null,M()},{hook:"group-by",ownerDocument:d})),c=n.find(t=>t.key===A)?.label):A=void 0;let s;if(A){const t=new Map,x=[];for(const C of e){const a=Be(C.metadata,A)??De;t.has(a)||(t.set(a,[]),x.push(a)),t.get(a).push(C)}s=x.map(C=>({key:C,items:t.get(C)}))}L!==null&&!s?.some(t=>t.key===L)&&(L=null),s&&s.length>0&&o.appendChild(Xe(s.map(t=>t.key),"Show:",L,t=>_(t),{ownerDocument:d}).el);let f=null;if(D.onOpenGuide){const t=d.createElement("button");t.type="button",t.innerHTML=He.help,t.setAttribute("aria-label","User guide"),Object.assign(t.style,{...We("bare"),display:"inline-flex",alignItems:"center",justifyContent:"center",width:"24px",height:"24px",flexShrink:"0"}),ae(t,"bare"),Ge(t,"User guide"),t.addEventListener("click",()=>D.onOpenGuide()),Object.assign(t.style,{marginLeft:"auto"}),f=t}$.appendChild(o),f&&$.appendChild(f);const y=L!==null?s?.find(t=>t.key===L):void 0,u=y?.items??e,m=y?void 0:s,i=Le(u),b=i.defs,h=b.filter(Ie);I!==null&&!h.some(t=>t.testNumber===I)&&(I=null);const g=W==="overview"?we(u,h,b,m,c):W==="distributions"?Se(u,h,m,c):Te(u,h,m),p=i.conflicts.filter(t=>t.excluded);if(p.length>0){const t=d.createElement("div");Object.assign(t.style,{color:B.label,fontSize:G.body,padding:`0 ${R} ${w.sm}`});const x=p.slice(0,6).map(l=>l.testNumber).join(", "),C=p.length>6?`, and ${p.length-6} more`:"",a=p.length===1?"it":"them";t.textContent=`${p.length} test ${p.length===1?"number is":"numbers are"} hidden (${x}${C}) \u2014 the wafers in view describe ${a} differently, so their values cannot be pooled. `+(s&&s.length>0?`Pick one ${c??"group"} under "Show:" to analyse ${a}.`:"Load one test program at a time to analyse them."),t.dataset.wmapWithheldTests=String(p.length),j.appendChild(t)}F.push(g),j.appendChild(g.card)}return{el:E,render:M,destroy:()=>{for(const e of F)e.destroy();E.remove()}}}
@@ -1,12 +1,16 @@
1
1
  import type { Die } from '../core/dies.js';
2
2
  import type { TestDef, BinDef } from '../renderer/buildWaferMap.js';
3
3
  import type { PlotMode } from '../renderer/buildView.js';
4
+ import type { BinColors } from '../renderer/binColors.js';
4
5
  export interface MaplessSummaryOptions {
5
6
  plotMode: PlotMode;
6
7
  activeTest?: number;
7
8
  hbinDefs?: BinDef[];
8
9
  sbinDefs?: BinDef[];
9
- colorScheme?: string;
10
+ /** The map's resolved bin colours (`View.binColors`), so bars match its legend. */
11
+ binColors?: BinColors;
12
+ /** The map's value gradient name, so histogram bars match its colorbar. */
13
+ valueColorScheme?: string;
10
14
  /** Effective log-scale setting for the active test — same resolution the
11
15
  * map itself uses (explicit viewOpts.logScale, falling back to the
12
16
  * TestDef's own default). */
@@ -1 +1 @@
1
- import{getDieTestValue as R}from"../renderer/buildWaferMap.js";import{resolveTestNumber as T,findTestDef as $}from"../renderer/buildView.js";import{buildBinSection as y}from"./summaryPanel.js";import{buildTestHistogramData as B}from"../stats/histogram.js";import{getColorScheme as z}from"../renderer/colorSchemes.js";import{CLR as u,getTooltip as E,positionTooltip as H,hideTooltip as V}from"./toolbar.js";import{fmt as b}from"../renderer/fmt.js";function c(i,n,e){const t=document.createElement(i);return n&&Object.assign(t.style,n),e!==void 0&&(t.textContent=e),t}function F(i,n){i.tabIndex=0,i.setAttribute("role","img"),i.setAttribute("aria-label",n);const e=m=>{const l=E(i.ownerDocument);if(l.textContent=n,l.style.display="block",m)H(l,i,m.clientX,m.clientY);else{const r=i.getBoundingClientRect();H(l,i,r.left+r.width/2,r.top)}},t=()=>V(i.ownerDocument);i.addEventListener("mousemove",e),i.addEventListener("mouseleave",t),i.addEventListener("focus",()=>e()),i.addEventListener("blur",t)}function I(i,n,e,t,m){let l=1/0,r=-1/0;for(const p of i){const a=R(p,n);a!==void 0&&(a<l&&(l=a),a>r&&(r=a))}const f=t==="spec"&&e&&(e.limitLow!==void 0||e.limitHigh!==void 0);let s,d;f?(s=e.limitLow!==void 0?e.limitLow:isFinite(l)?l:0,d=e.limitHigh!==void 0?e.limitHigh:isFinite(r)?r:1):(s=isFinite(l)?l:0,d=isFinite(r)?r:1),s===d&&(d=s+1);const x=p=>Math.min(1,Math.max(0,p));if(m&&s>0&&d>0){const p=Math.log10(s),a=Math.log10(d)-p;return h=>h<=0?0:x((Math.log10(h)-p)/a)}return p=>x((p-s)/(d-s))}function N(i,n,e,t,m,l,r){const f=c("div",{display:"flex",flexDirection:"column",gap:"2px",minWidth:"0",flex:"1",minHeight:"0"});f.appendChild(c("div",{fontSize:"10px",fontWeight:"700",letterSpacing:"0.06em",textTransform:"uppercase",color:u.label},n?.name?`${n.name} distribution`:"Value distribution"));const s=i[0].rangeLow,d=i[i.length-1].rangeHigh,x=d-s||1,p=o=>Math.min(1,Math.max(0,(o-s)/x)),a=z(t),h=I(m,e,n,l,r),S=Math.max(1,...i.map(o=>o.count)),L=c("div",{position:"relative",display:"flex",alignItems:"flex-end",gap:"2px",flex:"1",minHeight:"48px"});for(const o of i){const g=c("div",{flex:"1",minWidth:"2px",background:a.forValue(h((o.rangeLow+o.rangeHigh)/2)),height:`${o.count/S*100}%`,borderRadius:"1px 1px 0 0"});g.dataset.wmapBar="1",F(g,`${b(o.rangeLow,n?.unit)} \u2013 ${b(o.rangeHigh,n?.unit)}: ${o.count}`),L.appendChild(g)}const M=[];for(const[o,g]of[[n?.limitLow,"LSL"],[n?.limitHigh,"USL"]]){if(o===void 0||o<s||o>d)continue;const v=p(o)*100,w=c("div",{position:"absolute",top:"0",bottom:"0",left:`${v}%`,width:"2px",marginLeft:"-1px",background:u.value,boxShadow:`0 0 0 1px ${u.panelBg}`,pointerEvents:"none"});w.dataset.wmapLimitMarker="1",L.appendChild(w),M.push({pct:v,text:`${g} ${b(o,n?.unit)}`})}if(f.appendChild(L),M.length){const o=c("div",{position:"relative",height:"14px"});for(const{pct:g,text:v}of M){const w=Math.min(96,Math.max(4,g));o.appendChild(c("span",{position:"absolute",left:`${w}%`,top:"0",transform:"translateX(-50%)",whiteSpace:"nowrap",fontSize:"9px",fontWeight:"600",color:u.text,background:u.panelBg,border:`1px solid ${u.value}`,borderRadius:"2px",padding:"0 3px",lineHeight:"12px"},v))}f.appendChild(o)}const C=c("div",{display:"flex",justifyContent:"space-between",fontSize:"10px",color:u.label});return C.appendChild(c("span",{},b(i[0].rangeLow,n?.unit))),C.appendChild(c("span",{},b(i[i.length-1].rangeHigh,n?.unit))),f.appendChild(C),f}export function buildMaplessSummary(i,n,e){const{plotMode:t,activeTest:m,hbinDefs:l,sbinDefs:r,colorScheme:f,logScale:s=!1,colorbarRangeMode:d="spec",valueRangeDies:x}=e;if(t==="hardBin"||t==="softBin"){const a=y(i,t==="hardBin"?l:r,t==="hardBin"?"hard":"soft",f);if(a)return a}else if(t==="value"){const{testNumber:p}=T(m??0,n),a=$(n,m??0),h=B([{dies:i}],p,12,a?.limitLow,a?.limitHigh);if(h.length)return N(h,a,p,f,x??i,d,s)}return c("div",{padding:"12px",fontSize:"11px",color:u.label,textAlign:"center"},"No summary available for this view.")}
1
+ import{getDieTestValue as y}from"../renderer/buildWaferMap.js";import{resolveTestNumber as $,findTestDef as T}from"../renderer/buildView.js";import{buildBinSection as B}from"./summaryPanel.js";import{buildTestHistogramData as z}from"../stats/histogram.js";import{getValueColorScheme as N}from"../renderer/colorSchemes.js";import{TRACKING as V,SPACE as R,RADIUS as F,FONT as M,CLR as h,wireTooltip as I}from"./toolbar.js";import{fmt as v}from"../renderer/fmt.js";function d(o,n,t){const e=document.createElement(o);return n&&Object.assign(e.style,n),t!==void 0&&(e.textContent=t),e}function A(o,n,t,e,x){let p=1/0,m=-1/0;for(const s of o){const l=y(s,n);l!==void 0&&(l<p&&(p=l),l>m&&(m=l))}const c=e==="spec"&&t&&(t.limitLow!==void 0||t.limitHigh!==void 0);let a,r;c?(a=t.limitLow!==void 0?t.limitLow:isFinite(p)?p:0,r=t.limitHigh!==void 0?t.limitHigh:isFinite(m)?m:1):(a=isFinite(p)?p:0,r=isFinite(m)?m:1),a===r&&(r=a+1);const b=s=>Math.min(1,Math.max(0,s));if(x&&a>0&&r>0){const s=Math.log10(a),l=Math.log10(r)-s;return f=>f<=0?0:b((Math.log10(f)-s)/l)}return s=>b((s-a)/(r-a))}function W(o,n,t,e,x,p,m){const c=d("div",{display:"flex",flexDirection:"column",gap:R.xxs,minWidth:"0",flex:"1",minHeight:"0"});c.appendChild(d("div",{fontSize:M.meta,fontWeight:"700",letterSpacing:V,textTransform:"uppercase",color:h.label},n?.name?`${n.name} distribution`:"Value distribution"));const a=o[0].rangeLow,r=o[o.length-1].rangeHigh,b=r-a||1,s=i=>Math.min(1,Math.max(0,(i-a)/b)),l=N(e),f=A(x,t,n,p,m),g=Math.max(1,...o.map(i=>i.count)),S=d("div",{position:"relative",display:"flex",alignItems:"flex-end",gap:R.xxs,flex:"1",minHeight:"48px"});for(const i of o){const u=d("div",{flex:"1",minWidth:"2px",background:l.forValue(f((i.rangeLow+i.rangeHigh)/2)),height:`${i.count/g*100}%`,borderRadius:"1px 1px 0 0"});u.dataset.wmapBar="1",I(u,`${v(i.rangeLow,n?.unit)} \u2013 ${v(i.rangeHigh,n?.unit)}: ${i.count}`,{asDataPoint:!0}),S.appendChild(u)}const L=[];for(const[i,u]of[[n?.limitLow,"LSL"],[n?.limitHigh,"USL"]]){if(i===void 0||i<a||i>r)continue;const w=s(i)*100,C=d("div",{position:"absolute",top:"0",bottom:"0",left:`${w}%`,width:"2px",marginLeft:"-1px",background:h.value,boxShadow:`0 0 0 1px ${h.panelBg}`,pointerEvents:"none"});C.dataset.wmapLimitMarker="1",S.appendChild(C),L.push({pct:w,text:`${u} ${v(i,n?.unit)}`})}if(c.appendChild(S),L.length){const i=d("div",{position:"relative",height:"14px"});for(const{pct:u,text:w}of L){const C=Math.min(96,Math.max(4,u));i.appendChild(d("span",{position:"absolute",left:`${C}%`,top:"0",transform:"translateX(-50%)",whiteSpace:"nowrap",fontSize:M.body,fontWeight:"600",color:h.text,background:h.panelBg,border:`1px solid ${h.value}`,borderRadius:F.control,padding:"0 3px",lineHeight:"12px"},w))}c.appendChild(i)}const H=d("div",{display:"flex",justifyContent:"space-between",fontSize:M.body,color:h.label});return H.appendChild(d("span",{},v(o[0].rangeLow,n?.unit))),H.appendChild(d("span",{},v(o[o.length-1].rangeHigh,n?.unit))),c.appendChild(H),c}export function buildMaplessSummary(o,n,t){const{plotMode:e,activeTest:x,hbinDefs:p,sbinDefs:m,binColors:c,valueColorScheme:a,logScale:r=!1,colorbarRangeMode:b="spec",valueRangeDies:s}=t;if(e==="hardBin"||e==="softBin"){const l=e==="hardBin"?p:m,f=e==="hardBin"?c?.hard:c?.soft,g=B(o,l,e==="hardBin"?"hard":"soft",f);if(g)return g}else if(e==="value"){const{testNumber:l}=$(x??0,n),f=T(n,x??0),g=z([{dies:o}],l,12,f?.limitLow,f?.limitHigh);if(g.length)return W(g,f,l,a,s??o,b,r)}return d("div",{padding:R.xl,fontSize:M.body,color:h.label,textAlign:"center"},"No summary available for this view.")}
@@ -4,8 +4,8 @@ import type { WaferViewOptions } from './renderWaferMap.js';
4
4
  import type { RenderableWaferMap } from './renderWaferMap.js';
5
5
  import type { LotStatsSummary } from '../stats/types.js';
6
6
  import { type WarningsOptions } from './warnings.js';
7
- import type { SummaryPanelOptions } from './summaryPanel.js';
8
- import { type InsightsOptions } from './insightsTab.js';
7
+ import type { SummaryPanelOptions, FindingsNotice } from './summaryPanel.js';
8
+ import type { InsightsOptions } from './insightsTab.js';
9
9
  import type { DieListDisplayOptions } from './dieList.js';
10
10
  /**
11
11
  * The data and display overrides for a single gallery card.
@@ -101,6 +101,14 @@ export interface GalleryOptions {
101
101
  * map for a finding to highlight against.
102
102
  */
103
103
  summaryPanel?: SummaryPanelOptions;
104
+ /**
105
+ * A row at the top of the Findings section stating that a category of finding
106
+ * is not present, and optionally offering to compute it — see
107
+ * {@link FindingsNotice}. wmap never raises this itself: only the host knows
108
+ * what analysis it chose to skip and what running it would cost. Replaceable
109
+ * afterwards via the controller's `setFindingsNotice`.
110
+ */
111
+ findingsNotice?: FindingsNotice;
104
112
  /**
105
113
  * Display preferences for the lot-wide "View die list" link inside the
106
114
  * Summary panel — every die across every wafer, pooled, with a Wafer
@@ -181,6 +189,11 @@ export interface GalleryController {
181
189
  setFallbackFormat(format: 'si' | 'engineering'): void;
182
190
  /** Replace the lot-level stats summary used by the built-in Summary panel. */
183
191
  setLotStatsSummary(summary: LotStatsSummary | undefined): void;
192
+ /**
193
+ * Replace the lot Findings-section notice (see `FindingsNotice`). Pass
194
+ * `undefined` to clear it once the offered analysis has been run.
195
+ */
196
+ setFindingsNotice(notice: FindingsNotice | undefined): void;
184
197
  /**
185
198
  * Set the number of columns in the gallery grid. Pass `undefined` to restore
186
199
  * the auto-computed layout based on die pitch.
@@ -1,20 +1 @@
1
- import{getUniqueTestNumbers as kn,resolveTestNumber as Dn,findTestDef as Bn}from"../renderer/buildView.js";import{getColorScheme as En}from"../renderer/colorSchemes.js";import{metadataValueColor as On}from"../renderer/colorMap.js";import{resolveCanvasTheme as Tn}from"./canvasTheme.js";import{ICONS as ge}from"./icons.js";import{CLR as g,sevColor as Tt,BIN_LEGEND_MODES as Lt,STACKED_MODES as he,Z_ABOVE as Wt,applyOverlayZ as Ln,getTooltip as Wn,hideTooltip as Rt,createToolbarHelpers as Rn,buildModeMenuEl as In,openDetachWindow as $n,openFloatingWindow as Pn,openModal as Fn,openReportModal as An,copyWmapThemeTokens as Hn,syncWmapPopupTheme as jn,openUserGuideWindow as zn,makePaletteBtn as Vn,makeLogScaleBtn as Nn,makeLegendStyleBtn as _n,makeOverlaysBtn as Gn,makeOrientationBtn as Kn,menuLayerFor as It,saveImageBlob as qn,markMenuTrigger as be,wireMenuA11y as $t,wireExpandToggle as Pt,passFailMenuRows as Xn,requestedPassFailDisplay as Ue,logWmapVersionOnce as Un,buildDataModeEntries as Qn,metadataKeyHasData as Yn,metadataModeEntry as Zn}from"./toolbar.js";import{aggregateValues as Jn,aggregateBinCounts as Ft}from"../core/aggregates.js";import{renderWaferMap as Qe}from"./renderWaferMap.js";import{classifyChanged as eo}from"./renderWaferMap.js";import{buildWaferMap as to,getTestPassStatus as no,isParametricTest as At}from"../renderer/buildWaferMap.js";import{analyzeWaferMap as Le}from"../stats/analyzeWaferMap.js";import{collectWarnings as oo,buildWarningsMenuEl as io,severityOf as ao}from"./warnings.js";import{compareNatural as lo}from"../core/utils.js";import{createSummaryPanelEl as Ye,buildMetadataStripRow as so,buildCompactMetadataRows as Ht,metadataEntries as jt,renderLotSummaryContent as ro}from"./summaryPanel.js";import"../stats/facets.js";import{escHtml as ye,renderSection as co,renderSeverityBadge as uo,reportStyles as fo}from"../stats/reportHtml.js";import{createInsightsTab as po}from"./insightsTab.js";import{getDieKey as mo,hasPosition as go}from"../core/dies.js";function We(f){const D=new Set;return f.filter(p=>D.has(p.bin)?!1:(D.add(p.bin),!0))}function zt(f,D){const p=f.ownerDocument.createElement("div");Object.assign(p.style,{display:"flex",alignItems:"center",gap:"5px",cursor:"pointer",userSelect:"none",padding:"2px 4px",borderRadius:"3px"});const Q=f.ownerDocument.createElement("span");Object.assign(Q.style,{display:"inline-block",width:"13px",height:"13px",flexShrink:"0",background:D.color,border:D.isActive?`2px solid ${g.iconActive}`:`1px solid ${g.menuBorder}`,borderRadius:"2px",boxSizing:"border-box"});const ne=f.ownerDocument.createElement("span");ne.textContent=D.label,Object.assign(ne.style,{fontWeight:D.isActive?"700":"400",color:D.isActive?g.iconActive:g.text,whiteSpace:"nowrap"}),p.appendChild(Q),p.appendChild(ne),p.setAttribute("role","button"),p.setAttribute("aria-pressed",D.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",D.onClick),p.addEventListener("keydown",W=>{(W.key==="Enter"||W.key===" ")&&(W.preventDefault(),D.onClick())}),f.appendChild(p)}export function renderWaferGallery(f,D,p={}){Un();const Q=p.cardPadding??6,ne=p.downloadFilename??"wafer-gallery";let W=p.columns;const Vt=p.showPlotModeSelector??!0,Nt=p.showHelpButton??!1,_t=p.userGuideExtension,Ze=p.insights?.enabled??!1,Gt=Ln(p.zIndex),Y=p.summaryPanel,Je=p.passBins??[1];let we=p.fallbackFormat,E=p.lotStatsSummary,oe=p.legendPosition??"default",xe=p.perCardLegend??!1;function ie(){const e=r.plotMode??"hardBin";return Lt.has(e)?null:r.colorbarRangeMode==="data"?"Each map has its own value range, so it keeps its own colour bar":"This lot has no shared colour bar for value mode, so each map keeps its own"}function et(){const e=xe||ie()!==null;for(const t of v)t&&t.setOptions({showLegend:e})}let r={plotMode:"hardBin",colorScheme:"default",showDieLabels:!1,showRingBoundaries:!1,showQuadrantBoundaries:!1,ringCount:4,rotation:0,flipX:!1,flipY:!1,...p.viewOptions},v=[],q=[],Z=[],k=[],w=D.map(e=>typeof e=="function"?null:e),Re=0,ve=0;const I=new Map;let Kt=0,O=null,ae=null,tt=new Set,m=null,le="lot",qt={};function nt(e){return w[e]?.statsSummary??E?.perWafer.find(t=>t.waferIndex===e)?.summary}function Ce(){return!!(w.some(e=>e?.statsSummary?.findings.length)||E?.perWafer.some(e=>e.summary.findings.length))}const Xt=Wn(),J=Rn(Xt),{makeBtn:N,setActive:se,makeSep:$,makeMenuRow:Ut,makeMenuSection:Qt,makeDropdown:ot,makeCheckMenuBtn:ho,closeOpenMenu:Se,getOpenMenu:re,setOpenMenu:de}=J;f.ownerDocument.addEventListener("click",Se,!0);const it=()=>Rt();window.addEventListener("blur",it);function Ie(e){tt=new Set(e);const t=[...B.querySelectorAll(".wmap-gallery-card")];let n;t.forEach((o,s)=>{const c=tt.has(s);o.style.outline=c?`3px solid ${g.findingHighlight}`:"",o.style.outlineOffset=c?"-3px":"",c&&n===void 0&&(n=o)}),n?.scrollIntoView?.({behavior:"smooth",block:"nearest"})}function $e(){Ie([])}function Pe(){for(const e of v)e&&e.clearSelection()}function Fe(e,t){const n=new Set(e),o=t??v.map((s,c)=>c);for(const s of o){const c=k[s],i=v[s];if(!c||!i)continue;const d=c.dies.filter(l=>n.has(mo(l)));i.setSelection(d)}}function at(){const e=f.ownerDocument.createElement("div");Object.assign(e.style,{display:"flex",gap:"4px",marginBottom:"10px",borderBottom:`1px solid ${g.menuBorder}`,paddingBottom:"8px"});for(const t of["lot","wafers"]){const n=f.ownerDocument.createElement("button");n.type="button",n.textContent=t==="lot"?"Lot":"Findings";const o=le===t;Object.assign(n.style,{border:"none",borderRadius:"4px",padding:"2px 8px",fontSize:"11px",cursor:"pointer",fontWeight:o?"600":"400",background:o?g.bgActive:"transparent",color:o?g.iconHover:g.icon}),n.addEventListener("click",()=>{le=t,$e(),Pe(),R()}),e.appendChild(n)}return e}function Yt(){if(!m)return;m.innerHTML="",E&&m.appendChild(at());const e=[];for(let n=0;n<w.length;n++){const o=w[n];if(!o)continue;const s=nt(n)?.findings??[];if(!s.length)continue;const c=s.filter(d=>d.severity==="unusual").length,i=s.filter(d=>d.severity==="notable").length;e.push({index:n,item:o,unusualCount:c,notableCount:i,totalCount:s.length})}if(w.length>0){const n=f.ownerDocument.createElement("div"),o=e.length,s=w.filter(Boolean).length;n.textContent=o===0?`No findings on any of the ${s} wafers`:`${o} of ${s} wafer${s===1?"":"s"} with findings`,Object.assign(n.style,{fontSize:"11px",color:g.label,marginBottom:"8px"}),m.appendChild(n)}if(e.length>0){const n=f.ownerDocument.createElement("button");n.type="button",n.textContent="Findings report",Object.assign(n.style,{border:`1px solid ${g.menuBorder}`,borderRadius:"4px",padding:"3px 8px",marginBottom:"10px",fontSize:"10px",color:g.iconHover,background:"none",cursor:"pointer",display:"block",width:"100%",textAlign:"left"}),n.addEventListener("click",()=>{const o=`Findings report \u2014 ${e.length} wafer${e.length>1?"s":""}`,s=new Date().toLocaleString(),c=e.map(({item:d,index:l})=>{const a=nt(l),u=d.label??`W${l+1}`,h=a.findings.map(b=>`<li>${uo(b.severity)} ${ye(b.summary)}</li>`).join("");return co(ye(u),`<ul style="margin:0;padding-left:18px;list-style:none">${h}</ul>`)}).join(`
2
- `),i=`<!DOCTYPE html>
3
- <html lang="en">
4
- <head>
5
- <meta charset="UTF-8">
6
- <title>${ye(o)}</title>
7
- <style>
8
- ${fo()}
9
- </style>
10
- </head>
11
- <body>
12
- <main class="report">
13
- <header class="report-header">
14
- <h1>${ye(o)}</h1>
15
- <p class="report-subtitle">Generated ${ye(s)}</p>
16
- </header>
17
- ${c}
18
- </main>
19
- </body>
20
- </html>`;An(i,{anchor:f})}),m.appendChild(n)}if(e.length===0){const n=f.ownerDocument.createElement("div");Object.assign(n.style,{color:g.icon,fontSize:"11px",padding:"4px 0"}),n.textContent="No findings on any wafer.",m.appendChild(n)}else for(const{index:n,item:o,unusualCount:s,notableCount:c,totalCount:i}of e){const d=s?"unusual":c?"notable":"info",l=s+c||i,a=f.ownerDocument.createElement("button");a.type="button",Object.assign(a.style,{display:"flex",alignItems:"center",justifyContent:"space-between",width:"100%",padding:"5px 8px",marginBottom:"4px",border:"none",borderLeft:`3px solid ${Tt(d)}`,borderRadius:"3px",background:g.bgHover,cursor:"pointer",fontSize:"11px",textAlign:"left",boxSizing:"border-box"}),a.addEventListener("mouseover",()=>{a.style.background=g.bgActive}),a.addEventListener("mouseout",()=>{a.style.background=g.bgHover});const u=f.ownerDocument.createElement("span");u.textContent=o.label??`W${n+1}`,Object.assign(u.style,{color:g.iconHover,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"});const h=f.ownerDocument.createElement("span");h.textContent=String(l),a.setAttribute("aria-label",`${o.label??`W${n+1}`} \u2014 ${l} finding${l===1?"":"s"}${s?`, ${s} unusual`:""} \u2014 view wafer`),Object.assign(h.style,{marginLeft:"6px",flexShrink:"0",background:Tt(d),color:"#fff",borderRadius:"8px",padding:"1px 5px",fontSize:"10px",fontWeight:"600"}),a.appendChild(u),a.appendChild(h),a.addEventListener("click",()=>Oe(n,o)),m.appendChild(a)}const t=f.ownerDocument.createElement("div");t.style.height="12px",m.appendChild(t)}function R(){if(m)if(le==="lot"&&E){const e=We(w.flatMap(n=>n?.hbinDefs??[])),t=We(w.flatMap(n=>n?.sbinDefs??[]));ro(m,{lotSummary:E,items:w,hbinDefs:e.length?e:void 0,sbinDefs:t.length?t:void 0,testDefs:w.find(n=>n?.testDefs?.length)?.testDefs,passBins:Je,ringCount:r.ringCount,colorScheme:r.colorScheme,fallbackFormat:we,activeFindingId:ae,warnings:p.warnings?.display??!0?_:[],findingsFilter:qt,onFindingsFilterChange:R,onSaveText:p.onSaveText,onFindingClick:(n,o)=>{ae===n.id?Ae():Zt(n,o),R()},onWaferClick:n=>{Ie([n])},dieListOptions:p.dieList}),Ce()&&m.insertBefore(at(),m.firstChild)}else Yt()}function lt(e){return[e.variable.kind,e.variable.index??"",e.variable.bin??"",e.comparison.family,e.comparison.left,e.effect.direction].join("|")}function Ae(){ae=null,$e(),Pe(),C({highlightBin:void 0},{fireCallback:!1})}function Zt(e,t){if(ae===e.id){Ae();return}ae=e.id,t.style.background=g.bgActive,t.style.fontWeight="600";const{kind:n,index:o}=e.variable;n==="test"?C({plotMode:"value",activeTest:o??0,highlightBin:void 0},{fireCallback:!1}):n==="softBin"?C({plotMode:"softBin",highlightBin:void 0},{fireCallback:!1}):C({plotMode:"hardBin",highlightBin:void 0},{fireCallback:!1}),$e(),Pe();const s=e.highlight;if(s.kind==="wafer"){Ie(s.waferIndices);const c=lt(e);for(const i of s.waferIndices){const a=k[i]?.statsSummary?.findings.find(u=>lt(u)===c)?.highlight?.dieKeys;a?.length&&Fe(a,[i])}}else s.kind==="bin"?s.dieKeys?.length&&Fe(s.dieKeys):(s.kind==="region"||s.kind==="dies")&&s.dieKeys?.length&&Fe(s.dieKeys)}function X(){if(!O)return;const e=!!m;O.style.display=(E||Ce())&&e&&!je?"flex":"none";const t=m?m.style.display!=="none":!1;(E?.hasNotableFindings||w.some(o=>o?.statsSummary?.hasNotableFindings))&&!t?O.style.color=g.findingIndicator:O.dataset.active||(O.style.color=g.icon)}const T=f.ownerDocument.createElement("div");T.dataset.wmapToolbar="gallery",Object.assign(T.style,{display:"inline-flex",flexDirection:"row",alignItems:"center",gap:"0",background:g.menuBg,border:`1px solid ${g.menuBorder}`,borderRadius:"6px",padding:"3px 4px",marginBottom:"10px",boxShadow:"0 1px 4px rgba(0,0,0,0.10)",flexWrap:"wrap",minWidth:"0",overflowX:"auto"});const st=()=>{const e=re();e&&(e.remove(),de(null)),be(j,!1)},j=N("mode","Plot mode",()=>{if(re()){st();return}const e=w.flatMap(b=>b?.dies??[]),t=w.find(b=>b?.testDefs?.length)?.testDefs,{testEntries:n,binEntries:o,stackedEntries:s}=Qn(e,t,{includeStacked:!0}),c=r.plotMode??"hardBin",i=r.activeTest??0;function d(b){return b.plotMode!==c?!1:b.plotMode==="value"?i===(b.activeTest??0):b.plotMode==="metadata"?r.activeMetadataKey===b.activeMetadataKey:!0}function l(b,S){b.activeTest!==void 0?C({plotMode:"value",activeTest:b.activeTest,activeMetadataKey:void 0,logScale:b.logScale}):b.activeMetadataKey!==void 0?C({plotMode:b.plotMode,activeTest:void 0,activeMetadataKey:b.activeMetadataKey,passFailDisplay:"off"}):C({plotMode:b.plotMode,activeTest:void 0,activeMetadataKey:void 0,passFailDisplay:"off"}),S.remove(),de(null),be(j,!1)}const a=new Set,u=w.flatMap(b=>b?.metadataFields??[]).filter(b=>!a.has(b.key)&&a.add(b.key)).filter(b=>Yn(e,b.key)).map(Zn),h=In(j.getBoundingClientRect(),n,o,s,d,l,{makeMenuRow:Ut,makeMenuSection:Qt},c,j.ownerDocument.defaultView??window,u);It(j).appendChild(h),de(h),be(j,!0),$t(h,j,st)});be(j,!1);const Jt=()=>k.flatMap(e=>e?[...e.hbinDefs??[],...e.sbinDefs??[]]:[]).some(e=>e.color),{btn:en,sync:rt}=Vn(J,()=>r.plotMode??"hardBin",()=>r.colorScheme??"default",Jt,e=>C({colorScheme:e}),{get:()=>r.markFailingDies??!1,set:e=>C({markFailingDies:e})});rt();const tn=D.some(e=>typeof e!="function"&&(e.reticles?.length??0)>0);function He(){const e=w.find(n=>n?.testDefs?.length)?.testDefs,{testNumber:t}=Dn(r.activeTest??0,e);return{testNumber:t,td:Bn(e,t)}}function dt(){if((r.plotMode??"hardBin")!=="value")return!1;const{td:e}=He();return e!==void 0&&(e.limitLow!==void 0||e.limitHigh!==void 0)}function ce(){if((r.plotMode??"hardBin")!=="value")return!1;const{td:e}=He();return e!==void 0&&!At(e)}function nn(){if((r.plotMode??"hardBin")!=="value")return!1;const{testNumber:e,td:t}=He();return w.some(n=>n?.dies?.some(o=>no(o,e,t)!==void 0))}const on=Gn(J,()=>[{label:"Ring boundaries",active:!!r.showRingBoundaries,onClick:()=>C({showRingBoundaries:!r.showRingBoundaries})},{label:"Quadrant lines",active:!!r.showQuadrantBoundaries,onClick:()=>C({showQuadrantBoundaries:!r.showQuadrantBoundaries})},{label:"Die labels",active:!!r.showDieLabels,onClick:()=>C({showDieLabels:!r.showDieLabels})},{label:"Reticle grid",active:!!r.showReticle,enabled:tn,onClick:()=>C({showReticle:!r.showReticle})},{label:"XY indicator",active:!!r.showXYIndicator,onClick:()=>C({showXYIndicator:!r.showXYIndicator})},...Xn({functionalActive:ce(),hasLimits:dt()&&!ce(),hasRecorded:nn()&&!ce(),display:Ue(r)},e=>C({passFailDisplay:e}))],()=>!!(r.showRingBoundaries||r.showQuadrantBoundaries||r.showDieLabels||r.showReticle||r.showXYIndicator||Ue(r)!=="off")),{btn:an,sync:ct}=_n(J,()=>({plotMode:r.plotMode,legendPosition:oe}),e=>{oe=e;for(const t of v)t&&t.setOptions({legendPosition:oe})},{get:()=>xe,set:e=>{xe=e,et()},blockedReason:ie});ct();const ln=[{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"}],ut=ot("aggr","Aggregation method",()=>ln,()=>r.aggregationMethod??"mean",e=>C({aggregationMethod:e}));function ft(){const e=r.plotMode==="stackedValues";ut.style.display=e?"":"none"}ft();const{btn:sn,sync:pt}=Nn(J,()=>({...r,functionalActive:ce()}),e=>C(e));pt();const Me=N("specRange","Colorbar range: spec limits",()=>{const e=r.colorbarRangeMode==="data"?"spec":"data";C({colorbarRangeMode:e})});function mt(){const e=(r.plotMode??"hardBin")==="value"&&dt()&&Ue(r)==="off"&&!ce();Me.style.display=e?"":"none";const t=(r.colorbarRangeMode??"spec")==="spec";se(Me,t),Me.ariaLabel=t?"Colorbar range: spec limits (click for data range)":"Colorbar range: data range (click for spec limits)"}mt();const rn=Kn(J,()=>r,e=>C(e)),dn=N("downloadAll","Download gallery PNG",Sn),cn=ot("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"}],()=>W!=null?String(W):"auto",e=>Mt(e==="auto"?void 0:Number(e))),M=f.ownerDocument.createElement("div");Object.assign(M.style,{display:"inline-flex",alignItems:"center",gap:"0"}),T.appendChild(M),Vt&&M.appendChild(j),M.appendChild(en),M.appendChild(ut),M.appendChild(sn),M.appendChild(Me),M.appendChild($()),M.appendChild(on),M.appendChild($()),M.appendChild(an),M.appendChild($()),M.appendChild(rn),M.appendChild($()),M.appendChild(cn),M.appendChild($()),M.appendChild(dn),(E||Ce())&&(O=N("findings","Summary panel",()=>{if(!m)return;const e=m.style.display!=="none";e||R(),m.style.display=e?"none":"flex",se(O,!e),X()}),T.appendChild($()),T.appendChild(O));let P=null,ke=null,_=[],gt=!1;function ht(){const e=oo({lotStatsSummary:E,result:{warnings:w.flatMap(n=>n?.warnings??[])}}),t=e.length!==_.length||e.some((n,o)=>n.code!==_[o]?.code||n.message!==_[o]?.message);_=e,(t||!gt)&&(gt=!0,p.warnings?.onWarning?.(e)),un()}function un(){if(!P||!ke)return;const e=_.length,t=e>0;if(P.style.display=t?"flex":"none",ke.style.display=t?"":"none",!t)return;const n=ao(_[0]),o=`${e} data ${e===1?"warning":"warnings"}`;P.style.color=n==="error"?g.errText:g.warnText,P.ariaLabel=n==="error"?`${o} \u2014 wafers in this lot may be positionally wrong`:o}(p.warnings?.display??!0)&&(ke=$(),P=N("warning","Data warnings",()=>{const e=re();if(Se(new MouseEvent("click")),e)return;const t=io(P.getBoundingClientRect(),_,P.ownerDocument.defaultView??window);It(f).appendChild(t),de(t),$t(t,P,()=>Se(new MouseEvent("click")))}),be(P,!1),T.appendChild(ke),T.appendChild(P)),ht();let U=null;Ze&&(U=N("analysis","Insights",()=>{const e=ee?.style.display!=="none";yt(!e)}),U.dataset.wmapInsightsBtn="1",T.appendChild($()),T.appendChild(U));function bt(){import("./userGuideHtml.js").then(e=>zn({buildWaferMap:to,renderWaferMap:Qe,renderWaferGallery,analyzeWaferMap:Le},e.USER_GUIDE_HTML,_t,f))}Nt&&(T.appendChild($()),T.appendChild(N("help","User guide",()=>bt())));const G=f.ownerDocument.createElement("div");G.dataset.wmapGalleryLegend="1",Object.assign(G.style,{display:"flex",flexDirection:"column",gap:"6px",background:g.menuBg,border:`1px solid ${g.menuBorder}`,borderRadius:"6px",padding:"6px 10px",marginBottom:"10px",boxShadow:"0 1px 4px rgba(0,0,0,0.10)",fontSize:"12px",lineHeight:"1",boxSizing:"border-box",width:"100%",minWidth:"0"});const F=f.ownerDocument.createElement("div");Object.assign(F.style,{display:"flex",flexDirection:"row",gap:"12px",alignItems:"flex-start"});let ue=null,ee=null;Ze&&(ue=po({getItems:()=>w,getLotStats:()=>E,getColorSchemeName:()=>r.colorScheme??"default",passBins:Je,getRingCount:()=>r.ringCount??4,defaultView:p.insights?.defaultView,backTab:{label:"Gallery",onBack:()=>yt(!1)},showMetadataStrip:!1,onSaveImage:p.onSaveImage,onSaveText:p.onSaveText,ownerDocument:f.ownerDocument,openWafer:(e,t,n)=>{const o=w[e];if(!o)return;let s=null;const c=Fn({title:t,onClose:()=>s?.destroy(),anchor:f});Bt(c,t,o.wafer.metadata??void 0),s=Ge(c.contentWrap,o,n)}}),ee=ue.el);let je=!1;function yt(e){!ue||!ee||(je=e,ee.style.display=e?"flex":"none",F.style.display=e?"none":"flex",M.style.display=e?"none":"inline-flex",U&&(se(U,e),U.innerHTML=e?ge.wafer:ge.analysis,U.ariaLabel=e?"Back to gallery view":"Insights"),X(),Ee(),e&&ue.render())}const fn=4,ze=240,wt=480,pn=720,mn=1.25,xt=p.maxSize;let z=xt??wt;function vt(e){const t=Q*2+110+2;let n=null;for(const o of e){if(o==null||!o.dies?.length)continue;const s=o.dies[0].width;if(!(s>0))continue;const c=o.wafer.radius*2*(fn/s),i=Math.ceil(c+t);(n==null||i>n)&&(n=i)}return n}function gn(e){const t=vt(e);return t==null?ze:Math.min(z,Math.max(ze,t))}function hn(e){if(xt!=null)return!1;const t=vt(e);if(t==null)return!1;const n=Math.min(pn,Math.max(wt,t));return n<=z?!1:(z=n,!0)}function bn(){for(const e of Array.from(B.children))e.classList.contains("wmap-gallery-card")&&(e.style.maxWidth=`${z}px`,e.style.maxHeight=`${z}px`)}let De=ze,Ct=0;function St(e){const t=hn(e);if(t&&bn(),W!=null){t&&Be();return}const n=gn(e);n>De&&(De=n),Be()}function Mt(e){W=e,Be()}function Ve(e){return`repeat(${e}, minmax(0, ${z}px))`}function kt(e){B.style.gridTemplateColumns!==e&&(B.style.gridTemplateColumns=e)}function Be(){if(W!=null){kt(Ve(W));return}const e=Math.max(1,Ct),t=12,n=B.clientWidth||0,o=c=>(n-t*(c-1))/c;let s=Math.max(1,Math.ceil(Math.sqrt(e)));if(n>0){const c=Math.min(z,De*mn),i=d=>{let l=0;for(;l<e&&o(l+1)>=d;)l++;return l};s=i(c)||i(De)||1}kt(Ve(s))}const B=f.ownerDocument.createElement("div");if(Object.assign(B.style,{flex:"1 1 0",minWidth:"0",display:"grid",gridTemplateColumns:Ve(1),gap:"12px",justifyContent:"start",alignContent:"start",isolation:"isolate"}),le=E?"lot":"wafers",Y?.placement){const e=Y.placement;m=Ye(e,f.ownerDocument),m.style.maxHeight="calc(100vh - 80px)",m.style.position="sticky",m.style.top="8px",m.style.display="flex",m.style.flexDirection="column"}else if(E||Ce()){const e=!!Y?.defaultOpen;m=Ye("right",f.ownerDocument),m.style.maxHeight="calc(100vh - 80px)",m.style.position="sticky",m.style.top="8px",m.style.flexDirection="column",m.style.display=e?"flex":"none",R()}X(),m?.style.display!=="none"&&O&&se(O,!0),(Y?.placement??"right")==="left"?(m&&F.appendChild(m),F.appendChild(B)):(F.appendChild(B),m&&F.appendChild(m));const fe=f.ownerDocument.createElement("div");Object.assign(fe.style,{position:"sticky",top:"0",zIndex:"1",background:g.menuBg}),fe.appendChild(T),fe.appendChild(G),f.appendChild(fe),f.appendChild(F),ee&&f.appendChild(ee);function Ee(){G.innerHTML="";const e=r.plotMode??"hardBin",t=!je&&Lt.has(e),n=k.filter(y=>y!=null),o=n.find(y=>y.isLotStack),s=so(n.map(y=>({metadata:y.wafer.metadata??void 0})),o?{lotSize:o.lotSize??n.length,aggrMethod:o.aggrMethod}:void 0),c=e==="metadata",i=r.activeMetadataKey,d=new Set;if(t&&!c)for(const y of n)for(const L of y.dies){if(L.partial)continue;const x=e==="softBin"?L.sbin:L.hbin;x!=null&&d.add(x)}const l=t&&!c?[...d].sort((y,L)=>y-L):[],a=new Set;if(t&&c&&i)for(const y of n)for(const L of y.dies){if(L.partial)continue;const x=L.metadata?.[i];x!=null&&(typeof x=="string"||typeof x=="number"||typeof x=="boolean")&&a.add(String(x))}const u=t&&c?[...a].sort(lo):[];if(!s&&!l.length&&!u.length){G.style.display="none";return}if(G.style.display="flex",s&&G.appendChild(s),!l.length&&!u.length)return;const h=f.ownerDocument.createElement("div");Object.assign(h.style,{display:"flex",flexWrap:"wrap",alignItems:"center",gap:"6px 14px"}),s&&Object.assign(h.style,{borderTop:`1px solid ${g.separator}`,paddingTop:"6px"}),G.appendChild(h);const b=En(r.colorScheme),S=r.highlightBin;if(c){const y=r.highlightMetadataValue,L=k.flatMap(x=>x?.metadataFields??[]).find(x=>x.key===i);u.forEach((x,Ke)=>{const qe=y===x,Ot=L?.values?.find(Xe=>Xe.value===x),Mn=Ot?.color??On(Ke);zt(h,{color:Mn,isActive:qe,label:Ot?.label??x,onClick:()=>{const Xe=r.highlightMetadataValue===x?void 0:x;C({highlightMetadataValue:Xe})}})});return}const A=e==="softBin"?k.flatMap(y=>y?.sbinDefs??[]):k.flatMap(y=>y?.hbinDefs??[]),H=new Set,K=[];for(const y of A)H.has(y.bin)||(H.add(y.bin),K.push(y));const me=K.length>0?new Map(K.map(y=>[y.bin,y])):null;for(const y of l){const L=S===y,x=me?.get(y),Ke=(r.colorScheme==="custom"?x?.color:void 0)??b.forBin(y);zt(h,{color:Ke,isActive:L,label:x?.name?`${y} \xB7 ${x.name}`:`Bin ${y}`,onClick:()=>{const qe=r.highlightBin===y?void 0:y;C({highlightBin:qe})}})}}function pe(e){const t=w.filter(d=>d!==null);if(!t.length)return[];const n=t.map(d=>d.dies.filter(go)),o=t[0].wafer,s=t.length,c=o.metadata?{...o,metadata:(({wafer:d,waferId:l,...a})=>a)(o.metadata)}:o;function i(d,l){return{...d,stats:{...d.stats,isLotStack:!0,aggregationMethod:l,lotSize:s}}}if(e==="stackedValues"){const d=t.find(u=>u.testDefs?.length)?.testDefs;let l=d?.filter(At);if(d?.length||(l=kn(t.flatMap(h=>h.dies)).map(h=>({testNumber:h,name:`Test ${h}`}))),!l?.length)return[];const a=r.aggregationMethod??"mean";return l.map(u=>{const h=Jn(n,a,u.testNumber),b={testNumber:0,name:u.name,unit:u.unit};return{wafer:c,dies:h,testDefs:[b],label:`${u.name} \xB7 ${a}`,isLotStack:!0,aggrMethod:a,lotSize:s,statsSummary:i(Le({wafer:c,dies:h,testDefs:[b]},{testNumbers:[0]}),a)}})}if(e==="stackedBins"){let d=We(t.flatMap(l=>l.hbinDefs??[]));return(!d||d.length===0)&&(d=[...new Set(t.flatMap(a=>a.dies.map(u=>u.hbin).filter(u=>u!=null)))].sort((a,u)=>a-u).map(a=>({bin:a,name:`Bin ${a}`}))),d.map(l=>{const a=Ft(n,l.bin,"hard"),u=[{bin:l.bin,name:l.name}];return{wafer:c,dies:a,hbinDefs:u,label:`${l.bin} \xB7 ${l.name}`,isLotStack:!0,aggrMethod:"countBin",lotSize:s,statsSummary:i(Le({wafer:c,dies:a,hbinDefs:u}),"countBin")}})}if(e==="stackedSoftBins"){let d=We(t.flatMap(l=>l.sbinDefs??[]));return(!d||d.length===0)&&(d=[...new Set(t.flatMap(a=>a.dies.map(u=>u.sbin).filter(u=>u!=null)))].sort((a,u)=>a-u).map(a=>({bin:a,name:`Bin ${a}`}))),d.map(l=>{const a=Ft(n,l.bin,"soft"),u=[{bin:l.bin,name:l.name}];return{wafer:c,dies:a,sbinDefs:u,label:`${l.bin} \xB7 ${l.name}`,isLotStack:!0,aggrMethod:"countBin",lotSize:s,statsSummary:i(Le({wafer:c,dies:a,sbinDefs:u}),"countBin")}})}return t}function Ne(e){const t=w.length;return e==="stackedBins"||e==="stackedSoftBins"?{valueRange:[0,t],lotSize:t}:e==="stackedValues"?{aggregationMethod:r.aggregationMethod??"mean",valueRange:void 0,lotSize:void 0}:{}}const yn=new Set(["default","accessible","custom"]);function C(e,{fireCallback:t=!0}={}){const n=r.plotMode,o=ie()!==null;r={...r,...e};const s=r.plotMode,c=he.has(s),i=n!==void 0&&he.has(n),d=ve>0;if(e.plotMode!==void 0&&e.plotMode!==n&&(s==="hardBin"||s==="softBin")&&!yn.has(r.colorScheme??"")&&(r={...r,colorScheme:"default"}),e.plotMode!==void 0)if(c){const a=Ne(s);if(r={...r,...a},d)for(const u of v)u&&u.setOptions(e);else V(pe(s))}else if(i){const{valueRange:a,lotSize:u,aggregationMethod:h,...b}=r;if(r=b,d)for(const S of v)S&&S.setOptions(e);else V(w.filter(S=>S!==null))}else for(const a of v)a&&a.setOptions(e);else if(e.aggregationMethod!==void 0&&s==="stackedValues")if(d)for(const a of v)a&&a.setOptions(e);else V(pe("stackedValues"));else for(const a of v)a&&a.setOptions(e);ie()!==null!==o&&et(),Ee(),ft(),ct(),rt();const l=e.plotMode!==void 0&&e.plotMode!==n;if((e.colorScheme!==void 0||l)&&R(),pt(),mt(),t){const a=Object.keys(e);p.onViewOptionsChange?.(r,a,eo(a))}}function Dt(e,t,n){const o=e.createElement("div");Object.assign(o.style,{display:"flex",alignItems:"center",gap:"4px",flex:"1",minWidth:"0"});const s=e.createElement("span");s.textContent=t,Object.assign(s.style,{fontWeight:"700",fontSize:"13px",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}),o.appendChild(s);const c=jt(n??{});let i=null;if(c.length>0){const d=e.createElement("span");Object.assign(d.style,{fontSize:"12px",lineHeight:"1",color:g.label,flexShrink:"0"}),d.textContent="\u25BE",o.appendChild(d),Object.assign(o.style,{cursor:"pointer"}),i=e.createElement("div"),i.dataset.wmapCardMetaPanel="1",Object.assign(i.style,{position:"absolute",top:"0",left:"0",right:"0",zIndex:Wt,background:g.menuBg,borderBottom:`1px solid ${g.menuBorder}`,boxShadow:"0 2px 6px rgba(0,0,0,0.15)",padding:"8px 10px",fontSize:"11px",display:"none"});const l=Ht(n??{});l&&i.appendChild(l),o.setAttribute("aria-expanded","false"),o.setAttribute("aria-label",`Wafer info for ${t||"this card"}. Click to expand.`),Pt(o,a=>{d.textContent=a?"\u25B4":"\u25BE",o.setAttribute("aria-expanded",String(a)),i&&(i.style.display=a?"block":"none")})}return{wrap:o,metaPanel:i}}function Bt(e,t,n){const o=e.box.querySelector("[data-wmap-window-title]"),s=jt(n??{});if(!o||s.length===0)return;const c=o.parentElement,i=f.ownerDocument.createElement("div");Object.assign(i.style,{display:"flex",alignItems:"center",gap:"4px",flex:"1",minWidth:"0",cursor:"pointer"}),c?.insertBefore(i,o),i.appendChild(o);const d=f.ownerDocument.createElement("span");Object.assign(d.style,{fontSize:"12px",lineHeight:"1",color:g.label,flexShrink:"0"}),d.textContent="\u25BE",i.appendChild(d);const l=f.ownerDocument.createElement("div");l.dataset.wmapCardMetaPanel="1",Object.assign(l.style,{position:"absolute",top:"0",left:"0",right:"0",zIndex:Wt,background:g.menuBg,borderBottom:`1px solid ${g.menuBorder}`,boxShadow:"0 2px 6px rgba(0,0,0,0.15)",padding:"8px 10px",fontSize:"11px",display:"none"});const a=Ht(n??{});a&&l.appendChild(a),e.contentWrap.style.position="relative",e.contentWrap.appendChild(l),i.setAttribute("aria-expanded","false"),i.setAttribute("aria-label",`Wafer info for ${t}. Click to expand.`),Pt(i,u=>{d.textContent=u?"\u25B4":"\u25BE",i.setAttribute("aria-expanded",String(u)),l.style.display=u?"block":"none"})}function _e(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:"10px",overflow:"hidden",display:"flex",flexDirection:"column",position:"relative",aspectRatio:"1",maxWidth:`${z}px`,maxHeight:`${z}px`});const s=f.ownerDocument.createElement("div");Object.assign(s.style,{display:"flex",alignItems:"center",padding:"8px 10px 6px",borderBottom:`1px solid ${g.menuBorder}`,flexShrink:"0",gap:"6px"});const{wrap:c,metaPanel:i}=Dt(document,e.label??"",e.wafer.metadata??void 0);s.appendChild(c);const d=f.ownerDocument.createElement("button");d.dataset.wmapExpandBtn="1",d.title="Open full view",d.innerHTML=ge.expand,Object.assign(d.style,{display:"flex",alignItems:"center",justifyContent:"center",border:`1px solid ${g.menuBorder}`,borderRadius:"4px",background:g.panelBg,color:g.label,padding:"2px",cursor:"pointer",flexShrink:"0",width:"22px",height:"22px"}),s.appendChild(d),o.appendChild(s);const l=f.ownerDocument.createElement("div");Object.assign(l.style,{position:"relative",flex:"1",minHeight:"0",overflow:"hidden",display:"flex",flexDirection:"column"}),o.appendChild(l),i&&l.appendChild(i),B.appendChild(o);const a=xe||ie()!==null,u=e.viewOptions?{...r,...e.viewOptions}:r,h=Qe(l,e,{viewOptions:{...u,showLegend:a},toolbarControls:"full",showTooltip:!0,padding:Q,legendPosition:oe,fallbackFormat:we,statsSummary:e.statsSummary,onSaveImage:p.onSaveImage,onSaveText:p.onSaveText,onClick:e.onClick,onSelect:e.onSelect,onExpand:()=>Oe(t,e),showMetadataBadge:!1});return h.setViewControlsVisible(!1),h.setSummaryVisible(!1),d.onclick=()=>Oe(t,e),{card:o,ctrl:h,canvasWrapper:l,expandBtn:d}}function wn(e){const t=Z[e];if(!t)return;const n=[...I.values()].find(o=>o.cardIndex===e);n?(t.innerHTML=ge.minimize,t.title="Reattach to gallery",t.setAttribute("aria-label","Reattach to gallery"),t.onclick=()=>vn(n.id)):(t.innerHTML=ge.expand,t.title="Open full view",t.setAttribute("aria-label","Open full view"),t.onclick=()=>Oe(e,k[e]))}function V(e){Cn(),re()?.remove(),de(null),Ae(),k=[];for(const i of v)i&&i.destroy();v=[],q=[],Z=[],ve=0,B.innerHTML="",Ct=e.length,St(e.map(i=>typeof i=="function"?null:i));const t=[];for(let i=0;i<e.length;i++){const d=e[i];if(typeof d=="function"){const l=f.ownerDocument.createElement("div");l.className="wmap-gallery-card",Object.assign(l.style,{background:g.menuBg,border:`1px solid ${g.menuBorder}`,borderRadius:"10px",aspectRatio:"1",display:"flex",alignItems:"center",justifyContent:"center"});const a=f.ownerDocument.createElement("span");a.textContent="\u2026",Object.assign(a.style,{color:g.label,fontSize:"18px"}),l.appendChild(a),B.appendChild(l),k.push(null),v.push(null),q.push(null),Z.push(null),t.push({index:i,factory:d,placeholder:l}),ve++}else{const{ctrl:l,canvasWrapper:a,expandBtn:u}=_e(d,i,e.length);k.push(d),v.push(l),q.push(a),Z.push(u)}}k.flatMap(i=>i?[...i.hbinDefs??[],...i.sbinDefs??[]]:[]).some(i=>i.color)&&!p.viewOptions?.colorScheme&&(r={...r,colorScheme:"custom"}),Ee();const o=++Re;let s=0;function c(){if(o!==Re)return;if(s>=t.length){if(he.has(r.plotMode)){const A=r.plotMode;V(pe(A))}return}const{index:i,factory:d,placeholder:l}=t[s++],a=d();k[i]=a,w[i]=a,St([a]);const{card:u,ctrl:h,canvasWrapper:b,expandBtn:S}=_e(a,i,e.length);v[i]=h,q[i]=b,Z[i]=S,ve--,l.replaceWith(u),Ee(),!m&&!Y?.placement&&a.statsSummary?.findings.length?(E||(le="wafers"),m=Ye("right",f.ownerDocument),m.style.maxHeight="calc(100vh - 80px)",m.style.position="sticky",m.style.top="8px",m.style.flexDirection="column",m.style.display="none",(Y?.placement??"right")==="left"?F.insertBefore(m,B):F.appendChild(m),R(),O||(O=N("findings","Summary panel",()=>{if(!m)return;const H=m.style.display!=="none";H||R(),m.style.display=H?"none":"flex",se(O,!H),X()}),T.appendChild($()),T.appendChild(O)),X()):m&&m.style.display!=="none"&&R(),X(),setTimeout(c,0)}t.length>0&&setTimeout(c,0)}if(he.has(r.plotMode)&&w.length>0){const e=Ne(r.plotMode);r={...r,...e},V(pe(r.plotMode))}else V(D);let te=0;const Et=new(f.ownerDocument.defaultView??window).ResizeObserver(()=>{if(te)return;te=(f.ownerDocument.defaultView??window).requestAnimationFrame(()=>{te=0,W==null&&Be()})});Et.observe(B),m&&R();function xn(e,t){const n=q[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:"12px",textAlign:"center",padding:"0 12px"}),n.appendChild(o)}function Oe(e,t){for(const i of I.values())if(i.cardIndex===e)return;const n=t.label??"Wafer map",o=Kt++,s=v[e]?.getOptions(),c=$n(n);if(c){const i=c.document;i.title=n,Object.assign(i.documentElement.style,{height:"100%"}),Object.assign(i.body.style,{margin:"0",height:"100vh",overflow:"hidden",display:"flex",flexDirection:"column",fontFamily:'system-ui, -apple-system, "Segoe UI", sans-serif'}),Hn(f,i.documentElement);const d=jn(f,i.documentElement,()=>A.setOptions({})),l=i.createElement("div");l.dataset.wmapWindowBanner="1",l.textContent=n,Object.assign(l.style,{display:"none",padding:"6px 12px",fontSize:"12px",fontWeight:"700",background:g.warnBg,color:g.warnText,borderBottom:`1px solid ${g.warnBorder}`,flexShrink:"0"}),i.body.appendChild(l);const a=i.createElement("div");Object.assign(a.style,{flex:"1",minHeight:"0",display:"flex",flexDirection:"column"}),i.body.appendChild(a);const{wrap:u,metaPanel:h}=Dt(i,n,t.wafer.metadata??void 0),b=i.createElement("div");Object.assign(b.style,{display:"flex",alignItems:"center",padding:"8px 10px 6px",borderBottom:`1px solid ${g.menuBorder}`,flexShrink:"0",gap:"6px"}),b.appendChild(u),a.appendChild(b);const S=i.createElement("div");Object.assign(S.style,{position:"relative",flex:"1",minHeight:"0",overflow:"hidden",display:"flex",flexDirection:"column"}),h&&S.appendChild(h),a.appendChild(S);const A=Ge(S,t,void 0,s),H=setInterval(()=>{c.closed&&Te(o)},400);c.addEventListener("pagehide",()=>Te(o)),I.set(o,{id:o,ctrl:A,cardIndex:e,label:n,closePollId:H,stopThemeSync:d,close:()=>{c.closed||c.close()},setTitle:K=>{i.title=K,l.textContent=K,l.style.display="block"}})}else{const i=Pn({title:n,onClose:()=>Te(o),anchor:f});i.contentWrap.style.flexDirection="column",Bt(i,n,t.wafer.metadata??void 0);const d=Ge(i.contentWrap,t,void 0,s);I.set(o,{id:o,ctrl:d,cardIndex:e,label:n,closePollId:null,close:()=>i.close(),setTitle:l=>{const a=i.box.querySelector("[data-wmap-window-title]");a&&(a.textContent=l,a.title=l)}})}v[e]?.destroy(),v[e]=null,xn(e,c!==null),wn(e)}function Ge(e,t,n,o){const s=t.viewOptions?{...r,...t.viewOptions}:r,c=o?{...s,...o}:s,d={...n!==void 0?{...c,plotMode:"value",activeTest:n}:c,showLegend:!0},l=Qe(e,t,{viewOptions:d,toolbarControls:"full",showTooltip:!0,padding:Q,legendPosition:oe,fallbackFormat:we,statsSummary:t.statsSummary,onSaveImage:p.onSaveImage,onSaveText:p.onSaveText,onClick:t.onClick,onSelect:t.onSelect,showExpandButton:!1,showMetadataBadge:!1});return l.setViewControlsVisible(!0),l.setSummaryVisible(!0),l.setExpandVisible(!1),l}function Te(e){const t=I.get(e);if(!t)return;I.delete(e),t.closePollId!=null&&clearInterval(t.closePollId),t.stopThemeSync?.();const n=t.ctrl.getOptions();if(t.ctrl.destroy(),t.cardIndex===null)return;const o=t.cardIndex,s=k[o];if(!s)return;const c={...s,viewOptions:n};k[o]=c;const{card:i,ctrl:d,canvasWrapper:l,expandBtn:a}=_e(c,o,k.length);q[o]?.parentElement?.replaceWith(i),v[o]=d,q[o]=l,Z[o]=a}function vn(e){const t=I.get(e);t&&(t.close(),Te(e))}function Cn(){for(const e of I.values())e.cardIndex!==null&&(e.cardIndex=null,e.setTitle(`${e.label} \u2014 unlinked from gallery`))}function Sn(){const e=[...B.querySelectorAll("canvas")];if(!e.length)return;const t=e.length,n=Math.ceil(Math.sqrt(t)),o=Math.ceil(t/n),s=e[0].width,c=e[0].height,i=8,d=window.devicePixelRatio||1,l=Math.round(26*d),a=Math.round(12*d),u=f.ownerDocument.createElement("canvas");u.width=n*s+(n-1)*i,u.height=o*(c+l)+(o-1)*i;const h=u.getContext("2d"),b=Tn(B);h.fillStyle=b.background,h.fillRect(0,0,u.width,u.height),e.forEach((S,A)=>{const H=A%n,K=Math.floor(A/n),me=H*(s+i),y=K*(c+l+i),L=S.closest(".wmap-gallery-card")?.querySelector("span")?.textContent??"";h.fillStyle=b.surface,h.fillRect(me,y,s,l),h.fillStyle=b.text,h.font=`700 ${a}px system-ui, sans-serif`,h.textAlign="left",h.textBaseline="middle",h.fillText(L,me+Math.round(10*d),y+l/2,s-Math.round(20*d)),h.drawImage(S,me,y+l)}),u.toBlob(S=>{S&&qn(S,ne,p.onSaveImage)})}return{setItems(e){w=e.map(n=>typeof n=="function"?null:n);const t=r.plotMode;if(he.has(t))if(e.some(o=>typeof o=="function"))V(e);else{const o=Ne(t);r={...r,...o},V(pe(t))}else V(e)},setOptions(e){C(e,{fireCallback:!1})},getOptions(){return{...r}},setFallbackFormat(e){we=e;for(const t of v)t&&t.setFallbackFormat(e)},setLotStatsSummary(e){E=e,ht(),m&&R(),X()},setColumns(e){Mt(e)},openUserGuide:bt,destroy(){Re++;for(const e of[...I.values()])e.closePollId!=null&&clearInterval(e.closePollId),e.close(),e.ctrl.destroy();I.clear();for(const e of v)e&&e.destroy();v=[],re()?.remove(),Et.disconnect(),te&&((f.ownerDocument.defaultView??window).cancelAnimationFrame(te),te=0),f.ownerDocument.removeEventListener("click",Se,!0),window.removeEventListener("blur",it),Gt(),Rt(),fe.remove(),F.remove(),m?.remove(),ue?.destroy()}}}
1
+ import{getUniqueTestNumbers as ro,resolveTestNumber as co,findTestDef as fo,collectMetadataValues as uo}from"../renderer/buildView.js";import{metadataCategoricalValue as po}from"../core/metadata.js";import{resolveBinColors as go,binColorWarning as mo}from"../renderer/binColors.js";import{NO_DATA_FILL as ho}from"../renderer/colorMap.js";import{metadataValueColor as bo}from"../renderer/colorMap.js";import{resolveCanvasTheme as yo}from"./canvasTheme.js";import{ICONS as $e}from"./icons.js";import{SHADOW as We,LEADING as Ze,TRACKING as wo,controlStyle as xo,wireControlHover as mt,SPACE as x,EDGE_GUTTER as te,MAP_CHROME_INSET as vo,RADIUS as V,FONT as O,CLR as m,sevColor as an,MODE_LABELS as Co,BIN_LEGEND_MODES as sn,STACKED_MODES as be,Z_ABOVE as rn,applyOverlayZ as So,getTooltip as Mo,hideTooltip as dn,createToolbarHelpers as Do,buildModeMenuEl as ko,openDetachWindow as Eo,openFloatingWindow as Bo,openModal as Oo,openReportModal as To,copyWmapThemeTokens as Lo,syncWmapPopupTheme as $o,openUserGuideWindow as Wo,makePaletteBtn as Ro,makeLogScaleBtn as Io,makeLegendStyleBtn as Ao,makeOverlaysBtn as Po,makeOrientationBtn as Fo,menuLayerFor as cn,saveImageBlob as Ho,markMenuTrigger as Re,wireMenuA11y as fn,wireExpandToggle as un,wireTooltip as pn,requestedPassFailDisplay as gn,overlayMenuRows as jo,anyOverlayActive as Vo,logWmapVersionOnce as zo,buildDataModeEntries as No,metadataKeyHasData as _o,metadataModeEntry as Go}from"./toolbar.js";import{aggregateValues as Ko,aggregateBinCounts as mn}from"../core/aggregates.js";import{renderWaferMap as ht}from"./renderWaferMap.js";import{classifyChanged as qo,COLOR_KEYS as Uo}from"./renderWaferMap.js";import{buildWaferMap as Xo,getTestPassStatus as hn,isParametricTest as bt,getDieTestValue as Zo}from"../renderer/buildWaferMap.js";import{analyzeWaferMap as Ye}from"../stats/analyzeWaferMap.js";import{collectWarnings as Yo,buildWarningsMenuEl as Qo,severityOf as Jo}from"./warnings.js";import{compareNatural as bn}from"../core/utils.js";import{createSummaryPanelEl as yt,buildMetadataStripRow as ei,buildCompactMetadataRows as yn,metadataEntries as wn,renderLotSummaryContent as ti}from"./summaryPanel.js";import{renderLotSummaryReportHtml as ni}from"../stats/renderSummaryReport.js";import{prettyKey as oi}from"../stats/facets.js";import{mergeTestDefs as ii}from"../stats/mergeTestDefs.js";import{getDieKey as li,hasPosition as ai}from"../core/dies.js";function ne(f){const C=new Set;return f.filter(p=>C.has(p.bin)?!1:(C.add(p.bin),!0))}const wt=12;function si(f,C,p){let P=C;if(C.length>wt){const v=C.slice(0,wt-1),T=C.slice(wt-1),oe=T.reduce((Je,re)=>Je+re.count,0);P=[...v,{color:m.label,count:oe,label:`Other (${T.length} bins)`}]}const F=f.createElement("div");Object.assign(F.style,{display:"flex",width:"100%",height:"8px",borderRadius:V.control,overflow:"hidden",border:`1px solid ${m.menuBorder}`,boxSizing:"border-box",marginTop:x.xs,flexShrink:"0"}),F.setAttribute("role","img"),F.setAttribute("aria-label",`Population split: ${P.map(v=>`${v.label} ${Qe(v.count/p*100)}`).join(", ")}`);for(const v of P){const T=v.count/p*100,oe=f.createElement("div");Object.assign(oe.style,{flex:`${T} 1 0`,minWidth:T>0?"2px":"0",background:v.color}),pn(oe,`${v.label} \xB7 ${v.count.toLocaleString()} dies \xB7 ${Qe(T)}`),F.appendChild(oe)}return F}function Qe(f){return f>0&&f<.1?"<0.1%":`${f.toFixed(1)}%`}function xn(f,C){const p=new Map;let P=0;for(const F of f)for(const v of F.dies){if(v.partial||v.edgeExcluded)continue;const T=C(v);T!==void 0&&(p.set(T,(p.get(T)??0)+1),P++)}return{counts:p,total:P}}function vn(f,C){const p=f.ownerDocument.createElement("div");Object.assign(p.style,{display:"flex",alignItems:"center",gap:"5px",cursor:"pointer",userSelect:"none",padding:`${x.xxs} ${x.xs}`,borderRadius:V.control});const P=f.ownerDocument.createElement("span");Object.assign(P.style,{display:"inline-block",width:"13px",height:"13px",flexShrink:"0",background:C.color,border:C.isActive?`2px solid ${m.iconActive}`:`1px solid ${m.menuBorder}`,borderRadius:V.control,boxSizing:"border-box"});const F=f.ownerDocument.createElement("span");if(F.textContent=C.label,Object.assign(F.style,{fontWeight:C.isActive?"700":"400",color:C.isActive?m.iconActive:m.text,whiteSpace:"nowrap"}),p.appendChild(P),p.appendChild(F),C.count!==void 0){const v=f.ownerDocument.createElement("span");if(v.textContent=C.count.toLocaleString(),Object.assign(v.style,{color:C.isActive?m.iconActive:m.text,fontWeight:C.isActive?"700":"400",whiteSpace:"nowrap"}),p.appendChild(v),C.percent!==void 0){const T=f.ownerDocument.createElement("span");T.textContent=Qe(C.percent),Object.assign(T.style,{color:m.label,whiteSpace:"nowrap"}),p.appendChild(T)}}p.setAttribute("role","button"),p.setAttribute("aria-pressed",C.isActive?"true":"false"),p.tabIndex=0,p.addEventListener("mouseenter",()=>{p.style.background=m.bgHover}),p.addEventListener("mouseleave",()=>{p.style.background="transparent"}),p.addEventListener("focus",()=>{p.style.background=m.bgHover}),p.addEventListener("blur",()=>{p.style.background="transparent"}),p.addEventListener("click",C.onClick),p.addEventListener("keydown",v=>{(v.key==="Enter"||v.key===" ")&&(v.preventDefault(),C.onClick())}),f.appendChild(p)}export function renderWaferGallery(f,C,p={}){zo();const P=p.cardPadding??6,F=p.downloadFilename??"wafer-gallery";let v=p.columns;const T=p.showPlotModeSelector??!0,oe=p.showHelpButton??!1,Je=p.userGuideExtension,re=p.insights?.enabled??!1,Cn=So(p.zIndex),de=p.summaryPanel,ye=p.passBins??[1];let Ie=p.fallbackFormat,H=p.lotStatsSummary,we=p.legendPosition??"default",Ae=p.perCardLegend??!1;function xe(){const e=d.plotMode??"hardBin";return sn.has(e)?null:d.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 xt(){const e=Ae||xe()!==null;for(const t of S)t&&t.setOptions({showLegend:e})}let d={plotMode:"hardBin",showDieLabels:!1,showRingBoundaries:!1,showQuadrantBoundaries:!1,ringCount:4,rotation:0,flipX:!1,flipY:!1,...p.viewOptions},S=[],ie=[],ce=[],L=[],w=C.map(e=>typeof e=="function"?null:e);function vt(){return ii(w)}function fe(){if(w.some(e=>e?.testDefs?.length))return vt().defs}let et=0,Pe=0;const z=new Map;let Sn=0,A=null,ve=null,Ct=new Set,h=null,Mn={};function St(e){return w[e]?.statsSummary??H?.perWafer.find(t=>t.waferIndex===e)?.summary}function tt(){return!!(w.some(e=>e?.statsSummary?.findings.length)||H?.perWafer.some(e=>e.summary.findings.length))}const Dn=Mo(),ue=Do(Dn),{makeBtn:Z,setActive:Ce,makeSep:N,makeMenuRow:kn,makeMenuSection:En,makeDropdown:Mt,closeOpenMenu:Fe,getOpenMenu:Se,setOpenMenu:Me}=ue;f.ownerDocument.addEventListener("click",Fe,!0);const Dt=()=>dn();window.addEventListener("blur",Dt);let kt=p.findingsNotice;function Et(e){Ct=new Set(e);const t=[...I.querySelectorAll(".wmap-gallery-card")];let n;t.forEach((o,c)=>{const l=Ct.has(c);o.style.outline=l?`3px solid ${m.findingHighlight}`:"",o.style.outlineOffset=l?"-3px":"",l&&n===void 0&&(n=o)}),n?.scrollIntoView?.({behavior:"smooth",block:"nearest"})}function Bt(){Et([])}function Ot(){for(const e of S)e&&e.clearSelection()}function nt(e,t){const n=new Set(e),o=t??S.map((c,l)=>l);for(const c of o){const l=L[c],a=S[c];if(!l||!a)continue;const s=l.dies.filter(i=>n.has(li(i)));a.setSelection(s)}}function Bn(){const e=[];for(let t=0;t<w.length;t++){const n=w[t];if(!n)continue;const o=St(t)?.findings??[];o.length&&e.push({index:t,item:n,unusualCount:o.filter(c=>c.severity==="unusual").length,notableCount:o.filter(c=>c.severity==="notable").length,totalCount:o.length})}return e}function On(e){const t=L[e]??w[e];t&&Te(e,t)}function Tn(e){const t=St(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 Ln(){const e=ne(w.flatMap(n=>n?.hbinDefs??[])),t=ne(w.flatMap(n=>n?.sbinDefs??[]));To(ni({items:w.map((n,o)=>({label:n?.label??`W${o+1}`,wafer:n?.wafer,dies:n?.dies,statsSummary:n?.statsSummary})),hbinDefs:e.length?e:void 0,sbinDefs:t.length?t:void 0,testDefs:fe(),passBins:ye,ringCount:d.ringCount}),{anchor:f})}function $n(){if(!h)return;h.innerHTML="";const e=Bn();if(w.length>0){const n=f.ownerDocument.createElement("div"),o=e.length,c=w.filter(Boolean).length;n.textContent=o===0?`No findings on any of the ${c} wafers`:`${o} of ${c} wafer${c===1?"":"s"} with findings`,Object.assign(n.style,{fontSize:O.body,color:m.label,marginBottom:x.md}),h.appendChild(n)}if(e.length>0){const n=f.ownerDocument.createElement("button");n.type="button",n.textContent="Summary report",Object.assign(n.style,{...xo("outlined"),marginBottom:x.lg,display:"block",width:"100%",textAlign:"left"}),mt(n),n.addEventListener("click",Ln),h.appendChild(n)}if(e.length===0){const n=f.ownerDocument.createElement("div");Object.assign(n.style,{color:m.icon,fontSize:O.body,padding:"4px 0"}),n.textContent="No findings on any wafer.",h.appendChild(n)}else for(const{index:n,item:o,unusualCount:c,notableCount:l,totalCount:a}of e){const s=c?"unusual":l?"notable":"info",i=c+l||a,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:x.xs,border:"none",borderLeft:`3px solid ${an(s)}`,borderRadius:V.control,background:m.bgHover,cursor:"pointer",fontSize:O.body,textAlign:"left",boxSizing:"border-box"}),r.addEventListener("mouseover",()=>{r.style.background=m.bgActive}),r.addEventListener("mouseout",()=>{r.style.background=m.bgHover});const u=f.ownerDocument.createElement("span");u.textContent=o.label??`W${n+1}`,Object.assign(u.style,{color:m.iconHover,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"});const b=f.ownerDocument.createElement("span");b.textContent=String(i),r.setAttribute("aria-label",`${o.label??`W${n+1}`} \u2014 ${i} finding${i===1?"":"s"}${c?`, ${c} unusual`:""} \u2014 view wafer`),Object.assign(b.style,{marginLeft:x.sm,flexShrink:"0",background:an(s),color:"#fff",borderRadius:V.container,padding:"1px 5px",fontSize:O.body,fontWeight:"600"}),r.appendChild(u),r.appendChild(b),r.addEventListener("click",()=>Te(n,o)),h.appendChild(r)}const t=f.ownerDocument.createElement("div");t.style.height="12px",h.appendChild(t)}function j(){if(h)if(H){const e=ne(w.flatMap(n=>n?.hbinDefs??[])),t=ne(w.flatMap(n=>n?.sbinDefs??[]));ti(h,{lotSummary:H,items:w,hbinDefs:e.length?e:void 0,sbinDefs:t.length?t:void 0,testDefs:fe(),passBins:ye,ringCount:d.ringCount,binColors:d.binColors,plotMode:d.plotMode??"hardBin",fallbackFormat:Ie,activeFindingId:ve,warnings:p.warnings?.display??!0?Y:[],findingsFilter:Mn,findingsNotice:kt,onFindingsFilterChange:j,onSaveText:p.onSaveText,onFindingClick:(n,o)=>{ve===n.id?ot():Rn(n,o),j()},onWaferClick:On,findingsFor:Tn,dieListOptions:p.dieList})}else $n()}function Wn(e){const t=e.highlight;return t?.kind==="wafer"&&t.waferIndices?.length?t.waferIndices:null}function Tt(e){return[e.variable.kind,e.variable.index??"",e.variable.bin??"",e.comparison.family,e.comparison.left,e.effect.direction].join("|")}let He=[];function Lt(){if(He.length!==0){for(const e of He)S[e]?.setOptions({plotMode:d.plotMode,activeTest:d.activeTest});He=[]}}function ot(){ve=null,Bt(),Ot(),Lt(),B({highlightBin:void 0},{fireCallback:!1})}function Rn(e,t){if(ve===e.id){ot();return}ve=e.id,t.style.background=m.bgActive,t.style.fontWeight="600",Lt();const{kind:n,index:o}=e.variable;if(n==="test"){const l=o??0,a=fe();if(a===void 0||a.some(i=>i.testNumber===l))B({plotMode:"value",activeTest:l,highlightBin:void 0},{fireCallback:!1});else{B({highlightBin:void 0},{fireCallback:!1});const r=be.has(d.plotMode??"hardBin")?null:Wn(e);if(r){for(const u of r)S[u]?.setOptions({plotMode:"value",activeTest:l});He=[...r]}}}else n==="softBin"?B({plotMode:"softBin",highlightBin:void 0},{fireCallback:!1}):B({plotMode:"hardBin",highlightBin:void 0},{fireCallback:!1});Bt(),Ot();const c=e.highlight;if(c.kind==="wafer"){Et(c.waferIndices);const l=Tt(e);for(const a of c.waferIndices){const r=L[a]?.statsSummary?.findings.find(u=>Tt(u)===l)?.highlight?.dieKeys;r?.length&&nt(r,[a])}}else c.kind==="bin"?c.dieKeys?.length&&nt(c.dieKeys):(c.kind==="region"||c.kind==="dies")&&c.dieKeys?.length&&nt(c.dieKeys)}function le(){if(!A)return;const e=!!h;A.style.display=(H||tt())&&e&&!Ee?"flex":"none";const t=h?h.style.display!=="none":!1;(H?.hasNotableFindings||w.some(o=>o?.statsSummary?.hasNotableFindings))&&!t?A.style.color=m.findingIndicator:A.dataset.active||(A.style.color=m.icon)}const R=f.ownerDocument.createElement("div");R.dataset.wmapToolbar="gallery",Object.assign(R.style,{flexShrink:"0",marginLeft:"auto",display:"inline-flex",flexDirection:"row",alignItems:"center",gap:"0",background:m.menuBg,border:`1px solid ${m.menuBorder}`,borderRadius:V.control,padding:"0",boxShadow:We.panel,flexWrap:"wrap",minWidth:"0",overflowX:"auto"});const $t=()=>{const e=Se();e&&(e.remove(),Me(null)),Re(K,!1)},K=Z("mode","Plot mode",()=>{if(Se()){$t();return}const e=w.flatMap(y=>y?.dies??[]),t=fe(),{testEntries:n,binEntries:o,stackedEntries:c}=No(e,t,{includeStacked:!0}),l=w.filter(Boolean).length,a=y=>{if(y===void 0)return l;let $=0;for(const se of w)se?.dies?.some(X=>hn(X,y)!==void 0||X.testValues?.[y]!==void 0)&&$++;return $},s=l<2?n:n.map(y=>{const $=a(y.activeTest);return $===l?y:{...y,label:`${y.label} \u2014 ${$} of ${l} wafers`}}),i=d.plotMode??"hardBin",r=d.activeTest??0;function u(y){return y.plotMode!==i?!1:y.plotMode==="value"?r===(y.activeTest??0):y.plotMode==="metadata"?d.activeMetadataKey===y.activeMetadataKey:!0}function b(y,$){y.activeTest!==void 0?B({plotMode:"value",activeTest:y.activeTest,activeMetadataKey:void 0,logScale:y.logScale}):y.activeMetadataKey!==void 0?B({plotMode:y.plotMode,activeTest:void 0,activeMetadataKey:y.activeMetadataKey,passFailDisplay:"off"}):B({plotMode:y.plotMode,activeTest:void 0,activeMetadataKey:void 0,passFailDisplay:"off"}),$.remove(),Me(null),Re(K,!1)}const M=new Set,k=w.flatMap(y=>y?.metadataFields??[]).filter(y=>!M.has(y.key)&&M.add(y.key)).filter(y=>_o(e,y.key)).map(Go),D=ko(K.getBoundingClientRect(),s,o,c,u,b,{makeMenuRow:kn,makeMenuSection:En},i,K.ownerDocument.defaultView??window,k);cn(K).appendChild(D),Me(D),Re(K,!0),fn(D,K,$t)});Re(K,!1);const In=()=>L.flatMap(e=>e?[...e.hbinDefs??[],...e.sbinDefs??[]]:[]).some(e=>e.color),{btn:An,sync:Wt}=Ro(ue,()=>({...d,plotMode:d.plotMode??"hardBin"}),In,e=>B(e));Wt();const Pn=C.some(e=>typeof e!="function"&&(e.reticles?.length??0)>0);function je(){const e=fe(),{testNumber:t}=co(d.activeTest??0,e);return{testNumber:t,td:fo(e,t)}}function Rt(){if((d.plotMode??"hardBin")!=="value")return!1;const{td:e}=je();return e!==void 0&&(e.limitLow!==void 0||e.limitHigh!==void 0)}function De(){if((d.plotMode??"hardBin")!=="value")return!1;const{td:e}=je();return e!==void 0&&!bt(e)}function Fn(){if((d.plotMode??"hardBin")!=="value")return!1;const{testNumber:e,td:t}=je();return w.some(n=>n?.dies?.some(o=>hn(o,e,t)!==void 0))}function Hn(e,t){if(!t||!bt(t))return;const n=t.limitLow!==void 0||t.limitHigh!==void 0;if((gn(d)==="spec"&&n?"spec":d.colorbarRangeMode??"spec")==="spec"&&n)return;let l=1/0,a=-1/0;for(const s of w)if(s)for(const i of s.dies){const r=Zo(i,e);r!==void 0&&(r<l&&(l=r),r>a&&(a=r))}if(isFinite(l))return l===a?[l,l+1]:[l,a]}function It(){if((d.plotMode??"hardBin")!=="metadata")return;const e=d.activeMetadataKey;if(!e)return;const t=new Set;for(const n of w)if(n)for(const o of uo(n.dies,e))t.add(o);return{key:e,values:[...t].sort(bn)}}function it(){const e=It();if(!(e===void 0&&d.metadataValueOrder===void 0)){d={...d,metadataValueOrder:e};for(const t of S)t&&t.setOptions({metadataValueOrder:e})}}function lt(){if((d.plotMode??"hardBin")!=="value")return;const{testNumber:e,td:t}=je(),n=Hn(e,t),o=n?{test:e,range:n}:void 0;d={...d,valueRange:o};for(const c of S)c&&c.setOptions({valueRange:o})}let at=!1;function jn(){if(at)return;at=!0,(f.ownerDocument.defaultView?.requestAnimationFrame??(t=>setTimeout(()=>t(0),0)))(()=>{at=!1,lt(),it(),At()})}function Ve(){const e=ne(w.flatMap(o=>o?.hbinDefs??[])),t=ne(w.flatMap(o=>o?.sbinDefs??[]));function*n(){for(const o of w)o&&(yield*o.dies)}return go(n(),{passBins:ye,binColorScheme:d.binColorScheme,useDefinedBinColors:d.useDefinedBinColors,hbinDefs:e,sbinDefs:t})}function At(){const e=Ve();d={...d,binColors:e};for(const t of S)t&&t.setOptions({binColors:e})}const Vn=Po(ue,()=>jo(d,Pn,{functionalActive:De(),hasLimits:Rt()&&!De(),hasRecorded:Fn()&&!De(),binMode:(d.plotMode??"hardBin")==="hardBin"||(d.plotMode??"hardBin")==="softBin"},e=>B(e)),()=>Vo(d)),{btn:zn,sync:Pt}=Ao(ue,()=>({plotMode:d.plotMode,legendPosition:we}),e=>{we=e;for(const t of S)t&&t.setOptions({legendPosition:we})},{get:()=>Ae,set:e=>{Ae=e,xt()},blockedReason:xe});Pt();const Nn=[{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"}],Ft=Mt("aggr","Aggregation method",()=>Nn,()=>d.aggregationMethod??"mean",e=>B({aggregationMethod:e}));function Ht(){const e=d.plotMode==="stackedValues";Ft.style.display=e?"":"none"}Ht();const{btn:_n,sync:jt}=Io(ue,()=>({...d,functionalActive:De()}),e=>B(e));jt();const ze=Z("specRange","Colorbar range: spec limits",()=>{const e=d.colorbarRangeMode==="data"?"spec":"data";B({colorbarRangeMode:e})});function Vt(){const e=(d.plotMode??"hardBin")==="value"&&Rt()&&gn(d)==="off"&&!De();ze.style.display=e?"":"none";const t=(d.colorbarRangeMode??"spec")==="spec";Ce(ze,t),ze.ariaLabel=t?"Colorbar range: spec limits (click for data range)":"Colorbar range: data range (click for spec limits)"}Vt();const Gn=Fo(ue,()=>d,e=>B(e)),Kn=Z("downloadAll","Download gallery PNG",ao),qn=Mt("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"}],()=>v!=null?String(v):"auto",e=>Yt(e==="auto"?void 0:Number(e))),E=f.ownerDocument.createElement("div");Object.assign(E.style,{display:"inline-flex",alignItems:"center",gap:"0"}),R.appendChild(E),T&&E.appendChild(K),E.appendChild(An),E.appendChild(Ft),E.appendChild(_n),E.appendChild(ze),E.appendChild(N()),E.appendChild(Vn),E.appendChild(N()),E.appendChild(zn),E.appendChild(N()),E.appendChild(Gn),E.appendChild(N()),E.appendChild(qn),E.appendChild(N()),E.appendChild(Kn),(H||tt())&&(A=Z("findings","Summary panel",()=>{if(!h)return;const e=h.style.display!=="none";e||j(),h.style.display=e?"none":"flex",Ce(A,!e),le()}),R.appendChild(N()),R.appendChild(A));let _=null,Ne=null,Y=[],zt=!1;function _e(){const e=Yo({lotStatsSummary:H,result:{warnings:[...w.flatMap(n=>n?.warnings??[]),...vt().warnings]},extra:[d.binColors&&mo(d.binColors,d.plotMode)].filter(n=>!!n)}),t=e.length!==Y.length||e.some((n,o)=>n.code!==Y[o]?.code||n.message!==Y[o]?.message);Y=e,(t||!zt)&&(zt=!0,p.warnings?.onWarning?.(e)),Un()}function Un(){if(!_||!Ne)return;const e=Y.length,t=e>0;if(_.style.display=t?"flex":"none",Ne.style.display=t?"":"none",!t)return;const n=Jo(Y[0]),o=`${e} data ${e===1?"warning":"warnings"}`;_.style.color=n==="error"?m.errText:m.warnText,_.ariaLabel=n==="error"?`${o} \u2014 some wafers may be positionally wrong`:o}(p.warnings?.display??!0)&&(Ne=N(),_=Z("warning","Data warnings",()=>{const e=Se();if(Fe(new MouseEvent("click")),e)return;const t=Qo(_.getBoundingClientRect(),Y,_.ownerDocument.defaultView??window);cn(f).appendChild(t),Me(t),fn(t,_,()=>Fe(new MouseEvent("click")))}),Re(_,!1),R.appendChild(Ne),R.appendChild(_)),_e();let ae=null;re&&(ae=Z("analysis","Insights",()=>{Gt(!Ee)}),ae.dataset.wmapInsightsBtn="1",R.appendChild(N()),R.appendChild(ae));function Nt(){import("./userGuideHtml.js").then(e=>Wo({buildWaferMap:Xo,renderWaferMap:ht,renderWaferGallery,analyzeWaferMap:Ye},e.USER_GUIDE_HTML,Je,f))}oe&&(R.appendChild(N()),R.appendChild(Z("help","User guide",()=>Nt())));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:`${x.sm} ${x.lg}`,fontSize:O.sub,lineHeight:Ze.none,boxSizing:"border-box"});const Ge=f.ownerDocument.createElement("div");Object.assign(Ge.style,{background:m.canvasBg,display:"flex",alignItems:"stretch",gap:x.lg,paddingBottom:x.lg,minWidth:"0"});const Q=f.ownerDocument.createElement("div");Q.dataset.wmapGalleryLegend="1",Object.assign(Q.style,{display:"flex",flexDirection:"column",gap:x.sm,background:m.menuBg,border:`1px solid ${m.menuBorder}`,borderRadius:V.container,padding:`${x.sm} ${x.lg}`,marginBottom:x.lg,boxShadow:We.panel,fontSize:O.body,lineHeight:Ze.none,boxSizing:"border-box",width:"100%",minWidth:"0"});const G=f.ownerDocument.createElement("div");Object.assign(G.style,{display:"flex",flexDirection:"row",alignItems:"flex-start"});let ge=null,ke=null,_t=null;function Xn(){return re?ge?Promise.resolve(ge):(_t??=import("./insightsTab.js").then(({createInsightsTab:e})=>(ge=e({getItems:()=>w,getLotStats:()=>H,getBinColors:()=>d.binColors??Ve(),passBins:ye,getRingCount:()=>d.ringCount??4,defaultView:p.insights?.defaultView,onOpenGuide:void 0,showMetadataStrip:!1,onSaveImage:p.onSaveImage,onSaveText:p.onSaveText,ownerDocument:f.ownerDocument,openWafer:(t,n,o)=>{const c=w[t];if(!c)return;let l=null;const a=Oo({title:n,onClose:()=>l?.destroy(),anchor:f});en(a,n,c.wafer.metadata??void 0),l=ft(a.contentWrap,c,o)}}),ke=ge.el,ke.style.display="none",f.appendChild(ke),ge)),_t):Promise.resolve(null)}let Ee=!1;function Gt(e){re&&(Ee=e,ke&&(ke.style.display=e?"flex":"none"),G.style.display=e?"none":"flex",E.style.display=e?"none":"inline-flex",R.style.display="inline-flex",ae&&(Ce(ae,e),ae.innerHTML=e?$e.wafer:$e.analysis,ae.ariaLabel=e?"Back to gallery view":"Insights"),le(),Ue(),e&&Xn().then(t=>{!t||!Ee||(t.el.style.display="flex",t.render())}))}re&&p.insights?.defaultOpen&&queueMicrotask(()=>Gt(!0));const Zn=4,st=240,Kt=480,Yn=720,Qn=1.25,qt=p.maxSize;let q=qt??Kt;function Ut(e){const t=P*2+110+2;let n=null;for(const o of e){if(o==null||!o.dies?.length)continue;const c=o.dies[0].width;if(!(c>0))continue;const l=o.wafer.radius*2*(Zn/c),a=Math.ceil(l+t);(n==null||a>n)&&(n=a)}return n}function Jn(e){const t=Ut(e);return t==null?st:Math.min(q,Math.max(st,t))}function eo(e){if(qt!=null)return!1;const t=Ut(e);if(t==null)return!1;const n=Math.min(Yn,Math.max(Kt,t));return n<=q?!1:(q=n,!0)}function to(){for(const e of Array.from(I.children))e.classList.contains("wmap-gallery-card")&&(e.style.maxWidth=`${q}px`,e.style.maxHeight=`${q}px`)}let Ke=st,Xt=0;function Zt(e){const t=eo(e);if(t&&to(),v!=null){t&&qe();return}const n=Jn(e);n>Ke&&(Ke=n),qe()}function Yt(e){v=e,qe()}function rt(e){return`repeat(${e}, minmax(0, ${q}px))`}function Qt(e){I.style.gridTemplateColumns!==e&&(I.style.gridTemplateColumns=e)}function qe(){if(v!=null){Qt(rt(v));return}const e=Math.max(1,Xt),t=12,n=I.clientWidth||0,o=l=>(n-t*(l-1))/l;let c=Math.max(1,Math.ceil(Math.sqrt(e)));if(n>0){const l=Math.min(q,Ke*Qn),a=s=>{let i=0;for(;i<e&&o(i+1)>=s;)i++;return i};c=a(l)||a(Ke)||1}Qt(rt(c))}const I=f.ownerDocument.createElement("div");if(Object.assign(I.style,{flex:"1 1 0",minWidth:"0",display:"grid",gridTemplateColumns:rt(1),gap:x.xl,paddingLeft:te,paddingRight:te,justifyContent:"start",alignContent:"start",isolation:"isolate"}),de?.placement){const e=de.placement;h=yt(e,te,f.ownerDocument),h.style.maxHeight="calc(100vh - 80px)",h.style.position="sticky",h.style.top="8px",h.style.display="flex",h.style.flexDirection="column"}else if(H||tt()){const e=!!de?.defaultOpen;h=yt("right",te,f.ownerDocument),h.style.maxHeight="calc(100vh - 80px)",h.style.position="sticky",h.style.top="8px",h.style.flexDirection="column",h.style.display=e?"flex":"none",j()}le(),h?.style.display!=="none"&&A&&Ce(A,!0),(de?.placement??"right")==="left"?(h&&G.appendChild(h),G.appendChild(I)):(G.appendChild(I),h&&G.appendChild(h));const Be=f.ownerDocument.createElement("div");Object.assign(Be.style,{position:"sticky",top:"0",display:"flex",flexDirection:"column",paddingLeft:te,paddingRight:te,paddingTop:te,zIndex:"1",background:m.menuBg}),Ge.appendChild(pe),Ge.appendChild(R),Be.appendChild(Ge),Be.appendChild(Q),f.appendChild(Be),f.appendChild(G);function Ue(){Q.innerHTML="";const e=d.plotMode??"hardBin",t=!Ee&&sn.has(e),n=L.filter(g=>g!=null),o=n.find(g=>g.isLotStack),c=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=d.activeMetadataKey,s=t&&!l?xn(n,g=>(e==="softBin"?g.sbin:g.hbin)??void 0):{counts:new Map,total:0},i=[...s.counts.keys()].sort((g,W)=>g-W),r=t&&l&&a?xn(n,g=>po(g.metadata?.[a])):{counts:new Map,total:0},u=l?It()?.values:void 0,b=t&&l?(u??[...r.counts.keys()].sort(bn)).filter(g=>r.counts.has(g)):[];if(pe.innerHTML="",c&&pe.appendChild(c),pe.style.display=c?"flex":"none",!i.length&&!b.length){Q.style.display="none";return}Q.style.display="flex";const M=f.ownerDocument.createElement("div");Object.assign(M.style,{display:"flex",flexWrap:"wrap",alignItems:"center",gap:`${x.sm} ${x.xl}`,maxHeight:"86px",overflowY:"auto",overflowX:"hidden"}),Q.appendChild(M);const k=d.highlightBin,D=L.flatMap(g=>g?.metadataFields??[]).find(g=>g.key===a),y=l?D?.label??(a?oi(a):"Metadata"):Co[e],$=f.ownerDocument.createElement("span");if($.textContent=y,Object.assign($.style,{fontSize:O.body,fontWeight:"700",letterSpacing:wo,textTransform:"uppercase",color:m.label,flexShrink:"0"}),M.appendChild($),!l&&s.total>0){const g=ye.reduce((he,pt)=>he+(s.counts.get(pt)??0),0),W=g/s.total*100,J=f.ownerDocument.createElement("span");J.textContent=`Yield ${Qe(W)}`,Object.assign(J.style,{fontSize:O.body,fontWeight:"700",color:m.value,whiteSpace:"nowrap",flexShrink:"0"});const ee=f.ownerDocument.createElement("span");ee.textContent=`${g.toLocaleString()} / ${s.total.toLocaleString()} dies`,Object.assign(ee.style,{fontSize:O.body,color:m.label,whiteSpace:"nowrap",flexShrink:"0"}),M.appendChild(J),M.appendChild(ee)}if(l){const g=d.highlightMetadataValue;b.forEach((W,J)=>{const ee=g===W,he=D?.values?.find(gt=>gt.value===W),pt=he?.color??bo(J),ln=r.counts.get(W)??0;vn(M,{color:pt,isActive:ee,label:he?.label??W,count:ln,percent:r.total>0?ln/r.total*100:void 0,onClick:()=>{const gt=d.highlightMetadataValue===W?void 0:W;B({highlightMetadataValue:gt})}})});return}const se=e==="softBin"?L.flatMap(g=>g?.sbinDefs??[]):L.flatMap(g=>g?.hbinDefs??[]),X=new Set,Le=[];for(const g of se)X.has(g.bin)||(X.add(g.bin),Le.push(g));const ut=Le.length>0?new Map(Le.map(g=>[g.bin,g])):null,nn=d.binColors??Ve(),so=e==="softBin"?nn.soft:nn.hard,on=g=>so.get(g)??ho;for(const g of i){const W=k===g,J=ut?.get(g),ee=s.counts.get(g)??0;vn(M,{color:on(g),isActive:W,label:J?.name?`${g} \xB7 ${J.name}`:`Bin ${g}`,count:ee,percent:s.total>0?ee/s.total*100:void 0,onClick:()=>{const he=d.highlightBin===g?void 0:g;B({highlightBin:he})}})}s.total>0&&i.length>1&&Q.appendChild(si(f.ownerDocument,[...s.counts.entries()].sort(([,g],[,W])=>W-g).map(([g,W])=>({color:on(g),count:W,label:ut?.get(g)?.name?`${g} \xB7 ${ut.get(g).name}`:`Bin ${g}`})),s.total))}function Oe(e){const t=w.filter(s=>s!==null);if(!t.length)return[];const n=t.map(s=>s.dies.filter(ai)),o=t[0].wafer,c=t.length,l=o.metadata?{...o,metadata:(({wafer:s,waferId:i,...r})=>r)(o.metadata)}:o;function a(s,i){return{...s,stats:{...s.stats,isLotStack:!0,aggregationMethod:i,lotSize:c}}}if(e==="stackedValues"){const s=fe();let i=s?.filter(bt);if(s!==void 0&&i?.length===0)return[];if(s?.length||(i=ro(t.flatMap(b=>b.dies)).map(b=>({testNumber:b,name:`Test ${b}`}))),!i?.length)return[];const r=d.aggregationMethod??"mean";return i.map(u=>{const b=Ko(n,r,u.testNumber),M={testNumber:0,name:u.name,unit:u.unit};return{wafer:l,dies:b,testDefs:[M],label:`${u.name} \xB7 ${r}`,isLotStack:!0,aggrMethod:r,lotSize:c,statsSummary:a(Ye({wafer:l,dies:b,testDefs:[M]},{testNumbers:[0]}),r)}})}if(e==="stackedBins"){let s=ne(t.flatMap(i=>i.hbinDefs??[]));return(!s||s.length===0)&&(s=[...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}`}))),s.map(i=>{const r=mn(n,i.bin,"hard"),u=[{bin:i.bin,name:i.name}];return{wafer:l,dies:r,hbinDefs:u,label:`${i.bin} \xB7 ${i.name}`,isLotStack:!0,aggrMethod:"countBin",lotSize:c,statsSummary:a(Ye({wafer:l,dies:r,hbinDefs:u}),"countBin")}})}if(e==="stackedSoftBins"){let s=ne(t.flatMap(i=>i.sbinDefs??[]));return(!s||s.length===0)&&(s=[...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}`}))),s.map(i=>{const r=mn(n,i.bin,"soft"),u=[{bin:i.bin,name:i.name}];return{wafer:l,dies:r,sbinDefs:u,label:`${i.bin} \xB7 ${i.name}`,isLotStack:!0,aggrMethod:"countBin",lotSize:c,statsSummary:a(Ye({wafer:l,dies:r,sbinDefs:u}),"countBin")}})}return t}function dt(e){const t=w.length;return e==="stackedBins"||e==="stackedSoftBins"?{valueRange:[0,t],lotSize:t}:e==="stackedValues"?{aggregationMethod:d.aggregationMethod??"mean",valueRange:void 0,lotSize:void 0}:{}}function B(e,{fireCallback:t=!0}={}){const n=Object.keys(e),o=d.plotMode,c=xe()!==null;d={...d,...e};const l=d.plotMode,a=be.has(l),s=o!==void 0&&be.has(o),i=Pe>0;if("binColorScheme"in e||"useDefinedBinColors"in e){const u=Ve();d={...d,binColors:u},e={...e,binColors:u}}if(e.plotMode!==void 0)if(a){const u=dt(l);if(d={...d,...u},i)for(const b of S)b&&b.setOptions(e);else U(Oe(l))}else if(s){const{valueRange:u,lotSize:b,aggregationMethod:M,...k}=d;if(d=k,i)for(const D of S)D&&D.setOptions(e);else U(w.filter(D=>D!==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 U(Oe("stackedValues"));else for(const u of S)u&&u.setOptions(e);xe()!==null!==c&&xt(),Ue(),Ht(),Pt(),Wt();const r=e.plotMode!==void 0&&e.plotMode!==o;(Uo.some(u=>u in e)||r)&&j(),_e(),jt(),Vt(),lt(),it(),t&&p.onViewOptionsChange?.(d,n,qo(n))}function Jt(e,t,n){const o=e.createElement("div");Object.assign(o.style,{display:"flex",alignItems:"center",gap:x.xs,flex:"1",minWidth:"0"});const c=e.createElement("span");c.textContent=t,Object.assign(c.style,{fontWeight:"700",fontSize:O.sub,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}),o.appendChild(c);const l=wn(n??{});let a=null;if(l.length>0){const s=e.createElement("span");Object.assign(s.style,{fontSize:O.body,lineHeight:Ze.none,color:m.label,flexShrink:"0"}),s.textContent="\u25BE",o.appendChild(s),Object.assign(o.style,{cursor:"pointer",borderRadius:V.control}),o.addEventListener("mouseenter",()=>{o.style.background=m.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:rn,background:m.menuBg,borderBottom:`1px solid ${m.menuBorder}`,boxShadow:We.menu,padding:`${x.md} ${x.lg}`,fontSize:O.body,display:"none"});const i=yn(n??{});i&&a.appendChild(i),o.setAttribute("aria-expanded","false"),o.setAttribute("aria-label",`Wafer info for ${t||"this card"}. Click to expand.`),un(o,r=>{s.textContent=r?"\u25B4":"\u25BE",o.setAttribute("aria-expanded",String(r)),a&&(a.style.display=r?"block":"none")})}return{wrap:o,metaPanel:a}}function en(e,t,n){const o=e.box.querySelector("[data-wmap-window-title]"),c=wn(n??{});if(!o||c.length===0)return;const l=o.parentElement,a=f.ownerDocument.createElement("div");Object.assign(a.style,{display:"flex",alignItems:"center",gap:x.xs,flex:"1",minWidth:"0",cursor:"pointer"}),mt(a,"bare"),l?.insertBefore(a,o),a.appendChild(o);const s=f.ownerDocument.createElement("span");Object.assign(s.style,{fontSize:O.body,lineHeight:Ze.none,color:m.label,flexShrink:"0"}),s.textContent="\u25BE",a.appendChild(s);const i=f.ownerDocument.createElement("div");i.dataset.wmapCardMetaPanel="1",Object.assign(i.style,{position:"absolute",top:"0",left:"0",right:"0",zIndex:rn,background:m.menuBg,borderBottom:`1px solid ${m.menuBorder}`,boxShadow:We.menu,padding:`${x.md} ${x.lg}`,fontSize:O.body,display:"none"});const r=yn(n??{});r&&i.appendChild(r),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.`),un(a,u=>{s.textContent=u?"\u25B4":"\u25BE",a.setAttribute("aria-expanded",String(u)),i.style.display=u?"block":"none"})}function ct(e,t,n){const o=f.ownerDocument.createElement("div");o.className="wmap-gallery-card",Object.assign(o.style,{background:m.menuBg,border:`1px solid ${m.menuBorder}`,borderRadius:V.container,boxShadow:We.panel,overflow:"hidden",display:"flex",flexDirection:"column",position:"relative",aspectRatio:"1",maxWidth:`${q}px`,maxHeight:`${q}px`});const c=f.ownerDocument.createElement("div");Object.assign(c.style,{display:"flex",alignItems:"center",padding:`${x.md} ${x.lg} ${x.sm}`,borderBottom:`1px solid ${m.menuBorder}`,flexShrink:"0",gap:x.sm});const{wrap:l,metaPanel:a}=Jt(document,e.label??"",e.wafer.metadata??void 0);c.appendChild(l);const s=f.ownerDocument.createElement("button");s.dataset.wmapExpandBtn="1",s.setAttribute("aria-label","Open full view"),pn(s),s.innerHTML=$e.expand,Object.assign(s.style,{display:"flex",alignItems:"center",justifyContent:"center",border:`1px solid ${m.menuBorder}`,borderRadius:V.control,background:m.panelBg,color:m.label,padding:x.xxs,cursor:"pointer",flexShrink:"0",width:"22px",height:"22px"}),mt(s),c.appendChild(s),o.appendChild(c);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),I.appendChild(o);const r=Ae||xe()!==null,u=e.viewOptions?{...d,...e.viewOptions}:d,b=ht(i,e,{viewOptions:{...u,showLegend:r},toolbarControls:"full",showTooltip:!0,padding:P,legendPosition:we,fallbackFormat:Ie,statsSummary:e.statsSummary,onSaveImage:p.onSaveImage,onSaveText:p.onSaveText,onClick:e.onClick,onSelect:e.onSelect,onExpand:()=>Te(t,e),showIdentity:!1,chromeInset:vo});return b.setViewControlsVisible(!1),b.setSummaryVisible(!1),s.onclick=()=>Te(t,e),{card:o,ctrl:b,canvasWrapper:i,expandBtn:s}}function no(e){const t=ce[e];if(!t)return;const n=[...z.values()].find(o=>o.cardIndex===e);n?(t.innerHTML=$e.minimize,t.setAttribute("aria-label","Reattach to gallery"),t.onclick=()=>io(n.id)):(t.innerHTML=$e.expand,t.setAttribute("aria-label","Open full view"),t.onclick=()=>Te(e,L[e]))}function U(e){lo(),Se()?.remove(),Me(null),ot(),L=[];for(const l of S)l&&l.destroy();S=[],ie=[],ce=[],Pe=0,I.innerHTML="",Xt=e.length,Zt(e.map(l=>typeof l=="function"?null:l));const t=[];for(let l=0;l<e.length;l++){const a=e[l];if(typeof a=="function"){const s=f.ownerDocument.createElement("div");s.className="wmap-gallery-card",Object.assign(s.style,{background:m.menuBg,border:`1px solid ${m.menuBorder}`,borderRadius:V.container,aspectRatio:"1",display:"flex",alignItems:"center",justifyContent:"center"});const i=f.ownerDocument.createElement("span");i.textContent="\u2026",Object.assign(i.style,{color:m.label,fontSize:"18px"}),s.appendChild(i),I.appendChild(s),L.push(null),S.push(null),ie.push(null),ce.push(null),t.push({index:l,factory:a,placeholder:s}),Pe++}else{const{ctrl:s,canvasWrapper:i,expandBtn:r}=ct(a,l,e.length);L.push(a),S.push(s),ie.push(i),ce.push(r)}}At(),Ue(),lt(),it();const n=++et;let o=0;function c(){if(n!==et)return;if(o>=t.length){if(be.has(d.plotMode)){const k=d.plotMode;U(Oe(k))}return}const{index:l,factory:a,placeholder:s}=t[o++],i=a();L[l]=i,w[l]=i,Zt([i]);const{card:r,ctrl:u,canvasWrapper:b,expandBtn:M}=ct(i,l,e.length);S[l]=u,ie[l]=b,ce[l]=M,Pe--,s.replaceWith(r),Ue(),jn(),!h&&!de?.placement&&i.statsSummary?.findings.length?(h=yt("right",te,f.ownerDocument),h.style.maxHeight="calc(100vh - 80px)",h.style.position="sticky",h.style.top="8px",h.style.flexDirection="column",h.style.display="none",(de?.placement??"right")==="left"?G.insertBefore(h,I):G.appendChild(h),j(),A||(A=Z("findings","Summary panel",()=>{if(!h)return;const D=h.style.display!=="none";D||j(),h.style.display=D?"none":"flex",Ce(A,!D),le()}),R.appendChild(N()),R.appendChild(A)),le()):h&&h.style.display!=="none"&&j(),le(),setTimeout(c,0)}t.length>0&&setTimeout(c,0)}if(be.has(d.plotMode)&&w.length>0){const e=dt(d.plotMode);d={...d,...e},U(Oe(d.plotMode))}else U(C);_e();let me=0;const tn=new(f.ownerDocument.defaultView??window).ResizeObserver(()=>{if(me)return;me=(f.ownerDocument.defaultView??window).requestAnimationFrame(()=>{me=0,v==null&&qe()})});tn.observe(I),h&&j();function oo(e,t){const n=ie[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:m.label,fontSize:O.body,textAlign:"center",padding:"0 12px"}),n.appendChild(o)}function Te(e,t){for(const a of z.values())if(a.cardIndex===e)return;const n=t.label??"Wafer map",o=Sn++,c=S[e]?.getOptions(),l=Eo(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:O.family}),Lo(f,a.documentElement);const s=$o(f,a.documentElement,()=>D.setOptions({})),i=a.createElement("div");i.dataset.wmapWindowBanner="1",i.textContent=n,Object.assign(i.style,{display:"none",padding:`${x.sm} ${x.xl}`,fontSize:O.body,fontWeight:"700",background:m.warnBg,color:m.warnText,borderBottom:`1px solid ${m.warnBorder}`,flexShrink:"0"}),a.body.appendChild(i);const r=a.createElement("div");Object.assign(r.style,{flex:"1",minHeight:"0",display:"flex",flexDirection:"column"}),a.body.appendChild(r);const{wrap:u,metaPanel:b}=Jt(a,n,t.wafer.metadata??void 0),M=a.createElement("div");Object.assign(M.style,{display:"flex",alignItems:"center",padding:`${x.md} ${x.lg} ${x.sm}`,borderBottom:`1px solid ${m.menuBorder}`,flexShrink:"0",gap:x.sm}),M.appendChild(u),r.appendChild(M);const k=a.createElement("div");Object.assign(k.style,{position:"relative",flex:"1",minHeight:"0",overflow:"hidden",display:"flex",flexDirection:"column"}),b&&k.appendChild(b),r.appendChild(k);const D=ft(k,t,void 0,c),y=setInterval(()=>{l.closed&&Xe(o)},400);l.addEventListener("pagehide",()=>Xe(o)),z.set(o,{id:o,ctrl:D,cardIndex:e,label:n,closePollId:y,stopThemeSync:s,close:()=>{l.closed||l.close()},setTitle:$=>{a.title=$,i.textContent=$,i.style.display="block"}})}else{const a=Bo({title:n,onClose:()=>Xe(o),anchor:f});a.contentWrap.style.flexDirection="column",en(a,n,t.wafer.metadata??void 0);const s=ft(a.contentWrap,t,void 0,c);z.set(o,{id:o,ctrl:s,cardIndex:e,label:n,closePollId:null,close:()=>a.close(),setTitle:i=>{const r=a.box.querySelector("[data-wmap-window-title]");r&&(r.textContent=i,r.title=i)}})}S[e]?.destroy(),S[e]=null,oo(e,l!==null),no(e)}function ft(e,t,n,o){const c=t.viewOptions?{...d,...t.viewOptions}:d,l=o?{...c,...o}:c,s={...n!==void 0?{...l,plotMode:"value",activeTest:n}:l,showLegend:!0},i=ht(e,t,{viewOptions:s,toolbarControls:"full",showTooltip:!0,padding:P,legendPosition:we,fallbackFormat:Ie,statsSummary:t.statsSummary,onSaveImage:p.onSaveImage,onSaveText:p.onSaveText,onClick:t.onClick,onSelect:t.onSelect,showExpandButton:!1,showIdentity:!1});return i.setViewControlsVisible(!0),i.setSummaryVisible(!0),i.setExpandVisible(!1),i}function Xe(e){const t=z.get(e);if(!t)return;z.delete(e),t.closePollId!=null&&clearInterval(t.closePollId),t.stopThemeSync?.();const n=t.ctrl.getOptions();if(t.ctrl.destroy(),t.cardIndex===null)return;const o=t.cardIndex,c=L[o];if(!c)return;const l={...c,viewOptions:n};L[o]=l;const{card:a,ctrl:s,canvasWrapper:i,expandBtn:r}=ct(l,o,L.length);ie[o]?.parentElement?.replaceWith(a),S[o]=s,ie[o]=i,ce[o]=r}function io(e){const t=z.get(e);t&&(t.close(),Xe(e))}function lo(){for(const e of z.values())e.cardIndex!==null&&(e.cardIndex=null,e.setTitle(`${e.label} \u2014 unlinked from gallery`))}function ao(){const e=[...I.querySelectorAll("canvas")];if(!e.length)return;const t=e.length,n=Math.ceil(Math.sqrt(t)),o=Math.ceil(t/n),c=e[0].width,l=e[0].height,a=8,s=(f.ownerDocument.defaultView??window).devicePixelRatio||1,i=Math.round(26*s),r=Math.round(12*s),u=f.ownerDocument.createElement("canvas");u.width=n*c+(n-1)*a,u.height=o*(l+i)+(o-1)*a;const b=u.getContext("2d"),M=yo(I);b.fillStyle=M.background,b.fillRect(0,0,u.width,u.height),e.forEach((k,D)=>{const y=D%n,$=Math.floor(D/n),se=y*(c+a),X=$*(l+i+a),Le=k.closest(".wmap-gallery-card")?.querySelector("span")?.textContent??"";b.fillStyle=M.surface,b.fillRect(se,X,c,i),b.fillStyle=M.text,b.font=`700 ${r}px system-ui, sans-serif`,b.textAlign="left",b.textBaseline="middle",b.fillText(Le,se+Math.round(10*s),X+i/2,c-Math.round(20*s)),b.drawImage(k,se,X+i)}),u.toBlob(k=>{k&&Ho(k,F,p.onSaveImage)})}return{setItems(e){w=e.map(n=>typeof n=="function"?null:n);const t=d.plotMode;if(be.has(t))if(e.some(o=>typeof o=="function"))U(e);else{const o=dt(t);d={...d,...o},U(Oe(t))}else U(e)},setOptions(e){B(e,{fireCallback:!1})},getOptions(){return{...d}},setFallbackFormat(e){Ie=e;for(const t of S)t&&t.setFallbackFormat(e)},setFindingsNotice(e){kt=e,j()},setLotStatsSummary(e){H=e,_e(),h&&j(),le()},setColumns(e){Yt(e)},openUserGuide:Nt,destroy(){et++;for(const e of[...z.values()])e.closePollId!=null&&clearInterval(e.closePollId),e.close(),e.ctrl.destroy();z.clear();for(const e of S)e&&e.destroy();S=[],Se()?.remove(),tn.disconnect(),me&&((f.ownerDocument.defaultView??window).cancelAnimationFrame(me),me=0),f.ownerDocument.removeEventListener("click",Fe,!0),window.removeEventListener("blur",Dt),Cn(),dn(),Be.remove(),G.remove(),h?.remove(),ge?.destroy()}}}
@@ -4,16 +4,32 @@ import { type ToCanvasOptions } from './toCanvas.js';
4
4
  import type { WaferMapResult } from '../renderer/buildWaferMap.js';
5
5
  import type { StatsSummary } from '../stats/types.js';
6
6
  import { type SaveImageHandler, type SaveTextHandler, type UserGuideExtension } from './toolbar.js';
7
- import type { SummaryPanelOptions } from './summaryPanel.js';
7
+ import type { SummaryPanelOptions, FindingsNotice } from './summaryPanel.js';
8
8
  import { type WarningsOptions } from './warnings.js';
9
- import { type InsightsOptions } from './insightsTab.js';
9
+ import type { InsightsOptions } from './insightsTab.js';
10
10
  import { type DieListDisplayOptions } from './dieList.js';
11
+ import { type BinColors } from '../renderer/binColors.js';
11
12
  /**
12
13
  * Stable display preferences — worth persisting to localStorage or a user profile.
13
14
  * These describe how the user wants to view wafer maps in general.
14
15
  */
15
16
  export interface WaferPreferences {
16
- colorScheme?: string;
17
+ /**
18
+ * Bin palette for hard/soft-bin maps — a name from `listBinColorSchemes()`.
19
+ * Default `'default'`. Independent of `valueColorScheme`: each mode keeps
20
+ * its own choice, and switching modes never resets either.
21
+ */
22
+ binColorScheme?: string;
23
+ /**
24
+ * Value gradient for value and stacked maps — a name from
25
+ * `listValueColorSchemes()`. Default `'default'`.
26
+ */
27
+ valueColorScheme?: string;
28
+ /**
29
+ * Honour `BinDef.color` where a bin definition supplies one. Default true.
30
+ * The toolbar offers the toggle only when some definition carries a colour.
31
+ */
32
+ useDefinedBinColors?: boolean;
17
33
  /** Interactive rotation in degrees (0 | 90 | 180 | 270). */
18
34
  rotation?: 0 | 90 | 180 | 270;
19
35
  flipX?: boolean;
@@ -110,6 +126,24 @@ export interface WaferDisplayState {
110
126
  test: number;
111
127
  range: [number, number];
112
128
  };
129
+ /**
130
+ * The full, ordered list of metadata values to assign colours from in
131
+ * `metadata` plot mode — applied only when `key` matches `activeMetadataKey`.
132
+ * Set by a host rendering several wafers together (`renderWaferGallery` does
133
+ * it for you) so every map indexes into ONE list; without it each map derives
134
+ * the order from its own dies, and a wafer missing a value the others have
135
+ * paints every later value in the next map's colour. See `ViewOptions`.
136
+ */
137
+ metadataValueOrder?: {
138
+ key: string;
139
+ values: string[];
140
+ };
141
+ /**
142
+ * Bin colours resolved over the whole population being shown together —
143
+ * set by `renderWaferGallery` so a bin is one colour on every card. A lone
144
+ * map leaves it unset and resolves over its own dies. See `ViewOptions.binColors`.
145
+ */
146
+ binColors?: BinColors;
113
147
  /**
114
148
  * Aggregation method for `stackedValues` mode.
115
149
  * Drives both the per-die aggregation and the hover tooltip label.
@@ -131,7 +165,30 @@ export interface WaferDisplayState {
131
165
  * whether a change is worth persisting.
132
166
  */
133
167
  export type WaferViewOptions = WaferPreferences & WaferDisplayState;
134
- export interface RenderOptions extends Omit<ToCanvasOptions, 'viewport' | 'hbinDefs' | 'sbinDefs'> {
168
+ /**
169
+ * The drawing parameters `renderWaferMap` forwards to the canvas. Declared
170
+ * explicitly rather than inherited from `ToCanvasOptions`, which is what this
171
+ * interface used to do.
172
+ *
173
+ * That inheritance leaked 16 low-level fields onto the top-level render API, and
174
+ * five of them were **accepted and silently ignored** — `renderWaferMap` computes
175
+ * or overrides them on every draw (`topClearance` is hardcoded to 0,
176
+ * `minRightReserve` is derived from the legend, and `markFailingDies`/`activeBin`/
177
+ * `hoverBin` are read from `viewOptions` and internal hover state instead). An
178
+ * option that is typed, documented and ignored costs a caller a debugging session
179
+ * to discover the API lied, so they are gone rather than merely undocumented.
180
+ *
181
+ * Listing the fields also stops future `ToCanvasOptions` additions arriving here
182
+ * by accident: `toCanvas` is the low-level surface and is free to grow, and a
183
+ * caller who genuinely needs that level of control should call it directly.
184
+ *
185
+ * These stay at the top level of `RenderOptions` rather than moving under a
186
+ * nested `draw` key. Grouping would read better, but it would break every caller
187
+ * of the ten options that DO work in exchange for tidiness alone, and the defect
188
+ * here was the five that don't.
189
+ */
190
+ type ForwardedDrawOptions = Pick<ToCanvasOptions, 'padding' | 'background' | 'showColorbar' | 'colorbarWidth' | 'showAxes' | 'showTitle' | 'legendPosition' | 'legendOffset' | 'diePitchMm' | 'fallbackFormat' | 'metadataFields'>;
191
+ export interface RenderOptions extends ForwardedDrawOptions {
135
192
  /** Initial scene display options. All are overridable via the toolbar. */
136
193
  viewOptions?: WaferViewOptions;
137
194
  /** Called when the user hovers over a die. Null when leaving a die. */
@@ -153,16 +210,31 @@ export interface RenderOptions extends Omit<ToCanvasOptions, 'viewport' | 'hbinD
153
210
  /** Show the built-in toolbar. Default true. */
154
211
  showToolbar?: boolean;
155
212
  /**
156
- * Show a small always-visible metadata badge (lot, wafer ID, product, test
157
- * program, temperature, etc.) overlaid bottom-left on the canvas. Default
158
- * true. Independent of `showToolbar` and the Insights tab — this exists so
159
- * basic wafer/lot identity is never hidden behind a mode or toggle, without
160
- * costing any layout space (it's an overlay, not a layout element). Renders
161
- * nothing when the result has no metadata at all. Collapsed by default to a
162
- * single identifying line; click/Enter/Space expands in place to the full
163
- * field set.
213
+ * Show an always-visible identity header row (lot, wafer ID, product, test
214
+ * program, temperature, etc.) above the canvas. Default true. Independent
215
+ * of `showToolbar` and the Insights tab — this exists so basic wafer/lot
216
+ * identity is never hidden behind a mode or toggle. A real layout row, not
217
+ * an overlay, so it can never collide with anything the canvas draws
218
+ * (colorbar, legend, toolbar) regardless of `legendPosition`. Carries identity
219
+ * and nothing else — Expand lives in the toolbar with the other view
220
+ * controls, so turning this off costs only the identity text. Collapsed by
221
+ * default to a single identifying line; click/Enter/Space expands a panel
222
+ * over the top of the canvas to the full field set. Renders nothing when the
223
+ * result has no metadata/lot-stack context.
164
224
  */
165
- showMetadataBadge?: boolean;
225
+ showIdentity?: boolean;
226
+ /**
227
+ * Inset for this map's own chrome row (identity + toolbar) and for a Summary
228
+ * panel docked inside the map area, from the edge of the map area.
229
+ *
230
+ * Defaults to `EDGE_GUTTER` — correct for a standalone map, where the map
231
+ * area IS the region and its chrome is a bounded surface against that edge.
232
+ * Pass the smaller `MAP_CHROME_INSET` when the map is embedded in a surface
233
+ * that already provides its own inset (this is what `renderWaferGallery`
234
+ * passes for its cards); a second full gutter inside one stacks two, which
235
+ * reads as a toolbar standing well off the side of the card.
236
+ */
237
+ chromeInset?: string;
166
238
  /** Optional precomputed wafer-level stats summary. Enables the summary panel toggle button in the toolbar. */
167
239
  statsSummary?: StatsSummary;
168
240
  /**
@@ -214,6 +286,14 @@ export interface RenderOptions extends Omit<ToCanvasOptions, 'viewport' | 'hbinD
214
286
  * Insights has no map for a finding to highlight against.
215
287
  */
216
288
  summaryPanel?: SummaryPanelOptions;
289
+ /**
290
+ * A row at the top of the Findings section stating that a category of finding
291
+ * is not present, and optionally offering to compute it — see
292
+ * {@link FindingsNotice}. wmap never raises this itself: only the host knows
293
+ * what analysis it chose to skip and what running it would cost. Replaceable
294
+ * afterwards via the controller's `setFindingsNotice`.
295
+ */
296
+ findingsNotice?: FindingsNotice;
217
297
  /**
218
298
  * Display preferences for every built-in die-list surface: the
219
299
  * coordinate-less map replacement, the "+N dies without position data"
@@ -246,9 +326,11 @@ export interface RenderOptions extends Omit<ToCanvasOptions, 'viewport' | 'hbinD
246
326
  /** Override the expand action for both the expand button and the E key. Used by the gallery to route through its own modal logic. */
247
327
  onExpand?: () => void;
248
328
  /**
249
- * Show the toolbar expand button and enable the E-key shortcut. Default true.
250
- * Set false when the host already renders the map inside its own expanded/modal
251
- * context, where wmap's built-in expand modal would be redundant.
329
+ * Show the expand button in the toolbar and enable the E-key shortcut.
330
+ * Default true. Independent of `showIdentity` — expand is a view control,
331
+ * not part of the wafer's identity. Set false when the host already renders
332
+ * the map inside its own expanded/modal context, where wmap's built-in
333
+ * expand modal would be redundant.
252
334
  */
253
335
  showExpandButton?: boolean;
254
336
  /**
@@ -314,6 +396,12 @@ export interface WaferMapController {
314
396
  /** Return current scene options snapshot. */
315
397
  getOptions(): WaferViewOptions;
316
398
  /** Programmatically set the selected dies (renders highlight overlay). */
399
+ /**
400
+ * Replace the Findings-section notice (see `FindingsNotice`). Pass `undefined`
401
+ * to clear it — which is what a host does once it has run the analysis the
402
+ * notice was offering.
403
+ */
404
+ setFindingsNotice(notice: FindingsNotice | undefined): void;
317
405
  setSelection(dies: Die[]): void;
318
406
  /** Clear the current selection. */
319
407
  clearSelection(): void;
@@ -331,8 +419,8 @@ export interface WaferMapController {
331
419
  setExpandVisible(visible: boolean): void;
332
420
  /** Show or hide the help toolbar button. */
333
421
  setHelpButtonVisible(visible: boolean): void;
334
- /** Show or hide the metadata badge without affecting its content. */
335
- setMetadataBadgeVisible(visible: boolean): void;
422
+ /** Show or hide the identity header without affecting its content. */
423
+ setIdentityVisible(visible: boolean): void;
336
424
  /**
337
425
  * Opens the built-in end-user guide window — the same action the help
338
426
  * toolbar button performs, but callable directly. Works regardless of
@@ -360,6 +448,9 @@ export interface WaferMapController {
360
448
  /** Remove all event listeners and DOM elements. */
361
449
  destroy(): void;
362
450
  }
451
+ /** Options that change die colours without changing what the view contains —
452
+ * any of them means every colour-bearing surface (panels, footer) redraws. */
453
+ export declare const COLOR_KEYS: readonly (keyof WaferViewOptions)[];
363
454
  export declare function classifyChanged(keys: (keyof WaferViewOptions)[]): 'preference' | 'state' | 'mixed';
364
455
  /**
365
456
  * What `renderWaferMap` actually needs: a wafer and its dies, plus anything
@@ -378,4 +469,5 @@ export declare function classifyChanged(keys: (keyof WaferViewOptions)[]): 'pref
378
469
  */
379
470
  export type RenderableWaferMap = Pick<WaferMapResult, 'wafer' | 'dies'> & Partial<Omit<WaferMapResult, 'wafer' | 'dies'>>;
380
471
  export declare function renderWaferMap(container: HTMLElement, result: RenderableWaferMap, options?: RenderOptions): WaferMapController;
472
+ export {};
381
473
  //# sourceMappingURL=renderWaferMap.d.ts.map