@wafertools/wafermap 0.30.4 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/AGENTS.md +9 -19
  2. package/CHANGELOG.md +93 -1
  3. package/README.md +2 -2
  4. package/dist/packages/canvas-adapter/charts/boxplot.js +1 -1
  5. package/dist/packages/canvas-adapter/charts/chartShell.d.ts +89 -6
  6. package/dist/packages/canvas-adapter/charts/chartShell.js +1 -1
  7. package/dist/packages/canvas-adapter/charts/histogram.js +1 -1
  8. package/dist/packages/canvas-adapter/charts/scatter.d.ts +11 -1
  9. package/dist/packages/canvas-adapter/charts/scatter.js +1 -1
  10. package/dist/packages/canvas-adapter/charts/trend.js +1 -1
  11. package/dist/packages/canvas-adapter/dieList.d.ts +1 -1
  12. package/dist/packages/canvas-adapter/exportName.d.ts +1 -12
  13. package/dist/packages/canvas-adapter/exportName.js +1 -1
  14. package/dist/packages/canvas-adapter/index.d.ts +2 -3
  15. package/dist/packages/canvas-adapter/index.js +1 -1
  16. package/dist/packages/canvas-adapter/insightsTab.js +1 -1
  17. package/dist/packages/canvas-adapter/renderWaferGallery.d.ts +4 -7
  18. package/dist/packages/canvas-adapter/renderWaferGallery.js +1 -1
  19. package/dist/packages/canvas-adapter/renderWaferMap.d.ts +15 -30
  20. package/dist/packages/canvas-adapter/renderWaferMap.js +1 -1
  21. package/dist/packages/canvas-adapter/userGuideHtml.d.ts +1 -1
  22. package/dist/packages/canvas-adapter/userGuideHtml.js +14 -10
  23. package/dist/packages/canvas-adapter/version.d.ts +2 -2
  24. package/dist/packages/canvas-adapter/version.js +1 -1
  25. package/dist/packages/core/aggregates.d.ts +0 -6
  26. package/dist/packages/core/aggregates.js +1 -1
  27. package/dist/packages/core/dies.d.ts +0 -2
  28. package/dist/packages/core/dies.js +1 -1
  29. package/dist/packages/core/index.d.ts +8 -10
  30. package/dist/packages/core/index.js +1 -1
  31. package/dist/packages/core/stdf.d.ts +9 -0
  32. package/dist/packages/core/stdf.js +1 -0
  33. package/dist/packages/core/transforms.d.ts +0 -23
  34. package/dist/packages/core/transforms.js +1 -1
  35. package/dist/packages/renderer/buildView.d.ts +1 -9
  36. package/dist/packages/renderer/buildView.js +1 -1
  37. package/dist/packages/renderer/buildWaferMap.d.ts +17 -25
  38. package/dist/packages/renderer/buildWaferMap.js +1 -1
  39. package/dist/packages/renderer/colorMap.d.ts +0 -2
  40. package/dist/packages/renderer/colorMap.js +1 -1
  41. package/dist/packages/renderer/deprecate.d.ts +1 -1
  42. package/dist/packages/renderer/deprecate.js +1 -1
  43. package/dist/packages/renderer/derivedTests/apply.js +1 -1
  44. package/dist/packages/renderer/index.d.ts +6 -5
  45. package/dist/packages/renderer/index.js +1 -1
  46. package/dist/packages/stats/clusterDetection.d.ts +2 -1
  47. package/dist/packages/stats/facets.d.ts +1 -1
  48. package/dist/packages/stats/index.d.ts +6 -16
  49. package/dist/packages/stats/index.js +1 -1
  50. package/dist/packages/stats/patternClassification.d.ts +2 -1
  51. package/dist/packages/stats/regions.d.ts +2 -1
  52. package/dist/packages/stats/renderFindingsReport.d.ts +0 -4
  53. package/dist/packages/stats/renderFindingsReport.js +1 -21
  54. package/package.json +2 -2
  55. package/dist/packages/canvas-adapter/deprecated.d.ts +0 -7
  56. package/dist/packages/canvas-adapter/deprecated.js +0 -1
  57. package/dist/packages/core/deprecated.d.ts +0 -60
  58. package/dist/packages/core/deprecated.js +0 -1
  59. package/dist/packages/renderer/deprecated.d.ts +0 -45
  60. package/dist/packages/renderer/deprecated.js +0 -1
  61. package/dist/packages/stats/deprecated.d.ts +0 -85
  62. package/dist/packages/stats/deprecated.js +0 -1
@@ -1 +1 @@
1
- import{NO_DATA_FILL as mt}from"../../renderer/colorMap.js";import{maxOf as ut,minOf as pt}from"../../core/utils.js";import{categorical as Ct}from"./palette.js";import{buildScatterData as Lt,buildScatterDataGrouped as At}from"../../stats/scatter.js";import{pearsonOfPairs as Ot}from"../../stats/correlation.js";import{buildFacetTable as Dt}from"../../stats/facets.js";import{SPACE as M,RADIUS as Bt,fontPx as R,FONT as Z,CLR as _}from"../toolbar.js";import{fitTicks as xt}from"../../renderer/axisTicks.js";import{cardShell as Pt,observeResize as $t,makeTooltip as Ht,attachChartTip as Et,makeTestSelect as It,makeWaferSelect as Wt,chartFillHeight as Nt,applyCanvasFlow as Ft,drawAxisUnit as Rt,resolveChartCanvasColors as _t,makeAxisFormat as ht,horizontalTickSpacing as zt,VERTICAL_TICK_SPACING_PX as Gt,makeSeriesLegendItem as jt,prepareCanvas as Ut}from"./chartShell.js";const r=52,Xt=16,l=16,Yt=44;export const NO_BIN_CATEGORY="none";export function binCategoryOf(b){return b===void 0?NO_BIN_CATEGORY:String(b)}export function binCategories(b){const z=new Set;let T=!1;for(const v of b)v.hbin===void 0?T=!0:z.add(v.hbin);const O=Array.from(z).sort((v,Y)=>v-Y).map(String);return T&&O.push(NO_BIN_CATEGORY),O}export function renderScatterPanel(b){const{title:z="Test scatter",items:T,testDefs:O,binColors:v,onSaveImage:Y,groups:G}=b,{card:i,body:C,controlsRow:tt}=Pt(z,Y,b.ownerDocument),j=O.filter(e=>e.testNumber!==void 0),S=!!(G&&G.length>0),et=(G??[]).map(e=>e.key),gt=new Map(et.map((e,n)=>[e,n]));let m=b.xTestNumber??j[0]?.testNumber??null,x=b.yTestNumber??j[1]?.testNumber??m,D=null;const nt=()=>D!==null?T[D]?[T[D]]:[]:T;function ot(e,n,o){const s=i.ownerDocument.createElement("label");Object.assign(s.style,{display:"inline-flex",alignItems:"center",gap:M.xs,fontSize:Z.body,color:_.label});const g=i.ownerDocument.createElement("span");g.textContent=e;const c=It(j,n,o,{maxWidth:"180px",emptyText:"No tests",ownerDocument:i.ownerDocument});return s.append(g,c),{wrap:s,select:c}}const{wrap:bt,select:yt}=ot("X:",m,e=>{m=e,E()}),{wrap:Tt,select:St}=ot("Y:",x,e=>{x=e,E()});tt.append(bt,Tt),!S&&T.length>1&&tt.appendChild(Wt(T,D,e=>{D=e,E()},{ownerDocument:i.ownerDocument}));const B=i.ownerDocument.createElement("div");Object.assign(B.style,{color:_.warnText,background:_.warnBg,border:`1px solid ${_.warnBorder}`,borderRadius:Bt.control,padding:`${M.xs} ${M.md}`,fontSize:Z.body,marginBottom:M.xs,display:"none"}),i.insertBefore(B,C);function it(){const e=S?[]:Dt(nt(),{facetableOnly:!0}).filter(n=>n.splittable).map(n=>n.label);e.length>0?(B.textContent=`\u26A0 Mixed ${e.join(", ")} across these points \u2014 trends here may be confounded (Simpson's paradox). Use Group by, or the Wafer picker, to narrow to a like-for-like set.`,B.style.display=""):B.style.display="none"}it();const K=i.ownerDocument.createElement("div");Object.assign(K.style,{color:_.label,fontSize:Z.body,marginBottom:M.xs}),i.insertBefore(K,C);function V(){const e=S?"One point per die \xB7 coloured by group \xB7 click legend to filter":"One point per die across all wafers \xB7 coloured by hard bin \xB7 click legend to filter",n=h.size===0?u:u.filter(g=>h.has(U(g))),{r:o,n:s}=Ot(n);K.textContent=o===null?`${e} \xB7 n = ${s.toLocaleString()}`:`${e} \xB7 r = ${o.toFixed(3)} \xB7 n = ${s.toLocaleString()}`}const U=e=>S?e.group??"\u2014":binCategoryOf(e.hbin),st=e=>S?Ct(gt.get(e)??0):e===NO_BIN_CATEGORY?mt:v?.get(Number(e))??mt,lt=e=>S?e:e===NO_BIN_CATEGORY?"No bin data":`Bin ${e}`,h=new Set,P=i.ownerDocument.createElement("div");Object.assign(P.style,{display:"flex",flexWrap:"wrap",gap:M.sm,marginTop:M.md,marginBottom:M.xl}),C.appendChild(P);const L=i.ownerDocument.createElement("canvas");L.style.display="block",L.style.cursor="crosshair",C.appendChild(L);const wt=Ht(i);let u=[],y=0,A=1,w=0,$=1;function H(e){const n=O.find(o=>o.testNumber===e);return{unit:n?.unit,limitLow:n?.limitLow,limitHigh:n?.limitHigh}}function Mt(){const e=C.clientWidth,n=Math.max(200,Math.min(400,e*.65)),o=Nt(i,C,L,n);return{w:e,h:o,plotW:Math.max(10,e-r-Xt),plotH:Math.max(10,o-l-Yt)}}const q=new Map;function at(){for(const[e,n]of q){const o=h.has(e);n.setState({selected:o,dimmed:h.size>0&&!o})}}function rt(e){P.innerHTML="",q.clear(),h.clear();for(const n of e){const o=jt(lt(n),st(n),i.ownerDocument),s=o.el;s.dataset.cat=n,q.set(n,o),Et(s,i,wt,`${lt(n)} \u2014 click to filter`),s.addEventListener("click",()=>{h.has(n)?h.delete(n):h.add(n),at(),V(),X()}),P.appendChild(s)}at()}function X(){Ft(L,P);const e=_t(i),n=A-y,o=$-w,{w:s,h:g,plotW:c,plotH:a}=Mt(),I=Ut(L,i,s,g);if(!I)return;const{ctx:t}=I;if(u.length===0){t.font=`${R()}px system-ui, sans-serif`,t.fillStyle=e.textMuted,t.textAlign="center",t.textBaseline="middle",t.fillText("No data \u2014 select two parametric tests with values.",s/2,g/2);return}t.font=`${R(-1)}px system-ui, sans-serif`;const W=m!==null?H(m).unit:void 0,ct=xt(y,A,c,zt(t,Math.max(Math.abs(y),Math.abs(A)),W)),dt=xt(w,$,a,()=>Gt),J=ht(Math.max(Math.abs(y),Math.abs(A)),m!==null?H(m).unit:void 0,ct.step||void 0),Q=ht(Math.max(Math.abs(w),Math.abs($)),x!==null?H(x).unit:void 0,dt.step||void 0);t.font=`${R(-1)}px system-ui, sans-serif`,t.strokeStyle=e.border,t.lineWidth=.5,t.fillStyle=e.textMuted;for(const d of ct.ticks){const f=r+(d-y)/n*c;t.beginPath(),t.moveTo(f,l),t.lineTo(f,l+a),t.stroke(),t.textAlign="center",t.textBaseline="top",t.fillText(J.tick(d),f,l+a+4)}for(const d of dt.ticks){const f=l+(1-(d-w)/o)*a;t.beginPath(),t.moveTo(r,f),t.lineTo(r+c,f),t.stroke(),t.textAlign="right",t.textBaseline="middle",t.fillText(Q.tick(d),r-4,f)}J.unitLabel&&Rt(t,J.unitLabel,r+c/2,l+a+24,e.textMuted),Q.unitLabel&&(t.save(),t.font=`${R(-1)}px system-ui, sans-serif`,t.fillStyle=e.textMuted,t.textAlign="center",t.textBaseline="middle",t.translate(6,l+a/2),t.rotate(-Math.PI/2),t.fillText(`(${Q.unitLabel})`,0,0),t.restore());const N=h.size===0?u:u.filter(d=>h.has(U(d))),ft=N.length>5e3?Math.ceil(N.length/5e3):1;t.globalAlpha=Math.max(.15,Math.min(.7,200/(N.length/ft)));for(let d=0;d<N.length;d+=ft){const f=N[d],p=r+(f.x-y)/n*c,F=l+(1-(f.y-w)/o)*a;t.beginPath(),t.arc(p,F,2.5,0,Math.PI*2),t.fillStyle=st(U(f)),t.fill()}if(t.globalAlpha=1,m!==null&&x!==null){const d=H(m),f=H(x);t.strokeStyle=e.textMuted,t.fillStyle=e.textMuted,t.lineWidth=1,t.setLineDash([4,3]),t.font=`${R(-1)}px system-ui, sans-serif`,t.textBaseline="top";for(const[p,F]of[[d.limitLow,"Lo limit"],[d.limitHigh,"Hi limit"]]){if(p===void 0||p<y||p>A)continue;const k=r+(p-y)/n*c;t.beginPath(),t.moveTo(k,l),t.lineTo(k,l+a),t.stroke(),t.textAlign="left",t.fillText(F,k+2,l+2)}for(const[p,F]of[[f.limitLow,"Lo limit"],[f.limitHigh,"Hi limit"]]){if(p===void 0||p<w||p>$)continue;const k=l+(1-(p-w)/o)*a;t.beginPath(),t.moveTo(r,k),t.lineTo(r+c,k),t.stroke(),t.textAlign="left",t.fillText(F,r+3,k+2)}t.setLineDash([])}t.strokeStyle=e.border,t.lineWidth=1,t.beginPath(),t.moveTo(r,l),t.lineTo(r,l+a),t.moveTo(r,l+a),t.lineTo(r+c,l+a),t.stroke()}function E(){if(it(),j.length<2||m===null||x===null){u=[],rt([]),V(),X();return}u=S?At(G,m,x):Lt(nt(),m,x);let e;if(S){const n=new Set(u.map(U));e=et.filter(o=>n.has(o))}else e=binCategories(u);if(rt(e),V(),u.length>0){const n=u.map(W=>W.x),o=u.map(W=>W.y),s=pt(n),g=ut(n),c=pt(o),a=ut(o),I=(g-s)*.05||1,t=(a-c)*.05||1;y=s-I,A=g+I,w=c-t,$=a+t}X()}const kt=$t(i,()=>X());E();function vt(e,n){m=e,x=n,yt.value=String(e),St.value=String(n),E()}return{card:i,setXY:vt,destroy:()=>kt.disconnect()}}
1
+ import{NO_DATA_FILL as Ce}from"../../renderer/colorMap.js";import{maxOf as J,minOf as Le}from"../../core/utils.js";import{categorical as Xe}from"./palette.js";import{buildScatterData as Ye,buildScatterDataGrouped as Ke}from"../../stats/scatter.js";import{pearsonOfPairs as Ve}from"../../stats/correlation.js";import{buildFacetTable as qe}from"../../stats/facets.js";import{SPACE as k,RADIUS as Je,fontPx as L,FONT as re,CLR as X}from"../toolbar.js";import{fitTicks as Ae}from"../../renderer/axisTicks.js";import{cardShell as Qe,observeResize as Ze,makeTooltip as et,attachChartTip as tt,makeTestSelect as nt,makeWaferSelect as it,chartFillHeight as ot,applyCanvasFlow as st,drawAxisUnit as lt,resolveChartCanvasColors as at,makeAxisFormat as Q,horizontalTickSpacing as rt,VERTICAL_TICK_SPACING_PX as ct,makeSeriesLegendItem as ft,prepareCanvas as dt,drawOffAxisLimits as Oe,limitLines as mt,hasBothLimitKinds as ut,makeLimitsSelect as pt,stackLabelRows as Pe,strokeLimitLine as De,fillTextOnHalo as Be}from"./chartShell.js";const c=52,xt=16,l=16,ht=44;export const NO_BIN_CATEGORY="none";export function binCategoryOf(h){return h===void 0?NO_BIN_CATEGORY:String(h)}export function binCategories(h){const Y=new Set;let S=!1;for(const O of h)O.hbin===void 0?S=!0:Y.add(O.hbin);const A=Array.from(Y).sort((O,Z)=>O-Z).map(String);return S&&A.push(NO_BIN_CATEGORY),A}export function renderScatterPanel(h){const{title:Y="Test scatter",items:S,testDefs:A,binColors:O,onSaveImage:Z,groups:K}=h,{card:s,body:P,controlsRow:ee}=Qe(Y,Z,h.ownerDocument),V=A.filter(e=>e.testNumber!==void 0),v=!!(K&&K.length>0),ce=(K??[]).map(e=>e.key),Ee=new Map(ce.map((e,n)=>[e,n]));let p=h.xTestNumber??V[0]?.testNumber??null,b=h.yTestNumber??V[1]?.testNumber??p,R=null;const fe=()=>R!==null?S[R]?[S[R]]:[]:S;function de(e,n,o){const r=s.ownerDocument.createElement("label");Object.assign(r.style,{display:"inline-flex",alignItems:"center",gap:k.xs,fontSize:re.body,color:X.label});const T=s.ownerDocument.createElement("span");T.textContent=e;const d=nt(V,n,o,{maxWidth:"180px",emptyText:"No tests",ownerDocument:s.ownerDocument});return r.append(T,d),{wrap:r,select:d}}const{wrap:$e,select:Re}=de("X:",p,e=>{p=e,F()}),{wrap:Ie,select:We}=de("Y:",b,e=>{b=e,F()});ee.append($e,Ie);let M=h.axisPrefs??{clipOutliers:!1};const me=s.ownerDocument.createElement("span");ee.appendChild(me);function ue(){const e=[p,b].map(n=>A.find(o=>o.testNumber===n));me.replaceChildren(...e.some(ut)?[pt(M.limits??"both",n=>{M={...M,limits:n},h.onAxisPrefsChange?.(M),E()},s.ownerDocument)]:[])}!v&&S.length>1&&ee.appendChild(it(S,R,e=>{R=e,F()},{ownerDocument:s.ownerDocument}));const I=s.ownerDocument.createElement("div");Object.assign(I.style,{color:X.warnText,background:X.warnBg,border:`1px solid ${X.warnBorder}`,borderRadius:Je.control,padding:`${k.xs} ${k.md}`,fontSize:re.body,marginBottom:k.xs,display:"none"}),s.insertBefore(I,P);function pe(){const e=v?[]:qe(fe(),{facetableOnly:!0}).filter(n=>n.splittable).map(n=>n.label);e.length>0?(I.textContent=`\u26A0 Mixed ${e.join(", ")} across these points \u2014 trends here may be confounded (Simpson's paradox). Use Group by, or the Wafer picker, to narrow to a like-for-like set.`,I.style.display=""):I.style.display="none"}pe();const te=s.ownerDocument.createElement("div");Object.assign(te.style,{color:X.label,fontSize:re.body,marginBottom:k.xs}),s.insertBefore(te,P);function ne(){const e=v?"One point per die \xB7 coloured by group \xB7 click legend to filter":"One point per die across all wafers \xB7 coloured by hard bin \xB7 click legend to filter",n=g.size===0?x:x.filter(T=>g.has(q(T))),{r:o,n:r}=Ve(n);te.textContent=o===null?`${e} \xB7 n = ${r.toLocaleString()}`:`${e} \xB7 r = ${o.toFixed(3)} \xB7 n = ${r.toLocaleString()}`}const q=e=>v?e.group??"\u2014":binCategoryOf(e.hbin),xe=e=>v?Xe(Ee.get(e)??0):e===NO_BIN_CATEGORY?Ce:O?.get(Number(e))??Ce,he=e=>v?e:e===NO_BIN_CATEGORY?"No bin data":`Bin ${e}`,g=new Set,W=s.ownerDocument.createElement("div");Object.assign(W.style,{display:"flex",flexWrap:"wrap",gap:k.sm,marginTop:k.md,marginBottom:k.xl}),P.appendChild(W);const D=s.ownerDocument.createElement("canvas");D.style.display="block",D.style.cursor="crosshair",P.appendChild(D);const Ne=et(s);let x=[],y=0,C=1,w=0,B=1;function N(e){const n=A.find(o=>o.testNumber===e);return{unit:n?.unit,lines:mt(n,M.limits)}}function Fe(){const e=P.clientWidth,n=Math.max(200,Math.min(400,e*.65)),o=ot(s,P,D,n);return{w:e,h:o,plotW:Math.max(10,e-c-xt),plotH:Math.max(10,o-l-ht)}}const ie=new Map;function be(){for(const[e,n]of ie){const o=g.has(e);n.setState({selected:o,dimmed:g.size>0&&!o})}}function ge(e){W.innerHTML="",ie.clear(),g.clear();for(const n of e){const o=ft(he(n),xe(n),s.ownerDocument),r=o.el;r.dataset.cat=n,ie.set(n,o),tt(r,s,Ne,`${he(n)} \u2014 click to filter`),r.addEventListener("click",()=>{g.has(n)?g.delete(n):g.add(n),be(),ne(),E()}),W.appendChild(r)}be()}function E(){st(D,W);const e=at(s),n=C-y,o=B-w,{w:r,h:T,plotW:d,plotH:f}=Fe(),H=dt(D,s,r,T);if(!H)return;const{ctx:t}=H;if(x.length===0){t.font=`${L()}px system-ui, sans-serif`,t.fillStyle=e.textMuted,t.textAlign="center",t.textBaseline="middle",t.fillText("No data \u2014 select two parametric tests with values.",r/2,T/2);return}t.font=`${L(-1)}px system-ui, sans-serif`;const _=p!==null?N(p).unit:void 0,ye=Ae(y,C,d,rt(t,Math.max(Math.abs(y),Math.abs(C)),_)),Te=Ae(w,B,f,()=>ct),oe=Q(Math.max(Math.abs(y),Math.abs(C)),p!==null?N(p).unit:void 0,ye.step||void 0),se=Q(Math.max(Math.abs(w),Math.abs(B)),b!==null?N(b).unit:void 0,Te.step||void 0);t.font=`${L(-1)}px system-ui, sans-serif`,t.strokeStyle=e.grid,t.lineWidth=.5,t.fillStyle=e.textMuted;for(const m of ye.ticks){const u=c+(m-y)/n*d;t.beginPath(),t.moveTo(u,l),t.lineTo(u,l+f),t.stroke(),t.textAlign="center",t.textBaseline="top",t.fillText(oe.tick(m),u,l+f+4)}for(const m of Te.ticks){const u=l+(1-(m-w)/o)*f;t.beginPath(),t.moveTo(c,u),t.lineTo(c+d,u),t.stroke(),t.textAlign="right",t.textBaseline="middle",t.fillText(se.tick(m),c-4,u)}oe.unitLabel&&lt(t,oe.unitLabel,c+d/2,l+f+24,e.textMuted),se.unitLabel&&(t.save(),t.font=`${L(-1)}px system-ui, sans-serif`,t.fillStyle=e.textMuted,t.textAlign="center",t.textBaseline="middle",t.translate(6,l+f/2),t.rotate(-Math.PI/2),t.fillText(`(${se.unitLabel})`,0,0),t.restore());const z=g.size===0?x:x.filter(m=>g.has(q(m))),we=z.length>5e3?Math.ceil(z.length/5e3):1;t.globalAlpha=Math.max(.15,Math.min(.7,200/(z.length/we)));for(let m=0;m<z.length;m+=we){const u=z[m],G=c+(u.x-y)/n*d,j=l+(1-(u.y-w)/o)*f;t.beginPath(),t.arc(G,j,2.5,0,Math.PI*2),t.fillStyle=xe(q(u)),t.fill()}if(t.globalAlpha=1,p!==null&&b!==null){const m=N(p),u=N(b);t.strokeStyle=e.limitLine,t.fillStyle=e.limitLine,t.lineWidth=1,t.font=`${L(-1)}px system-ui, sans-serif`,t.textBaseline="top";const G=L(-1)+2,j=m.lines.filter(i=>i.value>=y&&i.value<=C).map(i=>{const a=c+(i.value-y)/n*d;return{l:i,cx:a,start:a+2,end:a+2+t.measureText(i.label).width}}),Se=Pe(j);j.forEach(({l:i,cx:a},U)=>{De(t,i,e.limitLine,a,l,a,l+f),t.textAlign="left",Be(t,i.label,a+2,l+2+Se[U]*G,e.bg)});const le=u.lines.filter(i=>i.value>=w&&i.value<=B).map(i=>{const a=l+(1-(i.value-w)/o)*f;return{l:i,cy:a,start:a+2,end:a+2+L(-1)}}),Ge=Pe(le,1),je=J(le.map(i=>t.measureText(i.l.label).width))+8;le.forEach(({l:i,cy:a},U)=>{De(t,i,e.limitLine,c,a,c+d,a),t.textAlign="left",Be(t,i.label,c+3+Ge[U]*je,a+2,e.bg)});const ve=(i,a,U)=>i.filter($=>$.value<a||$.value>U).map($=>({value:$.value,label:$.label,side:$.value<a?"lo":"hi"})),Me={left:c,right:c+d,top:l,bottom:l+f},ae=ve(m.lines,y,C),ke=l+(j.length?(J(Se)+1)*G:0),Ue=Math.max(ae.filter(i=>i.side==="lo").length,ae.filter(i=>i.side==="hi").length);Oe(t,ae,{...Me,top:ke},"horizontal",e.limitLine,i=>Q(Math.abs(i),m.unit).tick(i),e.bg),Oe(t,ve(u.lines,w,B),{...Me,top:ke+Ue*G},"vertical",e.limitLine,i=>Q(Math.abs(i),u.unit).tick(i),e.bg),t.setLineDash([])}t.strokeStyle=e.border,t.lineWidth=1,t.beginPath(),t.moveTo(c,l),t.lineTo(c,l+f),t.moveTo(c,l+f),t.lineTo(c+d,l+f),t.stroke()}function F(){if(pe(),ue(),V.length<2||p===null||b===null){x=[],ge([]),ne(),E();return}x=v?Ke(K,p,b):Ye(fe(),p,b);let e;if(v){const n=new Set(x.map(q));e=ce.filter(o=>n.has(o))}else e=binCategories(x);if(ge(e),ne(),x.length>0){const n=x.map(_=>_.x),o=x.map(_=>_.y),r=Le(n),T=J(n),d=Le(o),f=J(o),H=(T-r)*.05||1,t=(f-d)*.05||1;y=r-H,C=T+H,w=d-t,B=f+t}E()}const He=Ze(s,()=>E());F();function _e(e,n){p=e,b=n,Re.value=String(e),We.value=String(n),F()}function ze(e){if((e.limits??"both")===(M.limits??"both")){M=e;return}M=e,ue(),E()}return{card:s,setXY:_e,setAxisPrefs:ze,destroy:()=>He.disconnect()}}
@@ -1 +1 @@
1
- import{buildTestTrendData as he,trendCentre as pe}from"../../stats/trend.js";import{isParametricTest as xe}from"../../renderer/buildWaferMap.js";import{fmt as D}from"../../renderer/fmt.js";import{SPACE as le,fontPx as ge,FONT as ye,CLR as be}from"../toolbar.js";import{QUANTITY as X}from"./palette.js";import{cardShell as Te,observeResize as ve,makeTooltip as Le,positionChartTooltip as ke,makeLinkedTestSelect as we,makeLinkedAxisPrefs as Ce,renderEmptyState as z,chartFillHeight as Ae,PADDING as G,resolveAxisRange as Me,shouldIncludeLimitsByDefault as Pe,drawOffAxisLimits as Se,makeAxisFormat as Ne,VERTICAL_TICK_SPACING_PX as He,WAFER_MENU_HINT as Ee,prepareCanvas as Ie}from"./chartShell.js";import{fitTicks as De}from"../../renderer/axisTicks.js";import{escHtml as U}from"../../core/utils.js";const se=220,Oe=56,We=34,$e=3.5;export function renderTrendPanel(f){const{items:j,testDefs:re,onSaveImage:ae,onOpen:C,centreLabel:Y="mean of all wafers"}=f,ce=f.title??"Wafer-to-wafer trend",{card:s,body:u,controlsRow:K}=Te(ce,ae,f.ownerDocument);s.style.alignSelf="start";const N=re.filter(o=>o.testNumber!==void 0&&xe(o));let h=f.selectedTestNumber??N[0]?.testNumber??null,O=0;const Q=we(N,h,o=>{h=o,A(),f.onTestChange?.(o)},{maxWidth:"240px",emptyText:"No parametric tests",ownerDocument:s.ownerDocument});K.appendChild(Q.el);const W=s.ownerDocument.createElement("span");Object.assign(W.style,{display:"inline-flex",gap:le.lg,alignItems:"center"}),K.appendChild(W);const $=Ce(W,f.axisPrefs,o=>{f.onAxisPrefsChange?.(o),A()},s.ownerDocument),w=s.ownerDocument.createElement("div");Object.assign(w.style,{color:be.label,fontSize:ye.body,marginBottom:le.sm}),s.insertBefore(w,u);const g=Le(s);let H=null,i=[];function me(o){return N.find(R=>R.testNumber===o)}function A(){const{includeLimits:o,clipOutliers:R}=$.get();if(u.innerHTML="",H?.disconnect(),H=null,N.length===0||h===null){w.textContent="",z(u,"No parametric test data available for a trend.");return}if(j.length<2){w.textContent="",z(u,"A wafer-to-wafer trend needs at least two wafers.");return}if(i=he(j,h),!i.some(l=>l.count>0)){w.textContent="",z(u,"No values recorded for this test.");return}const r=me(h),y=pe(i),V=()=>{w.textContent=`Point = wafer mean, whisker = \xB11\u03C3, dashed = ${Y} \xB7 wafers in slot order`+(C?" \xB7 click a point to open that wafer":"")+(O?` \xB7 axis clipped, ${O} outside`:"")};V();const d=s.ownerDocument.createElement("canvas");d.style.display="block",u.appendChild(d);let M=null;const q=()=>{const l=Math.max(1,u.clientWidth),a=Math.max(se,Ae(s,u,d,se)),n=Ie(d,s,l,a);if(!n)return;const{ctx:e,theme:b}=n;let P=1/0,S=-1/0;const J=[];for(const t of i)!t.count||!Number.isFinite(t.mean)||(P=Math.min(P,t.mean-t.stddev),S=Math.max(S,t.mean+t.stddev),J.push(t.mean-t.stddev,t.mean+t.stddev));if(!Number.isFinite(P)||!Number.isFinite(S))return;const Z=o??Pe(P,S,r?.limitLow,r?.limitHigh);$.sync(Z,r?.limitLow!==void 0||r?.limitHigh!==void 0);const E=Me({dataMin:P,dataMax:S,limitLow:r?.limitLow,limitHigh:r?.limitHigh,includeLimits:Z,clipOutliers:R,values:J});O=E.clippedCount,V();let x=E.lo,T=E.hi;const ee=(T-x)*.08;x-=ee,T+=ee;const c=G+Oe;e.font=`${ge(-1)}px system-ui, sans-serif`;const te=t=>t.length>8?`${t.slice(0,7)}\u2026`:t,de=i.length?Math.ceil(Math.max(e.measureText(te(i[0].label)).width,e.measureText(te(i[i.length-1].label)).width)/2):0,v=l-G-de,I=G,L=a-We,k=t=>L-(t-x)/(T-x)*(L-I),ne=i.length>1?(v-c)/(i.length-1):0;M={left:c,step:ne};const _=t=>i.length>1?c+t*ne:(c+v)/2;e.strokeStyle=b.border,e.lineWidth=1,e.beginPath(),e.moveTo(c,I),e.lineTo(c,L),e.lineTo(v,L),e.stroke(),e.fillStyle=b.text,e.textAlign="right",e.textBaseline="middle";const ie=De(x,T,L-I,()=>He),fe=Ne(Math.max(Math.abs(x),Math.abs(T)),r?.unit,ie.step||void 0);for(const t of ie.ticks)e.fillText(fe.tickWithUnit(t),c-6,k(t));Se(e,E.offAxis,{left:c,right:v,top:I,bottom:L},"vertical",b.limitLine,t=>D(t,r?.unit));for(const[t,p]of[[r?.limitLow,"Lo limit"],[r?.limitHigh,"Hi limit"]]){if(t===void 0||t<x||t>T)continue;const m=k(t);e.save(),e.strokeStyle=b.limitLine,e.globalAlpha=.7,e.setLineDash([4,3]),e.beginPath(),e.moveTo(c,m),e.lineTo(v,m),e.stroke(),e.restore(),e.save(),e.fillStyle=b.limitLine,e.textAlign="left",e.fillText(p,c+3,m-6),e.restore()}if(y!==null&&y>=x&&y<=T){const t=k(y);e.save(),e.strokeStyle=b.text,e.globalAlpha=.5,e.setLineDash([3,3]),e.beginPath(),e.moveTo(c,t),e.lineTo(v,t),e.stroke(),e.restore()}e.strokeStyle=X,e.lineWidth=1.5,e.beginPath();let B=!1;i.forEach((t,p)=>{if(!t.count||!Number.isFinite(t.mean)){B=!1;return}const m=_(p),oe=k(t.mean);B?e.lineTo(m,oe):e.moveTo(m,oe),B=!0}),e.stroke(),i.forEach((t,p)=>{if(!t.count||!Number.isFinite(t.mean))return;const m=_(p);t.stddev>0&&(e.save(),e.strokeStyle=X,e.globalAlpha=.55,e.lineWidth=1,e.beginPath(),e.moveTo(m,k(t.mean-t.stddev)),e.lineTo(m,k(t.mean+t.stddev)),e.stroke(),e.restore()),e.fillStyle=X,e.beginPath(),e.arc(m,k(t.mean),$e,0,Math.PI*2),e.fill()}),e.fillStyle=b.text,e.textBaseline="top",e.textAlign="center";const ue=Math.max(1,Math.ceil(i.length*42/Math.max(1,v-c)));i.forEach((t,p)=>{if(p%ue!==0&&p!==i.length-1)return;const m=t.label.length>8?`${t.label.slice(0,7)}\u2026`:t.label;e.fillText(m,_(p),L+6)})},F=l=>{if(!M||M.step<=0)return-1;const a=d.getBoundingClientRect(),n=Math.round((l.clientX-a.left-M.left)/M.step);return n>=0&&n<i.length&&i[n].count>0?n:-1};d.addEventListener("mousemove",l=>{const a=F(l);if(a<0){g.style.display="none",d.style.cursor="default";return}const n=i[a];d.style.cursor=C&&n.key!==void 0?"pointer":"default",g.innerHTML=`<strong>${U(n.label)}</strong><br>`+U(`mean ${D(n.mean,r?.unit)} \xB7 \u03C3 ${D(n.stddev,r?.unit)}`)+`<br>n = ${n.count.toLocaleString()}`+(y!==null?"<br>"+U(`\u0394 vs ${Y} ${n.mean-y>=0?"+":""}${D(n.mean-y,r?.unit)}`):"")+(C&&n.key!==void 0?"<br><em>click to open this wafer</em>":"")+(f.onWaferContextMenu&&n.key!==void 0?Ee:""),g.style.display="block",ke(g,s,l.clientX,l.clientY)}),d.addEventListener("mouseleave",()=>{g.style.display="none"}),d.addEventListener("click",l=>{const a=F(l);if(a<0||!C)return;const n=i[a];n.key!==void 0&&h!==null&&C(n.key,h)}),d.addEventListener("contextmenu",l=>{const a=F(l),n=a<0?void 0:i[a].key;n===void 0||!f.onWaferContextMenu||(g.style.display="none",f.onWaferContextMenu(n,h??void 0,l))}),q(),H=ve(u,q)}return A(),{card:s,destroy:()=>{H?.disconnect(),g.remove(),s.remove()},setTest:o=>{Q.set(o)&&(h=o,A())},setAxisPrefs:o=>{$.set(o)&&A()}}}
1
+ import{buildTestTrendData as ke,trendCentre as we}from"../../stats/trend.js";import{isParametricTest as Ce}from"../../renderer/buildWaferMap.js";import{fmt as W}from"../../renderer/fmt.js";import{SPACE as re,fontPx as ce,FONT as Ae,CLR as Me}from"../toolbar.js";import{QUANTITY as G}from"./palette.js";import{cardShell as Pe,observeResize as Se,makeTooltip as Ne,positionChartTooltip as Ee,makeLinkedTestSelect as Ie,makeLinkedAxisPrefs as De,renderEmptyState as U,chartFillHeight as Oe,PADDING as j,resolveAxisRange as We,shouldIncludeLimitsByDefault as He,drawOffAxisLimits as $e,limitLines as me,limitExtent as de,hasBothLimitKinds as Re,stackLabelRows as Be,strokeLimitLine as Fe,makeAxisFormat as _e,VERTICAL_TICK_SPACING_PX as Xe,WAFER_MENU_HINT as ze,prepareCanvas as Ge}from"./chartShell.js";import{fitTicks as Ue}from"../../renderer/axisTicks.js";import{escHtml as K}from"../../core/utils.js";import{maxOf as je}from"../../core/utils.js";const fe=220,Ke=56,Ye=34,Qe=3.5;export function renderTrendPanel(d){const{items:Y,testDefs:ue,onSaveImage:he,onOpen:C,centreLabel:Q="mean of all wafers"}=d,pe=d.title??"Wafer-to-wafer trend",{card:a,body:u,controlsRow:V}=Pe(pe,he,d.ownerDocument);a.style.alignSelf="start";const N=ue.filter(s=>s.testNumber!==void 0&&Ce(s));let h=d.selectedTestNumber??N[0]?.testNumber??null,H=0;const q=Ie(N,h,s=>{h=s,A(),d.onTestChange?.(s)},{maxWidth:"240px",emptyText:"No parametric tests",ownerDocument:a.ownerDocument});V.appendChild(q.el);const $=a.ownerDocument.createElement("span");Object.assign($.style,{display:"inline-flex",gap:re.lg,alignItems:"center"}),V.appendChild($);const R=De($,d.axisPrefs,s=>{d.onAxisPrefsChange?.(s),A()},a.ownerDocument),w=a.ownerDocument.createElement("div");Object.assign(w.style,{color:Me.label,fontSize:Ae.body,marginBottom:re.sm}),a.insertBefore(w,u);const b=Ne(a);let E=null,i=[];function xe(s){return N.find(B=>B.testNumber===s)}function A(){const{includeLimits:s,clipOutliers:B,limits:be}=R.get();if(u.innerHTML="",E?.disconnect(),E=null,N.length===0||h===null){w.textContent="",U(u,"No parametric test data available for a trend.");return}if(Y.length<2){w.textContent="",U(u,"A wafer-to-wafer trend needs at least two wafers.");return}if(i=ke(Y,h),!i.some(o=>o.count>0)){w.textContent="",U(u,"No values recorded for this test.");return}const p=xe(h),I=me(p,be),g=we(i),J=()=>{w.textContent=`Point = wafer mean, whisker = \xB11\u03C3, dashed = ${Q} \xB7 wafers in slot order`+(C?" \xB7 click a point to open that wafer":"")+(H?` \xB7 axis clipped, ${H} outside`:"")};J();const m=a.ownerDocument.createElement("canvas");m.style.display="block",u.appendChild(m);let M=null;const Z=()=>{const o=Math.max(1,u.clientWidth),r=Math.max(fe,Oe(a,u,m,fe)),n=Ge(m,a,o,r);if(!n)return;const{ctx:e,theme:y}=n;let P=1/0,S=-1/0;const ee=[];for(const t of i)!t.count||!Number.isFinite(t.mean)||(P=Math.min(P,t.mean-t.stddev),S=Math.max(S,t.mean+t.stddev),ee.push(t.mean-t.stddev,t.mean+t.stddev));if(!Number.isFinite(P)||!Number.isFinite(S))return;const te=s??He(P,S,de(I).lo,de(I).hi);R.sync(te,me(p).length>0,Re(p));const D=We({dataMin:P,dataMax:S,limits:I,includeLimits:te,clipOutliers:B,values:ee});H=D.clippedCount,J();let x=D.lo,v=D.hi;const ne=(v-x)*.08;x-=ne,v+=ne;const c=j+Ke;e.font=`${ce(-1)}px system-ui, sans-serif`;const ie=t=>t.length>8?`${t.slice(0,7)}\u2026`:t,ge=i.length?Math.ceil(Math.max(e.measureText(ie(i[0].label)).width,e.measureText(ie(i[i.length-1].label)).width)/2):0,T=o-j-ge,O=j,L=r-Ye,k=t=>L-(t-x)/(v-x)*(L-O),se=i.length>1?(T-c)/(i.length-1):0;M={left:c,step:se};const _=t=>i.length>1?c+t*se:(c+T)/2;e.strokeStyle=y.border,e.lineWidth=1,e.beginPath(),e.moveTo(c,O),e.lineTo(c,L),e.lineTo(T,L),e.stroke(),e.fillStyle=y.text,e.textAlign="right",e.textBaseline="middle";const oe=Ue(x,v,L-O,()=>Xe),ye=_e(Math.max(Math.abs(x),Math.abs(v)),p?.unit,oe.step||void 0);for(const t of oe.ticks)e.fillText(ye.tickWithUnit(t),c-6,k(t));$e(e,D.offAxis,{left:c,right:T,top:O,bottom:L},"vertical",y.limitLine,t=>W(t,p?.unit));const le=ce(-1),X=I.filter(t=>t.value>=x&&t.value<=v).map(t=>{const l=k(t.value);return{l:t,y:l,start:l-6-le/2,end:l-6+le/2}}),ve=Be(X,1),Te=je(X.map(t=>e.measureText(t.l.label).width))+8;if(X.forEach(({l:t,y:l},f)=>{e.save(),e.globalAlpha=.7,Fe(e,t,y.limitLine,c,l,T,l),e.restore(),e.save(),e.fillStyle=y.limitLine,e.textAlign="left",e.fillText(t.label,c+3+ve[f]*Te,l-6),e.restore()}),g!==null&&g>=x&&g<=v){const t=k(g);e.save(),e.strokeStyle=y.text,e.globalAlpha=.5,e.setLineDash([3,3]),e.beginPath(),e.moveTo(c,t),e.lineTo(T,t),e.stroke(),e.restore()}e.strokeStyle=G,e.lineWidth=1.5,e.beginPath();let z=!1;i.forEach((t,l)=>{if(!t.count||!Number.isFinite(t.mean)){z=!1;return}const f=_(l),ae=k(t.mean);z?e.lineTo(f,ae):e.moveTo(f,ae),z=!0}),e.stroke(),i.forEach((t,l)=>{if(!t.count||!Number.isFinite(t.mean))return;const f=_(l);t.stddev>0&&(e.save(),e.strokeStyle=G,e.globalAlpha=.55,e.lineWidth=1,e.beginPath(),e.moveTo(f,k(t.mean-t.stddev)),e.lineTo(f,k(t.mean+t.stddev)),e.stroke(),e.restore()),e.fillStyle=G,e.beginPath(),e.arc(f,k(t.mean),Qe,0,Math.PI*2),e.fill()}),e.fillStyle=y.text,e.textBaseline="top",e.textAlign="center";const Le=Math.max(1,Math.ceil(i.length*42/Math.max(1,T-c)));i.forEach((t,l)=>{if(l%Le!==0&&l!==i.length-1)return;const f=t.label.length>8?`${t.label.slice(0,7)}\u2026`:t.label;e.fillText(f,_(l),L+6)})},F=o=>{if(!M||M.step<=0)return-1;const r=m.getBoundingClientRect(),n=Math.round((o.clientX-r.left-M.left)/M.step);return n>=0&&n<i.length&&i[n].count>0?n:-1};m.addEventListener("mousemove",o=>{const r=F(o);if(r<0){b.style.display="none",m.style.cursor="default";return}const n=i[r];m.style.cursor=C&&n.key!==void 0?"pointer":"default",b.innerHTML=`<strong>${K(n.label)}</strong><br>`+K(`mean ${W(n.mean,p?.unit)} \xB7 \u03C3 ${W(n.stddev,p?.unit)}`)+`<br>n = ${n.count.toLocaleString()}`+(g!==null?"<br>"+K(`\u0394 vs ${Q} ${n.mean-g>=0?"+":""}${W(n.mean-g,p?.unit)}`):"")+(C&&n.key!==void 0?"<br><em>click to open this wafer</em>":"")+(d.onWaferContextMenu&&n.key!==void 0?ze:""),b.style.display="block",Ee(b,a,o.clientX,o.clientY)}),m.addEventListener("mouseleave",()=>{b.style.display="none"}),m.addEventListener("click",o=>{const r=F(o);if(r<0||!C)return;const n=i[r];n.key!==void 0&&h!==null&&C(n.key,h)}),m.addEventListener("contextmenu",o=>{const r=F(o),n=r<0?void 0:i[r].key;n===void 0||!d.onWaferContextMenu||(b.style.display="none",d.onWaferContextMenu(n,h??void 0,o))}),Z(),E=Se(u,Z)}return A(),{card:a,destroy:()=>{E?.disconnect(),b.remove(),a.remove()},setTest:s=>{q.set(s)&&(h=s,A())},setAxisPrefs:s=>{R.set(s)&&A()}}}
@@ -15,7 +15,7 @@ export interface DieListDisplayOptions {
15
15
  * Show a "View die list" link inside the Summary panel (`renderWaferMap`)
16
16
  * / lot Summary panel (`renderWaferGallery`) that opens this wafer's — or,
17
17
  * in the gallery, the whole lot's — dies as a table in a modal, with the
18
- * same "Export CSV" button `buildDieListSection` always has. **Default
18
+ * same "Export CSV" button every die list has. **Default
19
19
  * `true`** — set `enabled: false` to hide it. Requires a Summary panel to
20
20
  * be reachable at all (`RenderOptions.summaryPanel` / `GalleryOptions.summaryPanel`),
21
21
  * since that panel is this link's only home; irrelevant otherwise.
@@ -18,20 +18,9 @@
18
18
  * `suggestedName` argument of their save hooks.
19
19
  */
20
20
  import { type SaveImageHandler, type SaveTextHandler } from './toolbar.js';
21
- /**
22
- * Tell a host that passes `downloadFilename` its meaning changes in 0.31.0.
23
- * Until then it keeps its documented meaning — the whole name of the map or
24
- * gallery PNG — and nothing else reads it; changing that in a patch release
25
- * would break hosts that match the name their `onSaveImage` receives.
26
- */
27
- export declare function noticeDownloadFilenameChange(downloadFilename: string | undefined): void;
28
21
  /** What a renderer knows about the data behind an export. */
29
22
  export interface ExportContext {
30
- /**
31
- * Leads the name, and suppresses any context it already names. Reserved for
32
- * `downloadFilename` from 0.31.0; no renderer sets it before then (see
33
- * `noticeDownloadFilenameChange`).
34
- */
23
+ /** The host's `downloadFilename`: leads the name, and suppresses any context it already names. */
35
24
  prefix?: string;
36
25
  /** Distinct lot IDs covered, in display order. */
37
26
  lots: string[];
@@ -1 +1 @@
1
- import{downloadBlob as u}from"./toolbar.js";import{noticeOnce as _}from"../renderer/deprecate.js";export function noticeDownloadFilenameChange(e){e!=null&&_("downloadFilename",'downloadFilename becomes a prefix in 0.31.0: the library will append the lot, wafer and content (e.g. "<downloadFilename>_W05_hard-bin.png") and apply it to every saved file, CSVs included. Until then it names only the map or gallery PNG, as before.')}const $=60,m=180,g=/^(con|prn|aux|nul|com\d|lpt\d)$/i;function f(e){return e.normalize("NFC").replace(/[^\p{L}\p{N}._+-]+/gu,"-").replace(/-{2,}/g,"-").replace(/^[-._]+|[-._]+$/g,"").slice(0,$).replace(/[-._]+$/g,"")}function c(e,n){return/^\d+$/.test(n)?`${e}-${n}`:n}function w(e,n){const o=`_${e.toLowerCase().replace(/[-_.\s]+/g,"_")}_`,r=`_${n.toLowerCase().replace(/[-_.\s]+/g,"_")}_`;return o.includes(r)}export function buildExportFilename(e,n){const o=n.lastIndexOf("."),r=o>=0?n.slice(o):"",l=f(o>=0?n.slice(0,o):n).toLowerCase(),t=e.prefix?.trim()?f(e.prefix):"",a=[];if(e.lots.length===1?a.push({raw:e.lots[0],text:c("lot",e.lots[0])}):e.lots.length>1&&a.push({raw:`${e.lots.length}-lots`,text:`${e.lots.length}-lots`}),e.stackedWafers!==void 0){const i=e.stackedWafers===!0?"stacked":`stacked-${e.stackedWafers}-wafer${e.stackedWafers===1?"":"s"}`;a.push({raw:i,text:i})}else e.wafer!==void 0?a.push({raw:e.wafer,text:c("wafer",e.wafer)}):e.waferCount!==void 0&&e.waferCount>1&&a.push({raw:`${e.waferCount}-wafers`,text:`${e.waferCount}-wafers`});const p=[t];for(const{raw:i,text:h}of a){const d=f(h);d&&(t&&(w(t,f(i))||w(t,d))||p.push(d))}p.push(l);let s=p.filter(Boolean).join("_").slice(0,m).replace(/[-_.]+$/g,"");return s||(s="wafermap"),g.test(s)&&(s=`wafermap-${s}`),`${s}${r}`}export function withExportContext(e,n,o){return{onSaveImage:(r,l)=>{const t=buildExportFilename(e(),l);if(n)return n(r,t);u(r,t)},onSaveText:(r,l,t)=>{const a=buildExportFilename(e(),l);if(o)return o(r,a,t);u(new Blob([r],{type:t}),a)}}}
1
+ import{downloadBlob as w}from"./toolbar.js";const _=60,h=180,g=/^(con|prn|aux|nul|com\d|lpt\d)$/i;function i(e){return e.normalize("NFC").replace(/[^\p{L}\p{N}._+-]+/gu,"-").replace(/-{2,}/g,"-").replace(/^[-._]+|[-._]+$/g,"").slice(0,_).replace(/[-._]+$/g,"")}function c(e,t){return/^\d+$/.test(t)?`${e}-${t}`:t}function d(e,t){const r=`_${e.toLowerCase().replace(/[-_.\s]+/g,"_")}_`,n=`_${t.toLowerCase().replace(/[-_.\s]+/g,"_")}_`;return r.includes(n)}export function buildExportFilename(e,t){const r=t.lastIndexOf("."),n=r>=0?t.slice(r):"",f=i(r>=0?t.slice(0,r):t).toLowerCase(),s=e.prefix?.trim()?i(e.prefix):"",o=[];if(e.lots.length===1?o.push({raw:e.lots[0],text:c("lot",e.lots[0])}):e.lots.length>1&&o.push({raw:`${e.lots.length}-lots`,text:`${e.lots.length}-lots`}),e.stackedWafers!==void 0){const l=e.stackedWafers===!0?"stacked":`stacked-${e.stackedWafers}-wafer${e.stackedWafers===1?"":"s"}`;o.push({raw:l,text:l})}else e.wafer!==void 0?o.push({raw:e.wafer,text:c("wafer",e.wafer)}):e.waferCount!==void 0&&e.waferCount>1&&o.push({raw:`${e.waferCount}-wafers`,text:`${e.waferCount}-wafers`});const u=[s];for(const{raw:l,text:$}of o){const p=i($);p&&(s&&(d(s,i(l))||d(s,p))||u.push(p))}u.push(f);let a=u.filter(Boolean).join("_").slice(0,h).replace(/[-_.]+$/g,"");return a||(a="wafermap"),g.test(a)&&(a=`wafermap-${a}`),`${a}${n}`}export function withExportContext(e,t,r){return{onSaveImage:(n,f)=>{const s=buildExportFilename(e(),f);if(t)return t(n,s);w(n,s)},onSaveText:(n,f,s)=>{const o=buildExportFilename(e(),f);if(r)return r(n,o,s);w(new Blob([n],{type:s}),o)}}}
@@ -1,11 +1,11 @@
1
1
  export { WMAP_VERSION, WMAP_BUILD_TIME } from './version.js';
2
- export type { ToCanvasOptions, ToCanvasResult, HitTarget, ViewportTransform } from './toCanvas.js';
2
+ export type { ToCanvasOptions, ViewportTransform } from './toCanvas.js';
3
3
  export { renderWaferMap } from './renderWaferMap.js';
4
4
  export type { RenderOptions, WaferMapController, WaferViewOptions, WaferPreferences, WaferDisplayState } from './renderWaferMap.js';
5
5
  export { renderWaferGallery } from './renderWaferGallery.js';
6
6
  export type { WaferMapDisplayItem, WaferMapDisplayItemFactory, GalleryOptions, GalleryController } from './renderWaferGallery.js';
7
7
  export type { SummaryPanelOptions, FindingsNotice } from './summaryPanel.js';
8
- export type { DieListOptions, DieListDisplayOptions } from './dieList.js';
8
+ export type { DieListDisplayOptions } from './dieList.js';
9
9
  export { collectWarnings, severityOf } from './warnings.js';
10
10
  export type { WarningsOptions } from './warnings.js';
11
11
  export type { InsightsOptions, InsightsView } from './insightsTab.js';
@@ -16,5 +16,4 @@ export { openWaferMapGuide } from './toolbar.js';
16
16
  export { ICONS } from './icons.js';
17
17
  export type { OverlayHandle } from './toolbar.js';
18
18
  export { openReportModal } from './toolbar.js';
19
- export { toCanvas, buildDieListSection, } from './deprecated.js';
20
19
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- export{WMAP_VERSION,WMAP_BUILD_TIME}from"./version.js";export{renderWaferMap}from"./renderWaferMap.js";export{renderWaferGallery}from"./renderWaferGallery.js";export{collectWarnings,severityOf}from"./warnings.js";export{setDetachWindowOpener}from"./toolbar.js";export{openWaferMapGuide}from"./toolbar.js";export{ICONS}from"./icons.js";export{openReportModal}from"./toolbar.js";export{toCanvas,buildDieListSection}from"./deprecated.js";
1
+ export{WMAP_VERSION,WMAP_BUILD_TIME}from"./version.js";export{renderWaferMap}from"./renderWaferMap.js";export{renderWaferGallery}from"./renderWaferGallery.js";export{collectWarnings,severityOf}from"./warnings.js";export{setDetachWindowOpener}from"./toolbar.js";export{openWaferMapGuide}from"./toolbar.js";export{ICONS}from"./icons.js";export{openReportModal}from"./toolbar.js";
@@ -1 +1 @@
1
- import{buildFacetTable as Ye,facetValueOf as Ge,FACET_NONE_VALUE as He}from"../stats/facets.js";import{mergeTestDefs as re}from"../stats/mergeTestDefs.js";import{isParametricTest as Fe}from"../renderer/buildWaferMap.js";import{waferDisplayLabel as Ne,waferIdentityLabel as Ve}from"../core/waferLabel.js";import{hasDrilldownTargets as ie,waferPopulation as _e}from"./chartPopulation.js";import{openDrilldownMenu as Ue}from"./drilldown.js";import{INPUT_DEFAULT_PASS_BINS as R,itemPassBins as ze,passBinsLabel as le}from"../core/passBins.js";import{NO_DATA_FILL as de}from"../renderer/colorMap.js";import{describeWaferPopulation as qe,populationStat as Qe}from"../stats/population.js";import{LEADING as ce,ALPHA as Ke,SPACE as x,EDGE_GUTTER as Z,FONT as W,CLR as k,RADIUS as pe,SHADOW as Xe,controlStyle as ue,wireControlHover as ee,wireTooltip as Je}from"./toolbar.js";import{ICONS as Ze}from"./icons.js";import{renderCapabilityPanel as et}from"./charts/capability.js";import{renderBoxplotPanel as tt}from"./charts/boxplot.js";import{renderTrendPanel as nt}from"./charts/trend.js";import{renderSweepPanel as at}from"./charts/sweep.js";import{sweepAppliesTo as ot}from"../stats/sweep.js";import{renderHistogramPanel as st}from"./charts/histogram.js";import{renderCorrelationPanel as rt}from"./charts/correlation.js";import{renderScatterPanel as it}from"./charts/scatter.js";import{renderBarPanel as fe}from"./charts/barPanel.js";import{renderBinClusterPanel as lt}from"./charts/binCluster.js";import{renderTestPassRatePanel as dt}from"./charts/testPassRate.js";import{QUANTITY as ct}from"./charts/palette.js";import{cardFrameStyle as pt,makeChartGridWrap as V,makeLabeledSelect as ut,makeLinkedGroupSelect as ft}from"./charts/chartShell.js";import{buildYieldData as _,buildYieldDataCombined as me}from"../stats/yield.js";import{buildBinParetoData as mt}from"../stats/binPareto.js";import{buildLotTestSection as bt,buildLotFunctionalSection as gt,buildMetadataStripBox as ht}from"./summaryPanel.js";import{buildRegionYieldData as be,buildRingRegions as yt,buildQuadrantRegions as wt}from"../stats/regions.js";import{renderRegionYieldDiagram as ge}from"./charts/regionYieldDiagram.js";const he=[{key:"overview",label:"Overview"},{key:"distributions",label:"Distributions"},{key:"correlation",label:"Correlation"}],Ct={key:"sweeps",label:"Sweeps"};export function createInsightsTab(v){const{getItems:ye,getLotStats:we,getBinColors:te,getRingCount:Ce,onSaveImage:T,onSaveText:U,openWafer:Y,focusTest:ne}=v,xe=v.showMetadataStrip??!0,j=v.contentInset??Z,p=v.ownerDocument??document,O=p.createElement("div");Object.assign(O.style,{display:"none",flexDirection:"column",width:"100%",paddingTop:"0"});const Se=Z,P=p.createElement("div");Object.assign(P.style,{paddingLeft:Se});const B=p.createElement("div");Object.assign(B.style,{display:"flex",gap:x.xs,alignItems:"center",background:k.menuBg,border:`1px solid ${k.menuBorder}`,borderRadius:pe.container,boxShadow:Xe.panel,padding:`0 ${x.lg}`,marginBottom:x.lg,marginLeft:j,marginRight:j}),B.setAttribute("role","tablist"),B.addEventListener("keydown",e=>{if(e.key!=="ArrowLeft"&&e.key!=="ArrowRight")return;const t=Array.from(B.querySelectorAll('[role="tab"]')),o=t.indexOf(p.activeElement);if(o===-1)return;e.preventDefault();const r=t[(o+(e.key==="ArrowRight"?1:-1)+t.length)%t.length];r.focus(),r.click()});const M=p.createElement("div");Object.assign(M.style,{display:"flex",flexDirection:"column",gap:x.lg,marginTop:"0",paddingLeft:j,paddingRight:j}),O.appendChild(P),O.appendChild(B),O.appendChild(M);const ae=(v.sweeps?.length??0)>0,ve=ae?[...he,Ct]:he;let L=v.defaultView==="sweeps"&&!ae?"overview":v.defaultView??"overview",A,$=null,E=null,G={includeLimits:void 0,clipOutliers:!1};const z=e=>{E!==e&&(E=e,F())};let H=new Map;function oe(){for(const e of H.values())e.destroy();H=new Map}function q(e,t,o){Y?.(e,t,o)}function Q(e){if(e.some(t=>ie(t.testDefs,v.sweeps)))return(t,o,r)=>{const i=e.find(f=>f.waferIndex===t);if(!i||!ie(i.testDefs,v.sweeps))return;r.preventDefault();const l=_e(i.dies,{waferLabel:i.identity,testDefs:i.testDefs,activeTest:o??$??void 0,waferIndex:t});Ue({x:r.clientX,y:r.clientY},r.target,l,{sweeps:v.sweeps,onSaveImage:T})}}function Te(e){return Y?{open:(t,o)=>q(t,`Wafer ${e.find(r=>r.waferIndex===t)?.label??t}`,o)}:ne&&e.length===1?{open:(t,o)=>ne(o),label:"show this test on the map"}:null}function ke(){return ye().map((e,t)=>e==null?null:{metadata:e.wafer.metadata??void 0,dies:e.dies,wafer:e.wafer,label:Ne(e,t),identity:Ve(e),waferIndex:t,passBins:ze(e),statsSummary:e.statsSummary,testDefs:e.testDefs}).filter(e=>e!=null)}function se(e,t){Object.assign(e.style,{background:"none",border:"none",borderBottom:t?`2px solid ${k.iconActive}`:"2px solid transparent",color:t?k.iconActive:k.label,fontWeight:t?"700":"500",fontSize:W.body,padding:`${x.sm} ${Z} ${x.md}`,cursor:"pointer",marginBottom:"-1px"})}function De(e,t){const o=p.createElement("button");o.type="button",o.textContent=t;const r=e===L;return se(o,r),o.dataset.on=r?"true":"false",ee(o,"bare"),o.dataset.wmapInsightsTab=e,o.setAttribute("role","tab"),o.setAttribute("aria-selected",r?"true":"false"),o.tabIndex=r?0:-1,o.addEventListener("click",()=>{L!==e&&(L=e,F({keepSections:!0}))}),o}function Be(e){const t=p.createElement("button");return t.type="button",t.textContent=`\u2039 ${e.label}`,se(t,!1),t.dataset.wmapInsightsBack="1",t.addEventListener("click",e.onBack),t}function $e(e,t,o,r=!0){const i=V(p),l=te();let f="label";const u=o??"group",m=le(e.map(c=>c.passBins)),d=we?.(),g=new Map(d?.lotYieldSeries.map(c=>[c.waferIndex,c.yieldPercent])),C=c=>({...c,label:c.label.replace(/\s*·\s*\d+(\.\d+)?%$/,""),yieldPercent:g.get(c.waferIndex),key:c.waferIndex}),b=e.map(C),h=t?.map(c=>({key:c.key,items:c.items.map(C)})),S=()=>h?me(h,R,f):_(b,R,f),w={title:t?`Yield by ${u} (pass: ${m})`:`Yield by wafer (pass: ${m})`,data:S(),selfControl:{current:f,options:[["yield","Sort: yield"],["label",t?`Sort: ${u}`:"Sort: wafer ID"]],onChange:c=>(f=c,{data:S()})},barColor:()=>ct,valueLabel:c=>`${c.percent.toFixed(1)}%`,reference:c=>{if(c.length<3)return null;const D=c.map(J=>J.percent).sort((J,Me)=>J-Me),I=D.length%2?D[(D.length-1)/2]:(D[D.length/2-1]+D[D.length/2])/2;return{value:I,label:`median ${I.toFixed(1)}%`}},drill:h?{onOpenGroup:c=>{const D=h.find(I=>I.key===c.label)?.items??[];return{data:_(D,R,f),title:`Yield by wafer \u2014 ${u}: ${c.label} (pass: ${m})`}},onBack:()=>({data:S(),title:`Yield by ${u} (pass: ${m})`}),groupLabelText:u}:void 0,onOpen:Y?c=>{typeof c.key=="number"&&q(c.key,`Wafer ${c.label}`)}:void 0,onWaferContextMenu:Q(e),ownerDocument:p};let n=null;if(r&&(n=fe(w,T),n.card.style.minHeight="360px",i.appendChild(n.card)),t){const c=lt({title:"Hard bin pareto",groups:t.map(D=>({key:D.key,items:D.items.map(I=>({dies:I.dies,hardBinCounts:I.statsSummary?.stats.hardBinCounts,softBinCounts:I.statsSummary?.stats.softBinCounts}))})),onSaveImage:T,ownerDocument:p});return c.card.style.minHeight="360px",i.appendChild(c.card),{card:i,destroy:()=>{n?.destroy(),c.destroy()}}}let a="hbin";const s=c=>c===void 0?de:(a==="hbin"?l.hard:l.soft).get(c)??de,y=e.map(c=>({dies:c.dies,hardBinCounts:c.statsSummary?.stats.hardBinCounts,softBinCounts:c.statsSummary?.stats.softBinCounts})),N=()=>mt(y,a),je={title:"Hard bin pareto",data:N(),selfControl:{current:a,options:[["hbin","Hard bins"],["sbin","Soft bins"]],onChange:c=>(a=c,{data:N(),title:`${a==="hbin"?"Hard":"Soft"} bin pareto`})},barColor:c=>s(c.binCode),ownerDocument:p},X=fe(je,T);return X.card.style.minHeight="360px",i.appendChild(X.card),{card:i,destroy:()=>{n?.destroy(),X.destroy()}}}function K(){const e=p.createElement("div");return e.dataset.wmapChartCard="1",Object.assign(e.style,{...pt(),display:"flex",flexDirection:"column",gap:x.lg,minWidth:"0"}),e}function Ee(e){if(P.innerHTML="",P.style.marginBottom="0",!xe)return;const t=ht(e.map(o=>({metadata:o.metadata})),void 0,{facetableOnly:!1});t&&(t.style.marginBottom="0",P.appendChild(t),P.style.marginBottom=x.xs)}function Le(e,t,o,r){if(!e.length)return{elements:[],testValuesCard:null,functionalCard:null,destroy:()=>{}};const i=e.map(s=>s.wafer),l=e.map(s=>s.dies),f=e.flatMap(s=>s.dies),u=e.map(s=>s.statsSummary),m=u.every(s=>s!==void 0)?u:void 0,d=Ce?.()??4,g=[],C=[],h=dt({groups:(r??[{key:"",items:e}]).map(s=>({key:s.key,items:s.items.map(y=>({dies:y.dies,testSpecYield:y.statsSummary?.stats.testSpecYield,functionalYield:y.statsSummary?.stats.functionalYield}))})),testDefs:o,onSaveImage:T,ownerDocument:p});h.card.style.minHeight="300px",g.push(h.card),C.push(h.destroy);const S=be(l,i,d,s=>e[s].passBins,yt);if(S.length){const s=ge({title:"Ring yield",mode:"ring",rows:S,onSaveImage:T,ownerDocument:p});g.push(s.card),C.push(s.destroy)}const w=be(l,i,d,s=>e[s].passBins,wt);if(w.length){const s=ge({title:"Quadrant yield",mode:"quadrant",rows:w,onSaveImage:T,ownerDocument:p});g.push(s.card),C.push(s.destroy)}let n=null;if(t.length){const s=bt(f,t,void 0,m,U,l.map(y=>({dies:y})),void 0,"full");if(s){const y=K();y.appendChild(s),n=y}}let a=null;if(o.length){const s=gt(f,o,m,U);if(s){const y=K();y.appendChild(s),a=y}}return{elements:g,testValuesCard:n,functionalCard:a,destroy:()=>{for(const s of C)s()}}}function Ie(e){const t=le(e.map(d=>d.passBins)),o=e.length===1,r=e[0],i=K();Object.assign(i.style,{flexDirection:"row",flexWrap:"wrap",gap:x.md});const l=d=>{const g=d.lastElementChild;return g&&Object.assign(g.style,{borderRight:"none",paddingRight:"0",marginRight:"0"}),d};function f(d,g,C){const b=p.createElement("div");Object.assign(b.style,{display:"flex",alignItems:"baseline",gap:x.sm,paddingRight:x.xxl,marginRight:x.md,borderRight:`1px solid ${k.menuBorder}`});const h=p.createElement("div");h.textContent=d,Object.assign(h.style,{fontSize:W.heading,fontWeight:"700",color:k.value,lineHeight:ce.tight});const S=p.createElement("div");if(S.textContent=g,Object.assign(S.style,{fontSize:W.body,color:k.label}),b.append(h,S),C){const w=p.createElement("div");w.textContent=C,Object.assign(w.style,{fontSize:W.meta,color:k.label,opacity:Ke.muted}),b.appendChild(w)}return b}if(o){const d=_([{...r,key:r.waferIndex}],R)[0]?.percent;return d!==void 0&&i.appendChild(f(`${d.toFixed(1)}%`,`Yield \xB7 pass: ${t}`)),i.appendChild(f(String(r.dies.length),"Total dies")),l(i)}i.appendChild(f(String(e.length),"Wafers"));const u=_(e.map(d=>({...d,key:d.waferIndex})),R).map(d=>d.percent).filter(d=>Number.isFinite(d));if(u.length){const d=u.reduce((b,h)=>b+h,0)/u.length,g=me([{key:"all",items:e.map(b=>({...b,key:b.waferIndex}))}],R)[0]?.percent,C=g!==void 0&&g.toFixed(1)!==d.toFixed(1);i.appendChild(f(`${d.toFixed(1)}%`,`Mean per-wafer yield \xB7 pass: ${t}`,C?`${g.toFixed(1)}% by dies`:void 0))}const m=e.map(d=>d.statsSummary);if(m.every(d=>d!==void 0)){const d=m.reduce((C,b)=>C+b.stats.analyzedDies,0),g=m.reduce((C,b)=>C+b.stats.excludedDies,0);i.appendChild(f(d.toLocaleString(),"Dies analysed",g?`${g.toLocaleString()} excluded`:void 0))}else i.appendChild(f(e.reduce((d,g)=>d+g.dies.length,0).toLocaleString(),"Total dies"));return l(i)}function Oe(e,t,o,r,i){const l=p.createElement("div");Object.assign(l.style,{display:"flex",flexDirection:"column",gap:x.lg});const f=e.length===1&&!r;e.length&&!r&&l.appendChild(Ie(e));const u=$e(e,r,i,!f);l.appendChild(u.card);const m=Le(e,t,o,r);for(const d of m.elements)u.card.appendChild(d);return m.testValuesCard&&l.appendChild(m.testValuesCard),m.functionalCard&&l.appendChild(m.functionalCard),{card:l,destroy:()=>{u.destroy(),m.destroy()}}}function Pe(e,t,o,r){const i=V(p),l=Te(e),f=a=>{G=a;for(const s of[b,h,S])s!==u&&s?.setAxisPrefs(a)};let u=null;const m=a=>s=>{u=a(),f(s),u=null},d=a=>({...a,testStats:a.statsSummary?.stats.perTestStats}),g=e.map(d),C=o?.map(a=>({key:a.key,items:a.items.map(d)})),b=tt({title:"Test value distribution",axisPrefs:G,onAxisPrefsChange:m(()=>b),onTestChange:a=>w(a),selectedTestNumber:$??void 0,items:g,testDefs:t,groups:C,groupLabelText:r,onSaveImage:T,onGroupChange:a=>z(a),onOpen:l?.open,openActionLabel:l?.label,onWaferContextMenu:Q(e),ownerDocument:p}),h=st({title:"Value histogram",axisPrefs:G,onAxisPrefsChange:m(()=>h),onTestChange:a=>w(a),selectedTestNumber:$??void 0,items:e,testDefs:t,groups:o,onGroupChange:a=>z(a),onSaveImage:T,ownerDocument:p}),S=nt({title:"Wafer-to-wafer trend",axisPrefs:G,onAxisPrefsChange:m(()=>S),onTestChange:a=>w(a),selectedTestNumber:$??void 0,items:e.map(a=>({label:a.label,key:a.waferIndex,dies:a.dies,testStats:a.statsSummary?.stats.perTestStats})),testDefs:t,onSaveImage:T,centreLabel:Qe(qe(e.map(a=>a.wafer.metadata)),"mean"),onOpen:Y?(a,s)=>q(a,`Wafer ${e.find(y=>y.waferIndex===a)?.label??a}`,s):void 0,onWaferContextMenu:Q(e),ownerDocument:p}),w=a=>{$=a,b.setTest(a),h.setTest(a),S.setTest(a),n.setTest(a)},n=et({title:"Process capability",items:e,testDefs:t,onSaveImage:T,selectedTestNumber:$??void 0,onSelectTest:a=>w(a),ownerDocument:p});return i.append(n.card,b.card,h.card,S.card),{card:i,destroy:()=>{n.destroy(),b.destroy(),h.destroy(),S.destroy()}}}function Ae(e){const t=V(p),o=re(e).defs,r=e.flatMap(u=>u.dies),i=v.sweeps??[],l=i.filter(u=>!ot(u,o));l.length>0&&t.appendChild(Re(l,i.length));const f=i.map(u=>at({spec:u,dies:r,testDefs:o,onSaveImage:T,ownerDocument:p}));for(const u of f)t.appendChild(u.card);return{card:t,destroy:()=>{for(const u of f)u.destroy()}}}function Re(e,t){const o=p.createElement("div");o.setAttribute("role","status"),Object.assign(o.style,{gridColumn:"1 / -1",display:"flex",flexWrap:"wrap",alignItems:"center",gap:x.md,padding:`${x.sm} ${x.md}`,background:k.warnBg,border:`1px solid ${k.warnBorder}`,borderRadius:pe.container,color:k.warnText,fontSize:W.body,lineHeight:ce.base});const r=e.length,i=p.createElement("span");if(i.style.flex="1 1 24ch",i.textContent=(r===t?r===1?"This sweep names no test in this data":"None of these sweeps names a test in this data":`${r} of ${t} sweeps name no test in this data: ${e.map(l=>l.title).join(", ")}`)+` \u2014 ${r===1?"it":"they"} may belong to another test program.`,o.appendChild(i),v.onRemoveSweeps){const l=p.createElement("button");l.type="button",Object.assign(l.style,ue("outlined")),l.textContent=r===1?"Remove this sweep":`Remove these ${r} sweeps`,ee(l);const f=e.map(u=>u.id);l.addEventListener("click",()=>v.onRemoveSweeps(f)),o.appendChild(l)}return o}function We(e,t,o){const r=V(p),i=it({title:"Test scatter",items:e,testDefs:t,groups:o,binColors:te().hard,onSaveImage:T,ownerDocument:p}),l=rt({title:"Test correlation matrix",items:e,testDefs:t,onSaveImage:T,onSaveText:U,onSelectPair:(f,u)=>i.setXY(f,u),ownerDocument:p});return r.append(l.card,i.card),{card:r,destroy:()=>{l.destroy(),i.destroy()}}}function F(e){e?.keepSections||oe(),M.innerHTML="",B.innerHTML="",v.backTab&&B.appendChild(Be(v.backTab));for(const n of ve)B.appendChild(De(n.key,n.label));const t=ke();Ee(t);const o=Ye(t,{facetableOnly:!0}).filter(n=>n.splittable),r=p.createElement("div");Object.assign(r.style,{display:"flex",gap:x.md,alignItems:"center",marginLeft:x.xxl,paddingBottom:x.xs});let i;o.length>0?(r.appendChild(ut("Group by:",[{value:"",label:"None"},...o.map(n=>({value:n.key,label:`${n.label} (${n.values.length})`}))],A??"",n=>{A=n||void 0,E=null,F()},{hook:"group-by",ownerDocument:p})),i=o.find(n=>n.key===A)?.label):A=void 0;let l;if(A){const n=new Map,a=[];for(const s of t){const y=Ge(s.metadata,A)??He;n.has(y)||(n.set(y,[]),a.push(y)),n.get(y).push(s)}l=a.map(s=>({key:s,items:n.get(s)}))}E!==null&&!l?.some(n=>n.key===E)&&(E=null),l&&l.length>0&&r.appendChild(ft(l.map(n=>n.key),"Show:",E,n=>z(n),{ownerDocument:p}).el);let f=null;if(v.onOpenGuide){const n=p.createElement("button");n.type="button",n.innerHTML=Ze.help,n.setAttribute("aria-label","User guide"),Object.assign(n.style,{...ue("bare"),display:"inline-flex",alignItems:"center",justifyContent:"center",width:"24px",height:"24px",flexShrink:"0"}),ee(n,"bare"),Je(n,"User guide"),n.addEventListener("click",()=>v.onOpenGuide()),Object.assign(n.style,{marginLeft:"auto"}),f=n}B.appendChild(r),f&&B.appendChild(f);const u=E!==null?l?.find(n=>n.key===E):void 0,m=u?.items??t,d=u?void 0:l,g=re(m),C=g.defs,b=C.filter(Fe);$!==null&&!b.some(n=>n.testNumber===$)&&($=null);const h=e?.keepSections?H.get(L):void 0,S=h??(L==="overview"?Oe(m,b,C,d,i):L==="distributions"?Pe(m,b,d,i):L==="sweeps"?Ae(m):We(m,b,d));h||H.set(L,S);const w=g.conflicts.filter(n=>n.excluded);if(w.length>0){const n=p.createElement("div");Object.assign(n.style,{color:k.label,fontSize:W.body,padding:`0 ${j} ${x.sm}`});const a=w.slice(0,6).map(N=>N.testNumber).join(", "),s=w.length>6?`, and ${w.length-6} more`:"",y=w.length===1?"it":"them";n.textContent=`${w.length} test ${w.length===1?"number is":"numbers are"} hidden (${a}${s}) \u2014 the wafers in view describe ${y} differently, so their values cannot be pooled. `+(l&&l.length>0?`Pick one ${i??"group"} under "Show:" to analyse ${y}.`:"Load one test program at a time to analyse them."),n.dataset.wmapWithheldTests=String(w.length),M.appendChild(n)}M.appendChild(S.card)}return{el:O,render:F,destroy:()=>{oe(),O.remove()}}}
1
+ import{buildFacetTable as He,facetValueOf as Fe,FACET_NONE_VALUE as Ne}from"../stats/facets.js";import{mergeTestDefs as le}from"../stats/mergeTestDefs.js";import{isParametricTest as Ve}from"../renderer/buildWaferMap.js";import{waferDisplayLabel as _e,waferIdentityLabel as Ue}from"../core/waferLabel.js";import{hasDrilldownTargets as de,waferPopulation as ze}from"./chartPopulation.js";import{openDrilldownMenu as qe}from"./drilldown.js";import{INPUT_DEFAULT_PASS_BINS as R,itemPassBins as Qe,passBinsLabel as ce}from"../core/passBins.js";import{NO_DATA_FILL as pe}from"../renderer/colorMap.js";import{describeWaferPopulation as Ke,populationStat as Xe}from"../stats/population.js";import{LEADING as ue,ALPHA as Je,SPACE as C,EDGE_GUTTER as ee,FONT as W,CLR as k,RADIUS as fe,SHADOW as Ze,controlStyle as me,wireControlHover as te,wireTooltip as et}from"./toolbar.js";import{ICONS as tt}from"./icons.js";import{renderCapabilityPanel as nt}from"./charts/capability.js";import{renderBoxplotPanel as at}from"./charts/boxplot.js";import{renderTrendPanel as ot}from"./charts/trend.js";import{renderSweepPanel as st}from"./charts/sweep.js";import{sweepAppliesTo as rt}from"../stats/sweep.js";import{renderHistogramPanel as it}from"./charts/histogram.js";import{renderCorrelationPanel as lt}from"./charts/correlation.js";import{renderScatterPanel as dt}from"./charts/scatter.js";import{renderBarPanel as be}from"./charts/barPanel.js";import{renderBinClusterPanel as ct}from"./charts/binCluster.js";import{renderTestPassRatePanel as pt}from"./charts/testPassRate.js";import{QUANTITY as ut}from"./charts/palette.js";import{cardFrameStyle as ft,makeChartGridWrap as V,makeLabeledSelect as mt,makeLinkedGroupSelect as bt}from"./charts/chartShell.js";import{buildYieldData as _,buildYieldDataCombined as ge}from"../stats/yield.js";import{buildBinParetoData as gt}from"../stats/binPareto.js";import{buildLotTestSection as ht,buildLotFunctionalSection as yt,buildMetadataStripBox as wt}from"./summaryPanel.js";import{buildRegionYieldData as he,buildRingRegions as Ct,buildQuadrantRegions as xt}from"../stats/regions.js";import{renderRegionYieldDiagram as ye}from"./charts/regionYieldDiagram.js";const we=[{key:"overview",label:"Overview"},{key:"distributions",label:"Distributions"},{key:"correlation",label:"Correlation"}],St={key:"sweeps",label:"Sweeps"};export function createInsightsTab(x){const{getItems:Ce,getLotStats:xe,getBinColors:ne,getRingCount:Se,onSaveImage:T,onSaveText:U,openWafer:G,focusTest:ae}=x,ve=x.showMetadataStrip??!0,M=x.contentInset??ee,p=x.ownerDocument??document,I=p.createElement("div");Object.assign(I.style,{display:"none",flexDirection:"column",width:"100%",paddingTop:"0"});const Te=ee,O=p.createElement("div");Object.assign(O.style,{paddingLeft:Te});const B=p.createElement("div");Object.assign(B.style,{display:"flex",gap:C.xs,alignItems:"center",background:k.menuBg,border:`1px solid ${k.menuBorder}`,borderRadius:fe.container,boxShadow:Ze.panel,padding:`0 ${C.lg}`,marginBottom:C.lg,marginLeft:M,marginRight:M}),B.setAttribute("role","tablist"),B.addEventListener("keydown",e=>{if(e.key!=="ArrowLeft"&&e.key!=="ArrowRight")return;const t=Array.from(B.querySelectorAll('[role="tab"]')),a=t.indexOf(p.activeElement);if(a===-1)return;e.preventDefault();const s=t[(a+(e.key==="ArrowRight"?1:-1)+t.length)%t.length];s.focus(),s.click()});const j=p.createElement("div");Object.assign(j.style,{display:"flex",flexDirection:"column",gap:C.lg,marginTop:"0",paddingLeft:M,paddingRight:M}),I.appendChild(O),I.appendChild(B),I.appendChild(j);const oe=(x.sweeps?.length??0)>0,ke=oe?[...we,St]:we;let L=x.defaultView==="sweeps"&&!oe?"overview":x.defaultView??"overview",A,$=null,E=null,Y={includeLimits:void 0,clipOutliers:!1,limits:"both"};const z=new Map,se=(e,t)=>{Y=e;for(const a of z.values())for(const s of a)s!==t&&s.setAxisPrefs(e)},q=e=>{E!==e&&(E=e,F())};let H=new Map;function re(){for(const e of H.values())e.destroy();H=new Map}function Q(e,t,a){G?.(e,t,a)}function K(e){if(e.some(t=>de(t.testDefs,x.sweeps)))return(t,a,s)=>{const r=e.find(u=>u.waferIndex===t);if(!r||!de(r.testDefs,x.sweeps))return;s.preventDefault();const i=ze(r.dies,{waferLabel:r.identity,testDefs:r.testDefs,activeTest:a??$??void 0,waferIndex:t});qe({x:s.clientX,y:s.clientY},s.target,i,{sweeps:x.sweeps,onSaveImage:T})}}function De(e){return G?{open:(t,a)=>Q(t,`Wafer ${e.find(s=>s.waferIndex===t)?.label??t}`,a)}:ae&&e.length===1?{open:(t,a)=>ae(a),label:"show this test on the map"}:null}function Be(){return Ce().map((e,t)=>e==null?null:{metadata:e.wafer.metadata??void 0,dies:e.dies,wafer:e.wafer,label:_e(e,t),identity:Ue(e),waferIndex:t,passBins:Qe(e),statsSummary:e.statsSummary,testDefs:e.testDefs}).filter(e=>e!=null)}function ie(e,t){Object.assign(e.style,{background:"none",border:"none",borderBottom:t?`2px solid ${k.iconActive}`:"2px solid transparent",color:t?k.iconActive:k.label,fontWeight:t?"700":"500",fontSize:W.body,padding:`${C.sm} ${ee} ${C.md}`,cursor:"pointer",marginBottom:"-1px"})}function $e(e,t){const a=p.createElement("button");a.type="button",a.textContent=t;const s=e===L;return ie(a,s),a.dataset.on=s?"true":"false",te(a,"bare"),a.dataset.wmapInsightsTab=e,a.setAttribute("role","tab"),a.setAttribute("aria-selected",s?"true":"false"),a.tabIndex=s?0:-1,a.addEventListener("click",()=>{L!==e&&(L=e,F({keepSections:!0}))}),a}function Ee(e){const t=p.createElement("button");return t.type="button",t.textContent=`\u2039 ${e.label}`,ie(t,!1),t.dataset.wmapInsightsBack="1",t.addEventListener("click",e.onBack),t}function Le(e,t,a,s=!0){const r=V(p),i=ne();let u="label";const f=a??"group",g=ce(e.map(l=>l.passBins)),d=xe?.(),m=new Map(d?.lotYieldSeries.map(l=>[l.waferIndex,l.yieldPercent])),h=l=>({...l,label:l.label.replace(/\s*·\s*\d+(\.\d+)?%$/,""),yieldPercent:m.get(l.waferIndex),key:l.waferIndex}),b=e.map(h),y=t?.map(l=>({key:l.key,items:l.items.map(h)})),S=()=>y?ge(y,R,u):_(b,R,u),o={title:t?`Yield by ${f} (pass: ${g})`:`Yield by wafer (pass: ${g})`,data:S(),selfControl:{current:u,options:[["yield","Sort: yield"],["label",t?`Sort: ${f}`:"Sort: wafer ID"]],onChange:l=>(u=l,{data:S()})},barColor:()=>ut,valueLabel:l=>`${l.percent.toFixed(1)}%`,reference:l=>{if(l.length<3)return null;const D=l.map(Z=>Z.percent).sort((Z,Ge)=>Z-Ge),P=D.length%2?D[(D.length-1)/2]:(D[D.length/2-1]+D[D.length/2])/2;return{value:P,label:`median ${P.toFixed(1)}%`}},drill:y?{onOpenGroup:l=>{const D=y.find(P=>P.key===l.label)?.items??[];return{data:_(D,R,u),title:`Yield by wafer \u2014 ${f}: ${l.label} (pass: ${g})`}},onBack:()=>({data:S(),title:`Yield by ${f} (pass: ${g})`}),groupLabelText:f}:void 0,onOpen:G?l=>{typeof l.key=="number"&&Q(l.key,`Wafer ${l.label}`)}:void 0,onWaferContextMenu:K(e),ownerDocument:p};let n=null;if(s&&(n=be(o,T),n.card.style.minHeight="360px",r.appendChild(n.card)),t){const l=ct({title:"Hard bin pareto",groups:t.map(D=>({key:D.key,items:D.items.map(P=>({dies:P.dies,hardBinCounts:P.statsSummary?.stats.hardBinCounts,softBinCounts:P.statsSummary?.stats.softBinCounts}))})),onSaveImage:T,ownerDocument:p});return l.card.style.minHeight="360px",r.appendChild(l.card),{card:r,destroy:()=>{n?.destroy(),l.destroy()}}}let v="hbin";const c=l=>l===void 0?pe:(v==="hbin"?i.hard:i.soft).get(l)??pe,w=e.map(l=>({dies:l.dies,hardBinCounts:l.statsSummary?.stats.hardBinCounts,softBinCounts:l.statsSummary?.stats.softBinCounts})),N=()=>gt(w,v),Ye={title:"Hard bin pareto",data:N(),selfControl:{current:v,options:[["hbin","Hard bins"],["sbin","Soft bins"]],onChange:l=>(v=l,{data:N(),title:`${v==="hbin"?"Hard":"Soft"} bin pareto`})},barColor:l=>c(l.binCode),ownerDocument:p},J=be(Ye,T);return J.card.style.minHeight="360px",r.appendChild(J.card),{card:r,destroy:()=>{n?.destroy(),J.destroy()}}}function X(){const e=p.createElement("div");return e.dataset.wmapChartCard="1",Object.assign(e.style,{...ft(),display:"flex",flexDirection:"column",gap:C.lg,minWidth:"0"}),e}function Pe(e){if(O.innerHTML="",O.style.marginBottom="0",!ve)return;const t=wt(e.map(a=>({metadata:a.metadata})),void 0,{facetableOnly:!1});t&&(t.style.marginBottom="0",O.appendChild(t),O.style.marginBottom=C.xs)}function Ie(e,t,a,s){if(!e.length)return{elements:[],testValuesCard:null,functionalCard:null,destroy:()=>{}};const r=e.map(c=>c.wafer),i=e.map(c=>c.dies),u=e.flatMap(c=>c.dies),f=e.map(c=>c.statsSummary),g=f.every(c=>c!==void 0)?f:void 0,d=Se?.()??4,m=[],h=[],y=pt({groups:(s??[{key:"",items:e}]).map(c=>({key:c.key,items:c.items.map(w=>({dies:w.dies,testSpecYield:w.statsSummary?.stats.testSpecYield,functionalYield:w.statsSummary?.stats.functionalYield}))})),testDefs:a,onSaveImage:T,ownerDocument:p});y.card.style.minHeight="300px",m.push(y.card),h.push(y.destroy);const S=he(i,r,d,c=>e[c].passBins,Ct);if(S.length){const c=ye({title:"Ring yield",mode:"ring",rows:S,onSaveImage:T,ownerDocument:p});m.push(c.card),h.push(c.destroy)}const o=he(i,r,d,c=>e[c].passBins,xt);if(o.length){const c=ye({title:"Quadrant yield",mode:"quadrant",rows:o,onSaveImage:T,ownerDocument:p});m.push(c.card),h.push(c.destroy)}let n=null;if(t.length){const c=ht(u,t,void 0,g,U,i.map(w=>({dies:w})),void 0,"full");if(c){const w=X();w.appendChild(c),n=w}}let v=null;if(a.length){const c=yt(u,a,g,U);if(c){const w=X();w.appendChild(c),v=w}}return{elements:m,testValuesCard:n,functionalCard:v,destroy:()=>{for(const c of h)c()}}}function Oe(e){const t=ce(e.map(d=>d.passBins)),a=e.length===1,s=e[0],r=X();Object.assign(r.style,{flexDirection:"row",flexWrap:"wrap",gap:C.md});const i=d=>{const m=d.lastElementChild;return m&&Object.assign(m.style,{borderRight:"none",paddingRight:"0",marginRight:"0"}),d};function u(d,m,h){const b=p.createElement("div");Object.assign(b.style,{display:"flex",alignItems:"baseline",gap:C.sm,paddingRight:C.xxl,marginRight:C.md,borderRight:`1px solid ${k.menuBorder}`});const y=p.createElement("div");y.textContent=d,Object.assign(y.style,{fontSize:W.heading,fontWeight:"700",color:k.value,lineHeight:ue.tight});const S=p.createElement("div");if(S.textContent=m,Object.assign(S.style,{fontSize:W.body,color:k.label}),b.append(y,S),h){const o=p.createElement("div");o.textContent=h,Object.assign(o.style,{fontSize:W.meta,color:k.label,opacity:Je.muted}),b.appendChild(o)}return b}if(a){const d=_([{...s,key:s.waferIndex}],R)[0]?.percent;return d!==void 0&&r.appendChild(u(`${d.toFixed(1)}%`,`Yield \xB7 pass: ${t}`)),r.appendChild(u(String(s.dies.length),"Total dies")),i(r)}r.appendChild(u(String(e.length),"Wafers"));const f=_(e.map(d=>({...d,key:d.waferIndex})),R).map(d=>d.percent).filter(d=>Number.isFinite(d));if(f.length){const d=f.reduce((b,y)=>b+y,0)/f.length,m=ge([{key:"all",items:e.map(b=>({...b,key:b.waferIndex}))}],R)[0]?.percent,h=m!==void 0&&m.toFixed(1)!==d.toFixed(1);r.appendChild(u(`${d.toFixed(1)}%`,`Mean per-wafer yield \xB7 pass: ${t}`,h?`${m.toFixed(1)}% by dies`:void 0))}const g=e.map(d=>d.statsSummary);if(g.every(d=>d!==void 0)){const d=g.reduce((h,b)=>h+b.stats.analyzedDies,0),m=g.reduce((h,b)=>h+b.stats.excludedDies,0);r.appendChild(u(d.toLocaleString(),"Dies analysed",m?`${m.toLocaleString()} excluded`:void 0))}else r.appendChild(u(e.reduce((d,m)=>d+m.dies.length,0).toLocaleString(),"Total dies"));return i(r)}function Ae(e,t,a,s,r){const i=p.createElement("div");Object.assign(i.style,{display:"flex",flexDirection:"column",gap:C.lg});const u=e.length===1&&!s;e.length&&!s&&i.appendChild(Oe(e));const f=Le(e,s,r,!u);i.appendChild(f.card);const g=Ie(e,t,a,s);for(const d of g.elements)f.card.appendChild(d);return g.testValuesCard&&i.appendChild(g.testValuesCard),g.functionalCard&&i.appendChild(g.functionalCard),{card:i,destroy:()=>{f.destroy(),g.destroy()}}}function Re(e,t,a,s){const r=V(p),i=De(e),u=o=>n=>se(n,o()),f=o=>({...o,testStats:o.statsSummary?.stats.perTestStats}),g=e.map(f),d=a?.map(o=>({key:o.key,items:o.items.map(f)})),m=at({title:"Test value distribution",axisPrefs:Y,onAxisPrefsChange:u(()=>m),onTestChange:o=>y(o),selectedTestNumber:$??void 0,items:g,testDefs:t,groups:d,groupLabelText:s,onSaveImage:T,onGroupChange:o=>q(o),onOpen:i?.open,openActionLabel:i?.label,onWaferContextMenu:K(e),ownerDocument:p}),h=it({title:"Value histogram",axisPrefs:Y,onAxisPrefsChange:u(()=>h),onTestChange:o=>y(o),selectedTestNumber:$??void 0,items:e,testDefs:t,groups:a,onGroupChange:o=>q(o),onSaveImage:T,ownerDocument:p}),b=ot({title:"Wafer-to-wafer trend",axisPrefs:Y,onAxisPrefsChange:u(()=>b),onTestChange:o=>y(o),selectedTestNumber:$??void 0,items:e.map(o=>({label:o.label,key:o.waferIndex,dies:o.dies,testStats:o.statsSummary?.stats.perTestStats})),testDefs:t,onSaveImage:T,centreLabel:Xe(Ke(e.map(o=>o.wafer.metadata)),"mean"),onOpen:G?(o,n)=>Q(o,`Wafer ${e.find(v=>v.waferIndex===o)?.label??o}`,n):void 0,onWaferContextMenu:K(e),ownerDocument:p}),y=o=>{$=o,m.setTest(o),h.setTest(o),b.setTest(o),S.setTest(o)};z.set("distribution",[m,h,b]);const S=nt({title:"Process capability",items:e,testDefs:t,onSaveImage:T,selectedTestNumber:$??void 0,onSelectTest:o=>y(o),ownerDocument:p});return r.append(S.card,m.card,h.card,b.card),{card:r,destroy:()=>{S.destroy(),m.destroy(),h.destroy(),b.destroy()}}}function We(e){const t=V(p),a=le(e).defs,s=e.flatMap(f=>f.dies),r=x.sweeps??[],i=r.filter(f=>!rt(f,a));i.length>0&&t.appendChild(Me(i,r.length));const u=r.map(f=>st({spec:f,dies:s,testDefs:a,onSaveImage:T,ownerDocument:p}));for(const f of u)t.appendChild(f.card);return{card:t,destroy:()=>{for(const f of u)f.destroy()}}}function Me(e,t){const a=p.createElement("div");a.setAttribute("role","status"),Object.assign(a.style,{gridColumn:"1 / -1",display:"flex",flexWrap:"wrap",alignItems:"center",gap:C.md,padding:`${C.sm} ${C.md}`,background:k.warnBg,border:`1px solid ${k.warnBorder}`,borderRadius:fe.container,color:k.warnText,fontSize:W.body,lineHeight:ue.base});const s=e.length,r=p.createElement("span");if(r.style.flex="1 1 24ch",r.textContent=(s===t?s===1?"This sweep names no test in this data":"None of these sweeps names a test in this data":`${s} of ${t} sweeps name no test in this data: ${e.map(i=>i.title).join(", ")}`)+` \u2014 ${s===1?"it":"they"} may belong to another test program.`,a.appendChild(r),x.onRemoveSweeps){const i=p.createElement("button");i.type="button",Object.assign(i.style,me("outlined")),i.textContent=s===1?"Remove this sweep":`Remove these ${s} sweeps`,te(i);const u=e.map(f=>f.id);i.addEventListener("click",()=>x.onRemoveSweeps(u)),a.appendChild(i)}return a}function je(e,t,a){const s=V(p),r=dt({title:"Test scatter",items:e,testDefs:t,groups:a,binColors:ne().hard,onSaveImage:T,axisPrefs:Y,onAxisPrefsChange:u=>se(u,r),ownerDocument:p});z.set("correlation",[r]);const i=lt({title:"Test correlation matrix",items:e,testDefs:t,onSaveImage:T,onSaveText:U,onSelectPair:(u,f)=>r.setXY(u,f),ownerDocument:p});return s.append(i.card,r.card),{card:s,destroy:()=>{i.destroy(),r.destroy()}}}function F(e){e?.keepSections||re(),j.innerHTML="",B.innerHTML="",x.backTab&&B.appendChild(Ee(x.backTab));for(const n of ke)B.appendChild($e(n.key,n.label));const t=Be();Pe(t);const a=He(t,{facetableOnly:!0}).filter(n=>n.splittable),s=p.createElement("div");Object.assign(s.style,{display:"flex",gap:C.md,alignItems:"center",marginLeft:C.xxl,paddingBottom:C.xs});let r;a.length>0?(s.appendChild(mt("Group by:",[{value:"",label:"None"},...a.map(n=>({value:n.key,label:`${n.label} (${n.values.length})`}))],A??"",n=>{A=n||void 0,E=null,F()},{hook:"group-by",ownerDocument:p})),r=a.find(n=>n.key===A)?.label):A=void 0;let i;if(A){const n=new Map,v=[];for(const c of t){const w=Fe(c.metadata,A)??Ne;n.has(w)||(n.set(w,[]),v.push(w)),n.get(w).push(c)}i=v.map(c=>({key:c,items:n.get(c)}))}E!==null&&!i?.some(n=>n.key===E)&&(E=null),i&&i.length>0&&s.appendChild(bt(i.map(n=>n.key),"Show:",E,n=>q(n),{ownerDocument:p}).el);let u=null;if(x.onOpenGuide){const n=p.createElement("button");n.type="button",n.innerHTML=tt.help,n.setAttribute("aria-label","User guide"),Object.assign(n.style,{...me("bare"),display:"inline-flex",alignItems:"center",justifyContent:"center",width:"24px",height:"24px",flexShrink:"0"}),te(n,"bare"),et(n,"User guide"),n.addEventListener("click",()=>x.onOpenGuide()),Object.assign(n.style,{marginLeft:"auto"}),u=n}B.appendChild(s),u&&B.appendChild(u);const f=E!==null?i?.find(n=>n.key===E):void 0,g=f?.items??t,d=f?void 0:i,m=le(g),h=m.defs,b=h.filter(Ve);$!==null&&!b.some(n=>n.testNumber===$)&&($=null);const y=e?.keepSections?H.get(L):void 0,S=y??(L==="overview"?Ae(g,b,h,d,r):L==="distributions"?Re(g,b,d,r):L==="sweeps"?We(g):je(g,b,d));y||H.set(L,S);const o=m.conflicts.filter(n=>n.excluded);if(o.length>0){const n=p.createElement("div");Object.assign(n.style,{color:k.label,fontSize:W.body,padding:`0 ${M} ${C.sm}`});const v=o.slice(0,6).map(N=>N.testNumber).join(", "),c=o.length>6?`, and ${o.length-6} more`:"",w=o.length===1?"it":"them";n.textContent=`${o.length} test ${o.length===1?"number is":"numbers are"} hidden (${v}${c}) \u2014 the wafers in view describe ${w} differently, so their values cannot be pooled. `+(i&&i.length>0?`Pick one ${r??"group"} under "Show:" to analyse ${w}.`:"Load one test program at a time to analyse them."),n.dataset.wmapWithheldTests=String(o.length),j.appendChild(n)}j.appendChild(S.card)}return{el:I,render:F,destroy:()=>{re(),I.remove()}}}
@@ -110,13 +110,10 @@ export interface GalleryOptions {
110
110
  */
111
111
  perCardLegend?: boolean;
112
112
  /**
113
- * Name for the composite gallery PNG, without extension. When omitted, it is
114
- * named for its lots, wafer count and plot mode
115
- * (`LOT123_25-wafers_gallery-hard-bin.png`); cards, CSV exports and charts are
116
- * always named that way. See docs/api.md §5.4.5.
117
- *
118
- * **Changes in 0.31.0:** this becomes a prefix for every file the gallery and
119
- * its cards save. Passing it logs a one-time notice.
113
+ * A prefix for every file the gallery, its cards and their detached windows
114
+ * save — PNGs and CSVs alike. The lots, wafer or wafer count, and content
115
+ * follow it (`<prefix>_25-wafers_gallery-hard-bin.png`), except any the prefix
116
+ * already names. See docs/api.md §5.4.5.
120
117
  */
121
118
  downloadFilename?: string;
122
119
  /**
@@ -1 +1 @@
1
- import{getUniqueTestNumbers as Do,resolveTestNumber as ko,findTestDef as Eo,collectMetadataValues as Bo}from"../renderer/buildView.js";import{metadataCategoricalValue as Oo}from"../core/metadata.js";import{resolveBinColorsForMaps as To,mergeBinDefs as Ye,binColorWarning as Lo,mixedPassBinsWarning as Ro,binColorsEqual as Io}from"../renderer/binColors.js";import{itemPassBins as Wo,INPUT_DEFAULT_PASS_BINS as $o}from"../core/passBins.js";import{NO_DATA_FILL as Ao}from"../renderer/colorMap.js";import{metadataValueColor as Po}from"../renderer/colorMap.js";import{resolveCanvasTheme as Fo}from"./canvasTheme.js";import{ICONS as We}from"./icons.js";import{SHADOW as $e,LEADING as Ze,TRACKING as Ho,controlStyle as jo,wireControlHover as xt,SPACE as w,EDGE_GUTTER as oe,MAP_CHROME_INSET as Vo,RADIUS as z,FONT as L,CLR as h,sevColor as gn,MODE_LABELS as No,BIN_LEGEND_MODES as hn,STACKED_MODES as be,Z_ABOVE as bn,applyOverlayZ as zo,getTooltip as _o,hideTooltip as yn,createToolbarHelpers as Go,buildModeMenuEl as Ko,openDetachWindow as qo,openFloatingWindow as Uo,openModal as Xo,openReportModal as Yo,copyWmapThemeTokens as Zo,syncWmapPopupTheme as Qo,openUserGuideWindow as Jo,makePaletteBtn as ei,makeLogScaleBtn as ti,makeLegendStyleBtn as ni,makeOverlaysBtn as oi,makeOrientationBtn as ii,menuLayerFor as wn,saveImageBlob as vn,markMenuTrigger as Ae,wireMenuA11y as xn,wireExpandToggle as Cn,wireTooltip as Sn,requestedPassFailDisplay as Mn,overlayMenuRows as ai,anyOverlayActive as li,logWmapVersionOnce as si,buildDataModeEntries as ri,metadataKeyHasData as di,metadataModeEntry as ci}from"./toolbar.js";import{waferDisplayLabel as Qe,waferIdentityLabel as Dn}from"../core/waferLabel.js";import{metadataDisplayValue as ui}from"../core/metadata.js";import{withExportContext as fi,noticeDownloadFilenameChange as pi}from"./exportName.js";import{sortBinsForDisplay as mi}from"../stats/binPareto.js";import{diePassStatus as gi}from"../core/dies.js";import{aggregateValues as hi,aggregateBinCounts as kn}from"../core/aggregates.js";import{renderWaferMap as bi,renderWaferMapCard as En,toPublicViewOptions as Bn}from"./renderWaferMap.js";import{hasDrilldownTargets as yi,waferPopulation as wi}from"./chartPopulation.js";import{classifyChanged as vi,COLOR_KEYS as xi}from"./renderWaferMap.js";import{buildWaferMap as Ci,getTestPassStatus as On,isParametricTest as Ct,getDieTestValue as Si}from"../renderer/buildWaferMap.js";import{analyzeWaferMap as Je}from"../stats/analyzeWaferMap.js";import{collectWarnings as Mi,buildWarningsMenuEl as Di,severityOf as ki}from"./warnings.js";import{compareNatural as St,arrayEqual as Tn}from"../core/utils.js";import{createSummaryPanelEl as Mt,buildMetadataStripRow as Ei,buildCompactMetadataRows as Ln,metadataEntries as Rn,renderLotSummaryContentSteps as Bi,reportMapsFromItems as Oi}from"./summaryPanel.js";import{renderLotReportHtml as Ti}from"../stats/renderSummaryReport.js";import{prettyKey as Li}from"../stats/facets.js";import{testLabel as Ri,markedTestLabel as Ii,derivedFields as Wi}from"../renderer/testLabel.js";import{mergeTestDefs as $i}from"../stats/mergeTestDefs.js";import{getDieKey as Ai,hasPosition as Pi}from"../core/dies.js";import{runChunked as Fi}from"./chunked.js";function In(f){if(typeof f!="number"||!Number.isFinite(f))return;const C=Math.round(f);return C>=1?C:void 0}const Dt=12;function Hi(f,C,p){let A=C;if(C.length>Dt){const E=C.slice(0,Dt-1),I=C.slice(Dt-1),H=I.reduce((X,ie)=>X+ie.count,0);A=[...E,{color:h.label,count:H,label:`Other (${I.length} bins)`}]}const k=f.createElement("div");Object.assign(k.style,{display:"flex",columnGap:"1px",width:"100%",height:"8px",borderRadius:z.control,overflow:"hidden",border:`1px solid ${h.menuBorder}`,boxSizing:"border-box",marginTop:w.xs,flexShrink:"0"}),k.setAttribute("role","img"),k.setAttribute("aria-label",`Population split: ${A.map(E=>`${E.label} ${et(E.count/p*100)}`).join(", ")}`);for(const E of A){const I=E.count/p*100,H=f.createElement("div");Object.assign(H.style,{flex:`${I} 1 0`,minWidth:I>0?"2px":"0",background:E.color}),Sn(H,`${E.label} \xB7 ${E.count.toLocaleString()} dies \xB7 ${et(I)}`),k.appendChild(H)}return k}function et(f){return f>0&&f<.1?"<0.1%":`${f.toFixed(1)}%`}function Wn(f,C,p){const A=new Map;let k=0,E=0;for(const I of f){const H=p?new Set(p(I)):void 0;for(const X of I.dies){if(X.partial||X.edgeExcluded)continue;const ie=C(X);ie!==void 0&&(A.set(ie,(A.get(ie)??0)+1),k++,H&&gi(X,H)&&E++)}}return{counts:A,total:k,pass:E}}function $n(f,C){const p=f.ownerDocument.createElement("div");Object.assign(p.style,{display:"flex",alignItems:"center",gap:"5px",cursor:"pointer",userSelect:"none",padding:`${w.xxs} ${w.xs}`,borderRadius:z.control});const A=f.ownerDocument.createElement("span");Object.assign(A.style,{display:"inline-block",width:"13px",height:"13px",flexShrink:"0",background:C.color,border:C.isActive?`2px solid ${h.iconActive}`:`1px solid ${h.menuBorder}`,borderRadius:z.control,boxSizing:"border-box"});const k=f.ownerDocument.createElement("span");if(k.textContent=C.label,Object.assign(k.style,{fontWeight:C.isActive?"700":"400",color:C.isActive?h.iconActive:h.text,whiteSpace:"nowrap"}),p.appendChild(A),p.appendChild(k),C.count!==void 0){const E=f.ownerDocument.createElement("span");if(E.textContent=C.count.toLocaleString(),Object.assign(E.style,{color:C.isActive?h.iconActive:h.text,fontWeight:C.isActive?"700":"400",whiteSpace:"nowrap"}),p.appendChild(E),C.percent!==void 0){const I=f.ownerDocument.createElement("span");I.textContent=et(C.percent),Object.assign(I.style,{color:h.label,whiteSpace:"nowrap"}),p.appendChild(I)}}p.setAttribute("role","button"),p.setAttribute("aria-pressed",C.isActive?"true":"false"),p.tabIndex=0,p.addEventListener("mouseenter",()=>{p.style.background=h.bgHover}),p.addEventListener("mouseleave",()=>{p.style.background="transparent"}),p.addEventListener("focus",()=>{p.style.background=h.bgHover}),p.addEventListener("blur",()=>{p.style.background="transparent"}),p.addEventListener("click",C.onClick),p.addEventListener("keydown",E=>{(E.key==="Enter"||E.key===" ")&&(E.preventDefault(),C.onClick())}),f.appendChild(p)}export function renderWaferGallery(f,C,p={}){si();const A=6;let k=In(p.columns);const E=p.showHelpButton??!1,I=p.userGuideExtension,H=p.insights?.enabled??!1,X=p.insights?.sweeps?{sweeps:p.insights.sweeps}:void 0,ie=zo(p.zIndex),re=p.summaryPanel,An=e=>[...Wo(e)],kt=()=>v.flatMap(e=>e?[e.ringCount??4]:[]),tt=()=>kt()[0]??4;function Pn(e){const t=[...new Set(e)].sort((n,o)=>n-o);return t.length<2?null:{code:"ring-count-mixed",severity:"warning",message:`These wafers were built with different ring counts (${t.join(", ")}). Each card and each wafer's findings use their own; the lot's ring yield in the Summary panel, report and Insights uses ${e[0]} rings.`}}let V=p.lotStatsSummary,ye=p.viewOptions?.legendPosition??"default",Pe=p.perCardLegend??!1;function we(){const e=c.plotMode??"hardBin";return hn.has(e)?null:c.colorbarRangeMode==="data"?"Each map has its own value range, so it keeps its own colour bar":"These wafers have no shared colour bar for value mode, so each map keeps its own"}function Et(){const e=Pe||we()!==null;for(const t of S)t&&t.setOptions({showLegend:e})}let c={plotMode:"hardBin",showDieLabels:!1,showRingBoundaries:!1,showQuadrantBoundaries:!1,rotation:0,flipX:!1,flipY:!1,...p.viewOptions},S=[],ae=[],de=[],R=[];const Fe=fi(()=>{const e=R.filter(n=>n!=null);return{lots:[...new Set(e.map(n=>ui(n.wafer.metadata?.lot)).filter(n=>n!==void 0))].sort(St),...e.length===1?{wafer:Dn(e[0])}:{waferCount:e.length}}},p.onSaveImage,p.onSaveText);pi(p.downloadFilename);let v=C.map(e=>typeof e=="function"?null:e);function Bt(){return $i(v)}function ve(){if(v.some(e=>e?.testDefs?.length))return Bt().defs}let xe=0,He=0;const _=new Map;let Fn=0,P=null,Ce=null,Ot=new Set,b=null,Hn={};function Tt(e){return v[e]?.statsSummary??V?.perWafer.find(t=>t.waferIndex===e)?.summary}function nt(){return!!(v.some(e=>e?.statsSummary?.findings.length)||V?.perWafer.some(e=>e.summary.findings.length))}const jn=_o(),ce=Go(jn),{makeBtn:Q,setActive:Se,makeSep:G,makeMenuRow:Vn,makeMenuSection:Nn,makeDropdown:Lt,closeOpenMenu:je,getOpenMenu:Me,setOpenMenu:De}=ce;f.ownerDocument.addEventListener("click",je,!0);const Rt=()=>yn();window.addEventListener("blur",Rt);let It=p.findingsNotice;function Wt(e){Ot=new Set(e);const t=[...$.querySelectorAll(".wmap-gallery-card")];let n;t.forEach((o,d)=>{const l=Ot.has(d);o.style.outline=l?`3px solid ${h.findingHighlight}`:"",o.style.outlineOffset=l?"-3px":"",l&&n===void 0&&(n=o)}),n?.scrollIntoView?.({behavior:"smooth",block:"nearest"})}function $t(){Wt([])}function At(){for(const e of S)e&&e.clearSelection()}function ot(e,t){const n=new Set(e),o=t??S.map((d,l)=>l);for(const d of o){const l=R[d],a=S[d];if(!l||!a)continue;const r=l.dies.filter(i=>n.has(Ai(i)));a.setSelection(r)}}function zn(){const e=[];for(let t=0;t<v.length;t++){const n=v[t];if(!n)continue;const o=Tt(t)?.findings??[];o.length&&e.push({index:t,item:n,unusualCount:o.filter(d=>d.severity==="unusual").length,notableCount:o.filter(d=>d.severity==="notable").length,totalCount:o.length})}return e}function _n(e){const t=R[e]??v[e];t&&Ie(e,t)}function Gn(e){const t=Tt(e)?.findings??[];if(t.length)return{total:t.length,unusual:t.filter(n=>n.severity==="unusual").length,notable:t.filter(n=>n.severity==="notable").length}}function Kn(){Yo(Ti(Oi(v,$o,tt())),{anchor:f})}function qn(){if(!b)return;b.innerHTML="";const e=zn();if(v.length>0){const n=f.ownerDocument.createElement("div"),o=e.length,d=v.filter(Boolean).length;n.textContent=o===0?`No findings on any of the ${d} wafers`:`${o} of ${d} wafer${d===1?"":"s"} with findings`,Object.assign(n.style,{fontSize:L.body,color:h.label,marginBottom:w.md}),b.appendChild(n)}if(e.length>0){const n=f.ownerDocument.createElement("button");n.type="button",n.textContent="Summary report",Object.assign(n.style,{...jo("outlined"),marginBottom:w.lg,display:"block",width:"100%",textAlign:"left"}),xt(n),n.addEventListener("click",Kn),b.appendChild(n)}if(e.length===0){const n=f.ownerDocument.createElement("div");Object.assign(n.style,{color:h.icon,fontSize:L.body,padding:"4px 0"}),n.textContent="No findings on any wafer.",b.appendChild(n)}else for(const{index:n,item:o,unusualCount:d,notableCount:l,totalCount:a}of e){const r=d?"unusual":l?"notable":"info",i=d+l||a,s=f.ownerDocument.createElement("button");s.type="button",Object.assign(s.style,{display:"flex",alignItems:"center",justifyContent:"space-between",width:"100%",padding:"5px 8px",marginBottom:w.xs,border:"none",borderLeft:`3px solid ${gn(r)}`,borderRadius:z.control,background:h.bgHover,cursor:"pointer",fontSize:L.body,textAlign:"left",boxSizing:"border-box"}),s.addEventListener("mouseover",()=>{s.style.background=h.bgActive}),s.addEventListener("mouseout",()=>{s.style.background=h.bgHover});const u=f.ownerDocument.createElement("span");u.textContent=Qe(o,n),Object.assign(u.style,{color:h.iconHover,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"});const m=f.ownerDocument.createElement("span");m.textContent=String(i),s.setAttribute("aria-label",`${Qe(o,n)} \u2014 ${i} finding${i===1?"":"s"}${d?`, ${d} unusual`:""} \u2014 view wafer`),Object.assign(m.style,{marginLeft:w.sm,flexShrink:"0",background:gn(r),color:"#fff",borderRadius:z.container,padding:"1px 5px",fontSize:L.body,fontWeight:"600"}),s.appendChild(u),s.appendChild(m),s.addEventListener("click",()=>Ie(n,o)),b.appendChild(s)}const t=f.ownerDocument.createElement("div");t.style.height="12px",b.appendChild(t)}let ue=null,ke=null;function N(){if(b)if(ue?.cancel(),ue=null,V){const e=Ye(v.map(n=>n?.hbinDefs)),t=Ye(v.map(n=>n?.sbinDefs));ue=Fi(Bi(b,{lotSummary:V,items:v,hbinDefs:e.length?e:void 0,sbinDefs:t.length?t:void 0,testDefs:ve(),ringCount:tt(),binColors:c.binColors,plotMode:c.plotMode??"hardBin",fallbackFormat:c.fallbackFormat,activeFindingId:Ce,warnings:p.warnings?.display??!0?J:[],findingsFilter:Hn,findingsNotice:It,onFindingsFilterChange:N,onSaveText:Fe.onSaveText,onFindingClick:(n,o)=>{Ce===n.id?it():Xn(n,o),N()},onWaferClick:_n,findingsFor:Gn,dieListOptions:p.dieList}),{onDone:()=>{const n=ke;ke=null,n?.()}})}else qn()}function Un(e){const t=e.highlight;return t?.kind==="wafer"&&t.waferIndices?.length?t.waferIndices:null}function Pt(e){return[e.variable.kind,e.variable.index??"",e.variable.bin??"",e.comparison.family,e.comparison.left,e.effect.direction].join("|")}let Ve=[];function Ft(){if(Ve.length!==0){for(const e of Ve)S[e]?.setOptions({plotMode:c.plotMode,activeTest:c.activeTest});Ve=[]}}function it(){Ce=null,$t(),At(),Ft(),T({highlightBin:void 0},{fireCallback:!1})}function Xn(e,t){if(Ce===e.id){it();return}Ce=e.id,t.style.background=h.bgActive,t.style.fontWeight="600",Ft();const{kind:n,index:o}=e.variable;if(n==="test"){const l=o??0,a=ve();if(a===void 0||a.some(i=>i.testNumber===l))T({plotMode:"value",activeTest:l,highlightBin:void 0},{fireCallback:!1});else{T({highlightBin:void 0},{fireCallback:!1});const s=be.has(c.plotMode??"hardBin")?null:Un(e);if(s){for(const u of s)S[u]?.setOptions({plotMode:"value",activeTest:l});Ve=[...s]}}}else n==="softBin"?T({plotMode:"softBin",highlightBin:void 0},{fireCallback:!1}):T({plotMode:"hardBin",highlightBin:void 0},{fireCallback:!1});$t(),At();const d=e.highlight;if(d.kind==="wafer"){Wt(d.waferIndices);const l=Pt(e);for(const a of d.waferIndices){const s=R[a]?.statsSummary?.findings.find(u=>Pt(u)===l)?.highlight?.dieKeys;s?.length&&ot(s,[a])}}else d.kind==="bin"?d.dieKeys?.length&&ot(d.dieKeys):(d.kind==="region"||d.kind==="dies")&&d.dieKeys?.length&&ot(d.dieKeys)}function le(){if(!P)return;const e=!!b;P.style.display=(V||nt())&&e&&!Te?"flex":"none";const t=b?b.style.display!=="none":!1;(V?.hasNotableFindings||v.some(o=>o?.statsSummary?.hasNotableFindings))&&!t?P.style.color=h.findingIndicator:P.dataset.active||(P.style.color=h.icon)}const W=f.ownerDocument.createElement("div");W.dataset.wmapToolbar="gallery",Object.assign(W.style,{flexShrink:"0",marginLeft:"auto",display:"inline-flex",flexDirection:"row",alignItems:"center",gap:"0",background:h.menuBg,border:`1px solid ${h.menuBorder}`,borderRadius:z.control,padding:"0",boxShadow:$e.panel,flexWrap:"wrap",minWidth:"0",overflowX:"auto"});const Ht=()=>{const e=Me();e&&(e.remove(),De(null)),Ae(Y,!1)},Y=Q("mode","Plot mode",()=>{if(Me()){Ht();return}const e=v.flatMap(y=>y?.dies??[]),t=ve(),{testEntries:n,binEntries:o,stackedEntries:d}=ri(e,t,{includeStacked:!0}),l=v.filter(Boolean).length,a=y=>{if(y===void 0)return l;let B=0;for(const j of v)j?.dies?.some(U=>On(U,y)!==void 0||U.testValues?.[y]!==void 0)&&B++;return B},r=l<2?n:n.map(y=>{const B=a(y.activeTest);return B===l?y:{...y,label:`${y.label} \u2014 ${B} of ${l} wafers`}}),i=c.plotMode??"hardBin",s=c.activeTest??0;function u(y){return y.plotMode!==i?!1:y.plotMode==="value"?s===(y.activeTest??0):y.plotMode==="metadata"?c.activeMetadataKey===y.activeMetadataKey:!0}function m(y,B){y.activeTest!==void 0?T({plotMode:"value",activeTest:y.activeTest,activeMetadataKey:void 0,logScale:y.logScale}):y.activeMetadataKey!==void 0?T({plotMode:y.plotMode,activeTest:void 0,activeMetadataKey:y.activeMetadataKey,passFailDisplay:"off"}):T({plotMode:y.plotMode,activeTest:void 0,activeMetadataKey:void 0,passFailDisplay:"off"}),B.remove(),De(null),Ae(Y,!1)}const M=new Set,D=v.flatMap(y=>y?.metadataFields??[]).filter(y=>!M.has(y.key)&&M.add(y.key)).filter(y=>di(e,y.key)).map(ci),x=Ko(Y.getBoundingClientRect(),r,o,d,u,m,{makeMenuRow:Vn,makeMenuSection:Nn},i,Y.ownerDocument.defaultView??window,D);wn(Y).appendChild(x),De(x),Ae(Y,!0),xn(x,Y,Ht)});Ae(Y,!1);const Yn=()=>R.flatMap(e=>e?[...e.hbinDefs??[],...e.sbinDefs??[]]:[]).some(e=>e.color),{btn:Zn,sync:jt}=ei(ce,()=>({...c,plotMode:c.plotMode??"hardBin"}),Yn,e=>T(e));jt();const Qn=C.some(e=>typeof e!="function"&&(e.reticles?.length??0)>0);function Ne(){const e=ve(),{testNumber:t}=ko(c.activeTest??0,e);return{testNumber:t,td:Eo(e,t)}}function Vt(){if((c.plotMode??"hardBin")!=="value")return!1;const{td:e}=Ne();return e!==void 0&&(e.limitLow!==void 0||e.limitHigh!==void 0)}function Ee(){if((c.plotMode??"hardBin")!=="value")return!1;const{td:e}=Ne();return e!==void 0&&!Ct(e)}function Jn(){if((c.plotMode??"hardBin")!=="value")return!1;const{testNumber:e,td:t}=Ne();return v.some(n=>n?.dies?.some(o=>On(o,e,t)!==void 0))}function eo(e,t){if(!t||!Ct(t))return;const n=t.limitLow!==void 0||t.limitHigh!==void 0;if((Mn(c)==="spec"&&n?"spec":c.colorbarRangeMode??"spec")==="spec"&&n)return;let l=1/0,a=-1/0;for(const r of v)if(r)for(const i of r.dies){const s=Si(i,e);s!==void 0&&(s<l&&(l=s),s>a&&(a=s))}if(isFinite(l))return l===a?[l,l+1]:[l,a]}function at(e,t,n){const o=c[e];if(o===t||o!=null&&t!=null&&n(o,t))return!1;c={...c,[e]:t};for(const d of S)d&&d.setOptions({[e]:t});return!0}function Nt(){if((c.plotMode??"hardBin")!=="metadata")return;const e=c.activeMetadataKey;if(!e)return;const t=new Set;for(const n of v)if(n)for(const o of Bo(n.dies,e))t.add(o);return{key:e,values:[...t].sort(St)}}function lt(){at("metadataValueOrder",Nt(),(e,t)=>e.key===t.key&&Tn(e.values,t.values))}function st(){if((c.plotMode??"hardBin")!=="value")return;const{testNumber:e,td:t}=Ne(),n=eo(e,t);at("valueRange",n?{test:e,range:n}:void 0,(d,l)=>{const a=s=>Array.isArray(s)?{test:void 0,range:s}:{test:s.test,range:s.range},r=a(d),i=a(l);return r.test===i.test&&Tn(r.range,i.range)})}let rt=!1;function to(){if(rt)return;rt=!0,(f.ownerDocument.defaultView?.requestAnimationFrame??(t=>setTimeout(()=>t(0),0)))(()=>{rt=!1,st(),lt(),_t()})}let dt=!1;function no(){if(dt)return;dt=!0,(f.ownerDocument.defaultView?.requestAnimationFrame??(t=>setTimeout(()=>t(0),0)))(()=>{dt=!1,qe()})}let zt=[];function fe(){const{colors:e,mixedHardBins:t}=To(v.filter(n=>n!=null),{binColorScheme:c.binColorScheme,useDefinedBinColors:c.useDefinedBinColors});return zt=t,e}function _t(){at("binColors",fe(),Io),Be()}const oo=oi(ce,()=>ai(c,Qn,{functionalActive:Ee(),hasLimits:Vt()&&!Ee(),hasRecorded:Jn()&&!Ee(),binMode:(c.plotMode??"hardBin")==="hardBin"||(c.plotMode??"hardBin")==="softBin"},e=>T(e)),()=>li(c)),{btn:io,sync:Gt}=ni(ce,()=>({plotMode:c.plotMode,legendPosition:ye}),e=>{ye=e;for(const t of S)t&&t.setOptions({legendPosition:ye})},{get:()=>Pe,set:e=>{Pe=e,Et()},blockedReason:we});Gt();const ao=[{value:"mean",label:"Mean"},{value:"median",label:"Median"},{value:"stddev",label:"Std Dev"},{value:"min",label:"Min"},{value:"max",label:"Max"},{value:"count",label:"Count"}],Kt=Lt("aggr","Aggregation method",()=>ao,()=>c.aggregationMethod??"mean",e=>T({aggregationMethod:e}));function qt(){const e=c.plotMode==="stackedValues";Kt.style.display=e?"":"none"}qt();const{btn:lo,sync:Ut}=ti(ce,()=>({...c,functionalActive:Ee()}),e=>T(e));Ut();const ze=Q("specRange","Colorbar range: test limits",()=>{const e=c.colorbarRangeMode==="data"?"spec":"data";T({colorbarRangeMode:e})});function Xt(){const e=(c.plotMode??"hardBin")==="value"&&Vt()&&Mn(c)==="off"&&!Ee();ze.style.display=e?"":"none";const t=(c.colorbarRangeMode??"spec")==="spec";Se(ze,t),ze.ariaLabel=t?"Colorbar range: test limits (click for data range)":"Colorbar range: data range (click for test limits)"}Xt();const so=ii(ce,()=>c,e=>T(e)),ro=Q("downloadAll","Download gallery PNG",Co),co=Lt("columns","Columns",()=>[{value:"auto",label:"Auto"},{value:"1",label:"1 column"},{value:"2",label:"2 columns"},{value:"3",label:"3 columns"},{value:"4",label:"4 columns"},{value:"5",label:"5 columns"}],()=>k!=null?String(k):"auto",e=>ln(e==="auto"?void 0:Number(e))),O=f.ownerDocument.createElement("div");Object.assign(O.style,{display:"inline-flex",alignItems:"center",gap:"0"}),W.appendChild(O),O.appendChild(Y),O.appendChild(Zn),O.appendChild(Kt),O.appendChild(lo),O.appendChild(ze),O.appendChild(G()),O.appendChild(oo),O.appendChild(G()),O.appendChild(io),O.appendChild(G()),O.appendChild(so),O.appendChild(G()),O.appendChild(co),O.appendChild(G()),O.appendChild(ro),(V||nt())&&(P=Q("findings","Summary panel",()=>{if(!b)return;const e=b.style.display!=="none";e||N(),b.style.display=e?"none":"flex",Se(P,!e),le()}),W.appendChild(G()),W.appendChild(P));let K=null,_e=null,J=[],Yt=!1;function Be(){const e=Mi({lotStatsSummary:V,result:{warnings:[...v.flatMap(n=>n?.warnings??[]),...Bt().warnings]},extra:[c.binColors&&Lo(c.binColors,c.plotMode),Ro(zt),Pn(kt())].filter(n=>!!n)}),t=e.length!==J.length||e.some((n,o)=>n.code!==J[o]?.code||n.message!==J[o]?.message);J=e,(t||!Yt)&&(Yt=!0,p.warnings?.onWarning?.(e)),uo()}function uo(){if(!K||!_e)return;const e=J.length,t=e>0;if(K.style.display=t?"flex":"none",_e.style.display=t?"":"none",!t)return;const n=ki(J[0]),o=`${e} data ${e===1?"warning":"warnings"}`;K.style.color=n==="error"?h.errText:h.warnText,K.ariaLabel=n==="error"?`${o} \u2014 some wafers may be positionally wrong`:o}(p.warnings?.display??!0)&&(_e=G(),K=Q("warning","Data warnings",()=>{const e=Me();if(je(new MouseEvent("click")),e)return;const t=Di(K.getBoundingClientRect(),J,K.ownerDocument.defaultView??window);wn(f).appendChild(t),De(t),xn(t,K,()=>je(new MouseEvent("click")))}),Ae(K,!1),W.appendChild(_e),W.appendChild(K)),Be();let se=null;H&&(se=Q("analysis","Insights",()=>{Jt(!Te)}),se.dataset.wmapInsightsBtn="1",W.appendChild(G()),W.appendChild(se));function Zt(){import("./userGuideHtml.js").then(e=>Jo({buildWaferMap:Ci,renderWaferMap:bi,renderWaferGallery,analyzeWaferMap:Je},e.USER_GUIDE_HTML,I,f))}E&&(W.appendChild(G()),W.appendChild(Q("help","User guide",()=>Zt())));const pe=f.ownerDocument.createElement("div");pe.dataset.wmapGalleryMeta="1",Object.assign(pe.style,{flex:"1",minWidth:"0",overflow:"hidden",display:"flex",alignItems:"center",padding:`${w.sm} ${w.lg}`,fontSize:L.sub,lineHeight:Ze.none,boxSizing:"border-box"});const Ge=f.ownerDocument.createElement("div");Object.assign(Ge.style,{background:h.canvasBg,display:"flex",alignItems:"stretch",gap:w.lg,paddingBottom:w.lg,minWidth:"0"});const ee=f.ownerDocument.createElement("div");ee.dataset.wmapGalleryLegend="1",Object.assign(ee.style,{display:"flex",flexDirection:"column",gap:w.sm,background:h.menuBg,border:`1px solid ${h.menuBorder}`,borderRadius:z.container,padding:`${w.sm} ${w.lg}`,marginBottom:w.lg,boxShadow:$e.panel,fontSize:L.body,lineHeight:Ze.none,boxSizing:"border-box",width:"100%",minWidth:"0"});const q=f.ownerDocument.createElement("div");Object.assign(q.style,{display:"flex",flexDirection:"row",alignItems:"flex-start"});let me=null,Oe=null,Qt=null;function fo(){return H?me?Promise.resolve(me):(Qt??=import("./insightsTab.js").then(({createInsightsTab:e})=>(me=e({getItems:()=>v,getLotStats:()=>V,getBinColors:()=>c.binColors??fe(),getRingCount:tt,defaultView:p.insights?.defaultView,sweeps:p.insights?.sweeps,onRemoveSweeps:p.insights?.onRemoveSweeps,onOpenGuide:void 0,showMetadataStrip:!1,onSaveImage:Fe.onSaveImage,onSaveText:Fe.onSaveText,ownerDocument:f.ownerDocument,openWafer:(t,n,o)=>{const d=v[t];if(!d)return;let l=null;const a=Xo({title:n,onClose:()=>l?.destroy(),anchor:f});dn(a,n,d.wafer.metadata??void 0),l=ht(a.contentWrap,d,o)}}),Oe=me.el,Oe.style.display="none",f.appendChild(Oe),me)),Qt):Promise.resolve(null)}let Te=!1;function Jt(e){H&&(Te=e,Oe&&(Oe.style.display=e?"flex":"none"),q.style.display=e?"none":"flex",O.style.display=e?"none":"inline-flex",W.style.display="inline-flex",se&&(Se(se,e),se.innerHTML=e?We.wafer:We.analysis,se.ariaLabel=e?"Back to gallery view":"Insights"),le(),qe(),e&&fo().then(t=>{!t||!Te||(t.el.style.display="flex",t.render())}))}H&&p.insights?.defaultOpen&&queueMicrotask(()=>Jt(!0));const po=4,ct=240,en=480,mo=720,go=1.25;let ge=en;function tn(e){const t=A*2+110+2;let n=null;for(const o of e){if(o==null||!o.dies?.length)continue;const d=o.dies[0].width;if(!(d>0))continue;const l=o.wafer.radius*2*(po/d),a=Math.ceil(l+t);(n==null||a>n)&&(n=a)}return n}function ho(e){const t=tn(e);return t==null?ct:Math.min(ge,Math.max(ct,t))}function bo(e){const t=tn(e);if(t==null)return!1;const n=Math.min(mo,Math.max(en,t));return n<=ge?!1:(ge=n,!0)}function ut(){return k!=null?"none":`${ge}px`}function nn(){const e=ut();for(const t of Array.from($.children))t.classList.contains("wmap-gallery-card")&&(t.style.maxWidth=e,t.style.maxHeight=e)}let Ke=ct,on=0;function an(e){if(bo(e)&&nn(),k==null){const n=ho(e);n>Ke&&(Ke=n)}pt()}function ln(e){k=In(e),nn(),pt()}function ft(e){return`repeat(${e}, minmax(0, ${k!=null?"1fr":`${ge}px`}))`}function sn(e){$.style.gridTemplateColumns!==e&&($.style.gridTemplateColumns=e)}function pt(){if(k!=null){sn(ft(k));return}const e=Math.max(1,on),t=12,n=$.clientWidth||0,o=l=>(n-t*(l-1))/l;let d=Math.max(1,Math.ceil(Math.sqrt(e)));if(n>0){const l=Math.min(ge,Ke*go),a=r=>{let i=0;for(;i<e&&o(i+1)>=r;)i++;return i};d=a(l)||a(Ke)||1}sn(ft(d))}const $=f.ownerDocument.createElement("div");if(Object.assign($.style,{flex:"1 1 0",minWidth:"0",display:"grid",gridTemplateColumns:ft(1),gap:w.xl,paddingLeft:oe,paddingRight:oe,justifyContent:"start",alignContent:"start",isolation:"isolate"}),re?.placement){const e=re.placement;b=Mt(e,oe,f.ownerDocument),b.style.maxHeight="calc(100vh - 80px)",b.style.position="sticky",b.style.top="8px",b.style.display="flex",b.style.flexDirection="column"}else if(V||nt()){const e=!!re?.defaultOpen;b=Mt("right",oe,f.ownerDocument),b.style.maxHeight="calc(100vh - 80px)",b.style.position="sticky",b.style.top="8px",b.style.flexDirection="column",b.style.display=e?"flex":"none",N()}le(),b?.style.display!=="none"&&P&&Se(P,!0),(re?.placement??"right")==="left"?(b&&q.appendChild(b),q.appendChild($)):(q.appendChild($),b&&q.appendChild(b));const Le=f.ownerDocument.createElement("div");Object.assign(Le.style,{position:"sticky",top:"0",display:"flex",flexDirection:"column",paddingLeft:oe,paddingRight:oe,paddingTop:oe,zIndex:"1",background:h.menuBg}),Ge.appendChild(pe),Ge.appendChild(W),Le.appendChild(Ge),Le.appendChild(ee),f.appendChild(Le),f.appendChild(q);function qe(){ee.innerHTML="";const e=c.plotMode??"hardBin",t=!Te&&hn.has(e),n=R.filter(g=>g!=null),o=n.find(g=>g.isLotStack),d=Ei(n.map(g=>({metadata:g.wafer.metadata??void 0})),o?{lotSize:o.lotSize??n.length,aggrMethod:o.aggrMethod}:void 0),l=e==="metadata",a=c.activeMetadataKey,r=t&&!l?Wn(n,g=>(e==="softBin"?g.sbin:g.hbin)??void 0,An):{counts:new Map,total:0,pass:0},i=t&&!l?c.binColors??fe():void 0,s=i?e==="softBin"?i.pass.soft:i.pass.hard:new Set,u=mi(r.counts.entries(),s).map(([g])=>g),m=t&&l&&a?Wn(n,g=>Oo(g.metadata?.[a])):{counts:new Map,total:0,pass:0},M=l?Nt()?.values:void 0,D=t&&l?(M??[...m.counts.keys()].sort(St)).filter(g=>m.counts.has(g)):[];if(pe.innerHTML="",d&&pe.appendChild(d),pe.style.display=d?"flex":"none",!u.length&&!D.length){ee.style.display="none";return}ee.style.display="flex";const x=f.ownerDocument.createElement("div");Object.assign(x.style,{display:"flex",flexWrap:"wrap",alignItems:"center",gap:`${w.sm} ${w.xl}`,maxHeight:"86px",overflowY:"auto",overflowX:"hidden"}),ee.appendChild(x);const y=c.highlightBin,B=R.flatMap(g=>g?.metadataFields??[]).find(g=>g.key===a),j=l?B?.label??(a?Li(a):"Metadata"):No[e],U=f.ownerDocument.createElement("span");if(U.textContent=j,Object.assign(U.style,{fontSize:L.body,fontWeight:"700",letterSpacing:Ho,textTransform:"uppercase",color:h.label,flexShrink:"0"}),x.appendChild(U),!l&&r.total>0){const g=r.pass,F=g/r.total*100,te=f.ownerDocument.createElement("span");te.textContent=`Yield ${et(F)}`,Object.assign(te.style,{fontSize:L.body,fontWeight:"700",color:h.value,whiteSpace:"nowrap",flexShrink:"0"});const ne=f.ownerDocument.createElement("span");ne.textContent=`${g.toLocaleString()} / ${r.total.toLocaleString()} dies`,Object.assign(ne.style,{fontSize:L.body,color:h.label,whiteSpace:"nowrap",flexShrink:"0"}),x.appendChild(te),x.appendChild(ne)}if(l){const g=c.highlightMetadataValue;D.forEach((F,te)=>{const ne=g===F,Xe=B?.values?.find(vt=>vt.value===F),Mo=Xe?.color??Po(te),mn=m.counts.get(F)??0;$n(x,{color:Mo,isActive:ne,label:Xe?.label??F,count:mn,percent:m.total>0?mn/m.total*100:void 0,onClick:()=>{const vt=c.highlightMetadataValue===F?void 0:F;T({highlightMetadataValue:vt})}})});return}const bt=e==="softBin"?R.flatMap(g=>g?.sbinDefs??[]):R.flatMap(g=>g?.hbinDefs??[]),un=new Set,yt=[];for(const g of bt)un.has(g.bin)||(un.add(g.bin),yt.push(g));const wt=yt.length>0?new Map(yt.map(g=>[g.bin,g])):null,fn=i??c.binColors??fe(),So=e==="softBin"?fn.soft:fn.hard,pn=g=>So.get(g)??Ao;for(const g of u){const F=y===g,te=wt?.get(g),ne=r.counts.get(g)??0;$n(x,{color:pn(g),isActive:F,label:te?.name?`${g} \xB7 ${te.name}`:`Bin ${g}`,count:ne,percent:r.total>0?ne/r.total*100:void 0,onClick:()=>{const Xe=c.highlightBin===g?void 0:g;T({highlightBin:Xe})}})}r.total>0&&u.length>1&&ee.appendChild(Hi(f.ownerDocument,[...r.counts.entries()].sort(([,g],[,F])=>F-g).map(([g,F])=>({color:pn(g),count:F,label:wt?.get(g)?.name?`${g} \xB7 ${wt.get(g).name}`:`Bin ${g}`})),r.total))}function Re(e){const t=v.filter(r=>r!==null);if(!t.length)return[];const n=t.map(r=>r.dies.filter(Pi)),o=t[0].wafer,d=t.length,l=o.metadata?{...o,metadata:(({wafer:r,waferId:i,...s})=>s)(o.metadata)}:o;function a(r,i){return{...r,stats:{...r.stats,isLotStack:!0,aggregationMethod:i,lotSize:d}}}if(e==="stackedValues"){const r=ve();let i=r?.filter(Ct);if(r!==void 0&&i?.length===0)return[];if(r?.length||(i=Do(t.flatMap(m=>m.dies)).map(m=>({testNumber:m,name:Ri(void 0,m)}))),!i?.length)return[];const s=c.aggregationMethod??"mean";return i.map(u=>{const m=hi(n,s,u.testNumber),M={testNumber:0,name:u.name,unit:u.unit,...Wi(u)};return{wafer:l,dies:m,testDefs:[M],label:`${Ii(u,u.testNumber)} \xB7 ${s}`,isLotStack:!0,aggrMethod:s,lotSize:d,statsSummary:a(Je({wafer:l,dies:m,testDefs:[M]},{testNumbers:[0]}),s)}})}if(e==="stackedBins"){let r=Ye(t.map(i=>i?.hbinDefs));return(!r||r.length===0)&&(r=[...new Set(t.flatMap(s=>s.dies.map(u=>u.hbin).filter(u=>u!=null)))].sort((s,u)=>s-u).map(s=>({bin:s,name:`Bin ${s}`}))),r.map(i=>{const s=kn(n,i.bin,"hard"),u=[{bin:i.bin,name:i.name}];return{wafer:l,dies:s,hbinDefs:u,label:`${i.bin} \xB7 ${i.name}`,isLotStack:!0,aggrMethod:"countBin",lotSize:d,statsSummary:a(Je({wafer:l,dies:s,hbinDefs:u}),"countBin")}})}if(e==="stackedSoftBins"){let r=Ye(t.map(i=>i?.sbinDefs));return(!r||r.length===0)&&(r=[...new Set(t.flatMap(s=>s.dies.map(u=>u.sbin).filter(u=>u!=null)))].sort((s,u)=>s-u).map(s=>({bin:s,name:`Bin ${s}`}))),r.map(i=>{const s=kn(n,i.bin,"soft"),u=[{bin:i.bin,name:i.name}];return{wafer:l,dies:s,sbinDefs:u,label:`${i.bin} \xB7 ${i.name}`,isLotStack:!0,aggrMethod:"countBin",lotSize:d,statsSummary:a(Je({wafer:l,dies:s,sbinDefs:u}),"countBin")}})}return t}function mt(e){const t=v.length;return e==="stackedBins"||e==="stackedSoftBins"?{valueRange:[0,t],lotSize:t}:e==="stackedValues"?{aggregationMethod:c.aggregationMethod??"mean",valueRange:void 0,lotSize:void 0}:{}}function T(e,{fireCallback:t=!0}={}){const n=Object.keys(e),o=c.plotMode,d=we()!==null;c={...c,...e};const l=c.plotMode,a=be.has(l),r=o!==void 0&&be.has(o),i=He>0;if("binColorScheme"in e||"useDefinedBinColors"in e){const u=fe();c={...c,binColors:u},e={...e,binColors:u}}if(e.plotMode!==void 0)if(a){const u=mt(l);if(c={...c,...u},i)for(const m of S)m&&m.setOptions(e);else Z(Re(l))}else if(r){const{valueRange:u,lotSize:m,aggregationMethod:M,...D}=c;if(c=D,i)for(const x of S)x&&x.setOptions(e);else Z(v.filter(x=>x!==null))}else for(const u of S)u&&u.setOptions(e);else if(e.aggregationMethod!==void 0&&l==="stackedValues")if(i)for(const u of S)u&&u.setOptions(e);else Z(Re("stackedValues"));else for(const u of S)u&&u.setOptions(e);we()!==null!==d&&Et(),qe(),qt(),Gt(),jt();const s=e.plotMode!==void 0&&e.plotMode!==o;(xi.some(u=>u in e)||s)&&N(),Be(),Ut(),Xt(),st(),lt(),t&&p.onViewOptionsChange?.(Bn(c),n,vi(n))}function rn(e,t,n){const o=e.createElement("div");Object.assign(o.style,{display:"flex",alignItems:"center",gap:w.xs,flex:"1",minWidth:"0"});const d=e.createElement("span");d.textContent=t,Object.assign(d.style,{fontWeight:"700",fontSize:L.sub,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}),o.appendChild(d);const l=Rn(n??{});let a=null;if(l.length>0){const r=e.createElement("span");Object.assign(r.style,{fontSize:L.body,lineHeight:Ze.none,color:h.label,flexShrink:"0"}),r.textContent="\u25BE",o.appendChild(r),Object.assign(o.style,{cursor:"pointer",borderRadius:z.control}),o.addEventListener("mouseenter",()=>{o.style.background=h.bgHover}),o.addEventListener("mouseleave",()=>{o.style.background="none"}),a=e.createElement("div"),a.dataset.wmapCardMetaPanel="1",Object.assign(a.style,{position:"absolute",top:"0",left:"0",right:"0",zIndex:bn,background:h.menuBg,borderBottom:`1px solid ${h.menuBorder}`,boxShadow:$e.menu,padding:`${w.md} ${w.lg}`,fontSize:L.body,display:"none"});const i=Ln(n??{});i&&a.appendChild(i),o.setAttribute("aria-expanded","false"),o.setAttribute("aria-label",`Wafer info for ${t||"this card"}. Click to expand.`),Cn(o,s=>{r.textContent=s?"\u25B4":"\u25BE",o.setAttribute("aria-expanded",String(s)),a&&(a.style.display=s?"block":"none")})}return{wrap:o,metaPanel:a}}function dn(e,t,n){const o=e.box.querySelector("[data-wmap-window-title]"),d=Rn(n??{});if(!o||d.length===0)return;const l=o.parentElement,a=f.ownerDocument.createElement("div");Object.assign(a.style,{display:"flex",alignItems:"center",gap:w.xs,flex:"1",minWidth:"0",cursor:"pointer"}),xt(a,"bare"),l?.insertBefore(a,o),a.appendChild(o);const r=f.ownerDocument.createElement("span");Object.assign(r.style,{fontSize:L.body,lineHeight:Ze.none,color:h.label,flexShrink:"0"}),r.textContent="\u25BE",a.appendChild(r);const i=f.ownerDocument.createElement("div");i.dataset.wmapCardMetaPanel="1",Object.assign(i.style,{position:"absolute",top:"0",left:"0",right:"0",zIndex:bn,background:h.menuBg,borderBottom:`1px solid ${h.menuBorder}`,boxShadow:$e.menu,padding:`${w.md} ${w.lg}`,fontSize:L.body,display:"none"});const s=Ln(n??{});s&&i.appendChild(s),e.contentWrap.style.position="relative",e.contentWrap.appendChild(i),a.setAttribute("aria-expanded","false"),a.setAttribute("aria-label",`Wafer info for ${t}. Click to expand.`),Cn(a,u=>{r.textContent=u?"\u25B4":"\u25BE",a.setAttribute("aria-expanded",String(u)),i.style.display=u?"block":"none"})}function gt(e,t,n){const o=f.ownerDocument.createElement("div");o.className="wmap-gallery-card",Object.assign(o.style,{background:h.menuBg,border:`1px solid ${h.menuBorder}`,borderRadius:z.container,boxShadow:$e.panel,overflow:"hidden",display:"flex",flexDirection:"column",position:"relative",aspectRatio:"1",maxWidth:ut(),maxHeight:ut()});const d=f.ownerDocument.createElement("div");Object.assign(d.style,{display:"flex",alignItems:"center",padding:`${w.md} ${w.lg} ${w.sm}`,borderBottom:`1px solid ${h.menuBorder}`,flexShrink:"0",gap:w.sm});const{wrap:l,metaPanel:a}=rn(document,Qe(e,t),e.wafer.metadata??void 0);d.appendChild(l);const r=f.ownerDocument.createElement("button");r.dataset.wmapExpandBtn="1",r.setAttribute("aria-label","Open full view"),Sn(r),r.innerHTML=We.expand,Object.assign(r.style,{display:"flex",alignItems:"center",justifyContent:"center",border:`1px solid ${h.menuBorder}`,borderRadius:z.control,background:h.panelBg,color:h.label,padding:w.xxs,cursor:"pointer",flexShrink:"0",width:"22px",height:"22px"}),xt(r),d.appendChild(r),o.appendChild(d);const i=f.ownerDocument.createElement("div");Object.assign(i.style,{position:"relative",flex:"1",minHeight:"0",overflow:"hidden",display:"flex",flexDirection:"column"}),o.appendChild(i),a&&i.appendChild(a),$.appendChild(o),o.addEventListener("contextmenu",M=>{if(M.defaultPrevented)return;const D=p.insights?.sweeps;if(!yi(e.testDefs,D))return;M.preventDefault();const x=e.viewOptions?{...c,...e.viewOptions}:c,y=wi(e.dies,{waferLabel:Dn(e),testDefs:e.testDefs,isLotStack:e.isLotStack,activeTest:x.plotMode==="value"?x.activeTest:void 0,waferIndex:t}),B={x:M.clientX,y:M.clientY};import("./drilldown.js").then(({openDrilldownMenu:j})=>{o.isConnected&&j(B,o,y,{sweeps:D,onSaveImage:p.onSaveImage})})});const s=Pe||we()!==null,u=e.viewOptions?{...c,...e.viewOptions}:c,m=En(i,e,{viewOptions:{...u,showLegend:s,legendPosition:ye},showTooltip:!0,padding:A,statsSummary:e.statsSummary,onSaveImage:p.onSaveImage,onSaveText:p.onSaveText,onClick:e.onClick,onSelect:e.onSelect,insights:X,onExpand:()=>Ie(t,e),showIdentity:!1,chromeInset:Vo});return m.setViewControlsVisible(!1),m.setSummaryVisible(!1),r.onclick=()=>Ie(t,e),{card:o,ctrl:m,canvasWrapper:i,expandBtn:r}}function yo(e){const t=de[e];if(!t)return;const n=[..._.values()].find(o=>o.cardIndex===e);n?(t.innerHTML=We.minimize,t.setAttribute("aria-label","Reattach to gallery"),t.onclick=()=>vo(n.id)):(t.innerHTML=We.expand,t.setAttribute("aria-label","Open full view"),t.onclick=()=>Ie(e,R[e]))}function Z(e){xo(),Me()?.remove(),De(null),it(),R=[];for(const i of S)i&&i.destroy();S=[],ae=[],de=[],He=0,$.innerHTML="",on=e.length,an(e.map(i=>typeof i=="function"?null:i));const t=[];for(let i=0;i<e.length;i++){const s=e[i];if(typeof s=="function"){const u=f.ownerDocument.createElement("div");u.className="wmap-gallery-card",Object.assign(u.style,{background:h.menuBg,border:`1px solid ${h.menuBorder}`,borderRadius:z.container,aspectRatio:"1",display:"flex",alignItems:"center",justifyContent:"center"});const m=f.ownerDocument.createElement("span");m.textContent="\u2026",Object.assign(m.style,{color:h.label,fontSize:"18px"}),u.appendChild(m),$.appendChild(u),R.push(null),S.push(null),ae.push(null),de.push(null),t.push({index:i,factory:s,placeholder:u}),He++}else{const{ctrl:u,canvasWrapper:m,expandBtn:M}=gt(s,i,e.length);R.push(s),S.push(u),ae.push(m),de.push(M)}}_t(),qe(),st(),lt();const n=++xe,o=()=>{setTimeout(()=>{n===xe&&p.onItemsResolved?.()},0)},d=i=>{setTimeout(()=>{n===xe&&p.onItemResolved?.(i,e.length)},0)};let l=e.length-t.length;l>0&&d(l);let a=0;function r(){if(n!==xe)return;if(a>=t.length){if(be.has(c.plotMode)){const B=c.plotMode;Z(Re(B));return}ke=o,N(),ue||(ke=null,o());return}const{index:i,factory:s,placeholder:u}=t[a++],m=s();R[i]=m,v[i]=m,an([m]);const{card:M,ctrl:D,canvasWrapper:x,expandBtn:y}=gt(m,i,e.length);S[i]=D,ae[i]=x,de[i]=y,He--,u.replaceWith(M),d(++l),no(),to(),!b&&!re?.placement&&m.statsSummary?.findings.length&&(b=Mt("right",oe,f.ownerDocument),b.style.maxHeight="calc(100vh - 80px)",b.style.position="sticky",b.style.top="8px",b.style.flexDirection="column",b.style.display="none",(re?.placement??"right")==="left"?q.insertBefore(b,$):q.appendChild(b),N(),P||(P=Q("findings","Summary panel",()=>{if(!b)return;const j=b.style.display!=="none";j||N(),b.style.display=j?"none":"flex",Se(P,!j),le()}),W.appendChild(G()),W.appendChild(P)),le()),le(),setTimeout(r,0)}t.length>0?setTimeout(r,0):o()}if(be.has(c.plotMode)&&v.length>0){const e=mt(c.plotMode);c={...c,...e},Z(Re(c.plotMode))}else Z(C);Be();let he=0;const cn=new(f.ownerDocument.defaultView??window).ResizeObserver(()=>{if(he)return;he=(f.ownerDocument.defaultView??window).requestAnimationFrame(()=>{he=0,k==null&&pt()})});cn.observe($),b&&N();function wo(e,t){const n=ae[e];if(!n)return;n.innerHTML="",Object.assign(n.style,{alignItems:"center",justifyContent:"center"});const o=f.ownerDocument.createElement("span");o.textContent=t?"Opened in its own window":"Opened in the wafer viewer",Object.assign(o.style,{color:h.label,fontSize:L.body,textAlign:"center",padding:"0 12px"}),n.appendChild(o)}function Ie(e,t){for(const a of _.values())if(a.cardIndex===e)return;const n=Qe(t,e),o=Fn++,d=S[e]?.getOptions(),l=qo(n);if(l){const a=l.document;a.title=n,Object.assign(a.documentElement.style,{height:"100%"}),Object.assign(a.body.style,{margin:"0",height:"100vh",overflow:"hidden",display:"flex",flexDirection:"column",fontFamily:L.family}),Zo(f,a.documentElement);const r=Qo(f,a.documentElement,()=>x.setOptions({})),i=a.createElement("div");i.dataset.wmapWindowBanner="1",i.textContent=n,Object.assign(i.style,{display:"none",padding:`${w.sm} ${w.xl}`,fontSize:L.body,fontWeight:"700",background:h.warnBg,color:h.warnText,borderBottom:`1px solid ${h.warnBorder}`,flexShrink:"0"}),a.body.appendChild(i);const s=a.createElement("div");Object.assign(s.style,{flex:"1",minHeight:"0",display:"flex",flexDirection:"column"}),a.body.appendChild(s);const{wrap:u,metaPanel:m}=rn(a,n,t.wafer.metadata??void 0),M=a.createElement("div");Object.assign(M.style,{display:"flex",alignItems:"center",padding:`${w.md} ${w.lg} ${w.sm}`,borderBottom:`1px solid ${h.menuBorder}`,flexShrink:"0",gap:w.sm}),M.appendChild(u),s.appendChild(M);const D=a.createElement("div");Object.assign(D.style,{position:"relative",flex:"1",minHeight:"0",overflow:"hidden",display:"flex",flexDirection:"column"}),m&&D.appendChild(m),s.appendChild(D);const x=ht(D,t,void 0,d),y=setInterval(()=>{l.closed&&Ue(o)},400);l.addEventListener("pagehide",()=>Ue(o)),_.set(o,{id:o,ctrl:x,cardIndex:e,label:n,closePollId:y,stopThemeSync:r,close:()=>{l.closed||l.close()},setTitle:B=>{a.title=B,i.textContent=B,i.style.display="block"}})}else{const a=Uo({title:n,onClose:()=>Ue(o),anchor:f});a.contentWrap.style.flexDirection="column",dn(a,n,t.wafer.metadata??void 0);const r=ht(a.contentWrap,t,void 0,d);_.set(o,{id:o,ctrl:r,cardIndex:e,label:n,closePollId:null,close:()=>a.close(),setTitle:i=>{const s=a.box.querySelector("[data-wmap-window-title]");s&&(s.textContent=i,s.title=i)}})}S[e]?.destroy(),S[e]=null,wo(e,l!==null),yo(e)}function ht(e,t,n,o){const d=t.viewOptions?{...c,...t.viewOptions}:c,l=o?{...d,...o}:d,r={...n!==void 0?{...l,plotMode:"value",activeTest:n}:l,showLegend:!0,legendPosition:ye},i=En(e,t,{viewOptions:r,showTooltip:!0,padding:A,statsSummary:t.statsSummary,onSaveImage:p.onSaveImage,onSaveText:p.onSaveText,onClick:t.onClick,onSelect:t.onSelect,insights:X,showExpandButton:!1,showIdentity:!1});return i.setViewControlsVisible(!0),i.setSummaryVisible(!0),i.setExpandVisible(!1),i}function Ue(e){const t=_.get(e);if(!t||(_.delete(e),t.closePollId!=null&&clearInterval(t.closePollId),t.stopThemeSync?.(),t.ctrl.destroy(),t.cardIndex===null))return;const n=t.cardIndex,o=R[n];if(!o)return;const{card:d,ctrl:l,canvasWrapper:a,expandBtn:r}=gt(o,n,R.length);ae[n]?.parentElement?.replaceWith(d),S[n]=l,ae[n]=a,de[n]=r}function vo(e){const t=_.get(e);t&&(t.close(),Ue(e))}function xo(){for(const e of _.values())e.cardIndex!==null&&(e.cardIndex=null,e.setTitle(`${e.label} \u2014 unlinked from gallery`))}function Co(){const e=[...$.querySelectorAll("canvas")];if(!e.length)return;const t=e.length,n=Math.ceil(Math.sqrt(t)),o=Math.ceil(t/n),d=e[0].width,l=e[0].height,a=8,r=(f.ownerDocument.defaultView??window).devicePixelRatio||1,i=Math.round(26*r),s=Math.round(12*r),u=f.ownerDocument.createElement("canvas");u.width=n*d+(n-1)*a,u.height=o*(l+i)+(o-1)*a;const m=u.getContext("2d"),M=Fo($);m.fillStyle=M.background,m.fillRect(0,0,u.width,u.height),e.forEach((D,x)=>{const y=x%n,B=Math.floor(x/n),j=y*(d+a),U=B*(l+i+a),bt=D.closest(".wmap-gallery-card")?.querySelector("span")?.textContent??"";m.fillStyle=M.surface,m.fillRect(j,U,d,i),m.fillStyle=M.text,m.font=`700 ${s}px system-ui, sans-serif`,m.textAlign="left",m.textBaseline="middle",m.fillText(bt,j+Math.round(10*r),U+i/2,d-Math.round(20*r)),m.drawImage(D,j,U+i)}),u.toBlob(D=>{if(!D)return;if(p.downloadFilename!=null){vn(D,p.downloadFilename,p.onSaveImage);return}const x=S.find(y=>y!=null)?.getExportTitle();vn(D,["gallery",x].filter(Boolean).join(" "),Fe.onSaveImage)})}return{setItems(e){v=e.map(n=>typeof n=="function"?null:n);const t=c.plotMode;if(be.has(t))if(e.some(o=>typeof o=="function"))Z(e);else{const o=mt(t);c={...c,...o},Z(Re(t))}else Z(e)},setOptions(e){T(e,{fireCallback:!1})},getOptions(){return Bn(c)},setFindingsNotice(e){It=e,N()},setColumns(e){ln(e)},getBinColors(){return c.binColors??fe()},setLotStatsSummary(e){V=e,Be(),b&&N(),le()},openUserGuide:Zt,destroy(){xe++,ue?.cancel(),ue=null,ke=null;for(const e of[..._.values()])e.closePollId!=null&&clearInterval(e.closePollId),e.close(),e.ctrl.destroy();_.clear();for(const e of S)e&&e.destroy();S=[],Me()?.remove(),cn.disconnect(),he&&((f.ownerDocument.defaultView??window).cancelAnimationFrame(he),he=0),f.ownerDocument.removeEventListener("click",je,!0),window.removeEventListener("blur",Rt),ie(),yn(),Le.remove(),q.remove(),b?.remove(),me?.destroy()}}}
1
+ import{getUniqueTestNumbers as Mo,resolveTestNumber as Do,findTestDef as ko,collectMetadataValues as Eo}from"../renderer/buildView.js";import{metadataCategoricalValue as Bo}from"../core/metadata.js";import{resolveBinColorsForMaps as Oo,mergeBinDefs as Ye,binColorWarning as To,mixedPassBinsWarning as Lo,binColorsEqual as Ro}from"../renderer/binColors.js";import{itemPassBins as Io,INPUT_DEFAULT_PASS_BINS as Wo}from"../core/passBins.js";import{NO_DATA_FILL as $o}from"../renderer/colorMap.js";import{metadataValueColor as Ao}from"../renderer/colorMap.js";import{resolveCanvasTheme as Po}from"./canvasTheme.js";import{ICONS as We}from"./icons.js";import{SHADOW as $e,LEADING as Ze,TRACKING as Fo,controlStyle as Ho,wireControlHover as xt,SPACE as w,EDGE_GUTTER as oe,MAP_CHROME_INSET as jo,RADIUS as z,FONT as L,CLR as h,sevColor as gn,MODE_LABELS as Vo,BIN_LEGEND_MODES as hn,STACKED_MODES as be,Z_ABOVE as bn,applyOverlayZ as No,getTooltip as zo,hideTooltip as yn,createToolbarHelpers as _o,buildModeMenuEl as Go,openDetachWindow as Ko,openFloatingWindow as qo,openModal as Uo,openReportModal as Xo,copyWmapThemeTokens as Yo,syncWmapPopupTheme as Zo,openUserGuideWindow as Qo,makePaletteBtn as Jo,makeLogScaleBtn as ei,makeLegendStyleBtn as ti,makeOverlaysBtn as ni,makeOrientationBtn as oi,menuLayerFor as wn,saveImageBlob as ii,markMenuTrigger as Ae,wireMenuA11y as vn,wireExpandToggle as xn,wireTooltip as Cn,requestedPassFailDisplay as Sn,overlayMenuRows as ai,anyOverlayActive as li,logWmapVersionOnce as si,buildDataModeEntries as ri,metadataKeyHasData as di,metadataModeEntry as ci}from"./toolbar.js";import{waferDisplayLabel as Qe,waferIdentityLabel as Mn}from"../core/waferLabel.js";import{metadataDisplayValue as ui}from"../core/metadata.js";import{withExportContext as fi}from"./exportName.js";import{sortBinsForDisplay as pi}from"../stats/binPareto.js";import{diePassStatus as mi}from"../core/dies.js";import{aggregateValues as gi,aggregateBinCounts as Dn}from"../core/aggregates.js";import{renderWaferMap as hi,renderWaferMapCard as kn,toPublicViewOptions as En}from"./renderWaferMap.js";import{hasDrilldownTargets as bi,waferPopulation as yi}from"./chartPopulation.js";import{classifyChanged as wi,COLOR_KEYS as vi}from"./renderWaferMap.js";import{buildWaferMap as xi,getTestPassStatus as Bn,isParametricTest as Ct,getDieTestValue as Ci}from"../renderer/buildWaferMap.js";import{analyzeWaferMap as Je}from"../stats/analyzeWaferMap.js";import{collectWarnings as Si,buildWarningsMenuEl as Mi,severityOf as Di}from"./warnings.js";import{compareNatural as St,arrayEqual as On}from"../core/utils.js";import{createSummaryPanelEl as Mt,buildMetadataStripRow as ki,buildCompactMetadataRows as Tn,metadataEntries as Ln,renderLotSummaryContentSteps as Ei,reportMapsFromItems as Bi}from"./summaryPanel.js";import{renderLotReportHtml as Oi}from"../stats/renderSummaryReport.js";import{prettyKey as Ti}from"../stats/facets.js";import{testLabel as Li,markedTestLabel as Ri,derivedFields as Ii}from"../renderer/testLabel.js";import{mergeTestDefs as Wi}from"../stats/mergeTestDefs.js";import{getDieKey as $i,hasPosition as Ai}from"../core/dies.js";import{runChunked as Pi}from"./chunked.js";function Rn(f){if(typeof f!="number"||!Number.isFinite(f))return;const C=Math.round(f);return C>=1?C:void 0}const Dt=12;function Fi(f,C,p){let A=C;if(C.length>Dt){const k=C.slice(0,Dt-1),I=C.slice(Dt-1),H=I.reduce((X,ie)=>X+ie.count,0);A=[...k,{color:h.label,count:H,label:`Other (${I.length} bins)`}]}const D=f.createElement("div");Object.assign(D.style,{display:"flex",columnGap:"1px",width:"100%",height:"8px",borderRadius:z.control,overflow:"hidden",border:`1px solid ${h.menuBorder}`,boxSizing:"border-box",marginTop:w.xs,flexShrink:"0"}),D.setAttribute("role","img"),D.setAttribute("aria-label",`Population split: ${A.map(k=>`${k.label} ${et(k.count/p*100)}`).join(", ")}`);for(const k of A){const I=k.count/p*100,H=f.createElement("div");Object.assign(H.style,{flex:`${I} 1 0`,minWidth:I>0?"2px":"0",background:k.color}),Cn(H,`${k.label} \xB7 ${k.count.toLocaleString()} dies \xB7 ${et(I)}`),D.appendChild(H)}return D}function et(f){return f>0&&f<.1?"<0.1%":`${f.toFixed(1)}%`}function In(f,C,p){const A=new Map;let D=0,k=0;for(const I of f){const H=p?new Set(p(I)):void 0;for(const X of I.dies){if(X.partial||X.edgeExcluded)continue;const ie=C(X);ie!==void 0&&(A.set(ie,(A.get(ie)??0)+1),D++,H&&mi(X,H)&&k++)}}return{counts:A,total:D,pass:k}}function Wn(f,C){const p=f.ownerDocument.createElement("div");Object.assign(p.style,{display:"flex",alignItems:"center",gap:"5px",cursor:"pointer",userSelect:"none",padding:`${w.xxs} ${w.xs}`,borderRadius:z.control});const A=f.ownerDocument.createElement("span");Object.assign(A.style,{display:"inline-block",width:"13px",height:"13px",flexShrink:"0",background:C.color,border:C.isActive?`2px solid ${h.iconActive}`:`1px solid ${h.menuBorder}`,borderRadius:z.control,boxSizing:"border-box"});const D=f.ownerDocument.createElement("span");if(D.textContent=C.label,Object.assign(D.style,{fontWeight:C.isActive?"700":"400",color:C.isActive?h.iconActive:h.text,whiteSpace:"nowrap"}),p.appendChild(A),p.appendChild(D),C.count!==void 0){const k=f.ownerDocument.createElement("span");if(k.textContent=C.count.toLocaleString(),Object.assign(k.style,{color:C.isActive?h.iconActive:h.text,fontWeight:C.isActive?"700":"400",whiteSpace:"nowrap"}),p.appendChild(k),C.percent!==void 0){const I=f.ownerDocument.createElement("span");I.textContent=et(C.percent),Object.assign(I.style,{color:h.label,whiteSpace:"nowrap"}),p.appendChild(I)}}p.setAttribute("role","button"),p.setAttribute("aria-pressed",C.isActive?"true":"false"),p.tabIndex=0,p.addEventListener("mouseenter",()=>{p.style.background=h.bgHover}),p.addEventListener("mouseleave",()=>{p.style.background="transparent"}),p.addEventListener("focus",()=>{p.style.background=h.bgHover}),p.addEventListener("blur",()=>{p.style.background="transparent"}),p.addEventListener("click",C.onClick),p.addEventListener("keydown",k=>{(k.key==="Enter"||k.key===" ")&&(k.preventDefault(),C.onClick())}),f.appendChild(p)}export function renderWaferGallery(f,C,p={}){si();const A=6;let D=Rn(p.columns);const k=p.showHelpButton??!1,I=p.userGuideExtension,H=p.insights?.enabled??!1,X=p.insights?.sweeps?{sweeps:p.insights.sweeps}:void 0,ie=No(p.zIndex),re=p.summaryPanel,$n=e=>[...Io(e)],kt=()=>v.flatMap(e=>e?[e.ringCount??4]:[]),tt=()=>kt()[0]??4;function An(e){const t=[...new Set(e)].sort((n,o)=>n-o);return t.length<2?null:{code:"ring-count-mixed",severity:"warning",message:`These wafers were built with different ring counts (${t.join(", ")}). Each card and each wafer's findings use their own; the lot's ring yield in the Summary panel, report and Insights uses ${e[0]} rings.`}}let V=p.lotStatsSummary,ye=p.viewOptions?.legendPosition??"default",Pe=p.perCardLegend??!1;function we(){const e=c.plotMode??"hardBin";return hn.has(e)?null:c.colorbarRangeMode==="data"?"Each map has its own value range, so it keeps its own colour bar":"These wafers have no shared colour bar for value mode, so each map keeps its own"}function Et(){const e=Pe||we()!==null;for(const t of S)t&&t.setOptions({showLegend:e})}let c={plotMode:"hardBin",showDieLabels:!1,showRingBoundaries:!1,showQuadrantBoundaries:!1,rotation:0,flipX:!1,flipY:!1,...p.viewOptions},S=[],ae=[],de=[],R=[];const Fe=fi(()=>{const e=R.filter(n=>n!=null),t=[...new Set(e.map(n=>ui(n.wafer.metadata?.lot)).filter(n=>n!==void 0))].sort(St);return{prefix:p.downloadFilename,lots:t,...e.length===1?{wafer:Mn(e[0])}:{waferCount:e.length}}},p.onSaveImage,p.onSaveText);let v=C.map(e=>typeof e=="function"?null:e);function Bt(){return Wi(v)}function ve(){if(v.some(e=>e?.testDefs?.length))return Bt().defs}let xe=0,He=0;const _=new Map;let Pn=0,P=null,Ce=null,Ot=new Set,b=null,Fn={};function Tt(e){return v[e]?.statsSummary??V?.perWafer.find(t=>t.waferIndex===e)?.summary}function nt(){return!!(v.some(e=>e?.statsSummary?.findings.length)||V?.perWafer.some(e=>e.summary.findings.length))}const Hn=zo(),ce=_o(Hn),{makeBtn:Q,setActive:Se,makeSep:G,makeMenuRow:jn,makeMenuSection:Vn,makeDropdown:Lt,closeOpenMenu:je,getOpenMenu:Me,setOpenMenu:De}=ce;f.ownerDocument.addEventListener("click",je,!0);const Rt=()=>yn();window.addEventListener("blur",Rt);let It=p.findingsNotice;function Wt(e){Ot=new Set(e);const t=[...$.querySelectorAll(".wmap-gallery-card")];let n;t.forEach((o,d)=>{const l=Ot.has(d);o.style.outline=l?`3px solid ${h.findingHighlight}`:"",o.style.outlineOffset=l?"-3px":"",l&&n===void 0&&(n=o)}),n?.scrollIntoView?.({behavior:"smooth",block:"nearest"})}function $t(){Wt([])}function At(){for(const e of S)e&&e.clearSelection()}function ot(e,t){const n=new Set(e),o=t??S.map((d,l)=>l);for(const d of o){const l=R[d],a=S[d];if(!l||!a)continue;const r=l.dies.filter(i=>n.has($i(i)));a.setSelection(r)}}function Nn(){const e=[];for(let t=0;t<v.length;t++){const n=v[t];if(!n)continue;const o=Tt(t)?.findings??[];o.length&&e.push({index:t,item:n,unusualCount:o.filter(d=>d.severity==="unusual").length,notableCount:o.filter(d=>d.severity==="notable").length,totalCount:o.length})}return e}function zn(e){const t=R[e]??v[e];t&&Ie(e,t)}function _n(e){const t=Tt(e)?.findings??[];if(t.length)return{total:t.length,unusual:t.filter(n=>n.severity==="unusual").length,notable:t.filter(n=>n.severity==="notable").length}}function Gn(){Xo(Oi(Bi(v,Wo,tt())),{anchor:f})}function Kn(){if(!b)return;b.innerHTML="";const e=Nn();if(v.length>0){const n=f.ownerDocument.createElement("div"),o=e.length,d=v.filter(Boolean).length;n.textContent=o===0?`No findings on any of the ${d} wafers`:`${o} of ${d} wafer${d===1?"":"s"} with findings`,Object.assign(n.style,{fontSize:L.body,color:h.label,marginBottom:w.md}),b.appendChild(n)}if(e.length>0){const n=f.ownerDocument.createElement("button");n.type="button",n.textContent="Summary report",Object.assign(n.style,{...Ho("outlined"),marginBottom:w.lg,display:"block",width:"100%",textAlign:"left"}),xt(n),n.addEventListener("click",Gn),b.appendChild(n)}if(e.length===0){const n=f.ownerDocument.createElement("div");Object.assign(n.style,{color:h.icon,fontSize:L.body,padding:"4px 0"}),n.textContent="No findings on any wafer.",b.appendChild(n)}else for(const{index:n,item:o,unusualCount:d,notableCount:l,totalCount:a}of e){const r=d?"unusual":l?"notable":"info",i=d+l||a,s=f.ownerDocument.createElement("button");s.type="button",Object.assign(s.style,{display:"flex",alignItems:"center",justifyContent:"space-between",width:"100%",padding:"5px 8px",marginBottom:w.xs,border:"none",borderLeft:`3px solid ${gn(r)}`,borderRadius:z.control,background:h.bgHover,cursor:"pointer",fontSize:L.body,textAlign:"left",boxSizing:"border-box"}),s.addEventListener("mouseover",()=>{s.style.background=h.bgActive}),s.addEventListener("mouseout",()=>{s.style.background=h.bgHover});const u=f.ownerDocument.createElement("span");u.textContent=Qe(o,n),Object.assign(u.style,{color:h.iconHover,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"});const m=f.ownerDocument.createElement("span");m.textContent=String(i),s.setAttribute("aria-label",`${Qe(o,n)} \u2014 ${i} finding${i===1?"":"s"}${d?`, ${d} unusual`:""} \u2014 view wafer`),Object.assign(m.style,{marginLeft:w.sm,flexShrink:"0",background:gn(r),color:"#fff",borderRadius:z.container,padding:"1px 5px",fontSize:L.body,fontWeight:"600"}),s.appendChild(u),s.appendChild(m),s.addEventListener("click",()=>Ie(n,o)),b.appendChild(s)}const t=f.ownerDocument.createElement("div");t.style.height="12px",b.appendChild(t)}let ue=null,ke=null;function N(){if(b)if(ue?.cancel(),ue=null,V){const e=Ye(v.map(n=>n?.hbinDefs)),t=Ye(v.map(n=>n?.sbinDefs));ue=Pi(Ei(b,{lotSummary:V,items:v,hbinDefs:e.length?e:void 0,sbinDefs:t.length?t:void 0,testDefs:ve(),ringCount:tt(),binColors:c.binColors,plotMode:c.plotMode??"hardBin",fallbackFormat:c.fallbackFormat,activeFindingId:Ce,warnings:p.warnings?.display??!0?J:[],findingsFilter:Fn,findingsNotice:It,onFindingsFilterChange:N,onSaveText:Fe.onSaveText,onFindingClick:(n,o)=>{Ce===n.id?it():Un(n,o),N()},onWaferClick:zn,findingsFor:_n,dieListOptions:p.dieList}),{onDone:()=>{const n=ke;ke=null,n?.()}})}else Kn()}function qn(e){const t=e.highlight;return t?.kind==="wafer"&&t.waferIndices?.length?t.waferIndices:null}function Pt(e){return[e.variable.kind,e.variable.index??"",e.variable.bin??"",e.comparison.family,e.comparison.left,e.effect.direction].join("|")}let Ve=[];function Ft(){if(Ve.length!==0){for(const e of Ve)S[e]?.setOptions({plotMode:c.plotMode,activeTest:c.activeTest});Ve=[]}}function it(){Ce=null,$t(),At(),Ft(),T({highlightBin:void 0},{fireCallback:!1})}function Un(e,t){if(Ce===e.id){it();return}Ce=e.id,t.style.background=h.bgActive,t.style.fontWeight="600",Ft();const{kind:n,index:o}=e.variable;if(n==="test"){const l=o??0,a=ve();if(a===void 0||a.some(i=>i.testNumber===l))T({plotMode:"value",activeTest:l,highlightBin:void 0},{fireCallback:!1});else{T({highlightBin:void 0},{fireCallback:!1});const s=be.has(c.plotMode??"hardBin")?null:qn(e);if(s){for(const u of s)S[u]?.setOptions({plotMode:"value",activeTest:l});Ve=[...s]}}}else n==="softBin"?T({plotMode:"softBin",highlightBin:void 0},{fireCallback:!1}):T({plotMode:"hardBin",highlightBin:void 0},{fireCallback:!1});$t(),At();const d=e.highlight;if(d.kind==="wafer"){Wt(d.waferIndices);const l=Pt(e);for(const a of d.waferIndices){const s=R[a]?.statsSummary?.findings.find(u=>Pt(u)===l)?.highlight?.dieKeys;s?.length&&ot(s,[a])}}else d.kind==="bin"?d.dieKeys?.length&&ot(d.dieKeys):(d.kind==="region"||d.kind==="dies")&&d.dieKeys?.length&&ot(d.dieKeys)}function le(){if(!P)return;const e=!!b;P.style.display=(V||nt())&&e&&!Te?"flex":"none";const t=b?b.style.display!=="none":!1;(V?.hasNotableFindings||v.some(o=>o?.statsSummary?.hasNotableFindings))&&!t?P.style.color=h.findingIndicator:P.dataset.active||(P.style.color=h.icon)}const W=f.ownerDocument.createElement("div");W.dataset.wmapToolbar="gallery",Object.assign(W.style,{flexShrink:"0",marginLeft:"auto",display:"inline-flex",flexDirection:"row",alignItems:"center",gap:"0",background:h.menuBg,border:`1px solid ${h.menuBorder}`,borderRadius:z.control,padding:"0",boxShadow:$e.panel,flexWrap:"wrap",minWidth:"0",overflowX:"auto"});const Ht=()=>{const e=Me();e&&(e.remove(),De(null)),Ae(Y,!1)},Y=Q("mode","Plot mode",()=>{if(Me()){Ht();return}const e=v.flatMap(y=>y?.dies??[]),t=ve(),{testEntries:n,binEntries:o,stackedEntries:d}=ri(e,t,{includeStacked:!0}),l=v.filter(Boolean).length,a=y=>{if(y===void 0)return l;let B=0;for(const j of v)j?.dies?.some(U=>Bn(U,y)!==void 0||U.testValues?.[y]!==void 0)&&B++;return B},r=l<2?n:n.map(y=>{const B=a(y.activeTest);return B===l?y:{...y,label:`${y.label} \u2014 ${B} of ${l} wafers`}}),i=c.plotMode??"hardBin",s=c.activeTest??0;function u(y){return y.plotMode!==i?!1:y.plotMode==="value"?s===(y.activeTest??0):y.plotMode==="metadata"?c.activeMetadataKey===y.activeMetadataKey:!0}function m(y,B){y.activeTest!==void 0?T({plotMode:"value",activeTest:y.activeTest,activeMetadataKey:void 0,logScale:y.logScale}):y.activeMetadataKey!==void 0?T({plotMode:y.plotMode,activeTest:void 0,activeMetadataKey:y.activeMetadataKey,passFailDisplay:"off"}):T({plotMode:y.plotMode,activeTest:void 0,activeMetadataKey:void 0,passFailDisplay:"off"}),B.remove(),De(null),Ae(Y,!1)}const M=new Set,E=v.flatMap(y=>y?.metadataFields??[]).filter(y=>!M.has(y.key)&&M.add(y.key)).filter(y=>di(e,y.key)).map(ci),x=Go(Y.getBoundingClientRect(),r,o,d,u,m,{makeMenuRow:jn,makeMenuSection:Vn},i,Y.ownerDocument.defaultView??window,E);wn(Y).appendChild(x),De(x),Ae(Y,!0),vn(x,Y,Ht)});Ae(Y,!1);const Xn=()=>R.flatMap(e=>e?[...e.hbinDefs??[],...e.sbinDefs??[]]:[]).some(e=>e.color),{btn:Yn,sync:jt}=Jo(ce,()=>({...c,plotMode:c.plotMode??"hardBin"}),Xn,e=>T(e));jt();const Zn=C.some(e=>typeof e!="function"&&(e.reticles?.length??0)>0);function Ne(){const e=ve(),{testNumber:t}=Do(c.activeTest??0,e);return{testNumber:t,td:ko(e,t)}}function Vt(){if((c.plotMode??"hardBin")!=="value")return!1;const{td:e}=Ne();return e!==void 0&&(e.limitLow!==void 0||e.limitHigh!==void 0)}function Ee(){if((c.plotMode??"hardBin")!=="value")return!1;const{td:e}=Ne();return e!==void 0&&!Ct(e)}function Qn(){if((c.plotMode??"hardBin")!=="value")return!1;const{testNumber:e,td:t}=Ne();return v.some(n=>n?.dies?.some(o=>Bn(o,e,t)!==void 0))}function Jn(e,t){if(!t||!Ct(t))return;const n=t.limitLow!==void 0||t.limitHigh!==void 0;if((Sn(c)==="spec"&&n?"spec":c.colorbarRangeMode??"spec")==="spec"&&n)return;let l=1/0,a=-1/0;for(const r of v)if(r)for(const i of r.dies){const s=Ci(i,e);s!==void 0&&(s<l&&(l=s),s>a&&(a=s))}if(isFinite(l))return l===a?[l,l+1]:[l,a]}function at(e,t,n){const o=c[e];if(o===t||o!=null&&t!=null&&n(o,t))return!1;c={...c,[e]:t};for(const d of S)d&&d.setOptions({[e]:t});return!0}function Nt(){if((c.plotMode??"hardBin")!=="metadata")return;const e=c.activeMetadataKey;if(!e)return;const t=new Set;for(const n of v)if(n)for(const o of Eo(n.dies,e))t.add(o);return{key:e,values:[...t].sort(St)}}function lt(){at("metadataValueOrder",Nt(),(e,t)=>e.key===t.key&&On(e.values,t.values))}function st(){if((c.plotMode??"hardBin")!=="value")return;const{testNumber:e,td:t}=Ne(),n=Jn(e,t);at("valueRange",n?{test:e,range:n}:void 0,(d,l)=>{const a=s=>Array.isArray(s)?{test:void 0,range:s}:{test:s.test,range:s.range},r=a(d),i=a(l);return r.test===i.test&&On(r.range,i.range)})}let rt=!1;function eo(){if(rt)return;rt=!0,(f.ownerDocument.defaultView?.requestAnimationFrame??(t=>setTimeout(()=>t(0),0)))(()=>{rt=!1,st(),lt(),_t()})}let dt=!1;function to(){if(dt)return;dt=!0,(f.ownerDocument.defaultView?.requestAnimationFrame??(t=>setTimeout(()=>t(0),0)))(()=>{dt=!1,qe()})}let zt=[];function fe(){const{colors:e,mixedHardBins:t}=Oo(v.filter(n=>n!=null),{binColorScheme:c.binColorScheme,useDefinedBinColors:c.useDefinedBinColors});return zt=t,e}function _t(){at("binColors",fe(),Ro),Be()}const no=ni(ce,()=>ai(c,Zn,{functionalActive:Ee(),hasLimits:Vt()&&!Ee(),hasRecorded:Qn()&&!Ee(),binMode:(c.plotMode??"hardBin")==="hardBin"||(c.plotMode??"hardBin")==="softBin"},e=>T(e)),()=>li(c)),{btn:oo,sync:Gt}=ti(ce,()=>({plotMode:c.plotMode,legendPosition:ye}),e=>{ye=e;for(const t of S)t&&t.setOptions({legendPosition:ye})},{get:()=>Pe,set:e=>{Pe=e,Et()},blockedReason:we});Gt();const io=[{value:"mean",label:"Mean"},{value:"median",label:"Median"},{value:"stddev",label:"Std Dev"},{value:"min",label:"Min"},{value:"max",label:"Max"},{value:"count",label:"Count"}],Kt=Lt("aggr","Aggregation method",()=>io,()=>c.aggregationMethod??"mean",e=>T({aggregationMethod:e}));function qt(){const e=c.plotMode==="stackedValues";Kt.style.display=e?"":"none"}qt();const{btn:ao,sync:Ut}=ei(ce,()=>({...c,functionalActive:Ee()}),e=>T(e));Ut();const ze=Q("specRange","Colorbar range: test limits",()=>{const e=c.colorbarRangeMode==="data"?"spec":"data";T({colorbarRangeMode:e})});function Xt(){const e=(c.plotMode??"hardBin")==="value"&&Vt()&&Sn(c)==="off"&&!Ee();ze.style.display=e?"":"none";const t=(c.colorbarRangeMode??"spec")==="spec";Se(ze,t),ze.ariaLabel=t?"Colorbar range: test limits (click for data range)":"Colorbar range: data range (click for test limits)"}Xt();const lo=oi(ce,()=>c,e=>T(e)),so=Q("downloadAll","Download gallery PNG",xo),ro=Lt("columns","Columns",()=>[{value:"auto",label:"Auto"},{value:"1",label:"1 column"},{value:"2",label:"2 columns"},{value:"3",label:"3 columns"},{value:"4",label:"4 columns"},{value:"5",label:"5 columns"}],()=>D!=null?String(D):"auto",e=>ln(e==="auto"?void 0:Number(e))),O=f.ownerDocument.createElement("div");Object.assign(O.style,{display:"inline-flex",alignItems:"center",gap:"0"}),W.appendChild(O),O.appendChild(Y),O.appendChild(Yn),O.appendChild(Kt),O.appendChild(ao),O.appendChild(ze),O.appendChild(G()),O.appendChild(no),O.appendChild(G()),O.appendChild(oo),O.appendChild(G()),O.appendChild(lo),O.appendChild(G()),O.appendChild(ro),O.appendChild(G()),O.appendChild(so),(V||nt())&&(P=Q("findings","Summary panel",()=>{if(!b)return;const e=b.style.display!=="none";e||N(),b.style.display=e?"none":"flex",Se(P,!e),le()}),W.appendChild(G()),W.appendChild(P));let K=null,_e=null,J=[],Yt=!1;function Be(){const e=Si({lotStatsSummary:V,result:{warnings:[...v.flatMap(n=>n?.warnings??[]),...Bt().warnings]},extra:[c.binColors&&To(c.binColors,c.plotMode),Lo(zt),An(kt())].filter(n=>!!n)}),t=e.length!==J.length||e.some((n,o)=>n.code!==J[o]?.code||n.message!==J[o]?.message);J=e,(t||!Yt)&&(Yt=!0,p.warnings?.onWarning?.(e)),co()}function co(){if(!K||!_e)return;const e=J.length,t=e>0;if(K.style.display=t?"flex":"none",_e.style.display=t?"":"none",!t)return;const n=Di(J[0]),o=`${e} data ${e===1?"warning":"warnings"}`;K.style.color=n==="error"?h.errText:h.warnText,K.ariaLabel=n==="error"?`${o} \u2014 some wafers may be positionally wrong`:o}(p.warnings?.display??!0)&&(_e=G(),K=Q("warning","Data warnings",()=>{const e=Me();if(je(new MouseEvent("click")),e)return;const t=Mi(K.getBoundingClientRect(),J,K.ownerDocument.defaultView??window);wn(f).appendChild(t),De(t),vn(t,K,()=>je(new MouseEvent("click")))}),Ae(K,!1),W.appendChild(_e),W.appendChild(K)),Be();let se=null;H&&(se=Q("analysis","Insights",()=>{Jt(!Te)}),se.dataset.wmapInsightsBtn="1",W.appendChild(G()),W.appendChild(se));function Zt(){import("./userGuideHtml.js").then(e=>Qo({buildWaferMap:xi,renderWaferMap:hi,renderWaferGallery,analyzeWaferMap:Je},e.USER_GUIDE_HTML,I,f))}k&&(W.appendChild(G()),W.appendChild(Q("help","User guide",()=>Zt())));const pe=f.ownerDocument.createElement("div");pe.dataset.wmapGalleryMeta="1",Object.assign(pe.style,{flex:"1",minWidth:"0",overflow:"hidden",display:"flex",alignItems:"center",padding:`${w.sm} ${w.lg}`,fontSize:L.sub,lineHeight:Ze.none,boxSizing:"border-box"});const Ge=f.ownerDocument.createElement("div");Object.assign(Ge.style,{background:h.canvasBg,display:"flex",alignItems:"stretch",gap:w.lg,paddingBottom:w.lg,minWidth:"0"});const ee=f.ownerDocument.createElement("div");ee.dataset.wmapGalleryLegend="1",Object.assign(ee.style,{display:"flex",flexDirection:"column",gap:w.sm,background:h.menuBg,border:`1px solid ${h.menuBorder}`,borderRadius:z.container,padding:`${w.sm} ${w.lg}`,marginBottom:w.lg,boxShadow:$e.panel,fontSize:L.body,lineHeight:Ze.none,boxSizing:"border-box",width:"100%",minWidth:"0"});const q=f.ownerDocument.createElement("div");Object.assign(q.style,{display:"flex",flexDirection:"row",alignItems:"flex-start"});let me=null,Oe=null,Qt=null;function uo(){return H?me?Promise.resolve(me):(Qt??=import("./insightsTab.js").then(({createInsightsTab:e})=>(me=e({getItems:()=>v,getLotStats:()=>V,getBinColors:()=>c.binColors??fe(),getRingCount:tt,defaultView:p.insights?.defaultView,sweeps:p.insights?.sweeps,onRemoveSweeps:p.insights?.onRemoveSweeps,onOpenGuide:void 0,showMetadataStrip:!1,onSaveImage:Fe.onSaveImage,onSaveText:Fe.onSaveText,ownerDocument:f.ownerDocument,openWafer:(t,n,o)=>{const d=v[t];if(!d)return;let l=null;const a=Uo({title:n,onClose:()=>l?.destroy(),anchor:f});dn(a,n,d.wafer.metadata??void 0),l=ht(a.contentWrap,d,o)}}),Oe=me.el,Oe.style.display="none",f.appendChild(Oe),me)),Qt):Promise.resolve(null)}let Te=!1;function Jt(e){H&&(Te=e,Oe&&(Oe.style.display=e?"flex":"none"),q.style.display=e?"none":"flex",O.style.display=e?"none":"inline-flex",W.style.display="inline-flex",se&&(Se(se,e),se.innerHTML=e?We.wafer:We.analysis,se.ariaLabel=e?"Back to gallery view":"Insights"),le(),qe(),e&&uo().then(t=>{!t||!Te||(t.el.style.display="flex",t.render())}))}H&&p.insights?.defaultOpen&&queueMicrotask(()=>Jt(!0));const fo=4,ct=240,en=480,po=720,mo=1.25;let ge=en;function tn(e){const t=A*2+110+2;let n=null;for(const o of e){if(o==null||!o.dies?.length)continue;const d=o.dies[0].width;if(!(d>0))continue;const l=o.wafer.radius*2*(fo/d),a=Math.ceil(l+t);(n==null||a>n)&&(n=a)}return n}function go(e){const t=tn(e);return t==null?ct:Math.min(ge,Math.max(ct,t))}function ho(e){const t=tn(e);if(t==null)return!1;const n=Math.min(po,Math.max(en,t));return n<=ge?!1:(ge=n,!0)}function ut(){return D!=null?"none":`${ge}px`}function nn(){const e=ut();for(const t of Array.from($.children))t.classList.contains("wmap-gallery-card")&&(t.style.maxWidth=e,t.style.maxHeight=e)}let Ke=ct,on=0;function an(e){if(ho(e)&&nn(),D==null){const n=go(e);n>Ke&&(Ke=n)}pt()}function ln(e){D=Rn(e),nn(),pt()}function ft(e){return`repeat(${e}, minmax(0, ${D!=null?"1fr":`${ge}px`}))`}function sn(e){$.style.gridTemplateColumns!==e&&($.style.gridTemplateColumns=e)}function pt(){if(D!=null){sn(ft(D));return}const e=Math.max(1,on),t=12,n=$.clientWidth||0,o=l=>(n-t*(l-1))/l;let d=Math.max(1,Math.ceil(Math.sqrt(e)));if(n>0){const l=Math.min(ge,Ke*mo),a=r=>{let i=0;for(;i<e&&o(i+1)>=r;)i++;return i};d=a(l)||a(Ke)||1}sn(ft(d))}const $=f.ownerDocument.createElement("div");if(Object.assign($.style,{flex:"1 1 0",minWidth:"0",display:"grid",gridTemplateColumns:ft(1),gap:w.xl,paddingLeft:oe,paddingRight:oe,justifyContent:"start",alignContent:"start",isolation:"isolate"}),re?.placement){const e=re.placement;b=Mt(e,oe,f.ownerDocument),b.style.maxHeight="calc(100vh - 80px)",b.style.position="sticky",b.style.top="8px",b.style.display="flex",b.style.flexDirection="column"}else if(V||nt()){const e=!!re?.defaultOpen;b=Mt("right",oe,f.ownerDocument),b.style.maxHeight="calc(100vh - 80px)",b.style.position="sticky",b.style.top="8px",b.style.flexDirection="column",b.style.display=e?"flex":"none",N()}le(),b?.style.display!=="none"&&P&&Se(P,!0),(re?.placement??"right")==="left"?(b&&q.appendChild(b),q.appendChild($)):(q.appendChild($),b&&q.appendChild(b));const Le=f.ownerDocument.createElement("div");Object.assign(Le.style,{position:"sticky",top:"0",display:"flex",flexDirection:"column",paddingLeft:oe,paddingRight:oe,paddingTop:oe,zIndex:"1",background:h.menuBg}),Ge.appendChild(pe),Ge.appendChild(W),Le.appendChild(Ge),Le.appendChild(ee),f.appendChild(Le),f.appendChild(q);function qe(){ee.innerHTML="";const e=c.plotMode??"hardBin",t=!Te&&hn.has(e),n=R.filter(g=>g!=null),o=n.find(g=>g.isLotStack),d=ki(n.map(g=>({metadata:g.wafer.metadata??void 0})),o?{lotSize:o.lotSize??n.length,aggrMethod:o.aggrMethod}:void 0),l=e==="metadata",a=c.activeMetadataKey,r=t&&!l?In(n,g=>(e==="softBin"?g.sbin:g.hbin)??void 0,$n):{counts:new Map,total:0,pass:0},i=t&&!l?c.binColors??fe():void 0,s=i?e==="softBin"?i.pass.soft:i.pass.hard:new Set,u=pi(r.counts.entries(),s).map(([g])=>g),m=t&&l&&a?In(n,g=>Bo(g.metadata?.[a])):{counts:new Map,total:0,pass:0},M=l?Nt()?.values:void 0,E=t&&l?(M??[...m.counts.keys()].sort(St)).filter(g=>m.counts.has(g)):[];if(pe.innerHTML="",d&&pe.appendChild(d),pe.style.display=d?"flex":"none",!u.length&&!E.length){ee.style.display="none";return}ee.style.display="flex";const x=f.ownerDocument.createElement("div");Object.assign(x.style,{display:"flex",flexWrap:"wrap",alignItems:"center",gap:`${w.sm} ${w.xl}`,maxHeight:"86px",overflowY:"auto",overflowX:"hidden"}),ee.appendChild(x);const y=c.highlightBin,B=R.flatMap(g=>g?.metadataFields??[]).find(g=>g.key===a),j=l?B?.label??(a?Ti(a):"Metadata"):Vo[e],U=f.ownerDocument.createElement("span");if(U.textContent=j,Object.assign(U.style,{fontSize:L.body,fontWeight:"700",letterSpacing:Fo,textTransform:"uppercase",color:h.label,flexShrink:"0"}),x.appendChild(U),!l&&r.total>0){const g=r.pass,F=g/r.total*100,te=f.ownerDocument.createElement("span");te.textContent=`Yield ${et(F)}`,Object.assign(te.style,{fontSize:L.body,fontWeight:"700",color:h.value,whiteSpace:"nowrap",flexShrink:"0"});const ne=f.ownerDocument.createElement("span");ne.textContent=`${g.toLocaleString()} / ${r.total.toLocaleString()} dies`,Object.assign(ne.style,{fontSize:L.body,color:h.label,whiteSpace:"nowrap",flexShrink:"0"}),x.appendChild(te),x.appendChild(ne)}if(l){const g=c.highlightMetadataValue;E.forEach((F,te)=>{const ne=g===F,Xe=B?.values?.find(vt=>vt.value===F),So=Xe?.color??Ao(te),mn=m.counts.get(F)??0;Wn(x,{color:So,isActive:ne,label:Xe?.label??F,count:mn,percent:m.total>0?mn/m.total*100:void 0,onClick:()=>{const vt=c.highlightMetadataValue===F?void 0:F;T({highlightMetadataValue:vt})}})});return}const bt=e==="softBin"?R.flatMap(g=>g?.sbinDefs??[]):R.flatMap(g=>g?.hbinDefs??[]),un=new Set,yt=[];for(const g of bt)un.has(g.bin)||(un.add(g.bin),yt.push(g));const wt=yt.length>0?new Map(yt.map(g=>[g.bin,g])):null,fn=i??c.binColors??fe(),Co=e==="softBin"?fn.soft:fn.hard,pn=g=>Co.get(g)??$o;for(const g of u){const F=y===g,te=wt?.get(g),ne=r.counts.get(g)??0;Wn(x,{color:pn(g),isActive:F,label:te?.name?`${g} \xB7 ${te.name}`:`Bin ${g}`,count:ne,percent:r.total>0?ne/r.total*100:void 0,onClick:()=>{const Xe=c.highlightBin===g?void 0:g;T({highlightBin:Xe})}})}r.total>0&&u.length>1&&ee.appendChild(Fi(f.ownerDocument,[...r.counts.entries()].sort(([,g],[,F])=>F-g).map(([g,F])=>({color:pn(g),count:F,label:wt?.get(g)?.name?`${g} \xB7 ${wt.get(g).name}`:`Bin ${g}`})),r.total))}function Re(e){const t=v.filter(r=>r!==null);if(!t.length)return[];const n=t.map(r=>r.dies.filter(Ai)),o=t[0].wafer,d=t.length,l=o.metadata?{...o,metadata:(({wafer:r,waferId:i,...s})=>s)(o.metadata)}:o;function a(r,i){return{...r,stats:{...r.stats,isLotStack:!0,aggregationMethod:i,lotSize:d}}}if(e==="stackedValues"){const r=ve();let i=r?.filter(Ct);if(r!==void 0&&i?.length===0)return[];if(r?.length||(i=Mo(t.flatMap(m=>m.dies)).map(m=>({testNumber:m,name:Li(void 0,m)}))),!i?.length)return[];const s=c.aggregationMethod??"mean";return i.map(u=>{const m=gi(n,s,u.testNumber),M={testNumber:0,name:u.name,unit:u.unit,...Ii(u)};return{wafer:l,dies:m,testDefs:[M],label:`${Ri(u,u.testNumber)} \xB7 ${s}`,isLotStack:!0,aggrMethod:s,lotSize:d,statsSummary:a(Je({wafer:l,dies:m,testDefs:[M]},{testNumbers:[0]}),s)}})}if(e==="stackedBins"){let r=Ye(t.map(i=>i?.hbinDefs));return(!r||r.length===0)&&(r=[...new Set(t.flatMap(s=>s.dies.map(u=>u.hbin).filter(u=>u!=null)))].sort((s,u)=>s-u).map(s=>({bin:s,name:`Bin ${s}`}))),r.map(i=>{const s=Dn(n,i.bin,"hard"),u=[{bin:i.bin,name:i.name}];return{wafer:l,dies:s,hbinDefs:u,label:`${i.bin} \xB7 ${i.name}`,isLotStack:!0,aggrMethod:"countBin",lotSize:d,statsSummary:a(Je({wafer:l,dies:s,hbinDefs:u}),"countBin")}})}if(e==="stackedSoftBins"){let r=Ye(t.map(i=>i?.sbinDefs));return(!r||r.length===0)&&(r=[...new Set(t.flatMap(s=>s.dies.map(u=>u.sbin).filter(u=>u!=null)))].sort((s,u)=>s-u).map(s=>({bin:s,name:`Bin ${s}`}))),r.map(i=>{const s=Dn(n,i.bin,"soft"),u=[{bin:i.bin,name:i.name}];return{wafer:l,dies:s,sbinDefs:u,label:`${i.bin} \xB7 ${i.name}`,isLotStack:!0,aggrMethod:"countBin",lotSize:d,statsSummary:a(Je({wafer:l,dies:s,sbinDefs:u}),"countBin")}})}return t}function mt(e){const t=v.length;return e==="stackedBins"||e==="stackedSoftBins"?{valueRange:[0,t],lotSize:t}:e==="stackedValues"?{aggregationMethod:c.aggregationMethod??"mean",valueRange:void 0,lotSize:void 0}:{}}function T(e,{fireCallback:t=!0}={}){const n=Object.keys(e),o=c.plotMode,d=we()!==null;c={...c,...e};const l=c.plotMode,a=be.has(l),r=o!==void 0&&be.has(o),i=He>0;if("binColorScheme"in e||"useDefinedBinColors"in e){const u=fe();c={...c,binColors:u},e={...e,binColors:u}}if(e.plotMode!==void 0)if(a){const u=mt(l);if(c={...c,...u},i)for(const m of S)m&&m.setOptions(e);else Z(Re(l))}else if(r){const{valueRange:u,lotSize:m,aggregationMethod:M,...E}=c;if(c=E,i)for(const x of S)x&&x.setOptions(e);else Z(v.filter(x=>x!==null))}else for(const u of S)u&&u.setOptions(e);else if(e.aggregationMethod!==void 0&&l==="stackedValues")if(i)for(const u of S)u&&u.setOptions(e);else Z(Re("stackedValues"));else for(const u of S)u&&u.setOptions(e);we()!==null!==d&&Et(),qe(),qt(),Gt(),jt();const s=e.plotMode!==void 0&&e.plotMode!==o;(vi.some(u=>u in e)||s)&&N(),Be(),Ut(),Xt(),st(),lt(),t&&p.onViewOptionsChange?.(En(c),n,wi(n))}function rn(e,t,n){const o=e.createElement("div");Object.assign(o.style,{display:"flex",alignItems:"center",gap:w.xs,flex:"1",minWidth:"0"});const d=e.createElement("span");d.textContent=t,Object.assign(d.style,{fontWeight:"700",fontSize:L.sub,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}),o.appendChild(d);const l=Ln(n??{});let a=null;if(l.length>0){const r=e.createElement("span");Object.assign(r.style,{fontSize:L.body,lineHeight:Ze.none,color:h.label,flexShrink:"0"}),r.textContent="\u25BE",o.appendChild(r),Object.assign(o.style,{cursor:"pointer",borderRadius:z.control}),o.addEventListener("mouseenter",()=>{o.style.background=h.bgHover}),o.addEventListener("mouseleave",()=>{o.style.background="none"}),a=e.createElement("div"),a.dataset.wmapCardMetaPanel="1",Object.assign(a.style,{position:"absolute",top:"0",left:"0",right:"0",zIndex:bn,background:h.menuBg,borderBottom:`1px solid ${h.menuBorder}`,boxShadow:$e.menu,padding:`${w.md} ${w.lg}`,fontSize:L.body,display:"none"});const i=Tn(n??{});i&&a.appendChild(i),o.setAttribute("aria-expanded","false"),o.setAttribute("aria-label",`Wafer info for ${t||"this card"}. Click to expand.`),xn(o,s=>{r.textContent=s?"\u25B4":"\u25BE",o.setAttribute("aria-expanded",String(s)),a&&(a.style.display=s?"block":"none")})}return{wrap:o,metaPanel:a}}function dn(e,t,n){const o=e.box.querySelector("[data-wmap-window-title]"),d=Ln(n??{});if(!o||d.length===0)return;const l=o.parentElement,a=f.ownerDocument.createElement("div");Object.assign(a.style,{display:"flex",alignItems:"center",gap:w.xs,flex:"1",minWidth:"0",cursor:"pointer"}),xt(a,"bare"),l?.insertBefore(a,o),a.appendChild(o);const r=f.ownerDocument.createElement("span");Object.assign(r.style,{fontSize:L.body,lineHeight:Ze.none,color:h.label,flexShrink:"0"}),r.textContent="\u25BE",a.appendChild(r);const i=f.ownerDocument.createElement("div");i.dataset.wmapCardMetaPanel="1",Object.assign(i.style,{position:"absolute",top:"0",left:"0",right:"0",zIndex:bn,background:h.menuBg,borderBottom:`1px solid ${h.menuBorder}`,boxShadow:$e.menu,padding:`${w.md} ${w.lg}`,fontSize:L.body,display:"none"});const s=Tn(n??{});s&&i.appendChild(s),e.contentWrap.style.position="relative",e.contentWrap.appendChild(i),a.setAttribute("aria-expanded","false"),a.setAttribute("aria-label",`Wafer info for ${t}. Click to expand.`),xn(a,u=>{r.textContent=u?"\u25B4":"\u25BE",a.setAttribute("aria-expanded",String(u)),i.style.display=u?"block":"none"})}function gt(e,t,n){const o=f.ownerDocument.createElement("div");o.className="wmap-gallery-card",Object.assign(o.style,{background:h.menuBg,border:`1px solid ${h.menuBorder}`,borderRadius:z.container,boxShadow:$e.panel,overflow:"hidden",display:"flex",flexDirection:"column",position:"relative",aspectRatio:"1",maxWidth:ut(),maxHeight:ut()});const d=f.ownerDocument.createElement("div");Object.assign(d.style,{display:"flex",alignItems:"center",padding:`${w.md} ${w.lg} ${w.sm}`,borderBottom:`1px solid ${h.menuBorder}`,flexShrink:"0",gap:w.sm});const{wrap:l,metaPanel:a}=rn(document,Qe(e,t),e.wafer.metadata??void 0);d.appendChild(l);const r=f.ownerDocument.createElement("button");r.dataset.wmapExpandBtn="1",r.setAttribute("aria-label","Open full view"),Cn(r),r.innerHTML=We.expand,Object.assign(r.style,{display:"flex",alignItems:"center",justifyContent:"center",border:`1px solid ${h.menuBorder}`,borderRadius:z.control,background:h.panelBg,color:h.label,padding:w.xxs,cursor:"pointer",flexShrink:"0",width:"22px",height:"22px"}),xt(r),d.appendChild(r),o.appendChild(d);const i=f.ownerDocument.createElement("div");Object.assign(i.style,{position:"relative",flex:"1",minHeight:"0",overflow:"hidden",display:"flex",flexDirection:"column"}),o.appendChild(i),a&&i.appendChild(a),$.appendChild(o),o.addEventListener("contextmenu",M=>{if(M.defaultPrevented)return;const E=p.insights?.sweeps;if(!bi(e.testDefs,E))return;M.preventDefault();const x=e.viewOptions?{...c,...e.viewOptions}:c,y=yi(e.dies,{waferLabel:Mn(e),testDefs:e.testDefs,isLotStack:e.isLotStack,activeTest:x.plotMode==="value"?x.activeTest:void 0,waferIndex:t}),B={x:M.clientX,y:M.clientY};import("./drilldown.js").then(({openDrilldownMenu:j})=>{o.isConnected&&j(B,o,y,{sweeps:E,onSaveImage:m.getSaveImageHook()})})});const s=Pe||we()!==null,u=e.viewOptions?{...c,...e.viewOptions}:c,m=kn(i,e,{viewOptions:{...u,showLegend:s,legendPosition:ye},showTooltip:!0,padding:A,statsSummary:e.statsSummary,onSaveImage:p.onSaveImage,onSaveText:p.onSaveText,downloadFilename:p.downloadFilename,onClick:e.onClick,onSelect:e.onSelect,insights:X,onExpand:()=>Ie(t,e),showIdentity:!1,chromeInset:jo});return m.setViewControlsVisible(!1),m.setSummaryVisible(!1),r.onclick=()=>Ie(t,e),{card:o,ctrl:m,canvasWrapper:i,expandBtn:r}}function bo(e){const t=de[e];if(!t)return;const n=[..._.values()].find(o=>o.cardIndex===e);n?(t.innerHTML=We.minimize,t.setAttribute("aria-label","Reattach to gallery"),t.onclick=()=>wo(n.id)):(t.innerHTML=We.expand,t.setAttribute("aria-label","Open full view"),t.onclick=()=>Ie(e,R[e]))}function Z(e){vo(),Me()?.remove(),De(null),it(),R=[];for(const i of S)i&&i.destroy();S=[],ae=[],de=[],He=0,$.innerHTML="",on=e.length,an(e.map(i=>typeof i=="function"?null:i));const t=[];for(let i=0;i<e.length;i++){const s=e[i];if(typeof s=="function"){const u=f.ownerDocument.createElement("div");u.className="wmap-gallery-card",Object.assign(u.style,{background:h.menuBg,border:`1px solid ${h.menuBorder}`,borderRadius:z.container,aspectRatio:"1",display:"flex",alignItems:"center",justifyContent:"center"});const m=f.ownerDocument.createElement("span");m.textContent="\u2026",Object.assign(m.style,{color:h.label,fontSize:"18px"}),u.appendChild(m),$.appendChild(u),R.push(null),S.push(null),ae.push(null),de.push(null),t.push({index:i,factory:s,placeholder:u}),He++}else{const{ctrl:u,canvasWrapper:m,expandBtn:M}=gt(s,i,e.length);R.push(s),S.push(u),ae.push(m),de.push(M)}}_t(),qe(),st(),lt();const n=++xe,o=()=>{setTimeout(()=>{n===xe&&p.onItemsResolved?.()},0)},d=i=>{setTimeout(()=>{n===xe&&p.onItemResolved?.(i,e.length)},0)};let l=e.length-t.length;l>0&&d(l);let a=0;function r(){if(n!==xe)return;if(a>=t.length){if(be.has(c.plotMode)){const B=c.plotMode;Z(Re(B));return}ke=o,N(),ue||(ke=null,o());return}const{index:i,factory:s,placeholder:u}=t[a++],m=s();R[i]=m,v[i]=m,an([m]);const{card:M,ctrl:E,canvasWrapper:x,expandBtn:y}=gt(m,i,e.length);S[i]=E,ae[i]=x,de[i]=y,He--,u.replaceWith(M),d(++l),to(),eo(),!b&&!re?.placement&&m.statsSummary?.findings.length&&(b=Mt("right",oe,f.ownerDocument),b.style.maxHeight="calc(100vh - 80px)",b.style.position="sticky",b.style.top="8px",b.style.flexDirection="column",b.style.display="none",(re?.placement??"right")==="left"?q.insertBefore(b,$):q.appendChild(b),N(),P||(P=Q("findings","Summary panel",()=>{if(!b)return;const j=b.style.display!=="none";j||N(),b.style.display=j?"none":"flex",Se(P,!j),le()}),W.appendChild(G()),W.appendChild(P)),le()),le(),setTimeout(r,0)}t.length>0?setTimeout(r,0):o()}if(be.has(c.plotMode)&&v.length>0){const e=mt(c.plotMode);c={...c,...e},Z(Re(c.plotMode))}else Z(C);Be();let he=0;const cn=new(f.ownerDocument.defaultView??window).ResizeObserver(()=>{if(he)return;he=(f.ownerDocument.defaultView??window).requestAnimationFrame(()=>{he=0,D==null&&pt()})});cn.observe($),b&&N();function yo(e,t){const n=ae[e];if(!n)return;n.innerHTML="",Object.assign(n.style,{alignItems:"center",justifyContent:"center"});const o=f.ownerDocument.createElement("span");o.textContent=t?"Opened in its own window":"Opened in the wafer viewer",Object.assign(o.style,{color:h.label,fontSize:L.body,textAlign:"center",padding:"0 12px"}),n.appendChild(o)}function Ie(e,t){for(const a of _.values())if(a.cardIndex===e)return;const n=Qe(t,e),o=Pn++,d=S[e]?.getOptions(),l=Ko(n);if(l){const a=l.document;a.title=n,Object.assign(a.documentElement.style,{height:"100%"}),Object.assign(a.body.style,{margin:"0",height:"100vh",overflow:"hidden",display:"flex",flexDirection:"column",fontFamily:L.family}),Yo(f,a.documentElement);const r=Zo(f,a.documentElement,()=>x.setOptions({})),i=a.createElement("div");i.dataset.wmapWindowBanner="1",i.textContent=n,Object.assign(i.style,{display:"none",padding:`${w.sm} ${w.xl}`,fontSize:L.body,fontWeight:"700",background:h.warnBg,color:h.warnText,borderBottom:`1px solid ${h.warnBorder}`,flexShrink:"0"}),a.body.appendChild(i);const s=a.createElement("div");Object.assign(s.style,{flex:"1",minHeight:"0",display:"flex",flexDirection:"column"}),a.body.appendChild(s);const{wrap:u,metaPanel:m}=rn(a,n,t.wafer.metadata??void 0),M=a.createElement("div");Object.assign(M.style,{display:"flex",alignItems:"center",padding:`${w.md} ${w.lg} ${w.sm}`,borderBottom:`1px solid ${h.menuBorder}`,flexShrink:"0",gap:w.sm}),M.appendChild(u),s.appendChild(M);const E=a.createElement("div");Object.assign(E.style,{position:"relative",flex:"1",minHeight:"0",overflow:"hidden",display:"flex",flexDirection:"column"}),m&&E.appendChild(m),s.appendChild(E);const x=ht(E,t,void 0,d),y=setInterval(()=>{l.closed&&Ue(o)},400);l.addEventListener("pagehide",()=>Ue(o)),_.set(o,{id:o,ctrl:x,cardIndex:e,label:n,closePollId:y,stopThemeSync:r,close:()=>{l.closed||l.close()},setTitle:B=>{a.title=B,i.textContent=B,i.style.display="block"}})}else{const a=qo({title:n,onClose:()=>Ue(o),anchor:f});a.contentWrap.style.flexDirection="column",dn(a,n,t.wafer.metadata??void 0);const r=ht(a.contentWrap,t,void 0,d);_.set(o,{id:o,ctrl:r,cardIndex:e,label:n,closePollId:null,close:()=>a.close(),setTitle:i=>{const s=a.box.querySelector("[data-wmap-window-title]");s&&(s.textContent=i,s.title=i)}})}S[e]?.destroy(),S[e]=null,yo(e,l!==null),bo(e)}function ht(e,t,n,o){const d=t.viewOptions?{...c,...t.viewOptions}:c,l=o?{...d,...o}:d,r={...n!==void 0?{...l,plotMode:"value",activeTest:n}:l,showLegend:!0,legendPosition:ye},i=kn(e,t,{viewOptions:r,showTooltip:!0,padding:A,statsSummary:t.statsSummary,onSaveImage:p.onSaveImage,onSaveText:p.onSaveText,downloadFilename:p.downloadFilename,onClick:t.onClick,onSelect:t.onSelect,insights:X,showExpandButton:!1,showIdentity:!1});return i.setViewControlsVisible(!0),i.setSummaryVisible(!0),i.setExpandVisible(!1),i}function Ue(e){const t=_.get(e);if(!t||(_.delete(e),t.closePollId!=null&&clearInterval(t.closePollId),t.stopThemeSync?.(),t.ctrl.destroy(),t.cardIndex===null))return;const n=t.cardIndex,o=R[n];if(!o)return;const{card:d,ctrl:l,canvasWrapper:a,expandBtn:r}=gt(o,n,R.length);ae[n]?.parentElement?.replaceWith(d),S[n]=l,ae[n]=a,de[n]=r}function wo(e){const t=_.get(e);t&&(t.close(),Ue(e))}function vo(){for(const e of _.values())e.cardIndex!==null&&(e.cardIndex=null,e.setTitle(`${e.label} \u2014 unlinked from gallery`))}function xo(){const e=[...$.querySelectorAll("canvas")];if(!e.length)return;const t=e.length,n=Math.ceil(Math.sqrt(t)),o=Math.ceil(t/n),d=e[0].width,l=e[0].height,a=8,r=(f.ownerDocument.defaultView??window).devicePixelRatio||1,i=Math.round(26*r),s=Math.round(12*r),u=f.ownerDocument.createElement("canvas");u.width=n*d+(n-1)*a,u.height=o*(l+i)+(o-1)*a;const m=u.getContext("2d"),M=Po($);m.fillStyle=M.background,m.fillRect(0,0,u.width,u.height),e.forEach((E,x)=>{const y=x%n,B=Math.floor(x/n),j=y*(d+a),U=B*(l+i+a),bt=E.closest(".wmap-gallery-card")?.querySelector("span")?.textContent??"";m.fillStyle=M.surface,m.fillRect(j,U,d,i),m.fillStyle=M.text,m.font=`700 ${s}px system-ui, sans-serif`,m.textAlign="left",m.textBaseline="middle",m.fillText(bt,j+Math.round(10*r),U+i/2,d-Math.round(20*r)),m.drawImage(E,j,U+i)}),u.toBlob(E=>{if(!E)return;const x=S.find(y=>y!=null)?.getExportTitle();ii(E,["gallery",x].filter(Boolean).join(" "),Fe.onSaveImage)})}return{setItems(e){v=e.map(n=>typeof n=="function"?null:n);const t=c.plotMode;if(be.has(t))if(e.some(o=>typeof o=="function"))Z(e);else{const o=mt(t);c={...c,...o},Z(Re(t))}else Z(e)},setOptions(e){T(e,{fireCallback:!1})},getOptions(){return En(c)},setFindingsNotice(e){It=e,N()},setColumns(e){ln(e)},getBinColors(){return c.binColors??fe()},setLotStatsSummary(e){V=e,Be(),b&&N(),le()},openUserGuide:Zt,destroy(){xe++,ue?.cancel(),ue=null,ke=null;for(const e of[..._.values()])e.closePollId!=null&&clearInterval(e.closePollId),e.close(),e.ctrl.destroy();_.clear();for(const e of S)e&&e.destroy();S=[],Me()?.remove(),cn.disconnect(),he&&((f.ownerDocument.defaultView??window).cancelAnimationFrame(he),he=0),f.ownerDocument.removeEventListener("click",je,!0),window.removeEventListener("blur",Rt),ie(),yn(),Le.remove(),q.remove(),b?.remove(),me?.destroy()}}}