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