@wafertools/wafermap 0.29.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +13 -14
- package/CHANGELOG.md +235 -0
- package/README.md +5 -5
- package/dist/packages/canvas-adapter/deprecated.d.ts +10 -0
- package/dist/packages/canvas-adapter/deprecated.js +1 -0
- package/dist/packages/canvas-adapter/dieList.d.ts +1 -3
- package/dist/packages/canvas-adapter/dieList.js +7 -7
- package/dist/packages/canvas-adapter/index.d.ts +1 -3
- package/dist/packages/canvas-adapter/index.js +1 -1
- package/dist/packages/canvas-adapter/insightsTab.d.ts +0 -1
- package/dist/packages/canvas-adapter/insightsTab.js +1 -1
- package/dist/packages/canvas-adapter/maplessSummary.js +1 -1
- package/dist/packages/canvas-adapter/renderWaferGallery.d.ts +1 -40
- package/dist/packages/canvas-adapter/renderWaferGallery.js +1 -1
- package/dist/packages/canvas-adapter/renderWaferMap.d.ts +74 -104
- package/dist/packages/canvas-adapter/renderWaferMap.js +1 -1
- package/dist/packages/canvas-adapter/summaryPanel.d.ts +11 -8
- package/dist/packages/canvas-adapter/summaryPanel.js +3 -3
- package/dist/packages/canvas-adapter/toCanvas.d.ts +20 -12
- package/dist/packages/canvas-adapter/toCanvas.js +1 -1
- 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 +12 -8
- 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/deprecated.d.ts +64 -0
- package/dist/packages/core/deprecated.js +1 -0
- package/dist/packages/core/index.d.ts +1 -3
- package/dist/packages/core/index.js +1 -1
- package/dist/packages/core/passBins.d.ts +33 -0
- package/dist/packages/core/passBins.js +1 -0
- package/dist/packages/core/waferLabel.d.ts +25 -0
- package/dist/packages/core/waferLabel.js +1 -0
- package/dist/packages/renderer/binColors.d.ts +67 -13
- package/dist/packages/renderer/binColors.js +1 -1
- package/dist/packages/renderer/buildView.d.ts +8 -9
- package/dist/packages/renderer/buildView.js +1 -1
- package/dist/packages/renderer/buildWaferMap.d.ts +47 -13
- package/dist/packages/renderer/buildWaferMap.js +1 -1
- package/dist/packages/renderer/colorMap.d.ts +4 -3
- package/dist/packages/renderer/colorSchemes.d.ts +8 -6
- package/dist/packages/renderer/deprecate.d.ts +24 -0
- package/dist/packages/renderer/deprecate.js +1 -0
- package/dist/packages/renderer/deprecated.d.ts +45 -0
- package/dist/packages/renderer/deprecated.js +1 -0
- package/dist/packages/renderer/index.d.ts +2 -3
- package/dist/packages/renderer/index.js +1 -1
- package/dist/packages/stats/analyzeWaferMap.js +1 -1
- package/dist/packages/stats/binPareto.d.ts +6 -1
- package/dist/packages/stats/clusterDetection.d.ts +0 -2
- package/dist/packages/stats/deprecated.d.ts +87 -0
- package/dist/packages/stats/deprecated.js +1 -0
- package/dist/packages/stats/index.d.ts +3 -14
- package/dist/packages/stats/index.js +1 -1
- package/dist/packages/stats/regions.d.ts +7 -2
- package/dist/packages/stats/regions.js +1 -1
- package/dist/packages/stats/renderSummaryReport.d.ts +3 -0
- package/dist/packages/stats/renderSummaryReport.js +34 -34
- package/dist/packages/stats/types.d.ts +0 -43
- package/dist/packages/stats/yield.d.ts +12 -6
- package/dist/packages/stats/yield.js +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type SaveImageHandler, type SaveTextHandler, type UserGuideExtension } from './toolbar.js';
|
|
2
|
-
import type
|
|
2
|
+
import { type Die } from '../core/dies.js';
|
|
3
3
|
import type { WaferViewOptions } from './renderWaferMap.js';
|
|
4
4
|
import type { RenderableWaferMap } from './renderWaferMap.js';
|
|
5
5
|
import type { LotStatsSummary } from '../stats/types.js';
|
|
@@ -40,8 +40,6 @@ export interface GalleryOptions {
|
|
|
40
40
|
viewOptions?: WaferViewOptions;
|
|
41
41
|
/** Called whenever a shared gallery option changes. */
|
|
42
42
|
onViewOptionsChange?: (opts: WaferViewOptions, changed: (keyof WaferViewOptions)[], category: 'preference' | 'state' | 'mixed') => void;
|
|
43
|
-
/** Legend position for bin modes. Default 'default'. */
|
|
44
|
-
legendPosition?: 'default' | 'compact' | 'bottom' | 'top' | 'left' | 'floating';
|
|
45
43
|
/**
|
|
46
44
|
* Draw a legend on every card as well as the lot-level one. Default false.
|
|
47
45
|
*
|
|
@@ -55,8 +53,6 @@ export interface GalleryOptions {
|
|
|
55
53
|
* disabled with that reason rather than appearing to do nothing.
|
|
56
54
|
*/
|
|
57
55
|
perCardLegend?: boolean;
|
|
58
|
-
/** Padding inside each card canvas in CSS pixels. Default 6. */
|
|
59
|
-
cardPadding?: number;
|
|
60
56
|
/** Filename stem for the composite gallery PNG. Default 'wafer-gallery'. */
|
|
61
57
|
downloadFilename?: string;
|
|
62
58
|
/**
|
|
@@ -76,18 +72,6 @@ export interface GalleryOptions {
|
|
|
76
72
|
* the default browser download behaviour is unchanged.
|
|
77
73
|
*/
|
|
78
74
|
onSaveText?: SaveTextHandler;
|
|
79
|
-
/**
|
|
80
|
-
* Format to use for unitless values outside the normal display range [0.1, 9999].
|
|
81
|
-
* `'engineering'` (default): multiples-of-3 exponent notation (e.g. `12E-6`).
|
|
82
|
-
* `'si'`: SI prefix with no unit suffix (e.g. `12 µ`).
|
|
83
|
-
* Values with a unit always use SI prefix regardless of this setting.
|
|
84
|
-
*/
|
|
85
|
-
fallbackFormat?: 'si' | 'engineering';
|
|
86
|
-
/**
|
|
87
|
-
* Show the plot mode selector in the gallery control bar. Default true.
|
|
88
|
-
* Set to false when the host application manages mode switching itself.
|
|
89
|
-
*/
|
|
90
|
-
showPlotModeSelector?: boolean;
|
|
91
75
|
/** Precomputed lot-level stats summary. Enables the summary panel toggle button in the control bar. */
|
|
92
76
|
lotStatsSummary?: LotStatsSummary;
|
|
93
77
|
/**
|
|
@@ -118,28 +102,12 @@ export interface GalleryOptions {
|
|
|
118
102
|
* own coordinate-less die-list table, which this reuses.
|
|
119
103
|
*/
|
|
120
104
|
dieList?: DieListDisplayOptions;
|
|
121
|
-
/**
|
|
122
|
-
* Bin numbers treated as pass for yield calculation in the summary panel.
|
|
123
|
-
* Defaults to `[1]`. Must match the `passBins` passed to `analyzeWaferLot` / `buildWaferMap`
|
|
124
|
-
* to ensure the summary panel yield label is consistent with the rest of the display.
|
|
125
|
-
*/
|
|
126
|
-
passBins?: number[];
|
|
127
105
|
/**
|
|
128
106
|
* Fix the number of columns in the gallery grid. When set, overrides the
|
|
129
107
|
* auto-computed minimum card width and the toolbar columns control.
|
|
130
108
|
* Omit (default) to let the gallery auto-size cards based on die pitch.
|
|
131
109
|
*/
|
|
132
110
|
columns?: number;
|
|
133
|
-
/**
|
|
134
|
-
* Cap each gallery card's rendered width and height at this many CSS pixels.
|
|
135
|
-
* Cards pack from the left rather than stretching to fill the grid width.
|
|
136
|
-
*
|
|
137
|
-
* Omit it and the cap is derived from die density: 480px for an ordinary
|
|
138
|
-
* wafer, widening (to at most 720px) for high-DPW wafers that need the room
|
|
139
|
-
* to keep dies readable. Set it to take hard control instead — an explicit
|
|
140
|
-
* value is never widened, so you own the readability trade-off at high DPW.
|
|
141
|
-
*/
|
|
142
|
-
maxSize?: number;
|
|
143
111
|
/**
|
|
144
112
|
* Show a help button in the gallery control bar that opens the built-in end-user guide in a modal.
|
|
145
113
|
* Default false. Enable in applications that want to surface the guide without linking externally.
|
|
@@ -185,8 +153,6 @@ export interface GalleryController {
|
|
|
185
153
|
setOptions(opts: Partial<WaferViewOptions>): void;
|
|
186
154
|
/** Return the current shared scene options. */
|
|
187
155
|
getOptions(): WaferViewOptions;
|
|
188
|
-
/** Update the fallback format for unitless values across all cards. */
|
|
189
|
-
setFallbackFormat(format: 'si' | 'engineering'): void;
|
|
190
156
|
/** Replace the lot-level stats summary used by the built-in Summary panel. */
|
|
191
157
|
setLotStatsSummary(summary: LotStatsSummary | undefined): void;
|
|
192
158
|
/**
|
|
@@ -194,11 +160,6 @@ export interface GalleryController {
|
|
|
194
160
|
* `undefined` to clear it once the offered analysis has been run.
|
|
195
161
|
*/
|
|
196
162
|
setFindingsNotice(notice: FindingsNotice | undefined): void;
|
|
197
|
-
/**
|
|
198
|
-
* Set the number of columns in the gallery grid. Pass `undefined` to restore
|
|
199
|
-
* the auto-computed layout based on die pitch.
|
|
200
|
-
*/
|
|
201
|
-
setColumns(columns: number | undefined): void;
|
|
202
163
|
/**
|
|
203
164
|
* Opens the built-in end-user guide window — the same action the help
|
|
204
165
|
* toolbar button performs, but callable directly. Works regardless of
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getUniqueTestNumbers as ro,resolveTestNumber as co,findTestDef as fo,collectMetadataValues as uo}from"../renderer/buildView.js";import{metadataCategoricalValue as po}from"../core/metadata.js";import{resolveBinColors as go,binColorWarning as mo}from"../renderer/binColors.js";import{NO_DATA_FILL as ho}from"../renderer/colorMap.js";import{metadataValueColor as bo}from"../renderer/colorMap.js";import{resolveCanvasTheme as yo}from"./canvasTheme.js";import{ICONS as $e}from"./icons.js";import{SHADOW as We,LEADING as Ze,TRACKING as wo,controlStyle as xo,wireControlHover as mt,SPACE as x,EDGE_GUTTER as te,MAP_CHROME_INSET as vo,RADIUS as V,FONT as O,CLR as m,sevColor as an,MODE_LABELS as Co,BIN_LEGEND_MODES as sn,STACKED_MODES as be,Z_ABOVE as rn,applyOverlayZ as So,getTooltip as Mo,hideTooltip as dn,createToolbarHelpers as Do,buildModeMenuEl as ko,openDetachWindow as Eo,openFloatingWindow as Bo,openModal as Oo,openReportModal as To,copyWmapThemeTokens as Lo,syncWmapPopupTheme as $o,openUserGuideWindow as Wo,makePaletteBtn as Ro,makeLogScaleBtn as Io,makeLegendStyleBtn as Ao,makeOverlaysBtn as Po,makeOrientationBtn as Fo,menuLayerFor as cn,saveImageBlob as Ho,markMenuTrigger as Re,wireMenuA11y as fn,wireExpandToggle as un,wireTooltip as pn,requestedPassFailDisplay as gn,overlayMenuRows as jo,anyOverlayActive as Vo,logWmapVersionOnce as zo,buildDataModeEntries as No,metadataKeyHasData as _o,metadataModeEntry as Go}from"./toolbar.js";import{aggregateValues as Ko,aggregateBinCounts as mn}from"../core/aggregates.js";import{renderWaferMap as ht}from"./renderWaferMap.js";import{classifyChanged as qo,COLOR_KEYS as Uo}from"./renderWaferMap.js";import{buildWaferMap as Xo,getTestPassStatus as hn,isParametricTest as bt,getDieTestValue as Zo}from"../renderer/buildWaferMap.js";import{analyzeWaferMap as Ye}from"../stats/analyzeWaferMap.js";import{collectWarnings as Yo,buildWarningsMenuEl as Qo,severityOf as Jo}from"./warnings.js";import{compareNatural as bn}from"../core/utils.js";import{createSummaryPanelEl as yt,buildMetadataStripRow as ei,buildCompactMetadataRows as yn,metadataEntries as wn,renderLotSummaryContent as ti}from"./summaryPanel.js";import{renderLotSummaryReportHtml as ni}from"../stats/renderSummaryReport.js";import{prettyKey as oi}from"../stats/facets.js";import{mergeTestDefs as ii}from"../stats/mergeTestDefs.js";import{getDieKey as li,hasPosition as ai}from"../core/dies.js";function ne(f){const C=new Set;return f.filter(p=>C.has(p.bin)?!1:(C.add(p.bin),!0))}const wt=12;function si(f,C,p){let P=C;if(C.length>wt){const v=C.slice(0,wt-1),T=C.slice(wt-1),oe=T.reduce((Je,re)=>Je+re.count,0);P=[...v,{color:m.label,count:oe,label:`Other (${T.length} bins)`}]}const F=f.createElement("div");Object.assign(F.style,{display:"flex",width:"100%",height:"8px",borderRadius:V.control,overflow:"hidden",border:`1px solid ${m.menuBorder}`,boxSizing:"border-box",marginTop:x.xs,flexShrink:"0"}),F.setAttribute("role","img"),F.setAttribute("aria-label",`Population split: ${P.map(v=>`${v.label} ${Qe(v.count/p*100)}`).join(", ")}`);for(const v of P){const T=v.count/p*100,oe=f.createElement("div");Object.assign(oe.style,{flex:`${T} 1 0`,minWidth:T>0?"2px":"0",background:v.color}),pn(oe,`${v.label} \xB7 ${v.count.toLocaleString()} dies \xB7 ${Qe(T)}`),F.appendChild(oe)}return F}function Qe(f){return f>0&&f<.1?"<0.1%":`${f.toFixed(1)}%`}function xn(f,C){const p=new Map;let P=0;for(const F of f)for(const v of F.dies){if(v.partial||v.edgeExcluded)continue;const T=C(v);T!==void 0&&(p.set(T,(p.get(T)??0)+1),P++)}return{counts:p,total:P}}function vn(f,C){const p=f.ownerDocument.createElement("div");Object.assign(p.style,{display:"flex",alignItems:"center",gap:"5px",cursor:"pointer",userSelect:"none",padding:`${x.xxs} ${x.xs}`,borderRadius:V.control});const P=f.ownerDocument.createElement("span");Object.assign(P.style,{display:"inline-block",width:"13px",height:"13px",flexShrink:"0",background:C.color,border:C.isActive?`2px solid ${m.iconActive}`:`1px solid ${m.menuBorder}`,borderRadius:V.control,boxSizing:"border-box"});const F=f.ownerDocument.createElement("span");if(F.textContent=C.label,Object.assign(F.style,{fontWeight:C.isActive?"700":"400",color:C.isActive?m.iconActive:m.text,whiteSpace:"nowrap"}),p.appendChild(P),p.appendChild(F),C.count!==void 0){const v=f.ownerDocument.createElement("span");if(v.textContent=C.count.toLocaleString(),Object.assign(v.style,{color:C.isActive?m.iconActive:m.text,fontWeight:C.isActive?"700":"400",whiteSpace:"nowrap"}),p.appendChild(v),C.percent!==void 0){const T=f.ownerDocument.createElement("span");T.textContent=Qe(C.percent),Object.assign(T.style,{color:m.label,whiteSpace:"nowrap"}),p.appendChild(T)}}p.setAttribute("role","button"),p.setAttribute("aria-pressed",C.isActive?"true":"false"),p.tabIndex=0,p.addEventListener("mouseenter",()=>{p.style.background=m.bgHover}),p.addEventListener("mouseleave",()=>{p.style.background="transparent"}),p.addEventListener("focus",()=>{p.style.background=m.bgHover}),p.addEventListener("blur",()=>{p.style.background="transparent"}),p.addEventListener("click",C.onClick),p.addEventListener("keydown",v=>{(v.key==="Enter"||v.key===" ")&&(v.preventDefault(),C.onClick())}),f.appendChild(p)}export function renderWaferGallery(f,C,p={}){zo();const P=p.cardPadding??6,F=p.downloadFilename??"wafer-gallery";let v=p.columns;const T=p.showPlotModeSelector??!0,oe=p.showHelpButton??!1,Je=p.userGuideExtension,re=p.insights?.enabled??!1,Cn=So(p.zIndex),de=p.summaryPanel,ye=p.passBins??[1];let Ie=p.fallbackFormat,H=p.lotStatsSummary,we=p.legendPosition??"default",Ae=p.perCardLegend??!1;function xe(){const e=d.plotMode??"hardBin";return sn.has(e)?null:d.colorbarRangeMode==="data"?"Each map has its own value range, so it keeps its own colour bar":"These wafers have no shared colour bar for value mode, so each map keeps its own"}function xt(){const e=Ae||xe()!==null;for(const t of S)t&&t.setOptions({showLegend:e})}let d={plotMode:"hardBin",showDieLabels:!1,showRingBoundaries:!1,showQuadrantBoundaries:!1,ringCount:4,rotation:0,flipX:!1,flipY:!1,...p.viewOptions},S=[],ie=[],ce=[],L=[],w=C.map(e=>typeof e=="function"?null:e);function vt(){return ii(w)}function fe(){if(w.some(e=>e?.testDefs?.length))return vt().defs}let et=0,Pe=0;const z=new Map;let Sn=0,A=null,ve=null,Ct=new Set,h=null,Mn={};function St(e){return w[e]?.statsSummary??H?.perWafer.find(t=>t.waferIndex===e)?.summary}function tt(){return!!(w.some(e=>e?.statsSummary?.findings.length)||H?.perWafer.some(e=>e.summary.findings.length))}const Dn=Mo(),ue=Do(Dn),{makeBtn:Z,setActive:Ce,makeSep:N,makeMenuRow:kn,makeMenuSection:En,makeDropdown:Mt,closeOpenMenu:Fe,getOpenMenu:Se,setOpenMenu:Me}=ue;f.ownerDocument.addEventListener("click",Fe,!0);const Dt=()=>dn();window.addEventListener("blur",Dt);let kt=p.findingsNotice;function Et(e){Ct=new Set(e);const t=[...I.querySelectorAll(".wmap-gallery-card")];let n;t.forEach((o,c)=>{const l=Ct.has(c);o.style.outline=l?`3px solid ${m.findingHighlight}`:"",o.style.outlineOffset=l?"-3px":"",l&&n===void 0&&(n=o)}),n?.scrollIntoView?.({behavior:"smooth",block:"nearest"})}function Bt(){Et([])}function Ot(){for(const e of S)e&&e.clearSelection()}function nt(e,t){const n=new Set(e),o=t??S.map((c,l)=>l);for(const c of o){const l=L[c],a=S[c];if(!l||!a)continue;const s=l.dies.filter(i=>n.has(li(i)));a.setSelection(s)}}function Bn(){const e=[];for(let t=0;t<w.length;t++){const n=w[t];if(!n)continue;const o=St(t)?.findings??[];o.length&&e.push({index:t,item:n,unusualCount:o.filter(c=>c.severity==="unusual").length,notableCount:o.filter(c=>c.severity==="notable").length,totalCount:o.length})}return e}function On(e){const t=L[e]??w[e];t&&Te(e,t)}function Tn(e){const t=St(e)?.findings??[];if(t.length)return{total:t.length,unusual:t.filter(n=>n.severity==="unusual").length,notable:t.filter(n=>n.severity==="notable").length}}function Ln(){const e=ne(w.flatMap(n=>n?.hbinDefs??[])),t=ne(w.flatMap(n=>n?.sbinDefs??[]));To(ni({items:w.map((n,o)=>({label:n?.label??`W${o+1}`,wafer:n?.wafer,dies:n?.dies,statsSummary:n?.statsSummary})),hbinDefs:e.length?e:void 0,sbinDefs:t.length?t:void 0,testDefs:fe(),passBins:ye,ringCount:d.ringCount}),{anchor:f})}function $n(){if(!h)return;h.innerHTML="";const e=Bn();if(w.length>0){const n=f.ownerDocument.createElement("div"),o=e.length,c=w.filter(Boolean).length;n.textContent=o===0?`No findings on any of the ${c} wafers`:`${o} of ${c} wafer${c===1?"":"s"} with findings`,Object.assign(n.style,{fontSize:O.body,color:m.label,marginBottom:x.md}),h.appendChild(n)}if(e.length>0){const n=f.ownerDocument.createElement("button");n.type="button",n.textContent="Summary report",Object.assign(n.style,{...xo("outlined"),marginBottom:x.lg,display:"block",width:"100%",textAlign:"left"}),mt(n),n.addEventListener("click",Ln),h.appendChild(n)}if(e.length===0){const n=f.ownerDocument.createElement("div");Object.assign(n.style,{color:m.icon,fontSize:O.body,padding:"4px 0"}),n.textContent="No findings on any wafer.",h.appendChild(n)}else for(const{index:n,item:o,unusualCount:c,notableCount:l,totalCount:a}of e){const s=c?"unusual":l?"notable":"info",i=c+l||a,r=f.ownerDocument.createElement("button");r.type="button",Object.assign(r.style,{display:"flex",alignItems:"center",justifyContent:"space-between",width:"100%",padding:"5px 8px",marginBottom:x.xs,border:"none",borderLeft:`3px solid ${an(s)}`,borderRadius:V.control,background:m.bgHover,cursor:"pointer",fontSize:O.body,textAlign:"left",boxSizing:"border-box"}),r.addEventListener("mouseover",()=>{r.style.background=m.bgActive}),r.addEventListener("mouseout",()=>{r.style.background=m.bgHover});const u=f.ownerDocument.createElement("span");u.textContent=o.label??`W${n+1}`,Object.assign(u.style,{color:m.iconHover,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"});const b=f.ownerDocument.createElement("span");b.textContent=String(i),r.setAttribute("aria-label",`${o.label??`W${n+1}`} \u2014 ${i} finding${i===1?"":"s"}${c?`, ${c} unusual`:""} \u2014 view wafer`),Object.assign(b.style,{marginLeft:x.sm,flexShrink:"0",background:an(s),color:"#fff",borderRadius:V.container,padding:"1px 5px",fontSize:O.body,fontWeight:"600"}),r.appendChild(u),r.appendChild(b),r.addEventListener("click",()=>Te(n,o)),h.appendChild(r)}const t=f.ownerDocument.createElement("div");t.style.height="12px",h.appendChild(t)}function j(){if(h)if(H){const e=ne(w.flatMap(n=>n?.hbinDefs??[])),t=ne(w.flatMap(n=>n?.sbinDefs??[]));ti(h,{lotSummary:H,items:w,hbinDefs:e.length?e:void 0,sbinDefs:t.length?t:void 0,testDefs:fe(),passBins:ye,ringCount:d.ringCount,binColors:d.binColors,plotMode:d.plotMode??"hardBin",fallbackFormat:Ie,activeFindingId:ve,warnings:p.warnings?.display??!0?Y:[],findingsFilter:Mn,findingsNotice:kt,onFindingsFilterChange:j,onSaveText:p.onSaveText,onFindingClick:(n,o)=>{ve===n.id?ot():Rn(n,o),j()},onWaferClick:On,findingsFor:Tn,dieListOptions:p.dieList})}else $n()}function Wn(e){const t=e.highlight;return t?.kind==="wafer"&&t.waferIndices?.length?t.waferIndices:null}function Tt(e){return[e.variable.kind,e.variable.index??"",e.variable.bin??"",e.comparison.family,e.comparison.left,e.effect.direction].join("|")}let He=[];function Lt(){if(He.length!==0){for(const e of He)S[e]?.setOptions({plotMode:d.plotMode,activeTest:d.activeTest});He=[]}}function ot(){ve=null,Bt(),Ot(),Lt(),B({highlightBin:void 0},{fireCallback:!1})}function Rn(e,t){if(ve===e.id){ot();return}ve=e.id,t.style.background=m.bgActive,t.style.fontWeight="600",Lt();const{kind:n,index:o}=e.variable;if(n==="test"){const l=o??0,a=fe();if(a===void 0||a.some(i=>i.testNumber===l))B({plotMode:"value",activeTest:l,highlightBin:void 0},{fireCallback:!1});else{B({highlightBin:void 0},{fireCallback:!1});const r=be.has(d.plotMode??"hardBin")?null:Wn(e);if(r){for(const u of r)S[u]?.setOptions({plotMode:"value",activeTest:l});He=[...r]}}}else n==="softBin"?B({plotMode:"softBin",highlightBin:void 0},{fireCallback:!1}):B({plotMode:"hardBin",highlightBin:void 0},{fireCallback:!1});Bt(),Ot();const c=e.highlight;if(c.kind==="wafer"){Et(c.waferIndices);const l=Tt(e);for(const a of c.waferIndices){const r=L[a]?.statsSummary?.findings.find(u=>Tt(u)===l)?.highlight?.dieKeys;r?.length&&nt(r,[a])}}else c.kind==="bin"?c.dieKeys?.length&&nt(c.dieKeys):(c.kind==="region"||c.kind==="dies")&&c.dieKeys?.length&&nt(c.dieKeys)}function le(){if(!A)return;const e=!!h;A.style.display=(H||tt())&&e&&!Ee?"flex":"none";const t=h?h.style.display!=="none":!1;(H?.hasNotableFindings||w.some(o=>o?.statsSummary?.hasNotableFindings))&&!t?A.style.color=m.findingIndicator:A.dataset.active||(A.style.color=m.icon)}const R=f.ownerDocument.createElement("div");R.dataset.wmapToolbar="gallery",Object.assign(R.style,{flexShrink:"0",marginLeft:"auto",display:"inline-flex",flexDirection:"row",alignItems:"center",gap:"0",background:m.menuBg,border:`1px solid ${m.menuBorder}`,borderRadius:V.control,padding:"0",boxShadow:We.panel,flexWrap:"wrap",minWidth:"0",overflowX:"auto"});const $t=()=>{const e=Se();e&&(e.remove(),Me(null)),Re(K,!1)},K=Z("mode","Plot mode",()=>{if(Se()){$t();return}const e=w.flatMap(y=>y?.dies??[]),t=fe(),{testEntries:n,binEntries:o,stackedEntries:c}=No(e,t,{includeStacked:!0}),l=w.filter(Boolean).length,a=y=>{if(y===void 0)return l;let $=0;for(const se of w)se?.dies?.some(X=>hn(X,y)!==void 0||X.testValues?.[y]!==void 0)&&$++;return $},s=l<2?n:n.map(y=>{const $=a(y.activeTest);return $===l?y:{...y,label:`${y.label} \u2014 ${$} of ${l} wafers`}}),i=d.plotMode??"hardBin",r=d.activeTest??0;function u(y){return y.plotMode!==i?!1:y.plotMode==="value"?r===(y.activeTest??0):y.plotMode==="metadata"?d.activeMetadataKey===y.activeMetadataKey:!0}function b(y,$){y.activeTest!==void 0?B({plotMode:"value",activeTest:y.activeTest,activeMetadataKey:void 0,logScale:y.logScale}):y.activeMetadataKey!==void 0?B({plotMode:y.plotMode,activeTest:void 0,activeMetadataKey:y.activeMetadataKey,passFailDisplay:"off"}):B({plotMode:y.plotMode,activeTest:void 0,activeMetadataKey:void 0,passFailDisplay:"off"}),$.remove(),Me(null),Re(K,!1)}const M=new Set,k=w.flatMap(y=>y?.metadataFields??[]).filter(y=>!M.has(y.key)&&M.add(y.key)).filter(y=>_o(e,y.key)).map(Go),D=ko(K.getBoundingClientRect(),s,o,c,u,b,{makeMenuRow:kn,makeMenuSection:En},i,K.ownerDocument.defaultView??window,k);cn(K).appendChild(D),Me(D),Re(K,!0),fn(D,K,$t)});Re(K,!1);const In=()=>L.flatMap(e=>e?[...e.hbinDefs??[],...e.sbinDefs??[]]:[]).some(e=>e.color),{btn:An,sync:Wt}=Ro(ue,()=>({...d,plotMode:d.plotMode??"hardBin"}),In,e=>B(e));Wt();const Pn=C.some(e=>typeof e!="function"&&(e.reticles?.length??0)>0);function je(){const e=fe(),{testNumber:t}=co(d.activeTest??0,e);return{testNumber:t,td:fo(e,t)}}function Rt(){if((d.plotMode??"hardBin")!=="value")return!1;const{td:e}=je();return e!==void 0&&(e.limitLow!==void 0||e.limitHigh!==void 0)}function De(){if((d.plotMode??"hardBin")!=="value")return!1;const{td:e}=je();return e!==void 0&&!bt(e)}function Fn(){if((d.plotMode??"hardBin")!=="value")return!1;const{testNumber:e,td:t}=je();return w.some(n=>n?.dies?.some(o=>hn(o,e,t)!==void 0))}function Hn(e,t){if(!t||!bt(t))return;const n=t.limitLow!==void 0||t.limitHigh!==void 0;if((gn(d)==="spec"&&n?"spec":d.colorbarRangeMode??"spec")==="spec"&&n)return;let l=1/0,a=-1/0;for(const s of w)if(s)for(const i of s.dies){const r=Zo(i,e);r!==void 0&&(r<l&&(l=r),r>a&&(a=r))}if(isFinite(l))return l===a?[l,l+1]:[l,a]}function It(){if((d.plotMode??"hardBin")!=="metadata")return;const e=d.activeMetadataKey;if(!e)return;const t=new Set;for(const n of w)if(n)for(const o of uo(n.dies,e))t.add(o);return{key:e,values:[...t].sort(bn)}}function it(){const e=It();if(!(e===void 0&&d.metadataValueOrder===void 0)){d={...d,metadataValueOrder:e};for(const t of S)t&&t.setOptions({metadataValueOrder:e})}}function lt(){if((d.plotMode??"hardBin")!=="value")return;const{testNumber:e,td:t}=je(),n=Hn(e,t),o=n?{test:e,range:n}:void 0;d={...d,valueRange:o};for(const c of S)c&&c.setOptions({valueRange:o})}let at=!1;function jn(){if(at)return;at=!0,(f.ownerDocument.defaultView?.requestAnimationFrame??(t=>setTimeout(()=>t(0),0)))(()=>{at=!1,lt(),it(),At()})}function Ve(){const e=ne(w.flatMap(o=>o?.hbinDefs??[])),t=ne(w.flatMap(o=>o?.sbinDefs??[]));function*n(){for(const o of w)o&&(yield*o.dies)}return go(n(),{passBins:ye,binColorScheme:d.binColorScheme,useDefinedBinColors:d.useDefinedBinColors,hbinDefs:e,sbinDefs:t})}function At(){const e=Ve();d={...d,binColors:e};for(const t of S)t&&t.setOptions({binColors:e})}const Vn=Po(ue,()=>jo(d,Pn,{functionalActive:De(),hasLimits:Rt()&&!De(),hasRecorded:Fn()&&!De(),binMode:(d.plotMode??"hardBin")==="hardBin"||(d.plotMode??"hardBin")==="softBin"},e=>B(e)),()=>Vo(d)),{btn:zn,sync:Pt}=Ao(ue,()=>({plotMode:d.plotMode,legendPosition:we}),e=>{we=e;for(const t of S)t&&t.setOptions({legendPosition:we})},{get:()=>Ae,set:e=>{Ae=e,xt()},blockedReason:xe});Pt();const Nn=[{value:"mean",label:"Mean"},{value:"median",label:"Median"},{value:"stddev",label:"Std Dev"},{value:"min",label:"Min"},{value:"max",label:"Max"},{value:"count",label:"Count"}],Ft=Mt("aggr","Aggregation method",()=>Nn,()=>d.aggregationMethod??"mean",e=>B({aggregationMethod:e}));function Ht(){const e=d.plotMode==="stackedValues";Ft.style.display=e?"":"none"}Ht();const{btn:_n,sync:jt}=Io(ue,()=>({...d,functionalActive:De()}),e=>B(e));jt();const ze=Z("specRange","Colorbar range: spec limits",()=>{const e=d.colorbarRangeMode==="data"?"spec":"data";B({colorbarRangeMode:e})});function Vt(){const e=(d.plotMode??"hardBin")==="value"&&Rt()&&gn(d)==="off"&&!De();ze.style.display=e?"":"none";const t=(d.colorbarRangeMode??"spec")==="spec";Ce(ze,t),ze.ariaLabel=t?"Colorbar range: spec limits (click for data range)":"Colorbar range: data range (click for spec limits)"}Vt();const Gn=Fo(ue,()=>d,e=>B(e)),Kn=Z("downloadAll","Download gallery PNG",ao),qn=Mt("columns","Columns",()=>[{value:"auto",label:"Auto"},{value:"1",label:"1 column"},{value:"2",label:"2 columns"},{value:"3",label:"3 columns"},{value:"4",label:"4 columns"},{value:"5",label:"5 columns"}],()=>v!=null?String(v):"auto",e=>Yt(e==="auto"?void 0:Number(e))),E=f.ownerDocument.createElement("div");Object.assign(E.style,{display:"inline-flex",alignItems:"center",gap:"0"}),R.appendChild(E),T&&E.appendChild(K),E.appendChild(An),E.appendChild(Ft),E.appendChild(_n),E.appendChild(ze),E.appendChild(N()),E.appendChild(Vn),E.appendChild(N()),E.appendChild(zn),E.appendChild(N()),E.appendChild(Gn),E.appendChild(N()),E.appendChild(qn),E.appendChild(N()),E.appendChild(Kn),(H||tt())&&(A=Z("findings","Summary panel",()=>{if(!h)return;const e=h.style.display!=="none";e||j(),h.style.display=e?"none":"flex",Ce(A,!e),le()}),R.appendChild(N()),R.appendChild(A));let _=null,Ne=null,Y=[],zt=!1;function _e(){const e=Yo({lotStatsSummary:H,result:{warnings:[...w.flatMap(n=>n?.warnings??[]),...vt().warnings]},extra:[d.binColors&&mo(d.binColors,d.plotMode)].filter(n=>!!n)}),t=e.length!==Y.length||e.some((n,o)=>n.code!==Y[o]?.code||n.message!==Y[o]?.message);Y=e,(t||!zt)&&(zt=!0,p.warnings?.onWarning?.(e)),Un()}function Un(){if(!_||!Ne)return;const e=Y.length,t=e>0;if(_.style.display=t?"flex":"none",Ne.style.display=t?"":"none",!t)return;const n=Jo(Y[0]),o=`${e} data ${e===1?"warning":"warnings"}`;_.style.color=n==="error"?m.errText:m.warnText,_.ariaLabel=n==="error"?`${o} \u2014 some wafers may be positionally wrong`:o}(p.warnings?.display??!0)&&(Ne=N(),_=Z("warning","Data warnings",()=>{const e=Se();if(Fe(new MouseEvent("click")),e)return;const t=Qo(_.getBoundingClientRect(),Y,_.ownerDocument.defaultView??window);cn(f).appendChild(t),Me(t),fn(t,_,()=>Fe(new MouseEvent("click")))}),Re(_,!1),R.appendChild(Ne),R.appendChild(_)),_e();let ae=null;re&&(ae=Z("analysis","Insights",()=>{Gt(!Ee)}),ae.dataset.wmapInsightsBtn="1",R.appendChild(N()),R.appendChild(ae));function Nt(){import("./userGuideHtml.js").then(e=>Wo({buildWaferMap:Xo,renderWaferMap:ht,renderWaferGallery,analyzeWaferMap:Ye},e.USER_GUIDE_HTML,Je,f))}oe&&(R.appendChild(N()),R.appendChild(Z("help","User guide",()=>Nt())));const pe=f.ownerDocument.createElement("div");pe.dataset.wmapGalleryMeta="1",Object.assign(pe.style,{flex:"1",minWidth:"0",overflow:"hidden",display:"flex",alignItems:"center",padding:`${x.sm} ${x.lg}`,fontSize:O.sub,lineHeight:Ze.none,boxSizing:"border-box"});const Ge=f.ownerDocument.createElement("div");Object.assign(Ge.style,{background:m.canvasBg,display:"flex",alignItems:"stretch",gap:x.lg,paddingBottom:x.lg,minWidth:"0"});const Q=f.ownerDocument.createElement("div");Q.dataset.wmapGalleryLegend="1",Object.assign(Q.style,{display:"flex",flexDirection:"column",gap:x.sm,background:m.menuBg,border:`1px solid ${m.menuBorder}`,borderRadius:V.container,padding:`${x.sm} ${x.lg}`,marginBottom:x.lg,boxShadow:We.panel,fontSize:O.body,lineHeight:Ze.none,boxSizing:"border-box",width:"100%",minWidth:"0"});const G=f.ownerDocument.createElement("div");Object.assign(G.style,{display:"flex",flexDirection:"row",alignItems:"flex-start"});let ge=null,ke=null,_t=null;function Xn(){return re?ge?Promise.resolve(ge):(_t??=import("./insightsTab.js").then(({createInsightsTab:e})=>(ge=e({getItems:()=>w,getLotStats:()=>H,getBinColors:()=>d.binColors??Ve(),passBins:ye,getRingCount:()=>d.ringCount??4,defaultView:p.insights?.defaultView,onOpenGuide:void 0,showMetadataStrip:!1,onSaveImage:p.onSaveImage,onSaveText:p.onSaveText,ownerDocument:f.ownerDocument,openWafer:(t,n,o)=>{const c=w[t];if(!c)return;let l=null;const a=Oo({title:n,onClose:()=>l?.destroy(),anchor:f});en(a,n,c.wafer.metadata??void 0),l=ft(a.contentWrap,c,o)}}),ke=ge.el,ke.style.display="none",f.appendChild(ke),ge)),_t):Promise.resolve(null)}let Ee=!1;function Gt(e){re&&(Ee=e,ke&&(ke.style.display=e?"flex":"none"),G.style.display=e?"none":"flex",E.style.display=e?"none":"inline-flex",R.style.display="inline-flex",ae&&(Ce(ae,e),ae.innerHTML=e?$e.wafer:$e.analysis,ae.ariaLabel=e?"Back to gallery view":"Insights"),le(),Ue(),e&&Xn().then(t=>{!t||!Ee||(t.el.style.display="flex",t.render())}))}re&&p.insights?.defaultOpen&&queueMicrotask(()=>Gt(!0));const Zn=4,st=240,Kt=480,Yn=720,Qn=1.25,qt=p.maxSize;let q=qt??Kt;function Ut(e){const t=P*2+110+2;let n=null;for(const o of e){if(o==null||!o.dies?.length)continue;const c=o.dies[0].width;if(!(c>0))continue;const l=o.wafer.radius*2*(Zn/c),a=Math.ceil(l+t);(n==null||a>n)&&(n=a)}return n}function Jn(e){const t=Ut(e);return t==null?st:Math.min(q,Math.max(st,t))}function eo(e){if(qt!=null)return!1;const t=Ut(e);if(t==null)return!1;const n=Math.min(Yn,Math.max(Kt,t));return n<=q?!1:(q=n,!0)}function to(){for(const e of Array.from(I.children))e.classList.contains("wmap-gallery-card")&&(e.style.maxWidth=`${q}px`,e.style.maxHeight=`${q}px`)}let Ke=st,Xt=0;function Zt(e){const t=eo(e);if(t&&to(),v!=null){t&&qe();return}const n=Jn(e);n>Ke&&(Ke=n),qe()}function Yt(e){v=e,qe()}function rt(e){return`repeat(${e}, minmax(0, ${q}px))`}function Qt(e){I.style.gridTemplateColumns!==e&&(I.style.gridTemplateColumns=e)}function qe(){if(v!=null){Qt(rt(v));return}const e=Math.max(1,Xt),t=12,n=I.clientWidth||0,o=l=>(n-t*(l-1))/l;let c=Math.max(1,Math.ceil(Math.sqrt(e)));if(n>0){const l=Math.min(q,Ke*Qn),a=s=>{let i=0;for(;i<e&&o(i+1)>=s;)i++;return i};c=a(l)||a(Ke)||1}Qt(rt(c))}const I=f.ownerDocument.createElement("div");if(Object.assign(I.style,{flex:"1 1 0",minWidth:"0",display:"grid",gridTemplateColumns:rt(1),gap:x.xl,paddingLeft:te,paddingRight:te,justifyContent:"start",alignContent:"start",isolation:"isolate"}),de?.placement){const e=de.placement;h=yt(e,te,f.ownerDocument),h.style.maxHeight="calc(100vh - 80px)",h.style.position="sticky",h.style.top="8px",h.style.display="flex",h.style.flexDirection="column"}else if(H||tt()){const e=!!de?.defaultOpen;h=yt("right",te,f.ownerDocument),h.style.maxHeight="calc(100vh - 80px)",h.style.position="sticky",h.style.top="8px",h.style.flexDirection="column",h.style.display=e?"flex":"none",j()}le(),h?.style.display!=="none"&&A&&Ce(A,!0),(de?.placement??"right")==="left"?(h&&G.appendChild(h),G.appendChild(I)):(G.appendChild(I),h&&G.appendChild(h));const Be=f.ownerDocument.createElement("div");Object.assign(Be.style,{position:"sticky",top:"0",display:"flex",flexDirection:"column",paddingLeft:te,paddingRight:te,paddingTop:te,zIndex:"1",background:m.menuBg}),Ge.appendChild(pe),Ge.appendChild(R),Be.appendChild(Ge),Be.appendChild(Q),f.appendChild(Be),f.appendChild(G);function Ue(){Q.innerHTML="";const e=d.plotMode??"hardBin",t=!Ee&&sn.has(e),n=L.filter(g=>g!=null),o=n.find(g=>g.isLotStack),c=ei(n.map(g=>({metadata:g.wafer.metadata??void 0})),o?{lotSize:o.lotSize??n.length,aggrMethod:o.aggrMethod}:void 0),l=e==="metadata",a=d.activeMetadataKey,s=t&&!l?xn(n,g=>(e==="softBin"?g.sbin:g.hbin)??void 0):{counts:new Map,total:0},i=[...s.counts.keys()].sort((g,W)=>g-W),r=t&&l&&a?xn(n,g=>po(g.metadata?.[a])):{counts:new Map,total:0},u=l?It()?.values:void 0,b=t&&l?(u??[...r.counts.keys()].sort(bn)).filter(g=>r.counts.has(g)):[];if(pe.innerHTML="",c&&pe.appendChild(c),pe.style.display=c?"flex":"none",!i.length&&!b.length){Q.style.display="none";return}Q.style.display="flex";const M=f.ownerDocument.createElement("div");Object.assign(M.style,{display:"flex",flexWrap:"wrap",alignItems:"center",gap:`${x.sm} ${x.xl}`,maxHeight:"86px",overflowY:"auto",overflowX:"hidden"}),Q.appendChild(M);const k=d.highlightBin,D=L.flatMap(g=>g?.metadataFields??[]).find(g=>g.key===a),y=l?D?.label??(a?oi(a):"Metadata"):Co[e],$=f.ownerDocument.createElement("span");if($.textContent=y,Object.assign($.style,{fontSize:O.body,fontWeight:"700",letterSpacing:wo,textTransform:"uppercase",color:m.label,flexShrink:"0"}),M.appendChild($),!l&&s.total>0){const g=ye.reduce((he,pt)=>he+(s.counts.get(pt)??0),0),W=g/s.total*100,J=f.ownerDocument.createElement("span");J.textContent=`Yield ${Qe(W)}`,Object.assign(J.style,{fontSize:O.body,fontWeight:"700",color:m.value,whiteSpace:"nowrap",flexShrink:"0"});const ee=f.ownerDocument.createElement("span");ee.textContent=`${g.toLocaleString()} / ${s.total.toLocaleString()} dies`,Object.assign(ee.style,{fontSize:O.body,color:m.label,whiteSpace:"nowrap",flexShrink:"0"}),M.appendChild(J),M.appendChild(ee)}if(l){const g=d.highlightMetadataValue;b.forEach((W,J)=>{const ee=g===W,he=D?.values?.find(gt=>gt.value===W),pt=he?.color??bo(J),ln=r.counts.get(W)??0;vn(M,{color:pt,isActive:ee,label:he?.label??W,count:ln,percent:r.total>0?ln/r.total*100:void 0,onClick:()=>{const gt=d.highlightMetadataValue===W?void 0:W;B({highlightMetadataValue:gt})}})});return}const se=e==="softBin"?L.flatMap(g=>g?.sbinDefs??[]):L.flatMap(g=>g?.hbinDefs??[]),X=new Set,Le=[];for(const g of se)X.has(g.bin)||(X.add(g.bin),Le.push(g));const ut=Le.length>0?new Map(Le.map(g=>[g.bin,g])):null,nn=d.binColors??Ve(),so=e==="softBin"?nn.soft:nn.hard,on=g=>so.get(g)??ho;for(const g of i){const W=k===g,J=ut?.get(g),ee=s.counts.get(g)??0;vn(M,{color:on(g),isActive:W,label:J?.name?`${g} \xB7 ${J.name}`:`Bin ${g}`,count:ee,percent:s.total>0?ee/s.total*100:void 0,onClick:()=>{const he=d.highlightBin===g?void 0:g;B({highlightBin:he})}})}s.total>0&&i.length>1&&Q.appendChild(si(f.ownerDocument,[...s.counts.entries()].sort(([,g],[,W])=>W-g).map(([g,W])=>({color:on(g),count:W,label:ut?.get(g)?.name?`${g} \xB7 ${ut.get(g).name}`:`Bin ${g}`})),s.total))}function Oe(e){const t=w.filter(s=>s!==null);if(!t.length)return[];const n=t.map(s=>s.dies.filter(ai)),o=t[0].wafer,c=t.length,l=o.metadata?{...o,metadata:(({wafer:s,waferId:i,...r})=>r)(o.metadata)}:o;function a(s,i){return{...s,stats:{...s.stats,isLotStack:!0,aggregationMethod:i,lotSize:c}}}if(e==="stackedValues"){const s=fe();let i=s?.filter(bt);if(s!==void 0&&i?.length===0)return[];if(s?.length||(i=ro(t.flatMap(b=>b.dies)).map(b=>({testNumber:b,name:`Test ${b}`}))),!i?.length)return[];const r=d.aggregationMethod??"mean";return i.map(u=>{const b=Ko(n,r,u.testNumber),M={testNumber:0,name:u.name,unit:u.unit};return{wafer:l,dies:b,testDefs:[M],label:`${u.name} \xB7 ${r}`,isLotStack:!0,aggrMethod:r,lotSize:c,statsSummary:a(Ye({wafer:l,dies:b,testDefs:[M]},{testNumbers:[0]}),r)}})}if(e==="stackedBins"){let s=ne(t.flatMap(i=>i.hbinDefs??[]));return(!s||s.length===0)&&(s=[...new Set(t.flatMap(r=>r.dies.map(u=>u.hbin).filter(u=>u!=null)))].sort((r,u)=>r-u).map(r=>({bin:r,name:`Bin ${r}`}))),s.map(i=>{const r=mn(n,i.bin,"hard"),u=[{bin:i.bin,name:i.name}];return{wafer:l,dies:r,hbinDefs:u,label:`${i.bin} \xB7 ${i.name}`,isLotStack:!0,aggrMethod:"countBin",lotSize:c,statsSummary:a(Ye({wafer:l,dies:r,hbinDefs:u}),"countBin")}})}if(e==="stackedSoftBins"){let s=ne(t.flatMap(i=>i.sbinDefs??[]));return(!s||s.length===0)&&(s=[...new Set(t.flatMap(r=>r.dies.map(u=>u.sbin).filter(u=>u!=null)))].sort((r,u)=>r-u).map(r=>({bin:r,name:`Bin ${r}`}))),s.map(i=>{const r=mn(n,i.bin,"soft"),u=[{bin:i.bin,name:i.name}];return{wafer:l,dies:r,sbinDefs:u,label:`${i.bin} \xB7 ${i.name}`,isLotStack:!0,aggrMethod:"countBin",lotSize:c,statsSummary:a(Ye({wafer:l,dies:r,sbinDefs:u}),"countBin")}})}return t}function dt(e){const t=w.length;return e==="stackedBins"||e==="stackedSoftBins"?{valueRange:[0,t],lotSize:t}:e==="stackedValues"?{aggregationMethod:d.aggregationMethod??"mean",valueRange:void 0,lotSize:void 0}:{}}function B(e,{fireCallback:t=!0}={}){const n=Object.keys(e),o=d.plotMode,c=xe()!==null;d={...d,...e};const l=d.plotMode,a=be.has(l),s=o!==void 0&&be.has(o),i=Pe>0;if("binColorScheme"in e||"useDefinedBinColors"in e){const u=Ve();d={...d,binColors:u},e={...e,binColors:u}}if(e.plotMode!==void 0)if(a){const u=dt(l);if(d={...d,...u},i)for(const b of S)b&&b.setOptions(e);else U(Oe(l))}else if(s){const{valueRange:u,lotSize:b,aggregationMethod:M,...k}=d;if(d=k,i)for(const D of S)D&&D.setOptions(e);else U(w.filter(D=>D!==null))}else for(const u of S)u&&u.setOptions(e);else if(e.aggregationMethod!==void 0&&l==="stackedValues")if(i)for(const u of S)u&&u.setOptions(e);else U(Oe("stackedValues"));else for(const u of S)u&&u.setOptions(e);xe()!==null!==c&&xt(),Ue(),Ht(),Pt(),Wt();const r=e.plotMode!==void 0&&e.plotMode!==o;(Uo.some(u=>u in e)||r)&&j(),_e(),jt(),Vt(),lt(),it(),t&&p.onViewOptionsChange?.(d,n,qo(n))}function Jt(e,t,n){const o=e.createElement("div");Object.assign(o.style,{display:"flex",alignItems:"center",gap:x.xs,flex:"1",minWidth:"0"});const c=e.createElement("span");c.textContent=t,Object.assign(c.style,{fontWeight:"700",fontSize:O.sub,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}),o.appendChild(c);const l=wn(n??{});let a=null;if(l.length>0){const s=e.createElement("span");Object.assign(s.style,{fontSize:O.body,lineHeight:Ze.none,color:m.label,flexShrink:"0"}),s.textContent="\u25BE",o.appendChild(s),Object.assign(o.style,{cursor:"pointer",borderRadius:V.control}),o.addEventListener("mouseenter",()=>{o.style.background=m.bgHover}),o.addEventListener("mouseleave",()=>{o.style.background="none"}),a=e.createElement("div"),a.dataset.wmapCardMetaPanel="1",Object.assign(a.style,{position:"absolute",top:"0",left:"0",right:"0",zIndex:rn,background:m.menuBg,borderBottom:`1px solid ${m.menuBorder}`,boxShadow:We.menu,padding:`${x.md} ${x.lg}`,fontSize:O.body,display:"none"});const i=yn(n??{});i&&a.appendChild(i),o.setAttribute("aria-expanded","false"),o.setAttribute("aria-label",`Wafer info for ${t||"this card"}. Click to expand.`),un(o,r=>{s.textContent=r?"\u25B4":"\u25BE",o.setAttribute("aria-expanded",String(r)),a&&(a.style.display=r?"block":"none")})}return{wrap:o,metaPanel:a}}function en(e,t,n){const o=e.box.querySelector("[data-wmap-window-title]"),c=wn(n??{});if(!o||c.length===0)return;const l=o.parentElement,a=f.ownerDocument.createElement("div");Object.assign(a.style,{display:"flex",alignItems:"center",gap:x.xs,flex:"1",minWidth:"0",cursor:"pointer"}),mt(a,"bare"),l?.insertBefore(a,o),a.appendChild(o);const s=f.ownerDocument.createElement("span");Object.assign(s.style,{fontSize:O.body,lineHeight:Ze.none,color:m.label,flexShrink:"0"}),s.textContent="\u25BE",a.appendChild(s);const i=f.ownerDocument.createElement("div");i.dataset.wmapCardMetaPanel="1",Object.assign(i.style,{position:"absolute",top:"0",left:"0",right:"0",zIndex:rn,background:m.menuBg,borderBottom:`1px solid ${m.menuBorder}`,boxShadow:We.menu,padding:`${x.md} ${x.lg}`,fontSize:O.body,display:"none"});const r=yn(n??{});r&&i.appendChild(r),e.contentWrap.style.position="relative",e.contentWrap.appendChild(i),a.setAttribute("aria-expanded","false"),a.setAttribute("aria-label",`Wafer info for ${t}. Click to expand.`),un(a,u=>{s.textContent=u?"\u25B4":"\u25BE",a.setAttribute("aria-expanded",String(u)),i.style.display=u?"block":"none"})}function ct(e,t,n){const o=f.ownerDocument.createElement("div");o.className="wmap-gallery-card",Object.assign(o.style,{background:m.menuBg,border:`1px solid ${m.menuBorder}`,borderRadius:V.container,boxShadow:We.panel,overflow:"hidden",display:"flex",flexDirection:"column",position:"relative",aspectRatio:"1",maxWidth:`${q}px`,maxHeight:`${q}px`});const c=f.ownerDocument.createElement("div");Object.assign(c.style,{display:"flex",alignItems:"center",padding:`${x.md} ${x.lg} ${x.sm}`,borderBottom:`1px solid ${m.menuBorder}`,flexShrink:"0",gap:x.sm});const{wrap:l,metaPanel:a}=Jt(document,e.label??"",e.wafer.metadata??void 0);c.appendChild(l);const s=f.ownerDocument.createElement("button");s.dataset.wmapExpandBtn="1",s.setAttribute("aria-label","Open full view"),pn(s),s.innerHTML=$e.expand,Object.assign(s.style,{display:"flex",alignItems:"center",justifyContent:"center",border:`1px solid ${m.menuBorder}`,borderRadius:V.control,background:m.panelBg,color:m.label,padding:x.xxs,cursor:"pointer",flexShrink:"0",width:"22px",height:"22px"}),mt(s),c.appendChild(s),o.appendChild(c);const i=f.ownerDocument.createElement("div");Object.assign(i.style,{position:"relative",flex:"1",minHeight:"0",overflow:"hidden",display:"flex",flexDirection:"column"}),o.appendChild(i),a&&i.appendChild(a),I.appendChild(o);const r=Ae||xe()!==null,u=e.viewOptions?{...d,...e.viewOptions}:d,b=ht(i,e,{viewOptions:{...u,showLegend:r},toolbarControls:"full",showTooltip:!0,padding:P,legendPosition:we,fallbackFormat:Ie,statsSummary:e.statsSummary,onSaveImage:p.onSaveImage,onSaveText:p.onSaveText,onClick:e.onClick,onSelect:e.onSelect,onExpand:()=>Te(t,e),showIdentity:!1,chromeInset:vo});return b.setViewControlsVisible(!1),b.setSummaryVisible(!1),s.onclick=()=>Te(t,e),{card:o,ctrl:b,canvasWrapper:i,expandBtn:s}}function no(e){const t=ce[e];if(!t)return;const n=[...z.values()].find(o=>o.cardIndex===e);n?(t.innerHTML=$e.minimize,t.setAttribute("aria-label","Reattach to gallery"),t.onclick=()=>io(n.id)):(t.innerHTML=$e.expand,t.setAttribute("aria-label","Open full view"),t.onclick=()=>Te(e,L[e]))}function U(e){lo(),Se()?.remove(),Me(null),ot(),L=[];for(const l of S)l&&l.destroy();S=[],ie=[],ce=[],Pe=0,I.innerHTML="",Xt=e.length,Zt(e.map(l=>typeof l=="function"?null:l));const t=[];for(let l=0;l<e.length;l++){const a=e[l];if(typeof a=="function"){const s=f.ownerDocument.createElement("div");s.className="wmap-gallery-card",Object.assign(s.style,{background:m.menuBg,border:`1px solid ${m.menuBorder}`,borderRadius:V.container,aspectRatio:"1",display:"flex",alignItems:"center",justifyContent:"center"});const i=f.ownerDocument.createElement("span");i.textContent="\u2026",Object.assign(i.style,{color:m.label,fontSize:"18px"}),s.appendChild(i),I.appendChild(s),L.push(null),S.push(null),ie.push(null),ce.push(null),t.push({index:l,factory:a,placeholder:s}),Pe++}else{const{ctrl:s,canvasWrapper:i,expandBtn:r}=ct(a,l,e.length);L.push(a),S.push(s),ie.push(i),ce.push(r)}}At(),Ue(),lt(),it();const n=++et;let o=0;function c(){if(n!==et)return;if(o>=t.length){if(be.has(d.plotMode)){const k=d.plotMode;U(Oe(k))}return}const{index:l,factory:a,placeholder:s}=t[o++],i=a();L[l]=i,w[l]=i,Zt([i]);const{card:r,ctrl:u,canvasWrapper:b,expandBtn:M}=ct(i,l,e.length);S[l]=u,ie[l]=b,ce[l]=M,Pe--,s.replaceWith(r),Ue(),jn(),!h&&!de?.placement&&i.statsSummary?.findings.length?(h=yt("right",te,f.ownerDocument),h.style.maxHeight="calc(100vh - 80px)",h.style.position="sticky",h.style.top="8px",h.style.flexDirection="column",h.style.display="none",(de?.placement??"right")==="left"?G.insertBefore(h,I):G.appendChild(h),j(),A||(A=Z("findings","Summary panel",()=>{if(!h)return;const D=h.style.display!=="none";D||j(),h.style.display=D?"none":"flex",Ce(A,!D),le()}),R.appendChild(N()),R.appendChild(A)),le()):h&&h.style.display!=="none"&&j(),le(),setTimeout(c,0)}t.length>0&&setTimeout(c,0)}if(be.has(d.plotMode)&&w.length>0){const e=dt(d.plotMode);d={...d,...e},U(Oe(d.plotMode))}else U(C);_e();let me=0;const tn=new(f.ownerDocument.defaultView??window).ResizeObserver(()=>{if(me)return;me=(f.ownerDocument.defaultView??window).requestAnimationFrame(()=>{me=0,v==null&&qe()})});tn.observe(I),h&&j();function oo(e,t){const n=ie[e];if(!n)return;n.innerHTML="",Object.assign(n.style,{alignItems:"center",justifyContent:"center"});const o=f.ownerDocument.createElement("span");o.textContent=t?"Opened in its own window":"Opened in the wafer viewer",Object.assign(o.style,{color:m.label,fontSize:O.body,textAlign:"center",padding:"0 12px"}),n.appendChild(o)}function Te(e,t){for(const a of z.values())if(a.cardIndex===e)return;const n=t.label??"Wafer map",o=Sn++,c=S[e]?.getOptions(),l=Eo(n);if(l){const a=l.document;a.title=n,Object.assign(a.documentElement.style,{height:"100%"}),Object.assign(a.body.style,{margin:"0",height:"100vh",overflow:"hidden",display:"flex",flexDirection:"column",fontFamily:O.family}),Lo(f,a.documentElement);const s=$o(f,a.documentElement,()=>D.setOptions({})),i=a.createElement("div");i.dataset.wmapWindowBanner="1",i.textContent=n,Object.assign(i.style,{display:"none",padding:`${x.sm} ${x.xl}`,fontSize:O.body,fontWeight:"700",background:m.warnBg,color:m.warnText,borderBottom:`1px solid ${m.warnBorder}`,flexShrink:"0"}),a.body.appendChild(i);const r=a.createElement("div");Object.assign(r.style,{flex:"1",minHeight:"0",display:"flex",flexDirection:"column"}),a.body.appendChild(r);const{wrap:u,metaPanel:b}=Jt(a,n,t.wafer.metadata??void 0),M=a.createElement("div");Object.assign(M.style,{display:"flex",alignItems:"center",padding:`${x.md} ${x.lg} ${x.sm}`,borderBottom:`1px solid ${m.menuBorder}`,flexShrink:"0",gap:x.sm}),M.appendChild(u),r.appendChild(M);const k=a.createElement("div");Object.assign(k.style,{position:"relative",flex:"1",minHeight:"0",overflow:"hidden",display:"flex",flexDirection:"column"}),b&&k.appendChild(b),r.appendChild(k);const D=ft(k,t,void 0,c),y=setInterval(()=>{l.closed&&Xe(o)},400);l.addEventListener("pagehide",()=>Xe(o)),z.set(o,{id:o,ctrl:D,cardIndex:e,label:n,closePollId:y,stopThemeSync:s,close:()=>{l.closed||l.close()},setTitle:$=>{a.title=$,i.textContent=$,i.style.display="block"}})}else{const a=Bo({title:n,onClose:()=>Xe(o),anchor:f});a.contentWrap.style.flexDirection="column",en(a,n,t.wafer.metadata??void 0);const s=ft(a.contentWrap,t,void 0,c);z.set(o,{id:o,ctrl:s,cardIndex:e,label:n,closePollId:null,close:()=>a.close(),setTitle:i=>{const r=a.box.querySelector("[data-wmap-window-title]");r&&(r.textContent=i,r.title=i)}})}S[e]?.destroy(),S[e]=null,oo(e,l!==null),no(e)}function ft(e,t,n,o){const c=t.viewOptions?{...d,...t.viewOptions}:d,l=o?{...c,...o}:c,s={...n!==void 0?{...l,plotMode:"value",activeTest:n}:l,showLegend:!0},i=ht(e,t,{viewOptions:s,toolbarControls:"full",showTooltip:!0,padding:P,legendPosition:we,fallbackFormat:Ie,statsSummary:t.statsSummary,onSaveImage:p.onSaveImage,onSaveText:p.onSaveText,onClick:t.onClick,onSelect:t.onSelect,showExpandButton:!1,showIdentity:!1});return i.setViewControlsVisible(!0),i.setSummaryVisible(!0),i.setExpandVisible(!1),i}function Xe(e){const t=z.get(e);if(!t)return;z.delete(e),t.closePollId!=null&&clearInterval(t.closePollId),t.stopThemeSync?.();const n=t.ctrl.getOptions();if(t.ctrl.destroy(),t.cardIndex===null)return;const o=t.cardIndex,c=L[o];if(!c)return;const l={...c,viewOptions:n};L[o]=l;const{card:a,ctrl:s,canvasWrapper:i,expandBtn:r}=ct(l,o,L.length);ie[o]?.parentElement?.replaceWith(a),S[o]=s,ie[o]=i,ce[o]=r}function io(e){const t=z.get(e);t&&(t.close(),Xe(e))}function lo(){for(const e of z.values())e.cardIndex!==null&&(e.cardIndex=null,e.setTitle(`${e.label} \u2014 unlinked from gallery`))}function ao(){const e=[...I.querySelectorAll("canvas")];if(!e.length)return;const t=e.length,n=Math.ceil(Math.sqrt(t)),o=Math.ceil(t/n),c=e[0].width,l=e[0].height,a=8,s=(f.ownerDocument.defaultView??window).devicePixelRatio||1,i=Math.round(26*s),r=Math.round(12*s),u=f.ownerDocument.createElement("canvas");u.width=n*c+(n-1)*a,u.height=o*(l+i)+(o-1)*a;const b=u.getContext("2d"),M=yo(I);b.fillStyle=M.background,b.fillRect(0,0,u.width,u.height),e.forEach((k,D)=>{const y=D%n,$=Math.floor(D/n),se=y*(c+a),X=$*(l+i+a),Le=k.closest(".wmap-gallery-card")?.querySelector("span")?.textContent??"";b.fillStyle=M.surface,b.fillRect(se,X,c,i),b.fillStyle=M.text,b.font=`700 ${r}px system-ui, sans-serif`,b.textAlign="left",b.textBaseline="middle",b.fillText(Le,se+Math.round(10*s),X+i/2,c-Math.round(20*s)),b.drawImage(k,se,X+i)}),u.toBlob(k=>{k&&Ho(k,F,p.onSaveImage)})}return{setItems(e){w=e.map(n=>typeof n=="function"?null:n);const t=d.plotMode;if(be.has(t))if(e.some(o=>typeof o=="function"))U(e);else{const o=dt(t);d={...d,...o},U(Oe(t))}else U(e)},setOptions(e){B(e,{fireCallback:!1})},getOptions(){return{...d}},setFallbackFormat(e){Ie=e;for(const t of S)t&&t.setFallbackFormat(e)},setFindingsNotice(e){kt=e,j()},setLotStatsSummary(e){H=e,_e(),h&&j(),le()},setColumns(e){Yt(e)},openUserGuide:Nt,destroy(){et++;for(const e of[...z.values()])e.closePollId!=null&&clearInterval(e.closePollId),e.close(),e.ctrl.destroy();z.clear();for(const e of S)e&&e.destroy();S=[],Se()?.remove(),tn.disconnect(),me&&((f.ownerDocument.defaultView??window).cancelAnimationFrame(me),me=0),f.ownerDocument.removeEventListener("click",Fe,!0),window.removeEventListener("blur",Dt),Cn(),dn(),Be.remove(),G.remove(),h?.remove(),ge?.destroy()}}}
|
|
1
|
+
import{getUniqueTestNumbers as go,resolveTestNumber as mo,findTestDef as ho,collectMetadataValues as bo}from"../renderer/buildView.js";import{metadataCategoricalValue as yo}from"../core/metadata.js";import{resolveBinColorsByWafer as wo,binColorWarning as vo,mixedPassBinsWarning as xo}from"../renderer/binColors.js";import{itemPassBins as Co}from"../core/passBins.js";import{NO_DATA_FILL as So}from"../renderer/colorMap.js";import{metadataValueColor as Mo}from"../renderer/colorMap.js";import{resolveCanvasTheme as Do}from"./canvasTheme.js";import{ICONS as $e}from"./icons.js";import{SHADOW as We,LEADING as Xe,TRACKING as Bo,controlStyle as ko,wireControlHover as ht,SPACE as v,EDGE_GUTTER as oe,MAP_CHROME_INSET as Eo,RADIUS as z,FONT as O,CLR as m,sevColor as ln,MODE_LABELS as Oo,BIN_LEGEND_MODES as rn,STACKED_MODES as be,Z_ABOVE as dn,applyOverlayZ as To,getTooltip as Lo,hideTooltip as cn,createToolbarHelpers as $o,buildModeMenuEl as Wo,openDetachWindow as Ro,openFloatingWindow as Io,openModal as Ao,openReportModal as Po,copyWmapThemeTokens as Ho,syncWmapPopupTheme as Fo,openUserGuideWindow as jo,makePaletteBtn as Vo,makeLogScaleBtn as zo,makeLegendStyleBtn as No,makeOverlaysBtn as _o,makeOrientationBtn as Go,menuLayerFor as fn,saveImageBlob as Ko,markMenuTrigger as Re,wireMenuA11y as un,wireExpandToggle as pn,wireTooltip as gn,requestedPassFailDisplay as mn,overlayMenuRows as qo,anyOverlayActive as Uo,logWmapVersionOnce as Xo,buildDataModeEntries as Zo,metadataKeyHasData as Yo,metadataModeEntry as Qo}from"./toolbar.js";import{waferDisplayLabel as Ie}from"../core/waferLabel.js";import{sortBinsForDisplay as Jo}from"../stats/binPareto.js";import{diePassStatus as ei}from"../core/dies.js";import{aggregateValues as ti,aggregateBinCounts as hn}from"../core/aggregates.js";import{renderWaferMap as ni,renderWaferMapCard as bn,toPublicViewOptions as yn}from"./renderWaferMap.js";import{classifyChanged as oi,COLOR_KEYS as ii}from"./renderWaferMap.js";import{buildWaferMap as ai,getTestPassStatus as wn,isParametricTest as bt,getDieTestValue as si}from"../renderer/buildWaferMap.js";import{analyzeWaferMap as Ze}from"../stats/analyzeWaferMap.js";import{collectWarnings as li,buildWarningsMenuEl as ri,severityOf as di}from"./warnings.js";import{compareNatural as vn}from"../core/utils.js";import{createSummaryPanelEl as yt,buildMetadataStripRow as ci,buildCompactMetadataRows as xn,metadataEntries as Cn,renderLotSummaryContent as fi}from"./summaryPanel.js";import{renderLotSummaryReportHtml as ui}from"../stats/renderSummaryReport.js";import{prettyKey as pi}from"../stats/facets.js";import{mergeTestDefs as gi}from"../stats/mergeTestDefs.js";import{getDieKey as mi,hasPosition as hi}from"../core/dies.js";function ie(u){const x=new Set;return u.filter(p=>x.has(p.bin)?!1:(x.add(p.bin),!0))}const wt=12;function bi(u,x,p){let I=x;if(x.length>wt){const C=x.slice(0,wt-1),L=x.slice(wt-1),N=L.reduce((F,ae)=>F+ae.count,0);I=[...C,{color:m.label,count:N,label:`Other (${L.length} bins)`}]}const A=u.createElement("div");Object.assign(A.style,{display:"flex",columnGap:"1px",width:"100%",height:"8px",borderRadius:z.control,overflow:"hidden",border:`1px solid ${m.menuBorder}`,boxSizing:"border-box",marginTop:v.xs,flexShrink:"0"}),A.setAttribute("role","img"),A.setAttribute("aria-label",`Population split: ${I.map(C=>`${C.label} ${Ye(C.count/p*100)}`).join(", ")}`);for(const C of I){const L=C.count/p*100,N=u.createElement("div");Object.assign(N.style,{flex:`${L} 1 0`,minWidth:L>0?"2px":"0",background:C.color}),gn(N,`${C.label} \xB7 ${C.count.toLocaleString()} dies \xB7 ${Ye(L)}`),A.appendChild(N)}return A}function Ye(u){return u>0&&u<.1?"<0.1%":`${u.toFixed(1)}%`}function Sn(u,x,p){const I=new Map;let A=0,C=0;for(const L of u){const N=p?new Set(p(L)):void 0;for(const F of L.dies){if(F.partial||F.edgeExcluded)continue;const ae=x(F);ae!==void 0&&(I.set(ae,(I.get(ae)??0)+1),A++,N&&ei(F,N)&&C++)}}return{counts:I,total:A,pass:C}}function Mn(u,x){const p=u.ownerDocument.createElement("div");Object.assign(p.style,{display:"flex",alignItems:"center",gap:"5px",cursor:"pointer",userSelect:"none",padding:`${v.xxs} ${v.xs}`,borderRadius:z.control});const I=u.ownerDocument.createElement("span");Object.assign(I.style,{display:"inline-block",width:"13px",height:"13px",flexShrink:"0",background:x.color,border:x.isActive?`2px solid ${m.iconActive}`:`1px solid ${m.menuBorder}`,borderRadius:z.control,boxSizing:"border-box"});const A=u.ownerDocument.createElement("span");if(A.textContent=x.label,Object.assign(A.style,{fontWeight:x.isActive?"700":"400",color:x.isActive?m.iconActive:m.text,whiteSpace:"nowrap"}),p.appendChild(I),p.appendChild(A),x.count!==void 0){const C=u.ownerDocument.createElement("span");if(C.textContent=x.count.toLocaleString(),Object.assign(C.style,{color:x.isActive?m.iconActive:m.text,fontWeight:x.isActive?"700":"400",whiteSpace:"nowrap"}),p.appendChild(C),x.percent!==void 0){const L=u.ownerDocument.createElement("span");L.textContent=Ye(x.percent),Object.assign(L.style,{color:m.label,whiteSpace:"nowrap"}),p.appendChild(L)}}p.setAttribute("role","button"),p.setAttribute("aria-pressed",x.isActive?"true":"false"),p.tabIndex=0,p.addEventListener("mouseenter",()=>{p.style.background=m.bgHover}),p.addEventListener("mouseleave",()=>{p.style.background="transparent"}),p.addEventListener("focus",()=>{p.style.background=m.bgHover}),p.addEventListener("blur",()=>{p.style.background="transparent"}),p.addEventListener("click",x.onClick),p.addEventListener("keydown",C=>{(C.key==="Enter"||C.key===" ")&&(C.preventDefault(),x.onClick())}),u.appendChild(p)}export function renderWaferGallery(u,x,p={}){Xo();const I=6,A=p.downloadFilename??"wafer-gallery";let C=p.columns;const L=p.showHelpButton??!1,N=p.userGuideExtension,F=p.insights?.enabled??!1,ae=To(p.zIndex),ce=p.summaryPanel,Qe=e=>[...Co(e)],vt=()=>w.flatMap(e=>e?[e.ringCount??4]:[]),Je=()=>vt()[0]??4;function Dn(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 j=p.lotStatsSummary,ye=p.viewOptions?.legendPosition??"default",Ae=p.perCardLegend??!1;function we(){const e=d.plotMode??"hardBin";return rn.has(e)?null:d.colorbarRangeMode==="data"?"Each map has its own value range, so it keeps its own colour bar":"These wafers have no shared colour bar for value mode, so each map keeps its own"}function xt(){const e=Ae||we()!==null;for(const t of S)t&&t.setOptions({showLegend:e})}let d={plotMode:"hardBin",showDieLabels:!1,showRingBoundaries:!1,showQuadrantBoundaries:!1,rotation:0,flipX:!1,flipY:!1,...p.viewOptions},S=[],se=[],fe=[],T=[],w=x.map(e=>typeof e=="function"?null:e);function Ct(){return gi(w)}function ue(){if(w.some(e=>e?.testDefs?.length))return Ct().defs}let et=0,Pe=0;const _=new Map;let Bn=0,P=null,ve=null,St=new Set,h=null,kn={};function Mt(e){return w[e]?.statsSummary??j?.perWafer.find(t=>t.waferIndex===e)?.summary}function tt(){return!!(w.some(e=>e?.statsSummary?.findings.length)||j?.perWafer.some(e=>e.summary.findings.length))}const En=Lo(),pe=$o(En),{makeBtn:Q,setActive:xe,makeSep:G,makeMenuRow:On,makeMenuSection:Tn,makeDropdown:Dt,closeOpenMenu:He,getOpenMenu:Ce,setOpenMenu:Se}=pe;u.ownerDocument.addEventListener("click",He,!0);const Bt=()=>cn();window.addEventListener("blur",Bt);let kt=p.findingsNotice;function Et(e){St=new Set(e);const t=[...W.querySelectorAll(".wmap-gallery-card")];let n;t.forEach((o,l)=>{const a=St.has(l);o.style.outline=a?`3px solid ${m.findingHighlight}`:"",o.style.outlineOffset=a?"-3px":"",a&&n===void 0&&(n=o)}),n?.scrollIntoView?.({behavior:"smooth",block:"nearest"})}function Ot(){Et([])}function Tt(){for(const e of S)e&&e.clearSelection()}function nt(e,t){const n=new Set(e),o=t??S.map((l,a)=>a);for(const l of o){const a=T[l],s=S[l];if(!a||!s)continue;const r=a.dies.filter(i=>n.has(mi(i)));s.setSelection(r)}}function Ln(){const e=[];for(let t=0;t<w.length;t++){const n=w[t];if(!n)continue;const o=Mt(t)?.findings??[];o.length&&e.push({index:t,item:n,unusualCount:o.filter(l=>l.severity==="unusual").length,notableCount:o.filter(l=>l.severity==="notable").length,totalCount:o.length})}return e}function $n(e){const t=T[e]??w[e];t&&Le(e,t)}function Wn(e){const t=Mt(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 Rn(){const e=ie(w.flatMap(n=>n?.hbinDefs??[])),t=ie(w.flatMap(n=>n?.sbinDefs??[]));Po(ui({items:w.map((n,o)=>({label:Ie(n,o),wafer:n?.wafer,dies:n?.dies,passBins:Qe(n),statsSummary:n?.statsSummary})),hbinDefs:e.length?e:void 0,sbinDefs:t.length?t:void 0,testDefs:ue(),ringCount:Je()}),{anchor:u})}function In(){if(!h)return;h.innerHTML="";const e=Ln();if(w.length>0){const n=u.ownerDocument.createElement("div"),o=e.length,l=w.filter(Boolean).length;n.textContent=o===0?`No findings on any of the ${l} wafers`:`${o} of ${l} wafer${l===1?"":"s"} with findings`,Object.assign(n.style,{fontSize:O.body,color:m.label,marginBottom:v.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,{...ko("outlined"),marginBottom:v.lg,display:"block",width:"100%",textAlign:"left"}),ht(n),n.addEventListener("click",Rn),h.appendChild(n)}if(e.length===0){const n=u.ownerDocument.createElement("div");Object.assign(n.style,{color:m.icon,fontSize:O.body,padding:"4px 0"}),n.textContent="No findings on any wafer.",h.appendChild(n)}else for(const{index:n,item:o,unusualCount:l,notableCount:a,totalCount:s}of e){const r=l?"unusual":a?"notable":"info",i=l+a||s,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:v.xs,border:"none",borderLeft:`3px solid ${ln(r)}`,borderRadius:z.control,background:m.bgHover,cursor:"pointer",fontSize:O.body,textAlign:"left",boxSizing:"border-box"}),c.addEventListener("mouseover",()=>{c.style.background=m.bgActive}),c.addEventListener("mouseout",()=>{c.style.background=m.bgHover});const f=u.ownerDocument.createElement("span");f.textContent=Ie(o,n),Object.assign(f.style,{color:m.iconHover,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"});const b=u.ownerDocument.createElement("span");b.textContent=String(i),c.setAttribute("aria-label",`${Ie(o,n)} \u2014 ${i} finding${i===1?"":"s"}${l?`, ${l} unusual`:""} \u2014 view wafer`),Object.assign(b.style,{marginLeft:v.sm,flexShrink:"0",background:ln(r),color:"#fff",borderRadius:z.container,padding:"1px 5px",fontSize:O.body,fontWeight:"600"}),c.appendChild(f),c.appendChild(b),c.addEventListener("click",()=>Le(n,o)),h.appendChild(c)}const t=u.ownerDocument.createElement("div");t.style.height="12px",h.appendChild(t)}function V(){if(h)if(j){const e=ie(w.flatMap(n=>n?.hbinDefs??[])),t=ie(w.flatMap(n=>n?.sbinDefs??[]));fi(h,{lotSummary:j,items:w,hbinDefs:e.length?e:void 0,sbinDefs:t.length?t:void 0,testDefs:ue(),ringCount:Je(),binColors:d.binColors,plotMode:d.plotMode??"hardBin",fallbackFormat:d.fallbackFormat,activeFindingId:ve,warnings:p.warnings?.display??!0?J:[],findingsFilter:kn,findingsNotice:kt,onFindingsFilterChange:V,onSaveText:p.onSaveText,onFindingClick:(n,o)=>{ve===n.id?ot():Pn(n,o),V()},onWaferClick:$n,findingsFor:Wn,dieListOptions:p.dieList})}else In()}function An(e){const t=e.highlight;return t?.kind==="wafer"&&t.waferIndices?.length?t.waferIndices:null}function Lt(e){return[e.variable.kind,e.variable.index??"",e.variable.bin??"",e.comparison.family,e.comparison.left,e.effect.direction].join("|")}let Fe=[];function $t(){if(Fe.length!==0){for(const e of Fe)S[e]?.setOptions({plotMode:d.plotMode,activeTest:d.activeTest});Fe=[]}}function ot(){ve=null,Ot(),Tt(),$t(),E({highlightBin:void 0},{fireCallback:!1})}function Pn(e,t){if(ve===e.id){ot();return}ve=e.id,t.style.background=m.bgActive,t.style.fontWeight="600",$t();const{kind:n,index:o}=e.variable;if(n==="test"){const a=o??0,s=ue();if(s===void 0||s.some(i=>i.testNumber===a))E({plotMode:"value",activeTest:a,highlightBin:void 0},{fireCallback:!1});else{E({highlightBin:void 0},{fireCallback:!1});const c=be.has(d.plotMode??"hardBin")?null:An(e);if(c){for(const f of c)S[f]?.setOptions({plotMode:"value",activeTest:a});Fe=[...c]}}}else n==="softBin"?E({plotMode:"softBin",highlightBin:void 0},{fireCallback:!1}):E({plotMode:"hardBin",highlightBin:void 0},{fireCallback:!1});Ot(),Tt();const l=e.highlight;if(l.kind==="wafer"){Et(l.waferIndices);const a=Lt(e);for(const s of l.waferIndices){const c=T[s]?.statsSummary?.findings.find(f=>Lt(f)===a)?.highlight?.dieKeys;c?.length&&nt(c,[s])}}else l.kind==="bin"?l.dieKeys?.length&&nt(l.dieKeys):(l.kind==="region"||l.kind==="dies")&&l.dieKeys?.length&&nt(l.dieKeys)}function le(){if(!P)return;const e=!!h;P.style.display=(j||tt())&&e&&!Ee?"flex":"none";const t=h?h.style.display!=="none":!1;(j?.hasNotableFindings||w.some(o=>o?.statsSummary?.hasNotableFindings))&&!t?P.style.color=m.findingIndicator:P.dataset.active||(P.style.color=m.icon)}const $=u.ownerDocument.createElement("div");$.dataset.wmapToolbar="gallery",Object.assign($.style,{flexShrink:"0",marginLeft:"auto",display:"inline-flex",flexDirection:"row",alignItems:"center",gap:"0",background:m.menuBg,border:`1px solid ${m.menuBorder}`,borderRadius:z.control,padding:"0",boxShadow:We.panel,flexWrap:"wrap",minWidth:"0",overflowX:"auto"});const Wt=()=>{const e=Ce();e&&(e.remove(),Se(null)),Re(X,!1)},X=Q("mode","Plot mode",()=>{if(Ce()){Wt();return}const e=w.flatMap(y=>y?.dies??[]),t=ue(),{testEntries:n,binEntries:o,stackedEntries:l}=Zo(e,t,{includeStacked:!0}),a=w.filter(Boolean).length,s=y=>{if(y===void 0)return a;let R=0;for(const de of w)de?.dies?.some(U=>wn(U,y)!==void 0||U.testValues?.[y]!==void 0)&&R++;return R},r=a<2?n:n.map(y=>{const R=s(y.activeTest);return R===a?y:{...y,label:`${y.label} \u2014 ${R} of ${a} wafers`}}),i=d.plotMode??"hardBin",c=d.activeTest??0;function f(y){return y.plotMode!==i?!1:y.plotMode==="value"?c===(y.activeTest??0):y.plotMode==="metadata"?d.activeMetadataKey===y.activeMetadataKey:!0}function b(y,R){y.activeTest!==void 0?E({plotMode:"value",activeTest:y.activeTest,activeMetadataKey:void 0,logScale:y.logScale}):y.activeMetadataKey!==void 0?E({plotMode:y.plotMode,activeTest:void 0,activeMetadataKey:y.activeMetadataKey,passFailDisplay:"off"}):E({plotMode:y.plotMode,activeTest:void 0,activeMetadataKey:void 0,passFailDisplay:"off"}),R.remove(),Se(null),Re(X,!1)}const k=new Set,D=w.flatMap(y=>y?.metadataFields??[]).filter(y=>!k.has(y.key)&&k.add(y.key)).filter(y=>Yo(e,y.key)).map(Qo),M=Wo(X.getBoundingClientRect(),r,o,l,f,b,{makeMenuRow:On,makeMenuSection:Tn},i,X.ownerDocument.defaultView??window,D);fn(X).appendChild(M),Se(M),Re(X,!0),un(M,X,Wt)});Re(X,!1);const Hn=()=>T.flatMap(e=>e?[...e.hbinDefs??[],...e.sbinDefs??[]]:[]).some(e=>e.color),{btn:Fn,sync:Rt}=Vo(pe,()=>({...d,plotMode:d.plotMode??"hardBin"}),Hn,e=>E(e));Rt();const jn=x.some(e=>typeof e!="function"&&(e.reticles?.length??0)>0);function je(){const e=ue(),{testNumber:t}=mo(d.activeTest??0,e);return{testNumber:t,td:ho(e,t)}}function It(){if((d.plotMode??"hardBin")!=="value")return!1;const{td:e}=je();return e!==void 0&&(e.limitLow!==void 0||e.limitHigh!==void 0)}function Me(){if((d.plotMode??"hardBin")!=="value")return!1;const{td:e}=je();return e!==void 0&&!bt(e)}function Vn(){if((d.plotMode??"hardBin")!=="value")return!1;const{testNumber:e,td:t}=je();return w.some(n=>n?.dies?.some(o=>wn(o,e,t)!==void 0))}function zn(e,t){if(!t||!bt(t))return;const n=t.limitLow!==void 0||t.limitHigh!==void 0;if((mn(d)==="spec"&&n?"spec":d.colorbarRangeMode??"spec")==="spec"&&n)return;let a=1/0,s=-1/0;for(const r of w)if(r)for(const i of r.dies){const c=si(i,e);c!==void 0&&(c<a&&(a=c),c>s&&(s=c))}if(isFinite(a))return a===s?[a,a+1]:[a,s]}function At(){if((d.plotMode??"hardBin")!=="metadata")return;const e=d.activeMetadataKey;if(!e)return;const t=new Set;for(const n of w)if(n)for(const o of bo(n.dies,e))t.add(o);return{key:e,values:[...t].sort(vn)}}function it(){const e=At();if(!(e===void 0&&d.metadataValueOrder===void 0)){d={...d,metadataValueOrder:e};for(const t of S)t&&t.setOptions({metadataValueOrder:e})}}function at(){if((d.plotMode??"hardBin")!=="value")return;const{testNumber:e,td:t}=je(),n=zn(e,t),o=n?{test:e,range:n}:void 0;d={...d,valueRange:o};for(const l of S)l&&l.setOptions({valueRange:o})}let st=!1;function Nn(){if(st)return;st=!0,(u.ownerDocument.defaultView?.requestAnimationFrame??(t=>setTimeout(()=>t(0),0)))(()=>{st=!1,at(),it(),Ht()})}let Pt=[];function De(){const e=ie(w.flatMap(l=>l?.hbinDefs??[])),t=ie(w.flatMap(l=>l?.sbinDefs??[])),{colors:n,mixedHardBins:o}=wo(w.flatMap(l=>l?[{dies:l.dies,passBins:Qe(l)}]:[]),{binColorScheme:d.binColorScheme,useDefinedBinColors:d.useDefinedBinColors,hbinDefs:e,sbinDefs:t});return Pt=o,n}function Ht(){const e=De();d={...d,binColors:e};for(const t of S)t&&t.setOptions({binColors:e});Be()}const _n=_o(pe,()=>qo(d,jn,{functionalActive:Me(),hasLimits:It()&&!Me(),hasRecorded:Vn()&&!Me(),binMode:(d.plotMode??"hardBin")==="hardBin"||(d.plotMode??"hardBin")==="softBin"},e=>E(e)),()=>Uo(d)),{btn:Gn,sync:Ft}=No(pe,()=>({plotMode:d.plotMode,legendPosition:ye}),e=>{ye=e;for(const t of S)t&&t.setOptions({legendPosition:ye})},{get:()=>Ae,set:e=>{Ae=e,xt()},blockedReason:we});Ft();const Kn=[{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"}],jt=Dt("aggr","Aggregation method",()=>Kn,()=>d.aggregationMethod??"mean",e=>E({aggregationMethod:e}));function Vt(){const e=d.plotMode==="stackedValues";jt.style.display=e?"":"none"}Vt();const{btn:qn,sync:zt}=zo(pe,()=>({...d,functionalActive:Me()}),e=>E(e));zt();const Ve=Q("specRange","Colorbar range: spec limits",()=>{const e=d.colorbarRangeMode==="data"?"spec":"data";E({colorbarRangeMode:e})});function Nt(){const e=(d.plotMode??"hardBin")==="value"&&It()&&mn(d)==="off"&&!Me();Ve.style.display=e?"":"none";const t=(d.colorbarRangeMode??"spec")==="spec";xe(Ve,t),Ve.ariaLabel=t?"Colorbar range: spec limits (click for data range)":"Colorbar range: data range (click for spec limits)"}Nt();const Un=Go(pe,()=>d,e=>E(e)),Xn=Q("downloadAll","Download gallery PNG",fo),Zn=Dt("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"}],()=>C!=null?String(C):"auto",e=>ao(e==="auto"?void 0:Number(e))),B=u.ownerDocument.createElement("div");Object.assign(B.style,{display:"inline-flex",alignItems:"center",gap:"0"}),$.appendChild(B),B.appendChild(X),B.appendChild(Fn),B.appendChild(jt),B.appendChild(qn),B.appendChild(Ve),B.appendChild(G()),B.appendChild(_n),B.appendChild(G()),B.appendChild(Gn),B.appendChild(G()),B.appendChild(Un),B.appendChild(G()),B.appendChild(Zn),B.appendChild(G()),B.appendChild(Xn),(j||tt())&&(P=Q("findings","Summary panel",()=>{if(!h)return;const e=h.style.display!=="none";e||V(),h.style.display=e?"none":"flex",xe(P,!e),le()}),$.appendChild(G()),$.appendChild(P));let K=null,ze=null,J=[],_t=!1;function Be(){const e=li({lotStatsSummary:j,result:{warnings:[...w.flatMap(n=>n?.warnings??[]),...Ct().warnings]},extra:[d.binColors&&vo(d.binColors,d.plotMode),xo(Pt),Dn(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||!_t)&&(_t=!0,p.warnings?.onWarning?.(e)),Yn()}function Yn(){if(!K||!ze)return;const e=J.length,t=e>0;if(K.style.display=t?"flex":"none",ze.style.display=t?"":"none",!t)return;const n=di(J[0]),o=`${e} data ${e===1?"warning":"warnings"}`;K.style.color=n==="error"?m.errText:m.warnText,K.ariaLabel=n==="error"?`${o} \u2014 some wafers may be positionally wrong`:o}(p.warnings?.display??!0)&&(ze=G(),K=Q("warning","Data warnings",()=>{const e=Ce();if(He(new MouseEvent("click")),e)return;const t=ri(K.getBoundingClientRect(),J,K.ownerDocument.defaultView??window);fn(u).appendChild(t),Se(t),un(t,K,()=>He(new MouseEvent("click")))}),Re(K,!1),$.appendChild(ze),$.appendChild(K)),Be();let re=null;F&&(re=Q("analysis","Insights",()=>{qt(!Ee)}),re.dataset.wmapInsightsBtn="1",$.appendChild(G()),$.appendChild(re));function Gt(){import("./userGuideHtml.js").then(e=>jo({buildWaferMap:ai,renderWaferMap:ni,renderWaferGallery,analyzeWaferMap:Ze},e.USER_GUIDE_HTML,N,u))}L&&($.appendChild(G()),$.appendChild(Q("help","User guide",()=>Gt())));const ge=u.ownerDocument.createElement("div");ge.dataset.wmapGalleryMeta="1",Object.assign(ge.style,{flex:"1",minWidth:"0",overflow:"hidden",display:"flex",alignItems:"center",padding:`${v.sm} ${v.lg}`,fontSize:O.sub,lineHeight:Xe.none,boxSizing:"border-box"});const Ne=u.ownerDocument.createElement("div");Object.assign(Ne.style,{background:m.canvasBg,display:"flex",alignItems:"stretch",gap:v.lg,paddingBottom:v.lg,minWidth:"0"});const ee=u.ownerDocument.createElement("div");ee.dataset.wmapGalleryLegend="1",Object.assign(ee.style,{display:"flex",flexDirection:"column",gap:v.sm,background:m.menuBg,border:`1px solid ${m.menuBorder}`,borderRadius:z.container,padding:`${v.sm} ${v.lg}`,marginBottom:v.lg,boxShadow:We.panel,fontSize:O.body,lineHeight:Xe.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 me=null,ke=null,Kt=null;function Qn(){return F?me?Promise.resolve(me):(Kt??=import("./insightsTab.js").then(({createInsightsTab:e})=>(me=e({getItems:()=>w,getLotStats:()=>j,getBinColors:()=>d.binColors??De(),getRingCount:Je,defaultView:p.insights?.defaultView,onOpenGuide:void 0,showMetadataStrip:!1,onSaveImage:p.onSaveImage,onSaveText:p.onSaveText,ownerDocument:u.ownerDocument,openWafer:(t,n,o)=>{const l=w[t];if(!l)return;let a=null;const s=Ao({title:n,onClose:()=>a?.destroy(),anchor:u});en(s,n,l.wafer.metadata??void 0),a=ft(s.contentWrap,l,o)}}),ke=me.el,ke.style.display="none",u.appendChild(ke),me)),Kt):Promise.resolve(null)}let Ee=!1;function qt(e){F&&(Ee=e,ke&&(ke.style.display=e?"flex":"none"),q.style.display=e?"none":"flex",B.style.display=e?"none":"inline-flex",$.style.display="inline-flex",re&&(xe(re,e),re.innerHTML=e?$e.wafer:$e.analysis,re.ariaLabel=e?"Back to gallery view":"Insights"),le(),Ke(),e&&Qn().then(t=>{!t||!Ee||(t.el.style.display="flex",t.render())}))}F&&p.insights?.defaultOpen&&queueMicrotask(()=>qt(!0));const Jn=4,lt=240,Ut=480,eo=720,to=1.25;let Z=Ut;function Xt(e){const t=I*2+110+2;let n=null;for(const o of e){if(o==null||!o.dies?.length)continue;const l=o.dies[0].width;if(!(l>0))continue;const a=o.wafer.radius*2*(Jn/l),s=Math.ceil(a+t);(n==null||s>n)&&(n=s)}return n}function no(e){const t=Xt(e);return t==null?lt:Math.min(Z,Math.max(lt,t))}function oo(e){const t=Xt(e);if(t==null)return!1;const n=Math.min(eo,Math.max(Ut,t));return n<=Z?!1:(Z=n,!0)}function io(){for(const e of Array.from(W.children))e.classList.contains("wmap-gallery-card")&&(e.style.maxWidth=`${Z}px`,e.style.maxHeight=`${Z}px`)}let _e=lt,Zt=0;function Yt(e){const t=oo(e);if(t&&io(),C!=null){t&&Ge();return}const n=no(e);n>_e&&(_e=n),Ge()}function ao(e){C=e,Ge()}function rt(e){return`repeat(${e}, minmax(0, ${Z}px))`}function Qt(e){W.style.gridTemplateColumns!==e&&(W.style.gridTemplateColumns=e)}function Ge(){if(C!=null){Qt(rt(C));return}const e=Math.max(1,Zt),t=12,n=W.clientWidth||0,o=a=>(n-t*(a-1))/a;let l=Math.max(1,Math.ceil(Math.sqrt(e)));if(n>0){const a=Math.min(Z,_e*to),s=r=>{let i=0;for(;i<e&&o(i+1)>=r;)i++;return i};l=s(a)||s(_e)||1}Qt(rt(l))}const W=u.ownerDocument.createElement("div");if(Object.assign(W.style,{flex:"1 1 0",minWidth:"0",display:"grid",gridTemplateColumns:rt(1),gap:v.xl,paddingLeft:oe,paddingRight:oe,justifyContent:"start",alignContent:"start",isolation:"isolate"}),ce?.placement){const e=ce.placement;h=yt(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(j||tt()){const e=!!ce?.defaultOpen;h=yt("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",V()}le(),h?.style.display!=="none"&&P&&xe(P,!0),(ce?.placement??"right")==="left"?(h&&q.appendChild(h),q.appendChild(W)):(q.appendChild(W),h&&q.appendChild(h));const Oe=u.ownerDocument.createElement("div");Object.assign(Oe.style,{position:"sticky",top:"0",display:"flex",flexDirection:"column",paddingLeft:oe,paddingRight:oe,paddingTop:oe,zIndex:"1",background:m.menuBg}),Ne.appendChild(ge),Ne.appendChild($),Oe.appendChild(Ne),Oe.appendChild(ee),u.appendChild(Oe),u.appendChild(q);function Ke(){ee.innerHTML="";const e=d.plotMode??"hardBin",t=!Ee&&rn.has(e),n=T.filter(g=>g!=null),o=n.find(g=>g.isLotStack),l=ci(n.map(g=>({metadata:g.wafer.metadata??void 0})),o?{lotSize:o.lotSize??n.length,aggrMethod:o.aggrMethod}:void 0),a=e==="metadata",s=d.activeMetadataKey,r=t&&!a?Sn(n,g=>(e==="softBin"?g.sbin:g.hbin)??void 0,Qe):{counts:new Map,total:0,pass:0},i=t&&!a?d.binColors??De():void 0,c=i?e==="softBin"?i.pass.soft:i.pass.hard:new Set,f=Jo(r.counts.entries(),c).map(([g])=>g),b=t&&a&&s?Sn(n,g=>yo(g.metadata?.[s])):{counts:new Map,total:0,pass:0},k=a?At()?.values:void 0,D=t&&a?(k??[...b.counts.keys()].sort(vn)).filter(g=>b.counts.has(g)):[];if(ge.innerHTML="",l&&ge.appendChild(l),ge.style.display=l?"flex":"none",!f.length&&!D.length){ee.style.display="none";return}ee.style.display="flex";const M=u.ownerDocument.createElement("div");Object.assign(M.style,{display:"flex",flexWrap:"wrap",alignItems:"center",gap:`${v.sm} ${v.xl}`,maxHeight:"86px",overflowY:"auto",overflowX:"hidden"}),ee.appendChild(M);const y=d.highlightBin,R=T.flatMap(g=>g?.metadataFields??[]).find(g=>g.key===s),de=a?R?.label??(s?pi(s):"Metadata"):Oo[e],U=u.ownerDocument.createElement("span");if(U.textContent=de,Object.assign(U.style,{fontSize:O.body,fontWeight:"700",letterSpacing:Bo,textTransform:"uppercase",color:m.label,flexShrink:"0"}),M.appendChild(U),!a&&r.total>0){const g=r.pass,H=g/r.total*100,te=u.ownerDocument.createElement("span");te.textContent=`Yield ${Ye(H)}`,Object.assign(te.style,{fontSize:O.body,fontWeight:"700",color:m.value,whiteSpace:"nowrap",flexShrink:"0"});const ne=u.ownerDocument.createElement("span");ne.textContent=`${g.toLocaleString()} / ${r.total.toLocaleString()} dies`,Object.assign(ne.style,{fontSize:O.body,color:m.label,whiteSpace:"nowrap",flexShrink:"0"}),M.appendChild(te),M.appendChild(ne)}if(a){const g=d.highlightMetadataValue;D.forEach((H,te)=>{const ne=g===H,Ue=R?.values?.find(mt=>mt.value===H),po=Ue?.color??Mo(te),sn=b.counts.get(H)??0;Mn(M,{color:po,isActive:ne,label:Ue?.label??H,count:sn,percent:b.total>0?sn/b.total*100:void 0,onClick:()=>{const mt=d.highlightMetadataValue===H?void 0:H;E({highlightMetadataValue:mt})}})});return}const ut=e==="softBin"?T.flatMap(g=>g?.sbinDefs??[]):T.flatMap(g=>g?.hbinDefs??[]),nn=new Set,pt=[];for(const g of ut)nn.has(g.bin)||(nn.add(g.bin),pt.push(g));const gt=pt.length>0?new Map(pt.map(g=>[g.bin,g])):null,on=i??d.binColors??De(),uo=e==="softBin"?on.soft:on.hard,an=g=>uo.get(g)??So;for(const g of f){const H=y===g,te=gt?.get(g),ne=r.counts.get(g)??0;Mn(M,{color:an(g),isActive:H,label:te?.name?`${g} \xB7 ${te.name}`:`Bin ${g}`,count:ne,percent:r.total>0?ne/r.total*100:void 0,onClick:()=>{const Ue=d.highlightBin===g?void 0:g;E({highlightBin:Ue})}})}r.total>0&&f.length>1&&ee.appendChild(bi(u.ownerDocument,[...r.counts.entries()].sort(([,g],[,H])=>H-g).map(([g,H])=>({color:an(g),count:H,label:gt?.get(g)?.name?`${g} \xB7 ${gt.get(g).name}`:`Bin ${g}`})),r.total))}function Te(e){const t=w.filter(r=>r!==null);if(!t.length)return[];const n=t.map(r=>r.dies.filter(hi)),o=t[0].wafer,l=t.length,a=o.metadata?{...o,metadata:(({wafer:r,waferId:i,...c})=>c)(o.metadata)}:o;function s(r,i){return{...r,stats:{...r.stats,isLotStack:!0,aggregationMethod:i,lotSize:l}}}if(e==="stackedValues"){const r=ue();let i=r?.filter(bt);if(r!==void 0&&i?.length===0)return[];if(r?.length||(i=go(t.flatMap(b=>b.dies)).map(b=>({testNumber:b,name:`Test ${b}`}))),!i?.length)return[];const c=d.aggregationMethod??"mean";return i.map(f=>{const b=ti(n,c,f.testNumber),k={testNumber:0,name:f.name,unit:f.unit};return{wafer:a,dies:b,testDefs:[k],label:`${f.name} \xB7 ${c}`,isLotStack:!0,aggrMethod:c,lotSize:l,statsSummary:s(Ze({wafer:a,dies:b,testDefs:[k]},{testNumbers:[0]}),c)}})}if(e==="stackedBins"){let r=ie(t.flatMap(i=>i.hbinDefs??[]));return(!r||r.length===0)&&(r=[...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}`}))),r.map(i=>{const c=hn(n,i.bin,"hard"),f=[{bin:i.bin,name:i.name}];return{wafer:a,dies:c,hbinDefs:f,label:`${i.bin} \xB7 ${i.name}`,isLotStack:!0,aggrMethod:"countBin",lotSize:l,statsSummary:s(Ze({wafer:a,dies:c,hbinDefs:f}),"countBin")}})}if(e==="stackedSoftBins"){let r=ie(t.flatMap(i=>i.sbinDefs??[]));return(!r||r.length===0)&&(r=[...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}`}))),r.map(i=>{const c=hn(n,i.bin,"soft"),f=[{bin:i.bin,name:i.name}];return{wafer:a,dies:c,sbinDefs:f,label:`${i.bin} \xB7 ${i.name}`,isLotStack:!0,aggrMethod:"countBin",lotSize:l,statsSummary:s(Ze({wafer:a,dies:c,sbinDefs:f}),"countBin")}})}return t}function dt(e){const t=w.length;return e==="stackedBins"||e==="stackedSoftBins"?{valueRange:[0,t],lotSize:t}:e==="stackedValues"?{aggregationMethod:d.aggregationMethod??"mean",valueRange:void 0,lotSize:void 0}:{}}function E(e,{fireCallback:t=!0}={}){const n=Object.keys(e),o=d.plotMode,l=we()!==null;d={...d,...e};const a=d.plotMode,s=be.has(a),r=o!==void 0&&be.has(o),i=Pe>0;if("binColorScheme"in e||"useDefinedBinColors"in e){const f=De();d={...d,binColors:f},e={...e,binColors:f}}if(e.plotMode!==void 0)if(s){const f=dt(a);if(d={...d,...f},i)for(const b of S)b&&b.setOptions(e);else Y(Te(a))}else if(r){const{valueRange:f,lotSize:b,aggregationMethod:k,...D}=d;if(d=D,i)for(const M of S)M&&M.setOptions(e);else Y(w.filter(M=>M!==null))}else for(const f of S)f&&f.setOptions(e);else if(e.aggregationMethod!==void 0&&a==="stackedValues")if(i)for(const f of S)f&&f.setOptions(e);else Y(Te("stackedValues"));else for(const f of S)f&&f.setOptions(e);we()!==null!==l&&xt(),Ke(),Vt(),Ft(),Rt();const c=e.plotMode!==void 0&&e.plotMode!==o;(ii.some(f=>f in e)||c)&&V(),Be(),zt(),Nt(),at(),it(),t&&p.onViewOptionsChange?.(yn(d),n,oi(n))}function Jt(e,t,n){const o=e.createElement("div");Object.assign(o.style,{display:"flex",alignItems:"center",gap:v.xs,flex:"1",minWidth:"0"});const l=e.createElement("span");l.textContent=t,Object.assign(l.style,{fontWeight:"700",fontSize:O.sub,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}),o.appendChild(l);const a=Cn(n??{});let s=null;if(a.length>0){const r=e.createElement("span");Object.assign(r.style,{fontSize:O.body,lineHeight:Xe.none,color:m.label,flexShrink:"0"}),r.textContent="\u25BE",o.appendChild(r),Object.assign(o.style,{cursor:"pointer",borderRadius:z.control}),o.addEventListener("mouseenter",()=>{o.style.background=m.bgHover}),o.addEventListener("mouseleave",()=>{o.style.background="none"}),s=e.createElement("div"),s.dataset.wmapCardMetaPanel="1",Object.assign(s.style,{position:"absolute",top:"0",left:"0",right:"0",zIndex:dn,background:m.menuBg,borderBottom:`1px solid ${m.menuBorder}`,boxShadow:We.menu,padding:`${v.md} ${v.lg}`,fontSize:O.body,display:"none"});const i=xn(n??{});i&&s.appendChild(i),o.setAttribute("aria-expanded","false"),o.setAttribute("aria-label",`Wafer info for ${t||"this card"}. Click to expand.`),pn(o,c=>{r.textContent=c?"\u25B4":"\u25BE",o.setAttribute("aria-expanded",String(c)),s&&(s.style.display=c?"block":"none")})}return{wrap:o,metaPanel:s}}function en(e,t,n){const o=e.box.querySelector("[data-wmap-window-title]"),l=Cn(n??{});if(!o||l.length===0)return;const a=o.parentElement,s=u.ownerDocument.createElement("div");Object.assign(s.style,{display:"flex",alignItems:"center",gap:v.xs,flex:"1",minWidth:"0",cursor:"pointer"}),ht(s,"bare"),a?.insertBefore(s,o),s.appendChild(o);const r=u.ownerDocument.createElement("span");Object.assign(r.style,{fontSize:O.body,lineHeight:Xe.none,color:m.label,flexShrink:"0"}),r.textContent="\u25BE",s.appendChild(r);const i=u.ownerDocument.createElement("div");i.dataset.wmapCardMetaPanel="1",Object.assign(i.style,{position:"absolute",top:"0",left:"0",right:"0",zIndex:dn,background:m.menuBg,borderBottom:`1px solid ${m.menuBorder}`,boxShadow:We.menu,padding:`${v.md} ${v.lg}`,fontSize:O.body,display:"none"});const c=xn(n??{});c&&i.appendChild(c),e.contentWrap.style.position="relative",e.contentWrap.appendChild(i),s.setAttribute("aria-expanded","false"),s.setAttribute("aria-label",`Wafer info for ${t}. Click to expand.`),pn(s,f=>{r.textContent=f?"\u25B4":"\u25BE",s.setAttribute("aria-expanded",String(f)),i.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:m.menuBg,border:`1px solid ${m.menuBorder}`,borderRadius:z.container,boxShadow:We.panel,overflow:"hidden",display:"flex",flexDirection:"column",position:"relative",aspectRatio:"1",maxWidth:`${Z}px`,maxHeight:`${Z}px`});const l=u.ownerDocument.createElement("div");Object.assign(l.style,{display:"flex",alignItems:"center",padding:`${v.md} ${v.lg} ${v.sm}`,borderBottom:`1px solid ${m.menuBorder}`,flexShrink:"0",gap:v.sm});const{wrap:a,metaPanel:s}=Jt(document,Ie(e,t),e.wafer.metadata??void 0);l.appendChild(a);const r=u.ownerDocument.createElement("button");r.dataset.wmapExpandBtn="1",r.setAttribute("aria-label","Open full view"),gn(r),r.innerHTML=$e.expand,Object.assign(r.style,{display:"flex",alignItems:"center",justifyContent:"center",border:`1px solid ${m.menuBorder}`,borderRadius:z.control,background:m.panelBg,color:m.label,padding:v.xxs,cursor:"pointer",flexShrink:"0",width:"22px",height:"22px"}),ht(r),l.appendChild(r),o.appendChild(l);const i=u.ownerDocument.createElement("div");Object.assign(i.style,{position:"relative",flex:"1",minHeight:"0",overflow:"hidden",display:"flex",flexDirection:"column"}),o.appendChild(i),s&&i.appendChild(s),W.appendChild(o);const c=Ae||we()!==null,f=e.viewOptions?{...d,...e.viewOptions}:d,b=bn(i,e,{viewOptions:{...f,showLegend:c,legendPosition:ye},showTooltip:!0,padding:I,statsSummary:e.statsSummary,onSaveImage:p.onSaveImage,onSaveText:p.onSaveText,onClick:e.onClick,onSelect:e.onSelect,onExpand:()=>Le(t,e),showIdentity:!1,chromeInset:Eo});return b.setViewControlsVisible(!1),b.setSummaryVisible(!1),r.onclick=()=>Le(t,e),{card:o,ctrl:b,canvasWrapper:i,expandBtn:r}}function so(e){const t=fe[e];if(!t)return;const n=[..._.values()].find(o=>o.cardIndex===e);n?(t.innerHTML=$e.minimize,t.setAttribute("aria-label","Reattach to gallery"),t.onclick=()=>ro(n.id)):(t.innerHTML=$e.expand,t.setAttribute("aria-label","Open full view"),t.onclick=()=>Le(e,T[e]))}function Y(e){co(),Ce()?.remove(),Se(null),ot(),T=[];for(const a of S)a&&a.destroy();S=[],se=[],fe=[],Pe=0,W.innerHTML="",Zt=e.length,Yt(e.map(a=>typeof a=="function"?null:a));const t=[];for(let a=0;a<e.length;a++){const s=e[a];if(typeof s=="function"){const r=u.ownerDocument.createElement("div");r.className="wmap-gallery-card",Object.assign(r.style,{background:m.menuBg,border:`1px solid ${m.menuBorder}`,borderRadius:z.container,aspectRatio:"1",display:"flex",alignItems:"center",justifyContent:"center"});const i=u.ownerDocument.createElement("span");i.textContent="\u2026",Object.assign(i.style,{color:m.label,fontSize:"18px"}),r.appendChild(i),W.appendChild(r),T.push(null),S.push(null),se.push(null),fe.push(null),t.push({index:a,factory:s,placeholder:r}),Pe++}else{const{ctrl:r,canvasWrapper:i,expandBtn:c}=ct(s,a,e.length);T.push(s),S.push(r),se.push(i),fe.push(c)}}Ht(),Ke(),at(),it();const n=++et;let o=0;function l(){if(n!==et)return;if(o>=t.length){if(be.has(d.plotMode)){const D=d.plotMode;Y(Te(D))}return}const{index:a,factory:s,placeholder:r}=t[o++],i=s();T[a]=i,w[a]=i,Yt([i]);const{card:c,ctrl:f,canvasWrapper:b,expandBtn:k}=ct(i,a,e.length);S[a]=f,se[a]=b,fe[a]=k,Pe--,r.replaceWith(c),Ke(),Nn(),!h&&!ce?.placement&&i.statsSummary?.findings.length?(h=yt("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",(ce?.placement??"right")==="left"?q.insertBefore(h,W):q.appendChild(h),V(),P||(P=Q("findings","Summary panel",()=>{if(!h)return;const M=h.style.display!=="none";M||V(),h.style.display=M?"none":"flex",xe(P,!M),le()}),$.appendChild(G()),$.appendChild(P)),le()):h&&h.style.display!=="none"&&V(),le(),setTimeout(l,0)}t.length>0&&setTimeout(l,0)}if(be.has(d.plotMode)&&w.length>0){const e=dt(d.plotMode);d={...d,...e},Y(Te(d.plotMode))}else Y(x);Be();let he=0;const tn=new(u.ownerDocument.defaultView??window).ResizeObserver(()=>{if(he)return;he=(u.ownerDocument.defaultView??window).requestAnimationFrame(()=>{he=0,C==null&&Ge()})});tn.observe(W),h&&V();function lo(e,t){const n=se[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:m.label,fontSize:O.body,textAlign:"center",padding:"0 12px"}),n.appendChild(o)}function Le(e,t){for(const s of _.values())if(s.cardIndex===e)return;const n=Ie(t,e),o=Bn++,l=S[e]?.getOptions(),a=Ro(n);if(a){const s=a.document;s.title=n,Object.assign(s.documentElement.style,{height:"100%"}),Object.assign(s.body.style,{margin:"0",height:"100vh",overflow:"hidden",display:"flex",flexDirection:"column",fontFamily:O.family}),Ho(u,s.documentElement);const r=Fo(u,s.documentElement,()=>M.setOptions({})),i=s.createElement("div");i.dataset.wmapWindowBanner="1",i.textContent=n,Object.assign(i.style,{display:"none",padding:`${v.sm} ${v.xl}`,fontSize:O.body,fontWeight:"700",background:m.warnBg,color:m.warnText,borderBottom:`1px solid ${m.warnBorder}`,flexShrink:"0"}),s.body.appendChild(i);const c=s.createElement("div");Object.assign(c.style,{flex:"1",minHeight:"0",display:"flex",flexDirection:"column"}),s.body.appendChild(c);const{wrap:f,metaPanel:b}=Jt(s,n,t.wafer.metadata??void 0),k=s.createElement("div");Object.assign(k.style,{display:"flex",alignItems:"center",padding:`${v.md} ${v.lg} ${v.sm}`,borderBottom:`1px solid ${m.menuBorder}`,flexShrink:"0",gap:v.sm}),k.appendChild(f),c.appendChild(k);const D=s.createElement("div");Object.assign(D.style,{position:"relative",flex:"1",minHeight:"0",overflow:"hidden",display:"flex",flexDirection:"column"}),b&&D.appendChild(b),c.appendChild(D);const M=ft(D,t,void 0,l),y=setInterval(()=>{a.closed&&qe(o)},400);a.addEventListener("pagehide",()=>qe(o)),_.set(o,{id:o,ctrl:M,cardIndex:e,label:n,closePollId:y,stopThemeSync:r,close:()=>{a.closed||a.close()},setTitle:R=>{s.title=R,i.textContent=R,i.style.display="block"}})}else{const s=Io({title:n,onClose:()=>qe(o),anchor:u});s.contentWrap.style.flexDirection="column",en(s,n,t.wafer.metadata??void 0);const r=ft(s.contentWrap,t,void 0,l);_.set(o,{id:o,ctrl:r,cardIndex:e,label:n,closePollId:null,close:()=>s.close(),setTitle:i=>{const c=s.box.querySelector("[data-wmap-window-title]");c&&(c.textContent=i,c.title=i)}})}S[e]?.destroy(),S[e]=null,lo(e,a!==null),so(e)}function ft(e,t,n,o){const l=t.viewOptions?{...d,...t.viewOptions}:d,a=o?{...l,...o}:l,r={...n!==void 0?{...a,plotMode:"value",activeTest:n}:a,showLegend:!0,legendPosition:ye},i=bn(e,t,{viewOptions:r,showTooltip:!0,padding:I,statsSummary:t.statsSummary,onSaveImage:p.onSaveImage,onSaveText:p.onSaveText,onClick:t.onClick,onSelect:t.onSelect,showExpandButton:!1,showIdentity:!1});return i.setViewControlsVisible(!0),i.setSummaryVisible(!0),i.setExpandVisible(!1),i}function qe(e){const t=_.get(e);if(!t)return;_.delete(e),t.closePollId!=null&&clearInterval(t.closePollId),t.stopThemeSync?.();const n=t.ctrl.getOptions();if(t.ctrl.destroy(),t.cardIndex===null)return;const o=t.cardIndex,l=T[o];if(!l)return;const a={...l,viewOptions:n};T[o]=a;const{card:s,ctrl:r,canvasWrapper:i,expandBtn:c}=ct(a,o,T.length);se[o]?.parentElement?.replaceWith(s),S[o]=r,se[o]=i,fe[o]=c}function ro(e){const t=_.get(e);t&&(t.close(),qe(e))}function co(){for(const e of _.values())e.cardIndex!==null&&(e.cardIndex=null,e.setTitle(`${e.label} \u2014 unlinked from gallery`))}function fo(){const e=[...W.querySelectorAll("canvas")];if(!e.length)return;const t=e.length,n=Math.ceil(Math.sqrt(t)),o=Math.ceil(t/n),l=e[0].width,a=e[0].height,s=8,r=(u.ownerDocument.defaultView??window).devicePixelRatio||1,i=Math.round(26*r),c=Math.round(12*r),f=u.ownerDocument.createElement("canvas");f.width=n*l+(n-1)*s,f.height=o*(a+i)+(o-1)*s;const b=f.getContext("2d"),k=Do(W);b.fillStyle=k.background,b.fillRect(0,0,f.width,f.height),e.forEach((D,M)=>{const y=M%n,R=Math.floor(M/n),de=y*(l+s),U=R*(a+i+s),ut=D.closest(".wmap-gallery-card")?.querySelector("span")?.textContent??"";b.fillStyle=k.surface,b.fillRect(de,U,l,i),b.fillStyle=k.text,b.font=`700 ${c}px system-ui, sans-serif`,b.textAlign="left",b.textBaseline="middle",b.fillText(ut,de+Math.round(10*r),U+i/2,l-Math.round(20*r)),b.drawImage(D,de,U+i)}),f.toBlob(D=>{D&&Ko(D,A,p.onSaveImage)})}return{setItems(e){w=e.map(n=>typeof n=="function"?null:n);const t=d.plotMode;if(be.has(t))if(e.some(o=>typeof o=="function"))Y(e);else{const o=dt(t);d={...d,...o},Y(Te(t))}else Y(e)},setOptions(e){E(e,{fireCallback:!1})},getOptions(){return yn(d)},setFindingsNotice(e){kt=e,V()},setLotStatsSummary(e){j=e,Be(),h&&V(),le()},openUserGuide:Gt,destroy(){et++;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=[],Ce()?.remove(),tn.disconnect(),he&&((u.ownerDocument.defaultView??window).cancelAnimationFrame(he),he=0),u.ownerDocument.removeEventListener("click",He,!0),window.removeEventListener("blur",Bt),ae(),cn(),Oe.remove(),q.remove(),h?.remove(),me?.destroy()}}}
|
|
@@ -46,9 +46,17 @@ export interface WaferPreferences {
|
|
|
46
46
|
showQuadrantBoundaries?: boolean;
|
|
47
47
|
showReticle?: boolean;
|
|
48
48
|
showXYIndicator?: boolean;
|
|
49
|
-
ringCount?: number;
|
|
50
49
|
/** Legend position for bin modes. Default 'default'. */
|
|
51
50
|
legendPosition?: 'default' | 'compact' | 'bottom' | 'top' | 'left' | 'floating';
|
|
51
|
+
/**
|
|
52
|
+
* Format for unitless values outside the normal display range [0.1, 9999].
|
|
53
|
+
* `'engineering'` (default): multiples-of-3 exponent notation (e.g. `12E-6`).
|
|
54
|
+
* `'si'`: SI prefix with no unit suffix (e.g. `12 µ`).
|
|
55
|
+
* Values with a unit always use SI prefix regardless of this setting.
|
|
56
|
+
* Set it like any other preference — `viewOptions` or `setOptions` — the one
|
|
57
|
+
* place it is set (it used to have four).
|
|
58
|
+
*/
|
|
59
|
+
fallbackFormat?: 'si' | 'engineering';
|
|
52
60
|
/**
|
|
53
61
|
* Draw this map's own legend block — the categorical bin legend, the spec/
|
|
54
62
|
* pass-fail legend, or the value colorbar, whichever the plot mode calls for.
|
|
@@ -133,24 +141,6 @@ export interface WaferDisplayState {
|
|
|
133
141
|
test: number;
|
|
134
142
|
range: [number, number];
|
|
135
143
|
};
|
|
136
|
-
/**
|
|
137
|
-
* The full, ordered list of metadata values to assign colours from in
|
|
138
|
-
* `metadata` plot mode — applied only when `key` matches `activeMetadataKey`.
|
|
139
|
-
* Set by a host rendering several wafers together (`renderWaferGallery` does
|
|
140
|
-
* it for you) so every map indexes into ONE list; without it each map derives
|
|
141
|
-
* the order from its own dies, and a wafer missing a value the others have
|
|
142
|
-
* paints every later value in the next map's colour. See `ViewOptions`.
|
|
143
|
-
*/
|
|
144
|
-
metadataValueOrder?: {
|
|
145
|
-
key: string;
|
|
146
|
-
values: string[];
|
|
147
|
-
};
|
|
148
|
-
/**
|
|
149
|
-
* Bin colours resolved over the whole population being shown together —
|
|
150
|
-
* set by `renderWaferGallery` so a bin is one colour on every card. A lone
|
|
151
|
-
* map leaves it unset and resolves over its own dies. See `ViewOptions.binColors`.
|
|
152
|
-
*/
|
|
153
|
-
binColors?: BinColors;
|
|
154
144
|
/**
|
|
155
145
|
* Aggregation method for `stackedValues` mode.
|
|
156
146
|
* Drives both the per-die aggregation and the hover tooltip label.
|
|
@@ -158,11 +148,6 @@ export interface WaferDisplayState {
|
|
|
158
148
|
* Defaults to `'mean'` when not set.
|
|
159
149
|
*/
|
|
160
150
|
aggregationMethod?: string;
|
|
161
|
-
/**
|
|
162
|
-
* Total number of wafers in the lot — used to compute bin occurrence percentage
|
|
163
|
-
* in `stackedBins` hover tooltips.
|
|
164
|
-
*/
|
|
165
|
-
lotSize?: number;
|
|
166
151
|
}
|
|
167
152
|
/**
|
|
168
153
|
* All scene-level options that the toolbar can control.
|
|
@@ -179,7 +164,7 @@ export type WaferViewOptions = WaferPreferences & WaferDisplayState;
|
|
|
179
164
|
*
|
|
180
165
|
* That inheritance leaked 16 low-level fields onto the top-level render API, and
|
|
181
166
|
* five of them were **accepted and silently ignored** — `renderWaferMap` computes
|
|
182
|
-
* or overrides them on every draw (`topClearance`
|
|
167
|
+
* or overrides them on every draw (`topClearance` was always 0, and has since been removed from `toCanvas` too;
|
|
183
168
|
* `minRightReserve` is derived from the legend, and `markFailingDies`/`activeBin`/
|
|
184
169
|
* `hoverBin` are read from `viewOptions` and internal hover state instead). An
|
|
185
170
|
* option that is typed, documented and ignored costs a caller a debugging session
|
|
@@ -194,7 +179,7 @@ export type WaferViewOptions = WaferPreferences & WaferDisplayState;
|
|
|
194
179
|
* of the ten options that DO work in exchange for tidiness alone, and the defect
|
|
195
180
|
* here was the five that don't.
|
|
196
181
|
*/
|
|
197
|
-
type ForwardedDrawOptions = Pick<ToCanvasOptions, 'padding' | 'background' | 'showColorbar' | 'colorbarWidth' | 'showAxes' | 'showTitle' | '
|
|
182
|
+
type ForwardedDrawOptions = Pick<ToCanvasOptions, 'padding' | 'background' | 'showColorbar' | 'colorbarWidth' | 'showAxes' | 'showTitle' | 'legendOffset' | 'diePitchMm' | 'metadataFields'>;
|
|
198
183
|
export interface RenderOptions extends ForwardedDrawOptions {
|
|
199
184
|
/** Initial scene display options. All are overridable via the toolbar. */
|
|
200
185
|
viewOptions?: WaferViewOptions;
|
|
@@ -230,40 +215,8 @@ export interface RenderOptions extends ForwardedDrawOptions {
|
|
|
230
215
|
* result has no metadata/lot-stack context.
|
|
231
216
|
*/
|
|
232
217
|
showIdentity?: boolean;
|
|
233
|
-
/**
|
|
234
|
-
* Inset for this map's own chrome row (identity + toolbar) and for a Summary
|
|
235
|
-
* panel docked inside the map area, from the edge of the map area.
|
|
236
|
-
*
|
|
237
|
-
* Defaults to `EDGE_GUTTER` — correct for a standalone map, where the map
|
|
238
|
-
* area IS the region and its chrome is a bounded surface against that edge.
|
|
239
|
-
* Pass the smaller `MAP_CHROME_INSET` when the map is embedded in a surface
|
|
240
|
-
* that already provides its own inset (this is what `renderWaferGallery`
|
|
241
|
-
* passes for its cards); a second full gutter inside one stacks two, which
|
|
242
|
-
* reads as a toolbar standing well off the side of the card.
|
|
243
|
-
*/
|
|
244
|
-
chromeInset?: string;
|
|
245
218
|
/** Optional precomputed wafer-level stats summary. Enables the summary panel toggle button in the toolbar. */
|
|
246
219
|
statsSummary?: StatsSummary;
|
|
247
|
-
/**
|
|
248
|
-
* Bin numbers treated as pass for yield calculation in the summary panel.
|
|
249
|
-
* Defaults to `[1]`. Must match the `passBins` passed to `analyzeWaferMap` / `buildWaferMap`
|
|
250
|
-
* to ensure the summary panel yield label is consistent with the rest of the display.
|
|
251
|
-
*/
|
|
252
|
-
passBins?: number[];
|
|
253
|
-
/**
|
|
254
|
-
* 'full' (default) shows all toolbar controls.
|
|
255
|
-
* 'view-only' shows only zoom, reset, box-select, and download — used by gallery cards.
|
|
256
|
-
*/
|
|
257
|
-
toolbarControls?: 'full' | 'view-only';
|
|
258
|
-
/**
|
|
259
|
-
* Show the plot mode selector in the toolbar. Default true.
|
|
260
|
-
* Set to false when the host application manages mode switching itself.
|
|
261
|
-
*/
|
|
262
|
-
showPlotModeSelector?: boolean;
|
|
263
|
-
/** Minimum zoom relative to fit. Default 0.4. */
|
|
264
|
-
minZoom?: number;
|
|
265
|
-
/** Maximum zoom relative to fit. Default 20. */
|
|
266
|
-
maxZoom?: number;
|
|
267
220
|
/** Filename for the PNG download (without extension). Default `'wafermap'`. */
|
|
268
221
|
downloadFilename?: string;
|
|
269
222
|
/**
|
|
@@ -313,12 +266,6 @@ export interface RenderOptions extends ForwardedDrawOptions {
|
|
|
313
266
|
* identity data into an export.
|
|
314
267
|
*/
|
|
315
268
|
dieList?: DieListDisplayOptions;
|
|
316
|
-
/**
|
|
317
|
-
* Custom tooltip renderer. When provided, replaces the built-in tooltip content.
|
|
318
|
-
* Return a string (set as innerHTML), an HTMLElement (appended directly), or null to suppress the tooltip.
|
|
319
|
-
* The built-in tooltip wrapper (positioning, show/hide behaviour) is preserved.
|
|
320
|
-
*/
|
|
321
|
-
renderTooltip?: (die: Die) => string | HTMLElement | null;
|
|
322
269
|
/**
|
|
323
270
|
* Show a help button in the toolbar that opens the built-in end-user guide in a modal.
|
|
324
271
|
* Default false. Enable in applications that want to surface the guide without linking externally.
|
|
@@ -330,8 +277,6 @@ export interface RenderOptions extends ForwardedDrawOptions {
|
|
|
330
277
|
* has one help button instead of two. See `UserGuideExtension`.
|
|
331
278
|
*/
|
|
332
279
|
userGuideExtension?: UserGuideExtension;
|
|
333
|
-
/** Override the expand action for both the expand button and the E key. Used by the gallery to route through its own modal logic. */
|
|
334
|
-
onExpand?: () => void;
|
|
335
280
|
/**
|
|
336
281
|
* Show the expand button in the toolbar and enable the E-key shortcut.
|
|
337
282
|
* Default true. Independent of `showIdentity` — expand is a view control,
|
|
@@ -350,15 +295,6 @@ export interface RenderOptions extends ForwardedDrawOptions {
|
|
|
350
295
|
* inset, or an explicit CSS height). Width always comes from the container.
|
|
351
296
|
*/
|
|
352
297
|
height?: number | string;
|
|
353
|
-
/**
|
|
354
|
-
* Cap the map's rendered width and height at this many CSS pixels. When
|
|
355
|
-
* the container is larger, the map sits top-left aligned within it rather
|
|
356
|
-
* than stretching to fill it. Number only (a fixed pixel ceiling, not a
|
|
357
|
-
* responsive length like `height`). Omit for no cap (fills the container,
|
|
358
|
-
* current behaviour). The expand button/E-key still opens the map at full
|
|
359
|
-
* size, unaffected by this cap.
|
|
360
|
-
*/
|
|
361
|
-
maxSize?: number;
|
|
362
298
|
/**
|
|
363
299
|
* Base `z-index` for wmap's transient overlays — toolbar menus, the die
|
|
364
300
|
* tooltip, the expand modal, and the user-guide modal. wmap layers its own
|
|
@@ -394,8 +330,6 @@ export interface RenderOptions extends ForwardedDrawOptions {
|
|
|
394
330
|
warnings?: WarningsOptions;
|
|
395
331
|
}
|
|
396
332
|
export interface WaferMapController {
|
|
397
|
-
/** Update the die data (e.g. after a data reload) — rebuilds scene, preserves zoom/pan. */
|
|
398
|
-
setDies(dies: Die[]): void;
|
|
399
333
|
/** Replace the wafer map result entirely — updates both wafer geometry and die data, preserves zoom/pan. */
|
|
400
334
|
setResult(result: WaferMapResult): void;
|
|
401
335
|
/** Merge scene option overrides — rebuilds scene, preserves zoom/pan. */
|
|
@@ -414,50 +348,25 @@ export interface WaferMapController {
|
|
|
414
348
|
clearSelection(): void;
|
|
415
349
|
/** Reset zoom and pan to fitted view. */
|
|
416
350
|
resetZoom(): void;
|
|
417
|
-
/** Update the fallback format for unitless values and re-render. */
|
|
418
|
-
setFallbackFormat(format: 'si' | 'engineering'): void;
|
|
419
351
|
/** Replace the current stats summary used by the built-in Summary panel. */
|
|
420
352
|
setStatsSummary(summary: StatsSummary | undefined): void;
|
|
421
|
-
/** Show or hide the Summary toolbar button without affecting the panel's content. */
|
|
422
|
-
setSummaryVisible(visible: boolean): void;
|
|
423
|
-
/** Show or hide the scene-control toolbar buttons (mode, orientation, etc). */
|
|
424
|
-
setViewControlsVisible(visible: boolean): void;
|
|
425
|
-
/** Show or hide the expand toolbar button. */
|
|
426
|
-
setExpandVisible(visible: boolean): void;
|
|
427
|
-
/** Show or hide the help toolbar button. */
|
|
428
|
-
setHelpButtonVisible(visible: boolean): void;
|
|
429
|
-
/** Show or hide the identity header without affecting its content. */
|
|
430
|
-
setIdentityVisible(visible: boolean): void;
|
|
431
353
|
/**
|
|
432
354
|
* Opens the built-in end-user guide window — the same action the help
|
|
433
355
|
* toolbar button performs, but callable directly. Works regardless of
|
|
434
|
-
* `showHelpButton
|
|
356
|
+
* `showHelpButton`, so a host that
|
|
435
357
|
* hides wmap's own help button (e.g. to fold it into its own combined help
|
|
436
358
|
* menu) can still trigger the guide without a DOM query against wmap's
|
|
437
359
|
* internal button markup.
|
|
438
360
|
*/
|
|
439
361
|
openUserGuide(): void;
|
|
440
|
-
/** Close the auto-mounted Summary panel if it is open. No-op if no panel exists. */
|
|
441
|
-
closeSummaryPanel(): void;
|
|
442
362
|
/** Programmatically open/close the Insights tab. No-op if `insights.enabled` was not set. */
|
|
443
363
|
setInsightsOpen(open: boolean): void;
|
|
444
|
-
/** Move the floating tooltip into a different parent (e.g. a maximized modal box). */
|
|
445
|
-
setTooltipParent(parent: HTMLElement): void;
|
|
446
|
-
/**
|
|
447
|
-
* Returns the current legend entries in `hardBin`/`softBin`/`metadata` modes, `null` in other
|
|
448
|
-
* modes. Each entry includes the bin number (or metadata value string), display name, and color.
|
|
449
|
-
*/
|
|
450
|
-
getActiveLegend(): Array<{
|
|
451
|
-
bin: number | string;
|
|
452
|
-
name: string;
|
|
453
|
-
color: string;
|
|
454
|
-
}> | null;
|
|
455
364
|
/** Remove all event listeners and DOM elements. */
|
|
456
365
|
destroy(): void;
|
|
457
366
|
}
|
|
458
367
|
/** Options that change die colours without changing what the view contains —
|
|
459
368
|
* any of them means every colour-bearing surface (panels, footer) redraws. */
|
|
460
|
-
export declare const COLOR_KEYS: readonly (keyof
|
|
369
|
+
export declare const COLOR_KEYS: readonly (keyof CardViewOptions)[];
|
|
461
370
|
export declare function classifyChanged(keys: (keyof WaferViewOptions)[]): 'preference' | 'state' | 'mixed';
|
|
462
371
|
/**
|
|
463
372
|
* What `renderWaferMap` actually needs: a wafer and its dies, plus anything
|
|
@@ -474,7 +383,68 @@ export declare function classifyChanged(keys: (keyof WaferViewOptions)[]): 'pref
|
|
|
474
383
|
* and each such read had to be found the hard way. Declaring them optional
|
|
475
384
|
* hands that job back to the compiler.
|
|
476
385
|
*/
|
|
386
|
+
/** @internal State a gallery shares with every card so one lot reads as one lot. */
|
|
387
|
+
export interface CardSharedState {
|
|
388
|
+
/**
|
|
389
|
+
* The full, ordered list of metadata values to assign colours from in
|
|
390
|
+
* `metadata` plot mode — applied only when `key` matches `activeMetadataKey`.
|
|
391
|
+
* Set by a host rendering several wafers together (`renderWaferGallery` does
|
|
392
|
+
* it for you) so every map indexes into ONE list; without it each map derives
|
|
393
|
+
* the order from its own dies, and a wafer missing a value the others have
|
|
394
|
+
* paints every later value in the next map's colour. See `ViewOptions`.
|
|
395
|
+
*/
|
|
396
|
+
metadataValueOrder?: {
|
|
397
|
+
key: string;
|
|
398
|
+
values: string[];
|
|
399
|
+
};
|
|
400
|
+
/**
|
|
401
|
+
* Bin colours resolved over the whole population being shown together —
|
|
402
|
+
* set by `renderWaferGallery` so a bin is one colour on every card. A lone
|
|
403
|
+
* map leaves it unset and resolves over its own dies. See `ViewOptions.binColors`.
|
|
404
|
+
*/
|
|
405
|
+
binColors?: BinColors;
|
|
406
|
+
/**
|
|
407
|
+
* Total number of wafers in the lot — the percentage denominator in
|
|
408
|
+
* `stackedBins`/`stackedSoftBins` hover tooltips.
|
|
409
|
+
*/
|
|
410
|
+
lotSize?: number;
|
|
411
|
+
}
|
|
412
|
+
/** @internal */
|
|
413
|
+
export type CardViewOptions = WaferViewOptions & CardSharedState;
|
|
414
|
+
/** @internal Options only renderWaferGallery passes. */
|
|
415
|
+
export interface CardRenderOptions extends Omit<RenderOptions, 'viewOptions'> {
|
|
416
|
+
viewOptions?: CardViewOptions;
|
|
417
|
+
/**
|
|
418
|
+
* Inset for this map's own chrome row (identity + toolbar) and for a Summary
|
|
419
|
+
* panel docked inside the map area, from the edge of the map area.
|
|
420
|
+
*
|
|
421
|
+
* Defaults to `EDGE_GUTTER` — correct for a standalone map, where the map
|
|
422
|
+
* area IS the region and its chrome is a bounded surface against that edge.
|
|
423
|
+
* Pass the smaller `MAP_CHROME_INSET` when the map is embedded in a surface
|
|
424
|
+
* that already provides its own inset (this is what `renderWaferGallery`
|
|
425
|
+
* passes for its cards); a second full gutter inside one stacks two, which
|
|
426
|
+
* reads as a toolbar standing well off the side of the card.
|
|
427
|
+
*/
|
|
428
|
+
chromeInset?: string;
|
|
429
|
+
/** Replaces the expand action for both the expand button and the E key. */
|
|
430
|
+
onExpand?: () => void;
|
|
431
|
+
}
|
|
432
|
+
/** @internal */
|
|
433
|
+
export interface CardController extends WaferMapController {
|
|
434
|
+
setOptions(opts: Partial<CardViewOptions>): void;
|
|
435
|
+
getOptions(): CardViewOptions;
|
|
436
|
+
/** Show or hide the Summary toolbar button without affecting the panel's content. */
|
|
437
|
+
setSummaryVisible(visible: boolean): void;
|
|
438
|
+
/** Show or hide the view-control toolbar buttons (mode, orientation, etc). */
|
|
439
|
+
setViewControlsVisible(visible: boolean): void;
|
|
440
|
+
/** Show or hide the expand toolbar button. */
|
|
441
|
+
setExpandVisible(visible: boolean): void;
|
|
442
|
+
}
|
|
443
|
+
/** @internal The public view of a card's options: everything but the gallery's shared state. */
|
|
444
|
+
export declare function toPublicViewOptions(opts: CardViewOptions): WaferViewOptions;
|
|
477
445
|
export type RenderableWaferMap = Pick<WaferMapResult, 'wafer' | 'dies'> & Partial<Omit<WaferMapResult, 'wafer' | 'dies'>>;
|
|
478
446
|
export declare function renderWaferMap(container: HTMLElement, result: RenderableWaferMap, options?: RenderOptions): WaferMapController;
|
|
447
|
+
/** @internal renderWaferMap plus the gallery-only options and controller methods. */
|
|
448
|
+
export declare function renderWaferMapCard(container: HTMLElement, result: RenderableWaferMap, options?: CardRenderOptions): CardController;
|
|
479
449
|
export {};
|
|
480
450
|
//# sourceMappingURL=renderWaferMap.d.ts.map
|