@wafertools/wafermap 0.30.1 → 0.30.3
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 +71 -11
- package/CHANGELOG.md +464 -8
- package/README.md +6 -3
- package/dist/packages/canvas-adapter/chartPopulation.d.ts +48 -0
- package/dist/packages/canvas-adapter/chartPopulation.js +1 -0
- package/dist/packages/canvas-adapter/charts/barPanel.d.ts +4 -1
- package/dist/packages/canvas-adapter/charts/barPanel.js +1 -1
- package/dist/packages/canvas-adapter/charts/boxplot.d.ts +4 -1
- package/dist/packages/canvas-adapter/charts/boxplot.js +1 -1
- package/dist/packages/canvas-adapter/charts/capability.js +1 -1
- package/dist/packages/canvas-adapter/charts/chartShell.d.ts +81 -7
- package/dist/packages/canvas-adapter/charts/chartShell.js +1 -1
- package/dist/packages/canvas-adapter/charts/correlation.js +2 -2
- package/dist/packages/canvas-adapter/charts/groupedBarPlot.js +1 -1
- package/dist/packages/canvas-adapter/charts/histogram.js +1 -1
- package/dist/packages/canvas-adapter/charts/regionYieldDiagram.js +1 -1
- package/dist/packages/canvas-adapter/charts/scatter.js +1 -1
- package/dist/packages/canvas-adapter/charts/sweep.d.ts +31 -0
- package/dist/packages/canvas-adapter/charts/sweep.js +1 -0
- package/dist/packages/canvas-adapter/charts/trend.d.ts +3 -1
- package/dist/packages/canvas-adapter/charts/trend.js +1 -1
- package/dist/packages/canvas-adapter/chunked.d.ts +45 -0
- package/dist/packages/canvas-adapter/chunked.js +1 -0
- package/dist/packages/canvas-adapter/dieList.js +2 -2
- package/dist/packages/canvas-adapter/drilldown.d.ts +23 -0
- package/dist/packages/canvas-adapter/drilldown.js +1 -0
- package/dist/packages/canvas-adapter/icons.js +1 -1
- package/dist/packages/canvas-adapter/insightsTab.d.ts +55 -3
- package/dist/packages/canvas-adapter/insightsTab.js +1 -1
- package/dist/packages/canvas-adapter/renderWaferGallery.d.ts +55 -0
- package/dist/packages/canvas-adapter/renderWaferGallery.js +1 -1
- package/dist/packages/canvas-adapter/renderWaferMap.js +1 -1
- package/dist/packages/canvas-adapter/summaryPanel.d.ts +55 -9
- package/dist/packages/canvas-adapter/summaryPanel.js +3 -3
- package/dist/packages/canvas-adapter/toCanvas.js +1 -1
- package/dist/packages/canvas-adapter/toolbar.d.ts +30 -2
- 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 +126 -3
- 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.js +1 -1
- package/dist/packages/core/aggregates.js +1 -1
- package/dist/packages/core/utils.d.ts +55 -0
- package/dist/packages/core/utils.js +1 -1
- package/dist/packages/renderer/axisTicks.d.ts +32 -0
- package/dist/packages/renderer/axisTicks.js +1 -0
- package/dist/packages/renderer/binColors.d.ts +14 -0
- package/dist/packages/renderer/binColors.js +1 -1
- package/dist/packages/renderer/buildView.d.ts +11 -37
- package/dist/packages/renderer/buildView.js +1 -1
- package/dist/packages/renderer/buildWaferMap.d.ts +58 -1
- package/dist/packages/renderer/buildWaferMap.js +1 -1
- package/dist/packages/renderer/deprecate.d.ts +13 -5
- package/dist/packages/renderer/deprecate.js +1 -1
- package/dist/packages/renderer/derivedTests/apply.d.ts +85 -0
- package/dist/packages/renderer/derivedTests/apply.js +1 -0
- package/dist/packages/renderer/derivedTests/evaluate.d.ts +48 -0
- package/dist/packages/renderer/derivedTests/evaluate.js +1 -0
- package/dist/packages/renderer/derivedTests/parser.d.ts +148 -0
- package/dist/packages/renderer/derivedTests/parser.js +2 -0
- package/dist/packages/renderer/fmt.d.ts +24 -2
- package/dist/packages/renderer/fmt.js +1 -1
- package/dist/packages/renderer/index.d.ts +1 -0
- package/dist/packages/renderer/index.js +1 -1
- package/dist/packages/renderer/spec.d.ts +49 -0
- package/dist/packages/renderer/spec.js +1 -0
- package/dist/packages/renderer/testLabel.d.ts +154 -0
- package/dist/packages/renderer/testLabel.js +1 -0
- package/dist/packages/stats/analyzeWaferMap.js +1 -1
- package/dist/packages/stats/capability.d.ts +60 -0
- package/dist/packages/stats/capability.js +1 -1
- package/dist/packages/stats/correlation.d.ts +33 -0
- package/dist/packages/stats/correlation.js +1 -1
- package/dist/packages/stats/deprecated.d.ts +3 -0
- package/dist/packages/stats/deprecated.js +1 -1
- package/dist/packages/stats/findingsNarrative.js +1 -1
- package/dist/packages/stats/index.d.ts +2 -2
- package/dist/packages/stats/index.js +1 -1
- package/dist/packages/stats/math.d.ts +27 -2
- package/dist/packages/stats/math.js +1 -1
- package/dist/packages/stats/mergeTestDefs.js +1 -1
- package/dist/packages/stats/renderFindingsReport.js +8 -28
- package/dist/packages/stats/renderSummaryReport.js +22 -31
- package/dist/packages/stats/reportHtml.d.ts +27 -0
- package/dist/packages/stats/reportHtml.js +35 -14
- package/dist/packages/stats/sweep.d.ts +178 -0
- package/dist/packages/stats/sweep.js +1 -0
- package/dist/packages/stats/sweepXFromName.d.ts +27 -0
- package/dist/packages/stats/sweepXFromName.js +1 -0
- package/dist/packages/stats/testPassRate.js +1 -1
- package/dist/packages/stats/types.d.ts +28 -1
- package/llms.txt +14 -8
- package/package.json +2 -2
|
@@ -2,7 +2,8 @@ import type { LotStatsSummary } from '../stats/types.js';
|
|
|
2
2
|
import type { WaferMapDisplayItem } from './renderWaferGallery.js';
|
|
3
3
|
import type { BinColors } from '../renderer/binColors.js';
|
|
4
4
|
import { type SaveImageHandler, type SaveTextHandler } from './toolbar.js';
|
|
5
|
-
|
|
5
|
+
import type { SweepSpec } from '../stats/sweep.js';
|
|
6
|
+
export type InsightsView = 'overview' | 'distributions' | 'correlation' | 'sweeps';
|
|
6
7
|
/** Public option shape for `RenderOptions.insights`/`GalleryOptions.insights`. */
|
|
7
8
|
export interface InsightsOptions {
|
|
8
9
|
/**
|
|
@@ -10,11 +11,60 @@ export interface InsightsOptions {
|
|
|
10
11
|
* grid with wmap's own chart suite across three sub-tabs — Overview
|
|
11
12
|
* (yield, bins, ring/quadrant yield, test values), Distributions
|
|
12
13
|
* (process capability, boxplot, histogram), and Correlation (matrix +
|
|
13
|
-
* scatter). Default false.
|
|
14
|
+
* scatter) — plus a fourth, Sweeps, when `sweeps` defines any. Default false.
|
|
14
15
|
*/
|
|
15
16
|
enabled?: boolean;
|
|
16
|
-
/** Which sub-tab is shown first. Default 'overview'.
|
|
17
|
+
/** Which sub-tab is shown first. Default 'overview'. `'sweeps'` with no
|
|
18
|
+
* `sweeps` defined falls back to 'overview' — there is no such tab to open. */
|
|
17
19
|
defaultView?: InsightsView;
|
|
20
|
+
/**
|
|
21
|
+
* Parametric sweeps, one card each in their own Sweeps sub-tab — which appears
|
|
22
|
+
* only when this is non-empty.
|
|
23
|
+
*
|
|
24
|
+
* A sweep reads an ordered run of tests as a response curve rather than as
|
|
25
|
+
* independent tests, and measures the PAIR: where the first two series cross,
|
|
26
|
+
* and how far apart they are at given levels. The case it exists for is the
|
|
27
|
+
* same quantity measured at a series of power levels, recorded as a block of
|
|
28
|
+
* consecutive test numbers, swept up in one block and down in another.
|
|
29
|
+
*
|
|
30
|
+
* ```ts
|
|
31
|
+
* insights: { enabled: true, sweeps: [{
|
|
32
|
+
* id: 'power', title: 'Power Sweep',
|
|
33
|
+
* series: [
|
|
34
|
+
* { label: 'Rising', tests: [1010, 1011, 1012], xValues: [0, 5, 10] },
|
|
35
|
+
* { label: 'Falling', tests: [1020, 1021, 1022], xValues: [0, 5, 10] },
|
|
36
|
+
* ],
|
|
37
|
+
* separationAt: [1.2, 2.5],
|
|
38
|
+
* }] }
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* Deliberately carries no population scope of its own: a sweep definition
|
|
42
|
+
* says which tests form the curve, and is therefore valid for any population
|
|
43
|
+
* and portable between hosts. The dies it aggregates are whatever the
|
|
44
|
+
* Insights view is currently scoped to.
|
|
45
|
+
*
|
|
46
|
+
* The same definitions drive drilldown: a user can select dies on a map and
|
|
47
|
+
* right-click (or use the toolbar's "Chart the selection") to sweep just
|
|
48
|
+
* those dies. A single map offers this even when `enabled` is off.
|
|
49
|
+
*
|
|
50
|
+
* **Provisional.** This arrived as one site's request. The mechanism — an
|
|
51
|
+
* ordered run of tests read as a curve — is a recurring semiconductor shape
|
|
52
|
+
* (shmoo, VDD/temperature sweeps, retention, endurance, IV), which is the case
|
|
53
|
+
* for it being library-level; against it is that only one host has asked. It
|
|
54
|
+
* is shipping so tsmap can put it in front of that user, and the answer
|
|
55
|
+
* decides it: a second sweep-shaped use means it is general and stays, while
|
|
56
|
+
* "also measure X, and split by Y" means it is a bespoke chart and belongs
|
|
57
|
+
* behind a host-contributed-panel extension point instead. `separationAt` is
|
|
58
|
+
* the narrowest part of the surface and the first thing to drop if it is not
|
|
59
|
+
* used. Do not widen this shape before that question is settled.
|
|
60
|
+
*
|
|
61
|
+
* Range strings in `tests` (`"1010..1030"`) are NOT a widening in that sense:
|
|
62
|
+
* they are input syntax for the same list of tests, and add nothing to what a
|
|
63
|
+
* sweep measures. They were added because ranges are the first thing anyone
|
|
64
|
+
* writing a sweep by hand asks for, and they share the derived-test parser so
|
|
65
|
+
* the syntax is one syntax library-wide.
|
|
66
|
+
*/
|
|
67
|
+
sweeps?: SweepSpec[];
|
|
18
68
|
/**
|
|
19
69
|
* Open the Insights view on mount instead of starting on the map/grid.
|
|
20
70
|
* Default false — the tab is offered, the map is what you see first.
|
|
@@ -71,6 +121,8 @@ export interface InsightsTabDeps {
|
|
|
71
121
|
focusTest?: (testNumber: number) => void;
|
|
72
122
|
/** Default sub-tab shown on first render. Default 'overview'. */
|
|
73
123
|
defaultView?: InsightsView;
|
|
124
|
+
/** Sweep definitions to render in the Distributions view — see `InsightsOptions.sweeps`. */
|
|
125
|
+
sweeps?: SweepSpec[];
|
|
74
126
|
/**
|
|
75
127
|
* When provided, the tab bar gets a leading "‹ Map"/"‹ Gallery" tab that
|
|
76
128
|
* exits Insights back to the host's normal view — one visible navigation
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{buildFacetTable as De,facetValueOf as $e,FACET_NONE_VALUE as Le}from"../stats/facets.js";import{mergeTestDefs as Ee}from"../stats/mergeTestDefs.js";import{isParametricTest as Ie}from"../renderer/buildWaferMap.js";import{waferDisplayLabel as Oe}from"../core/waferLabel.js";import{INPUT_DEFAULT_PASS_BINS as A,itemPassBins as Pe,passBinsLabel as ne}from"../core/passBins.js";import{NO_DATA_FILL as ae}from"../renderer/colorMap.js";import{describeWaferPopulation as Ae,populationStat as Re}from"../stats/population.js";import{LEADING as We,ALPHA as je,SPACE as S,EDGE_GUTTER as K,FONT as G,CLR as k,RADIUS as Ge,SHADOW as He,controlStyle as Ye,wireControlHover as oe,wireTooltip as Fe}from"./toolbar.js";import{ICONS as Ne}from"./icons.js";import{renderCapabilityPanel as Me}from"./charts/capability.js";import{renderBoxplotPanel as Ve}from"./charts/boxplot.js";import{renderTrendPanel as _e}from"./charts/trend.js";import{renderHistogramPanel as Ue}from"./charts/histogram.js";import{renderCorrelationPanel as ze}from"./charts/correlation.js";import{renderScatterPanel as qe}from"./charts/scatter.js";import{renderBarPanel as re}from"./charts/barPanel.js";import{renderBinClusterPanel as Qe}from"./charts/binCluster.js";import{renderTestPassRatePanel as Ke}from"./charts/testPassRate.js";import{QUANTITY as Xe}from"./charts/palette.js";import{cardFrameStyle as Je,makeChartGridWrap as X,makeLabeledSelect as Ze,makeLinkedGroupSelect as et}from"./charts/chartShell.js";import{buildYieldData as M,buildYieldDataCombined as se}from"../stats/yield.js";import{buildBinParetoData as tt}from"../stats/binPareto.js";import{buildLotTestSection as nt,buildLotFunctionalSection as at,buildMetadataStripBox as ot}from"./summaryPanel.js";import{buildRegionYieldData as ie,buildRingRegions as rt,buildQuadrantRegions as st}from"../stats/regions.js";import{renderRegionYieldDiagram as le}from"./charts/regionYieldDiagram.js";const it=[{key:"overview",label:"Overview"},{key:"distributions",label:"Distributions"},{key:"correlation",label:"Correlation"}];export function createInsightsTab(D){const{getItems:de,getLotStats:ce,getBinColors:J,getRingCount:pe,onSaveImage:T,onSaveText:V,openWafer:H,focusTest:Z}=D,ue=D.showMetadataStrip??!0,R=D.contentInset??K,d=D.ownerDocument??document,I=d.createElement("div");Object.assign(I.style,{display:"none",flexDirection:"column",width:"100%",paddingTop:"0"});const fe=K,O=d.createElement("div");Object.assign(O.style,{paddingLeft:fe});const B=d.createElement("div");Object.assign(B.style,{display:"flex",gap:S.xs,alignItems:"center",background:k.menuBg,border:`1px solid ${k.menuBorder}`,borderRadius:Ge.container,boxShadow:He.panel,padding:`0 ${S.lg}`,marginBottom:S.lg,marginLeft:R,marginRight:R}),B.setAttribute("role","tablist"),B.addEventListener("keydown",e=>{if(e.key!=="ArrowLeft"&&e.key!=="ArrowRight")return;const n=Array.from(B.querySelectorAll('[role="tab"]')),o=n.indexOf(d.activeElement);if(o===-1)return;e.preventDefault();const c=n[(o+(e.key==="ArrowRight"?1:-1)+n.length)%n.length];c.focus(),c.click()});const W=d.createElement("div");Object.assign(W.style,{display:"flex",flexDirection:"column",gap:S.lg,marginTop:"0",paddingLeft:R,paddingRight:R}),I.appendChild(O),I.appendChild(B),I.appendChild(W);let j=D.defaultView??"overview",P,L=null,$=null,Y={includeLimits:void 0,clipOutliers:!1};const _=e=>{$!==e&&($=e,N())};let F=[];function U(e,n,o){H?.(e,n,o)}function me(e){return H?{open:(n,o)=>U(n,`Wafer ${e.find(c=>c.waferIndex===n)?.label??n}`,o)}:Z&&e.length===1?{open:(n,o)=>Z(o),label:"show this test on the map"}:null}function be(){return de().map((e,n)=>e==null?null:{metadata:e.wafer.metadata??void 0,dies:e.dies,wafer:e.wafer,label:Oe(e,n),waferIndex:n,passBins:Pe(e),statsSummary:e.statsSummary,testDefs:e.testDefs}).filter(e=>e!=null)}function ee(e,n){Object.assign(e.style,{background:"none",border:"none",borderBottom:n?`2px solid ${k.iconActive}`:"2px solid transparent",color:n?k.iconActive:k.label,fontWeight:n?"700":"500",fontSize:G.body,padding:`${S.sm} ${K} ${S.md}`,cursor:"pointer",marginBottom:"-1px"})}function ge(e,n){const o=d.createElement("button");o.type="button",o.textContent=n;const c=e===j;return ee(o,c),o.dataset.on=c?"true":"false",oe(o,"bare"),o.dataset.wmapInsightsTab=e,o.setAttribute("role","tab"),o.setAttribute("aria-selected",c?"true":"false"),o.tabIndex=c?0:-1,o.addEventListener("click",()=>{j!==e&&(j=e,N())}),o}function ye(e){const n=d.createElement("button");return n.type="button",n.textContent=`\u2039 ${e.label}`,ee(n,!1),n.dataset.wmapInsightsBack="1",n.addEventListener("click",e.onBack),n}function he(e,n,o,c=!0){const l=X(d),f=J();let y="label";const u=o??"group",m=ne(e.map(s=>s.passBins)),i=ce?.(),b=new Map(i?.lotYieldSeries.map(s=>[s.waferIndex,s.yieldPercent])),h=s=>({...s,label:s.label.replace(/\s*·\s*\d+(\.\d+)?%$/,""),yieldPercent:b.get(s.waferIndex),key:s.waferIndex}),g=e.map(h),p=n?.map(s=>({key:s.key,items:s.items.map(h)})),t=()=>p?se(p,A,y):M(g,A,y),x={title:n?`Yield by ${u} (pass: ${m})`:`Yield by wafer (pass: ${m})`,data:t(),selfControl:{current:y,options:[["yield","Sort: yield"],["label",n?`Sort: ${u}`:"Sort: wafer ID"]],onChange:s=>(y=s,{data:t()})},barColor:()=>Xe,valueLabel:s=>`${s.percent.toFixed(1)}%`,reference:s=>{if(s.length<3)return null;const v=s.map(Q=>Q.percent).sort((Q,ke)=>Q-ke),E=v.length%2?v[(v.length-1)/2]:(v[v.length/2-1]+v[v.length/2])/2;return{value:E,label:`median ${E.toFixed(1)}%`}},drill:p?{onOpenGroup:s=>{const v=p.find(E=>E.key===s.label)?.items??[];return{data:M(v,A,y),title:`Yield by wafer \u2014 ${u}: ${s.label} (pass: ${m})`}},onBack:()=>({data:t(),title:`Yield by ${u} (pass: ${m})`}),groupLabelText:u}:void 0,onOpen:H?s=>{typeof s.key=="number"&&U(s.key,`Wafer ${s.label}`)}:void 0,ownerDocument:d};let C=null;if(c&&(C=re(x,T),C.card.style.minHeight="360px",l.appendChild(C.card)),n){const s=Qe({title:"Hard bin pareto",groups:n.map(v=>({key:v.key,items:v.items.map(E=>({dies:E.dies,hardBinCounts:E.statsSummary?.stats.hardBinCounts,softBinCounts:E.statsSummary?.stats.softBinCounts}))})),onSaveImage:T,ownerDocument:d});return s.card.style.minHeight="360px",l.appendChild(s.card),{card:l,destroy:()=>{C?.destroy(),s.destroy()}}}let a="hbin";const r=s=>s===void 0?ae:(a==="hbin"?f.hard:f.soft).get(s)??ae,w=e.map(s=>({dies:s.dies,hardBinCounts:s.statsSummary?.stats.hardBinCounts,softBinCounts:s.statsSummary?.stats.softBinCounts})),te=()=>tt(w,a),Be={title:"Hard bin pareto",data:te(),selfControl:{current:a,options:[["hbin","Hard bins"],["sbin","Soft bins"]],onChange:s=>(a=s,{data:te(),title:`${a==="hbin"?"Hard":"Soft"} bin pareto`})},barColor:s=>r(s.binCode),ownerDocument:d},q=re(Be,T);return q.card.style.minHeight="360px",l.appendChild(q.card),{card:l,destroy:()=>{C?.destroy(),q.destroy()}}}function z(){const e=d.createElement("div");return e.dataset.wmapChartCard="1",Object.assign(e.style,{...Je(),display:"flex",flexDirection:"column",gap:S.lg,minWidth:"0"}),e}function Ce(e){if(O.innerHTML="",O.style.marginBottom="0",!ue)return;const n=ot(e.map(o=>({metadata:o.metadata})),void 0,{facetableOnly:!1});n&&(n.style.marginBottom="0",O.appendChild(n),O.style.marginBottom=S.xs)}function xe(e,n,o,c){if(!e.length)return{elements:[],testValuesCard:null,functionalCard:null,destroy:()=>{}};const l=e.map(r=>r.wafer),f=e.map(r=>r.dies),y=e.flatMap(r=>r.dies),u=e.map(r=>r.statsSummary),m=u.every(r=>r!==void 0)?u:void 0,i=pe?.()??4,b=[],h=[],p=Ke({groups:(c??[{key:"",items:e}]).map(r=>({key:r.key,items:r.items.map(w=>({dies:w.dies,testSpecYield:w.statsSummary?.stats.testSpecYield,functionalYield:w.statsSummary?.stats.functionalYield}))})),testDefs:o,onSaveImage:T,ownerDocument:d});p.card.style.minHeight="300px",b.push(p.card),h.push(p.destroy);const t=ie(f,l,i,r=>e[r].passBins,rt);if(t.length){const r=le({title:"Ring yield",mode:"ring",rows:t,onSaveImage:T,ownerDocument:d});b.push(r.card),h.push(r.destroy)}const x=ie(f,l,i,r=>e[r].passBins,st);if(x.length){const r=le({title:"Quadrant yield",mode:"quadrant",rows:x,onSaveImage:T,ownerDocument:d});b.push(r.card),h.push(r.destroy)}let C=null;if(n.length){const r=nt(y,n,void 0,m,V,f.map(w=>({dies:w})),void 0,"full");if(r){const w=z();w.appendChild(r),C=w}}let a=null;if(o.length){const r=at(y,o,m,V);if(r){const w=z();w.appendChild(r),a=w}}return{elements:b,testValuesCard:C,functionalCard:a,destroy:()=>{for(const r of h)r()}}}function Se(e){const n=ne(e.map(i=>i.passBins)),o=e.length===1,c=e[0],l=z();Object.assign(l.style,{flexDirection:"row",flexWrap:"wrap",gap:S.md});const f=i=>{const b=i.lastElementChild;return b&&Object.assign(b.style,{borderRight:"none",paddingRight:"0",marginRight:"0"}),i};function y(i,b,h){const g=d.createElement("div");Object.assign(g.style,{display:"flex",alignItems:"baseline",gap:S.sm,paddingRight:S.xxl,marginRight:S.md,borderRight:`1px solid ${k.menuBorder}`});const p=d.createElement("div");p.textContent=i,Object.assign(p.style,{fontSize:G.heading,fontWeight:"700",color:k.value,lineHeight:We.tight});const t=d.createElement("div");if(t.textContent=b,Object.assign(t.style,{fontSize:G.body,color:k.label}),g.append(p,t),h){const x=d.createElement("div");x.textContent=h,Object.assign(x.style,{fontSize:G.meta,color:k.label,opacity:je.muted}),g.appendChild(x)}return g}if(o){const i=M([{...c,key:c.waferIndex}],A)[0]?.percent;return i!==void 0&&l.appendChild(y(`${i.toFixed(1)}%`,`Yield \xB7 pass: ${n}`)),l.appendChild(y(String(c.dies.length),"Total dies")),f(l)}l.appendChild(y(String(e.length),"Wafers"));const u=M(e.map(i=>({...i,key:i.waferIndex})),A).map(i=>i.percent).filter(i=>Number.isFinite(i));if(u.length){const i=u.reduce((g,p)=>g+p,0)/u.length,b=se([{key:"all",items:e.map(g=>({...g,key:g.waferIndex}))}],A)[0]?.percent,h=b!==void 0&&b.toFixed(1)!==i.toFixed(1);l.appendChild(y(`${i.toFixed(1)}%`,`Mean per-wafer yield \xB7 pass: ${n}`,h?`${b.toFixed(1)}% by dies`:void 0))}const m=e.map(i=>i.statsSummary);if(m.every(i=>i!==void 0)){const i=m.reduce((h,g)=>h+g.stats.analyzedDies,0),b=m.reduce((h,g)=>h+g.stats.excludedDies,0);l.appendChild(y(i.toLocaleString(),"Dies analysed",b?`${b.toLocaleString()} excluded`:void 0))}else l.appendChild(y(e.reduce((i,b)=>i+b.dies.length,0).toLocaleString(),"Total dies"));return f(l)}function we(e,n,o,c,l){const f=d.createElement("div");Object.assign(f.style,{display:"flex",flexDirection:"column",gap:S.lg});const y=e.length===1&&!c;e.length&&!c&&f.appendChild(Se(e));const u=he(e,c,l,!y);f.appendChild(u.card);const m=xe(e,n,o,c);for(const i of m.elements)u.card.appendChild(i);return m.testValuesCard&&f.appendChild(m.testValuesCard),m.functionalCard&&f.appendChild(m.functionalCard),{card:f,destroy:()=>{u.destroy(),m.destroy()}}}function Te(e,n,o,c){const l=X(d),f=me(e),y=a=>{Y=a;for(const r of[g,p,t])r!==u&&r?.setAxisPrefs(a)};let u=null;const m=a=>r=>{u=a(),y(r),u=null},i=a=>({...a,testStats:a.statsSummary?.stats.perTestStats}),b=e.map(i),h=o?.map(a=>({key:a.key,items:a.items.map(i)})),g=Ve({title:"Test value distribution",axisPrefs:Y,onAxisPrefsChange:m(()=>g),onTestChange:a=>x(a),selectedTestNumber:L??void 0,items:b,testDefs:n,groups:h,groupLabelText:c,onSaveImage:T,onGroupChange:a=>_(a),onOpen:f?.open,openActionLabel:f?.label,ownerDocument:d}),p=Ue({title:"Value histogram",axisPrefs:Y,onAxisPrefsChange:m(()=>p),onTestChange:a=>x(a),selectedTestNumber:L??void 0,items:e,testDefs:n,groups:o,onGroupChange:a=>_(a),onSaveImage:T,ownerDocument:d}),t=_e({title:"Wafer-to-wafer trend",axisPrefs:Y,onAxisPrefsChange:m(()=>t),onTestChange:a=>x(a),selectedTestNumber:L??void 0,items:e.map(a=>({label:a.label,key:a.waferIndex,dies:a.dies,testStats:a.statsSummary?.stats.perTestStats})),testDefs:n,onSaveImage:T,centreLabel:Re(Ae(e.map(a=>a.wafer.metadata)),"mean"),onOpen:H?(a,r)=>U(a,`Wafer ${e.find(w=>w.waferIndex===a)?.label??a}`,r):void 0,ownerDocument:d}),x=a=>{L=a,g.setTest(a),p.setTest(a),t.setTest(a),C.setTest(a)},C=Me({title:"Process capability",items:e,testDefs:n,onSaveImage:T,selectedTestNumber:L??void 0,onSelectTest:a=>x(a),ownerDocument:d});return l.append(C.card,g.card,p.card,t.card),{card:l,destroy:()=>{C.destroy(),g.destroy(),p.destroy(),t.destroy()}}}function ve(e,n,o){const c=X(d),l=qe({title:"Test scatter",items:e,testDefs:n,groups:o,binColors:J().hard,onSaveImage:T,ownerDocument:d}),f=ze({title:"Test correlation matrix",items:e,testDefs:n,onSaveImage:T,onSaveText:V,onSelectPair:(y,u)=>l.setXY(y,u),ownerDocument:d});return c.append(f.card,l.card),{card:c,destroy:()=>{f.destroy(),l.destroy()}}}function N(){for(const t of F)t.destroy();F=[],W.innerHTML="",B.innerHTML="",D.backTab&&B.appendChild(ye(D.backTab));for(const t of it)B.appendChild(ge(t.key,t.label));const e=be();Ce(e);const n=De(e,{facetableOnly:!0}).filter(t=>t.splittable),o=d.createElement("div");Object.assign(o.style,{display:"flex",gap:S.md,alignItems:"center",marginLeft:S.xxl,paddingBottom:S.xs});let c;n.length>0?(o.appendChild(Ze("Group by:",[{value:"",label:"None"},...n.map(t=>({value:t.key,label:`${t.label} (${t.values.length})`}))],P??"",t=>{P=t||void 0,$=null,N()},{hook:"group-by",ownerDocument:d})),c=n.find(t=>t.key===P)?.label):P=void 0;let l;if(P){const t=new Map,x=[];for(const C of e){const a=$e(C.metadata,P)??Le;t.has(a)||(t.set(a,[]),x.push(a)),t.get(a).push(C)}l=x.map(C=>({key:C,items:t.get(C)}))}$!==null&&!l?.some(t=>t.key===$)&&($=null),l&&l.length>0&&o.appendChild(et(l.map(t=>t.key),"Show:",$,t=>_(t),{ownerDocument:d}).el);let f=null;if(D.onOpenGuide){const t=d.createElement("button");t.type="button",t.innerHTML=Ne.help,t.setAttribute("aria-label","User guide"),Object.assign(t.style,{...Ye("bare"),display:"inline-flex",alignItems:"center",justifyContent:"center",width:"24px",height:"24px",flexShrink:"0"}),oe(t,"bare"),Fe(t,"User guide"),t.addEventListener("click",()=>D.onOpenGuide()),Object.assign(t.style,{marginLeft:"auto"}),f=t}B.appendChild(o),f&&B.appendChild(f);const y=$!==null?l?.find(t=>t.key===$):void 0,u=y?.items??e,m=y?void 0:l,i=Ee(u),b=i.defs,h=b.filter(Ie);L!==null&&!h.some(t=>t.testNumber===L)&&(L=null);const g=j==="overview"?we(u,h,b,m,c):j==="distributions"?Te(u,h,m,c):ve(u,h,m),p=i.conflicts.filter(t=>t.excluded);if(p.length>0){const t=d.createElement("div");Object.assign(t.style,{color:k.label,fontSize:G.body,padding:`0 ${R} ${S.sm}`});const x=p.slice(0,6).map(r=>r.testNumber).join(", "),C=p.length>6?`, and ${p.length-6} more`:"",a=p.length===1?"it":"them";t.textContent=`${p.length} test ${p.length===1?"number is":"numbers are"} hidden (${x}${C}) \u2014 the wafers in view describe ${a} differently, so their values cannot be pooled. `+(l&&l.length>0?`Pick one ${c??"group"} under "Show:" to analyse ${a}.`:"Load one test program at a time to analyse them."),t.dataset.wmapWithheldTests=String(p.length),W.appendChild(t)}F.push(g),W.appendChild(g.card)}return{el:I,render:N,destroy:()=>{for(const e of F)e.destroy();I.remove()}}}
|
|
1
|
+
import{buildFacetTable as Re,facetValueOf as We,FACET_NONE_VALUE as Me}from"../stats/facets.js";import{mergeTestDefs as re}from"../stats/mergeTestDefs.js";import{isParametricTest as Ye}from"../renderer/buildWaferMap.js";import{waferDisplayLabel as je,waferIdentityLabel as Ge}from"../core/waferLabel.js";import{hasDrilldownTargets as se,waferPopulation as He}from"./chartPopulation.js";import{openDrilldownMenu as Fe}from"./drilldown.js";import{INPUT_DEFAULT_PASS_BINS as R,itemPassBins as Ne,passBinsLabel as ie}from"../core/passBins.js";import{NO_DATA_FILL as le}from"../renderer/colorMap.js";import{describeWaferPopulation as Ve,populationStat as _e}from"../stats/population.js";import{LEADING as Ue,ALPHA as ze,SPACE as x,EDGE_GUTTER as Z,FONT as Y,CLR as B,RADIUS as qe,SHADOW as Qe,controlStyle as Ke,wireControlHover as de,wireTooltip as Xe}from"./toolbar.js";import{ICONS as Je}from"./icons.js";import{renderCapabilityPanel as Ze}from"./charts/capability.js";import{renderBoxplotPanel as et}from"./charts/boxplot.js";import{renderTrendPanel as tt}from"./charts/trend.js";import{renderSweepPanel as nt}from"./charts/sweep.js";import{renderHistogramPanel as at}from"./charts/histogram.js";import{renderCorrelationPanel as ot}from"./charts/correlation.js";import{renderScatterPanel as rt}from"./charts/scatter.js";import{renderBarPanel as ce}from"./charts/barPanel.js";import{renderBinClusterPanel as st}from"./charts/binCluster.js";import{renderTestPassRatePanel as it}from"./charts/testPassRate.js";import{QUANTITY as lt}from"./charts/palette.js";import{cardFrameStyle as dt,makeChartGridWrap as V,makeLabeledSelect as ct,makeLinkedGroupSelect as pt}from"./charts/chartShell.js";import{buildYieldData as _,buildYieldDataCombined as pe}from"../stats/yield.js";import{buildBinParetoData as ut}from"../stats/binPareto.js";import{buildLotTestSection as ft,buildLotFunctionalSection as mt,buildMetadataStripBox as bt}from"./summaryPanel.js";import{buildRegionYieldData as ue,buildRingRegions as gt,buildQuadrantRegions as yt}from"../stats/regions.js";import{renderRegionYieldDiagram as fe}from"./charts/regionYieldDiagram.js";const me=[{key:"overview",label:"Overview"},{key:"distributions",label:"Distributions"},{key:"correlation",label:"Correlation"}],ht={key:"sweeps",label:"Sweeps"};export function createInsightsTab(T){const{getItems:be,getLotStats:ge,getBinColors:ee,getRingCount:ye,onSaveImage:v,onSaveText:U,openWafer:j,focusTest:te}=T,he=T.showMetadataStrip??!0,W=T.contentInset??Z,p=T.ownerDocument??document,P=p.createElement("div");Object.assign(P.style,{display:"none",flexDirection:"column",width:"100%",paddingTop:"0"});const we=Z,O=p.createElement("div");Object.assign(O.style,{paddingLeft:we});const D=p.createElement("div");Object.assign(D.style,{display:"flex",gap:x.xs,alignItems:"center",background:B.menuBg,border:`1px solid ${B.menuBorder}`,borderRadius:qe.container,boxShadow:Qe.panel,padding:`0 ${x.lg}`,marginBottom:x.lg,marginLeft:W,marginRight:W}),D.setAttribute("role","tablist"),D.addEventListener("keydown",e=>{if(e.key!=="ArrowLeft"&&e.key!=="ArrowRight")return;const t=Array.from(D.querySelectorAll('[role="tab"]')),r=t.indexOf(p.activeElement);if(r===-1)return;e.preventDefault();const c=t[(r+(e.key==="ArrowRight"?1:-1)+t.length)%t.length];c.focus(),c.click()});const M=p.createElement("div");Object.assign(M.style,{display:"flex",flexDirection:"column",gap:x.lg,marginTop:"0",paddingLeft:W,paddingRight:W}),P.appendChild(O),P.appendChild(D),P.appendChild(M);const ne=(T.sweeps?.length??0)>0,Ce=ne?[...me,ht]:me;let E=T.defaultView==="sweeps"&&!ne?"overview":T.defaultView??"overview",A,L=null,$=null,G={includeLimits:void 0,clipOutliers:!1};const z=e=>{$!==e&&($=e,F())};let H=new Map;function ae(){for(const e of H.values())e.destroy();H=new Map}function q(e,t,r){j?.(e,t,r)}function Q(e){if(e.some(t=>se(t.testDefs,T.sweeps)))return(t,r,c)=>{const i=e.find(f=>f.waferIndex===t);if(!i||!se(i.testDefs,T.sweeps))return;c.preventDefault();const s=He(i.dies,{waferLabel:i.identity,testDefs:i.testDefs,activeTest:r??L??void 0,waferIndex:t});Fe({x:c.clientX,y:c.clientY},c.target,s,{sweeps:T.sweeps,onSaveImage:v})}}function Se(e){return j?{open:(t,r)=>q(t,`Wafer ${e.find(c=>c.waferIndex===t)?.label??t}`,r)}:te&&e.length===1?{open:(t,r)=>te(r),label:"show this test on the map"}:null}function xe(){return be().map((e,t)=>e==null?null:{metadata:e.wafer.metadata??void 0,dies:e.dies,wafer:e.wafer,label:je(e,t),identity:Ge(e),waferIndex:t,passBins:Ne(e),statsSummary:e.statsSummary,testDefs:e.testDefs}).filter(e=>e!=null)}function oe(e,t){Object.assign(e.style,{background:"none",border:"none",borderBottom:t?`2px solid ${B.iconActive}`:"2px solid transparent",color:t?B.iconActive:B.label,fontWeight:t?"700":"500",fontSize:Y.body,padding:`${x.sm} ${Z} ${x.md}`,cursor:"pointer",marginBottom:"-1px"})}function Te(e,t){const r=p.createElement("button");r.type="button",r.textContent=t;const c=e===E;return oe(r,c),r.dataset.on=c?"true":"false",de(r,"bare"),r.dataset.wmapInsightsTab=e,r.setAttribute("role","tab"),r.setAttribute("aria-selected",c?"true":"false"),r.tabIndex=c?0:-1,r.addEventListener("click",()=>{E!==e&&(E=e,F({keepSections:!0}))}),r}function ve(e){const t=p.createElement("button");return t.type="button",t.textContent=`\u2039 ${e.label}`,oe(t,!1),t.dataset.wmapInsightsBack="1",t.addEventListener("click",e.onBack),t}function ke(e,t,r,c=!0){const i=V(p),s=ee();let f="label";const b=r??"group",u=ie(e.map(d=>d.passBins)),l=ge?.(),g=new Map(l?.lotYieldSeries.map(d=>[d.waferIndex,d.yieldPercent])),C=d=>({...d,label:d.label.replace(/\s*·\s*\d+(\.\d+)?%$/,""),yieldPercent:g.get(d.waferIndex),key:d.waferIndex}),m=e.map(C),y=t?.map(d=>({key:d.key,items:d.items.map(C)})),S=()=>y?pe(y,R,f):_(m,R,f),w={title:t?`Yield by ${b} (pass: ${u})`:`Yield by wafer (pass: ${u})`,data:S(),selfControl:{current:f,options:[["yield","Sort: yield"],["label",t?`Sort: ${b}`:"Sort: wafer ID"]],onChange:d=>(f=d,{data:S()})},barColor:()=>lt,valueLabel:d=>`${d.percent.toFixed(1)}%`,reference:d=>{if(d.length<3)return null;const k=d.map(J=>J.percent).sort((J,Ae)=>J-Ae),I=k.length%2?k[(k.length-1)/2]:(k[k.length/2-1]+k[k.length/2])/2;return{value:I,label:`median ${I.toFixed(1)}%`}},drill:y?{onOpenGroup:d=>{const k=y.find(I=>I.key===d.label)?.items??[];return{data:_(k,R,f),title:`Yield by wafer \u2014 ${b}: ${d.label} (pass: ${u})`}},onBack:()=>({data:S(),title:`Yield by ${b} (pass: ${u})`}),groupLabelText:b}:void 0,onOpen:j?d=>{typeof d.key=="number"&&q(d.key,`Wafer ${d.label}`)}:void 0,onWaferContextMenu:Q(e),ownerDocument:p};let n=null;if(c&&(n=ce(w,v),n.card.style.minHeight="360px",i.appendChild(n.card)),t){const d=st({title:"Hard bin pareto",groups:t.map(k=>({key:k.key,items:k.items.map(I=>({dies:I.dies,hardBinCounts:I.statsSummary?.stats.hardBinCounts,softBinCounts:I.statsSummary?.stats.softBinCounts}))})),onSaveImage:v,ownerDocument:p});return d.card.style.minHeight="360px",i.appendChild(d.card),{card:i,destroy:()=>{n?.destroy(),d.destroy()}}}let a="hbin";const o=d=>d===void 0?le:(a==="hbin"?s.hard:s.soft).get(d)??le,h=e.map(d=>({dies:d.dies,hardBinCounts:d.statsSummary?.stats.hardBinCounts,softBinCounts:d.statsSummary?.stats.softBinCounts})),N=()=>ut(h,a),Oe={title:"Hard bin pareto",data:N(),selfControl:{current:a,options:[["hbin","Hard bins"],["sbin","Soft bins"]],onChange:d=>(a=d,{data:N(),title:`${a==="hbin"?"Hard":"Soft"} bin pareto`})},barColor:d=>o(d.binCode),ownerDocument:p},X=ce(Oe,v);return X.card.style.minHeight="360px",i.appendChild(X.card),{card:i,destroy:()=>{n?.destroy(),X.destroy()}}}function K(){const e=p.createElement("div");return e.dataset.wmapChartCard="1",Object.assign(e.style,{...dt(),display:"flex",flexDirection:"column",gap:x.lg,minWidth:"0"}),e}function De(e){if(O.innerHTML="",O.style.marginBottom="0",!he)return;const t=bt(e.map(r=>({metadata:r.metadata})),void 0,{facetableOnly:!1});t&&(t.style.marginBottom="0",O.appendChild(t),O.style.marginBottom=x.xs)}function Be(e,t,r,c){if(!e.length)return{elements:[],testValuesCard:null,functionalCard:null,destroy:()=>{}};const i=e.map(o=>o.wafer),s=e.map(o=>o.dies),f=e.flatMap(o=>o.dies),b=e.map(o=>o.statsSummary),u=b.every(o=>o!==void 0)?b:void 0,l=ye?.()??4,g=[],C=[],y=it({groups:(c??[{key:"",items:e}]).map(o=>({key:o.key,items:o.items.map(h=>({dies:h.dies,testSpecYield:h.statsSummary?.stats.testSpecYield,functionalYield:h.statsSummary?.stats.functionalYield}))})),testDefs:r,onSaveImage:v,ownerDocument:p});y.card.style.minHeight="300px",g.push(y.card),C.push(y.destroy);const S=ue(s,i,l,o=>e[o].passBins,gt);if(S.length){const o=fe({title:"Ring yield",mode:"ring",rows:S,onSaveImage:v,ownerDocument:p});g.push(o.card),C.push(o.destroy)}const w=ue(s,i,l,o=>e[o].passBins,yt);if(w.length){const o=fe({title:"Quadrant yield",mode:"quadrant",rows:w,onSaveImage:v,ownerDocument:p});g.push(o.card),C.push(o.destroy)}let n=null;if(t.length){const o=ft(f,t,void 0,u,U,s.map(h=>({dies:h})),void 0,"full");if(o){const h=K();h.appendChild(o),n=h}}let a=null;if(r.length){const o=mt(f,r,u,U);if(o){const h=K();h.appendChild(o),a=h}}return{elements:g,testValuesCard:n,functionalCard:a,destroy:()=>{for(const o of C)o()}}}function Le(e){const t=ie(e.map(l=>l.passBins)),r=e.length===1,c=e[0],i=K();Object.assign(i.style,{flexDirection:"row",flexWrap:"wrap",gap:x.md});const s=l=>{const g=l.lastElementChild;return g&&Object.assign(g.style,{borderRight:"none",paddingRight:"0",marginRight:"0"}),l};function f(l,g,C){const m=p.createElement("div");Object.assign(m.style,{display:"flex",alignItems:"baseline",gap:x.sm,paddingRight:x.xxl,marginRight:x.md,borderRight:`1px solid ${B.menuBorder}`});const y=p.createElement("div");y.textContent=l,Object.assign(y.style,{fontSize:Y.heading,fontWeight:"700",color:B.value,lineHeight:Ue.tight});const S=p.createElement("div");if(S.textContent=g,Object.assign(S.style,{fontSize:Y.body,color:B.label}),m.append(y,S),C){const w=p.createElement("div");w.textContent=C,Object.assign(w.style,{fontSize:Y.meta,color:B.label,opacity:ze.muted}),m.appendChild(w)}return m}if(r){const l=_([{...c,key:c.waferIndex}],R)[0]?.percent;return l!==void 0&&i.appendChild(f(`${l.toFixed(1)}%`,`Yield \xB7 pass: ${t}`)),i.appendChild(f(String(c.dies.length),"Total dies")),s(i)}i.appendChild(f(String(e.length),"Wafers"));const b=_(e.map(l=>({...l,key:l.waferIndex})),R).map(l=>l.percent).filter(l=>Number.isFinite(l));if(b.length){const l=b.reduce((m,y)=>m+y,0)/b.length,g=pe([{key:"all",items:e.map(m=>({...m,key:m.waferIndex}))}],R)[0]?.percent,C=g!==void 0&&g.toFixed(1)!==l.toFixed(1);i.appendChild(f(`${l.toFixed(1)}%`,`Mean per-wafer yield \xB7 pass: ${t}`,C?`${g.toFixed(1)}% by dies`:void 0))}const u=e.map(l=>l.statsSummary);if(u.every(l=>l!==void 0)){const l=u.reduce((C,m)=>C+m.stats.analyzedDies,0),g=u.reduce((C,m)=>C+m.stats.excludedDies,0);i.appendChild(f(l.toLocaleString(),"Dies analysed",g?`${g.toLocaleString()} excluded`:void 0))}else i.appendChild(f(e.reduce((l,g)=>l+g.dies.length,0).toLocaleString(),"Total dies"));return s(i)}function $e(e,t,r,c,i){const s=p.createElement("div");Object.assign(s.style,{display:"flex",flexDirection:"column",gap:x.lg});const f=e.length===1&&!c;e.length&&!c&&s.appendChild(Le(e));const b=ke(e,c,i,!f);s.appendChild(b.card);const u=Be(e,t,r,c);for(const l of u.elements)b.card.appendChild(l);return u.testValuesCard&&s.appendChild(u.testValuesCard),u.functionalCard&&s.appendChild(u.functionalCard),{card:s,destroy:()=>{b.destroy(),u.destroy()}}}function Ee(e,t,r,c){const i=V(p),s=Se(e),f=a=>{G=a;for(const o of[m,y,S])o!==b&&o?.setAxisPrefs(a)};let b=null;const u=a=>o=>{b=a(),f(o),b=null},l=a=>({...a,testStats:a.statsSummary?.stats.perTestStats}),g=e.map(l),C=r?.map(a=>({key:a.key,items:a.items.map(l)})),m=et({title:"Test value distribution",axisPrefs:G,onAxisPrefsChange:u(()=>m),onTestChange:a=>w(a),selectedTestNumber:L??void 0,items:g,testDefs:t,groups:C,groupLabelText:c,onSaveImage:v,onGroupChange:a=>z(a),onOpen:s?.open,openActionLabel:s?.label,onWaferContextMenu:Q(e),ownerDocument:p}),y=at({title:"Value histogram",axisPrefs:G,onAxisPrefsChange:u(()=>y),onTestChange:a=>w(a),selectedTestNumber:L??void 0,items:e,testDefs:t,groups:r,onGroupChange:a=>z(a),onSaveImage:v,ownerDocument:p}),S=tt({title:"Wafer-to-wafer trend",axisPrefs:G,onAxisPrefsChange:u(()=>S),onTestChange:a=>w(a),selectedTestNumber:L??void 0,items:e.map(a=>({label:a.label,key:a.waferIndex,dies:a.dies,testStats:a.statsSummary?.stats.perTestStats})),testDefs:t,onSaveImage:v,centreLabel:_e(Ve(e.map(a=>a.wafer.metadata)),"mean"),onOpen:j?(a,o)=>q(a,`Wafer ${e.find(h=>h.waferIndex===a)?.label??a}`,o):void 0,onWaferContextMenu:Q(e),ownerDocument:p}),w=a=>{L=a,m.setTest(a),y.setTest(a),S.setTest(a),n.setTest(a)},n=Ze({title:"Process capability",items:e,testDefs:t,onSaveImage:v,selectedTestNumber:L??void 0,onSelectTest:a=>w(a),ownerDocument:p});return i.append(n.card,m.card,y.card,S.card),{card:i,destroy:()=>{n.destroy(),m.destroy(),y.destroy(),S.destroy()}}}function Ie(e){const t=V(p),r=re(e).defs,c=e.flatMap(s=>s.dies),i=(T.sweeps??[]).map(s=>nt({spec:s,dies:c,testDefs:r,onSaveImage:v,ownerDocument:p}));for(const s of i)t.appendChild(s.card);return{card:t,destroy:()=>{for(const s of i)s.destroy()}}}function Pe(e,t,r){const c=V(p),i=rt({title:"Test scatter",items:e,testDefs:t,groups:r,binColors:ee().hard,onSaveImage:v,ownerDocument:p}),s=ot({title:"Test correlation matrix",items:e,testDefs:t,onSaveImage:v,onSaveText:U,onSelectPair:(f,b)=>i.setXY(f,b),ownerDocument:p});return c.append(s.card,i.card),{card:c,destroy:()=>{s.destroy(),i.destroy()}}}function F(e){e?.keepSections||ae(),M.innerHTML="",D.innerHTML="",T.backTab&&D.appendChild(ve(T.backTab));for(const n of Ce)D.appendChild(Te(n.key,n.label));const t=xe();De(t);const r=Re(t,{facetableOnly:!0}).filter(n=>n.splittable),c=p.createElement("div");Object.assign(c.style,{display:"flex",gap:x.md,alignItems:"center",marginLeft:x.xxl,paddingBottom:x.xs});let i;r.length>0?(c.appendChild(ct("Group by:",[{value:"",label:"None"},...r.map(n=>({value:n.key,label:`${n.label} (${n.values.length})`}))],A??"",n=>{A=n||void 0,$=null,F()},{hook:"group-by",ownerDocument:p})),i=r.find(n=>n.key===A)?.label):A=void 0;let s;if(A){const n=new Map,a=[];for(const o of t){const h=We(o.metadata,A)??Me;n.has(h)||(n.set(h,[]),a.push(h)),n.get(h).push(o)}s=a.map(o=>({key:o,items:n.get(o)}))}$!==null&&!s?.some(n=>n.key===$)&&($=null),s&&s.length>0&&c.appendChild(pt(s.map(n=>n.key),"Show:",$,n=>z(n),{ownerDocument:p}).el);let f=null;if(T.onOpenGuide){const n=p.createElement("button");n.type="button",n.innerHTML=Je.help,n.setAttribute("aria-label","User guide"),Object.assign(n.style,{...Ke("bare"),display:"inline-flex",alignItems:"center",justifyContent:"center",width:"24px",height:"24px",flexShrink:"0"}),de(n,"bare"),Xe(n,"User guide"),n.addEventListener("click",()=>T.onOpenGuide()),Object.assign(n.style,{marginLeft:"auto"}),f=n}D.appendChild(c),f&&D.appendChild(f);const b=$!==null?s?.find(n=>n.key===$):void 0,u=b?.items??t,l=b?void 0:s,g=re(u),C=g.defs,m=C.filter(Ye);L!==null&&!m.some(n=>n.testNumber===L)&&(L=null);const y=e?.keepSections?H.get(E):void 0,S=y??(E==="overview"?$e(u,m,C,l,i):E==="distributions"?Ee(u,m,l,i):E==="sweeps"?Ie(u):Pe(u,m,l));y||H.set(E,S);const w=g.conflicts.filter(n=>n.excluded);if(w.length>0){const n=p.createElement("div");Object.assign(n.style,{color:B.label,fontSize:Y.body,padding:`0 ${W} ${x.sm}`});const a=w.slice(0,6).map(N=>N.testNumber).join(", "),o=w.length>6?`, and ${w.length-6} more`:"",h=w.length===1?"it":"them";n.textContent=`${w.length} test ${w.length===1?"number is":"numbers are"} hidden (${a}${o}) \u2014 the wafers in view describe ${h} differently, so their values cannot be pooled. `+(s&&s.length>0?`Pick one ${i??"group"} under "Show:" to analyse ${h}.`:"Load one test program at a time to analyse them."),n.dataset.wmapWithheldTests=String(w.length),M.appendChild(n)}M.appendChild(S.card)}return{el:P,render:F,destroy:()=>{ae(),P.remove()}}}
|
|
@@ -41,6 +41,61 @@ export interface GalleryOptions {
|
|
|
41
41
|
viewOptions?: WaferViewOptions;
|
|
42
42
|
/** Called whenever a shared gallery option changes. */
|
|
43
43
|
onViewOptionsChange?: (opts: WaferViewOptions, changed: (keyof WaferViewOptions)[], category: 'preference' | 'state' | 'mixed') => void;
|
|
44
|
+
/**
|
|
45
|
+
* Called once the gallery has finished building: every factory resolved, and
|
|
46
|
+
* the lot-wide surfaces (legend, shared colours, summary panel) settled.
|
|
47
|
+
*
|
|
48
|
+
* Exists so a host can hold its own progress indicator over a large lot's
|
|
49
|
+
* load without polling the gallery's DOM. **Always fires, and always
|
|
50
|
+
* asynchronously, whichever form the items took** — a host passing factories
|
|
51
|
+
* and a host passing pre-built items get the same one signal, so neither has
|
|
52
|
+
* to know which path the gallery took. With factories it fires after the last
|
|
53
|
+
* card; with pre-built items, on the next task after mount (never before
|
|
54
|
+
* `renderWaferGallery` returns, so the controller is always in hand).
|
|
55
|
+
*
|
|
56
|
+
* **It waits for the Summary panel's own render to finish**, which on a large
|
|
57
|
+
* lot is seconds after the last card appears — the panel is staged across
|
|
58
|
+
* tasks, and on 50 wafers x 8,000 dies x 50 tests in Chrome the cards are in
|
|
59
|
+
* at 3.6 s and the panel at 8.2 s. That is the point of it: a host clearing
|
|
60
|
+
* its indicator when the cards land would leave the rest of the wait
|
|
61
|
+
* unexplained, which is the failure this signal exists to prevent. There is
|
|
62
|
+
* deliberately no earlier "cards are in" variant — one settle signal, one
|
|
63
|
+
* meaning.
|
|
64
|
+
*
|
|
65
|
+
* Fires once per build, so a rebuild fires it again — `setItems`, and the
|
|
66
|
+
* internal rebuild that switching into a stacked mode does. It says "the
|
|
67
|
+
* gallery is settled", not "this happened for the first time".
|
|
68
|
+
*/
|
|
69
|
+
onItemsResolved?: () => void;
|
|
70
|
+
/**
|
|
71
|
+
* Called as each card is built, with how many of the expected items now
|
|
72
|
+
* exist and how many there will be. `total` is the count `setItems` was
|
|
73
|
+
* given, so it is correct from the first call and a progress bar can be
|
|
74
|
+
* sized before anything arrives.
|
|
75
|
+
*
|
|
76
|
+
* This is the *advance* signal; `onItemsResolved` is the *settled* one, and
|
|
77
|
+
* they are not interchangeable. A progressive mount of a large lot runs for
|
|
78
|
+
* 10-25 s, and a host indicator that can only say "loading" for that long
|
|
79
|
+
* reads as a hang — which is the failure the progressive path exists to
|
|
80
|
+
* prevent, reintroduced one layer up.
|
|
81
|
+
*
|
|
82
|
+
* **Fires on the pre-built path too**, so no host has to branch on which
|
|
83
|
+
* form it passed: a fully pre-built mount is one call with
|
|
84
|
+
* `resolved === total`. A mixed set reports its pre-built items in one call
|
|
85
|
+
* and then one call per factory.
|
|
86
|
+
*
|
|
87
|
+
* It covers the cards only. On a large lot the Summary panel keeps filling
|
|
88
|
+
* in for seconds after the last card, with no card activity to report —
|
|
89
|
+
* `onItemsResolved` is what marks the end of *that*. There is deliberately
|
|
90
|
+
* no third callback between them: if a host needs to name that phase, it
|
|
91
|
+
* knows it has begun when `resolved === total` and ended when
|
|
92
|
+
* `onItemsResolved` fires.
|
|
93
|
+
*
|
|
94
|
+
* Deferred a task and generation-guarded like every callback here, so a
|
|
95
|
+
* gallery rebuilt or destroyed before the turn arrives stays quiet. Not
|
|
96
|
+
* called at all for an empty item list.
|
|
97
|
+
*/
|
|
98
|
+
onItemResolved?: (resolved: number, total: number) => void;
|
|
44
99
|
/**
|
|
45
100
|
* Draw a legend on every card as well as the lot-level one. Default false.
|
|
46
101
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getUniqueTestNumbers as bo,resolveTestNumber as yo,findTestDef as wo,collectMetadataValues as xo}from"../renderer/buildView.js";import{metadataCategoricalValue as vo}from"../core/metadata.js";import{resolveBinColorsForMaps as Co,mergeBinDefs as Ke,binColorWarning as So,mixedPassBinsWarning as Mo}from"../renderer/binColors.js";import{itemPassBins as Do,INPUT_DEFAULT_PASS_BINS as Bo}from"../core/passBins.js";import{NO_DATA_FILL as ko}from"../renderer/colorMap.js";import{metadataValueColor as Eo}from"../renderer/colorMap.js";import{resolveCanvasTheme as Oo}from"./canvasTheme.js";import{ICONS as Te}from"./icons.js";import{SHADOW as Le,LEADING as qe,TRACKING as To,controlStyle as Lo,wireControlHover as ht,SPACE as w,EDGE_GUTTER as oe,MAP_CHROME_INSET as $o,RADIUS as N,FONT as T,CLR as g,sevColor as cn,MODE_LABELS as Wo,BIN_LEGEND_MODES as un,STACKED_MODES as ge,Z_ABOVE as fn,applyOverlayZ as Ro,getTooltip as Io,hideTooltip as pn,createToolbarHelpers as Ao,buildModeMenuEl as Po,openDetachWindow as Fo,openFloatingWindow as Ho,openModal as jo,openReportModal as Vo,copyWmapThemeTokens as zo,syncWmapPopupTheme as No,openUserGuideWindow as _o,makePaletteBtn as Go,makeLogScaleBtn as Ko,makeLegendStyleBtn as qo,makeOverlaysBtn as Uo,makeOrientationBtn as Xo,menuLayerFor as mn,saveImageBlob as gn,markMenuTrigger as $e,wireMenuA11y as hn,wireExpandToggle as bn,wireTooltip as yn,requestedPassFailDisplay as wn,overlayMenuRows as Zo,anyOverlayActive as Yo,logWmapVersionOnce as Qo,buildDataModeEntries as Jo,metadataKeyHasData as ei,metadataModeEntry as ti}from"./toolbar.js";import{waferDisplayLabel as Ue,waferIdentityLabel as ni}from"../core/waferLabel.js";import{metadataDisplayValue as oi}from"../core/metadata.js";import{withExportContext as ii,noticeDownloadFilenameChange as ai}from"./exportName.js";import{sortBinsForDisplay as li}from"../stats/binPareto.js";import{diePassStatus as si}from"../core/dies.js";import{aggregateValues as ri,aggregateBinCounts as xn}from"../core/aggregates.js";import{renderWaferMap as di,renderWaferMapCard as vn,toPublicViewOptions as Cn}from"./renderWaferMap.js";import{classifyChanged as ci,COLOR_KEYS as ui}from"./renderWaferMap.js";import{buildWaferMap as fi,getTestPassStatus as Sn,isParametricTest as bt,getDieTestValue as pi}from"../renderer/buildWaferMap.js";import{analyzeWaferMap as Xe}from"../stats/analyzeWaferMap.js";import{collectWarnings as mi,buildWarningsMenuEl as gi,severityOf as hi}from"./warnings.js";import{compareNatural as yt}from"../core/utils.js";import{createSummaryPanelEl as wt,buildMetadataStripRow as bi,buildCompactMetadataRows as Mn,metadataEntries as Dn,renderLotSummaryContent as yi,reportMapsFromItems as wi}from"./summaryPanel.js";import{renderLotReportHtml as xi}from"../stats/renderSummaryReport.js";import{prettyKey as vi}from"../stats/facets.js";import{mergeTestDefs as Ci}from"../stats/mergeTestDefs.js";import{getDieKey as Si,hasPosition as Mi}from"../core/dies.js";function Bn(u){if(typeof u!="number"||!Number.isFinite(u))return;const v=Math.round(u);return v>=1?v:void 0}const xt=12;function Di(u,v,p){let A=v;if(v.length>xt){const D=v.slice(0,xt-1),$=v.slice(xt-1),H=$.reduce((Y,j)=>Y+j.count,0);A=[...D,{color:g.label,count:H,label:`Other (${$.length} bins)`}]}const M=u.createElement("div");Object.assign(M.style,{display:"flex",columnGap:"1px",width:"100%",height:"8px",borderRadius:N.control,overflow:"hidden",border:`1px solid ${g.menuBorder}`,boxSizing:"border-box",marginTop:w.xs,flexShrink:"0"}),M.setAttribute("role","img"),M.setAttribute("aria-label",`Population split: ${A.map(D=>`${D.label} ${Ze(D.count/p*100)}`).join(", ")}`);for(const D of A){const $=D.count/p*100,H=u.createElement("div");Object.assign(H.style,{flex:`${$} 1 0`,minWidth:$>0?"2px":"0",background:D.color}),yn(H,`${D.label} \xB7 ${D.count.toLocaleString()} dies \xB7 ${Ze($)}`),M.appendChild(H)}return M}function Ze(u){return u>0&&u<.1?"<0.1%":`${u.toFixed(1)}%`}function kn(u,v,p){const A=new Map;let M=0,D=0;for(const $ of u){const H=p?new Set(p($)):void 0;for(const Y of $.dies){if(Y.partial||Y.edgeExcluded)continue;const j=v(Y);j!==void 0&&(A.set(j,(A.get(j)??0)+1),M++,H&&si(Y,H)&&D++)}}return{counts:A,total:M,pass:D}}function En(u,v){const p=u.ownerDocument.createElement("div");Object.assign(p.style,{display:"flex",alignItems:"center",gap:"5px",cursor:"pointer",userSelect:"none",padding:`${w.xxs} ${w.xs}`,borderRadius:N.control});const A=u.ownerDocument.createElement("span");Object.assign(A.style,{display:"inline-block",width:"13px",height:"13px",flexShrink:"0",background:v.color,border:v.isActive?`2px solid ${g.iconActive}`:`1px solid ${g.menuBorder}`,borderRadius:N.control,boxSizing:"border-box"});const M=u.ownerDocument.createElement("span");if(M.textContent=v.label,Object.assign(M.style,{fontWeight:v.isActive?"700":"400",color:v.isActive?g.iconActive:g.text,whiteSpace:"nowrap"}),p.appendChild(A),p.appendChild(M),v.count!==void 0){const D=u.ownerDocument.createElement("span");if(D.textContent=v.count.toLocaleString(),Object.assign(D.style,{color:v.isActive?g.iconActive:g.text,fontWeight:v.isActive?"700":"400",whiteSpace:"nowrap"}),p.appendChild(D),v.percent!==void 0){const $=u.ownerDocument.createElement("span");$.textContent=Ze(v.percent),Object.assign($.style,{color:g.label,whiteSpace:"nowrap"}),p.appendChild($)}}p.setAttribute("role","button"),p.setAttribute("aria-pressed",v.isActive?"true":"false"),p.tabIndex=0,p.addEventListener("mouseenter",()=>{p.style.background=g.bgHover}),p.addEventListener("mouseleave",()=>{p.style.background="transparent"}),p.addEventListener("focus",()=>{p.style.background=g.bgHover}),p.addEventListener("blur",()=>{p.style.background="transparent"}),p.addEventListener("click",v.onClick),p.addEventListener("keydown",D=>{(D.key==="Enter"||D.key===" ")&&(D.preventDefault(),v.onClick())}),u.appendChild(p)}export function renderWaferGallery(u,v,p={}){Qo();const A=6;let M=Bn(p.columns);const D=p.showHelpButton??!1,$=p.userGuideExtension,H=p.insights?.enabled??!1,Y=Ro(p.zIndex),j=p.summaryPanel,On=e=>[...Do(e)],vt=()=>x.flatMap(e=>e?[e.ringCount??4]:[]),Ye=()=>vt()[0]??4;function Tn(e){const t=[...new Set(e)].sort((n,o)=>n-o);return t.length<2?null:{code:"ring-count-mixed",severity:"warning",message:`These wafers were built with different ring counts (${t.join(", ")}). Each card and each wafer's findings use their own; the lot's ring yield in the Summary panel, report and Insights uses ${e[0]} rings.`}}let V=p.lotStatsSummary,he=p.viewOptions?.legendPosition??"default",We=p.perCardLegend??!1;function be(){const e=r.plotMode??"hardBin";return un.has(e)?null:r.colorbarRangeMode==="data"?"Each map has its own value range, so it keeps its own colour bar":"These wafers have no shared colour bar for value mode, so each map keeps its own"}function Ct(){const e=We||be()!==null;for(const t of S)t&&t.setOptions({showLegend:e})}let r={plotMode:"hardBin",showDieLabels:!1,showRingBoundaries:!1,showQuadrantBoundaries:!1,rotation:0,flipX:!1,flipY:!1,...p.viewOptions},S=[],ie=[],re=[],L=[];const Re=ii(()=>{const e=L.filter(n=>n!=null);return{lots:[...new Set(e.map(n=>oi(n.wafer.metadata?.lot)).filter(n=>n!==void 0))].sort(yt),...e.length===1?{wafer:ni(e[0])}:{waferCount:e.length}}},p.onSaveImage,p.onSaveText);ai(p.downloadFilename);let x=v.map(e=>typeof e=="function"?null:e);function St(){return Ci(x)}function ye(){if(x.some(e=>e?.testDefs?.length))return St().defs}let Qe=0,Ie=0;const _=new Map;let Ln=0,P=null,we=null,Mt=new Set,h=null,$n={};function Dt(e){return x[e]?.statsSummary??V?.perWafer.find(t=>t.waferIndex===e)?.summary}function Je(){return!!(x.some(e=>e?.statsSummary?.findings.length)||V?.perWafer.some(e=>e.summary.findings.length))}const Wn=Io(),de=Ao(Wn),{makeBtn:Q,setActive:xe,makeSep:G,makeMenuRow:Rn,makeMenuSection:In,makeDropdown:Bt,closeOpenMenu:Ae,getOpenMenu:ve,setOpenMenu:Ce}=de;u.ownerDocument.addEventListener("click",Ae,!0);const kt=()=>pn();window.addEventListener("blur",kt);let Et=p.findingsNotice;function Ot(e){Mt=new Set(e);const t=[...R.querySelectorAll(".wmap-gallery-card")];let n;t.forEach((o,d)=>{const i=Mt.has(d);o.style.outline=i?`3px solid ${g.findingHighlight}`:"",o.style.outlineOffset=i?"-3px":"",i&&n===void 0&&(n=o)}),n?.scrollIntoView?.({behavior:"smooth",block:"nearest"})}function Tt(){Ot([])}function Lt(){for(const e of S)e&&e.clearSelection()}function et(e,t){const n=new Set(e),o=t??S.map((d,i)=>i);for(const d of o){const i=L[d],l=S[d];if(!i||!l)continue;const s=i.dies.filter(a=>n.has(Si(a)));l.setSelection(s)}}function An(){const e=[];for(let t=0;t<x.length;t++){const n=x[t];if(!n)continue;const o=Dt(t)?.findings??[];o.length&&e.push({index:t,item:n,unusualCount:o.filter(d=>d.severity==="unusual").length,notableCount:o.filter(d=>d.severity==="notable").length,totalCount:o.length})}return e}function Pn(e){const t=L[e]??x[e];t&&Oe(e,t)}function Fn(e){const t=Dt(e)?.findings??[];if(t.length)return{total:t.length,unusual:t.filter(n=>n.severity==="unusual").length,notable:t.filter(n=>n.severity==="notable").length}}function Hn(){Vo(xi(wi(x,Bo,Ye())),{anchor:u})}function jn(){if(!h)return;h.innerHTML="";const e=An();if(x.length>0){const n=u.ownerDocument.createElement("div"),o=e.length,d=x.filter(Boolean).length;n.textContent=o===0?`No findings on any of the ${d} wafers`:`${o} of ${d} wafer${d===1?"":"s"} with findings`,Object.assign(n.style,{fontSize:T.body,color:g.label,marginBottom:w.md}),h.appendChild(n)}if(e.length>0){const n=u.ownerDocument.createElement("button");n.type="button",n.textContent="Summary report",Object.assign(n.style,{...Lo("outlined"),marginBottom:w.lg,display:"block",width:"100%",textAlign:"left"}),ht(n),n.addEventListener("click",Hn),h.appendChild(n)}if(e.length===0){const n=u.ownerDocument.createElement("div");Object.assign(n.style,{color:g.icon,fontSize:T.body,padding:"4px 0"}),n.textContent="No findings on any wafer.",h.appendChild(n)}else for(const{index:n,item:o,unusualCount:d,notableCount:i,totalCount:l}of e){const s=d?"unusual":i?"notable":"info",a=d+i||l,c=u.ownerDocument.createElement("button");c.type="button",Object.assign(c.style,{display:"flex",alignItems:"center",justifyContent:"space-between",width:"100%",padding:"5px 8px",marginBottom:w.xs,border:"none",borderLeft:`3px solid ${cn(s)}`,borderRadius:N.control,background:g.bgHover,cursor:"pointer",fontSize:T.body,textAlign:"left",boxSizing:"border-box"}),c.addEventListener("mouseover",()=>{c.style.background=g.bgActive}),c.addEventListener("mouseout",()=>{c.style.background=g.bgHover});const f=u.ownerDocument.createElement("span");f.textContent=Ue(o,n),Object.assign(f.style,{color:g.iconHover,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"});const b=u.ownerDocument.createElement("span");b.textContent=String(a),c.setAttribute("aria-label",`${Ue(o,n)} \u2014 ${a} finding${a===1?"":"s"}${d?`, ${d} unusual`:""} \u2014 view wafer`),Object.assign(b.style,{marginLeft:w.sm,flexShrink:"0",background:cn(s),color:"#fff",borderRadius:N.container,padding:"1px 5px",fontSize:T.body,fontWeight:"600"}),c.appendChild(f),c.appendChild(b),c.addEventListener("click",()=>Oe(n,o)),h.appendChild(c)}const t=u.ownerDocument.createElement("div");t.style.height="12px",h.appendChild(t)}function z(){if(h)if(V){const e=Ke(x.map(n=>n?.hbinDefs)),t=Ke(x.map(n=>n?.sbinDefs));yi(h,{lotSummary:V,items:x,hbinDefs:e.length?e:void 0,sbinDefs:t.length?t:void 0,testDefs:ye(),ringCount:Ye(),binColors:r.binColors,plotMode:r.plotMode??"hardBin",fallbackFormat:r.fallbackFormat,activeFindingId:we,warnings:p.warnings?.display??!0?J:[],findingsFilter:$n,findingsNotice:Et,onFindingsFilterChange:z,onSaveText:Re.onSaveText,onFindingClick:(n,o)=>{we===n.id?tt():zn(n,o),z()},onWaferClick:Pn,findingsFor:Fn,dieListOptions:p.dieList})}else jn()}function Vn(e){const t=e.highlight;return t?.kind==="wafer"&&t.waferIndices?.length?t.waferIndices:null}function $t(e){return[e.variable.kind,e.variable.index??"",e.variable.bin??"",e.comparison.family,e.comparison.left,e.effect.direction].join("|")}let Pe=[];function Wt(){if(Pe.length!==0){for(const e of Pe)S[e]?.setOptions({plotMode:r.plotMode,activeTest:r.activeTest});Pe=[]}}function tt(){we=null,Tt(),Lt(),Wt(),O({highlightBin:void 0},{fireCallback:!1})}function zn(e,t){if(we===e.id){tt();return}we=e.id,t.style.background=g.bgActive,t.style.fontWeight="600",Wt();const{kind:n,index:o}=e.variable;if(n==="test"){const i=o??0,l=ye();if(l===void 0||l.some(a=>a.testNumber===i))O({plotMode:"value",activeTest:i,highlightBin:void 0},{fireCallback:!1});else{O({highlightBin:void 0},{fireCallback:!1});const c=ge.has(r.plotMode??"hardBin")?null:Vn(e);if(c){for(const f of c)S[f]?.setOptions({plotMode:"value",activeTest:i});Pe=[...c]}}}else n==="softBin"?O({plotMode:"softBin",highlightBin:void 0},{fireCallback:!1}):O({plotMode:"hardBin",highlightBin:void 0},{fireCallback:!1});Tt(),Lt();const d=e.highlight;if(d.kind==="wafer"){Ot(d.waferIndices);const i=$t(e);for(const l of d.waferIndices){const c=L[l]?.statsSummary?.findings.find(f=>$t(f)===i)?.highlight?.dieKeys;c?.length&&et(c,[l])}}else d.kind==="bin"?d.dieKeys?.length&&et(d.dieKeys):(d.kind==="region"||d.kind==="dies")&&d.dieKeys?.length&&et(d.dieKeys)}function ae(){if(!P)return;const e=!!h;P.style.display=(V||Je())&&e&&!Be?"flex":"none";const t=h?h.style.display!=="none":!1;(V?.hasNotableFindings||x.some(o=>o?.statsSummary?.hasNotableFindings))&&!t?P.style.color=g.findingIndicator:P.dataset.active||(P.style.color=g.icon)}const W=u.ownerDocument.createElement("div");W.dataset.wmapToolbar="gallery",Object.assign(W.style,{flexShrink:"0",marginLeft:"auto",display:"inline-flex",flexDirection:"row",alignItems:"center",gap:"0",background:g.menuBg,border:`1px solid ${g.menuBorder}`,borderRadius:N.control,padding:"0",boxShadow:Le.panel,flexWrap:"wrap",minWidth:"0",overflowX:"auto"});const Rt=()=>{const e=ve();e&&(e.remove(),Ce(null)),$e(X,!1)},X=Q("mode","Plot mode",()=>{if(ve()){Rt();return}const e=x.flatMap(y=>y?.dies??[]),t=ye(),{testEntries:n,binEntries:o,stackedEntries:d}=Jo(e,t,{includeStacked:!0}),i=x.filter(Boolean).length,l=y=>{if(y===void 0)return i;let I=0;for(const se of x)se?.dies?.some(U=>Sn(U,y)!==void 0||U.testValues?.[y]!==void 0)&&I++;return I},s=i<2?n:n.map(y=>{const I=l(y.activeTest);return I===i?y:{...y,label:`${y.label} \u2014 ${I} of ${i} wafers`}}),a=r.plotMode??"hardBin",c=r.activeTest??0;function f(y){return y.plotMode!==a?!1:y.plotMode==="value"?c===(y.activeTest??0):y.plotMode==="metadata"?r.activeMetadataKey===y.activeMetadataKey:!0}function b(y,I){y.activeTest!==void 0?O({plotMode:"value",activeTest:y.activeTest,activeMetadataKey:void 0,logScale:y.logScale}):y.activeMetadataKey!==void 0?O({plotMode:y.plotMode,activeTest:void 0,activeMetadataKey:y.activeMetadataKey,passFailDisplay:"off"}):O({plotMode:y.plotMode,activeTest:void 0,activeMetadataKey:void 0,passFailDisplay:"off"}),I.remove(),Ce(null),$e(X,!1)}const E=new Set,B=x.flatMap(y=>y?.metadataFields??[]).filter(y=>!E.has(y.key)&&E.add(y.key)).filter(y=>ei(e,y.key)).map(ti),C=Po(X.getBoundingClientRect(),s,o,d,f,b,{makeMenuRow:Rn,makeMenuSection:In},a,X.ownerDocument.defaultView??window,B);mn(X).appendChild(C),Ce(C),$e(X,!0),hn(C,X,Rt)});$e(X,!1);const Nn=()=>L.flatMap(e=>e?[...e.hbinDefs??[],...e.sbinDefs??[]]:[]).some(e=>e.color),{btn:_n,sync:It}=Go(de,()=>({...r,plotMode:r.plotMode??"hardBin"}),Nn,e=>O(e));It();const Gn=v.some(e=>typeof e!="function"&&(e.reticles?.length??0)>0);function Fe(){const e=ye(),{testNumber:t}=yo(r.activeTest??0,e);return{testNumber:t,td:wo(e,t)}}function At(){if((r.plotMode??"hardBin")!=="value")return!1;const{td:e}=Fe();return e!==void 0&&(e.limitLow!==void 0||e.limitHigh!==void 0)}function Se(){if((r.plotMode??"hardBin")!=="value")return!1;const{td:e}=Fe();return e!==void 0&&!bt(e)}function Kn(){if((r.plotMode??"hardBin")!=="value")return!1;const{testNumber:e,td:t}=Fe();return x.some(n=>n?.dies?.some(o=>Sn(o,e,t)!==void 0))}function qn(e,t){if(!t||!bt(t))return;const n=t.limitLow!==void 0||t.limitHigh!==void 0;if((wn(r)==="spec"&&n?"spec":r.colorbarRangeMode??"spec")==="spec"&&n)return;let i=1/0,l=-1/0;for(const s of x)if(s)for(const a of s.dies){const c=pi(a,e);c!==void 0&&(c<i&&(i=c),c>l&&(l=c))}if(isFinite(i))return i===l?[i,i+1]:[i,l]}function Pt(){if((r.plotMode??"hardBin")!=="metadata")return;const e=r.activeMetadataKey;if(!e)return;const t=new Set;for(const n of x)if(n)for(const o of xo(n.dies,e))t.add(o);return{key:e,values:[...t].sort(yt)}}function nt(){const e=Pt();if(!(e===void 0&&r.metadataValueOrder===void 0)){r={...r,metadataValueOrder:e};for(const t of S)t&&t.setOptions({metadataValueOrder:e})}}function ot(){if((r.plotMode??"hardBin")!=="value")return;const{testNumber:e,td:t}=Fe(),n=qn(e,t),o=n?{test:e,range:n}:void 0;r={...r,valueRange:o};for(const d of S)d&&d.setOptions({valueRange:o})}let it=!1;function Un(){if(it)return;it=!0,(u.ownerDocument.defaultView?.requestAnimationFrame??(t=>setTimeout(()=>t(0),0)))(()=>{it=!1,ot(),nt(),Ht()})}let Ft=[];function ce(){const{colors:e,mixedHardBins:t}=Co(x.filter(n=>n!=null),{binColorScheme:r.binColorScheme,useDefinedBinColors:r.useDefinedBinColors});return Ft=t,e}function Ht(){const e=ce();r={...r,binColors:e};for(const t of S)t&&t.setOptions({binColors:e});Me()}const Xn=Uo(de,()=>Zo(r,Gn,{functionalActive:Se(),hasLimits:At()&&!Se(),hasRecorded:Kn()&&!Se(),binMode:(r.plotMode??"hardBin")==="hardBin"||(r.plotMode??"hardBin")==="softBin"},e=>O(e)),()=>Yo(r)),{btn:Zn,sync:jt}=qo(de,()=>({plotMode:r.plotMode,legendPosition:he}),e=>{he=e;for(const t of S)t&&t.setOptions({legendPosition:he})},{get:()=>We,set:e=>{We=e,Ct()},blockedReason:be});jt();const Yn=[{value:"mean",label:"Mean"},{value:"median",label:"Median"},{value:"stddev",label:"Std Dev"},{value:"min",label:"Min"},{value:"max",label:"Max"},{value:"count",label:"Count"}],Vt=Bt("aggr","Aggregation method",()=>Yn,()=>r.aggregationMethod??"mean",e=>O({aggregationMethod:e}));function zt(){const e=r.plotMode==="stackedValues";Vt.style.display=e?"":"none"}zt();const{btn:Qn,sync:Nt}=Ko(de,()=>({...r,functionalActive:Se()}),e=>O(e));Nt();const He=Q("specRange","Colorbar range: spec limits",()=>{const e=r.colorbarRangeMode==="data"?"spec":"data";O({colorbarRangeMode:e})});function _t(){const e=(r.plotMode??"hardBin")==="value"&&At()&&wn(r)==="off"&&!Se();He.style.display=e?"":"none";const t=(r.colorbarRangeMode??"spec")==="spec";xe(He,t),He.ariaLabel=t?"Colorbar range: spec limits (click for data range)":"Colorbar range: data range (click for spec limits)"}_t();const Jn=Xo(de,()=>r,e=>O(e)),eo=Q("downloadAll","Download gallery PNG",mo),to=Bt("columns","Columns",()=>[{value:"auto",label:"Auto"},{value:"1",label:"1 column"},{value:"2",label:"2 columns"},{value:"3",label:"3 columns"},{value:"4",label:"4 columns"},{value:"5",label:"5 columns"}],()=>M!=null?String(M):"auto",e=>en(e==="auto"?void 0:Number(e))),k=u.ownerDocument.createElement("div");Object.assign(k.style,{display:"inline-flex",alignItems:"center",gap:"0"}),W.appendChild(k),k.appendChild(X),k.appendChild(_n),k.appendChild(Vt),k.appendChild(Qn),k.appendChild(He),k.appendChild(G()),k.appendChild(Xn),k.appendChild(G()),k.appendChild(Zn),k.appendChild(G()),k.appendChild(Jn),k.appendChild(G()),k.appendChild(to),k.appendChild(G()),k.appendChild(eo),(V||Je())&&(P=Q("findings","Summary panel",()=>{if(!h)return;const e=h.style.display!=="none";e||z(),h.style.display=e?"none":"flex",xe(P,!e),ae()}),W.appendChild(G()),W.appendChild(P));let K=null,je=null,J=[],Gt=!1;function Me(){const e=mi({lotStatsSummary:V,result:{warnings:[...x.flatMap(n=>n?.warnings??[]),...St().warnings]},extra:[r.binColors&&So(r.binColors,r.plotMode),Mo(Ft),Tn(vt())].filter(n=>!!n)}),t=e.length!==J.length||e.some((n,o)=>n.code!==J[o]?.code||n.message!==J[o]?.message);J=e,(t||!Gt)&&(Gt=!0,p.warnings?.onWarning?.(e)),no()}function no(){if(!K||!je)return;const e=J.length,t=e>0;if(K.style.display=t?"flex":"none",je.style.display=t?"":"none",!t)return;const n=hi(J[0]),o=`${e} data ${e===1?"warning":"warnings"}`;K.style.color=n==="error"?g.errText:g.warnText,K.ariaLabel=n==="error"?`${o} \u2014 some wafers may be positionally wrong`:o}(p.warnings?.display??!0)&&(je=G(),K=Q("warning","Data warnings",()=>{const e=ve();if(Ae(new MouseEvent("click")),e)return;const t=gi(K.getBoundingClientRect(),J,K.ownerDocument.defaultView??window);mn(u).appendChild(t),Ce(t),hn(t,K,()=>Ae(new MouseEvent("click")))}),$e(K,!1),W.appendChild(je),W.appendChild(K)),Me();let le=null;H&&(le=Q("analysis","Insights",()=>{Ut(!Be)}),le.dataset.wmapInsightsBtn="1",W.appendChild(G()),W.appendChild(le));function Kt(){import("./userGuideHtml.js").then(e=>_o({buildWaferMap:fi,renderWaferMap:di,renderWaferGallery,analyzeWaferMap:Xe},e.USER_GUIDE_HTML,$,u))}D&&(W.appendChild(G()),W.appendChild(Q("help","User guide",()=>Kt())));const ue=u.ownerDocument.createElement("div");ue.dataset.wmapGalleryMeta="1",Object.assign(ue.style,{flex:"1",minWidth:"0",overflow:"hidden",display:"flex",alignItems:"center",padding:`${w.sm} ${w.lg}`,fontSize:T.sub,lineHeight:qe.none,boxSizing:"border-box"});const Ve=u.ownerDocument.createElement("div");Object.assign(Ve.style,{background:g.canvasBg,display:"flex",alignItems:"stretch",gap:w.lg,paddingBottom:w.lg,minWidth:"0"});const ee=u.ownerDocument.createElement("div");ee.dataset.wmapGalleryLegend="1",Object.assign(ee.style,{display:"flex",flexDirection:"column",gap:w.sm,background:g.menuBg,border:`1px solid ${g.menuBorder}`,borderRadius:N.container,padding:`${w.sm} ${w.lg}`,marginBottom:w.lg,boxShadow:Le.panel,fontSize:T.body,lineHeight:qe.none,boxSizing:"border-box",width:"100%",minWidth:"0"});const q=u.ownerDocument.createElement("div");Object.assign(q.style,{display:"flex",flexDirection:"row",alignItems:"flex-start"});let fe=null,De=null,qt=null;function oo(){return H?fe?Promise.resolve(fe):(qt??=import("./insightsTab.js").then(({createInsightsTab:e})=>(fe=e({getItems:()=>x,getLotStats:()=>V,getBinColors:()=>r.binColors??ce(),getRingCount:Ye,defaultView:p.insights?.defaultView,onOpenGuide:void 0,showMetadataStrip:!1,onSaveImage:Re.onSaveImage,onSaveText:Re.onSaveText,ownerDocument:u.ownerDocument,openWafer:(t,n,o)=>{const d=x[t];if(!d)return;let i=null;const l=jo({title:n,onClose:()=>i?.destroy(),anchor:u});on(l,n,d.wafer.metadata??void 0),i=ut(l.contentWrap,d,o)}}),De=fe.el,De.style.display="none",u.appendChild(De),fe)),qt):Promise.resolve(null)}let Be=!1;function Ut(e){H&&(Be=e,De&&(De.style.display=e?"flex":"none"),q.style.display=e?"none":"flex",k.style.display=e?"none":"inline-flex",W.style.display="inline-flex",le&&(xe(le,e),le.innerHTML=e?Te.wafer:Te.analysis,le.ariaLabel=e?"Back to gallery view":"Insights"),ae(),Ne(),e&&oo().then(t=>{!t||!Be||(t.el.style.display="flex",t.render())}))}H&&p.insights?.defaultOpen&&queueMicrotask(()=>Ut(!0));const io=4,at=240,Xt=480,ao=720,lo=1.25;let pe=Xt;function Zt(e){const t=A*2+110+2;let n=null;for(const o of e){if(o==null||!o.dies?.length)continue;const d=o.dies[0].width;if(!(d>0))continue;const i=o.wafer.radius*2*(io/d),l=Math.ceil(i+t);(n==null||l>n)&&(n=l)}return n}function so(e){const t=Zt(e);return t==null?at:Math.min(pe,Math.max(at,t))}function ro(e){const t=Zt(e);if(t==null)return!1;const n=Math.min(ao,Math.max(Xt,t));return n<=pe?!1:(pe=n,!0)}function lt(){return M!=null?"none":`${pe}px`}function Yt(){const e=lt();for(const t of Array.from(R.children))t.classList.contains("wmap-gallery-card")&&(t.style.maxWidth=e,t.style.maxHeight=e)}let ze=at,Qt=0;function Jt(e){if(ro(e)&&Yt(),M==null){const n=so(e);n>ze&&(ze=n)}rt()}function en(e){M=Bn(e),Yt(),rt()}function st(e){return`repeat(${e}, minmax(0, ${M!=null?"1fr":`${pe}px`}))`}function tn(e){R.style.gridTemplateColumns!==e&&(R.style.gridTemplateColumns=e)}function rt(){if(M!=null){tn(st(M));return}const e=Math.max(1,Qt),t=12,n=R.clientWidth||0,o=i=>(n-t*(i-1))/i;let d=Math.max(1,Math.ceil(Math.sqrt(e)));if(n>0){const i=Math.min(pe,ze*lo),l=s=>{let a=0;for(;a<e&&o(a+1)>=s;)a++;return a};d=l(i)||l(ze)||1}tn(st(d))}const R=u.ownerDocument.createElement("div");if(Object.assign(R.style,{flex:"1 1 0",minWidth:"0",display:"grid",gridTemplateColumns:st(1),gap:w.xl,paddingLeft:oe,paddingRight:oe,justifyContent:"start",alignContent:"start",isolation:"isolate"}),j?.placement){const e=j.placement;h=wt(e,oe,u.ownerDocument),h.style.maxHeight="calc(100vh - 80px)",h.style.position="sticky",h.style.top="8px",h.style.display="flex",h.style.flexDirection="column"}else if(V||Je()){const e=!!j?.defaultOpen;h=wt("right",oe,u.ownerDocument),h.style.maxHeight="calc(100vh - 80px)",h.style.position="sticky",h.style.top="8px",h.style.flexDirection="column",h.style.display=e?"flex":"none",z()}ae(),h?.style.display!=="none"&&P&&xe(P,!0),(j?.placement??"right")==="left"?(h&&q.appendChild(h),q.appendChild(R)):(q.appendChild(R),h&&q.appendChild(h));const ke=u.ownerDocument.createElement("div");Object.assign(ke.style,{position:"sticky",top:"0",display:"flex",flexDirection:"column",paddingLeft:oe,paddingRight:oe,paddingTop:oe,zIndex:"1",background:g.menuBg}),Ve.appendChild(ue),Ve.appendChild(W),ke.appendChild(Ve),ke.appendChild(ee),u.appendChild(ke),u.appendChild(q);function Ne(){ee.innerHTML="";const e=r.plotMode??"hardBin",t=!Be&&un.has(e),n=L.filter(m=>m!=null),o=n.find(m=>m.isLotStack),d=bi(n.map(m=>({metadata:m.wafer.metadata??void 0})),o?{lotSize:o.lotSize??n.length,aggrMethod:o.aggrMethod}:void 0),i=e==="metadata",l=r.activeMetadataKey,s=t&&!i?kn(n,m=>(e==="softBin"?m.sbin:m.hbin)??void 0,On):{counts:new Map,total:0,pass:0},a=t&&!i?r.binColors??ce():void 0,c=a?e==="softBin"?a.pass.soft:a.pass.hard:new Set,f=li(s.counts.entries(),c).map(([m])=>m),b=t&&i&&l?kn(n,m=>vo(m.metadata?.[l])):{counts:new Map,total:0,pass:0},E=i?Pt()?.values:void 0,B=t&&i?(E??[...b.counts.keys()].sort(yt)).filter(m=>b.counts.has(m)):[];if(ue.innerHTML="",d&&ue.appendChild(d),ue.style.display=d?"flex":"none",!f.length&&!B.length){ee.style.display="none";return}ee.style.display="flex";const C=u.ownerDocument.createElement("div");Object.assign(C.style,{display:"flex",flexWrap:"wrap",alignItems:"center",gap:`${w.sm} ${w.xl}`,maxHeight:"86px",overflowY:"auto",overflowX:"hidden"}),ee.appendChild(C);const y=r.highlightBin,I=L.flatMap(m=>m?.metadataFields??[]).find(m=>m.key===l),se=i?I?.label??(l?vi(l):"Metadata"):Wo[e],U=u.ownerDocument.createElement("span");if(U.textContent=se,Object.assign(U.style,{fontSize:T.body,fontWeight:"700",letterSpacing:To,textTransform:"uppercase",color:g.label,flexShrink:"0"}),C.appendChild(U),!i&&s.total>0){const m=s.pass,F=m/s.total*100,te=u.ownerDocument.createElement("span");te.textContent=`Yield ${Ze(F)}`,Object.assign(te.style,{fontSize:T.body,fontWeight:"700",color:g.value,whiteSpace:"nowrap",flexShrink:"0"});const ne=u.ownerDocument.createElement("span");ne.textContent=`${m.toLocaleString()} / ${s.total.toLocaleString()} dies`,Object.assign(ne.style,{fontSize:T.body,color:g.label,whiteSpace:"nowrap",flexShrink:"0"}),C.appendChild(te),C.appendChild(ne)}if(i){const m=r.highlightMetadataValue;B.forEach((F,te)=>{const ne=m===F,Ge=I?.values?.find(gt=>gt.value===F),ho=Ge?.color??Eo(te),dn=b.counts.get(F)??0;En(C,{color:ho,isActive:ne,label:Ge?.label??F,count:dn,percent:b.total>0?dn/b.total*100:void 0,onClick:()=>{const gt=r.highlightMetadataValue===F?void 0:F;O({highlightMetadataValue:gt})}})});return}const ft=e==="softBin"?L.flatMap(m=>m?.sbinDefs??[]):L.flatMap(m=>m?.hbinDefs??[]),ln=new Set,pt=[];for(const m of ft)ln.has(m.bin)||(ln.add(m.bin),pt.push(m));const mt=pt.length>0?new Map(pt.map(m=>[m.bin,m])):null,sn=a??r.binColors??ce(),go=e==="softBin"?sn.soft:sn.hard,rn=m=>go.get(m)??ko;for(const m of f){const F=y===m,te=mt?.get(m),ne=s.counts.get(m)??0;En(C,{color:rn(m),isActive:F,label:te?.name?`${m} \xB7 ${te.name}`:`Bin ${m}`,count:ne,percent:s.total>0?ne/s.total*100:void 0,onClick:()=>{const Ge=r.highlightBin===m?void 0:m;O({highlightBin:Ge})}})}s.total>0&&f.length>1&&ee.appendChild(Di(u.ownerDocument,[...s.counts.entries()].sort(([,m],[,F])=>F-m).map(([m,F])=>({color:rn(m),count:F,label:mt?.get(m)?.name?`${m} \xB7 ${mt.get(m).name}`:`Bin ${m}`})),s.total))}function Ee(e){const t=x.filter(s=>s!==null);if(!t.length)return[];const n=t.map(s=>s.dies.filter(Mi)),o=t[0].wafer,d=t.length,i=o.metadata?{...o,metadata:(({wafer:s,waferId:a,...c})=>c)(o.metadata)}:o;function l(s,a){return{...s,stats:{...s.stats,isLotStack:!0,aggregationMethod:a,lotSize:d}}}if(e==="stackedValues"){const s=ye();let a=s?.filter(bt);if(s!==void 0&&a?.length===0)return[];if(s?.length||(a=bo(t.flatMap(b=>b.dies)).map(b=>({testNumber:b,name:`Test ${b}`}))),!a?.length)return[];const c=r.aggregationMethod??"mean";return a.map(f=>{const b=ri(n,c,f.testNumber),E={testNumber:0,name:f.name,unit:f.unit};return{wafer:i,dies:b,testDefs:[E],label:`${f.name} \xB7 ${c}`,isLotStack:!0,aggrMethod:c,lotSize:d,statsSummary:l(Xe({wafer:i,dies:b,testDefs:[E]},{testNumbers:[0]}),c)}})}if(e==="stackedBins"){let s=Ke(t.map(a=>a?.hbinDefs));return(!s||s.length===0)&&(s=[...new Set(t.flatMap(c=>c.dies.map(f=>f.hbin).filter(f=>f!=null)))].sort((c,f)=>c-f).map(c=>({bin:c,name:`Bin ${c}`}))),s.map(a=>{const c=xn(n,a.bin,"hard"),f=[{bin:a.bin,name:a.name}];return{wafer:i,dies:c,hbinDefs:f,label:`${a.bin} \xB7 ${a.name}`,isLotStack:!0,aggrMethod:"countBin",lotSize:d,statsSummary:l(Xe({wafer:i,dies:c,hbinDefs:f}),"countBin")}})}if(e==="stackedSoftBins"){let s=Ke(t.map(a=>a?.sbinDefs));return(!s||s.length===0)&&(s=[...new Set(t.flatMap(c=>c.dies.map(f=>f.sbin).filter(f=>f!=null)))].sort((c,f)=>c-f).map(c=>({bin:c,name:`Bin ${c}`}))),s.map(a=>{const c=xn(n,a.bin,"soft"),f=[{bin:a.bin,name:a.name}];return{wafer:i,dies:c,sbinDefs:f,label:`${a.bin} \xB7 ${a.name}`,isLotStack:!0,aggrMethod:"countBin",lotSize:d,statsSummary:l(Xe({wafer:i,dies:c,sbinDefs:f}),"countBin")}})}return t}function dt(e){const t=x.length;return e==="stackedBins"||e==="stackedSoftBins"?{valueRange:[0,t],lotSize:t}:e==="stackedValues"?{aggregationMethod:r.aggregationMethod??"mean",valueRange:void 0,lotSize:void 0}:{}}function O(e,{fireCallback:t=!0}={}){const n=Object.keys(e),o=r.plotMode,d=be()!==null;r={...r,...e};const i=r.plotMode,l=ge.has(i),s=o!==void 0&&ge.has(o),a=Ie>0;if("binColorScheme"in e||"useDefinedBinColors"in e){const f=ce();r={...r,binColors:f},e={...e,binColors:f}}if(e.plotMode!==void 0)if(l){const f=dt(i);if(r={...r,...f},a)for(const b of S)b&&b.setOptions(e);else Z(Ee(i))}else if(s){const{valueRange:f,lotSize:b,aggregationMethod:E,...B}=r;if(r=B,a)for(const C of S)C&&C.setOptions(e);else Z(x.filter(C=>C!==null))}else for(const f of S)f&&f.setOptions(e);else if(e.aggregationMethod!==void 0&&i==="stackedValues")if(a)for(const f of S)f&&f.setOptions(e);else Z(Ee("stackedValues"));else for(const f of S)f&&f.setOptions(e);be()!==null!==d&&Ct(),Ne(),zt(),jt(),It();const c=e.plotMode!==void 0&&e.plotMode!==o;(ui.some(f=>f in e)||c)&&z(),Me(),Nt(),_t(),ot(),nt(),t&&p.onViewOptionsChange?.(Cn(r),n,ci(n))}function nn(e,t,n){const o=e.createElement("div");Object.assign(o.style,{display:"flex",alignItems:"center",gap:w.xs,flex:"1",minWidth:"0"});const d=e.createElement("span");d.textContent=t,Object.assign(d.style,{fontWeight:"700",fontSize:T.sub,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}),o.appendChild(d);const i=Dn(n??{});let l=null;if(i.length>0){const s=e.createElement("span");Object.assign(s.style,{fontSize:T.body,lineHeight:qe.none,color:g.label,flexShrink:"0"}),s.textContent="\u25BE",o.appendChild(s),Object.assign(o.style,{cursor:"pointer",borderRadius:N.control}),o.addEventListener("mouseenter",()=>{o.style.background=g.bgHover}),o.addEventListener("mouseleave",()=>{o.style.background="none"}),l=e.createElement("div"),l.dataset.wmapCardMetaPanel="1",Object.assign(l.style,{position:"absolute",top:"0",left:"0",right:"0",zIndex:fn,background:g.menuBg,borderBottom:`1px solid ${g.menuBorder}`,boxShadow:Le.menu,padding:`${w.md} ${w.lg}`,fontSize:T.body,display:"none"});const a=Mn(n??{});a&&l.appendChild(a),o.setAttribute("aria-expanded","false"),o.setAttribute("aria-label",`Wafer info for ${t||"this card"}. Click to expand.`),bn(o,c=>{s.textContent=c?"\u25B4":"\u25BE",o.setAttribute("aria-expanded",String(c)),l&&(l.style.display=c?"block":"none")})}return{wrap:o,metaPanel:l}}function on(e,t,n){const o=e.box.querySelector("[data-wmap-window-title]"),d=Dn(n??{});if(!o||d.length===0)return;const i=o.parentElement,l=u.ownerDocument.createElement("div");Object.assign(l.style,{display:"flex",alignItems:"center",gap:w.xs,flex:"1",minWidth:"0",cursor:"pointer"}),ht(l,"bare"),i?.insertBefore(l,o),l.appendChild(o);const s=u.ownerDocument.createElement("span");Object.assign(s.style,{fontSize:T.body,lineHeight:qe.none,color:g.label,flexShrink:"0"}),s.textContent="\u25BE",l.appendChild(s);const a=u.ownerDocument.createElement("div");a.dataset.wmapCardMetaPanel="1",Object.assign(a.style,{position:"absolute",top:"0",left:"0",right:"0",zIndex:fn,background:g.menuBg,borderBottom:`1px solid ${g.menuBorder}`,boxShadow:Le.menu,padding:`${w.md} ${w.lg}`,fontSize:T.body,display:"none"});const c=Mn(n??{});c&&a.appendChild(c),e.contentWrap.style.position="relative",e.contentWrap.appendChild(a),l.setAttribute("aria-expanded","false"),l.setAttribute("aria-label",`Wafer info for ${t}. Click to expand.`),bn(l,f=>{s.textContent=f?"\u25B4":"\u25BE",l.setAttribute("aria-expanded",String(f)),a.style.display=f?"block":"none"})}function ct(e,t,n){const o=u.ownerDocument.createElement("div");o.className="wmap-gallery-card",Object.assign(o.style,{background:g.menuBg,border:`1px solid ${g.menuBorder}`,borderRadius:N.container,boxShadow:Le.panel,overflow:"hidden",display:"flex",flexDirection:"column",position:"relative",aspectRatio:"1",maxWidth:lt(),maxHeight:lt()});const d=u.ownerDocument.createElement("div");Object.assign(d.style,{display:"flex",alignItems:"center",padding:`${w.md} ${w.lg} ${w.sm}`,borderBottom:`1px solid ${g.menuBorder}`,flexShrink:"0",gap:w.sm});const{wrap:i,metaPanel:l}=nn(document,Ue(e,t),e.wafer.metadata??void 0);d.appendChild(i);const s=u.ownerDocument.createElement("button");s.dataset.wmapExpandBtn="1",s.setAttribute("aria-label","Open full view"),yn(s),s.innerHTML=Te.expand,Object.assign(s.style,{display:"flex",alignItems:"center",justifyContent:"center",border:`1px solid ${g.menuBorder}`,borderRadius:N.control,background:g.panelBg,color:g.label,padding:w.xxs,cursor:"pointer",flexShrink:"0",width:"22px",height:"22px"}),ht(s),d.appendChild(s),o.appendChild(d);const a=u.ownerDocument.createElement("div");Object.assign(a.style,{position:"relative",flex:"1",minHeight:"0",overflow:"hidden",display:"flex",flexDirection:"column"}),o.appendChild(a),l&&a.appendChild(l),R.appendChild(o);const c=We||be()!==null,f=e.viewOptions?{...r,...e.viewOptions}:r,b=vn(a,e,{viewOptions:{...f,showLegend:c,legendPosition:he},showTooltip:!0,padding:A,statsSummary:e.statsSummary,onSaveImage:p.onSaveImage,onSaveText:p.onSaveText,onClick:e.onClick,onSelect:e.onSelect,onExpand:()=>Oe(t,e),showIdentity:!1,chromeInset:$o});return b.setViewControlsVisible(!1),b.setSummaryVisible(!1),s.onclick=()=>Oe(t,e),{card:o,ctrl:b,canvasWrapper:a,expandBtn:s}}function co(e){const t=re[e];if(!t)return;const n=[..._.values()].find(o=>o.cardIndex===e);n?(t.innerHTML=Te.minimize,t.setAttribute("aria-label","Reattach to gallery"),t.onclick=()=>fo(n.id)):(t.innerHTML=Te.expand,t.setAttribute("aria-label","Open full view"),t.onclick=()=>Oe(e,L[e]))}function Z(e){po(),ve()?.remove(),Ce(null),tt(),L=[];for(const i of S)i&&i.destroy();S=[],ie=[],re=[],Ie=0,R.innerHTML="",Qt=e.length,Jt(e.map(i=>typeof i=="function"?null:i));const t=[];for(let i=0;i<e.length;i++){const l=e[i];if(typeof l=="function"){const s=u.ownerDocument.createElement("div");s.className="wmap-gallery-card",Object.assign(s.style,{background:g.menuBg,border:`1px solid ${g.menuBorder}`,borderRadius:N.container,aspectRatio:"1",display:"flex",alignItems:"center",justifyContent:"center"});const a=u.ownerDocument.createElement("span");a.textContent="\u2026",Object.assign(a.style,{color:g.label,fontSize:"18px"}),s.appendChild(a),R.appendChild(s),L.push(null),S.push(null),ie.push(null),re.push(null),t.push({index:i,factory:l,placeholder:s}),Ie++}else{const{ctrl:s,canvasWrapper:a,expandBtn:c}=ct(l,i,e.length);L.push(l),S.push(s),ie.push(a),re.push(c)}}Ht(),Ne(),ot(),nt();const n=++Qe;let o=0;function d(){if(n!==Qe)return;if(o>=t.length){if(ge.has(r.plotMode)){const B=r.plotMode;Z(Ee(B))}return}const{index:i,factory:l,placeholder:s}=t[o++],a=l();L[i]=a,x[i]=a,Jt([a]);const{card:c,ctrl:f,canvasWrapper:b,expandBtn:E}=ct(a,i,e.length);S[i]=f,ie[i]=b,re[i]=E,Ie--,s.replaceWith(c),Ne(),Un(),!h&&!j?.placement&&a.statsSummary?.findings.length?(h=wt("right",oe,u.ownerDocument),h.style.maxHeight="calc(100vh - 80px)",h.style.position="sticky",h.style.top="8px",h.style.flexDirection="column",h.style.display="none",(j?.placement??"right")==="left"?q.insertBefore(h,R):q.appendChild(h),z(),P||(P=Q("findings","Summary panel",()=>{if(!h)return;const C=h.style.display!=="none";C||z(),h.style.display=C?"none":"flex",xe(P,!C),ae()}),W.appendChild(G()),W.appendChild(P)),ae()):h&&h.style.display!=="none"&&z(),ae(),setTimeout(d,0)}t.length>0&&setTimeout(d,0)}if(ge.has(r.plotMode)&&x.length>0){const e=dt(r.plotMode);r={...r,...e},Z(Ee(r.plotMode))}else Z(v);Me();let me=0;const an=new(u.ownerDocument.defaultView??window).ResizeObserver(()=>{if(me)return;me=(u.ownerDocument.defaultView??window).requestAnimationFrame(()=>{me=0,M==null&&rt()})});an.observe(R),h&&z();function uo(e,t){const n=ie[e];if(!n)return;n.innerHTML="",Object.assign(n.style,{alignItems:"center",justifyContent:"center"});const o=u.ownerDocument.createElement("span");o.textContent=t?"Opened in its own window":"Opened in the wafer viewer",Object.assign(o.style,{color:g.label,fontSize:T.body,textAlign:"center",padding:"0 12px"}),n.appendChild(o)}function Oe(e,t){for(const l of _.values())if(l.cardIndex===e)return;const n=Ue(t,e),o=Ln++,d=S[e]?.getOptions(),i=Fo(n);if(i){const l=i.document;l.title=n,Object.assign(l.documentElement.style,{height:"100%"}),Object.assign(l.body.style,{margin:"0",height:"100vh",overflow:"hidden",display:"flex",flexDirection:"column",fontFamily:T.family}),zo(u,l.documentElement);const s=No(u,l.documentElement,()=>C.setOptions({})),a=l.createElement("div");a.dataset.wmapWindowBanner="1",a.textContent=n,Object.assign(a.style,{display:"none",padding:`${w.sm} ${w.xl}`,fontSize:T.body,fontWeight:"700",background:g.warnBg,color:g.warnText,borderBottom:`1px solid ${g.warnBorder}`,flexShrink:"0"}),l.body.appendChild(a);const c=l.createElement("div");Object.assign(c.style,{flex:"1",minHeight:"0",display:"flex",flexDirection:"column"}),l.body.appendChild(c);const{wrap:f,metaPanel:b}=nn(l,n,t.wafer.metadata??void 0),E=l.createElement("div");Object.assign(E.style,{display:"flex",alignItems:"center",padding:`${w.md} ${w.lg} ${w.sm}`,borderBottom:`1px solid ${g.menuBorder}`,flexShrink:"0",gap:w.sm}),E.appendChild(f),c.appendChild(E);const B=l.createElement("div");Object.assign(B.style,{position:"relative",flex:"1",minHeight:"0",overflow:"hidden",display:"flex",flexDirection:"column"}),b&&B.appendChild(b),c.appendChild(B);const C=ut(B,t,void 0,d),y=setInterval(()=>{i.closed&&_e(o)},400);i.addEventListener("pagehide",()=>_e(o)),_.set(o,{id:o,ctrl:C,cardIndex:e,label:n,closePollId:y,stopThemeSync:s,close:()=>{i.closed||i.close()},setTitle:I=>{l.title=I,a.textContent=I,a.style.display="block"}})}else{const l=Ho({title:n,onClose:()=>_e(o),anchor:u});l.contentWrap.style.flexDirection="column",on(l,n,t.wafer.metadata??void 0);const s=ut(l.contentWrap,t,void 0,d);_.set(o,{id:o,ctrl:s,cardIndex:e,label:n,closePollId:null,close:()=>l.close(),setTitle:a=>{const c=l.box.querySelector("[data-wmap-window-title]");c&&(c.textContent=a,c.title=a)}})}S[e]?.destroy(),S[e]=null,uo(e,i!==null),co(e)}function ut(e,t,n,o){const d=t.viewOptions?{...r,...t.viewOptions}:r,i=o?{...d,...o}:d,s={...n!==void 0?{...i,plotMode:"value",activeTest:n}:i,showLegend:!0,legendPosition:he},a=vn(e,t,{viewOptions:s,showTooltip:!0,padding:A,statsSummary:t.statsSummary,onSaveImage:p.onSaveImage,onSaveText:p.onSaveText,onClick:t.onClick,onSelect:t.onSelect,showExpandButton:!1,showIdentity:!1});return a.setViewControlsVisible(!0),a.setSummaryVisible(!0),a.setExpandVisible(!1),a}function _e(e){const t=_.get(e);if(!t||(_.delete(e),t.closePollId!=null&&clearInterval(t.closePollId),t.stopThemeSync?.(),t.ctrl.destroy(),t.cardIndex===null))return;const n=t.cardIndex,o=L[n];if(!o)return;const{card:d,ctrl:i,canvasWrapper:l,expandBtn:s}=ct(o,n,L.length);ie[n]?.parentElement?.replaceWith(d),S[n]=i,ie[n]=l,re[n]=s}function fo(e){const t=_.get(e);t&&(t.close(),_e(e))}function po(){for(const e of _.values())e.cardIndex!==null&&(e.cardIndex=null,e.setTitle(`${e.label} \u2014 unlinked from gallery`))}function mo(){const e=[...R.querySelectorAll("canvas")];if(!e.length)return;const t=e.length,n=Math.ceil(Math.sqrt(t)),o=Math.ceil(t/n),d=e[0].width,i=e[0].height,l=8,s=(u.ownerDocument.defaultView??window).devicePixelRatio||1,a=Math.round(26*s),c=Math.round(12*s),f=u.ownerDocument.createElement("canvas");f.width=n*d+(n-1)*l,f.height=o*(i+a)+(o-1)*l;const b=f.getContext("2d"),E=Oo(R);b.fillStyle=E.background,b.fillRect(0,0,f.width,f.height),e.forEach((B,C)=>{const y=C%n,I=Math.floor(C/n),se=y*(d+l),U=I*(i+a+l),ft=B.closest(".wmap-gallery-card")?.querySelector("span")?.textContent??"";b.fillStyle=E.surface,b.fillRect(se,U,d,a),b.fillStyle=E.text,b.font=`700 ${c}px system-ui, sans-serif`,b.textAlign="left",b.textBaseline="middle",b.fillText(ft,se+Math.round(10*s),U+a/2,d-Math.round(20*s)),b.drawImage(B,se,U+a)}),f.toBlob(B=>{if(!B)return;if(p.downloadFilename!=null){gn(B,p.downloadFilename,p.onSaveImage);return}const C=S.find(y=>y!=null)?.getExportTitle();gn(B,["gallery",C].filter(Boolean).join(" "),Re.onSaveImage)})}return{setItems(e){x=e.map(n=>typeof n=="function"?null:n);const t=r.plotMode;if(ge.has(t))if(e.some(o=>typeof o=="function"))Z(e);else{const o=dt(t);r={...r,...o},Z(Ee(t))}else Z(e)},setOptions(e){O(e,{fireCallback:!1})},getOptions(){return Cn(r)},setFindingsNotice(e){Et=e,z()},setColumns(e){en(e)},getBinColors(){return r.binColors??ce()},setLotStatsSummary(e){V=e,Me(),h&&z(),ae()},openUserGuide:Kt,destroy(){Qe++;for(const e of[..._.values()])e.closePollId!=null&&clearInterval(e.closePollId),e.close(),e.ctrl.destroy();_.clear();for(const e of S)e&&e.destroy();S=[],ve()?.remove(),an.disconnect(),me&&((u.ownerDocument.defaultView??window).cancelAnimationFrame(me),me=0),u.ownerDocument.removeEventListener("click",Ae,!0),window.removeEventListener("blur",kt),Y(),pn(),ke.remove(),q.remove(),h?.remove(),fe?.destroy()}}}
|
|
1
|
+
import{getUniqueTestNumbers as Do,resolveTestNumber as ko,findTestDef as Eo,collectMetadataValues as Bo}from"../renderer/buildView.js";import{metadataCategoricalValue as Oo}from"../core/metadata.js";import{resolveBinColorsForMaps as To,mergeBinDefs as Ye,binColorWarning as Lo,mixedPassBinsWarning as Ro,binColorsEqual as Io}from"../renderer/binColors.js";import{itemPassBins as Wo,INPUT_DEFAULT_PASS_BINS as $o}from"../core/passBins.js";import{NO_DATA_FILL as Ao}from"../renderer/colorMap.js";import{metadataValueColor as Po}from"../renderer/colorMap.js";import{resolveCanvasTheme as Fo}from"./canvasTheme.js";import{ICONS as We}from"./icons.js";import{SHADOW as $e,LEADING as Ze,TRACKING as Ho,controlStyle as jo,wireControlHover as xt,SPACE as w,EDGE_GUTTER as oe,MAP_CHROME_INSET as Vo,RADIUS as z,FONT as L,CLR as h,sevColor as gn,MODE_LABELS as No,BIN_LEGEND_MODES as hn,STACKED_MODES as be,Z_ABOVE as bn,applyOverlayZ as zo,getTooltip as _o,hideTooltip as yn,createToolbarHelpers as Go,buildModeMenuEl as Ko,openDetachWindow as qo,openFloatingWindow as Uo,openModal as Xo,openReportModal as Yo,copyWmapThemeTokens as Zo,syncWmapPopupTheme as Qo,openUserGuideWindow as Jo,makePaletteBtn as ei,makeLogScaleBtn as ti,makeLegendStyleBtn as ni,makeOverlaysBtn as oi,makeOrientationBtn as ii,menuLayerFor as wn,saveImageBlob as vn,markMenuTrigger as Ae,wireMenuA11y as xn,wireExpandToggle as Cn,wireTooltip as Sn,requestedPassFailDisplay as Mn,overlayMenuRows as ai,anyOverlayActive as li,logWmapVersionOnce as si,buildDataModeEntries as ri,metadataKeyHasData as di,metadataModeEntry as ci}from"./toolbar.js";import{waferDisplayLabel as Qe,waferIdentityLabel as Dn}from"../core/waferLabel.js";import{metadataDisplayValue as ui}from"../core/metadata.js";import{withExportContext as fi,noticeDownloadFilenameChange as pi}from"./exportName.js";import{sortBinsForDisplay as mi}from"../stats/binPareto.js";import{diePassStatus as gi}from"../core/dies.js";import{aggregateValues as hi,aggregateBinCounts as kn}from"../core/aggregates.js";import{renderWaferMap as bi,renderWaferMapCard as En,toPublicViewOptions as Bn}from"./renderWaferMap.js";import{hasDrilldownTargets as yi,waferPopulation as wi}from"./chartPopulation.js";import{classifyChanged as vi,COLOR_KEYS as xi}from"./renderWaferMap.js";import{buildWaferMap as Ci,getTestPassStatus as On,isParametricTest as Ct,getDieTestValue as Si}from"../renderer/buildWaferMap.js";import{analyzeWaferMap as Je}from"../stats/analyzeWaferMap.js";import{collectWarnings as Mi,buildWarningsMenuEl as Di,severityOf as ki}from"./warnings.js";import{compareNatural as St,arrayEqual as Tn}from"../core/utils.js";import{createSummaryPanelEl as Mt,buildMetadataStripRow as Ei,buildCompactMetadataRows as Ln,metadataEntries as Rn,renderLotSummaryContentSteps as Bi,reportMapsFromItems as Oi}from"./summaryPanel.js";import{renderLotReportHtml as Ti}from"../stats/renderSummaryReport.js";import{prettyKey as Li}from"../stats/facets.js";import{testLabel as Ri,markedTestLabel as Ii,derivedFields as Wi}from"../renderer/testLabel.js";import{mergeTestDefs as $i}from"../stats/mergeTestDefs.js";import{getDieKey as Ai,hasPosition as Pi}from"../core/dies.js";import{runChunked as Fi}from"./chunked.js";function In(f){if(typeof f!="number"||!Number.isFinite(f))return;const C=Math.round(f);return C>=1?C:void 0}const Dt=12;function Hi(f,C,p){let A=C;if(C.length>Dt){const E=C.slice(0,Dt-1),I=C.slice(Dt-1),H=I.reduce((X,ie)=>X+ie.count,0);A=[...E,{color:h.label,count:H,label:`Other (${I.length} bins)`}]}const k=f.createElement("div");Object.assign(k.style,{display:"flex",columnGap:"1px",width:"100%",height:"8px",borderRadius:z.control,overflow:"hidden",border:`1px solid ${h.menuBorder}`,boxSizing:"border-box",marginTop:w.xs,flexShrink:"0"}),k.setAttribute("role","img"),k.setAttribute("aria-label",`Population split: ${A.map(E=>`${E.label} ${et(E.count/p*100)}`).join(", ")}`);for(const E of A){const I=E.count/p*100,H=f.createElement("div");Object.assign(H.style,{flex:`${I} 1 0`,minWidth:I>0?"2px":"0",background:E.color}),Sn(H,`${E.label} \xB7 ${E.count.toLocaleString()} dies \xB7 ${et(I)}`),k.appendChild(H)}return k}function et(f){return f>0&&f<.1?"<0.1%":`${f.toFixed(1)}%`}function Wn(f,C,p){const A=new Map;let k=0,E=0;for(const I of f){const H=p?new Set(p(I)):void 0;for(const X of I.dies){if(X.partial||X.edgeExcluded)continue;const ie=C(X);ie!==void 0&&(A.set(ie,(A.get(ie)??0)+1),k++,H&&gi(X,H)&&E++)}}return{counts:A,total:k,pass:E}}function $n(f,C){const p=f.ownerDocument.createElement("div");Object.assign(p.style,{display:"flex",alignItems:"center",gap:"5px",cursor:"pointer",userSelect:"none",padding:`${w.xxs} ${w.xs}`,borderRadius:z.control});const A=f.ownerDocument.createElement("span");Object.assign(A.style,{display:"inline-block",width:"13px",height:"13px",flexShrink:"0",background:C.color,border:C.isActive?`2px solid ${h.iconActive}`:`1px solid ${h.menuBorder}`,borderRadius:z.control,boxSizing:"border-box"});const k=f.ownerDocument.createElement("span");if(k.textContent=C.label,Object.assign(k.style,{fontWeight:C.isActive?"700":"400",color:C.isActive?h.iconActive:h.text,whiteSpace:"nowrap"}),p.appendChild(A),p.appendChild(k),C.count!==void 0){const E=f.ownerDocument.createElement("span");if(E.textContent=C.count.toLocaleString(),Object.assign(E.style,{color:C.isActive?h.iconActive:h.text,fontWeight:C.isActive?"700":"400",whiteSpace:"nowrap"}),p.appendChild(E),C.percent!==void 0){const I=f.ownerDocument.createElement("span");I.textContent=et(C.percent),Object.assign(I.style,{color:h.label,whiteSpace:"nowrap"}),p.appendChild(I)}}p.setAttribute("role","button"),p.setAttribute("aria-pressed",C.isActive?"true":"false"),p.tabIndex=0,p.addEventListener("mouseenter",()=>{p.style.background=h.bgHover}),p.addEventListener("mouseleave",()=>{p.style.background="transparent"}),p.addEventListener("focus",()=>{p.style.background=h.bgHover}),p.addEventListener("blur",()=>{p.style.background="transparent"}),p.addEventListener("click",C.onClick),p.addEventListener("keydown",E=>{(E.key==="Enter"||E.key===" ")&&(E.preventDefault(),C.onClick())}),f.appendChild(p)}export function renderWaferGallery(f,C,p={}){si();const A=6;let k=In(p.columns);const E=p.showHelpButton??!1,I=p.userGuideExtension,H=p.insights?.enabled??!1,X=p.insights?.sweeps?{sweeps:p.insights.sweeps}:void 0,ie=zo(p.zIndex),re=p.summaryPanel,An=e=>[...Wo(e)],kt=()=>v.flatMap(e=>e?[e.ringCount??4]:[]),tt=()=>kt()[0]??4;function Pn(e){const t=[...new Set(e)].sort((n,o)=>n-o);return t.length<2?null:{code:"ring-count-mixed",severity:"warning",message:`These wafers were built with different ring counts (${t.join(", ")}). Each card and each wafer's findings use their own; the lot's ring yield in the Summary panel, report and Insights uses ${e[0]} rings.`}}let V=p.lotStatsSummary,ye=p.viewOptions?.legendPosition??"default",Pe=p.perCardLegend??!1;function we(){const e=c.plotMode??"hardBin";return hn.has(e)?null:c.colorbarRangeMode==="data"?"Each map has its own value range, so it keeps its own colour bar":"These wafers have no shared colour bar for value mode, so each map keeps its own"}function Et(){const e=Pe||we()!==null;for(const t of S)t&&t.setOptions({showLegend:e})}let c={plotMode:"hardBin",showDieLabels:!1,showRingBoundaries:!1,showQuadrantBoundaries:!1,rotation:0,flipX:!1,flipY:!1,...p.viewOptions},S=[],ae=[],de=[],R=[];const Fe=fi(()=>{const e=R.filter(n=>n!=null);return{lots:[...new Set(e.map(n=>ui(n.wafer.metadata?.lot)).filter(n=>n!==void 0))].sort(St),...e.length===1?{wafer:Dn(e[0])}:{waferCount:e.length}}},p.onSaveImage,p.onSaveText);pi(p.downloadFilename);let v=C.map(e=>typeof e=="function"?null:e);function Bt(){return $i(v)}function ve(){if(v.some(e=>e?.testDefs?.length))return Bt().defs}let xe=0,He=0;const _=new Map;let Fn=0,P=null,Ce=null,Ot=new Set,b=null,Hn={};function Tt(e){return v[e]?.statsSummary??V?.perWafer.find(t=>t.waferIndex===e)?.summary}function nt(){return!!(v.some(e=>e?.statsSummary?.findings.length)||V?.perWafer.some(e=>e.summary.findings.length))}const jn=_o(),ce=Go(jn),{makeBtn:Q,setActive:Se,makeSep:G,makeMenuRow:Vn,makeMenuSection:Nn,makeDropdown:Lt,closeOpenMenu:je,getOpenMenu:Me,setOpenMenu:De}=ce;f.ownerDocument.addEventListener("click",je,!0);const Rt=()=>yn();window.addEventListener("blur",Rt);let It=p.findingsNotice;function Wt(e){Ot=new Set(e);const t=[...$.querySelectorAll(".wmap-gallery-card")];let n;t.forEach((o,d)=>{const l=Ot.has(d);o.style.outline=l?`3px solid ${h.findingHighlight}`:"",o.style.outlineOffset=l?"-3px":"",l&&n===void 0&&(n=o)}),n?.scrollIntoView?.({behavior:"smooth",block:"nearest"})}function $t(){Wt([])}function At(){for(const e of S)e&&e.clearSelection()}function ot(e,t){const n=new Set(e),o=t??S.map((d,l)=>l);for(const d of o){const l=R[d],a=S[d];if(!l||!a)continue;const r=l.dies.filter(i=>n.has(Ai(i)));a.setSelection(r)}}function zn(){const e=[];for(let t=0;t<v.length;t++){const n=v[t];if(!n)continue;const o=Tt(t)?.findings??[];o.length&&e.push({index:t,item:n,unusualCount:o.filter(d=>d.severity==="unusual").length,notableCount:o.filter(d=>d.severity==="notable").length,totalCount:o.length})}return e}function _n(e){const t=R[e]??v[e];t&&Ie(e,t)}function Gn(e){const t=Tt(e)?.findings??[];if(t.length)return{total:t.length,unusual:t.filter(n=>n.severity==="unusual").length,notable:t.filter(n=>n.severity==="notable").length}}function Kn(){Yo(Ti(Oi(v,$o,tt())),{anchor:f})}function qn(){if(!b)return;b.innerHTML="";const e=zn();if(v.length>0){const n=f.ownerDocument.createElement("div"),o=e.length,d=v.filter(Boolean).length;n.textContent=o===0?`No findings on any of the ${d} wafers`:`${o} of ${d} wafer${d===1?"":"s"} with findings`,Object.assign(n.style,{fontSize:L.body,color:h.label,marginBottom:w.md}),b.appendChild(n)}if(e.length>0){const n=f.ownerDocument.createElement("button");n.type="button",n.textContent="Summary report",Object.assign(n.style,{...jo("outlined"),marginBottom:w.lg,display:"block",width:"100%",textAlign:"left"}),xt(n),n.addEventListener("click",Kn),b.appendChild(n)}if(e.length===0){const n=f.ownerDocument.createElement("div");Object.assign(n.style,{color:h.icon,fontSize:L.body,padding:"4px 0"}),n.textContent="No findings on any wafer.",b.appendChild(n)}else for(const{index:n,item:o,unusualCount:d,notableCount:l,totalCount:a}of e){const r=d?"unusual":l?"notable":"info",i=d+l||a,s=f.ownerDocument.createElement("button");s.type="button",Object.assign(s.style,{display:"flex",alignItems:"center",justifyContent:"space-between",width:"100%",padding:"5px 8px",marginBottom:w.xs,border:"none",borderLeft:`3px solid ${gn(r)}`,borderRadius:z.control,background:h.bgHover,cursor:"pointer",fontSize:L.body,textAlign:"left",boxSizing:"border-box"}),s.addEventListener("mouseover",()=>{s.style.background=h.bgActive}),s.addEventListener("mouseout",()=>{s.style.background=h.bgHover});const u=f.ownerDocument.createElement("span");u.textContent=Qe(o,n),Object.assign(u.style,{color:h.iconHover,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"});const m=f.ownerDocument.createElement("span");m.textContent=String(i),s.setAttribute("aria-label",`${Qe(o,n)} \u2014 ${i} finding${i===1?"":"s"}${d?`, ${d} unusual`:""} \u2014 view wafer`),Object.assign(m.style,{marginLeft:w.sm,flexShrink:"0",background:gn(r),color:"#fff",borderRadius:z.container,padding:"1px 5px",fontSize:L.body,fontWeight:"600"}),s.appendChild(u),s.appendChild(m),s.addEventListener("click",()=>Ie(n,o)),b.appendChild(s)}const t=f.ownerDocument.createElement("div");t.style.height="12px",b.appendChild(t)}let ue=null,ke=null;function N(){if(b)if(ue?.cancel(),ue=null,V){const e=Ye(v.map(n=>n?.hbinDefs)),t=Ye(v.map(n=>n?.sbinDefs));ue=Fi(Bi(b,{lotSummary:V,items:v,hbinDefs:e.length?e:void 0,sbinDefs:t.length?t:void 0,testDefs:ve(),ringCount:tt(),binColors:c.binColors,plotMode:c.plotMode??"hardBin",fallbackFormat:c.fallbackFormat,activeFindingId:Ce,warnings:p.warnings?.display??!0?J:[],findingsFilter:Hn,findingsNotice:It,onFindingsFilterChange:N,onSaveText:Fe.onSaveText,onFindingClick:(n,o)=>{Ce===n.id?it():Xn(n,o),N()},onWaferClick:_n,findingsFor:Gn,dieListOptions:p.dieList}),{onDone:()=>{const n=ke;ke=null,n?.()}})}else qn()}function Un(e){const t=e.highlight;return t?.kind==="wafer"&&t.waferIndices?.length?t.waferIndices:null}function Pt(e){return[e.variable.kind,e.variable.index??"",e.variable.bin??"",e.comparison.family,e.comparison.left,e.effect.direction].join("|")}let Ve=[];function Ft(){if(Ve.length!==0){for(const e of Ve)S[e]?.setOptions({plotMode:c.plotMode,activeTest:c.activeTest});Ve=[]}}function it(){Ce=null,$t(),At(),Ft(),T({highlightBin:void 0},{fireCallback:!1})}function Xn(e,t){if(Ce===e.id){it();return}Ce=e.id,t.style.background=h.bgActive,t.style.fontWeight="600",Ft();const{kind:n,index:o}=e.variable;if(n==="test"){const l=o??0,a=ve();if(a===void 0||a.some(i=>i.testNumber===l))T({plotMode:"value",activeTest:l,highlightBin:void 0},{fireCallback:!1});else{T({highlightBin:void 0},{fireCallback:!1});const s=be.has(c.plotMode??"hardBin")?null:Un(e);if(s){for(const u of s)S[u]?.setOptions({plotMode:"value",activeTest:l});Ve=[...s]}}}else n==="softBin"?T({plotMode:"softBin",highlightBin:void 0},{fireCallback:!1}):T({plotMode:"hardBin",highlightBin:void 0},{fireCallback:!1});$t(),At();const d=e.highlight;if(d.kind==="wafer"){Wt(d.waferIndices);const l=Pt(e);for(const a of d.waferIndices){const s=R[a]?.statsSummary?.findings.find(u=>Pt(u)===l)?.highlight?.dieKeys;s?.length&&ot(s,[a])}}else d.kind==="bin"?d.dieKeys?.length&&ot(d.dieKeys):(d.kind==="region"||d.kind==="dies")&&d.dieKeys?.length&&ot(d.dieKeys)}function le(){if(!P)return;const e=!!b;P.style.display=(V||nt())&&e&&!Te?"flex":"none";const t=b?b.style.display!=="none":!1;(V?.hasNotableFindings||v.some(o=>o?.statsSummary?.hasNotableFindings))&&!t?P.style.color=h.findingIndicator:P.dataset.active||(P.style.color=h.icon)}const W=f.ownerDocument.createElement("div");W.dataset.wmapToolbar="gallery",Object.assign(W.style,{flexShrink:"0",marginLeft:"auto",display:"inline-flex",flexDirection:"row",alignItems:"center",gap:"0",background:h.menuBg,border:`1px solid ${h.menuBorder}`,borderRadius:z.control,padding:"0",boxShadow:$e.panel,flexWrap:"wrap",minWidth:"0",overflowX:"auto"});const Ht=()=>{const e=Me();e&&(e.remove(),De(null)),Ae(Y,!1)},Y=Q("mode","Plot mode",()=>{if(Me()){Ht();return}const e=v.flatMap(y=>y?.dies??[]),t=ve(),{testEntries:n,binEntries:o,stackedEntries:d}=ri(e,t,{includeStacked:!0}),l=v.filter(Boolean).length,a=y=>{if(y===void 0)return l;let B=0;for(const j of v)j?.dies?.some(U=>On(U,y)!==void 0||U.testValues?.[y]!==void 0)&&B++;return B},r=l<2?n:n.map(y=>{const B=a(y.activeTest);return B===l?y:{...y,label:`${y.label} \u2014 ${B} of ${l} wafers`}}),i=c.plotMode??"hardBin",s=c.activeTest??0;function u(y){return y.plotMode!==i?!1:y.plotMode==="value"?s===(y.activeTest??0):y.plotMode==="metadata"?c.activeMetadataKey===y.activeMetadataKey:!0}function m(y,B){y.activeTest!==void 0?T({plotMode:"value",activeTest:y.activeTest,activeMetadataKey:void 0,logScale:y.logScale}):y.activeMetadataKey!==void 0?T({plotMode:y.plotMode,activeTest:void 0,activeMetadataKey:y.activeMetadataKey,passFailDisplay:"off"}):T({plotMode:y.plotMode,activeTest:void 0,activeMetadataKey:void 0,passFailDisplay:"off"}),B.remove(),De(null),Ae(Y,!1)}const M=new Set,D=v.flatMap(y=>y?.metadataFields??[]).filter(y=>!M.has(y.key)&&M.add(y.key)).filter(y=>di(e,y.key)).map(ci),x=Ko(Y.getBoundingClientRect(),r,o,d,u,m,{makeMenuRow:Vn,makeMenuSection:Nn},i,Y.ownerDocument.defaultView??window,D);wn(Y).appendChild(x),De(x),Ae(Y,!0),xn(x,Y,Ht)});Ae(Y,!1);const Yn=()=>R.flatMap(e=>e?[...e.hbinDefs??[],...e.sbinDefs??[]]:[]).some(e=>e.color),{btn:Zn,sync:jt}=ei(ce,()=>({...c,plotMode:c.plotMode??"hardBin"}),Yn,e=>T(e));jt();const Qn=C.some(e=>typeof e!="function"&&(e.reticles?.length??0)>0);function Ne(){const e=ve(),{testNumber:t}=ko(c.activeTest??0,e);return{testNumber:t,td:Eo(e,t)}}function Vt(){if((c.plotMode??"hardBin")!=="value")return!1;const{td:e}=Ne();return e!==void 0&&(e.limitLow!==void 0||e.limitHigh!==void 0)}function Ee(){if((c.plotMode??"hardBin")!=="value")return!1;const{td:e}=Ne();return e!==void 0&&!Ct(e)}function Jn(){if((c.plotMode??"hardBin")!=="value")return!1;const{testNumber:e,td:t}=Ne();return v.some(n=>n?.dies?.some(o=>On(o,e,t)!==void 0))}function eo(e,t){if(!t||!Ct(t))return;const n=t.limitLow!==void 0||t.limitHigh!==void 0;if((Mn(c)==="spec"&&n?"spec":c.colorbarRangeMode??"spec")==="spec"&&n)return;let l=1/0,a=-1/0;for(const r of v)if(r)for(const i of r.dies){const s=Si(i,e);s!==void 0&&(s<l&&(l=s),s>a&&(a=s))}if(isFinite(l))return l===a?[l,l+1]:[l,a]}function at(e,t,n){const o=c[e];if(o===t||o!=null&&t!=null&&n(o,t))return!1;c={...c,[e]:t};for(const d of S)d&&d.setOptions({[e]:t});return!0}function Nt(){if((c.plotMode??"hardBin")!=="metadata")return;const e=c.activeMetadataKey;if(!e)return;const t=new Set;for(const n of v)if(n)for(const o of Bo(n.dies,e))t.add(o);return{key:e,values:[...t].sort(St)}}function lt(){at("metadataValueOrder",Nt(),(e,t)=>e.key===t.key&&Tn(e.values,t.values))}function st(){if((c.plotMode??"hardBin")!=="value")return;const{testNumber:e,td:t}=Ne(),n=eo(e,t);at("valueRange",n?{test:e,range:n}:void 0,(d,l)=>{const a=s=>Array.isArray(s)?{test:void 0,range:s}:{test:s.test,range:s.range},r=a(d),i=a(l);return r.test===i.test&&Tn(r.range,i.range)})}let rt=!1;function to(){if(rt)return;rt=!0,(f.ownerDocument.defaultView?.requestAnimationFrame??(t=>setTimeout(()=>t(0),0)))(()=>{rt=!1,st(),lt(),_t()})}let dt=!1;function no(){if(dt)return;dt=!0,(f.ownerDocument.defaultView?.requestAnimationFrame??(t=>setTimeout(()=>t(0),0)))(()=>{dt=!1,qe()})}let zt=[];function fe(){const{colors:e,mixedHardBins:t}=To(v.filter(n=>n!=null),{binColorScheme:c.binColorScheme,useDefinedBinColors:c.useDefinedBinColors});return zt=t,e}function _t(){at("binColors",fe(),Io),Be()}const oo=oi(ce,()=>ai(c,Qn,{functionalActive:Ee(),hasLimits:Vt()&&!Ee(),hasRecorded:Jn()&&!Ee(),binMode:(c.plotMode??"hardBin")==="hardBin"||(c.plotMode??"hardBin")==="softBin"},e=>T(e)),()=>li(c)),{btn:io,sync:Gt}=ni(ce,()=>({plotMode:c.plotMode,legendPosition:ye}),e=>{ye=e;for(const t of S)t&&t.setOptions({legendPosition:ye})},{get:()=>Pe,set:e=>{Pe=e,Et()},blockedReason:we});Gt();const ao=[{value:"mean",label:"Mean"},{value:"median",label:"Median"},{value:"stddev",label:"Std Dev"},{value:"min",label:"Min"},{value:"max",label:"Max"},{value:"count",label:"Count"}],Kt=Lt("aggr","Aggregation method",()=>ao,()=>c.aggregationMethod??"mean",e=>T({aggregationMethod:e}));function qt(){const e=c.plotMode==="stackedValues";Kt.style.display=e?"":"none"}qt();const{btn:lo,sync:Ut}=ti(ce,()=>({...c,functionalActive:Ee()}),e=>T(e));Ut();const ze=Q("specRange","Colorbar range: spec limits",()=>{const e=c.colorbarRangeMode==="data"?"spec":"data";T({colorbarRangeMode:e})});function Xt(){const e=(c.plotMode??"hardBin")==="value"&&Vt()&&Mn(c)==="off"&&!Ee();ze.style.display=e?"":"none";const t=(c.colorbarRangeMode??"spec")==="spec";Se(ze,t),ze.ariaLabel=t?"Colorbar range: spec limits (click for data range)":"Colorbar range: data range (click for spec limits)"}Xt();const so=ii(ce,()=>c,e=>T(e)),ro=Q("downloadAll","Download gallery PNG",Co),co=Lt("columns","Columns",()=>[{value:"auto",label:"Auto"},{value:"1",label:"1 column"},{value:"2",label:"2 columns"},{value:"3",label:"3 columns"},{value:"4",label:"4 columns"},{value:"5",label:"5 columns"}],()=>k!=null?String(k):"auto",e=>ln(e==="auto"?void 0:Number(e))),O=f.ownerDocument.createElement("div");Object.assign(O.style,{display:"inline-flex",alignItems:"center",gap:"0"}),W.appendChild(O),O.appendChild(Y),O.appendChild(Zn),O.appendChild(Kt),O.appendChild(lo),O.appendChild(ze),O.appendChild(G()),O.appendChild(oo),O.appendChild(G()),O.appendChild(io),O.appendChild(G()),O.appendChild(so),O.appendChild(G()),O.appendChild(co),O.appendChild(G()),O.appendChild(ro),(V||nt())&&(P=Q("findings","Summary panel",()=>{if(!b)return;const e=b.style.display!=="none";e||N(),b.style.display=e?"none":"flex",Se(P,!e),le()}),W.appendChild(G()),W.appendChild(P));let K=null,_e=null,J=[],Yt=!1;function Be(){const e=Mi({lotStatsSummary:V,result:{warnings:[...v.flatMap(n=>n?.warnings??[]),...Bt().warnings]},extra:[c.binColors&&Lo(c.binColors,c.plotMode),Ro(zt),Pn(kt())].filter(n=>!!n)}),t=e.length!==J.length||e.some((n,o)=>n.code!==J[o]?.code||n.message!==J[o]?.message);J=e,(t||!Yt)&&(Yt=!0,p.warnings?.onWarning?.(e)),uo()}function uo(){if(!K||!_e)return;const e=J.length,t=e>0;if(K.style.display=t?"flex":"none",_e.style.display=t?"":"none",!t)return;const n=ki(J[0]),o=`${e} data ${e===1?"warning":"warnings"}`;K.style.color=n==="error"?h.errText:h.warnText,K.ariaLabel=n==="error"?`${o} \u2014 some wafers may be positionally wrong`:o}(p.warnings?.display??!0)&&(_e=G(),K=Q("warning","Data warnings",()=>{const e=Me();if(je(new MouseEvent("click")),e)return;const t=Di(K.getBoundingClientRect(),J,K.ownerDocument.defaultView??window);wn(f).appendChild(t),De(t),xn(t,K,()=>je(new MouseEvent("click")))}),Ae(K,!1),W.appendChild(_e),W.appendChild(K)),Be();let se=null;H&&(se=Q("analysis","Insights",()=>{Jt(!Te)}),se.dataset.wmapInsightsBtn="1",W.appendChild(G()),W.appendChild(se));function Zt(){import("./userGuideHtml.js").then(e=>Jo({buildWaferMap:Ci,renderWaferMap:bi,renderWaferGallery,analyzeWaferMap:Je},e.USER_GUIDE_HTML,I,f))}E&&(W.appendChild(G()),W.appendChild(Q("help","User guide",()=>Zt())));const pe=f.ownerDocument.createElement("div");pe.dataset.wmapGalleryMeta="1",Object.assign(pe.style,{flex:"1",minWidth:"0",overflow:"hidden",display:"flex",alignItems:"center",padding:`${w.sm} ${w.lg}`,fontSize:L.sub,lineHeight:Ze.none,boxSizing:"border-box"});const Ge=f.ownerDocument.createElement("div");Object.assign(Ge.style,{background:h.canvasBg,display:"flex",alignItems:"stretch",gap:w.lg,paddingBottom:w.lg,minWidth:"0"});const ee=f.ownerDocument.createElement("div");ee.dataset.wmapGalleryLegend="1",Object.assign(ee.style,{display:"flex",flexDirection:"column",gap:w.sm,background:h.menuBg,border:`1px solid ${h.menuBorder}`,borderRadius:z.container,padding:`${w.sm} ${w.lg}`,marginBottom:w.lg,boxShadow:$e.panel,fontSize:L.body,lineHeight:Ze.none,boxSizing:"border-box",width:"100%",minWidth:"0"});const q=f.ownerDocument.createElement("div");Object.assign(q.style,{display:"flex",flexDirection:"row",alignItems:"flex-start"});let me=null,Oe=null,Qt=null;function fo(){return H?me?Promise.resolve(me):(Qt??=import("./insightsTab.js").then(({createInsightsTab:e})=>(me=e({getItems:()=>v,getLotStats:()=>V,getBinColors:()=>c.binColors??fe(),getRingCount:tt,defaultView:p.insights?.defaultView,sweeps:p.insights?.sweeps,onOpenGuide:void 0,showMetadataStrip:!1,onSaveImage:Fe.onSaveImage,onSaveText:Fe.onSaveText,ownerDocument:f.ownerDocument,openWafer:(t,n,o)=>{const d=v[t];if(!d)return;let l=null;const a=Xo({title:n,onClose:()=>l?.destroy(),anchor:f});dn(a,n,d.wafer.metadata??void 0),l=ht(a.contentWrap,d,o)}}),Oe=me.el,Oe.style.display="none",f.appendChild(Oe),me)),Qt):Promise.resolve(null)}let Te=!1;function Jt(e){H&&(Te=e,Oe&&(Oe.style.display=e?"flex":"none"),q.style.display=e?"none":"flex",O.style.display=e?"none":"inline-flex",W.style.display="inline-flex",se&&(Se(se,e),se.innerHTML=e?We.wafer:We.analysis,se.ariaLabel=e?"Back to gallery view":"Insights"),le(),qe(),e&&fo().then(t=>{!t||!Te||(t.el.style.display="flex",t.render())}))}H&&p.insights?.defaultOpen&&queueMicrotask(()=>Jt(!0));const po=4,ct=240,en=480,mo=720,go=1.25;let ge=en;function tn(e){const t=A*2+110+2;let n=null;for(const o of e){if(o==null||!o.dies?.length)continue;const d=o.dies[0].width;if(!(d>0))continue;const l=o.wafer.radius*2*(po/d),a=Math.ceil(l+t);(n==null||a>n)&&(n=a)}return n}function ho(e){const t=tn(e);return t==null?ct:Math.min(ge,Math.max(ct,t))}function bo(e){const t=tn(e);if(t==null)return!1;const n=Math.min(mo,Math.max(en,t));return n<=ge?!1:(ge=n,!0)}function ut(){return k!=null?"none":`${ge}px`}function nn(){const e=ut();for(const t of Array.from($.children))t.classList.contains("wmap-gallery-card")&&(t.style.maxWidth=e,t.style.maxHeight=e)}let Ke=ct,on=0;function an(e){if(bo(e)&&nn(),k==null){const n=ho(e);n>Ke&&(Ke=n)}pt()}function ln(e){k=In(e),nn(),pt()}function ft(e){return`repeat(${e}, minmax(0, ${k!=null?"1fr":`${ge}px`}))`}function sn(e){$.style.gridTemplateColumns!==e&&($.style.gridTemplateColumns=e)}function pt(){if(k!=null){sn(ft(k));return}const e=Math.max(1,on),t=12,n=$.clientWidth||0,o=l=>(n-t*(l-1))/l;let d=Math.max(1,Math.ceil(Math.sqrt(e)));if(n>0){const l=Math.min(ge,Ke*go),a=r=>{let i=0;for(;i<e&&o(i+1)>=r;)i++;return i};d=a(l)||a(Ke)||1}sn(ft(d))}const $=f.ownerDocument.createElement("div");if(Object.assign($.style,{flex:"1 1 0",minWidth:"0",display:"grid",gridTemplateColumns:ft(1),gap:w.xl,paddingLeft:oe,paddingRight:oe,justifyContent:"start",alignContent:"start",isolation:"isolate"}),re?.placement){const e=re.placement;b=Mt(e,oe,f.ownerDocument),b.style.maxHeight="calc(100vh - 80px)",b.style.position="sticky",b.style.top="8px",b.style.display="flex",b.style.flexDirection="column"}else if(V||nt()){const e=!!re?.defaultOpen;b=Mt("right",oe,f.ownerDocument),b.style.maxHeight="calc(100vh - 80px)",b.style.position="sticky",b.style.top="8px",b.style.flexDirection="column",b.style.display=e?"flex":"none",N()}le(),b?.style.display!=="none"&&P&&Se(P,!0),(re?.placement??"right")==="left"?(b&&q.appendChild(b),q.appendChild($)):(q.appendChild($),b&&q.appendChild(b));const Le=f.ownerDocument.createElement("div");Object.assign(Le.style,{position:"sticky",top:"0",display:"flex",flexDirection:"column",paddingLeft:oe,paddingRight:oe,paddingTop:oe,zIndex:"1",background:h.menuBg}),Ge.appendChild(pe),Ge.appendChild(W),Le.appendChild(Ge),Le.appendChild(ee),f.appendChild(Le),f.appendChild(q);function qe(){ee.innerHTML="";const e=c.plotMode??"hardBin",t=!Te&&hn.has(e),n=R.filter(g=>g!=null),o=n.find(g=>g.isLotStack),d=Ei(n.map(g=>({metadata:g.wafer.metadata??void 0})),o?{lotSize:o.lotSize??n.length,aggrMethod:o.aggrMethod}:void 0),l=e==="metadata",a=c.activeMetadataKey,r=t&&!l?Wn(n,g=>(e==="softBin"?g.sbin:g.hbin)??void 0,An):{counts:new Map,total:0,pass:0},i=t&&!l?c.binColors??fe():void 0,s=i?e==="softBin"?i.pass.soft:i.pass.hard:new Set,u=mi(r.counts.entries(),s).map(([g])=>g),m=t&&l&&a?Wn(n,g=>Oo(g.metadata?.[a])):{counts:new Map,total:0,pass:0},M=l?Nt()?.values:void 0,D=t&&l?(M??[...m.counts.keys()].sort(St)).filter(g=>m.counts.has(g)):[];if(pe.innerHTML="",d&&pe.appendChild(d),pe.style.display=d?"flex":"none",!u.length&&!D.length){ee.style.display="none";return}ee.style.display="flex";const x=f.ownerDocument.createElement("div");Object.assign(x.style,{display:"flex",flexWrap:"wrap",alignItems:"center",gap:`${w.sm} ${w.xl}`,maxHeight:"86px",overflowY:"auto",overflowX:"hidden"}),ee.appendChild(x);const y=c.highlightBin,B=R.flatMap(g=>g?.metadataFields??[]).find(g=>g.key===a),j=l?B?.label??(a?Li(a):"Metadata"):No[e],U=f.ownerDocument.createElement("span");if(U.textContent=j,Object.assign(U.style,{fontSize:L.body,fontWeight:"700",letterSpacing:Ho,textTransform:"uppercase",color:h.label,flexShrink:"0"}),x.appendChild(U),!l&&r.total>0){const g=r.pass,F=g/r.total*100,te=f.ownerDocument.createElement("span");te.textContent=`Yield ${et(F)}`,Object.assign(te.style,{fontSize:L.body,fontWeight:"700",color:h.value,whiteSpace:"nowrap",flexShrink:"0"});const ne=f.ownerDocument.createElement("span");ne.textContent=`${g.toLocaleString()} / ${r.total.toLocaleString()} dies`,Object.assign(ne.style,{fontSize:L.body,color:h.label,whiteSpace:"nowrap",flexShrink:"0"}),x.appendChild(te),x.appendChild(ne)}if(l){const g=c.highlightMetadataValue;D.forEach((F,te)=>{const ne=g===F,Xe=B?.values?.find(vt=>vt.value===F),Mo=Xe?.color??Po(te),mn=m.counts.get(F)??0;$n(x,{color:Mo,isActive:ne,label:Xe?.label??F,count:mn,percent:m.total>0?mn/m.total*100:void 0,onClick:()=>{const vt=c.highlightMetadataValue===F?void 0:F;T({highlightMetadataValue:vt})}})});return}const bt=e==="softBin"?R.flatMap(g=>g?.sbinDefs??[]):R.flatMap(g=>g?.hbinDefs??[]),un=new Set,yt=[];for(const g of bt)un.has(g.bin)||(un.add(g.bin),yt.push(g));const wt=yt.length>0?new Map(yt.map(g=>[g.bin,g])):null,fn=i??c.binColors??fe(),So=e==="softBin"?fn.soft:fn.hard,pn=g=>So.get(g)??Ao;for(const g of u){const F=y===g,te=wt?.get(g),ne=r.counts.get(g)??0;$n(x,{color:pn(g),isActive:F,label:te?.name?`${g} \xB7 ${te.name}`:`Bin ${g}`,count:ne,percent:r.total>0?ne/r.total*100:void 0,onClick:()=>{const Xe=c.highlightBin===g?void 0:g;T({highlightBin:Xe})}})}r.total>0&&u.length>1&&ee.appendChild(Hi(f.ownerDocument,[...r.counts.entries()].sort(([,g],[,F])=>F-g).map(([g,F])=>({color:pn(g),count:F,label:wt?.get(g)?.name?`${g} \xB7 ${wt.get(g).name}`:`Bin ${g}`})),r.total))}function Re(e){const t=v.filter(r=>r!==null);if(!t.length)return[];const n=t.map(r=>r.dies.filter(Pi)),o=t[0].wafer,d=t.length,l=o.metadata?{...o,metadata:(({wafer:r,waferId:i,...s})=>s)(o.metadata)}:o;function a(r,i){return{...r,stats:{...r.stats,isLotStack:!0,aggregationMethod:i,lotSize:d}}}if(e==="stackedValues"){const r=ve();let i=r?.filter(Ct);if(r!==void 0&&i?.length===0)return[];if(r?.length||(i=Do(t.flatMap(m=>m.dies)).map(m=>({testNumber:m,name:Ri(void 0,m)}))),!i?.length)return[];const s=c.aggregationMethod??"mean";return i.map(u=>{const m=hi(n,s,u.testNumber),M={testNumber:0,name:u.name,unit:u.unit,...Wi(u)};return{wafer:l,dies:m,testDefs:[M],label:`${Ii(u,u.testNumber)} \xB7 ${s}`,isLotStack:!0,aggrMethod:s,lotSize:d,statsSummary:a(Je({wafer:l,dies:m,testDefs:[M]},{testNumbers:[0]}),s)}})}if(e==="stackedBins"){let r=Ye(t.map(i=>i?.hbinDefs));return(!r||r.length===0)&&(r=[...new Set(t.flatMap(s=>s.dies.map(u=>u.hbin).filter(u=>u!=null)))].sort((s,u)=>s-u).map(s=>({bin:s,name:`Bin ${s}`}))),r.map(i=>{const s=kn(n,i.bin,"hard"),u=[{bin:i.bin,name:i.name}];return{wafer:l,dies:s,hbinDefs:u,label:`${i.bin} \xB7 ${i.name}`,isLotStack:!0,aggrMethod:"countBin",lotSize:d,statsSummary:a(Je({wafer:l,dies:s,hbinDefs:u}),"countBin")}})}if(e==="stackedSoftBins"){let r=Ye(t.map(i=>i?.sbinDefs));return(!r||r.length===0)&&(r=[...new Set(t.flatMap(s=>s.dies.map(u=>u.sbin).filter(u=>u!=null)))].sort((s,u)=>s-u).map(s=>({bin:s,name:`Bin ${s}`}))),r.map(i=>{const s=kn(n,i.bin,"soft"),u=[{bin:i.bin,name:i.name}];return{wafer:l,dies:s,sbinDefs:u,label:`${i.bin} \xB7 ${i.name}`,isLotStack:!0,aggrMethod:"countBin",lotSize:d,statsSummary:a(Je({wafer:l,dies:s,sbinDefs:u}),"countBin")}})}return t}function mt(e){const t=v.length;return e==="stackedBins"||e==="stackedSoftBins"?{valueRange:[0,t],lotSize:t}:e==="stackedValues"?{aggregationMethod:c.aggregationMethod??"mean",valueRange:void 0,lotSize:void 0}:{}}function T(e,{fireCallback:t=!0}={}){const n=Object.keys(e),o=c.plotMode,d=we()!==null;c={...c,...e};const l=c.plotMode,a=be.has(l),r=o!==void 0&&be.has(o),i=He>0;if("binColorScheme"in e||"useDefinedBinColors"in e){const u=fe();c={...c,binColors:u},e={...e,binColors:u}}if(e.plotMode!==void 0)if(a){const u=mt(l);if(c={...c,...u},i)for(const m of S)m&&m.setOptions(e);else Z(Re(l))}else if(r){const{valueRange:u,lotSize:m,aggregationMethod:M,...D}=c;if(c=D,i)for(const x of S)x&&x.setOptions(e);else Z(v.filter(x=>x!==null))}else for(const u of S)u&&u.setOptions(e);else if(e.aggregationMethod!==void 0&&l==="stackedValues")if(i)for(const u of S)u&&u.setOptions(e);else Z(Re("stackedValues"));else for(const u of S)u&&u.setOptions(e);we()!==null!==d&&Et(),qe(),qt(),Gt(),jt();const s=e.plotMode!==void 0&&e.plotMode!==o;(xi.some(u=>u in e)||s)&&N(),Be(),Ut(),Xt(),st(),lt(),t&&p.onViewOptionsChange?.(Bn(c),n,vi(n))}function rn(e,t,n){const o=e.createElement("div");Object.assign(o.style,{display:"flex",alignItems:"center",gap:w.xs,flex:"1",minWidth:"0"});const d=e.createElement("span");d.textContent=t,Object.assign(d.style,{fontWeight:"700",fontSize:L.sub,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}),o.appendChild(d);const l=Rn(n??{});let a=null;if(l.length>0){const r=e.createElement("span");Object.assign(r.style,{fontSize:L.body,lineHeight:Ze.none,color:h.label,flexShrink:"0"}),r.textContent="\u25BE",o.appendChild(r),Object.assign(o.style,{cursor:"pointer",borderRadius:z.control}),o.addEventListener("mouseenter",()=>{o.style.background=h.bgHover}),o.addEventListener("mouseleave",()=>{o.style.background="none"}),a=e.createElement("div"),a.dataset.wmapCardMetaPanel="1",Object.assign(a.style,{position:"absolute",top:"0",left:"0",right:"0",zIndex:bn,background:h.menuBg,borderBottom:`1px solid ${h.menuBorder}`,boxShadow:$e.menu,padding:`${w.md} ${w.lg}`,fontSize:L.body,display:"none"});const i=Ln(n??{});i&&a.appendChild(i),o.setAttribute("aria-expanded","false"),o.setAttribute("aria-label",`Wafer info for ${t||"this card"}. Click to expand.`),Cn(o,s=>{r.textContent=s?"\u25B4":"\u25BE",o.setAttribute("aria-expanded",String(s)),a&&(a.style.display=s?"block":"none")})}return{wrap:o,metaPanel:a}}function dn(e,t,n){const o=e.box.querySelector("[data-wmap-window-title]"),d=Rn(n??{});if(!o||d.length===0)return;const l=o.parentElement,a=f.ownerDocument.createElement("div");Object.assign(a.style,{display:"flex",alignItems:"center",gap:w.xs,flex:"1",minWidth:"0",cursor:"pointer"}),xt(a,"bare"),l?.insertBefore(a,o),a.appendChild(o);const r=f.ownerDocument.createElement("span");Object.assign(r.style,{fontSize:L.body,lineHeight:Ze.none,color:h.label,flexShrink:"0"}),r.textContent="\u25BE",a.appendChild(r);const i=f.ownerDocument.createElement("div");i.dataset.wmapCardMetaPanel="1",Object.assign(i.style,{position:"absolute",top:"0",left:"0",right:"0",zIndex:bn,background:h.menuBg,borderBottom:`1px solid ${h.menuBorder}`,boxShadow:$e.menu,padding:`${w.md} ${w.lg}`,fontSize:L.body,display:"none"});const s=Ln(n??{});s&&i.appendChild(s),e.contentWrap.style.position="relative",e.contentWrap.appendChild(i),a.setAttribute("aria-expanded","false"),a.setAttribute("aria-label",`Wafer info for ${t}. Click to expand.`),Cn(a,u=>{r.textContent=u?"\u25B4":"\u25BE",a.setAttribute("aria-expanded",String(u)),i.style.display=u?"block":"none"})}function gt(e,t,n){const o=f.ownerDocument.createElement("div");o.className="wmap-gallery-card",Object.assign(o.style,{background:h.menuBg,border:`1px solid ${h.menuBorder}`,borderRadius:z.container,boxShadow:$e.panel,overflow:"hidden",display:"flex",flexDirection:"column",position:"relative",aspectRatio:"1",maxWidth:ut(),maxHeight:ut()});const d=f.ownerDocument.createElement("div");Object.assign(d.style,{display:"flex",alignItems:"center",padding:`${w.md} ${w.lg} ${w.sm}`,borderBottom:`1px solid ${h.menuBorder}`,flexShrink:"0",gap:w.sm});const{wrap:l,metaPanel:a}=rn(document,Qe(e,t),e.wafer.metadata??void 0);d.appendChild(l);const r=f.ownerDocument.createElement("button");r.dataset.wmapExpandBtn="1",r.setAttribute("aria-label","Open full view"),Sn(r),r.innerHTML=We.expand,Object.assign(r.style,{display:"flex",alignItems:"center",justifyContent:"center",border:`1px solid ${h.menuBorder}`,borderRadius:z.control,background:h.panelBg,color:h.label,padding:w.xxs,cursor:"pointer",flexShrink:"0",width:"22px",height:"22px"}),xt(r),d.appendChild(r),o.appendChild(d);const i=f.ownerDocument.createElement("div");Object.assign(i.style,{position:"relative",flex:"1",minHeight:"0",overflow:"hidden",display:"flex",flexDirection:"column"}),o.appendChild(i),a&&i.appendChild(a),$.appendChild(o),o.addEventListener("contextmenu",M=>{if(M.defaultPrevented)return;const D=p.insights?.sweeps;if(!yi(e.testDefs,D))return;M.preventDefault();const x=e.viewOptions?{...c,...e.viewOptions}:c,y=wi(e.dies,{waferLabel:Dn(e),testDefs:e.testDefs,isLotStack:e.isLotStack,activeTest:x.plotMode==="value"?x.activeTest:void 0,waferIndex:t}),B={x:M.clientX,y:M.clientY};import("./drilldown.js").then(({openDrilldownMenu:j})=>{o.isConnected&&j(B,o,y,{sweeps:D,onSaveImage:p.onSaveImage})})});const s=Pe||we()!==null,u=e.viewOptions?{...c,...e.viewOptions}:c,m=En(i,e,{viewOptions:{...u,showLegend:s,legendPosition:ye},showTooltip:!0,padding:A,statsSummary:e.statsSummary,onSaveImage:p.onSaveImage,onSaveText:p.onSaveText,onClick:e.onClick,onSelect:e.onSelect,insights:X,onExpand:()=>Ie(t,e),showIdentity:!1,chromeInset:Vo});return m.setViewControlsVisible(!1),m.setSummaryVisible(!1),r.onclick=()=>Ie(t,e),{card:o,ctrl:m,canvasWrapper:i,expandBtn:r}}function yo(e){const t=de[e];if(!t)return;const n=[..._.values()].find(o=>o.cardIndex===e);n?(t.innerHTML=We.minimize,t.setAttribute("aria-label","Reattach to gallery"),t.onclick=()=>vo(n.id)):(t.innerHTML=We.expand,t.setAttribute("aria-label","Open full view"),t.onclick=()=>Ie(e,R[e]))}function Z(e){xo(),Me()?.remove(),De(null),it(),R=[];for(const i of S)i&&i.destroy();S=[],ae=[],de=[],He=0,$.innerHTML="",on=e.length,an(e.map(i=>typeof i=="function"?null:i));const t=[];for(let i=0;i<e.length;i++){const s=e[i];if(typeof s=="function"){const u=f.ownerDocument.createElement("div");u.className="wmap-gallery-card",Object.assign(u.style,{background:h.menuBg,border:`1px solid ${h.menuBorder}`,borderRadius:z.container,aspectRatio:"1",display:"flex",alignItems:"center",justifyContent:"center"});const m=f.ownerDocument.createElement("span");m.textContent="\u2026",Object.assign(m.style,{color:h.label,fontSize:"18px"}),u.appendChild(m),$.appendChild(u),R.push(null),S.push(null),ae.push(null),de.push(null),t.push({index:i,factory:s,placeholder:u}),He++}else{const{ctrl:u,canvasWrapper:m,expandBtn:M}=gt(s,i,e.length);R.push(s),S.push(u),ae.push(m),de.push(M)}}_t(),qe(),st(),lt();const n=++xe,o=()=>{setTimeout(()=>{n===xe&&p.onItemsResolved?.()},0)},d=i=>{setTimeout(()=>{n===xe&&p.onItemResolved?.(i,e.length)},0)};let l=e.length-t.length;l>0&&d(l);let a=0;function r(){if(n!==xe)return;if(a>=t.length){if(be.has(c.plotMode)){const B=c.plotMode;Z(Re(B));return}ke=o,N(),ue||(ke=null,o());return}const{index:i,factory:s,placeholder:u}=t[a++],m=s();R[i]=m,v[i]=m,an([m]);const{card:M,ctrl:D,canvasWrapper:x,expandBtn:y}=gt(m,i,e.length);S[i]=D,ae[i]=x,de[i]=y,He--,u.replaceWith(M),d(++l),no(),to(),!b&&!re?.placement&&m.statsSummary?.findings.length&&(b=Mt("right",oe,f.ownerDocument),b.style.maxHeight="calc(100vh - 80px)",b.style.position="sticky",b.style.top="8px",b.style.flexDirection="column",b.style.display="none",(re?.placement??"right")==="left"?q.insertBefore(b,$):q.appendChild(b),N(),P||(P=Q("findings","Summary panel",()=>{if(!b)return;const j=b.style.display!=="none";j||N(),b.style.display=j?"none":"flex",Se(P,!j),le()}),W.appendChild(G()),W.appendChild(P)),le()),le(),setTimeout(r,0)}t.length>0?setTimeout(r,0):o()}if(be.has(c.plotMode)&&v.length>0){const e=mt(c.plotMode);c={...c,...e},Z(Re(c.plotMode))}else Z(C);Be();let he=0;const cn=new(f.ownerDocument.defaultView??window).ResizeObserver(()=>{if(he)return;he=(f.ownerDocument.defaultView??window).requestAnimationFrame(()=>{he=0,k==null&&pt()})});cn.observe($),b&&N();function wo(e,t){const n=ae[e];if(!n)return;n.innerHTML="",Object.assign(n.style,{alignItems:"center",justifyContent:"center"});const o=f.ownerDocument.createElement("span");o.textContent=t?"Opened in its own window":"Opened in the wafer viewer",Object.assign(o.style,{color:h.label,fontSize:L.body,textAlign:"center",padding:"0 12px"}),n.appendChild(o)}function Ie(e,t){for(const a of _.values())if(a.cardIndex===e)return;const n=Qe(t,e),o=Fn++,d=S[e]?.getOptions(),l=qo(n);if(l){const a=l.document;a.title=n,Object.assign(a.documentElement.style,{height:"100%"}),Object.assign(a.body.style,{margin:"0",height:"100vh",overflow:"hidden",display:"flex",flexDirection:"column",fontFamily:L.family}),Zo(f,a.documentElement);const r=Qo(f,a.documentElement,()=>x.setOptions({})),i=a.createElement("div");i.dataset.wmapWindowBanner="1",i.textContent=n,Object.assign(i.style,{display:"none",padding:`${w.sm} ${w.xl}`,fontSize:L.body,fontWeight:"700",background:h.warnBg,color:h.warnText,borderBottom:`1px solid ${h.warnBorder}`,flexShrink:"0"}),a.body.appendChild(i);const s=a.createElement("div");Object.assign(s.style,{flex:"1",minHeight:"0",display:"flex",flexDirection:"column"}),a.body.appendChild(s);const{wrap:u,metaPanel:m}=rn(a,n,t.wafer.metadata??void 0),M=a.createElement("div");Object.assign(M.style,{display:"flex",alignItems:"center",padding:`${w.md} ${w.lg} ${w.sm}`,borderBottom:`1px solid ${h.menuBorder}`,flexShrink:"0",gap:w.sm}),M.appendChild(u),s.appendChild(M);const D=a.createElement("div");Object.assign(D.style,{position:"relative",flex:"1",minHeight:"0",overflow:"hidden",display:"flex",flexDirection:"column"}),m&&D.appendChild(m),s.appendChild(D);const x=ht(D,t,void 0,d),y=setInterval(()=>{l.closed&&Ue(o)},400);l.addEventListener("pagehide",()=>Ue(o)),_.set(o,{id:o,ctrl:x,cardIndex:e,label:n,closePollId:y,stopThemeSync:r,close:()=>{l.closed||l.close()},setTitle:B=>{a.title=B,i.textContent=B,i.style.display="block"}})}else{const a=Uo({title:n,onClose:()=>Ue(o),anchor:f});a.contentWrap.style.flexDirection="column",dn(a,n,t.wafer.metadata??void 0);const r=ht(a.contentWrap,t,void 0,d);_.set(o,{id:o,ctrl:r,cardIndex:e,label:n,closePollId:null,close:()=>a.close(),setTitle:i=>{const s=a.box.querySelector("[data-wmap-window-title]");s&&(s.textContent=i,s.title=i)}})}S[e]?.destroy(),S[e]=null,wo(e,l!==null),yo(e)}function ht(e,t,n,o){const d=t.viewOptions?{...c,...t.viewOptions}:c,l=o?{...d,...o}:d,r={...n!==void 0?{...l,plotMode:"value",activeTest:n}:l,showLegend:!0,legendPosition:ye},i=En(e,t,{viewOptions:r,showTooltip:!0,padding:A,statsSummary:t.statsSummary,onSaveImage:p.onSaveImage,onSaveText:p.onSaveText,onClick:t.onClick,onSelect:t.onSelect,insights:X,showExpandButton:!1,showIdentity:!1});return i.setViewControlsVisible(!0),i.setSummaryVisible(!0),i.setExpandVisible(!1),i}function Ue(e){const t=_.get(e);if(!t||(_.delete(e),t.closePollId!=null&&clearInterval(t.closePollId),t.stopThemeSync?.(),t.ctrl.destroy(),t.cardIndex===null))return;const n=t.cardIndex,o=R[n];if(!o)return;const{card:d,ctrl:l,canvasWrapper:a,expandBtn:r}=gt(o,n,R.length);ae[n]?.parentElement?.replaceWith(d),S[n]=l,ae[n]=a,de[n]=r}function vo(e){const t=_.get(e);t&&(t.close(),Ue(e))}function xo(){for(const e of _.values())e.cardIndex!==null&&(e.cardIndex=null,e.setTitle(`${e.label} \u2014 unlinked from gallery`))}function Co(){const e=[...$.querySelectorAll("canvas")];if(!e.length)return;const t=e.length,n=Math.ceil(Math.sqrt(t)),o=Math.ceil(t/n),d=e[0].width,l=e[0].height,a=8,r=(f.ownerDocument.defaultView??window).devicePixelRatio||1,i=Math.round(26*r),s=Math.round(12*r),u=f.ownerDocument.createElement("canvas");u.width=n*d+(n-1)*a,u.height=o*(l+i)+(o-1)*a;const m=u.getContext("2d"),M=Fo($);m.fillStyle=M.background,m.fillRect(0,0,u.width,u.height),e.forEach((D,x)=>{const y=x%n,B=Math.floor(x/n),j=y*(d+a),U=B*(l+i+a),bt=D.closest(".wmap-gallery-card")?.querySelector("span")?.textContent??"";m.fillStyle=M.surface,m.fillRect(j,U,d,i),m.fillStyle=M.text,m.font=`700 ${s}px system-ui, sans-serif`,m.textAlign="left",m.textBaseline="middle",m.fillText(bt,j+Math.round(10*r),U+i/2,d-Math.round(20*r)),m.drawImage(D,j,U+i)}),u.toBlob(D=>{if(!D)return;if(p.downloadFilename!=null){vn(D,p.downloadFilename,p.onSaveImage);return}const x=S.find(y=>y!=null)?.getExportTitle();vn(D,["gallery",x].filter(Boolean).join(" "),Fe.onSaveImage)})}return{setItems(e){v=e.map(n=>typeof n=="function"?null:n);const t=c.plotMode;if(be.has(t))if(e.some(o=>typeof o=="function"))Z(e);else{const o=mt(t);c={...c,...o},Z(Re(t))}else Z(e)},setOptions(e){T(e,{fireCallback:!1})},getOptions(){return Bn(c)},setFindingsNotice(e){It=e,N()},setColumns(e){ln(e)},getBinColors(){return c.binColors??fe()},setLotStatsSummary(e){V=e,Be(),b&&N(),le()},openUserGuide:Zt,destroy(){xe++,ue?.cancel(),ue=null,ke=null;for(const e of[..._.values()])e.closePollId!=null&&clearInterval(e.closePollId),e.close(),e.ctrl.destroy();_.clear();for(const e of S)e&&e.destroy();S=[],Me()?.remove(),cn.disconnect(),he&&((f.ownerDocument.defaultView??window).cancelAnimationFrame(he),he=0),f.ownerDocument.removeEventListener("click",je,!0),window.removeEventListener("blur",Rt),ie(),yn(),Le.remove(),q.remove(),b?.remove(),me?.destroy()}}}
|