@wafertools/wafermap 0.29.0 → 0.30.1

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 (88) hide show
  1. package/AGENTS.md +26 -17
  2. package/CHANGELOG.md +410 -0
  3. package/README.md +6 -6
  4. package/dist/packages/canvas-adapter/charts/barPanel.js +1 -1
  5. package/dist/packages/canvas-adapter/charts/binCluster.js +1 -1
  6. package/dist/packages/canvas-adapter/charts/boxplot.js +1 -1
  7. package/dist/packages/canvas-adapter/charts/capability.js +1 -1
  8. package/dist/packages/canvas-adapter/charts/correlation.js +2 -2
  9. package/dist/packages/canvas-adapter/charts/groupedBarPlot.d.ts +1 -0
  10. package/dist/packages/canvas-adapter/charts/histogram.js +1 -1
  11. package/dist/packages/canvas-adapter/charts/testPassRate.js +1 -1
  12. package/dist/packages/canvas-adapter/charts/trend.js +1 -1
  13. package/dist/packages/canvas-adapter/deprecated.d.ts +7 -0
  14. package/dist/packages/canvas-adapter/deprecated.js +1 -0
  15. package/dist/packages/canvas-adapter/dieList.d.ts +1 -3
  16. package/dist/packages/canvas-adapter/dieList.js +7 -7
  17. package/dist/packages/canvas-adapter/exportName.d.ts +68 -0
  18. package/dist/packages/canvas-adapter/exportName.js +1 -0
  19. package/dist/packages/canvas-adapter/icons.js +2 -2
  20. package/dist/packages/canvas-adapter/index.d.ts +2 -3
  21. package/dist/packages/canvas-adapter/index.js +1 -1
  22. package/dist/packages/canvas-adapter/insightsTab.d.ts +0 -1
  23. package/dist/packages/canvas-adapter/insightsTab.js +1 -1
  24. package/dist/packages/canvas-adapter/maplessSummary.js +1 -1
  25. package/dist/packages/canvas-adapter/renderWaferGallery.d.ts +23 -40
  26. package/dist/packages/canvas-adapter/renderWaferGallery.js +1 -1
  27. package/dist/packages/canvas-adapter/renderWaferMap.d.ts +96 -104
  28. package/dist/packages/canvas-adapter/renderWaferMap.js +1 -1
  29. package/dist/packages/canvas-adapter/summaryPanel.d.ts +31 -13
  30. package/dist/packages/canvas-adapter/summaryPanel.js +3 -3
  31. package/dist/packages/canvas-adapter/toCanvas.d.ts +20 -12
  32. package/dist/packages/canvas-adapter/toCanvas.js +1 -1
  33. package/dist/packages/canvas-adapter/toolbar.d.ts +6 -0
  34. package/dist/packages/canvas-adapter/toolbar.js +2 -2
  35. package/dist/packages/canvas-adapter/userGuideHtml.d.ts +1 -1
  36. package/dist/packages/canvas-adapter/userGuideHtml.js +26 -15
  37. package/dist/packages/canvas-adapter/version.d.ts +2 -2
  38. package/dist/packages/canvas-adapter/version.js +1 -1
  39. package/dist/packages/canvas-adapter/warnings.js +1 -1
  40. package/dist/packages/core/deprecated.d.ts +60 -0
  41. package/dist/packages/core/deprecated.js +1 -0
  42. package/dist/packages/core/index.d.ts +1 -3
  43. package/dist/packages/core/index.js +1 -1
  44. package/dist/packages/core/passBins.d.ts +33 -0
  45. package/dist/packages/core/passBins.js +1 -0
  46. package/dist/packages/core/utils.d.ts +12 -0
  47. package/dist/packages/core/utils.js +1 -1
  48. package/dist/packages/core/waferLabel.d.ts +35 -0
  49. package/dist/packages/core/waferLabel.js +1 -0
  50. package/dist/packages/renderer/binColors.d.ts +105 -13
  51. package/dist/packages/renderer/binColors.js +1 -1
  52. package/dist/packages/renderer/buildView.d.ts +8 -9
  53. package/dist/packages/renderer/buildView.js +1 -1
  54. package/dist/packages/renderer/buildWaferMap.d.ts +76 -17
  55. package/dist/packages/renderer/buildWaferMap.js +1 -1
  56. package/dist/packages/renderer/colorMap.d.ts +4 -3
  57. package/dist/packages/renderer/colorSchemes.d.ts +8 -6
  58. package/dist/packages/renderer/deprecate.d.ts +31 -0
  59. package/dist/packages/renderer/deprecate.js +1 -0
  60. package/dist/packages/renderer/deprecated.d.ts +45 -0
  61. package/dist/packages/renderer/deprecated.js +1 -0
  62. package/dist/packages/renderer/index.d.ts +4 -4
  63. package/dist/packages/renderer/index.js +1 -1
  64. package/dist/packages/stats/analyzeWaferLot.js +1 -1
  65. package/dist/packages/stats/analyzeWaferMap.js +1 -1
  66. package/dist/packages/stats/binPareto.d.ts +6 -1
  67. package/dist/packages/stats/capability.d.ts +16 -1
  68. package/dist/packages/stats/capability.js +1 -1
  69. package/dist/packages/stats/clusterDetection.d.ts +0 -2
  70. package/dist/packages/stats/deprecated.d.ts +82 -0
  71. package/dist/packages/stats/deprecated.js +1 -0
  72. package/dist/packages/stats/index.d.ts +5 -14
  73. package/dist/packages/stats/index.js +1 -1
  74. package/dist/packages/stats/normalizeInput.d.ts +10 -0
  75. package/dist/packages/stats/normalizeInput.js +1 -0
  76. package/dist/packages/stats/regions.d.ts +9 -2
  77. package/dist/packages/stats/regions.js +1 -1
  78. package/dist/packages/stats/renderFindingsReport.js +1 -1
  79. package/dist/packages/stats/renderSummaryReport.d.ts +42 -1
  80. package/dist/packages/stats/renderSummaryReport.js +34 -34
  81. package/dist/packages/stats/reportHtml.d.ts +0 -1
  82. package/dist/packages/stats/reportHtml.js +10 -10
  83. package/dist/packages/stats/summaryFigures.d.ts +47 -0
  84. package/dist/packages/stats/summaryFigures.js +1 -0
  85. package/dist/packages/stats/types.d.ts +118 -43
  86. package/dist/packages/stats/yield.d.ts +12 -6
  87. package/dist/packages/stats/yield.js +1 -1
  88. package/package.json +1 -1
@@ -1,3 +1,3 @@
1
- import{isParametricTest as qt}from"../renderer/buildWaferMap.js";import{buildRingRegions as Vt,buildQuadrantRegions as Kt,buildRegionYieldData as Gt}from"../stats/regions.js";import{computeFunctionalYield as Ut}from"../stats/analyzeWaferMap.js";import{renderSummaryReportHtml as Qt,renderLotSummaryReportHtml as Xt}from"../stats/renderSummaryReport.js";import{buildFindingsNarrative as Zt}from"../stats/findingsNarrative.js";import{filterFindings as Jt}from"../stats/filterFindings.js";import{buildFacetTable as te,prettyKey as xt}from"../stats/facets.js";import{commonMetadata as yt}from"../stats/facets.js";import{resolveMetadataColumns as ee}from"../stats/metadataColumns.js";import{resolveBinColors as Ct}from"../renderer/binColors.js";import{NO_DATA_FILL as ne}from"../renderer/colorMap.js";import{describeWaferPopulation as wt,populationLabel as oe}from"../stats/population.js";import{buildWarningsBanner as mt,collectWarnings as St}from"./warnings.js";export{mt as buildWarningsBanner};import{fmt as vt,fmtAggregationMethod as ie,plainBinTerms as nt}from"../renderer/fmt.js";import{getUniqueTestNumbers as ae}from"../renderer/buildView.js";import{quantile as ot}from"../stats/math.js";import{buildCapabilityData as se}from"../stats/capability.js";import{sortBinsForDisplay as re}from"../stats/binPareto.js";import{poolFunctionalYield as le}from"../stats/testPassRate.js";import{makeLabeledSelect as $t,makeSegmented as ht}from"./charts/chartShell.js";import{SHADOW as kt,MOTION as Lt,LEADING as Q,TRACKING as rt,wireControlHover as q,controlStyle as lt,SPACE as y,RADIUS as O,FONT as F,CLR as B,sevColor as dt,openModal as Bt,openReportModal as Nt,saveTextFile as Ft,wireTooltip as it}from"./toolbar.js";import{buildDieListSection as de}from"./dieList.js";export{csvField}from"../core/utils.js";import{medianOfSorted as ce,csvField as ct}from"../core/utils.js";import{metadataDisplayValue as pe}from"../core/metadata.js";const ue=B.panelBg,Et=`1px solid ${B.menuBorder}`,fe="12px",Y=B.label,U=B.value,Rt="10px";function l(t,e,o,n=document){const i=n.createElement(t);return e&&Object.assign(i.style,e),o!==void 0&&(i.textContent=o),i}function J(t){return l("div",{fontSize:Rt,fontWeight:"700",letterSpacing:rt,textTransform:"uppercase",color:Y,marginBottom:y.sm},t)}const Tt=new WeakMap,Dt=["regionYield","testValues","functionalTests"];function pt(t){if(!t)return{collapsed:new Set(Dt),regionMode:"ring",waferSort:"slot"};let e=Tt.get(t);return e||(e={collapsed:new Set(Dt),regionMode:"ring",waferSort:"slot"},Tt.set(t,e)),e}function X(t,e=!0,o,n){const i=l("div"),d=pt(n?.panel);n?.stateKey&&n.panel&&(e=!d.collapsed.has(n.stateKey));const a=document.createElement("button");a.type="button",Object.assign(a.style,{display:"flex",alignItems:"center",gap:y.xs,width:"100%",background:"none",border:"none",cursor:"pointer",padding:"0 0 6px",textAlign:"left"});const p=l("span",{fontSize:F.meta,color:Y,transition:`transform ${Lt.base}`,transform:e?"rotate(90deg)":"rotate(0deg)",display:"inline-block",lineHeight:Q.none,marginRight:"1px"},"\u25B6"),c=l("span",{fontSize:Rt,fontWeight:"700",letterSpacing:rt,textTransform:"uppercase",color:Y,flex:"1"},t);if(q(a,"bare"),a.setAttribute("aria-expanded",e?"true":"false"),a.appendChild(p),a.appendChild(c),o){const b=l("span",{fontSize:F.meta,fontWeight:"700",background:B.warnBg,color:B.warnText,borderRadius:O.pill,padding:"1px 5px"},o);a.appendChild(b)}const r=l("div");r.style.display=e?"block":"none";let s=e;if(a.addEventListener("click",()=>{s=!s,r.style.display=s?"block":"none",p.style.transform=s?"rotate(90deg)":"rotate(0deg)",a.setAttribute("aria-expanded",s?"true":"false"),n?.stateKey&&n.panel&&(s?d.collapsed.delete(n.stateKey):d.collapsed.add(n.stateKey))}),n?.control){const b=l("div",{display:"flex",alignItems:"center",gap:y.sm});a.style.width="auto",a.style.flex="1",b.appendChild(a);const u=()=>{r.innerHTML="",n.render?.(r)},v=n.control(u);v&&(v.style.marginBottom="6px",v.addEventListener("click",N=>N.stopPropagation()),b.appendChild(v)),i.appendChild(b)}else i.appendChild(a);return i.appendChild(r),n?.render?.(r),{outer:i,content:r}}function Mt(){return l("div",{height:"1px",background:B.separator,margin:`${fe} 0`,flexShrink:"0"})}function gt(t,e,o=B.barFill,n,i){const d=l("div",{marginBottom:"5px"}),a=l("div",{display:"flex",justifyContent:"space-between",fontSize:F.body,color:U,marginBottom:y.xxs}),p=l("span",{color:Y},t),c=l("span",{fontWeight:"600"},`${e.toFixed(1)}%`);a.appendChild(p),a.appendChild(c);const r=n!==void 0?n:Math.min(100,Math.max(0,e)),s=o,b=l("div",{position:"relative",height:"9px",background:B.bgActive,borderRadius:O.control,overflow:"hidden"}),u=l("div",{height:"100%",width:`${r}%`,background:s,borderRadius:O.control,transition:`width ${Lt.base}`});if(b.appendChild(u),i!==void 0){const v=l("div",{position:"absolute",top:"0",bottom:"0",left:`${i}%`,width:"2px",marginLeft:"-1px",background:B.value,opacity:"0.8"});b.appendChild(v)}return d.appendChild(a),d.appendChild(b),d}function At(){const t=l("div",{display:"flex",gap:y.sm,marginBottom:y.md});return t.finish=()=>{const e=t.lastElementChild;e&&Object.assign(e.style,{borderRight:"none",paddingRight:"0"})},t}function at(t,e,o){const n=l("div",{padding:`${y.xxs} ${y.md} ${y.xxs} 0`,borderRight:Et,textAlign:"center",flex:"1"}),i=l("div",{fontSize:F.heading,fontWeight:"700",color:U,lineHeight:Q.tight},t),d=l("div",{fontSize:F.body,color:Y,marginTop:y.xxs},e);return n.appendChild(i),n.appendChild(d),o&&n.appendChild(l("div",{fontSize:F.body,color:Y,opacity:"0.85"},o)),n}function It(t,e){const o=l("div",{display:"flex",justifyContent:"space-between",fontSize:F.body,gap:y.md,marginBottom:"3px"}),n=l("span",{color:Y,flexShrink:"0"},t),i=l("span",{color:U,textAlign:"right",fontWeight:"500",wordBreak:"break-all"},e);return o.appendChild(n),o.appendChild(i),o}function me(t,e){const o=l("div",{display:"flex",fontSize:F.body,gap:y.sm,marginBottom:"3px"}),n=l("span",{color:Y,flexShrink:"0"},`${t}:`),i=l("span",{color:U,fontWeight:"500",wordBreak:"break-all"},e);return o.appendChild(n),o.appendChild(i),o}export function metadataEntries(t){const e=[];for(const[o,n]of Object.entries(t)){const i=pe(n);i!==void 0&&e.push([o,i])}return e}const he=["lot","product","testprogram","split"],ut=t=>{const e=he.indexOf(t.toLowerCase().replace(/[^a-z]/g,""));return e===-1?Number.MAX_SAFE_INTEGER:e};export function buildFacetSummaryChips(t,e=3){if(!t.length)return null;const o=l("div",{display:"flex",flexWrap:"wrap",alignItems:"baseline",gap:`${y.xs} ${y.lg}`}),n=[...t].sort((p,c)=>ut(p.key)-ut(c.key)),i=n.filter(p=>ut(p.key)!==Number.MAX_SAFE_INTEGER),d=n.filter(p=>ut(p.key)===Number.MAX_SAFE_INTEGER),a=p=>{const c=l("span",{whiteSpace:"nowrap"}),r=l("span",{color:Y},`${xt(p.key)}: `);c.appendChild(r);const s=p.values.slice(0,e),b=p.values.length-s.length;let u=s.map(v=>v.value).join(", ");return b>0&&(u+=` +${b} more`),c.appendChild(document.createTextNode(u)),c};for(const p of i)o.appendChild(a(p));if(d.length){const p=l("span",{display:"none",flexWrap:"wrap",alignItems:"baseline",gap:`${y.xs} ${y.lg}`});for(const s of d)p.appendChild(a(s));const c=l("button",{background:"none",border:"none",padding:"0",cursor:"pointer",color:B.iconActive,fontSize:F.body,whiteSpace:"nowrap"});c.type="button",q(c,"bare");const r=s=>{p.style.display=s?"contents":"none",c.textContent=s?"less":`+${d.length} more`,c.setAttribute("aria-expanded",String(s))};r(!1),c.addEventListener("click",()=>r(c.getAttribute("aria-expanded")!=="true")),o.appendChild(p),o.appendChild(c)}return o}export function buildMetadataStripRow(t,e,o){const n=te(t,o),i=buildFacetSummaryChips(n);if(!i&&!e)return null;const d=l("div",{display:"flex",flexWrap:"wrap",alignItems:"baseline",gap:"4px 14px"});if(e){const a=l("span",{fontWeight:"500",whiteSpace:"nowrap"},e.aggrMethod?`${e.lotSize} wafers stacked \xB7 ${e.aggrMethod}`:`${e.lotSize} wafers stacked`);d.appendChild(a)}return i&&d.appendChild(i),d}const ge={display:"flex",flexDirection:"column",gap:y.sm,background:B.menuBg,border:`1px solid ${B.menuBorder}`,borderRadius:O.container,padding:`${y.sm} ${y.lg}`,boxShadow:kt.panel,fontSize:F.body,lineHeight:Q.none,boxSizing:"border-box",width:"100%",minWidth:"0"};export function buildMetadataStripBox(t,e,o){const n=buildMetadataStripRow(t,e,o);if(!n)return null;const i=l("div",ge);return i.appendChild(n),i}export function buildCompactMetadataRows(t){const e=metadataEntries(t);if(!e.length)return null;const o=l("div");for(const[n,i]of e)o.appendChild(me(xt(n),i));return o}export function buildMetadataInfoSection(t,e){const o=buildMetadataStripRow(t,e,{facetableOnly:t.length>1});if(!o)return null;const n=l("div");return n.appendChild(J("Wafer Info")),n.appendChild(o),n}export function buildYieldSection(t,e,o=[1]){const n=l("div");n.appendChild(J("Summary"));const i=At();if(i.appendChild(at(String(t.totalDies),"Total dies")),t.partialDies>0&&i.appendChild(at(String(t.partialDies),"Partial")),t.yieldPercent!==null){const d=o.length===1?`bin ${o[0]}`:`bins ${o.join(", ")}`;i.appendChild(at(`${t.yieldPercent.toFixed(1)}%`,"Yield",`pass: ${d}`))}return i.finish(),n.appendChild(i),t.edgeExcludedDies>0&&n.appendChild(It("Edge excluded (outer zone)",String(t.edgeExcludedDies))),n}export function buildBinSection(t,e,o,n,i,d){const a=new Map;if(i)for(const[r,s]of Object.entries(i))a.set(Number(r),s);else for(const r of t){if(r.partial||r.edgeExcluded)continue;const s=o==="hard"?r.hbin:r.sbin;s!=null&&a.set(s,(a.get(s)??0)+1)}if(!a.size)return null;const p=n??be(t,o,e,d),c=l("div");c.appendChild(J(Wt(o,[...a.values()].reduce((r,s)=>r+s,0))));for(const r of Pt(a,e,p,d))c.appendChild(r);return c}function be(t,e,o,n){const i=Ct(t,{passBins:n,...e==="hard"?{hbinDefs:o}:{sbinDefs:o}});return e==="hard"?i.hard:i.soft}function Wt(t,e){return`${t==="hard"?"Hard":"Soft"} Bin Breakdown \u2014 % of dies (N=${e})`}function Pt(t,e,o,n=[1]){const i=[...t.values()].reduce((p,c)=>p+c,0),d=e?new Map(e.map(p=>[p.bin,p])):null;return re(t.entries(),n).map(([p,c])=>{const r=d?.get(p),s=r?.name?`Bin ${p} \xB7 ${r.name}`:`Bin ${p}`,b=c/i*100,u=o.get(p)??ne;return gt(`${s} (${c})`,b,u)})}export function buildBinBreakdownSection(t){const{dies:e,hbinDefs:o,sbinDefs:n,hardCounts:i,softCounts:d,plotMode:a,passBins:p=[1],panel:c}=t,r=t.binColors??Ct(e,{passBins:p,hbinDefs:o,sbinDefs:n}),s=m=>{const x=m==="hard"?i:d,w=new Map;if(x){for(const[$,L]of Object.entries(x))w.set(Number($),L);return w}for(const $ of e){if($.partial||$.edgeExcluded)continue;const L=m==="hard"?$.hbin:$.sbin;L!=null&&w.set(L,(w.get(L)??0)+1)}return w},b=s("hard"),u=s("soft"),v=b.size>0,N=u.size>0;if(!v&&!N)return null;const M=pt(c),W=a==="softBin"||a==="stackedSoftBins"?"soft":a==="hardBin"||a==="stackedBins"?"hard":void 0;let E=M.binMode??W??(v?"hard":"soft");E==="hard"&&!v&&(E="soft"),E==="soft"&&!N&&(E="hard");const H=E==="hard"?b:u,h=E==="hard"?o:n,f=[...H.values()].reduce((m,x)=>m+x,0),{outer:S}=X(Wt(E,f),!0,void 0,{stateKey:"bins",panel:c,render:m=>{const x=E==="hard"?r.hard:r.soft;for(const w of Pt(H,h,x,p))m.appendChild(w)},control:v&&N&&c?()=>ht([["hard","Hard"],["soft","Soft"]],E,m=>{M.binMode=m;const x=buildBinBreakdownSection(t);x&&S.replaceWith(x)},c.ownerDocument,!0):void 0});return S}export function buildLotBinSection(t,e,o,n){return buildBinSection(t,e,o,n)}export function buildRegionYieldPanelSection(t){const{diesByWafer:e,allWafers:o,ringCount:n,passBins:i,panel:d}=t,a=pt(d),p=s=>Gt(e,o,n,i,s==="ring"?Vt:Kt);if(!p("ring").length&&!p("quadrant").length)return null;const c=a.regionMode,{outer:r}=X(c==="ring"?"Ring Yield":"Quadrant Yield",!0,void 0,{stateKey:"regionYield",panel:d,render:s=>{const b=p(c);if(!b.length){s.appendChild(l("div",{fontSize:F.body,color:Y},"No positioned dies for this breakdown."));return}for(const{label:u,n:v,yieldPercent:N}of b)s.appendChild(gt(`${u} (N=${v})`,N))},control:d?()=>ht([["ring","Ring"],["quadrant","Quadrant"]],c,s=>{a.regionMode=s;const b=buildRegionYieldPanelSection(t);b&&r.replaceWith(b)},d.ownerDocument,!0):void 0});return r}export function buildLotOverviewSection(t,e=[]){const o=l("div"),n=wt(t.perWafer.map(a=>a.summary.wafer));o.appendChild(J(n.lotId!==void 0?"Lot Summary":"Summary"));const i=At();i.appendChild(at(String(t.stats.waferCount),"Wafers"));const d=t.perWafer.map(a=>a.summary.stats.yieldPercent).filter(a=>a!==null);if(d.length){const a=d.reduce((p,c)=>p+c,0)/d.length;i.appendChild(at(`${a.toFixed(1)}%`,"Mean per-wafer yield"))}if(i.finish(),o.appendChild(i),e.length){const a=e.reduce((c,r)=>c+r.stats.analyzedDies,0),p=e.reduce((c,r)=>c+r.stats.excludedDies,0);(a||p)&&o.appendChild(It("Dies analysed",p?`${a.toLocaleString()} (${p.toLocaleString()} excluded)`:a.toLocaleString()))}return o}export function buildPerWaferYieldSection(t,e,o,n,i){const d=t.perWafer.map(f=>({waferIndex:f.waferIndex,label:(e[f.waferIndex]?.label??`W${f.waferIndex+1}`).replace(/\s*·\s*\d+(\.\d+)?%$/,""),yieldPct:f.summary.stats.yieldPercent})).filter(f=>f.yieldPct!==null);if(!d.length)return null;const a=Math.min(...d.map(f=>f.yieldPct)),p=Math.max(...d.map(f=>f.yieldPct)),c=a===p?"":` (${a.toFixed(1)}\u2013${p.toFixed(1)}%)`,r=[...d.map(f=>f.yieldPct)].sort((f,S)=>f-S),s=ce(r),b=ot(r,.25),u=ot(r,.75),v=d.length>=5?b-1.5*(u-b):-1/0,N=pt(n),M=f=>{const S=N.waferSort==="yield"?[...d].sort((m,x)=>m.yieldPct-x.yieldPct):d;for(const{waferIndex:m,label:x,yieldPct:w}of S){const L=w<v?`${x} \xB7 low outlier`:x,R=gt(L,w,void 0,void 0,s),T=i?.(m);T?.total&&H(R,T),h(R,m,x,w,T),f.appendChild(R)}},W=` \xB7 median ${s.toFixed(1)}%`,{outer:E}=X("Wafer Yield"+c+W,!0,void 0,{stateKey:"waferYield",panel:n,render:M,control:n?f=>ht([["slot","Slot"],["yield","Yield"]],N.waferSort,S=>{N.waferSort=S,f()},n.ownerDocument,!0):void 0});return E;function H(f,S){const m=S.unusual?"unusual":S.notable?"notable":"info",x=l("span",{marginLeft:y.sm,flexShrink:"0",background:dt(m),color:"#fff",borderRadius:O.container,padding:"0 5px",fontSize:F.body,fontWeight:"600"},`${S.total}`);x.setAttribute("aria-hidden","true"),it(x,`${S.total} finding${S.total===1?"":"s"}`+(S.unusual?`, ${S.unusual} unusual`:"")+(S.notable?`, ${S.notable} notable`:"")),f.firstElementChild?.firstElementChild?.appendChild(x)}function h(f,S,m,x,w){o&&(f.style.cursor="pointer",f.style.borderRadius="4px",f.style.padding="2px 3px",f.style.marginLeft="-3px",f.style.marginRight="-3px",f.setAttribute("role","button"),f.setAttribute("aria-label",`${m}, ${x.toFixed(1)}% yield`+(w?.total?`, ${w.total} finding${w.total===1?"":"s"}${w.unusual?`, ${w.unusual} unusual`:""}`:"")+" \u2014 open wafer"),f.tabIndex=0,f.addEventListener("mouseenter",()=>{f.style.background=B.bgHover}),f.addEventListener("mouseleave",()=>{f.style.background=""}),f.addEventListener("focus",()=>{f.style.background=B.bgHover}),f.addEventListener("blur",()=>{f.style.background=""}),f.addEventListener("click",()=>o(S)),f.addEventListener("keydown",$=>{($.key==="Enter"||$.key===" ")&&($.preventDefault(),o(S))}))}}function xe(t){const e=[...t].sort((i,d)=>i-d),o=t.reduce((i,d)=>i+d,0)/t.length,n=t.reduce((i,d)=>i+(d-o)**2,0)/t.length;return{min:e[0],max:e[e.length-1],mean:o,count:t.length,stddev:Math.sqrt(n),median:ot(e,.5),q1:ot(e,.25),q3:ot(e,.75)}}function zt(t,e){if(!t)return[];const o=t.waferMetadata??(t.perWaferMetadata?yt(t.perWaferMetadata.map(n=>({metadata:n}))):void 0);return!o||!Object.keys(o).length?[]:ee({waferMetadata:o,waferKeys:"identity",waferPlacement:"csv",reservedLabels:e}).columns}function Ht(t){return t?.populationLabel?[{key:"population",label:"Population",scope:"wafer",constant:t.populationLabel,get:()=>t.populationLabel,csvOnly:!0}]:[]}export function buildTestSection(t,e,o,n,i,d,a,p,c="full"){const r=t.filter(g=>!g.partial&&!g.edgeExcluded),s=new Map((n?.perTestStats??[]).map(g=>[g.testNumber,g])),b=new Map((n?.testSpecYield??[]).map(g=>[g.testNumber,g]));let u;if(e?.length?u=e.filter(qt).map(g=>({testNumber:g.testNumber,name:g.name,unit:g.unit,limitLow:g.limitLow,limitHigh:g.limitHigh})):u=ae(r).map(C=>({testNumber:C,name:`Test ${C}`})),!u.length)return null;const v=u.filter(g=>r.some(C=>{const I=C.testValues?.[g.testNumber];return I!==void 0&&isFinite(I)}));if(!v.length)return null;const N=v.some(g=>g.limitLow!==void 0||g.limitHigh!==void 0),M=[];for(const g of v){const C=s.get(g.testNumber),I=C&&C.stddev!==void 0&&C.median!==void 0&&C.q1!==void 0&&C.q3!==void 0;let _;if(I){const k=C;_={testNumber:g.testNumber,min:k.min,max:k.max,mean:k.mean,count:k.count,stddev:k.stddev,median:k.median,q1:k.q1,q3:k.q3}}else{const k=r.map(D=>D.testValues?.[g.testNumber]).filter(D=>D!==void 0&&isFinite(D));if(!k.length)continue;_={testNumber:g.testNumber,...xe(k)}}let z=null,P=0;if(g.limitLow!==void 0||g.limitHigh!==void 0){const k=b.get(g.testNumber);if(k)({yieldPercent:z,totalDies:P}=k);else{const D=r.map(j=>j.testValues?.[g.testNumber]).filter(j=>j!==void 0&&isFinite(j)),Z=D.filter(j=>g.limitLow!==void 0&&j<g.limitLow||g.limitHigh!==void 0&&j>g.limitHigh).length;P=D.length,z=D.length>0?(D.length-Z)/D.length*100:null}}M.push({entry:g,stats:_,specYieldPct:z,specN:P})}if(!M.length)return null;const W=new Map;if(a?.length&&e?.length)for(const g of se(a,e))g.hasSpec&&W.set(g.testNumber,g.ppk);const E=W.size>0,h=new Set(M.map(g=>g.stats.count)).size===1?M[0].stats.count:null,f=l("div"),S=l("div",{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:y.sm}),m=h!==null?` \xB7 N=${h.toLocaleString()}`:"",x=d?.populationLabel?`Test Values (${M.length}) \u2014 ${d.populationLabel}${m}`:`Test Values (${M.length})${m}`,w=J(x);w.style.marginBottom="0",S.appendChild(w);const $=document.createElement("button");$.type="button",$.textContent="Test values CSV",Object.assign($.style,{...lt("outlined")}),q($),$.addEventListener("click",()=>{const g=["Test","Unit","N","Min","Q1","Median","Mean","Q3","Max","StdDev"];E&&g.push("Ppk");const C=M.some(k=>k.specYieldPct!==null&&k.specN!==k.stats.count);N&&(g.push("LSL","USL","Spec Yield %"),C&&g.push("Spec Yield N"));const I=[...zt(d,g),...Ht(d)],z=[[...I.map(k=>k.label),...g].map(ct).join(",")],P=k=>vt(k,void 0,"engineering");for(const{entry:k,stats:D,specYieldPct:Z,specN:j}of M){const st=[...I.map(et=>et.constant??""),k.name,k.unit??"",String(D.count),P(D.min),P(D.q1),P(D.median),P(D.mean),P(D.q3),P(D.max),P(D.stddev)];if(E){const et=W.get(k.testNumber);st.push(et==null?"":et.toFixed(3))}N&&(st.push(k.limitLow!==void 0?P(k.limitLow):"",k.limitHigh!==void 0?P(k.limitHigh):"",Z!==null?Z.toFixed(1):""),C&&st.push(k.limitLow!==void 0||k.limitHigh!==void 0?String(j):"")),z.push(st.map(ct).join(","))}Ft(z.join(`
2
- `),"test-values.csv","text/csv",i)}),S.appendChild($),f.appendChild(S);const L=l("table",{width:"100%",borderCollapse:"collapse",fontSize:F.body}),R=document.createElement("thead"),T=document.createElement("tr"),A=["Test"];h===null&&A.push("N"),c==="full"&&A.push("Min","Q1","Median"),A.push("Mean"),c==="full"&&A.push("Q3","Max","StdDev"),E&&A.push("Ppk"),c==="full"&&N&&A.push("LSL","USL"),N&&A.push("Spec yield");for(const g of A){const C=l("th",{textAlign:g==="Test"?"left":"right",fontWeight:"600",fontSize:F.meta,letterSpacing:rt,textTransform:"uppercase",color:Y,padding:"3px 8px 5px",borderBottom:`1px solid ${B.menuBorder}`,whiteSpace:"nowrap"},g);T.appendChild(C)}R.appendChild(T),L.appendChild(R);const V=document.createElement("tbody");for(const{entry:g,stats:C,specYieldPct:I,specN:_}of M){const z=D=>vt(D,g.unit,o),P=document.createElement("tr"),k=(D,Z="right")=>{const j=l("td",{textAlign:Z,padding:`${y.xs} ${y.md}`,borderBottom:`1px solid ${B.menuBorder}`,color:B.text,whiteSpace:"nowrap"},D);P.appendChild(j)};if(k(g.name,"left"),h===null&&k(`${C.count}`),c==="full"&&(k(z(C.min)),k(z(C.q1)),k(z(C.median))),k(z(C.mean)),c==="full"&&(k(z(C.q3)),k(z(C.max)),k(z(C.stddev))),E){const D=W.get(g.testNumber);k(D==null?"\u2014":D.toFixed(2))}c==="full"&&N&&(k(g.limitLow!==void 0?z(g.limitLow):"\u2014"),k(g.limitHigh!==void 0?z(g.limitHigh):"\u2014")),N&&k(I!==null?h!==null&&_===h?`${I.toFixed(1)}%`:`${I.toFixed(1)}% (N=${_})`:"\u2014"),V.appendChild(P)}L.appendChild(V);const K=l("div",{overflowX:"auto"});if(K.appendChild(L),!p)return f.appendChild(K),f;S.remove();const{outer:G}=X(x,!0,void 0,{stateKey:"testValues",panel:p,render:g=>g.appendChild(K),control:()=>$});return G}export function buildFunctionalTestSection(t,e,o,n,i,d){const a=o??Ut(t,e);if(!a?.length)return null;const c=new Set(a.map(m=>m.totalDies)).size===1?a[0].totalDies:null,r=c!==null?` \xB7 N=${c.toLocaleString()}`:"",s=l("div"),b=l("div",{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:y.sm}),u=i?.populationLabel?`Functional Tests (${a.length}) \u2014 ${i.populationLabel}${r}`:`Functional Tests (${a.length})${r}`,v=J(u);v.style.marginBottom="0",b.appendChild(v);const N=document.createElement("button");N.type="button",N.textContent="Functional CSV",Object.assign(N.style,{...lt("outlined")}),q(N),N.addEventListener("click",()=>{const m=["Test","N","Pass","Fail","Pass Rate %"],x=[...zt(i,m),...Ht(i)],w=[[...x.map($=>$.label),...m].map(ct).join(",")];for(const $ of a)w.push([...x.map(L=>L.constant??""),$.label,String($.totalDies),String($.passDies),String($.failDies),$.passRatePercent!==null?$.passRatePercent.toFixed(1):""].map(ct).join(","));Ft(w.join(`
3
- `),"functional-tests.csv","text/csv",n)}),b.appendChild(N),s.appendChild(b);const M=l("table",{width:"100%",borderCollapse:"collapse",fontSize:F.body}),W=document.createElement("thead"),E=document.createElement("tr"),H=c===null?["Test","N","Pass","Fail","Pass rate"]:["Test","Pass","Fail","Pass rate"];for(const m of H)E.appendChild(l("th",{textAlign:m==="Test"?"left":"right",fontWeight:"700",fontSize:F.body,letterSpacing:rt,textTransform:"uppercase",color:Y,padding:"3px 8px 5px",borderBottom:`1px solid ${B.menuBorder}`,whiteSpace:"nowrap"},m));W.appendChild(E),M.appendChild(W);const h=document.createElement("tbody");for(const m of a){const x=document.createElement("tr"),w=($,L="right")=>{x.appendChild(l("td",{textAlign:L,padding:`${y.xs} ${y.md}`,borderBottom:`1px solid ${B.menuBorder}`,color:U,whiteSpace:"nowrap"},$))};w(m.label,"left"),c===null&&w(String(m.totalDies)),w(String(m.passDies)),w(String(m.failDies)),w(m.passRatePercent!==null?`${m.passRatePercent.toFixed(1)}%`:"\u2014"),h.appendChild(x)}M.appendChild(h);const f=l("div",{overflowX:"auto"});if(f.appendChild(M),!d)return s.appendChild(f),s;b.remove();const{outer:S}=X(u,!0,void 0,{stateKey:"functionalTests",panel:d,render:m=>m.appendChild(f),control:()=>N});return S}export function buildLotFunctionalSection(t,e,o,n,i){const d=o?.length?{perWaferMetadata:o.map(p=>p.wafer??{}),populationLabel:`${o.length} wafer${o.length===1?"":"s"} pooled`}:void 0,a=le(o);return a?buildFunctionalTestSection(t,e,a,n,d,i):buildFunctionalTestSection(t,e,void 0,n,d,i)}const tt={unusual:0,notable:1,info:2};function bt(t){return l("span",{display:"inline-block",width:"7px",height:"7px",borderRadius:O.pill,background:dt(t),flexShrink:"0"})}function Yt(t,e){let o=t.summary;return e&&(o.startsWith(`${e} has `)?o=o.slice(e.length+5):o.startsWith(`${e} `)&&(o=o.slice(e.length+1))),o=nt(o),o.length?o[0].toUpperCase()+o.slice(1):o}export function buildFindingsSection(t,e,o,n,i=!1){if(!t.length)return null;const d=t.some(h=>h.severity==="unusual"||h.severity==="notable"),a=d?t.filter(h=>h.severity!=="info").length.toString():void 0,{outer:p,content:c}=i?(()=>{const h=l("div");return{outer:h,content:h}})():X(`Findings (${t.length})`,d,a);function r(h){return h.reduce((f,S)=>tt[S.severity]<tt[f]?S.severity:f,"info")}function s(h){const f=new Map;for(const m of h){const x=`${m.comparison.family}\0${m.comparison.left}`,w=f.get(x)??[];w.push(m),f.set(x,w)}const S=[...f.entries()].map(([m,x])=>{const w=[...x].sort(($,L)=>tt[$.severity]-tt[L.severity]);return{key:m,findings:w,worst:r(w)}});return S.sort((m,x)=>tt[m.worst]-tt[x.worst]),S}function b(h,f){const m={ring:"Ring",quadrant:"Quadrant",sector:"Sector","reticle-position":"Reticle","test-site":"Test site",cluster:"Cluster","edge-arc":"Edge arc",wafer:"Wafer"}[h]??h;return f.toLowerCase().startsWith(m.toLowerCase())?f:`${m}: ${f}`}const u=t.filter(h=>h.comparison.family==="spatial-pattern"),v=new Set([...u.flatMap(h=>h.relatedIds??[]),...t.flatMap(h=>h.absorbedIds??[])]),N=t.filter(h=>h.comparison.family!=="spatial-pattern"&&!v.has(h.id)),M=s(N);function W(h,f=!1,S){const m=n===h.id,x=document.createElement("button");return x.type="button",x.dataset.wmapFinding=h.id,x.textContent=Yt(h,S),it(x,h.summary),x.setAttribute("aria-current",m?"true":"false"),Object.assign(x.style,{border:`1px solid ${B.menuBorder}`,borderLeft:`3px solid ${dt(h.severity)}`,background:m?B.bgActive:B.menuBg,borderRadius:O.container,padding:f?"6px 10px":"8px 10px",textAlign:"left",fontSize:f?"10px":"11px",fontWeight:m?"600":"400",color:B.text,cursor:"pointer",width:"100%",marginBottom:y.xs}),q(x,"bare"),x.addEventListener("click",()=>o(h,x)),x}const E=nt(Zt(t)??"");if(E){const h=l("div",{background:B.bgActive,borderRadius:O.container,padding:`${y.md} ${y.lg}`,marginBottom:y.md,display:"flex",gap:y.md,alignItems:"flex-start"}),f=l("span",{flex:"1",fontSize:F.body,lineHeight:Q.base,color:B.text},E);h.appendChild(f);const S=l("button",{flexShrink:"0",border:"none",background:"none",fontSize:F.body,color:B.icon,cursor:"pointer",padding:"0",lineHeight:Q.base,whiteSpace:"nowrap"},"Detail \u25B8");S.type="button",q(S,"bare"),S.addEventListener("click",()=>{const m=Bt({title:"Findings Summary",onClose:()=>{},anchor:S}),x=l("p",{fontSize:"16px",lineHeight:Q.base,color:B.text,padding:`${y.xxl} ${y.xxxl} ${y.xxl}`,margin:"0",borderBottom:`1px solid ${B.menuBorder}`,flexShrink:"0"},E);m.contentWrap.appendChild(x);const w=l("div",{overflowY:"auto",padding:`${y.xxl} ${y.xxxl}`,flex:"1"}),$=(L,R)=>{const T=l("div",{display:"flex",alignItems:"center",gap:"7px",fontSize:F.sub,fontWeight:"600",color:U,marginTop:y.lg,marginBottom:y.xs});return T.appendChild(bt(L)),T.appendChild(l("span",{},R)),T};for(const L of u){w.appendChild($(L.severity,L.comparison.left)),w.appendChild(l("div",{fontSize:F.body,color:B.text,padding:"4px 0 4px 15px",marginBottom:y.xxs},nt(L.summary)));const R=t.filter(T=>L.relatedIds?.includes(T.id));for(const T of R)w.appendChild(l("div",{fontSize:F.body,color:Y,padding:"2px 0 2px 23px",marginBottom:y.xxs},nt(T.summary)))}for(const L of M){const[R,T]=L.key.split("\0");w.appendChild($(L.worst,b(R,T)));for(const A of L.findings)w.appendChild(l("div",{fontSize:F.body,color:B.text,padding:"4px 0 4px 15px",marginBottom:y.xxs},Yt(A,T)))}m.contentWrap.appendChild(w),Object.assign(m.contentWrap.style,{flexDirection:"column",overflow:"hidden"})}),h.appendChild(S),c.appendChild(h)}let H=!0;for(const h of u){H||c.appendChild(l("div",{height:"1px",background:B.separator,margin:"4px 0"})),H=!1;const f=t.filter($=>h.relatedIds?.includes($.id)),S=f.length>0,m=l("div",{position:"relative",marginBottom:S?"2px":"4px"}),x=n===h.id,w=document.createElement("button");if(w.type="button",w.dataset.wmapFinding=h.id,Object.assign(w.style,{border:`1px solid ${B.menuBorder}`,borderLeft:`3px solid ${dt(h.severity)}`,background:x?B.bgActive:B.menuBg,borderRadius:O.container,padding:"8px 32px 8px 10px",textAlign:"left",fontSize:F.body,fontWeight:x?"600":"500",color:B.text,cursor:"pointer",width:"100%"}),w.textContent=nt(h.summary),it(w,h.summary),w.setAttribute("aria-current",x?"true":"false"),q(w,"bare"),w.addEventListener("click",()=>o(h,w)),m.appendChild(w),S){const $=l("div",{display:"none",paddingLeft:"12px",marginBottom:y.xs});for(const T of f)$.appendChild(W(T,!0));m.appendChild($);let L=!1;const R=l("button",{position:"absolute",top:"50%",right:"8px",transform:"translateY(-50%)",border:"none",background:"none",fontSize:F.body,color:B.icon,cursor:"pointer",padding:`${y.xxs} ${y.xs}`,lineHeight:Q.none},"\u25B8");q(R,"bare"),R.type="button",it(R),R.setAttribute("aria-label","Show supporting findings"),R.setAttribute("aria-expanded","false"),R.addEventListener("click",T=>{T.stopPropagation(),L=!L,$.style.display=L?"block":"none",R.textContent=L?"\u25BE":"\u25B8";const A=L?"Hide supporting findings":"Show supporting findings";R.setAttribute("aria-label",A),R.setAttribute("aria-expanded",String(L))}),m.appendChild(R)}c.appendChild(m)}for(const h of M){H||c.appendChild(l("div",{height:"1px",background:B.separator,margin:"4px 0"})),H=!1;const[f,S]=h.key.split("\0"),m=l("div",{display:"flex",alignItems:"center",gap:y.sm,fontSize:F.body,fontWeight:"600",color:U,margin:"2px 0 4px"});m.appendChild(bt(h.worst)),m.appendChild(l("span",{},b(f,S))),c.appendChild(m);for(const x of h.findings)c.appendChild(W(x,!1,S))}return p}const ye=[{value:"",label:"All kinds"},{value:"yield",label:"Yield"},{value:"hardBin",label:"Hard bin"},{value:"softBin",label:"Soft bin"},{value:"test",label:"Test value"},{value:"functionalTest",label:"Functional test"},{value:"spatialPattern",label:"Spatial pattern"}],Ce=[{value:"",label:"All regions"},{value:"ring",label:"Ring"},{value:"quadrant",label:"Quadrant"},{value:"reticle-position",label:"Reticle position"},{value:"test-site",label:"Test site"},{value:"wafer",label:"Wafer"},{value:"sector",label:"Sector"},{value:"cluster",label:"Cluster"},{value:"edge-arc",label:"Edge arc"},{value:"spatial-pattern",label:"Spatial pattern"}],we=["unusual","notable","info"],Se={unusual:"Unusual",notable:"Notable",info:"Info"};function ve(t,e,o){const n=l("div",{display:"flex",flexWrap:"wrap",alignItems:"center",gap:y.lg,marginBottom:y.lg,paddingBottom:"10px",borderBottom:`1px solid ${B.separator}`}),i={unusual:0,notable:0,info:0};for(const r of t)i[r.severity]++;const d=we.filter(r=>i[r]>0),a=new Set(e.severity===void 0?d:Array.isArray(e.severity)?e.severity:[e.severity]),p=l("div",{display:"flex",gap:y.xs,flexWrap:"wrap"});for(const r of d){const s=document.createElement("button");s.type="button";const b=()=>{const u=a.has(r);s.setAttribute("aria-pressed",u?"true":"false"),Object.assign(s.style,{display:"inline-flex",alignItems:"center",gap:"5px",border:`1px solid ${B.menuBorder}`,borderRadius:O.pill,background:u?B.bgActive:"none",opacity:u?"1":"0.5",color:B.text,fontSize:F.body,padding:`${y.xxs} ${y.md}`,cursor:"pointer"}),s.dataset.on=u?"true":"false"};s.appendChild(bt(r)),s.appendChild(l("span",{},`${Se[r]} ${i[r]}`)),it(s,()=>a.has(r)?"Click to hide these findings":"Click to show these findings"),b(),q(s,"bare"),s.addEventListener("click",()=>{a.has(r)?a.delete(r):a.add(r),e.severity=a.size===d.length?void 0:[...a],o()}),p.appendChild(s)}n.appendChild(p);const c=e.kind!==void 0||e.family!==void 0;return(t.length>=$e||c)&&(n.appendChild($t("Kind:",ye,e.kind??"",r=>{e.kind=r||void 0,o()},{maxWidth:"130px"})),n.appendChild($t("Region:",Ce,e.family??"",r=>{e.family=r||void 0,o()},{maxWidth:"150px"}))),n}const $e=8;function ke(t,e){const o=l("div",{display:"flex",flexDirection:"column",gap:y.xs,padding:y.md,marginBottom:y.md,background:B.bgHover,borderRadius:O.control},void 0,e);if(o.appendChild(l("div",{fontSize:F.body,color:B.value},t.message,e)),t.detail&&o.appendChild(l("div",{fontSize:F.meta,color:Y},t.detail,e)),t.actionLabel&&t.onAction){const n=l("button",lt("outlined"),t.actionLabel,e);n.type="button",n.style.alignSelf="flex-start",n.style.marginTop=y.xs,q(n),n.addEventListener("click",t.onAction),o.appendChild(n)}return o}export function buildFindingsSectionWithFilter(t,e,o,n,i,d,a){if(!t.findings.length&&!a)return null;const p=t.findings.some(N=>N.severity==="unusual"||N.severity==="notable"),c=p?t.findings.filter(N=>N.severity!=="info").length.toString():void 0,r=d?.ownerDocument??document,{outer:s,content:b}=X(`Findings (${t.findings.length})`,p||!!a,c,{stateKey:"findings",panel:d});if(a&&b.appendChild(ke(a,r)),!t.findings.length)return s;b.appendChild(ve(t.findings,n,i));const u=Jt(t,n);if(!u.length)return b.appendChild(l("div",{color:Y,fontSize:F.body,textAlign:"center",padding:`${y.xxl} ${y.md}`},"No findings match the current filter.")),s;const v=buildFindingsSection(u,t,e,o,!0);return v&&b.appendChild(v),s}export function buildLotTestSection(t,e,o,n,i,d,a,p="full"){const c=n?.length?{perWaferMetadata:n.map(s=>s.wafer??{}),populationLabel:`${n.length} wafer${n.length===1?"":"s"} pooled`}:void 0;let r;if(n?.length&&n.every(s=>s.stats.perTestStats!==void 0)){const s=new Map;for(const b of n)for(const u of b.stats.perTestStats??[]){const v=s.get(u.testNumber);v?(v.n+=u.count,v.sum+=u.mean*u.count,v.min=Math.min(v.min,u.min),v.max=Math.max(v.max,u.max)):s.set(u.testNumber,{n:u.count,sum:u.mean*u.count,min:u.min,max:u.max})}r={perTestStats:[...s.entries()].map(([b,u])=>({testNumber:b,count:u.n,min:u.min,max:u.max,mean:u.sum/u.n}))}}if(n?.length&&n.every(s=>s.stats.testSpecYield!==void 0)){const s=new Map;for(const b of n)for(const u of b.stats.testSpecYield??[]){const v=s.get(u.testNumber);v?(v.passDies+=u.passDies,v.totalDies+=u.totalDies):s.set(u.testNumber,{passDies:u.passDies,totalDies:u.totalDies})}r={...r,testSpecYield:[...s.entries()].map(([b,u])=>({testNumber:b,totalDies:u.totalDies,yieldPercent:u.totalDies>0?u.passDies/u.totalDies*100:null}))}}return buildTestSection(t,e,o,r,i,c,d,a,p)}export function createSummaryPanelEl(t,e,o=document){const n=t==="top"||t==="bottom",i=l("div",{background:ue,color:B.text,fontVariantNumeric:"tabular-nums",border:Et,borderRadius:O.container,padding:y.xl,overflowY:"auto",overflowX:n?"auto":"hidden",flexShrink:"0",boxSizing:"border-box",fontFamily:F.family,fontSize:F.sub,boxShadow:kt.panel},void 0,o);return t==="right"&&(i.style.marginRight=e),t==="left"&&(i.style.marginLeft=e),t==="bottom"&&(i.style.marginBottom=e),n?(i.style.height="180px",i.style.width="100%"):(i.style.width="300px",i.style.maxHeight="100%"),i}export function wrapWithSummaryPanel(t,e,o){const n=o==="top"||o==="bottom",i=l("div",{display:"flex",flexDirection:n?"column":"row",gap:y.md,width:"100%",height:"100%",flex:"1 1 0",minHeight:"0",boxSizing:"border-box",alignItems:n?"flex-start":"stretch"});return t.style.flex="1 1 0",t.style.minWidth="0",t.style.minHeight="0",o==="right"||o==="bottom"?(i.appendChild(t),i.appendChild(e)):(i.appendChild(e),i.appendChild(t)),i}function Ot(t){return l("div",{fontSize:F.heading,fontWeight:"600",color:U,marginBottom:y.lg},t)}function ft(t,e){const o=l("button",lt("outlined"),t);return o.type="button",q(o),o.addEventListener("click",e),o}function _t(...t){const e=t.filter(n=>!!n);if(!e.length)return null;const o=l("div",{display:"flex",flexWrap:"wrap",gap:y.sm,marginBottom:y.lg});for(const n of e)o.appendChild(n);return o}function jt(t,e,o,n,i,d,a,p,c,r,s){const b=t.ownerDocument,u=Bt({title:"Die list",onClose:()=>{},anchor:t,ownerDocument:b});u.contentWrap.style.padding="14px 16px";const v=de(e,o,{...a,title:n,onSaveText:p,waferMetadata:i,metadataFields:d,extraColumn:c,getWafer:r,ringCount:s,ownerDocument:b});v&&u.contentWrap.appendChild(v)}export function renderWaferSummaryContent(t,e){const o=t.scrollTop;t.innerHTML="";const{wafer:n,dies:i,yieldSummary:d,dataCoverage:a,hbinDefs:p,sbinDefs:c,testDefs:r,statsSummary:s,passBins:b=[1],ringCount:u=4,binColors:v,plotMode:N,fallbackFormat:M,onFindingClick:W,activeFindingId:E=null,findingsFilter:H,onFindingsFilterChange:h,findingsNotice:f,onSaveText:S,metadataFields:m,dieListOptions:x,metadataShownElsewhere:w}=e;t.appendChild(Ot("Wafer Summary"));const $=e.warnings??St({statsSummary:s});$.length&&t.appendChild(mt($,t.ownerDocument));const L=d&&a?ft("Summary report",()=>{Nt(Qt({wafer:n,dies:i,yieldSummary:d,dataCoverage:a,hbinDefs:p,sbinDefs:c,testDefs:r,statsSummary:s,passBins:b,ringCount:u}),{anchor:t})}):null,R=(x?.enabled??!0)&&i.length?ft("View die list",()=>{jt(t,i,r,`Die list \u2014 ${i.length} dies`,n.metadata,m,x,S,void 0,()=>n,u)}):null,T=_t(L,R);T&&t.appendChild(T);const A=[],V=s?.stats.isLotStack?s.stats:void 0,K=V?.lotSize!==void 0?{lotSize:V.lotSize,aggrMethod:ie(V.aggregationMethod)}:void 0;w||A.push(buildMetadataInfoSection([{metadata:n.metadata??void 0}],K)),d&&a&&A.push(buildYieldSection(d,a,b)),s&&W&&H&&h&&A.push(buildFindingsSectionWithFilter(s,W,E,H,h,t,f)),A.push(buildBinBreakdownSection({dies:i,hbinDefs:p,sbinDefs:c,binColors:v,hardCounts:s?.stats.hardBinCounts,softCounts:s?.stats.softBinCounts,plotMode:N,passBins:b,panel:t})),A.push(buildRegionYieldPanelSection({diesByWafer:[i],allWafers:[n],ringCount:u,passBins:b,panel:t}));const G=n.metadata?{waferMetadata:n.metadata}:void 0;A.push(buildTestSection(i,r,M,s?.stats,S,G,[{dies:i}],t,"compact")),A.push(buildFunctionalTestSection(i,r,s?.stats.functionalYield,S,G,t));let g=!0;for(const C of A)C&&(g||t.appendChild(Mt()),g=!1,t.appendChild(C));t.appendChild(l("div",{height:"12px",flexShrink:"0"})),t.scrollTop=o}export function renderLotSummaryContent(t,e){const o=t.scrollTop;t.innerHTML="";const{lotSummary:n,items:i,hbinDefs:d,sbinDefs:a,testDefs:p,passBins:c=[1],ringCount:r=4,binColors:s,plotMode:b,fallbackFormat:u,onFindingClick:v,activeFindingId:N=null,onWaferClick:M,findingsFilter:W,onFindingsFilterChange:E,findingsNotice:H,onSaveText:h,dieListOptions:f,findingsFor:S}=e;t.appendChild(Ot(`Summary \u2014 ${oe(wt(n.perWafer.map(C=>C.summary.wafer)))}`));const m=e.warnings??St({lotStatsSummary:n});m.length&&t.appendChild(mt(m,t.ownerDocument));const x=ft("Summary report",()=>{Nt(Xt({items:i.map((C,I)=>({label:C?.label??`W${I+1}`,wafer:C?.wafer,dies:C?.dies,statsSummary:C?.statsSummary})),hbinDefs:d,sbinDefs:a,testDefs:p,passBins:c,ringCount:r}),{anchor:t})}),w=[],$=[],L=[],R=new WeakMap,T=new WeakMap;for(let C=0;C<i.length;C++){const I=i[C];if(!I){$.push([]);continue}I.wafer&&w.push(I.wafer);const _=I.dies??[],z=I.label??`W${C+1}`;for(const P of _)R.set(P,z),I.wafer&&T.set(P,I.wafer);$.push(_),L.push(..._)}const A=f?.enabled??!0?ft("View die list",()=>{L.length&&jt(t,L,p,`Die list \u2014 ${L.length} dies across ${i.length} wafer${i.length===1?"":"s"}`,yt(i.filter(C=>!!C).map(C=>({metadata:C.wafer?.metadata}))),i.find(C=>C?.metadataFields?.length)?.metadataFields,f,h,{label:"Wafer",get:C=>R.get(C)},C=>T.get(C),r)}):null,V=_t(x,A);V&&t.appendChild(V);const K=i.map(C=>C?.statsSummary).filter(C=>!!C),G=[buildLotOverviewSection(n,K)];v&&W&&E&&G.push(buildFindingsSectionWithFilter(n,v,N,W,E,t,H)),G.push(buildPerWaferYieldSection(n,i,M,t,S),buildBinBreakdownSection({dies:L,hbinDefs:d,sbinDefs:a,binColors:s,plotMode:b,passBins:c,panel:t}),buildRegionYieldPanelSection({diesByWafer:$,allWafers:w,ringCount:r,passBins:c,panel:t}),p?.length?buildLotTestSection(L,p,u,K,h,$.map(C=>({dies:C})),t,"compact"):null,p?.length?buildLotFunctionalSection(L,p,K,h,t):null);let g=!0;for(const C of G)C&&(g||t.appendChild(Mt()),g=!1,t.appendChild(C));t.appendChild(l("div",{height:"12px",flexShrink:"0"})),t.scrollTop=o}
1
+ import{waferDisplayLabel as me}from"../core/waferLabel.js";import{itemPassBins as he,passBinsLabel as Ke}from"../core/passBins.js";import{isParametricTest as Ge}from"../renderer/buildWaferMap.js";import{buildRingRegions as Ue,buildQuadrantRegions as Qe,buildRegionYieldData as Xe}from"../stats/regions.js";import{computeFunctionalYield as Ze}from"../stats/analyzeWaferMap.js";import{renderWaferReportHtml as Je,renderLotReportHtml as et}from"../stats/renderSummaryReport.js";import{buildFindingsNarrative as tt}from"../stats/findingsNarrative.js";import{filterFindings as nt}from"../stats/filterFindings.js";import{buildFacetTable as ot,prettyKey as Ce}from"../stats/facets.js";import{commonMetadata as we}from"../stats/facets.js";import{resolveMetadataColumns as it}from"../stats/metadataColumns.js";import{resolveBinColors as Se,resolveBinColorsByWafer as st}from"../renderer/binColors.js";import{NO_DATA_FILL as at}from"../renderer/colorMap.js";import{describeWaferPopulation as ve,populationLabel as rt}from"../stats/population.js";import{buildWarningsBanner as ge,collectWarnings as $e}from"./warnings.js";export{ge as buildWarningsBanner};import{fmt as ke,fmtAggregationMethod as lt,plainBinTerms as ne}from"../renderer/fmt.js";import{getUniqueTestNumbers as dt}from"../renderer/buildView.js";import{quantile as oe}from"../stats/math.js";import{buildCapabilityData as ct}from"../stats/capability.js";import{sortBinsForDisplay as pt}from"../stats/binPareto.js";import{poolFunctionalYield as ut}from"../stats/testPassRate.js";import{makeLabeledSelect as Be,makeSegmented as be}from"./charts/chartShell.js";import{SHADOW as Le,MOTION as Ne,LEADING as Q,TRACKING as re,wireControlHover as q,controlStyle as le,SPACE as y,RADIUS as _,FONT as E,CLR as B,sevColor as de,openModal as Fe,openReportModal as Ee,saveTextFile as De,wireTooltip as ie}from"./toolbar.js";import{buildDieListSection as ft}from"./dieList.js";export{csvField}from"../core/utils.js";import{medianOfSorted as mt,csvField as ce}from"../core/utils.js";import{metadataDisplayValue as ht}from"../core/metadata.js";const gt=B.panelBg,Re=`1px solid ${B.menuBorder}`,bt="12px",Y=B.label,K=B.value,Te="10px";function l(e,t,o,n=document){const i=n.createElement(e);return t&&Object.assign(i.style,t),o!==void 0&&(i.textContent=o),i}function J(e){return l("div",{fontSize:Te,fontWeight:"700",letterSpacing:re,textTransform:"uppercase",color:Y,marginBottom:y.sm},e)}const Me=new WeakMap,Ie=["regionYield","testValues","functionalTests"];function pe(e){if(!e)return{collapsed:new Set(Ie),regionMode:"ring",waferSort:"slot"};let t=Me.get(e);return t||(t={collapsed:new Set(Ie),regionMode:"ring",waferSort:"slot"},Me.set(e,t)),t}function X(e,t=!0,o,n){const i=l("div"),d=pe(n?.panel);n?.stateKey&&n.panel&&(t=!d.collapsed.has(n.stateKey));const s=document.createElement("button");s.type="button",Object.assign(s.style,{display:"flex",alignItems:"center",gap:y.xs,width:"100%",background:"none",border:"none",cursor:"pointer",padding:"0 0 6px",textAlign:"left"});const p=l("span",{fontSize:E.meta,color:Y,transition:`transform ${Ne.base}`,transform:t?"rotate(90deg)":"rotate(0deg)",display:"inline-block",lineHeight:Q.none,marginRight:"1px"},"\u25B6"),c=l("span",{fontSize:Te,fontWeight:"700",letterSpacing:re,textTransform:"uppercase",color:Y,flex:"1"},e);if(q(s,"bare"),s.setAttribute("aria-expanded",t?"true":"false"),s.appendChild(p),s.appendChild(c),o){const b=l("span",{fontSize:E.meta,fontWeight:"700",background:B.warnBg,color:B.warnText,borderRadius:_.pill,padding:"1px 5px"},o);s.appendChild(b)}const r=l("div");r.style.display=t?"block":"none";let a=t;if(s.addEventListener("click",()=>{a=!a,r.style.display=a?"block":"none",p.style.transform=a?"rotate(90deg)":"rotate(0deg)",s.setAttribute("aria-expanded",a?"true":"false"),n?.stateKey&&n.panel&&(a?d.collapsed.delete(n.stateKey):d.collapsed.add(n.stateKey))}),n?.control){const b=l("div",{display:"flex",alignItems:"center",gap:y.sm});s.style.width="auto",s.style.flex="1",b.appendChild(s);const u=()=>{r.innerHTML="",n.render?.(r)},S=n.control(u);S&&(S.style.marginBottom="6px",S.addEventListener("click",N=>N.stopPropagation()),b.appendChild(S)),i.appendChild(b)}else i.appendChild(s);return i.appendChild(r),n?.render?.(r),{outer:i,content:r}}function Ae(){return l("div",{height:"1px",background:B.separator,margin:`${bt} 0`,flexShrink:"0"})}function xe(e,t,o=B.barFill,n,i){const d=l("div",{marginBottom:"5px"}),s=l("div",{display:"flex",justifyContent:"space-between",fontSize:E.body,color:K,marginBottom:y.xxs}),p=l("span",{color:Y},e),c=l("span",{fontWeight:"600"},`${t.toFixed(1)}%`);s.appendChild(p),s.appendChild(c);const r=n!==void 0?n:Math.min(100,Math.max(0,t)),a=o,b=l("div",{position:"relative",height:"9px",background:B.bgActive,borderRadius:_.control,overflow:"hidden"}),u=l("div",{height:"100%",width:`${r}%`,background:a,borderRadius:_.control,transition:`width ${Ne.base}`});if(b.appendChild(u),i!==void 0){const S=l("div",{position:"absolute",top:"0",bottom:"0",left:`${i}%`,width:"2px",marginLeft:"-1px",background:B.value,opacity:"0.8"});b.appendChild(S)}return d.appendChild(s),d.appendChild(b),d}function We(){const e=l("div",{display:"flex",gap:y.sm,marginBottom:y.md});return e.finish=()=>{const t=e.lastElementChild;t&&Object.assign(t.style,{borderRight:"none",paddingRight:"0"})},e}function se(e,t,o){const n=l("div",{padding:`${y.xxs} ${y.md} ${y.xxs} 0`,borderRight:Re,textAlign:"center",flex:"1"}),i=l("div",{fontSize:E.heading,fontWeight:"700",color:K,lineHeight:Q.tight},e),d=l("div",{fontSize:E.body,color:Y,marginTop:y.xxs},t);return n.appendChild(i),n.appendChild(d),o&&n.appendChild(l("div",{fontSize:E.body,color:Y,opacity:"0.85"},o)),n}function Pe(e,t){const o=l("div",{display:"flex",justifyContent:"space-between",fontSize:E.body,gap:y.md,marginBottom:"3px"}),n=l("span",{color:Y,flexShrink:"0"},e),i=l("span",{color:K,textAlign:"right",fontWeight:"500",wordBreak:"break-all"},t);return o.appendChild(n),o.appendChild(i),o}function xt(e,t){const o=l("div",{display:"flex",fontSize:E.body,gap:y.sm,marginBottom:"3px"}),n=l("span",{color:Y,flexShrink:"0"},`${e}:`),i=l("span",{color:K,fontWeight:"500",wordBreak:"break-all"},t);return o.appendChild(n),o.appendChild(i),o}export function metadataEntries(e){const t=[];for(const[o,n]of Object.entries(e)){const i=ht(n);i!==void 0&&t.push([o,i])}return t}const yt=["lot","product","testprogram","split"],ue=e=>{const t=yt.indexOf(e.toLowerCase().replace(/[^a-z]/g,""));return t===-1?Number.MAX_SAFE_INTEGER:t};export function buildFacetSummaryChips(e,t=3){if(!e.length)return null;const o=l("div",{display:"flex",flexWrap:"wrap",alignItems:"baseline",gap:`${y.xs} ${y.lg}`}),n=[...e].sort((p,c)=>ue(p.key)-ue(c.key)),i=n.filter(p=>ue(p.key)!==Number.MAX_SAFE_INTEGER),d=n.filter(p=>ue(p.key)===Number.MAX_SAFE_INTEGER),s=p=>{const c=l("span",{whiteSpace:"nowrap"}),r=l("span",{color:Y},`${Ce(p.key)}: `);c.appendChild(r);const a=p.values.slice(0,t),b=p.values.length-a.length;let u=a.map(S=>S.value).join(", ");return b>0&&(u+=` +${b} more`),c.appendChild(document.createTextNode(u)),c};for(const p of i)o.appendChild(s(p));if(d.length){const p=l("span",{display:"none",flexWrap:"wrap",alignItems:"baseline",gap:`${y.xs} ${y.lg}`});for(const a of d)p.appendChild(s(a));const c=l("button",{background:"none",border:"none",padding:"0",cursor:"pointer",color:B.iconActive,fontSize:E.body,whiteSpace:"nowrap"});c.type="button",q(c,"bare");const r=a=>{p.style.display=a?"contents":"none",c.textContent=a?"less":`+${d.length} more`,c.setAttribute("aria-expanded",String(a))};r(!1),c.addEventListener("click",()=>r(c.getAttribute("aria-expanded")!=="true")),o.appendChild(p),o.appendChild(c)}return o}export function buildMetadataStripRow(e,t,o){const n=ot(e,o),i=buildFacetSummaryChips(n);if(!i&&!t)return null;const d=l("div",{display:"flex",flexWrap:"wrap",alignItems:"baseline",gap:"4px 14px"});if(t){const s=l("span",{fontWeight:"500",whiteSpace:"nowrap"},t.aggrMethod?`${t.lotSize} wafers stacked \xB7 ${t.aggrMethod}`:`${t.lotSize} wafers stacked`);d.appendChild(s)}return i&&d.appendChild(i),d}const Ct={display:"flex",flexDirection:"column",gap:y.sm,background:B.menuBg,border:`1px solid ${B.menuBorder}`,borderRadius:_.container,padding:`${y.sm} ${y.lg}`,boxShadow:Le.panel,fontSize:E.body,lineHeight:Q.none,boxSizing:"border-box",width:"100%",minWidth:"0"};export function buildMetadataStripBox(e,t,o){const n=buildMetadataStripRow(e,t,o);if(!n)return null;const i=l("div",Ct);return i.appendChild(n),i}export function buildCompactMetadataRows(e){const t=metadataEntries(e);if(!t.length)return null;const o=l("div");for(const[n,i]of t)o.appendChild(xt(Ce(n),i));return o}export function buildMetadataInfoSection(e,t){const o=buildMetadataStripRow(e,t,{facetableOnly:e.length>1});if(!o)return null;const n=l("div");return n.appendChild(J("Wafer Info")),n.appendChild(o),n}export function buildYieldSection(e,t,o=[1]){const n=l("div");n.appendChild(J("Summary"));const i=We();if(i.appendChild(se(String(e.totalDies),"Total dies")),e.partialDies>0&&i.appendChild(se(String(e.partialDies),"Partial")),e.yieldPercent!==null){const d=Ke([o]);i.appendChild(se(`${e.yieldPercent.toFixed(1)}%`,"Yield",`pass: ${d}`))}return i.finish(),n.appendChild(i),e.edgeExcludedDies>0&&n.appendChild(Pe("Edge excluded (outer zone)",String(e.edgeExcludedDies))),n}export function buildBinSection(e,t,o,n,i,d){const s=new Map;if(i)for(const[r,a]of Object.entries(i))s.set(Number(r),a);else for(const r of e){if(r.partial||r.edgeExcluded)continue;const a=o==="hard"?r.hbin:r.sbin;a!=null&&s.set(a,(s.get(a)??0)+1)}if(!s.size)return null;const p=n??Se(e,{passBins:d,...o==="hard"?{hbinDefs:t}:{sbinDefs:t}}),c=l("div");c.appendChild(J(ze(o,[...s.values()].reduce((r,a)=>r+a,0))));for(const r of He(s,t,p[o],p.pass[o]))c.appendChild(r);return c}function ze(e,t){return`${e==="hard"?"Hard":"Soft"} Bin Breakdown \u2014 % of dies (N=${t})`}function He(e,t,o,n){const i=[...e.values()].reduce((p,c)=>p+c,0),d=t?new Map(t.map(p=>[p.bin,p])):null;return pt(e.entries(),n).map(([p,c])=>{const r=d?.get(p),a=r?.name?`Bin ${p} \xB7 ${r.name}`:`Bin ${p}`,b=c/i*100,u=o.get(p)??at;return xe(`${a} (${c})`,b,u)})}export function buildBinBreakdownSection(e){const{dies:t,hbinDefs:o,sbinDefs:n,hardCounts:i,softCounts:d,plotMode:s,passBins:p=[1],panel:c}=e,r=e.binColors??Se(t,{passBins:p,hbinDefs:o,sbinDefs:n}),a=m=>{const x=m==="hard"?i:d,C=new Map;if(x){for(const[v,k]of Object.entries(x))C.set(Number(v),k);return C}for(const v of t){if(v.partial||v.edgeExcluded)continue;const k=m==="hard"?v.hbin:v.sbin;k!=null&&C.set(k,(C.get(k)??0)+1)}return C},b=a("hard"),u=a("soft"),S=b.size>0,N=u.size>0;if(!S&&!N)return null;const A=pe(c),P=s==="softBin"||s==="stackedSoftBins"?"soft":s==="hardBin"||s==="stackedBins"?"hard":void 0;let R=A.binMode??P??(S?"hard":"soft");R==="hard"&&!S&&(R="soft"),R==="soft"&&!N&&(R="hard");const H=R==="hard"?b:u,h=R==="hard"?o:n,f=[...H.values()].reduce((m,x)=>m+x,0),{outer:w}=X(ze(R,f),!0,void 0,{stateKey:"bins",panel:c,render:m=>{const x=R==="hard"?r.hard:r.soft;for(const C of He(H,h,x,r.pass[R]))m.appendChild(C)},control:S&&N&&c?()=>be([["hard","Hard"],["soft","Soft"]],R,m=>{A.binMode=m;const x=buildBinBreakdownSection(e);x&&w.replaceWith(x)},c.ownerDocument,!0):void 0});return w}export function buildLotBinSection(e,t,o,n){return buildBinSection(e,t,o,n)}export function buildRegionYieldPanelSection(e){const{diesByWafer:t,allWafers:o,ringCount:n,passBins:i,panel:d}=e,s=pe(d),p=a=>Xe(t,o,n,i,a==="ring"?Ue:Qe);if(!p("ring").length&&!p("quadrant").length)return null;const c=s.regionMode,{outer:r}=X(c==="ring"?"Ring Yield":"Quadrant Yield",!0,void 0,{stateKey:"regionYield",panel:d,render:a=>{const b=p(c);if(!b.length){a.appendChild(l("div",{fontSize:E.body,color:Y},"No positioned dies for this breakdown."));return}for(const{label:u,n:S,yieldPercent:N}of b)a.appendChild(xe(`${u} (N=${S})`,N))},control:d?()=>be([["ring","Ring"],["quadrant","Quadrant"]],c,a=>{s.regionMode=a;const b=buildRegionYieldPanelSection(e);b&&r.replaceWith(b)},d.ownerDocument,!0):void 0});return r}export function buildLotOverviewSection(e,t=[]){const o=l("div"),n=ve(e.perWafer.map(s=>s.summary.wafer));o.appendChild(J(n.lotId!==void 0?"Lot Summary":"Summary"));const i=We();i.appendChild(se(String(e.stats.waferCount),"Wafers"));const d=e.perWafer.map(s=>s.summary.stats.yieldPercent).filter(s=>s!==null);if(d.length){const s=d.reduce((p,c)=>p+c,0)/d.length;i.appendChild(se(`${s.toFixed(1)}%`,"Mean per-wafer yield"))}if(i.finish(),o.appendChild(i),t.length){const s=t.reduce((c,r)=>c+r.stats.analyzedDies,0),p=t.reduce((c,r)=>c+r.stats.excludedDies,0);(s||p)&&o.appendChild(Pe("Dies analysed",p?`${s.toLocaleString()} (${p.toLocaleString()} excluded)`:s.toLocaleString()))}return o}export function buildPerWaferYieldSection(e,t,o,n,i){const d=e.perWafer.map(f=>({waferIndex:f.waferIndex,label:me(t[f.waferIndex],f.waferIndex).replace(/\s*·\s*\d+(\.\d+)?%$/,""),yieldPct:f.summary.stats.yieldPercent})).filter(f=>f.yieldPct!==null);if(!d.length)return null;const s=Math.min(...d.map(f=>f.yieldPct)),p=Math.max(...d.map(f=>f.yieldPct)),c=s===p?"":` (${s.toFixed(1)}\u2013${p.toFixed(1)}%)`,r=[...d.map(f=>f.yieldPct)].sort((f,w)=>f-w),a=mt(r),b=oe(r,.25),u=oe(r,.75),S=d.length>=5?b-1.5*(u-b):-1/0,N=pe(n),A=f=>{const w=N.waferSort==="yield"?[...d].sort((m,x)=>m.yieldPct-x.yieldPct):d;for(const{waferIndex:m,label:x,yieldPct:C}of w){const k=C<S?`${x} \xB7 low outlier`:x,T=xe(k,C,void 0,void 0,a),M=i?.(m);M?.total&&H(T,M),h(T,m,x,C,M),f.appendChild(T)}},P=` \xB7 median ${a.toFixed(1)}%`,{outer:R}=X("Wafer Yield"+c+P,!0,void 0,{stateKey:"waferYield",panel:n,render:A,control:n?f=>be([["slot","Slot"],["yield","Yield"]],N.waferSort,w=>{N.waferSort=w,f()},n.ownerDocument,!0):void 0});return R;function H(f,w){const m=w.unusual?"unusual":w.notable?"notable":"info",x=l("span",{marginLeft:y.sm,flexShrink:"0",background:de(m),color:"#fff",borderRadius:_.container,padding:"0 5px",fontSize:E.body,fontWeight:"600"},`${w.total}`);x.setAttribute("aria-hidden","true"),ie(x,`${w.total} finding${w.total===1?"":"s"}`+(w.unusual?`, ${w.unusual} unusual`:"")+(w.notable?`, ${w.notable} notable`:"")),f.firstElementChild?.firstElementChild?.appendChild(x)}function h(f,w,m,x,C){o&&(f.style.cursor="pointer",f.style.borderRadius="4px",f.style.padding="2px 3px",f.style.marginLeft="-3px",f.style.marginRight="-3px",f.setAttribute("role","button"),f.setAttribute("aria-label",`${m}, ${x.toFixed(1)}% yield`+(C?.total?`, ${C.total} finding${C.total===1?"":"s"}${C.unusual?`, ${C.unusual} unusual`:""}`:"")+" \u2014 open wafer"),f.tabIndex=0,f.addEventListener("mouseenter",()=>{f.style.background=B.bgHover}),f.addEventListener("mouseleave",()=>{f.style.background=""}),f.addEventListener("focus",()=>{f.style.background=B.bgHover}),f.addEventListener("blur",()=>{f.style.background=""}),f.addEventListener("click",()=>o(w)),f.addEventListener("keydown",v=>{(v.key==="Enter"||v.key===" ")&&(v.preventDefault(),o(w))}))}}function wt(e){const t=[...e].sort((i,d)=>i-d),o=e.reduce((i,d)=>i+d,0)/e.length,n=e.reduce((i,d)=>i+(d-o)**2,0)/e.length;return{min:t[0],max:t[t.length-1],mean:o,count:e.length,stddev:Math.sqrt(n),median:oe(t,.5),q1:oe(t,.25),q3:oe(t,.75)}}function Ye(e,t){if(!e)return[];const o=e.waferMetadata??(e.perWaferMetadata?we(e.perWaferMetadata.map(n=>({metadata:n}))):void 0);return!o||!Object.keys(o).length?[]:it({waferMetadata:o,waferKeys:"identity",waferPlacement:"csv",reservedLabels:t}).columns}function Oe(e){return e?.populationLabel?[{key:"population",label:"Population",scope:"wafer",constant:e.populationLabel,get:()=>e.populationLabel,csvOnly:!0}]:[]}export function buildTestSection(e,t,o,n,i,d,s,p,c="full"){const r=e.filter(g=>!g.partial&&!g.edgeExcluded),a=new Map((n?.perTestStats??[]).map(g=>[g.testNumber,g])),b=new Map((n?.testSpecYield??[]).map(g=>[g.testNumber,g]));let u;if(t?.length?u=t.filter(Ge).map(g=>({testNumber:g.testNumber,name:g.name,unit:g.unit,limitLow:g.limitLow,limitHigh:g.limitHigh})):u=dt(r).map(F=>({testNumber:F,name:`Test ${F}`})),!u.length)return null;const S=u.filter(g=>r.some(F=>{const O=F.testValues?.[g.testNumber];return O!==void 0&&isFinite(O)}));if(!S.length)return null;const N=S.some(g=>g.limitLow!==void 0||g.limitHigh!==void 0),A=[];for(const g of S){const F=a.get(g.testNumber),O=F&&F.stddev!==void 0&&F.median!==void 0&&F.q1!==void 0&&F.q3!==void 0;let L;if(O){const $=F;L={testNumber:g.testNumber,min:$.min,max:$.max,mean:$.mean,count:$.count,stddev:$.stddev,median:$.median,q1:$.q1,q3:$.q3}}else{const $=r.map(D=>D.testValues?.[g.testNumber]).filter(D=>D!==void 0&&isFinite(D));if(!$.length)continue;L={testNumber:g.testNumber,...wt($)}}let I=null,z=0;if(g.limitLow!==void 0||g.limitHigh!==void 0){const $=b.get(g.testNumber);if($)({yieldPercent:I,totalDies:z}=$);else{const D=r.map(j=>j.testValues?.[g.testNumber]).filter(j=>j!==void 0&&isFinite(j)),Z=D.filter(j=>g.limitLow!==void 0&&j<g.limitLow||g.limitHigh!==void 0&&j>g.limitHigh).length;z=D.length,I=D.length>0?(D.length-Z)/D.length*100:null}}A.push({entry:g,stats:L,specYieldPct:I,specN:z})}if(!A.length)return null;const P=new Map;if(s?.length&&t?.length)for(const g of ct(s,t))g.hasSpec&&P.set(g.testNumber,g.ppk);const R=P.size>0,h=new Set(A.map(g=>g.stats.count)).size===1?A[0].stats.count:null,f=l("div"),w=l("div",{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:y.sm}),m=h!==null?` \xB7 N=${h.toLocaleString()}`:"",x=d?.populationLabel?`Test Values (${A.length}) \u2014 ${d.populationLabel}${m}`:`Test Values (${A.length})${m}`,C=J(x);C.style.marginBottom="0",w.appendChild(C);const v=document.createElement("button");v.type="button",v.textContent="Test values CSV",Object.assign(v.style,{...le("outlined")}),q(v),v.addEventListener("click",()=>{const g=["Test","Unit","N","Min","Q1","Median","Mean","Q3","Max","StdDev"];R&&g.push("Ppk");const F=A.some($=>$.specYieldPct!==null&&$.specN!==$.stats.count);N&&(g.push("LSL","USL","Spec Yield %"),F&&g.push("Spec Yield N"));const O=[...Ye(d,g),...Oe(d)],I=[[...O.map($=>$.label),...g].map(ce).join(",")],z=$=>ke($,void 0,"engineering");for(const{entry:$,stats:D,specYieldPct:Z,specN:j}of A){const ae=[...O.map(te=>te.constant??""),$.name,$.unit??"",String(D.count),z(D.min),z(D.q1),z(D.median),z(D.mean),z(D.q3),z(D.max),z(D.stddev)];if(R){const te=P.get($.testNumber);ae.push(te==null?"":te.toFixed(3))}N&&(ae.push($.limitLow!==void 0?z($.limitLow):"",$.limitHigh!==void 0?z($.limitHigh):"",Z!==null?Z.toFixed(1):""),F&&ae.push($.limitLow!==void 0||$.limitHigh!==void 0?String(j):"")),I.push(ae.map(ce).join(","))}De(I.join(`
2
+ `),"test-values.csv","text/csv",i)}),w.appendChild(v),f.appendChild(w);const k=l("table",{width:"100%",borderCollapse:"collapse",fontSize:E.body}),T=document.createElement("thead"),M=document.createElement("tr"),W=["Test"];h===null&&W.push("N"),c==="full"&&W.push("Min","Q1","Median"),W.push("Mean"),c==="full"&&W.push("Q3","Max","StdDev"),R&&W.push("Ppk"),c==="full"&&N&&W.push("LSL","USL"),N&&W.push("Spec yield");for(const g of W){const F=l("th",{textAlign:g==="Test"?"left":"right",fontWeight:"600",fontSize:E.meta,letterSpacing:re,textTransform:"uppercase",color:Y,padding:"3px 8px 5px",borderBottom:`1px solid ${B.menuBorder}`,whiteSpace:"nowrap"},g);M.appendChild(F)}T.appendChild(M),k.appendChild(T);const V=document.createElement("tbody");for(const{entry:g,stats:F,specYieldPct:O,specN:L}of A){const I=D=>ke(D,g.unit,o),z=document.createElement("tr"),$=(D,Z="right")=>{const j=l("td",{textAlign:Z,padding:`${y.xs} ${y.md}`,borderBottom:`1px solid ${B.menuBorder}`,color:B.text,whiteSpace:"nowrap"},D);z.appendChild(j)};if($(g.name,"left"),h===null&&$(`${F.count}`),c==="full"&&($(I(F.min)),$(I(F.q1)),$(I(F.median))),$(I(F.mean)),c==="full"&&($(I(F.q3)),$(I(F.max)),$(I(F.stddev))),R){const D=P.get(g.testNumber);$(D==null?"\u2014":D.toFixed(2))}c==="full"&&N&&($(g.limitLow!==void 0?I(g.limitLow):"\u2014"),$(g.limitHigh!==void 0?I(g.limitHigh):"\u2014")),N&&$(O!==null?h!==null&&L===h?`${O.toFixed(1)}%`:`${O.toFixed(1)}% (N=${L})`:"\u2014"),V.appendChild(z)}k.appendChild(V);const G=l("div",{overflowX:"auto"});if(G.appendChild(k),!p)return f.appendChild(G),f;w.remove();const{outer:U}=X(x,!0,void 0,{stateKey:"testValues",panel:p,render:g=>g.appendChild(G),control:()=>v});return U}export function buildFunctionalTestSection(e,t,o,n,i,d){const s=o??Ze(e,t);if(!s?.length)return null;const c=new Set(s.map(m=>m.totalDies)).size===1?s[0].totalDies:null,r=c!==null?` \xB7 N=${c.toLocaleString()}`:"",a=l("div"),b=l("div",{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:y.sm}),u=i?.populationLabel?`Functional Tests (${s.length}) \u2014 ${i.populationLabel}${r}`:`Functional Tests (${s.length})${r}`,S=J(u);S.style.marginBottom="0",b.appendChild(S);const N=document.createElement("button");N.type="button",N.textContent="Functional CSV",Object.assign(N.style,{...le("outlined")}),q(N),N.addEventListener("click",()=>{const m=["Test","N","Pass","Fail","Pass Rate %"],x=[...Ye(i,m),...Oe(i)],C=[[...x.map(v=>v.label),...m].map(ce).join(",")];for(const v of s)C.push([...x.map(k=>k.constant??""),v.label,String(v.totalDies),String(v.passDies),String(v.failDies),v.passRatePercent!==null?v.passRatePercent.toFixed(1):""].map(ce).join(","));De(C.join(`
3
+ `),"functional-tests.csv","text/csv",n)}),b.appendChild(N),a.appendChild(b);const A=l("table",{width:"100%",borderCollapse:"collapse",fontSize:E.body}),P=document.createElement("thead"),R=document.createElement("tr"),H=c===null?["Test","N","Pass","Fail","Pass rate"]:["Test","Pass","Fail","Pass rate"];for(const m of H)R.appendChild(l("th",{textAlign:m==="Test"?"left":"right",fontWeight:"700",fontSize:E.body,letterSpacing:re,textTransform:"uppercase",color:Y,padding:"3px 8px 5px",borderBottom:`1px solid ${B.menuBorder}`,whiteSpace:"nowrap"},m));P.appendChild(R),A.appendChild(P);const h=document.createElement("tbody");for(const m of s){const x=document.createElement("tr"),C=(v,k="right")=>{x.appendChild(l("td",{textAlign:k,padding:`${y.xs} ${y.md}`,borderBottom:`1px solid ${B.menuBorder}`,color:K,whiteSpace:"nowrap"},v))};C(m.label,"left"),c===null&&C(String(m.totalDies)),C(String(m.passDies)),C(String(m.failDies)),C(m.passRatePercent!==null?`${m.passRatePercent.toFixed(1)}%`:"\u2014"),h.appendChild(x)}A.appendChild(h);const f=l("div",{overflowX:"auto"});if(f.appendChild(A),!d)return a.appendChild(f),a;b.remove();const{outer:w}=X(u,!0,void 0,{stateKey:"functionalTests",panel:d,render:m=>m.appendChild(f),control:()=>N});return w}export function buildLotFunctionalSection(e,t,o,n,i){const d=o?.length?{perWaferMetadata:o.map(p=>p.wafer??{}),populationLabel:`${o.length} wafer${o.length===1?"":"s"} pooled`}:void 0,s=ut(o);return s?buildFunctionalTestSection(e,t,s,n,d,i):buildFunctionalTestSection(e,t,void 0,n,d,i)}const ee={unusual:0,notable:1,info:2};function ye(e){return l("span",{display:"inline-block",width:"7px",height:"7px",borderRadius:_.pill,background:de(e),flexShrink:"0"})}function _e(e,t){let o=e.summary;return t&&(o.startsWith(`${t} has `)?o=o.slice(t.length+5):o.startsWith(`${t} `)&&(o=o.slice(t.length+1))),o=ne(o),o.length?o[0].toUpperCase()+o.slice(1):o}export function buildFindingsSection(e,t,o,n,i=!1){if(!e.length)return null;const d=e.some(h=>h.severity==="unusual"||h.severity==="notable"),s=d?e.filter(h=>h.severity!=="info").length.toString():void 0,{outer:p,content:c}=i?(()=>{const h=l("div");return{outer:h,content:h}})():X(`Findings (${e.length})`,d,s);function r(h){return h.reduce((f,w)=>ee[w.severity]<ee[f]?w.severity:f,"info")}function a(h){const f=new Map;for(const m of h){const x=`${m.comparison.family}\0${m.comparison.left}`,C=f.get(x)??[];C.push(m),f.set(x,C)}const w=[...f.entries()].map(([m,x])=>{const C=[...x].sort((v,k)=>ee[v.severity]-ee[k.severity]);return{key:m,findings:C,worst:r(C)}});return w.sort((m,x)=>ee[m.worst]-ee[x.worst]),w}function b(h,f){const m={ring:"Ring",quadrant:"Quadrant",sector:"Sector","reticle-position":"Reticle","test-site":"Test site",cluster:"Cluster","edge-arc":"Edge arc",wafer:"Wafer"}[h]??h;return f.toLowerCase().startsWith(m.toLowerCase())?f:`${m}: ${f}`}const u=e.filter(h=>h.comparison.family==="spatial-pattern"),S=new Set([...u.flatMap(h=>h.relatedIds??[]),...e.flatMap(h=>h.absorbedIds??[])]),N=e.filter(h=>h.comparison.family!=="spatial-pattern"&&!S.has(h.id)),A=a(N);function P(h,f=!1,w){const m=n===h.id,x=document.createElement("button");return x.type="button",x.dataset.wmapFinding=h.id,x.textContent=_e(h,w),ie(x,h.summary),x.setAttribute("aria-current",m?"true":"false"),Object.assign(x.style,{border:`1px solid ${B.menuBorder}`,borderLeft:`3px solid ${de(h.severity)}`,background:m?B.bgActive:B.menuBg,borderRadius:_.container,padding:f?"6px 10px":"8px 10px",textAlign:"left",fontSize:f?"10px":"11px",fontWeight:m?"600":"400",color:B.text,cursor:"pointer",width:"100%",marginBottom:y.xs}),q(x,"bare"),x.addEventListener("click",()=>o(h,x)),x}const R=ne(tt(e)??"");if(R){const h=l("div",{background:B.bgActive,borderRadius:_.container,padding:`${y.md} ${y.lg}`,marginBottom:y.md,display:"flex",gap:y.md,alignItems:"flex-start"}),f=l("span",{flex:"1",fontSize:E.body,lineHeight:Q.base,color:B.text},R);h.appendChild(f);const w=l("button",{flexShrink:"0",border:"none",background:"none",fontSize:E.body,color:B.icon,cursor:"pointer",padding:"0",lineHeight:Q.base,whiteSpace:"nowrap"},"Detail \u25B8");w.type="button",q(w,"bare"),w.addEventListener("click",()=>{const m=Fe({title:"Findings Summary",onClose:()=>{},anchor:w}),x=l("p",{fontSize:"16px",lineHeight:Q.base,color:B.text,padding:`${y.xxl} ${y.xxxl} ${y.xxl}`,margin:"0",borderBottom:`1px solid ${B.menuBorder}`,flexShrink:"0"},R);m.contentWrap.appendChild(x);const C=l("div",{overflowY:"auto",padding:`${y.xxl} ${y.xxxl}`,flex:"1"}),v=(k,T)=>{const M=l("div",{display:"flex",alignItems:"center",gap:"7px",fontSize:E.sub,fontWeight:"600",color:K,marginTop:y.lg,marginBottom:y.xs});return M.appendChild(ye(k)),M.appendChild(l("span",{},T)),M};for(const k of u){C.appendChild(v(k.severity,k.comparison.left)),C.appendChild(l("div",{fontSize:E.body,color:B.text,padding:"4px 0 4px 15px",marginBottom:y.xxs},ne(k.summary)));const T=e.filter(M=>k.relatedIds?.includes(M.id));for(const M of T)C.appendChild(l("div",{fontSize:E.body,color:Y,padding:"2px 0 2px 23px",marginBottom:y.xxs},ne(M.summary)))}for(const k of A){const[T,M]=k.key.split("\0");C.appendChild(v(k.worst,b(T,M)));for(const W of k.findings)C.appendChild(l("div",{fontSize:E.body,color:B.text,padding:"4px 0 4px 15px",marginBottom:y.xxs},_e(W,M)))}m.contentWrap.appendChild(C),Object.assign(m.contentWrap.style,{flexDirection:"column",overflow:"hidden"})}),h.appendChild(w),c.appendChild(h)}let H=!0;for(const h of u){H||c.appendChild(l("div",{height:"1px",background:B.separator,margin:"4px 0"})),H=!1;const f=e.filter(v=>h.relatedIds?.includes(v.id)),w=f.length>0,m=l("div",{position:"relative",marginBottom:w?"2px":"4px"}),x=n===h.id,C=document.createElement("button");if(C.type="button",C.dataset.wmapFinding=h.id,Object.assign(C.style,{border:`1px solid ${B.menuBorder}`,borderLeft:`3px solid ${de(h.severity)}`,background:x?B.bgActive:B.menuBg,borderRadius:_.container,padding:"8px 32px 8px 10px",textAlign:"left",fontSize:E.body,fontWeight:x?"600":"500",color:B.text,cursor:"pointer",width:"100%"}),C.textContent=ne(h.summary),ie(C,h.summary),C.setAttribute("aria-current",x?"true":"false"),q(C,"bare"),C.addEventListener("click",()=>o(h,C)),m.appendChild(C),w){const v=l("div",{display:"none",paddingLeft:"12px",marginBottom:y.xs});for(const M of f)v.appendChild(P(M,!0));m.appendChild(v);let k=!1;const T=l("button",{position:"absolute",top:"50%",right:"8px",transform:"translateY(-50%)",border:"none",background:"none",fontSize:E.body,color:B.icon,cursor:"pointer",padding:`${y.xxs} ${y.xs}`,lineHeight:Q.none},"\u25B8");q(T,"bare"),T.type="button",ie(T),T.setAttribute("aria-label","Show supporting findings"),T.setAttribute("aria-expanded","false"),T.addEventListener("click",M=>{M.stopPropagation(),k=!k,v.style.display=k?"block":"none",T.textContent=k?"\u25BE":"\u25B8";const W=k?"Hide supporting findings":"Show supporting findings";T.setAttribute("aria-label",W),T.setAttribute("aria-expanded",String(k))}),m.appendChild(T)}c.appendChild(m)}for(const h of A){H||c.appendChild(l("div",{height:"1px",background:B.separator,margin:"4px 0"})),H=!1;const[f,w]=h.key.split("\0"),m=l("div",{display:"flex",alignItems:"center",gap:y.sm,fontSize:E.body,fontWeight:"600",color:K,margin:"2px 0 4px"});m.appendChild(ye(h.worst)),m.appendChild(l("span",{},b(f,w))),c.appendChild(m);for(const x of h.findings)c.appendChild(P(x,!1,w))}return p}const St=[{value:"",label:"All kinds"},{value:"yield",label:"Yield"},{value:"hardBin",label:"Hard bin"},{value:"softBin",label:"Soft bin"},{value:"test",label:"Test value"},{value:"functionalTest",label:"Functional test"},{value:"spatialPattern",label:"Spatial pattern"}],vt=[{value:"",label:"All regions"},{value:"ring",label:"Ring"},{value:"quadrant",label:"Quadrant"},{value:"reticle-position",label:"Reticle position"},{value:"test-site",label:"Test site"},{value:"wafer",label:"Wafer"},{value:"sector",label:"Sector"},{value:"cluster",label:"Cluster"},{value:"edge-arc",label:"Edge arc"},{value:"spatial-pattern",label:"Spatial pattern"}],$t=["unusual","notable","info"],kt={unusual:"Unusual",notable:"Notable",info:"Info"};function Bt(e,t,o){const n=l("div",{display:"flex",flexWrap:"wrap",alignItems:"center",gap:y.lg,marginBottom:y.lg,paddingBottom:"10px",borderBottom:`1px solid ${B.separator}`}),i={unusual:0,notable:0,info:0};for(const r of e)i[r.severity]++;const d=$t.filter(r=>i[r]>0),s=new Set(t.severity===void 0?d:Array.isArray(t.severity)?t.severity:[t.severity]),p=l("div",{display:"flex",gap:y.xs,flexWrap:"wrap"});for(const r of d){const a=document.createElement("button");a.type="button";const b=()=>{const u=s.has(r);a.setAttribute("aria-pressed",u?"true":"false"),Object.assign(a.style,{display:"inline-flex",alignItems:"center",gap:"5px",border:`1px solid ${B.menuBorder}`,borderRadius:_.pill,background:u?B.bgActive:"none",opacity:u?"1":"0.5",color:B.text,fontSize:E.body,padding:`${y.xxs} ${y.md}`,cursor:"pointer"}),a.dataset.on=u?"true":"false"};a.appendChild(ye(r)),a.appendChild(l("span",{},`${kt[r]} ${i[r]}`)),ie(a,()=>s.has(r)?"Click to hide these findings":"Click to show these findings"),b(),q(a,"bare"),a.addEventListener("click",()=>{s.has(r)?s.delete(r):s.add(r),t.severity=s.size===d.length?void 0:[...s],o()}),p.appendChild(a)}n.appendChild(p);const c=t.kind!==void 0||t.family!==void 0;return(e.length>=Lt||c)&&(n.appendChild(Be("Kind:",St,t.kind??"",r=>{t.kind=r||void 0,o()},{maxWidth:"130px"})),n.appendChild(Be("Region:",vt,t.family??"",r=>{t.family=r||void 0,o()},{maxWidth:"150px"}))),n}const Lt=8;function Nt(e,t){const o=l("div",{display:"flex",flexDirection:"column",gap:y.xs,padding:y.md,marginBottom:y.md,background:B.bgHover,borderRadius:_.control},void 0,t);if(o.appendChild(l("div",{fontSize:E.body,color:B.value},e.message,t)),e.detail&&o.appendChild(l("div",{fontSize:E.meta,color:Y},e.detail,t)),e.actionLabel&&e.onAction){const n=l("button",le("outlined"),e.actionLabel,t);n.type="button",n.style.alignSelf="flex-start",n.style.marginTop=y.xs,q(n),n.addEventListener("click",e.onAction),o.appendChild(n)}return o}export function buildFindingsSectionWithFilter(e,t,o,n,i,d,s){if(!e.findings.length&&!s)return null;const p=e.findings.some(N=>N.severity==="unusual"||N.severity==="notable"),c=p?e.findings.filter(N=>N.severity!=="info").length.toString():void 0,r=d?.ownerDocument??document,{outer:a,content:b}=X(`Findings (${e.findings.length})`,p||!!s,c,{stateKey:"findings",panel:d});if(s&&b.appendChild(Nt(s,r)),!e.findings.length)return a;b.appendChild(Bt(e.findings,n,i));const u=nt(e,n);if(!u.length)return b.appendChild(l("div",{color:Y,fontSize:E.body,textAlign:"center",padding:`${y.xxl} ${y.md}`},"No findings match the current filter.")),a;const S=buildFindingsSection(u,e,t,o,!0);return S&&b.appendChild(S),a}export function buildLotTestSection(e,t,o,n,i,d,s,p="full"){const c=n?.length?{perWaferMetadata:n.map(a=>a.wafer??{}),populationLabel:`${n.length} wafer${n.length===1?"":"s"} pooled`}:void 0;let r;if(n?.length&&n.every(a=>a.stats.perTestStats!==void 0)){const a=new Map;for(const b of n)for(const u of b.stats.perTestStats??[]){const S=a.get(u.testNumber);S?(S.n+=u.count,S.sum+=u.mean*u.count,S.min=Math.min(S.min,u.min),S.max=Math.max(S.max,u.max)):a.set(u.testNumber,{n:u.count,sum:u.mean*u.count,min:u.min,max:u.max})}r={perTestStats:[...a.entries()].map(([b,u])=>({testNumber:b,count:u.n,min:u.min,max:u.max,mean:u.sum/u.n}))}}if(n?.length&&n.every(a=>a.stats.testSpecYield!==void 0)){const a=new Map;for(const b of n)for(const u of b.stats.testSpecYield??[]){const S=a.get(u.testNumber);S?(S.passDies+=u.passDies,S.totalDies+=u.totalDies):a.set(u.testNumber,{passDies:u.passDies,totalDies:u.totalDies})}r={...r,testSpecYield:[...a.entries()].map(([b,u])=>({testNumber:b,totalDies:u.totalDies,yieldPercent:u.totalDies>0?u.passDies/u.totalDies*100:null}))}}return buildTestSection(e,t,o,r,i,c,d,s,p)}export function createSummaryPanelEl(e,t,o=document){const n=e==="top"||e==="bottom",i=l("div",{background:gt,color:B.text,fontVariantNumeric:"tabular-nums",border:Re,borderRadius:_.container,padding:y.xl,overflowY:"auto",overflowX:n?"auto":"hidden",flexShrink:"0",boxSizing:"border-box",fontFamily:E.family,fontSize:E.sub,boxShadow:Le.panel},void 0,o);return e==="right"&&(i.style.marginRight=t),e==="left"&&(i.style.marginLeft=t),e==="bottom"&&(i.style.marginBottom=t),n?(i.style.height="180px",i.style.width="100%"):(i.style.width="300px",i.style.maxHeight="100%"),i}export function wrapWithSummaryPanel(e,t,o){const n=o==="top"||o==="bottom",i=l("div",{display:"flex",flexDirection:n?"column":"row",gap:y.md,width:"100%",height:"100%",flex:"1 1 0",minHeight:"0",boxSizing:"border-box",alignItems:n?"flex-start":"stretch"});return e.style.flex="1 1 0",e.style.minWidth="0",e.style.minHeight="0",o==="right"||o==="bottom"?(i.appendChild(e),i.appendChild(t)):(i.appendChild(t),i.appendChild(e)),i}function je(e){return l("div",{fontSize:E.heading,fontWeight:"600",color:K,marginBottom:y.lg},e)}function fe(e,t){const o=l("button",le("outlined"),e);return o.type="button",q(o),o.addEventListener("click",t),o}function qe(...e){const t=e.filter(n=>!!n);if(!t.length)return null;const o=l("div",{display:"flex",flexWrap:"wrap",gap:y.sm,marginBottom:y.lg});for(const n of t)o.appendChild(n);return o}function Ve(e,t,o,n,i,d,s,p,c,r,a){const b=e.ownerDocument,u=Fe({title:"Die list",onClose:()=>{},anchor:e,ownerDocument:b});u.contentWrap.style.padding="14px 16px";const S=ft(t,o,{...s,title:n,onSaveText:p,waferMetadata:i,metadataFields:d,extraColumn:c,getWafer:r,ringCount:a,ownerDocument:b});S&&u.contentWrap.appendChild(S)}export function renderWaferSummaryContent(e,t){const o=e.scrollTop;e.innerHTML="";const{wafer:n,dies:i,yieldSummary:d,dataCoverage:s,hbinDefs:p,sbinDefs:c,testDefs:r,statsSummary:a,passBins:b=[1],ringCount:u=4,binColors:S,plotMode:N,fallbackFormat:A,onFindingClick:P,activeFindingId:R=null,findingsFilter:H,onFindingsFilterChange:h,findingsNotice:f,onSaveText:w,metadataFields:m,dieListOptions:x,metadataShownElsewhere:C}=t;e.appendChild(je("Wafer Summary"));const v=t.warnings??$e({statsSummary:a});v.length&&e.appendChild(ge(v,e.ownerDocument));const k=d&&s?fe("Summary report",()=>{Ee(Je({wafer:n,dies:i,yield:d,dataCoverage:s,hbinDefs:p,sbinDefs:c,testDefs:r,passBins:b,ringCount:u},a),{anchor:e})}):null,T=(x?.enabled??!0)&&i.length?fe("View die list",()=>{Ve(e,i,r,`Die list \u2014 ${i.length} dies`,n.metadata,m,x,w,void 0,()=>n,u)}):null,M=qe(k,T);M&&e.appendChild(M);const W=[],V=a?.stats.isLotStack?a.stats:void 0,G=V?.lotSize!==void 0?{lotSize:V.lotSize,aggrMethod:lt(V.aggregationMethod)}:void 0;C||W.push(buildMetadataInfoSection([{metadata:n.metadata??void 0}],G)),d&&s&&W.push(buildYieldSection(d,s,b)),a&&P&&H&&h&&W.push(buildFindingsSectionWithFilter(a,P,R,H,h,e,f)),W.push(buildBinBreakdownSection({dies:i,hbinDefs:p,sbinDefs:c,binColors:S,hardCounts:a?.stats.hardBinCounts,softCounts:a?.stats.softBinCounts,plotMode:N,passBins:b,panel:e})),W.push(buildRegionYieldPanelSection({diesByWafer:[i],allWafers:[n],ringCount:u,passBins:b,panel:e}));const U=n.metadata?{waferMetadata:n.metadata}:void 0;W.push(buildTestSection(i,r,A,a?.stats,w,U,[{dies:i}],e,"compact")),W.push(buildFunctionalTestSection(i,r,a?.stats.functionalYield,w,U,e));let g=!0;for(const F of W)F&&(g||e.appendChild(Ae()),g=!1,e.appendChild(F));e.appendChild(l("div",{height:"12px",flexShrink:"0"})),e.scrollTop=o}export function reportMapsFromItems(e,t,o){const n=[];return e.forEach((i,d)=>{!i?.wafer||!i.dies||n.push({...i,wafer:i.wafer,dies:i.dies,label:me(i,d),passBins:[...he(i,t)],ringCount:i.ringCount??o})}),n}export function renderLotSummaryContent(e,t){const o=e.scrollTop;e.innerHTML="";const{lotSummary:n,items:i,hbinDefs:d,sbinDefs:s,testDefs:p,passBins:c=[1],ringCount:r=4,binColors:a,plotMode:b,fallbackFormat:u,onFindingClick:S,activeFindingId:N=null,onWaferClick:A,findingsFilter:P,onFindingsFilterChange:R,findingsNotice:H,onSaveText:h,dieListOptions:f,findingsFor:w}=t;e.appendChild(je(`Summary \u2014 ${rt(ve(n.perWafer.map(L=>L.summary.wafer)))}`));const m=t.warnings??$e({lotStatsSummary:n});m.length&&e.appendChild(ge(m,e.ownerDocument));const x=fe("Summary report",()=>{Ee(et(reportMapsFromItems(i,c,r)),{anchor:e})}),C=[],v=[],k=[],T=[],M=[],W=new WeakMap,V=new WeakMap;for(let L=0;L<i.length;L++){const I=i[L];if(!I){v.push([]);continue}I.wafer&&(C.push(I.wafer),T.push(I.dies??[]),M.push(he(I,c)));const z=I.dies??[],$=me(I,L);for(const D of z)W.set(D,$),I.wafer&&V.set(D,I.wafer);v.push(z),k.push(...z)}const G=f?.enabled??!0?fe("View die list",()=>{k.length&&Ve(e,k,p,`Die list \u2014 ${k.length} dies across ${i.length} wafer${i.length===1?"":"s"}`,we(i.filter(L=>!!L).map(L=>({metadata:L.wafer?.metadata}))),i.find(L=>L?.metadataFields?.length)?.metadataFields,f,h,{label:"Wafer",get:L=>W.get(L)},L=>V.get(L),r)}):null,U=qe(x,G);U&&e.appendChild(U);const g=i.map(L=>L?.statsSummary).filter(L=>!!L),F=[buildLotOverviewSection(n,g)];S&&P&&R&&F.push(buildFindingsSectionWithFilter(n,S,N,P,R,e,H)),F.push(buildPerWaferYieldSection(n,i,A,e,w),buildBinBreakdownSection({dies:k,hbinDefs:d,sbinDefs:s,plotMode:b,passBins:c,panel:e,binColors:a??st(i.flatMap(L=>L?[{dies:L.dies??[],passBins:he(L,c)}]:[]),{hbinDefs:d,sbinDefs:s}).colors}),buildRegionYieldPanelSection({diesByWafer:T,allWafers:C,ringCount:r,passBins:L=>M[L],panel:e}),p?.length?buildLotTestSection(k,p,u,g,h,v.map(L=>({dies:L})),e,"compact"):null,p?.length?buildLotFunctionalSection(k,p,g,h,e):null);let O=!0;for(const L of F)L&&(O||e.appendChild(Ae()),O=!1,e.appendChild(L));e.appendChild(l("div",{height:"12px",flexShrink:"0"})),e.scrollTop=o}
@@ -42,14 +42,6 @@ export interface ToCanvasOptions {
42
42
  * zoom/pan. Also accepts a zoom-adjusted `snapDist` for hit testing.
43
43
  */
44
44
  viewport?: ViewportTransform;
45
- /** Currently highlighted bin (or metadata value) — drawn with an active indicator in the bin legend. */
46
- activeBin?: number | string;
47
- /** Bin legend row under the pointer — drawn with a background fill, which is
48
- * deliberately a different channel from `activeBin`'s accent border and bold
49
- * label so "selected" and "pointed at" never look the same. The legend is
50
- * canvas-drawn, so this is the only way it can answer the pointer at all;
51
- * a DOM `:hover` cannot reach it. */
52
- hoverBin?: number | string;
53
45
  /**
54
46
  * Format to use for unitless values outside the normal display range [0.1, 9999].
55
47
  * `'engineering'` (default): multiples-of-3 exponent notation (e.g. `12E-6`).
@@ -57,10 +49,6 @@ export interface ToCanvasOptions {
57
49
  * Values with a unit always use SI prefix regardless of this setting.
58
50
  */
59
51
  fallbackFormat?: 'si' | 'engineering';
60
- /** Extra space reserved at the top of the canvas in CSS pixels. Default 0. Used by renderWaferMap to prevent the floating toolbar from obscuring the wafer. */
61
- topClearance?: number;
62
- /** Minimum right-side reserve in CSS pixels. Ensures the wafer draw width stays stable across plot mode switches. */
63
- minRightReserve?: number;
64
52
  /** Named hard bin definitions — used to label the bin legend. */
65
53
  hbinDefs?: import('../renderer/buildWaferMap.js').BinDef[];
66
54
  /** Named soft bin definitions — used to label the bin legend. */
@@ -74,6 +62,24 @@ export interface ToCanvasOptions {
74
62
  */
75
63
  showTitle?: boolean;
76
64
  }
65
+ /**
66
+ * @internal What only `renderWaferMap` knows while it draws: the legend row it
67
+ * highlights, the one under the pointer, and the right-hand reserve that keeps the
68
+ * wafer the same size across plot modes. A direct `toCanvas` caller has no pointer
69
+ * or mode-switch state to pass, so these are not on `ToCanvasOptions`.
70
+ */
71
+ export interface MapCanvasOptions extends ToCanvasOptions {
72
+ /** Currently highlighted bin (or metadata value) — drawn with an active indicator in the bin legend. */
73
+ activeBin?: number | string;
74
+ /** Bin legend row under the pointer — drawn with a background fill, which is
75
+ * deliberately a different channel from `activeBin`'s accent border and bold
76
+ * label so "selected" and "pointed at" never look the same. The legend is
77
+ * canvas-drawn, so this is the only way it can answer the pointer at all;
78
+ * a DOM `:hover` cannot reach it. */
79
+ hoverBin?: number | string;
80
+ /** Minimum right-side reserve in CSS pixels. Ensures the wafer draw width stays stable across plot mode switches. */
81
+ minRightReserve?: number;
82
+ }
77
83
  /** Internal viewport state shared between toCanvas and renderWaferMap. */
78
84
  export interface ViewportTransform {
79
85
  originX: number;
@@ -119,5 +125,7 @@ export declare const BIN_LEGEND_ADAPT_FLOATING = 180;
119
125
  export declare const BIN_LEGEND_MIN_CANVAS_W = 150;
120
126
  export declare const BIN_LEGEND_MIN_CANVAS_H = 120;
121
127
  export declare function toCanvas(canvas: HTMLCanvasElement, view: View, options?: ToCanvasOptions): ToCanvasResult;
128
+ /** @internal `toCanvas` plus the interaction state `renderWaferMap` draws with. */
129
+ export declare function drawMapCanvas(canvas: HTMLCanvasElement, view: View, options?: MapCanvasOptions): ToCanvasResult;
122
130
  export { fmt, fmtColorbarAxis } from '../renderer/fmt.js';
123
131
  //# sourceMappingURL=toCanvas.d.ts.map
@@ -1 +1 @@
1
- import{fontPx as Ct}from"./toolbar.js";import{findTestDef as Re,buildMapTitle as Ce}from"../renderer/buildView.js";import{affineInvert as ze,affineVector as _e}from"../core/transforms.js";import{compareNatural as Je}from"../core/utils.js";import{resolveValueColorFn as Ze}from"../renderer/colorSchemes.js";import{NO_DATA_FILL as je}from"../renderer/colorMap.js";import{SPEC_PASS_FILL as Be,SPEC_FAIL_LOW as Qe,SPEC_FAIL_HIGH as Pe,contrastTextColor as We}from"../renderer/colorMap.js";import{fmt as De,fmtColorbarAxis as ve}from"../renderer/fmt.js";import{resolveCanvasTheme as to}from"./canvasTheme.js";import{hitGridDims as eo}from"./hitGrid.js";function Oe(m,e,I,M,h){m.moveTo(e,I+h*M),m.lineTo(e-M*.9,I-h*M*.6),m.lineTo(e+M*.9,I-h*M*.6),m.closePath()}const oo=new Set(["value","stackedValues","stackedBins","stackedSoftBins"]),no=new Set(["hardBin","softBin","metadata"]),Z=()=>`${Ct(-2)}px system-ui, sans-serif`,Fe=3,Gt=2,so=6,lo=20,io=()=>`600 ${Ct()}px system-ui, sans-serif`,Vt=()=>`${Ct(-1)}px system-ui, sans-serif`,ao=()=>`600 ${Ct(-1)}px system-ui, sans-serif`,Ut=128,co=()=>`${Ct(-2)}px system-ui, sans-serif`,Ie=4,D=17,w=11;export const BIN_LEGEND_W=110,BIN_LEGEND_W_COMPACT=64,BIN_LEGEND_ADAPT_COMPACT=280,BIN_LEGEND_ADAPT_FLOATING=180,BIN_LEGEND_MIN_CANVAS_W=150,BIN_LEGEND_MIN_CANVAS_H=120;const Kt=28,mt=5,ut=8,ro=15;export function toCanvas(m,e,I={}){const M=to(m.parentElement??m),{padding:h=16,showColorbar:H=!0,markFailingDies:X=!1,colorbarWidth:P=16,background:pt=M.background,legendPosition:j="default",legendOffset:xt,showAxes:Mt=!1,diePitchMm:V,viewport:q,activeBin:N,hoverBin:z,fallbackFormat:St,topClearance:Q=0,minRightReserve:ct,hbinDefs:yt,sbinDefs:st,metadataFields:bt,showTitle:rt=!0}=I,O=Math.floor(m.clientWidth||m.width),E=Math.floor(m.clientHeight||m.height),Lt=O>=BIN_LEGEND_MIN_CANVAS_W&&E>=BIN_LEGEND_MIN_CANVAS_H,kt=H&&Lt&&oo.has(e.plotMode)&&e.passFailDisplay==="off",ft=H&&Lt&&no.has(e.plotMode),tt=H&&Lt&&e.plotMode==="value"&&(e.passFailDisplay==="spec"&&e.specCounts!==void 0||e.passFailDisplay==="test"&&e.passFailCounts!==void 0),ht=ft||tt,_t=ft&&e.plotMode!=="metadata"&&e.binCounts?[...e.binCounts.entries()].sort(([o],[c])=>o-c):[],Bt=ft&&e.plotMode==="metadata"&&e.metadataCounts?[...e.metadataColorMap?.keys()??[...e.metadataCounts.keys()].sort(Je)].map(o=>[o,e.metadataCounts.get(o)??0]):[],et=[];if(tt&&e.passFailDisplay==="test"){const o=e.passFailCounts;et.push({key:-1,color:Be,label:"Pass",compactLabel:"Pass",count:o.pass,tooltip:`Pass \xB7 ${o.pass} dies`}),et.push({key:-2,color:Pe,label:"Fail",compactLabel:"Fail",count:o.fail,tooltip:`Fail \xB7 ${o.fail} dies`})}else if(tt){const o=e.specCounts,c=Re(e.testDefs,e.activeTest);et.push({key:-1,color:Be,label:"Pass",compactLabel:"Pass",count:o.pass,tooltip:`Pass \xB7 ${o.pass} dies`}),c?.limitHigh!==void 0&&et.push({key:-2,color:Pe,label:"Fail high",compactLabel:"Fail hi",count:o.failHigh,tooltip:`Fail high \xB7 ${o.failHigh} dies`}),c?.limitLow!==void 0&&et.push({key:-3,color:Qe,label:"Fail low",compactLabel:"Fail lo",count:o.failLow,tooltip:`Fail low \xB7 ${o.failLow} dies`})}const S=tt?et.length:e.plotMode==="metadata"?Bt.length:_t.length,L=(m.ownerDocument.defaultView??window).devicePixelRatio??1;if(O<=0||E<=0)return{hitTarget:{getDieAtPoint:()=>null},viewport:{originX:0,originY:0,ppm:1,snapDist:1},binLegendRows:[]};const $=j!=="default"?j:O<BIN_LEGEND_ADAPT_FLOATING?"floating":O<BIN_LEGEND_ADAPT_COMPACT?"compact":"default",re=$==="default"||$==="compact",fe=$==="left",zt=$==="bottom",Pt=$==="top",Wt=$==="floating",Dt=$==="compact"||$==="floating"?BIN_LEGEND_W_COMPACT:BIN_LEGEND_W,he=Math.floor((E-2*h)/D),de=S>he?he-1:S,ge=ht&&zt?de*D:0,Jt=ht&&Pt?de*D:0,Zt=e.plotMode==="stackedBins"||e.plotMode==="stackedSoftBins",jt=Re(e.testDefs,e.activeTest),Ne=Zt?"Count":jt?.name??(e.activeTest!=null?`Test ${e.activeTest}`:void 0),Ee=Zt?void 0:jt?.unit,[Ot,Ft]=e.valueRange,{tickFmt:Ye}=ve(Ft,Ne,Ee,St),It=e.allIntegerValues?o=>String(Math.round(o)):Ye;let Qt=0;if(kt){const o=m.getContext("2d");o.font=Z();const c=[It(Ot),It(Ft)];Ot<0&&c.push(It(-Math.max(Math.abs(Ot),Math.abs(Ft))));for(const s of c)Qt=Math.max(Qt,o.measureText(s).width)}const me=Math.max(lo,Math.ceil(Qt)+Fe+Gt+so-h),vt=kt?P+me+8:ht&&re?Dt:0,te=ht&&fe?Dt:0,ee=Mt?32:0,Nt=Mt?36:0,we=ct!=null?Math.max(vt,ct):vt,He=O-2*h-we-Nt-te,ue=E-2*h-ee-ge-Jt;m.width=Math.round(O*L),m.height=Math.round(E*L);const t=m.getContext("2d");t.scale(L,L),t.fillStyle=pt,t.fillRect(0,0,O,E);const G=e.hoverPoints;if(!G.length)return{hitTarget:{getDieAtPoint:()=>null},viewport:{originX:0,originY:0,ppm:1,snapDist:1},binLegendRows:[]};const Et=e.rectangles[0],oe=Et?Et.width/2:0,ne=Et?Et.height/2:0,Yt=e.dieBounds,pe=(Yt?.minX??0)-oe,Xe=(Yt?.maxX??0)+oe,$e=(Yt?.minY??0)-ne,xe=(Yt?.maxY??0)+ne,Me=Xe-pe,ye=xe-$e;let ot,nt,k;if(q)({originX:ot,originY:nt,ppm:k}=q);else{const c=e.notchDir,s=c&&c.y>.1?13:0,a=c&&c.y<-.1?13:0,r=c&&c.x<-.1?13:0,f=c&&c.x>.1?13:0,d=He-r-f,i=ue-Q-s-a;k=Math.min(d/Me,i/ye),ot=h+Nt+te+r+(d-Me*k)/2-pe*k,nt=h+Q+Jt+s+(i-ye*k)/2+xe*k}const wt=q?.snapDist??Math.max(oe,ne,1)*1.5,Ht=ot+e.waferCenter.x*k,Ge=nt-e.waferCenter.y*k,se=e.waferRadius*k,lt=o=>{const c=Math.abs(o-Ge);return c>=se?0:Math.sqrt(se*se-c*c)},it=(o,c,s,a,r,f,d=io(),i=M.text)=>{if(!o)return;t.save(),t.fillStyle=i,t.font=d,t.textAlign=a,t.textBaseline=r;const p=a==="right"?c-f:f-c;let l=o;if(p>8&&t.measureText(l).width>p){for(;l.length>1&&t.measureText(l+"\u2026").width>p;)l=l.slice(0,-1);l=l+"\u2026"}p>8&&t.fillText(l,c,s),t.restore()};if(t.save(),t.setTransform(k*L,0,0,-k*L,ot*L,nt*L),e.rectangles.length>0){const o=new Map;for(const s of e.rectangles){const a=String(s.fill);let r=o.get(a);r||(r=[],o.set(a,r)),r.push(s)}for(const[s,a]of o){t.beginPath();for(const r of a)t.rect(r.x-r.width/2,r.y-r.height/2,r.width,r.height);t.fillStyle=s,t.fill()}t.strokeStyle="rgba(0,0,0,0.18)",t.lineWidth=.5/(k*L),t.beginPath();for(const s of e.rectangles)t.rect(s.x-s.width/2,s.y-s.height/2,s.width,s.height);if(t.stroke(),X){const s=e.rectangles.filter(a=>a.binFail);if(s.length>0){const a=new Map;for(const r of s){const f=We(String(r.fill));let d=a.get(f);d||(d=[],a.set(f,d)),d.push(r)}t.save(),t.lineCap="butt";for(const[r,f]of a){t.strokeStyle=r,t.globalAlpha=.55,t.lineWidth=Math.max(.6/(k*L),Math.min(f[0].width,f[0].height)*.1);for(const d of f){const i=d.width/2,p=d.height/2,l=Math.max(1.6/(k*L),Math.min(d.width,d.height)/3);t.save(),t.beginPath(),t.rect(d.x-i,d.y-p,d.width,d.height),t.clip(),t.beginPath();for(let b=-(i+p);b<=i+p;b+=l)t.moveTo(d.x-i+b,d.y-p),t.lineTo(d.x-i+b+d.height,d.y+p);t.stroke(),t.restore()}}t.restore()}}const c=e.rectangles.filter(s=>s.specMark);if(c.length>0){const s=new Map;for(const r of c){const f=We(String(r.fill)),d=`${r.specMark}|${f}`;let i=s.get(d);i||(i=[],s.set(d,i)),i.push(r)}const a=2.5/(k*L);t.lineJoin="round";for(const[r,f]of s){const[d,i]=r.split("|"),p=i==="#000000"?"#ffffff":"#000000",l=d==="failHigh"?1:-1,b=Math.min(f[0].width,f[0].height),Y=Math.max(2.5/(k*L),b*.3);t.beginPath();for(const A of f)Oe(t,A.x,A.y,Y,l);t.strokeStyle=p,t.lineWidth=a,t.stroke(),t.fillStyle=i,t.fill()}}}for(const o of e.overlays){t.beginPath();for(const c of o.points){for(let s=0;s<c.length;s++)s===0?t.moveTo(c[s].x,c[s].y):t.lineTo(c[s].x,c[s].y);o.closed&&t.closePath()}o.fill&&!o.fill.startsWith("rgba(0,0,0,0)")&&(t.fillStyle=o.fill,t.fill()),o.kind==="ring-boundary"||o.kind==="quadrant-boundary"||o.kind==="reticle"?(t.strokeStyle="rgba(0,0,0,0.45)",t.lineWidth=3/(k*L),t.stroke(),t.strokeStyle="rgba(255,255,255,0.8)",t.lineWidth=1/(k*L),t.stroke()):(t.strokeStyle=o.lineColor,t.lineWidth=o.lineWidth/(k*L),t.stroke())}if(t.restore(),e.notchDir){const o=ot+e.waferCenter.x*k,c=nt-e.waferCenter.y*k,s=e.notchDir.x,a=-e.notchDir.y,r=e.waferRadius*k,f=4,d=9,i=5,p=o+s*(r+f),l=c+a*(r+f),b=p+s*d,Y=l+a*d,A={x:-a,y:s},W=h+Nt+te,U=O-h-vt,K=h+Q+Jt,C=E-h-ge-ee;t.save(),t.beginPath(),t.rect(W,K,U-W,C-K),t.clip(),t.beginPath(),t.moveTo(p,l),t.lineTo(b+A.x*i,Y+A.y*i),t.lineTo(b-A.x*i,Y-A.y*i),t.closePath(),t.fillStyle=M.text,t.fill(),t.restore()}t.save(),t.textAlign="center",t.textBaseline="middle";let be=0;if(e.rectangles.length>0){let o=1;for(const f of e.texts)f.role!=="indicator"&&f.text.length>o&&(o=f.text.length);const c=e.rectangles[0].width*k,s=e.rectangles[0].height*k,a=Math.min(c,s),r=c/o;be=Math.max(8,Math.min(64,Math.round(Math.min(a*.55,r*1.8))))}for(const o of e.texts){const c=ot+o.x*k,s=nt-o.y*k;t.font=`${o.role==="indicator"?o.fontSize:be}px system-ui, sans-serif`,t.fillStyle=o.color,t.fillText(o.text,c,s)}if(t.restore(),Mt&&fo(t,O,E,ot,nt,k,h,ee,Nt,V,e.gridToScreen,e.rotation,M),kt){const o=Ze(e.valueColorScheme,e.reverseValueScheme),c=me,s=ue-Q,a=Math.round(s*.75),r=h+Q+Math.round((s-a)/2),f=O-h-P-c,d=Ot,i=Ft,p=i-d,l=e.plotMode==="stackedSoftBins"?st:yt,{primary:b,secondary:Y}=rt?Ce(e,St,l):{primary:"",secondary:""};if(rt){const n=Math.max(r-6,h+Q+11),y=Ht+Math.max(lt(n),lt(n-12))+8;it(b,O-h,n,"right","bottom",y)}let A=r+a+4;const W=n=>Ht+Math.max(lt(n),lt(n+12))+8,U=e.logScale&&d>0?Math.log10(d):0,K=e.logScale&&i>0?Math.log10(i)-U:1,C=n=>e.logScale?(1-(Math.log10(n)-U)/K)*a:(1-(n-d)/p)*a;for(let n=0;n<Ut;n++){const y=1-n/(Ut-1),u=r+n/Ut*a,g=a/Ut+1;t.fillStyle=o(y),t.fillRect(f,u,P,g)}t.strokeStyle="rgba(0,0,0,0.25)",t.lineWidth=.5,t.strokeRect(f,r,P,a),t.fillStyle=M.text,t.font=Z(),t.textAlign="left",t.strokeStyle="rgba(0,0,0,0.35)",t.lineWidth=.5;const _=Fe,Rt=36,v=14,F=e.logScale&&K>0?ho(d,i,a,Rt,v,U,K):e.allIntegerValues?(()=>{const n=Math.max(1,qt(p*Rt/a)),y=[],u=Math.ceil(d/n)*n;for(let g=u;g<=i+n*1e-6;g+=n){const B=(1-(g-d)/p)*a;B>v&&B<a-v&&y.push(Math.round(g))}return y})():(()=>{const n=p>0?qt(p*Rt/a):0,y=[];if(n>0){const u=Math.ceil(d/n)*n;for(let g=u;g<=i+n*1e-6;g+=n){const B=(1-(g-d)/p)*a;B>v&&B<a-v&&y.push(g)}}return y})(),R=jt,x=Zt,T=It;t.textBaseline="middle";for(const n of F){const y=r+C(n);t.beginPath(),t.moveTo(f+P,y),t.lineTo(f+P+_,y),t.stroke(),t.fillText(T(n),f+P+_+Gt,y)}if(t.beginPath(),t.moveTo(f+P,r),t.lineTo(f+P+_,r),t.stroke(),t.textBaseline="top",t.fillText(T(i),f+P+_+Gt,r),t.beginPath(),t.moveTo(f+P,r+a),t.lineTo(f+P+_,r+a),t.stroke(),t.textBaseline="bottom",t.fillText(T(d),f+P+_+Gt,r+a),!x&&R&&(R.limitLow!==void 0||R.limitHigh!==void 0)){const n=[],y=e.colorbarRangeMode==="spec";for(const[u,g]of[[R.limitLow,"LSL"],[R.limitHigh,"USL"]]){if(u===void 0||e.logScale&&u<=0)continue;const B=C(u);!y&&(B<-v||B>a+v)||n.push({value:u,label:g,py:Math.max(0,Math.min(a,B))})}if(n.length>0){t.save(),t.font=Z(),t.textAlign="right",t.textBaseline="middle";for(const{py:u,label:g}of n){const B=r+u;y||(t.strokeStyle="rgba(255,255,255,0.85)",t.lineWidth=3,t.beginPath(),t.moveTo(f,B),t.lineTo(f+P,B),t.stroke(),t.strokeStyle="rgba(0,0,0,0.7)",t.lineWidth=1,t.beginPath(),t.moveTo(f,B),t.lineTo(f+P,B),t.stroke()),t.fillStyle=M.text,t.fillText(g,f-3,B);const dt=g==="USL"?-1:1,gt=4,Tt=f-3-t.measureText(g).width-gt-4;t.beginPath(),Oe(t,Tt,B,gt,dt),t.strokeStyle="#fff",t.lineWidth=2,t.lineJoin="round",t.stroke(),t.fillStyle=M.text,t.fill()}t.restore()}}if(!x){const n=e.logScale?"log\u2081\u2080":e.logScaleRequested?"linear \u2014 log n/a":null;n&&(t.save(),t.fillStyle=M.text,t.font=ao(),t.textAlign="right",t.textBaseline="top",t.fillText(n,O-h,A),t.restore(),A+=15)}rt&&Y&&it(Y,O-h,A,"right","top",W(A),Vt(),M.text)}const le=[];let J;if(ht){const o=$==="compact",c=e.plotMode==="softBin"?st:yt,s=c?new Map(c.map(l=>[l.bin,l])):null,a=e.plotMode==="softBin"?e.binColors.soft:e.binColors.hard,r=l=>a.get(l)??je,f=(l,b)=>{const Y=t.measureText(l).width,A=o?0:t.measureText(String(b)).width,W=w+mt+Y+(A?Kt:0);return{labelWidth:Y,countWidth:A,totalWidth:W}},d=bt?.find(l=>l.key===e.activeMetadataKey),i=tt?et.map(l=>{const b=o?l.compactLabel:l.label;return{key:l.key,color:l.color,count:l.count,label:b,tooltipLabel:l.tooltip,...f(b,l.count)}}):e.plotMode==="metadata"?Bt.map(([l,b])=>{const A=d?.values?.find(K=>K.value===l)?.label??l,W=o?l:A,U=e.metadataColorMap?.get(l)??"#d6d9dd";return{key:l,color:U,count:b,label:W,tooltipLabel:`${A} \xB7 ${b} dies`,...f(W,b)}}):_t.map(([l,b])=>{const Y=s?.get(l),A=Y?.name?`${l} \xB7 ${Y.name}`:`Bin ${l}`,W=o?String(l):A;return{key:l,color:r(l),count:b,label:W,tooltipLabel:`${A} \xB7 ${b} dies`,...f(W,b)}}),p=O-h*2;if(i.length>0){const l=Math.max(1,Math.floor((E-2*h)/D));let b=i.length,Y=1,A=b*D,W=[],U=0;const K=zt||Pt;if(K){const F=Math.max(...i.map(x=>x.totalWidth)),R=Math.max(1,Math.min(i.length,Math.floor((p+8)/(F+8))));for(let x=R;x>=1;x--){const T=Math.ceil(i.length/x);if(T>l)continue;const n=new Array(x).fill(0);for(let u=0;u<i.length;u++){const g=u%x;n[g]=Math.max(n[g],i[u].totalWidth)}if(n.reduce((u,g)=>u+g,0)+(x-1)*8<=p||x===1){Y=x,W=n,b=T,A=T*D;break}}}else b=Math.min(i.length,l),A=b*D,i.length>l&&(U=i.length-(l-1)),W=[Dt];let C,_;if(Wt){const F=Math.max(...i.map(g=>w+mt+t.measureText(g.label).width+Kt)),R=Math.ceil(F);W=[R];const x=rt?ro:0,T=R+ut*2,n=A+x+ut*2,y=xt?.x??0,u=xt?.y??0;C=Math.min(Math.max(O-h-T+y,h),O-h-T),_=Math.min(Math.max(E-h-n+u,h),E-h-n),J={x:C,y:_,w:T,h:n},t.save(),t.globalAlpha=.92,t.fillStyle=M.surface,t.fillRect(C,_,T,n),t.globalAlpha=1,t.strokeStyle=M.axisLine,t.lineWidth=1,t.strokeRect(C,_,T,n),t.restore(),C+=ut,_+=ut+x}else zt?(C=h,_=E-h-A):Pt?(C=h,_=h+Q):fe?(C=h+4,_=h+Math.round((E-2*h-A)/2)):(C=O-h-Dt+4,_=h+Math.round((E-2*h-A)/2));if(rt){const F=e.plotMode==="softBin"?st:yt,{primary:R,secondary:x}=Ce(e,St,F),T=6,n=g=>Ht-Math.max(lt(g),lt(g-12))-8,y=g=>re?O-h:n(g),u=Wt?J.y+J.h:_+A;if(Pt){const g=u+T;it(R,C,g,"left","top",Ht-Math.max(lt(g),lt(g+12))-8),x&&it(x,C,g+16,"left","top",n(g+16),Vt(),M.text)}else if(Wt)it(R,J.x+ut,J.y+ut,"left","top",J.x+J.w-ut),x&&it(x,J.x,u+T,"left","top",J.x+J.w,Vt(),M.text);else{const g=Math.max(_-T,h+Q+12);if(it(R,C,g,"left","bottom",y(g)),x){const B=u+T;it(x,C,B,"left","top",y(B),Vt(),M.text)}}}t.save(),t.font=Z();const Rt=K?8:0,v=(F,R)=>{if(t.measureText(F).width<=R)return F;let x=0,T=F.length;const n="\u2026",y=t.measureText(n).width;for(;x<T;){const u=x+T+1>>1;t.measureText(F.slice(0,u)).width+y<=R?x=u:T=u-1}return x===0?n:F.slice(0,x)+n};if(K){let F=0;for(let R=0;R<b;R++){let x=C;for(let T=0;T<Y;T++){const n=i[F++];if(!n)break;const y=n.key===N,u=!y&&n.key===z,g=x,B=x+w+mt,dt=_+R*D+D/2,gt=_+R*D+Math.round((D-w)/2),Tt=W[T]-w-mt-Kt;u&&(t.fillStyle=M.hoverRow,t.fillRect(x,_+R*D,W[T],D)),t.fillStyle=n.color,t.fillRect(g,gt,w,w),t.strokeStyle=y?M.accent:"rgba(0,0,0,0.25)",t.lineWidth=y?2:.75,t.strokeRect(g,gt,w,w),t.fillStyle=y?M.accent:M.text,t.font=y?`bold ${Z()}`:Z(),t.textAlign="left",t.textBaseline="middle",t.fillText(v(n.label,Tt),B,dt),t.fillStyle=M.textMuted,t.font=Z(),t.textAlign="right",t.fillText(String(n.count),x+W[T]-2,dt),le.push({bin:n.key,x,y:_+R*D,w:W[T],h:D,label:n.tooltipLabel}),x+=W[T]+Rt}}}else{const F=W[0],R=$!=="compact",x=F-w-mt-(R?Kt:0),T=C+F-2;let n=i;U>0&&(n=i.slice(0,l-1));let y=_;for(const u of n){const g=u.key===N,B=!g&&u.key===z,dt=C,gt=C+w+mt,Tt=y+D/2,Ae=y+Math.round((D-w)/2),qe=u.label;B&&(t.fillStyle=M.hoverRow,t.fillRect(C-3,y,F+3,D)),t.fillStyle=u.color,t.fillRect(dt,Ae,w,w),t.strokeStyle=g?M.accent:"rgba(0,0,0,0.25)",t.lineWidth=g?2:.75,t.strokeRect(dt,Ae,w,w),t.fillStyle=g?M.accent:M.text,t.font=g?`bold ${Z()}`:Z(),t.textAlign="left",t.textBaseline="middle",t.fillText(v(qe,x),gt,Tt),(R||Wt)&&(t.fillStyle=M.textMuted,t.font=Z(),t.textAlign="right",t.fillText(String(u.count),T,Tt)),le.push({bin:u.key,x:C,y,w:F,h:D,label:u.tooltipLabel}),y+=D}U>0&&(t.fillStyle=M.textMuted,t.font=Z(),t.textAlign="left",t.textBaseline="middle",t.fillText(`+ ${U} more`,C+w+mt,y+D/2))}}i.length>0&&t.restore()}const Ve={originX:ot,originY:nt,ppm:k,snapDist:wt},Te=e.rectangles[0]?.width??1,Se=e.rectangles[0]?.height??1,at=e.dieBounds,Xt=at?at.minX:G.length?Math.min(...G.map(o=>o.x)):0,$t=at?at.minY:G.length?Math.min(...G.map(o=>o.y)):0,Ue=at?at.maxX:G.length?Math.max(...G.map(o=>o.x)):1,Ke=at?at.maxY:G.length?Math.max(...G.map(o=>o.y)):1,{cellW:ie,cellH:ae,nCols:At,nRows:ce}=eo(Ue-Xt,Ke-$t,Te*1.5,Se*1.5,G.length),Le=Array.from({length:At*ce},()=>[]);for(let o=0;o<G.length;o++){const c=Math.floor((G[o].x-Xt)/ie),s=Math.floor((G[o].y-$t)/ae),a=Number.isFinite(c)?Math.max(0,Math.min(At-1,c)):0,r=Number.isFinite(s)?Math.max(0,Math.min(ce-1,s)):0;Le[r*At+a].push(o)}function ke(o,c,s){const a=Math.max(0,Math.floor((o-s-Xt)/ie)),r=Math.min(At-1,Math.floor((o+s-Xt)/ie)),f=Math.max(0,Math.floor((c-s-$t)/ae)),d=Math.min(ce-1,Math.floor((c+s-$t)/ae)),i=[];for(let p=f;p<=d;p++)for(let l=a;l<=r;l++)for(const b of Le[p*At+l])i.push(b);return i}return{hitTarget:{getDieAtPoint(o,c){const s=(o-ot)/k,a=(nt-c)/k,r=Math.max(Te,Se);for(const i of ke(s,a,r)){const p=e.rectangles[i];if(p&&Math.abs(s-p.x)<=p.width/2&&Math.abs(a-p.y)<=p.height/2)return e.dies[i]??null}let f=null,d=wt*wt;for(const i of ke(s,a,wt)){const p=G[i].x-s,l=G[i].y-a,b=p*p+l*l;b<d&&(d=b,f=e.dies[i]??null)}return f}},viewport:Ve,binLegendRows:le,legendBox:J}}function fo(m,e,I,M,h,H,X,P,pt,j,xt,Mt,V){m.save(),m.font=co(),m.fillStyle=V.text,m.strokeStyle=V.axisLine,m.lineWidth=.5;const q=I-P+4,N=X+pt-4,z=ze(xt),St=_e(z,1,0),Q=_e(z,0,1),ct=1e-9;function yt(S){return j?Math.abs(S.y)<ct&&Math.abs(S.x)>ct?{pitch:j.x,sign:Math.sign(S.x)}:Math.abs(S.x)<ct&&Math.abs(S.y)>ct?{pitch:j.y,sign:Math.sign(S.y)}:null:null}const st=yt(St),bt=yt(Q);function rt(S){return st?Math.round(S*st.sign/st.pitch):S}function O(S){return bt?Math.round(S*bt.sign/bt.pitch):S}function E(S){if(!S)return qt(50/H);const L=50/(S*H);return Math.max(1,Math.round(L))*S}const Lt=st?.pitch,kt=bt?.pitch,ft=E(Lt),tt=E(kt);m.textAlign="center",m.textBaseline="top";const ht=Math.ceil((X-M)/H/ft)*ft,_t=(e-X-M)/H;for(let S=ht;S<=_t;S+=ft){const L=M+S*H;if(L<X||L>e-X)continue;m.beginPath(),m.moveTo(L,q-Ie),m.lineTo(L,q),m.stroke();const $=j?String(rt(S)):De(S);m.fillText($,L,q+2)}m.textAlign="right",m.textBaseline="middle";const Bt=Math.ceil((h-(I-X))/H/tt)*tt,et=(h-X)/H;for(let S=Bt;S<=et;S+=tt){const L=h-S*H;if(L<X||L>I-X)continue;m.beginPath(),m.moveTo(N,L),m.lineTo(N+Ie,L),m.stroke();const $=j?String(O(S)):De(S);m.fillText($,N-2,L)}m.restore()}function qt(m){const e=Math.pow(10,Math.floor(Math.log10(m))),I=m/e;return(I<1.5?1:I<3.5?2:I<7.5?5:10)*e}function ho(m,e,I,M,h,H,X){const P=[],pt=X;if(pt<1){const V=qt((e-m)*M/I);if(V>0){const q=Math.ceil(m/V)*V;for(let N=q;N<=e+V*1e-6;N+=V){if(N<=m||N>=e)continue;const z=(1-(Math.log10(N)-H)/X)*I;z>h&&z<I-h&&P.push(N)}}return P}const j=pt<3?[1,2,5]:[1],xt=Math.floor(Math.log10(m)),Mt=Math.ceil(Math.log10(e));for(let V=xt;V<=Mt;V++)for(const q of j){const N=q*Math.pow(10,V);if(N<=m||N>=e)continue;const z=(1-(Math.log10(N)-H)/X)*I;z>h&&z<I-h&&P.push(N)}return P}export{fmt,fmtColorbarAxis}from"../renderer/fmt.js";
1
+ import{fontPx as Ct}from"./toolbar.js";import{findTestDef as Ce,buildMapTitle as _e}from"../renderer/buildView.js";import{sortBinsForDisplay as ve}from"../stats/binPareto.js";import{affineInvert as to,affineVector as Be}from"../core/transforms.js";import{compareNatural as eo}from"../core/utils.js";import{resolveValueColorFn as oo}from"../renderer/colorSchemes.js";import{NO_DATA_FILL as no}from"../renderer/colorMap.js";import{SPEC_PASS_FILL as Pe,SPEC_FAIL_LOW as so,SPEC_FAIL_HIGH as De,contrastTextColor as We}from"../renderer/colorMap.js";import{fmt as Ie,fmtColorbarAxis as lo}from"../renderer/fmt.js";import{resolveCanvasTheme as io}from"./canvasTheme.js";import{hitGridDims as ao}from"./hitGrid.js";function Fe(g,e,P,b,r){g.moveTo(e,P+r*b),g.lineTo(e-b*.9,P-r*b*.6),g.lineTo(e+b*.9,P-r*b*.6),g.closePath()}const co=new Set(["value","stackedValues","stackedBins","stackedSoftBins"]),ro=new Set(["hardBin","softBin","metadata"]),J=()=>`${Ct(-2)}px system-ui, sans-serif`,Ne=3,Ut=2,fo=6,ho=20,go=()=>`600 ${Ct()}px system-ui, sans-serif`,Kt=()=>`${Ct(-1)}px system-ui, sans-serif`,mo=()=>`600 ${Ct(-1)}px system-ui, sans-serif`,qt=128,uo=()=>`${Ct(-2)}px system-ui, sans-serif`,Oe=4,D=17,H=11;export const BIN_LEGEND_W=110,BIN_LEGEND_W_COMPACT=64,BIN_LEGEND_ADAPT_COMPACT=280,BIN_LEGEND_ADAPT_FLOATING=180,BIN_LEGEND_MIN_CANVAS_W=150,BIN_LEGEND_MIN_CANVAS_H=120;const zt=28,gt=5,ft=8,Ee=15,He=12,Ye=6;export function toCanvas(g,e,P={}){return drawMapCanvas(g,e,P)}export function drawMapCanvas(g,e,P={}){const b=io(g.parentElement??g),{padding:r=16,showColorbar:G=!0,markFailingDies:X=!1,colorbarWidth:B=16,background:mt=b.background,legendPosition:Z="default",legendOffset:ut,showAxes:pt=!1,diePitchMm:w,viewport:K,activeBin:O,hoverBin:q,fallbackFormat:Tt,minRightReserve:_t,hbinDefs:nt,sbinDefs:xt,metadataFields:Mt,showTitle:U=!0}=P,W=Math.floor(g.clientWidth||g.width),Y=Math.floor(g.clientHeight||g.height),yt=W>=BIN_LEGEND_MIN_CANVAS_W&&Y>=BIN_LEGEND_MIN_CANVAS_H,St=G&&yt&&co.has(e.plotMode)&&e.passFailDisplay==="off",Lt=G&&yt&&ro.has(e.plotMode),j=G&&yt&&e.plotMode==="value"&&(e.passFailDisplay==="spec"&&e.specCounts!==void 0||e.passFailDisplay==="test"&&e.passFailCounts!==void 0),Q=Lt||j,Bt=Lt&&e.plotMode!=="metadata"&&e.binCounts?ve(e.binCounts.entries(),e.plotMode==="softBin"?e.binColors.pass.soft:e.binColors.pass.hard):[],Pt=Lt&&e.plotMode==="metadata"&&e.metadataCounts?[...e.metadataColorMap?.keys()??[...e.metadataCounts.keys()].sort(eo)].map(o=>[o,e.metadataCounts.get(o)??0]):[],v=[];if(j&&e.passFailDisplay==="test"){const o=e.passFailCounts;v.push({key:-1,color:Pe,label:"Pass",compactLabel:"Pass",count:o.pass,tooltip:`Pass \xB7 ${o.pass} dies`}),v.push({key:-2,color:De,label:"Fail",compactLabel:"Fail",count:o.fail,tooltip:`Fail \xB7 ${o.fail} dies`})}else if(j){const o=e.specCounts,f=Ce(e.testDefs,e.activeTest);v.push({key:-1,color:Pe,label:"Pass",compactLabel:"Pass",count:o.pass,tooltip:`Pass \xB7 ${o.pass} dies`}),f?.limitHigh!==void 0&&v.push({key:-2,color:De,label:"Fail high",compactLabel:"Fail hi",count:o.failHigh,tooltip:`Fail high \xB7 ${o.failHigh} dies`}),f?.limitLow!==void 0&&v.push({key:-3,color:so,label:"Fail low",compactLabel:"Fail lo",count:o.failLow,tooltip:`Fail low \xB7 ${o.failLow} dies`})}const Dt=j?v.length:e.plotMode==="metadata"?Pt.length:Bt.length,M=(g.ownerDocument.defaultView??window).devicePixelRatio??1;if(W<=0||Y<=0)return{hitTarget:{getDieAtPoint:()=>null},viewport:{originX:0,originY:0,ppm:1,snapDist:1},binLegendRows:[]};const k=Z!=="default"?Z:W<BIN_LEGEND_ADAPT_FLOATING?"floating":W<BIN_LEGEND_ADAPT_COMPACT?"compact":"default",ht=k==="default"||k==="compact",he=k==="left",Zt=k==="bottom",kt=k==="top",At=k==="floating",Wt=k==="compact"||k==="floating"?BIN_LEGEND_W_COMPACT:BIN_LEGEND_W,de=Math.floor((Y-2*r)/D),ge=Dt>de?de-1:Dt,me=Q&&Zt?ge*D:0,jt=Q&&kt?ge*D:0,Qt=e.plotMode==="stackedBins"||e.plotMode==="stackedSoftBins",vt=Ce(e.testDefs,e.activeTest),Ge=Qt?"Count":vt?.name??(e.activeTest!=null?`Test ${e.activeTest}`:void 0),Xe=Qt?void 0:vt?.unit,[It,Ft]=e.valueRange,{tickFmt:$e}=lo(Ft,Ge,Xe,Tt),Nt=e.allIntegerValues?o=>String(Math.round(o)):$e;let te=0;if(St){const o=g.getContext("2d");o.font=J();const f=[Nt(It),Nt(Ft)];It<0&&f.push(Nt(-Math.max(Math.abs(It),Math.abs(Ft))));for(const s of f)te=Math.max(te,o.measureText(s).width)}const ue=Math.max(ho,Math.ceil(te)+Ne+Ut+fo-r),ee=St?B+ue+8:Q&&ht?Wt:0,oe=Q&&he?Wt:0,ne=pt?32:0,Ot=pt?36:0,we=_t!=null?Math.max(ee,_t):ee,Ve=W-2*r-we-Ot-oe,pe=Y-2*r-ne-me-jt;g.width=Math.round(W*M),g.height=Math.round(Y*M);const t=g.getContext("2d");t.scale(M,M),t.fillStyle=mt,t.fillRect(0,0,W,Y);const $=e.hoverPoints;if(!$.length)return{hitTarget:{getDieAtPoint:()=>null},viewport:{originX:0,originY:0,ppm:1,snapDist:1},binLegendRows:[]};const Et=e.rectangles[0],se=Et?Et.width/2:0,le=Et?Et.height/2:0,Ht=e.dieBounds,xe=(Ht?.minX??0)-se,Ue=(Ht?.maxX??0)+se,Ke=(Ht?.minY??0)-le,Me=(Ht?.maxY??0)+le,ye=Ue-xe,be=Me-Ke;let tt,et,A;if(K)({originX:tt,originY:et,ppm:A}=K);else{const f=e.notchDir,s=f&&f.y>.1?13:0,a=f&&f.y<-.1?13:0,c=f&&f.x<-.1?13:0,h=f&&f.x>.1?13:0,d=Ve-c-h,i=pe-s-a;A=Math.min(d/ye,i/be),tt=r+Ot+oe+c+(d-ye*A)/2-xe*A,et=r+jt+s+(i-be*A)/2+Me*A}const Yt=K?.snapDist??Math.max(se,le,1)*1.5,Gt=tt+e.waferCenter.x*A,qe=et-e.waferCenter.y*A,ie=e.waferRadius*A,st=o=>{const f=Math.abs(o-qe);return f>=ie?0:Math.sqrt(ie*ie-f*f)},lt=(o,f,s,a,c,h,d=go(),i=b.text)=>{if(!o)return;t.save(),t.fillStyle=i,t.font=d,t.textAlign=a,t.textBaseline=c;const y=a==="right"?f-h:h-f;let l=o;if(y>8&&t.measureText(l).width>y){for(;l.length>1&&t.measureText(l+"\u2026").width>y;)l=l.slice(0,-1);l=l+"\u2026"}y>8&&t.fillText(l,f,s),t.restore()};t.save(),t.setTransform(A*M,0,0,-A*M,tt*M,et*M);const dt=1/A,ze=1/(A*M);if(e.rectangles.length>0){const o=new Map;for(const s of e.rectangles){const a=String(s.fill);let c=o.get(a);c||(c=[],o.set(a,c)),c.push(s)}for(const[s,a]of o){t.beginPath();for(const c of a)t.rect(c.x-c.width/2,c.y-c.height/2,c.width,c.height);t.fillStyle=s,t.fill()}t.strokeStyle="rgba(0,0,0,0.18)",t.lineWidth=.5*ze,t.beginPath();for(const s of e.rectangles)t.rect(s.x-s.width/2,s.y-s.height/2,s.width,s.height);if(t.stroke(),X){const s=e.rectangles.filter(a=>a.binFail);if(s.length>0){const a=new Map;for(const c of s){const h=We(String(c.fill));let d=a.get(h);d||(d=[],a.set(h,d)),d.push(c)}t.save(),t.lineCap="butt";for(const[c,h]of a){t.strokeStyle=c,t.globalAlpha=.55,t.lineWidth=Math.max(.6*dt,Math.min(h[0].width,h[0].height)*.1);for(const d of h){const i=d.width/2,y=d.height/2,l=Math.max(1.6*dt,Math.min(d.width,d.height)/3);t.save(),t.beginPath(),t.rect(d.x-i,d.y-y,d.width,d.height),t.clip(),t.beginPath();for(let T=-(i+y);T<=i+y;T+=l)t.moveTo(d.x-i+T,d.y-y),t.lineTo(d.x-i+T+d.height,d.y+y);t.stroke(),t.restore()}}t.restore()}}const f=e.rectangles.filter(s=>s.specMark);if(f.length>0){const s=new Map;for(const c of f){const h=We(String(c.fill)),d=`${c.specMark}|${h}`;let i=s.get(d);i||(i=[],s.set(d,i)),i.push(c)}const a=2.5*dt;t.lineJoin="round";for(const[c,h]of s){const[d,i]=c.split("|"),y=i==="#000000"?"#ffffff":"#000000",l=d==="failHigh"?1:-1,T=Math.min(h[0].width,h[0].height),I=Math.max(2.5*dt,T*.3);t.beginPath();for(const R of h)Fe(t,R.x,R.y,I,l);t.strokeStyle=y,t.lineWidth=a,t.stroke(),t.fillStyle=i,t.fill()}}}for(const o of e.overlays){t.beginPath();for(const f of o.points){for(let s=0;s<f.length;s++)s===0?t.moveTo(f[s].x,f[s].y):t.lineTo(f[s].x,f[s].y);o.closed&&t.closePath()}o.fill&&!o.fill.startsWith("rgba(0,0,0,0)")&&(t.fillStyle=o.fill,t.fill()),o.kind==="ring-boundary"||o.kind==="quadrant-boundary"||o.kind==="reticle"?(t.strokeStyle="rgba(0,0,0,0.45)",t.lineWidth=3*dt,t.stroke(),t.strokeStyle="rgba(255,255,255,0.8)",t.lineWidth=1*dt,t.stroke()):(t.strokeStyle=o.lineColor,t.lineWidth=o.lineWidth*dt,t.stroke())}if(t.restore(),e.notchDir){const o=tt+e.waferCenter.x*A,f=et-e.waferCenter.y*A,s=e.notchDir.x,a=-e.notchDir.y,c=e.waferRadius*A,h=4,d=9,i=5,y=o+s*(c+h),l=f+a*(c+h),T=y+s*d,I=l+a*d,R={x:-a,y:s},F=r+Ot+oe,E=W-r-ee,V=r+jt,at=Y-r-me-ne;t.save(),t.beginPath(),t.rect(F,V,E-F,at-V),t.clip(),t.beginPath(),t.moveTo(y,l),t.lineTo(T+R.x*i,I+R.y*i),t.lineTo(T-R.x*i,I-R.y*i),t.closePath(),t.fillStyle=b.text,t.fill(),t.restore()}t.save(),t.textAlign="center",t.textBaseline="middle";let Te=0;if(e.rectangles.length>0){let o=1;for(const h of e.texts)h.role!=="indicator"&&h.text.length>o&&(o=h.text.length);const f=e.rectangles[0].width*A,s=e.rectangles[0].height*A,a=Math.min(f,s),c=f/o;Te=Math.max(8,Math.min(64,Math.round(Math.min(a*.55,c*1.8))))}for(const o of e.texts){const f=tt+o.x*A,s=et-o.y*A;t.font=`${o.role==="indicator"?o.fontSize:Te}px system-ui, sans-serif`,t.fillStyle=o.color,t.fillText(o.text,f,s)}if(t.restore(),pt&&po(t,W,Y,tt,et,A,r,ne,Ot,w,e.gridToScreen,e.rotation,b),St){const o=oo(e.valueColorScheme,e.reverseValueScheme),f=ue,s=pe,a=Math.round(s*.75),c=r+Math.round((s-a)/2),h=W-r-B-f,d=It,i=Ft,y=i-d,l=e.plotMode==="stackedSoftBins"?xt:nt,{primary:T,secondary:I}=U?_e(e,Tt,l):{primary:"",secondary:""};if(U){const n=Math.max(c-6,r+11),m=Gt+Math.max(st(n),st(n-12))+8;lt(T,W-r,n,"right","bottom",m)}let R=c+a+4;const F=n=>Gt+Math.max(st(n),st(n+12))+8,E=e.logScale&&d>0?Math.log10(d):0,V=e.logScale&&i>0?Math.log10(i)-E:1,at=n=>e.logScale?(1-(Math.log10(n)-E)/V)*a:(1-(n-d)/y)*a;for(let n=0;n<qt;n++){const m=1-n/(qt-1),S=c+n/qt*a,p=a/qt+1;t.fillStyle=o(m),t.fillRect(h,S,B,p)}t.strokeStyle="rgba(0,0,0,0.25)",t.lineWidth=.5,t.strokeRect(h,c,B,a),t.fillStyle=b.text,t.font=J(),t.textAlign="left",t.strokeStyle="rgba(0,0,0,0.35)",t.lineWidth=.5;const L=Ne,N=36,ot=14,wt=e.logScale&&V>0?xo(d,i,a,N,ot,E,V):e.allIntegerValues?(()=>{const n=Math.max(1,Jt(y*N/a)),m=[],S=Math.ceil(d/n)*n;for(let p=S;p<=i+n*1e-6;p+=n){const u=(1-(p-d)/y)*a;u>ot&&u<a-ot&&m.push(Math.round(p))}return m})():(()=>{const n=y>0?Jt(y*N/a):0,m=[];if(n>0){const S=Math.ceil(d/n)*n;for(let p=S;p<=i+n*1e-6;p+=n){const u=(1-(p-d)/y)*a;u>ot&&u<a-ot&&m.push(p)}}return m})(),C=vt,_=Qt,x=Nt;t.textBaseline="middle";for(const n of wt){const m=c+at(n);t.beginPath(),t.moveTo(h+B,m),t.lineTo(h+B+L,m),t.stroke(),t.fillText(x(n),h+B+L+Ut,m)}if(t.beginPath(),t.moveTo(h+B,c),t.lineTo(h+B+L,c),t.stroke(),t.textBaseline="top",t.fillText(x(i),h+B+L+Ut,c),t.beginPath(),t.moveTo(h+B,c+a),t.lineTo(h+B+L,c+a),t.stroke(),t.textBaseline="bottom",t.fillText(x(d),h+B+L+Ut,c+a),!_&&C&&(C.limitLow!==void 0||C.limitHigh!==void 0)){const n=[],m=e.colorbarRangeMode==="spec";for(const[S,p]of[[C.limitLow,"LSL"],[C.limitHigh,"USL"]]){if(S===void 0||e.logScale&&S<=0)continue;const u=at(S);!m&&(u<-ot||u>a+ot)||n.push({value:S,label:p,py:Math.max(0,Math.min(a,u))})}if(n.length>0){t.save(),t.font=J(),t.textAlign="right",t.textBaseline="middle";for(const{py:S,label:p}of n){const u=c+S;m||(t.strokeStyle="rgba(255,255,255,0.85)",t.lineWidth=3,t.beginPath(),t.moveTo(h,u),t.lineTo(h+B,u),t.stroke(),t.strokeStyle="rgba(0,0,0,0.7)",t.lineWidth=1,t.beginPath(),t.moveTo(h,u),t.lineTo(h+B,u),t.stroke()),t.fillStyle=b.text,t.fillText(p,h-3,u);const ct=p==="USL"?-1:1,rt=4,bt=h-3-t.measureText(p).width-rt-4;t.beginPath(),Fe(t,bt,u,rt,ct),t.strokeStyle="#fff",t.lineWidth=2,t.lineJoin="round",t.stroke(),t.fillStyle=b.text,t.fill()}t.restore()}}if(!_){const n=e.logScale?"log\u2081\u2080":e.logScaleRequested?"linear \u2014 log n/a":null;n&&(t.save(),t.fillStyle=b.text,t.font=mo(),t.textAlign="right",t.textBaseline="top",t.fillText(n,W-r,R),t.restore(),R+=15)}U&&I&&lt(I,W-r,R,"right","top",F(R),Kt(),b.text)}const ae=[];let z;if(Q){const o=k==="compact",f=e.plotMode==="softBin"?xt:nt,s=f?new Map(f.map(l=>[l.bin,l])):null,a=e.plotMode==="softBin"?e.binColors.soft:e.binColors.hard,c=l=>a.get(l)??no,h=(l,T)=>{const I=t.measureText(l).width,R=o?0:t.measureText(String(T)).width,F=H+gt+I+(R?zt:0);return{labelWidth:I,countWidth:R,totalWidth:F}},d=Mt?.find(l=>l.key===e.activeMetadataKey),i=j?v.map(l=>{const T=o?l.compactLabel:l.label;return{key:l.key,color:l.color,count:l.count,label:T,tooltipLabel:l.tooltip,...h(T,l.count)}}):e.plotMode==="metadata"?Pt.map(([l,T])=>{const R=d?.values?.find(V=>V.value===l)?.label??l,F=o?l:R,E=e.metadataColorMap?.get(l)??"#d6d9dd";return{key:l,color:E,count:T,label:F,tooltipLabel:`${R} \xB7 ${T} dies`,...h(F,T)}}):Bt.map(([l,T])=>{const I=s?.get(l),R=I?.name?`${l} \xB7 ${I.name}`:`Bin ${l}`,F=o?String(l):R;return{key:l,color:c(l),count:T,label:F,tooltipLabel:`${R} \xB7 ${T} dies`,...h(F,T)}}),y=W-r*2;if(i.length>0){const l=At?ft*2+(U?Ee:0):U&&!kt?He+Ye:0,T=Math.max(1,Math.floor((Y-2*r-l)/D));let I=i.length,R=1,F=I*D,E=[],V=0;const at=Zt||kt;if(at){const C=Math.max(...i.map(x=>x.totalWidth)),_=Math.max(1,Math.min(i.length,Math.floor((y+8)/(C+8))));for(let x=_;x>=1;x--){const n=Math.ceil(i.length/x);if(n>T)continue;const m=new Array(x).fill(0);for(let p=0;p<i.length;p++){const u=p%x;m[u]=Math.max(m[u],i[p].totalWidth)}if(m.reduce((p,u)=>p+u,0)+(x-1)*8<=y||x===1){R=x,E=m,I=n,F=n*D;break}}}else I=Math.min(i.length,T),F=I*D,i.length>T&&(V=i.length-(T-1)),E=[Wt];let L,N;if(At){const C=Math.max(...i.map(u=>H+gt+t.measureText(u.label).width+zt)),_=Math.ceil(C);E=[_];const x=U?Ee:0,n=_+ft*2,m=F+x+ft*2,S=ut?.x??0,p=ut?.y??0;L=Math.min(Math.max(W-r-n+S,r),W-r-n),N=Math.min(Math.max(Y-r-m+p,r),Y-r-m),z={x:L,y:N,w:n,h:m},t.save(),t.globalAlpha=.92,t.fillStyle=b.surface,t.fillRect(L,N,n,m),t.globalAlpha=1,t.strokeStyle=b.axisLine,t.lineWidth=1,t.strokeRect(L,N,n,m),t.restore(),L+=ft,N+=ft+x}else Zt?(L=r,N=Y-r-F):kt?(L=r,N=r):he?(L=r+4,N=Math.max(r+Math.round((Y-2*r-F)/2),r+l)):(L=W-r-Wt+4,N=Math.max(r+Math.round((Y-2*r-F)/2),r+l));if(U){const C=e.plotMode==="softBin"?xt:nt,{primary:_,secondary:x}=_e(e,Tt,C),n=Ye,m=u=>Gt-Math.max(st(u),st(u-12))-8,S=u=>ht?W-r:m(u),p=At?z.y+z.h:N+F;if(kt){const u=p+n;lt(_,L,u,"left","top",Gt-Math.max(st(u),st(u+12))-8),x&&lt(x,L,u+16,"left","top",m(u+16),Kt(),b.text)}else if(At)lt(_,z.x+ft,z.y+ft,"left","top",z.x+z.w-ft),x&&lt(x,z.x,p+n,"left","top",z.x+z.w,Kt(),b.text);else{const u=Math.max(N-n,r+He);if(lt(_,L,u,"left","bottom",S(u)),x){const ct=p+n;lt(x,L,ct,"left","top",S(ct),Kt(),b.text)}}}t.save(),t.font=J();const ot=at?8:0,wt=(C,_)=>{if(t.measureText(C).width<=_)return C;let x=0,n=C.length;const m="\u2026",S=t.measureText(m).width;for(;x<n;){const p=x+n+1>>1;t.measureText(C.slice(0,p)).width+S<=_?x=p:n=p-1}return x===0?m:C.slice(0,x)+m};if(at){let C=0;for(let _=0;_<I;_++){let x=L;for(let n=0;n<R;n++){const m=i[C++];if(!m)break;const S=m.key===O,p=!S&&m.key===q,u=x,ct=x+H+gt,rt=N+_*D+D/2,bt=N+_*D+Math.round((D-H)/2),Vt=E[n]-H-gt-zt;p&&(t.fillStyle=b.hoverRow,t.fillRect(x,N+_*D,E[n],D)),t.fillStyle=m.color,t.fillRect(u,bt,H,H),t.strokeStyle=S?b.accent:"rgba(0,0,0,0.25)",t.lineWidth=S?2:.75,t.strokeRect(u,bt,H,H),t.fillStyle=S?b.accent:b.text,t.font=S?`bold ${J()}`:J(),t.textAlign="left",t.textBaseline="middle",t.fillText(wt(m.label,Vt),ct,rt),t.fillStyle=b.textMuted,t.font=J(),t.textAlign="right",t.fillText(String(m.count),x+E[n]-2,rt),ae.push({bin:m.key,x,y:N+_*D,w:E[n],h:D,label:m.tooltipLabel}),x+=E[n]+ot}}}else{const C=E[0],_=k!=="compact",x=C-H-gt-(_?zt:0),n=L+C-2;let m=i;V>0&&(m=i.slice(0,T-1));let S=N;for(const p of m){const u=p.key===O,ct=!u&&p.key===q,rt=L,bt=L+H+gt,Vt=S+D/2,Re=S+Math.round((D-H)/2),Qe=p.label;ct&&(t.fillStyle=b.hoverRow,t.fillRect(L-3,S,C+3,D)),t.fillStyle=p.color,t.fillRect(rt,Re,H,H),t.strokeStyle=u?b.accent:"rgba(0,0,0,0.25)",t.lineWidth=u?2:.75,t.strokeRect(rt,Re,H,H),t.fillStyle=u?b.accent:b.text,t.font=u?`bold ${J()}`:J(),t.textAlign="left",t.textBaseline="middle",t.fillText(wt(Qe,x),bt,Vt),(_||At)&&(t.fillStyle=b.textMuted,t.font=J(),t.textAlign="right",t.fillText(String(p.count),n,Vt)),ae.push({bin:p.key,x:L,y:S,w:C,h:D,label:p.tooltipLabel}),S+=D}V>0&&(t.fillStyle=b.textMuted,t.font=J(),t.textAlign="left",t.textBaseline="middle",t.fillText(`+ ${V} more`,L+H+gt,S+D/2))}}i.length>0&&t.restore()}const Je={originX:tt,originY:et,ppm:A,snapDist:Yt},Se=e.rectangles[0]?.width??1,Le=e.rectangles[0]?.height??1,it=e.dieBounds,Xt=it?it.minX:$.length?Math.min(...$.map(o=>o.x)):0,$t=it?it.minY:$.length?Math.min(...$.map(o=>o.y)):0,Ze=it?it.maxX:$.length?Math.max(...$.map(o=>o.x)):1,je=it?it.maxY:$.length?Math.max(...$.map(o=>o.y)):1,{cellW:ce,cellH:re,nCols:Rt,nRows:fe}=ao(Ze-Xt,je-$t,Se*1.5,Le*1.5,$.length),ke=Array.from({length:Rt*fe},()=>[]);for(let o=0;o<$.length;o++){const f=Math.floor(($[o].x-Xt)/ce),s=Math.floor(($[o].y-$t)/re),a=Number.isFinite(f)?Math.max(0,Math.min(Rt-1,f)):0,c=Number.isFinite(s)?Math.max(0,Math.min(fe-1,s)):0;ke[c*Rt+a].push(o)}function Ae(o,f,s){const a=Math.max(0,Math.floor((o-s-Xt)/ce)),c=Math.min(Rt-1,Math.floor((o+s-Xt)/ce)),h=Math.max(0,Math.floor((f-s-$t)/re)),d=Math.min(fe-1,Math.floor((f+s-$t)/re)),i=[];for(let y=h;y<=d;y++)for(let l=a;l<=c;l++)for(const T of ke[y*Rt+l])i.push(T);return i}return{hitTarget:{getDieAtPoint(o,f){const s=(o-tt)/A,a=(et-f)/A,c=Math.max(Se,Le);for(const i of Ae(s,a,c)){const y=e.rectangles[i];if(y&&Math.abs(s-y.x)<=y.width/2&&Math.abs(a-y.y)<=y.height/2)return e.dies[i]??null}let h=null,d=Yt*Yt;for(const i of Ae(s,a,Yt)){const y=$[i].x-s,l=$[i].y-a,T=y*y+l*l;T<d&&(d=T,h=e.dies[i]??null)}return h}},viewport:Je,binLegendRows:ae,legendBox:z}}function po(g,e,P,b,r,G,X,B,mt,Z,ut,pt,w){g.save(),g.font=uo(),g.fillStyle=w.text,g.strokeStyle=w.axisLine,g.lineWidth=.5;const K=P-B+4,O=X+mt-4,q=to(ut),Tt=Be(q,1,0),_t=Be(q,0,1),nt=1e-9;function xt(M){return Z?Math.abs(M.y)<nt&&Math.abs(M.x)>nt?{pitch:Z.x,sign:Math.sign(M.x)}:Math.abs(M.x)<nt&&Math.abs(M.y)>nt?{pitch:Z.y,sign:Math.sign(M.y)}:null:null}const Mt=xt(Tt),U=xt(_t);function W(M){return Mt?Math.round(M*Mt.sign/Mt.pitch):M}function Y(M){return U?Math.round(M*U.sign/U.pitch):M}function yt(M){if(!M)return Jt(50/G);const k=50/(M*G);return Math.max(1,Math.round(k))*M}const St=Mt?.pitch,Lt=U?.pitch,j=yt(St),Q=yt(Lt);g.textAlign="center",g.textBaseline="top";const Bt=Math.ceil((X-b)/G/j)*j,Pt=(e-X-b)/G;for(let M=Bt;M<=Pt;M+=j){const k=b+M*G;if(k<X||k>e-X)continue;g.beginPath(),g.moveTo(k,K-Oe),g.lineTo(k,K),g.stroke();const ht=Z?String(W(M)):Ie(M);g.fillText(ht,k,K+2)}g.textAlign="right",g.textBaseline="middle";const v=Math.ceil((r-(P-X))/G/Q)*Q,Dt=(r-X)/G;for(let M=v;M<=Dt;M+=Q){const k=r-M*G;if(k<X||k>P-X)continue;g.beginPath(),g.moveTo(O,k),g.lineTo(O+Oe,k),g.stroke();const ht=Z?String(Y(M)):Ie(M);g.fillText(ht,O-2,k)}g.restore()}function Jt(g){const e=Math.pow(10,Math.floor(Math.log10(g))),P=g/e;return(P<1.5?1:P<3.5?2:P<7.5?5:10)*e}function xo(g,e,P,b,r,G,X){const B=[],mt=X;if(mt<1){const w=Jt((e-g)*b/P);if(w>0){const K=Math.ceil(g/w)*w;for(let O=K;O<=e+w*1e-6;O+=w){if(O<=g||O>=e)continue;const q=(1-(Math.log10(O)-G)/X)*P;q>r&&q<P-r&&B.push(O)}}return B}const Z=mt<3?[1,2,5]:[1],ut=Math.floor(Math.log10(g)),pt=Math.ceil(Math.log10(e));for(let w=ut;w<=pt;w++)for(const K of Z){const O=K*Math.pow(10,w);if(O<=g||O>=e)continue;const q=(1-(Math.log10(O)-G)/X)*P;q>r&&q<P-r&&B.push(O)}return B}export{fmt,fmtColorbarAxis}from"../renderer/fmt.js";
@@ -320,6 +320,12 @@ export type SaveImageHandler = (blob: Blob, suggestedName: string) => void | Pro
320
320
  * @param onSaveImage optional host hook; when present, bypasses `<a download>`
321
321
  */
322
322
  export declare function saveImageBlob(blob: Blob, filename: string, onSaveImage?: SaveImageHandler): void;
323
+ /**
324
+ * The browser's default save: a `<a download>` click. The one copy, used when
325
+ * no host hook is supplied — by `saveImageBlob`, `saveTextFile`, and the
326
+ * export-naming wrappers in exportName.ts, which must fall back to it too.
327
+ */
328
+ export declare function downloadBlob(blob: Blob, filename: string): void;
323
329
  /**
324
330
  * Host hook for saving a text file (CSV, etc). Mirrors `SaveImageHandler` —
325
331
  * when provided, `saveTextFile` calls this instead of triggering a browser