@wafertools/wafermap 0.30.0 → 0.30.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +13 -3
- package/CHANGELOG.md +175 -0
- package/README.md +3 -3
- package/dist/packages/canvas-adapter/charts/barPanel.js +1 -1
- package/dist/packages/canvas-adapter/charts/binCluster.js +1 -1
- package/dist/packages/canvas-adapter/charts/boxplot.js +1 -1
- package/dist/packages/canvas-adapter/charts/capability.js +1 -1
- package/dist/packages/canvas-adapter/charts/correlation.js +2 -2
- package/dist/packages/canvas-adapter/charts/groupedBarPlot.d.ts +1 -0
- package/dist/packages/canvas-adapter/charts/histogram.js +1 -1
- package/dist/packages/canvas-adapter/charts/testPassRate.js +1 -1
- package/dist/packages/canvas-adapter/charts/trend.js +1 -1
- package/dist/packages/canvas-adapter/deprecated.d.ts +0 -3
- package/dist/packages/canvas-adapter/deprecated.js +1 -1
- package/dist/packages/canvas-adapter/dieList.js +1 -1
- package/dist/packages/canvas-adapter/exportName.d.ts +68 -0
- package/dist/packages/canvas-adapter/exportName.js +1 -0
- package/dist/packages/canvas-adapter/icons.js +2 -2
- package/dist/packages/canvas-adapter/index.d.ts +2 -1
- package/dist/packages/canvas-adapter/index.js +1 -1
- package/dist/packages/canvas-adapter/renderWaferGallery.d.ts +25 -3
- package/dist/packages/canvas-adapter/renderWaferGallery.js +1 -1
- package/dist/packages/canvas-adapter/renderWaferMap.d.ts +24 -2
- package/dist/packages/canvas-adapter/renderWaferMap.js +1 -1
- package/dist/packages/canvas-adapter/summaryPanel.d.ts +21 -6
- package/dist/packages/canvas-adapter/summaryPanel.js +3 -3
- package/dist/packages/canvas-adapter/toCanvas.js +1 -1
- package/dist/packages/canvas-adapter/toolbar.d.ts +6 -0
- 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 +15 -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 +8 -12
- package/dist/packages/core/deprecated.js +1 -1
- package/dist/packages/core/index.d.ts +1 -1
- package/dist/packages/core/index.js +1 -1
- package/dist/packages/core/utils.d.ts +12 -0
- package/dist/packages/core/utils.js +1 -1
- package/dist/packages/core/waferLabel.d.ts +12 -2
- package/dist/packages/core/waferLabel.js +1 -1
- package/dist/packages/renderer/binColors.d.ts +38 -0
- package/dist/packages/renderer/binColors.js +1 -1
- package/dist/packages/renderer/buildView.js +1 -1
- package/dist/packages/renderer/buildWaferMap.d.ts +30 -5
- package/dist/packages/renderer/buildWaferMap.js +1 -1
- package/dist/packages/renderer/deprecate.d.ts +7 -0
- package/dist/packages/renderer/deprecate.js +1 -1
- package/dist/packages/renderer/deprecated.d.ts +2 -2
- package/dist/packages/renderer/deprecated.js +1 -1
- package/dist/packages/renderer/index.d.ts +2 -1
- package/dist/packages/renderer/index.js +1 -1
- package/dist/packages/stats/analyzeWaferLot.js +1 -1
- package/dist/packages/stats/analyzeWaferMap.js +1 -1
- package/dist/packages/stats/capability.d.ts +16 -1
- package/dist/packages/stats/capability.js +1 -1
- package/dist/packages/stats/deprecated.d.ts +30 -35
- package/dist/packages/stats/deprecated.js +1 -1
- package/dist/packages/stats/index.d.ts +4 -2
- package/dist/packages/stats/index.js +1 -1
- package/dist/packages/stats/normalizeInput.d.ts +10 -0
- package/dist/packages/stats/normalizeInput.js +1 -0
- package/dist/packages/stats/regions.d.ts +2 -0
- package/dist/packages/stats/regions.js +1 -1
- package/dist/packages/stats/renderFindingsReport.js +1 -1
- package/dist/packages/stats/renderSummaryReport.d.ts +39 -1
- package/dist/packages/stats/renderSummaryReport.js +26 -26
- package/dist/packages/stats/reportHtml.d.ts +0 -1
- package/dist/packages/stats/reportHtml.js +10 -10
- package/dist/packages/stats/summaryFigures.d.ts +47 -0
- package/dist/packages/stats/summaryFigures.js +1 -0
- package/dist/packages/stats/types.d.ts +118 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{buildView as hi,buildHoverText as gi,findTestDef as rt,resolveTestNumber as Vt}from"../renderer/buildView.js";import{drawMapCanvas as mi,BIN_LEGEND_W as Pn,BIN_LEGEND_W_COMPACT as yi,BIN_LEGEND_ADAPT_COMPACT as bi,BIN_LEGEND_ADAPT_FLOATING as vi}from"./toCanvas.js";import{buildWaferMap as xi,getTestPassStatus as Ci,isParametricTest as zt}from"../renderer/buildWaferMap.js";import{analyzeWaferMap as wi}from"../stats/analyzeWaferMap.js";import{SHADOW as Si,LEADING as Rn,wireControlHover as In,SPACE as W,EDGE_GUTTER as Mi,RADIUS as Wn,FONT as dt,CLR as x,applyOverlayZ as Ei,getTooltip as Fn,hideTooltip as ct,positionTooltip as An,createToolbarHelpers as Di,buildModeMenuEl as Bi,openReparentedModal as ki,openUserGuideWindow as Li,makePaletteBtn as Ti,makeLogScaleBtn as Oi,makeLegendStyleBtn as Pi,makeOverlaysBtn as Ri,makeOrientationBtn as Ii,menuLayerFor as Hn,saveImageBlob as Wi,markMenuTrigger as _e,wireMenuA11y as Vn,wireExpandToggle as Fi,nextFrame as Yt,requestedPassFailDisplay as Ai,overlayMenuRows as Hi,anyOverlayActive as Vi,logWmapVersionOnce as zi,buildDataModeEntries as Yi,metadataKeyHasData as Ni,metadataModeEntry as Xi}from"./toolbar.js";import{waferDisplayLabel as ji}from"../core/waferLabel.js";import{createSummaryPanelEl as Nt,wrapWithSummaryPanel as Xt,renderWaferSummaryContent as _i}from"./summaryPanel.js";import{collectWarnings as Ki,buildWarningsMenuEl as $i,severityOf as Gi}from"./warnings.js";import{ICONS as zn}from"./icons.js";import{createIdentityHeader as Ui,collapsedLabel as jt}from"./identityHeader.js";import{getDieKey as Be,hasPosition as Yn,isPositionedDie as Zi}from"../core/dies.js";import{buildDieListSection as Qi}from"./dieList.js";import{buildMaplessSummary as qi}from"./maplessSummary.js";import{resolveBinColors as Ji,binColorWarning as eo}from"../renderer/binColors.js";import{INPUT_DEFAULT_PASS_BINS as to}from"../core/passBins.js";const Nn=new Set(["binColorScheme","valueColorScheme","reverseValueScheme","useDefinedBinColors","rotation","flipX","flipY","showDieLabels","showPartialDies","showRingBoundaries","showQuadrantBoundaries","showReticle","showXYIndicator","legendPosition","logScale","colorbarRangeMode","markFailingDies","fallbackFormat"]);export const COLOR_KEYS=["binColorScheme","valueColorScheme","reverseValueScheme","useDefinedBinColors","binColors"];export function classifyChanged(O){const g=O.some(f=>Nn.has(f)),v=O.some(f=>!Nn.has(f));return g&&v?"mixed":g?"preference":"state"}export function toPublicViewOptions(O){const{metadataValueOrder:g,binColors:v,lotSize:f,...B}=O;return B}export function renderWaferMap(O,g,v={}){return renderWaferMapCard(O,g,v)}export function renderWaferMapCard(O,g,v={}){zi();const f=O.ownerDocument,B=f.defaultView??window;B.getComputedStyle(O).position==="static"&&(O.style.position="relative");const Xn=O.clientHeight;v.height!=null&&(O.style.height=typeof v.height=="number"?`${v.height}px`:v.height);const pt=g.dataCoverage?g.dataCoverage.unpositionedDies:g.dies.filter(e=>!Yn(e)).length,Ke=(g.dataCoverage?g.dataCoverage.totalDies:g.dies.length-pt)===0&&pt>0,ke=f.createElement("div");Object.assign(ke.style,{display:"flex",flexDirection:"column",width:"100%",height:"100%"}),O.appendChild(ke);const me=f.createElement("div");Object.assign(me.style,{position:"relative",width:"100%",flex:"1 1 auto",minHeight:"0"});const de=v.chromeInset??Mi,j=f.createElement("div");Object.assign(j.style,{display:"flex",alignItems:"stretch",gap:W.sm,background:x.canvasBg,paddingBottom:W.lg,paddingTop:de,paddingLeft:de,paddingRight:de,flexShrink:"0",minWidth:"0"}),ke.appendChild(j),ke.appendChild(me);function Le(){const e=[...j.children].some(t=>t.style.display!=="none");j.style.display=e?"flex":"none"}const w=f.createElement("div");Object.assign(w.style,{position:"relative",width:"100%",height:"100%"});const s=f.createElement("canvas");Object.assign(s.style,{width:"100%",height:"100%",display:"block"}),w.appendChild(s),me.appendChild(w);let $e=null;if(pt>0){let n=function(){if(t){const p=Qi(e,g.testDefs,{...v.dieList,onSaveText:v.onSaveText,waferMetadata:_.metadata,metadataFields:pe,ownerDocument:f});if(p)return p}const o=rt(g.testDefs,d.activeTest??0),r=zt(o)?d.logScale??o?.logScale??!1:!1;return qi(e,g.testDefs,{plotMode:d.plotMode??"hardBin",activeTest:d.activeTest,hbinDefs:G,sbinDefs:U,binColors:y.binColors,valueColorScheme:d.valueColorScheme,reverseValueScheme:d.reverseValueScheme,logScale:r,colorbarRangeMode:d.colorbarRangeMode,valueRangeDies:g.dies})},i=function(o){const r=f.createElement("button");return r.type="button",In(r),Object.assign(r.style,{fontSize:dt.body,padding:`${W.xxs} ${W.sm}`,borderRadius:Wn.control,flexShrink:"0",border:`1px solid ${x.menuBorder}`,background:x.menuBg,color:x.text,cursor:"pointer"}),r.textContent=t?"View chart":"View die list",r.addEventListener("click",p=>{p.stopPropagation(),t=!t,r.textContent=t?"View chart":"View die list",o()}),r};const e=g.dies.filter(o=>!Yn(o));let t=!1;if(Ke){const o=f.createElement("div");Object.assign(o.style,{position:"absolute",inset:"0",background:x.panelBg,padding:W.xl,boxSizing:"border-box",overflow:"hidden",display:"flex",flexDirection:"column",gap:W.md,zIndex:"1"});const r=f.createElement("div");Object.assign(r.style,{display:"flex",justifyContent:"space-between",alignItems:"flex-start",gap:W.md});const p=f.createElement("span");Object.assign(p.style,{fontSize:dt.body,color:x.label,lineHeight:Rn.base}),p.textContent="No die position data for this wafer.",r.appendChild(p);const l=f.createElement("div");Object.assign(l.style,{flex:"1",minHeight:"0",overflow:"auto",display:"flex",flexDirection:"column"}),r.appendChild(i(()=>l.replaceChildren(n()))),o.appendChild(r),o.appendChild(l),w.appendChild(o),$e=()=>{t||l.replaceChildren(n())}}else{const o=f.createElement("div");Object.assign(o.style,{position:"absolute",left:"0",right:"0",bottom:"0",zIndex:"3",background:x.panelBg,borderTop:`1px solid ${x.menuBorder}`,fontSize:dt.body,color:x.text,cursor:"pointer",padding:`${W.xs} ${W.md}`,display:"flex",alignItems:"center",justifyContent:"space-between",gap:W.md}),In(o,"bare");const r=f.createElement("span");r.textContent=`+${e.length} ${e.length===1?"die":"dies"} without position data`,o.appendChild(r);const p=f.createElement("span");p.textContent="\u25BE",Object.assign(p.style,{fontSize:dt.body,lineHeight:Rn.none,color:x.label,flexShrink:"0"}),o.appendChild(p),o.setAttribute("aria-expanded","false"),o.setAttribute("aria-label",`${e.length} dies without position data. Click to view.`);let l=null,a=null;Fi(o,c=>{if(p.textContent=c?"\u25B4":"\u25BE",o.setAttribute("aria-expanded",String(c)),c){l=f.createElement("div");const h=o.getBoundingClientRect().height||28;Object.assign(l.style,{position:"absolute",left:"0",right:"0",bottom:`${h}px`,top:"20%",zIndex:"2",background:x.panelBg,borderTop:`1px solid ${x.menuBorder}`,padding:W.md,boxSizing:"border-box",display:"flex",flexDirection:"column",gap:W.md}),l.addEventListener("click",oe=>oe.stopPropagation());const m=f.createElement("div");Object.assign(m.style,{display:"flex",justifyContent:"flex-end"}),m.appendChild(i(()=>{a&&a.replaceChildren(n())})),l.appendChild(m),a=f.createElement("div"),Object.assign(a.style,{flex:"1",minHeight:"0",overflow:"auto",display:"flex",flexDirection:"column"}),a.appendChild(n()),l.appendChild(a),w.appendChild(l)}else l&&(l.remove(),l=null,a=null)}),w.appendChild(o),$e=()=>{a&&!t&&a.replaceChildren(n())}}}const{onHover:Ge,onClick:jn,onSelect:ce,onViewOptionsChange:_n,showTooltip:Kn=!0,showToolbar:Te=!0,showIdentity:_t=!0,summaryPanel:Oe,showHelpButton:Kt=!1,userGuideExtension:$n,onExpand:$t,showExpandButton:Gt=!0,zIndex:Gn,insights:ft,warnings:Ut,viewOptions:Un={},...ye}=v,Pe=ft?.enabled??!1,Zn=.4,Qn=20,Ue=[...g.passBins??to],Zt=Ut?.display??!0,qn=Ei(Gn);let se=v.statsSummary,le=[],Qt=!1,Ze=null,qt=!1;function ut(){const e=Ki({result:g,statsSummary:se,extra:Ze?[Ze]:[]}),t=e.length!==le.length||e.some((n,i)=>n.code!==le[i]?.code||n.message!==le[i]?.message);le=e,(t||!Qt)&&(Qt=!0,Ut?.onWarning?.(e))}ut();let be=g,_=g.wafer,ve=g.dies,M=new Set,G=g.hbinDefs,U=g.sbinDefs,ee=g.testDefs,pe=g.metadataFields,Jt=g.reticles?.length?g.reticles:void 0,en=g.reticleConfig,tn=g.view?.dataAxisFlip,ht=g.isLotStack??!1,gt=g.aggrMethod,mt=g.lotSize;const Jn=Te&&Pe;let V=null,Z=null,Q=null;_t&&(V=Ui(jt(_.metadata??{},Re())??"",_.metadata,{lotStack:Re(),ownerDocument:f}),w.appendChild(V.metaPanel),V.metaPanel.style.visibility="visible",V.isEmpty()||(Z=nn(V.wrap),j.insertBefore(Z,j.firstChild),Le()));function nn(e){const t=f.createElement("div");return Object.assign(t.style,{display:"flex",alignItems:"center",padding:`${W.sm} ${W.lg}`,flex:"1 1 auto",minWidth:"0",overflow:"hidden",gap:W.sm}),Object.assign(e.style,{flex:"1",minWidth:"0"}),t.appendChild(e),t}function Re(){return ht?{lotSize:mt??1,aggrMethod:gt}:void 0}function ei(){if(!V)return;V.update(jt(_.metadata??{},Re())??"",_.metadata,Re());const e=Z?.isConnected??!1,t=!V.isEmpty();!t&&e?(Z.remove(),Z=null):t&&!e&&(Z=nn(V.wrap),Z.style.display="",j.insertBefore(Z,j.firstChild),Le())}const ti=[...G??[],...U??[]].some(e=>e.color);let d={plotMode:"hardBin",showDieLabels:!1,showPartialDies:!0,showRingBoundaries:!1,showQuadrantBoundaries:!1,showReticle:!1,showXYIndicator:!1,rotation:0,flipX:!1,flipY:!1,legendPosition:"default",...Un},z=null,te=!1,on=null;function ni(){return Pe?z?Promise.resolve(z):(on??=import("./insightsTab.js").then(({createInsightsTab:e})=>(z=e({getItems:()=>[{wafer:_,dies:ve,hbinDefs:G,sbinDefs:U,testDefs:ee,label:ji({wafer:_},0),passBins:Ue,statsSummary:se}],getBinColors:()=>y.binColors,getRingCount:()=>be.ringCount??4,onSaveImage:v.onSaveImage,onSaveText:v.onSaveText,defaultView:ft?.defaultView,showMetadataStrip:!1,contentInset:de,backTab:Jn?void 0:{label:"Map",onBack:()=>Ie(!1)},onOpenGuide:Kt&&!Te?()=>It():void 0,focusTest:t=>{E({plotMode:"value",activeTest:t,highlightBin:void 0}),Ie(!1)},ownerDocument:f}),Object.assign(z.el.style,{position:"absolute",inset:"0",background:x.canvasBg,overflowY:"auto",paddingTop:"0"}),z.el.style.display="none",me.appendChild(z.el),z)),on):Promise.resolve(null)}let sn=0;const yt=["wheel","touchstart","pointerdown","keydown"];function ii(e,t){if(t<=0)return;let n=!1;const i=[],o=()=>{n=!0;for(const p of i)B.clearTimeout(p);i.length=0;for(const p of yt)e.removeEventListener(p,o)},r=()=>n||!te?!0:(e.scrollTop=t,e.scrollTop>=t);if(!r()){for(const p of yt)e.addEventListener(p,o,{passive:!0,once:!0});for(const p of[0,50,150,300,600])i.push(B.setTimeout(()=>{r()},p));i.push(B.setTimeout(()=>{for(const p of yt)e.removeEventListener(p,o)},700))}}function Ie(e){if(!Pe)return;const t=te;te=e,z&&!e&&t&&(sn=z.el.scrollTop),z&&(z.el.style.display=e?"flex":"none"),w.style.visibility=e?"hidden":"",A&&(A.style.display=e||Ke?"none":"flex"),T&&(T.style.display=e?"none":"flex"),Q&&(Q.style.display=he?"none":"flex"),ne&&(ne.style.display="flex"),Z&&(Z.style.display=""),Le(),V&&e&&V.collapse(),tt(),H&&(H.innerHTML=e?zn.wafer:zn.analysis,H.ariaLabel=e?"Back to wafer view":"Insights"),e&&ni().then(n=>{!n||!te||(n.el.style.display="flex",n.render(),ii(n.el,sn))})}Pe&&ft?.defaultOpen&&queueMicrotask(()=>Ie(!0));let y,ln,Y=null,k=null,bt=[],vt;function an(e){vt!==e&&(vt=e,C())}let We=null,xt=ye.legendOffset??{x:0,y:0},Fe=!1,xe=!1,Ae={x:0,y:0},Ct={x:0,y:0},fe=!1,Ce=!1,N="pan",we={x:0,y:0},Qe={x:0,y:0},P={x:0,y:0},R={x:0,y:0},He=!1,Se=!1;function wt(){const e=d;y=hi(_,ve.filter(Zi),{plotMode:e.plotMode,binColorScheme:e.binColorScheme,valueColorScheme:e.valueColorScheme,reverseValueScheme:e.reverseValueScheme,useDefinedBinColors:e.useDefinedBinColors,binColors:e.binColors??Ji(ve,{passBins:Ue,binColorScheme:e.binColorScheme,hbinDefs:G,sbinDefs:U,useDefinedBinColors:e.useDefinedBinColors}),passBins:Ue,showDieLabels:e.showDieLabels,showPartialDies:e.showPartialDies,showRingBoundaries:e.showRingBoundaries,showQuadrantBoundaries:e.showQuadrantBoundaries,showReticle:e.showReticle,showXYIndicator:e.showXYIndicator,reticles:Jt,ringCount:be.ringCount??4,highlightBin:e.highlightBin,highlightMetadataValue:e.highlightMetadataValue,activeTest:e.activeTest,activeMetadataKey:e.activeMetadataKey,testDefs:ee,valueRange:e.valueRange,metadataValueOrder:e.metadataValueOrder,logScale:e.logScale,isLotStack:ht,aggregationMethod:gt??e.aggregationMethod,lotSize:mt??e.lotSize,dataAxisFlip:tn,colorbarRangeMode:e.colorbarRangeMode,passFailDisplay:e.passFailDisplay,fallbackFormat:e.fallbackFormat,interactiveTransform:{rotation:e.rotation??0,flipX:e.flipX??!1,flipY:e.flipY??!1}},{hbinDefs:G,sbinDefs:U,metadataFields:pe}),ln=new Map(y.dies.map((n,i)=>[Be(n),i]));const t=e.binColors?null:eo(y.binColors,y.plotMode);t?.message!==Ze?.message&&(Ze=t,ut(),qt&&St())}wt();let q=null,Me=null,qe=null,rn=v.findingsNotice,oi={},F=null,ae=null;function si(e){const{kind:t,index:n}=e.variable;E(t==="test"?{plotMode:"value",activeTest:n??0,highlightBin:void 0}:t==="softBin"?{plotMode:"softBin",highlightBin:void 0}:{plotMode:"hardBin",highlightBin:void 0});const i=e.highlight;i.kind==="bin"?(Lt(i.dieKeys),E({highlightBin:i.bin})):(i.kind==="region"||i.kind==="dies")&&Lt(i.dieKeys)}function dn(e){_i(e,{wafer:_,dies:ve,yieldSummary:be.yield,dataCoverage:be.dataCoverage,hbinDefs:G,sbinDefs:U,testDefs:ee,statsSummary:se,warnings:Zt?le:[],passBins:Ue,ringCount:be.ringCount??4,binColors:y.binColors,plotMode:d.plotMode??"hardBin",metadataShownElsewhere:_t,fallbackFormat:d.fallbackFormat,activeFindingId:qe,findingsFilter:oi,findingsNotice:rn,onFindingsFilterChange:ue,onSaveText:v.onSaveText,metadataFields:pe,dieListOptions:v.dieList,onFindingClick:(t,n)=>{qe===t.id?(qe=null,Lt([]),E({highlightBin:void 0})):(qe=t.id,si(t)),ue()}})}function ue(){q&&dn(q)}function Ve(){F&&dn(F)}if(Oe?.placement){const e=Oe.placement;q=Nt(e,de,f);const t=w.parentElement,n=w.nextSibling;Me=Xt(w,q,e),t?.insertBefore(Me,n),ue()}else if(se){const e=Oe?.defaultOpen??!Te;F=Nt("right",de,f),F.style.display=e?"block":"none";const t=w.parentElement,n=w.nextSibling;ae=Xt(w,F,"right"),t?.insertBefore(ae,n),Ve()}const I=Kn?Fn(f):null;let ne=null,L=null,A=null,T=null,Je=null,K=null,cn=null,H=null,ie=null,et=null;qt=!0;function St(){if(!ie||!et)return;const e=le.length,t=e>0;if(ie.style.display=t?"flex":"none",et.style.display=t?"":"none",!t)return;const n=Gi(le[0]),i=`${e} data ${e===1?"warning":"warnings"}`;ie.style.color=n==="error"?x.errText:x.warnText,ie.ariaLabel=n==="error"?`${i} \u2014 the map may be positionally wrong`:i}let Mt=null,pn=null,Et=null,Dt=null,Bt=null,kt=null;function Lt(e){M=new Set(e??[]),ce&&ce(Rt()),C()}function tt(){if(!K)return;const e=!!(q??F);K.style.display=se&&e&&!te?"flex":"none";const t=q??F,n=t?t.style.display!=="none":!1;se?.hasNotableFindings&&!n?K.style.color=x.findingIndicator:K.dataset.active||(K.style.color=x.icon)}if(Te){let h=function(D){N=D,i(oe,D==="zoom"),i(S,D==="pan"),Je&&i(Je,D==="select"),s.style.cursor=D==="pan"?"grab":"crosshair"};ne=f.createElement("div"),ne.dataset.wmapToolbar="single",Object.assign(ne.style,{marginLeft:"auto",flexShrink:"0",display:"flex",flexDirection:"row",alignItems:"center",flexWrap:"wrap-reverse",justifyContent:"flex-end",maxWidth:"100%",background:x.menuBg,border:`1px solid ${x.menuBorder}`,borderRadius:Wn.control,boxShadow:Si.panel,pointerEvents:"auto"});const e=Fn(f),t=Di(e),{makeBtn:n,setActive:i,makeSep:o,makeMenuRow:r,makeMenuSection:p,closeOpenMenu:l,getOpenMenu:a,setOpenMenu:c}=t;Mt=l,pn=a,f.addEventListener("click",l,!0),A=f.createElement("div"),Object.assign(A.style,{display:Ke?"none":"flex",alignItems:"center",gap:"0",flexWrap:"wrap",justifyContent:"flex-end"}),ne.appendChild(A);const m=n("download","Download PNG",ri);A.appendChild(m),A.appendChild(o());const oe=n("zoomMode","Zoom (drag to zoom region)",()=>h("zoom")),De=n("zoomIn","Zoom in",()=>Ee(s.clientWidth/2,s.clientHeight/2,1.2)),J=n("zoomOut","Zoom out",()=>Ee(s.clientWidth/2,s.clientHeight/2,1/1.2)),re=n("reset","Reset zoom (double-click)",()=>it());A.appendChild(oe),A.appendChild(De),A.appendChild(J),A.appendChild(re),A.appendChild(o());const S=n("pan","Pan (drag to move)",()=>h("pan"));A.appendChild(S),Je=n("boxSelect","Select (drag to select dies)",()=>h("select")),A.appendChild(Je),i(S,!0);{let D=function(u){return u.plotMode!==(d.plotMode??"hardBin")?!1:u.plotMode==="value"?(d.activeTest??0)===(u.activeTest??0):u.plotMode==="metadata"?d.activeMetadataKey===u.activeMetadataKey:!0},Wt=function(u,b){u.activeTest!==void 0?E({plotMode:u.plotMode,activeTest:u.activeTest,activeMetadataKey:void 0,logScale:u.logScale}):u.activeMetadataKey!==void 0?E({plotMode:u.plotMode,activeTest:void 0,activeMetadataKey:u.activeMetadataKey,passFailDisplay:"off"}):E({plotMode:u.plotMode,activeTest:void 0,activeMetadataKey:void 0,passFailDisplay:"off"}),b.remove(),c(null),_e($,!1)};L=f.createElement("div"),Object.assign(L.style,{display:"flex",alignItems:"center",gap:"0",flexWrap:"wrap",justifyContent:"flex-end"}),ne.appendChild(L),T=f.createElement("div"),Object.assign(T.style,{display:"flex",alignItems:"center",gap:"0"}),L.appendChild(T),T.appendChild(o());const ot=()=>{const u=a();u&&(u.remove(),c(null)),_e($,!1)},$=n("mode","Plot mode",()=>{if(a()){ot();return}const u=ve,b=y.testDefs,{testEntries:at,binEntries:ge,stackedEntries:Ne}=Yi(u,b,{includeStacked:y.isLotStack}),Ht=(pe??[]).filter(je=>Ni(u,je.key)).map(Xi),Xe=Bi($.getBoundingClientRect(),at,ge,Ne,D,Wt,{makeMenuRow:r,makeMenuSection:p},d.plotMode??"hardBin",$.ownerDocument.defaultView??window,Ht);Hn($).appendChild(Xe),c(Xe),_e($,!0),Vn(Xe,$,ot)});_e($,!1);const{btn:st,sync:Ye}=Ti(t,()=>({...d,plotMode:d.plotMode??"hardBin"}),()=>ti,E);Dt=Ye,Dt();const Ft=Ri(t,()=>{const u=!!y.hasReticle,b=(d.plotMode??"hardBin")==="value",{testNumber:at}=Vt(d.activeTest??0,y.testDefs),ge=rt(y.testDefs,at),Ne=b&&ge!==void 0&&!zt(ge),Ht=b&&!Ne&&(ge?.limitLow!==void 0||ge?.limitHigh!==void 0),Xe=b&&!Ne&&y.dies.some(je=>Ci(je,at,ge)!==void 0);return Hi(d,u,{functionalActive:Ne,hasLimits:Ht,hasRecorded:Xe,binMode:(d.plotMode??"hardBin")==="hardBin"||(d.plotMode??"hardBin")==="softBin"},je=>E(je))},()=>Vi(d)),{btn:At,sync:di}=Pi(t,()=>d,u=>E({legendPosition:u}));Et=di,Et();const On=()=>{const{testNumber:u}=Vt(d.activeTest??0,ee),b=rt(ee,u);return b!==void 0&&!zt(b)},{btn:ci,sync:pi}=Oi(t,()=>({...d,functionalActive:On()}),u=>E(u));Bt=pi,Bt();const fi=()=>{const{testNumber:u}=Vt(d.activeTest??0,ee),b=rt(ee,u);return b!==void 0&&(b.limitLow!==void 0||b.limitHigh!==void 0)},lt=n("specRange","Colorbar range: spec limits",()=>{const u=d.colorbarRangeMode==="data"?"spec":"data";E({colorbarRangeMode:u})});kt=()=>{const u=d.plotMode==="value"&&fi()&&Ai(d)==="off"&&!On();lt.style.display=u?"":"none";const b=(d.colorbarRangeMode??"spec")==="spec";i(lt,b),lt.ariaLabel=b?"Colorbar range: spec limits (click for data range)":"Colorbar range: data range (click for spec limits)"},kt();const ui=Ii(t,()=>d,u=>E(u));T.appendChild($),T.appendChild(st),T.appendChild(ci),T.appendChild(lt),Ke||(T.appendChild(o()),T.appendChild(Ft),T.appendChild(o()),T.appendChild(At),T.appendChild(o()),T.appendChild(ui)),se&&(K=n("findings","Summary panel",()=>{const u=q??F;if(!u)return;const b=u.style.display!=="none";u.style.display=b?"none":"block",i(K,!b),tt()}),L.appendChild(o()),L.appendChild(K),F?.style.display!=="none"&&i(K,!0),tt()),Zt&&(et=o(),ie=n("warning","Data warnings",()=>{const u=a();if(l(new MouseEvent("click")),u)return;const b=$i(ie.getBoundingClientRect(),le,B);Hn(me).appendChild(b),c(b),Vn(b,ie,()=>l(new MouseEvent("click")))}),_e(ie,!1),L.appendChild(et),L.appendChild(ie),St()),Pe&&(L.appendChild(o()),H=n("analysis","Insights",()=>{Ie(!te),i(H,te)}),H.dataset.wmapInsightsBtn="1",L.appendChild(H)),Gt&&(L.appendChild(o()),Q=n("expand","Expand (E)",$t??fn),L.appendChild(Q)),Kt&&(L.appendChild(o()),cn=n("help","User guide",()=>It()),L.appendChild(cn))}j.appendChild(ne),Le()}let he=null;function fn(){he&&(he.close(),he=null);const e=me;e.style.flex="1",e.style.minWidth="0",e.style.minHeight="0";const t=jt(_.metadata??{},Re()),n=j.childElementCount>0?[j,e]:[e],i=ki(n,{ownerDocument:f,boxSize:te?{width:"min(96vw, 1600px)",height:"min(92vh, 1000px)"}:void 0,onClosed:()=>{he=null,Q&&(Q.style.display="flex"),te||s.focus({preventScroll:!0})}});i&&(i.box.setAttribute("aria-label",t??"Expanded wafer map"),n.length>1&&(i.contentWrap.style.flexDirection="column"),he=i,Q&&(Q.style.display="none"))}function un(e){const t=d.plotMode;d={...d,...e},e.plotMode!==void 0&&e.plotMode,Object.keys(e).every(r=>r==="legendPosition"||r==="showLegend"||r==="markFailingDies")||wt(),Et?.(),Dt?.(),Bt?.(),kt?.(),C();const i=e.plotMode!==void 0&&e.plotMode!==t,o=COLOR_KEYS.some(r=>r in e);(o||i)&&(ue(),Ve()),(o||i||e.activeTest!==void 0||e.logScale!==void 0||e.colorbarRangeMode!==void 0)&&$e?.()}function E(e){un(e);const t=Object.keys(e);_n?.(d,t,classifyChanged(t))}let Tt=!1;function Ot(){Tt||(Tt=!0,Yt(()=>{Tt=!1,C()},B))}function C(){const e=k??void 0,t=y.dies[0],n=t?{x:t.width,y:t.height}:ye.diePitchMm,i=Math.floor(s.clientWidth||s.width),o=!!(G?.length||U?.length||y.dies.some(m=>m.hbin!=null||m.sbin!=null)),r=d.legendPosition??"default",p=d.showLegend??!0,l=r==="default"||r==="compact",a=(ye.colorbarWidth??16)+28,c=o&&l?r!=="default"?Math.max(Pn,a):i<vi?0:i<bi?Math.max(yi,a):Math.max(Pn,a):void 0,h=mi(s,y,{...ye,minRightReserve:p?c:0,showColorbar:p&&(ye.showColorbar??!0),markFailingDies:d.markFailingDies??!1,legendPosition:r,legendOffset:xt,diePitchMm:n,fallbackFormat:d.fallbackFormat,showAxes:ye.showAxes??k!==null,viewport:e,activeBin:d.plotMode==="metadata"?d.highlightMetadataValue:d.highlightBin,hoverBin:vt,hbinDefs:G,sbinDefs:U,metadataFields:pe});bt=h.binLegendRows,We=h.legendBox??null,k===null&&(Y=h.viewport),M.size>0&&li(),Ce&&ai()}function li(){const e=X();if(!e)return;const t=s.getContext("2d"),n=y.hoverPoints,i=y.rectangles[0],o=i?i.width/2*e.ppm:e.ppm*.5,r=i?i.height/2*e.ppm:e.ppm*.5,p=Math.max(1,Math.min(3,o*.08)),l=o-p,a=r-p,c=[];for(const h of M){const m=ln.get(h);m!==void 0&&c.push({sx:e.originX+n[m].x*e.ppm,sy:e.originY-n[m].y*e.ppm})}if(c.length){t.save(),t.setLineDash([]),t.fillStyle="rgba(0,0,0,0.12)",t.beginPath();for(const{sx:h,sy:m}of c)t.rect(h-l,m-a,l*2,a*2);t.fill(),t.strokeStyle="rgba(255,255,255,0.9)",t.lineWidth=3,t.beginPath();for(const{sx:h,sy:m}of c)t.rect(h-l,m-a,l*2,a*2);t.stroke(),t.strokeStyle="rgba(0,0,0,0.9)",t.lineWidth=1.5,t.beginPath();for(const{sx:h,sy:m}of c)t.rect(h-l,m-a,l*2,a*2);t.stroke(),t.restore()}}function ai(){const e=s.getContext("2d"),t=Math.min(P.x,R.x),n=Math.min(P.y,R.y),i=Math.abs(R.x-P.x),o=Math.abs(R.y-P.y);e.save(),e.fillStyle="rgba(0,0,0,0.08)",e.fillRect(t,n,i,o),e.setLineDash([5,3]),e.strokeStyle="rgba(255,255,255,0.9)",e.lineWidth=3,e.strokeRect(t,n,i,o),e.strokeStyle="rgba(0,0,0,0.9)",e.lineWidth=1.5,e.strokeRect(t,n,i,o),e.restore()}function ri(){s.toBlob(e=>{e&&Wi(e,v.downloadFilename??"wafermap",v.onSaveImage)})}function hn(e){return Y?Math.max(Y.ppm*Zn,Math.min(Y.ppm*Qn,e)):e}function Ee(e,t,n){const i=k??Y;if(!i)return;const o=hn(i.ppm*n),r=o/i.ppm,p=e-(e-i.originX)*r,l=t-(t-i.originY)*r,a=(Y?.snapDist??1)/(o/(Y?.ppm??o));k={originX:p,originY:l,ppm:o,snapDist:a},C()}function X(){return k??Y}function gn(e){if(e.ctrlKey||e.metaKey){e.preventDefault();const t=s.getBoundingClientRect(),n=e.deltaY<0?1.12:1/1.12;Ee(e.clientX-t.left,e.clientY-t.top,n)}else if(k!==null){e.preventDefault();const t=X(),n=k.snapDist;k={originX:t.originX-e.deltaX,originY:t.originY-e.deltaY,ppm:t.ppm,snapDist:n},C()}}function mn(e,t,n){return e>=n.x&&e<n.x+n.w&&t>=n.y&&t<n.y+n.h}function yn(e){if(e.button!==0||!X())return;s.focus({preventScroll:!0}),s.setPointerCapture(e.pointerId);const t=s.getBoundingClientRect(),n=e.clientX-t.left,i=e.clientY-t.top;if(We&&d.legendPosition==="floating"&&mn(n,i,We)){xe=!0,Ae={x:n,y:i},Ct={...xt};return}if(He&&N!=="pan"){Se=!0,fe=!0,we={x:n,y:i},Qe={x:X().originX,y:X().originY},s.style.cursor="grabbing";return}if(N==="zoom"||N==="select"){Ce=!0,P=R={x:n,y:i};return}fe=!0,we={x:n,y:i},Qe={x:X().originX,y:X().originY},s.style.cursor="grabbing"}function bn(e){const t=s.getBoundingClientRect(),n=e.clientX-t.left,i=e.clientY-t.top;if(Ce){R={x:n,y:i},Ot();return}if(xe){const h=n-Ae.x,m=i-Ae.y;h*h+m*m>16&&(xe=!1,Fe=!0,s.style.cursor="grabbing")}if(Fe){xt={x:Ct.x+(n-Ae.x),y:Ct.y+(i-Ae.y)},Ot();return}if(fe){const h=X(),m=k?.snapDist??Y?.snapDist??1;k={originX:Qe.x+(n-we.x),originY:Qe.y+(i-we.y),ppm:h.ppm,snapDist:m},Ot();return}const o=X();if(!o)return;const r=(n-o.originX)/o.ppm,p=(o.originY-i)/o.ppm,a=wn(r,p,o.snapDist)?.die??null,c=bt.find(h=>n>=h.x&&n<h.x+h.w&&i>=h.y&&i<h.y+h.h);if(an(c?c.bin:void 0),c){s.style.cursor="pointer",I&&(I.innerHTML=c.label??`Bin ${c.bin}`,I.style.display="block",An(I,s,e.clientX,e.clientY)),Ge?.(null,e);return}N==="pan"&&(s.style.cursor=a?"crosshair":"grab"),I&&(a?(I.innerHTML=gi(a,y.plotMode,{testDefs:ee,hbinDefs:G,sbinDefs:U,fallbackFormat:d.fallbackFormat,aggrMethod:y.aggrMethod,lotSize:y.lotSize,metadataFields:pe,activeTest:y.activeTest,reticleConfig:en}),I.style.display="block",An(I,s,e.clientX,e.clientY)):I.style.display="none"),Ge?.(a,e)}function vn(e){const t=s.getBoundingClientRect(),n=e.clientX-t.left,i=e.clientY-t.top,o=e.ctrlKey||e.metaKey;if(I&&(n<0||i<0||n>t.width||i>t.height)&&(I.style.display="none"),Ce){Ce=!1,R={x:n,y:i};const l=n-P.x,a=i-P.y,c=X();if(N==="zoom"){if(l*l+a*a<25)Ee(n,i,2);else if(c){const h=Math.min(P.x,R.x),m=Math.max(P.x,R.x),oe=Math.min(P.y,R.y),De=Math.max(P.y,R.y),J=m-h,re=De-oe;if(J>4&&re>4){const S=s.clientWidth,D=s.clientHeight,Wt=S/J,ot=D/re,$=Math.min(Wt,ot),st=hn(c.ppm*$),Ye=st/c.ppm,Ft=(h+m)/2,At=(oe+De)/2;k={originX:S/2-(Ft-c.originX)*Ye,originY:D/2-(At-c.originY)*Ye,ppm:st,snapDist:c.snapDist/Ye}}}C(),s.style.cursor="crosshair";return}if(l*l+a*a<25)Pt(n,i,o,e);else if(c){const h=(Math.min(P.x,R.x)-c.originX)/c.ppm,m=(Math.max(P.x,R.x)-c.originX)/c.ppm,oe=(c.originY-Math.max(P.y,R.y))/c.ppm,De=(c.originY-Math.min(P.y,R.y))/c.ppm,J=y.hoverPoints,re=[];for(let S=0;S<J.length;S++)if(J[S].x>=h&&J[S].x<=m&&J[S].y>=oe&&J[S].y<=De){const D=y.dies[S];D&&re.push(D)}if(o)for(const S of re){const D=Be(S);M.has(D)?M.delete(D):M.add(D)}else M=new Set(re.map(S=>Be(S)));ce?.(Rt())}C(),s.style.cursor="crosshair";return}if(xe){xe=!1,Pt(n,i,o,e);return}if(Fe){Fe=!1,s.style.cursor="grab";return}if(!fe)return;if(fe=!1,Se){Se=!1,s.style.cursor=He||N==="pan"?"grab":"crosshair";return}s.style.cursor=N==="pan"?"grab":"crosshair";const r=n-we.x,p=i-we.y;r*r+p*p<25&&Pt(n,i,o,e)}function Pt(e,t,n,i){for(const l of bt)if(e>=l.x&&e<l.x+l.w&&t>=l.y&&t<l.y+l.h){if(typeof l.bin=="number"){const a=d.highlightBin===l.bin?void 0:l.bin;E({highlightBin:a})}else{const a=d.highlightMetadataValue===l.bin?void 0:l.bin;E({highlightMetadataValue:a})}return}if(We&&mn(e,t,We))return;const o=X();if(!o)return;const p=wn((e-o.originX)/o.ppm,(o.originY-t)/o.ppm,o.snapDist)?.die??null;if(p){jn?.(p,i);const l=Be(p);n?M.has(l)?M.delete(l):M.add(l):M=new Set([l]),ce?.(Rt()),C()}else n||(M=new Set,ce?.([]),C())}function Rt(){const e=[],t=y.hoverPoints;for(let n=0;n<t.length;n++){const i=y.dies[n];i&&M.has(Be(i))&&e.push(i)}return e}function xn(){an(void 0),I&&ct(f),Ge?.(null,new MouseEvent("mouseleave")),s.style.cursor=N==="pan"?"grab":"crosshair"}function Cn(){fe=!1,Se=!1,Ce=!1,xe=!1,Fe=!1,I&&ct(f),Ge?.(null,new MouseEvent("mouseleave")),s.style.cursor=N==="pan"?"grab":"crosshair",C()}function wn(e,t,n){const i=y.hoverPoints,o=y.rectangles;for(let a=0;a<o.length;a++){const c=o[a];if(Math.abs(e-c.x)<=c.width/2&&Math.abs(t-c.y)<=c.height/2){const h=y.dies[a];return h?{die:h,index:a}:null}}let r=null,p=-1,l=n*n;for(let a=0;a<i.length;a++){const c=i[a].x-e,h=i[a].y-t,m=c*c+h*h;m<l&&(l=m,r=y.dies[a]??null,p=a)}return r?{die:r,index:p}:null}const Sn=new B.ResizeObserver(()=>{Y=null,k=null,C()});Sn.observe(s),v.height==null&&Xn<=0&&Yt(()=>Yt(()=>{O.clientHeight>0||console.warn("[wafermap] The map container has zero height, so the map cannot render. renderWaferMap fills its container \u2014 give the container a resolved height: an explicit CSS `height` (e.g. 600px), a height-resolved flex/grid parent, or `position:absolute; inset:0`. Alternatively pass `{ height: 600 }` in the render options and the library will size it for you.")}));let ze=B.matchMedia(`(resolution: ${B.devicePixelRatio}dppx)`);const nt=()=>{ze.removeEventListener("change",nt),ze=B.matchMedia(`(resolution: ${B.devicePixelRatio}dppx)`),ze.addEventListener("change",nt),C()};ze.addEventListener("change",nt);const Mn=B.matchMedia("(prefers-color-scheme: dark)"),En=()=>C();Mn.addEventListener("change",En);const Dn=()=>{I&&ct(f)};B.addEventListener("blur",Dn);function Bn(e){if(e.key==="Escape"&&M.size>0&&(M=new Set,ce?.([]),C()),(e.key==="e"||e.key==="E")&&Gt&&(e.stopPropagation(),($t??fn)()),(e.ctrlKey||e.metaKey)&&(e.key==="="||e.key==="+"?(e.preventDefault(),Ee(s.clientWidth/2,s.clientHeight/2,1.2)):e.key==="-"?(e.preventDefault(),Ee(s.clientWidth/2,s.clientHeight/2,1/1.2)):e.key==="0"&&(e.preventDefault(),it())),!e.ctrlKey&&!e.metaKey&&!e.shiftKey){const n=X();if(n){const i=k?.snapDist??Y?.snapDist??1;let o=0,r=0;e.key==="ArrowLeft"&&(o=20,e.preventDefault()),e.key==="ArrowRight"&&(o=-20,e.preventDefault()),e.key==="ArrowUp"&&(r=20,e.preventDefault()),e.key==="ArrowDown"&&(r=-20,e.preventDefault()),(o||r)&&(k={originX:n.originX+o,originY:n.originY+r,ppm:n.ppm,snapDist:i},C())}e.key===" "&&!He&&(e.preventDefault(),He=!0,N!=="pan"&&(s.style.cursor="grab"))}}function kn(e){e.key===" "&&(He=!1,Se&&(fe=!1,Se=!1),s.style.cursor=N==="pan"?"grab":"crosshair")}s.style.cursor="grab",s.setAttribute("tabindex","0"),s.addEventListener("wheel",gn,{passive:!1}),s.addEventListener("pointerdown",yn),s.addEventListener("pointermove",bn),s.addEventListener("pointerup",vn),s.addEventListener("pointerleave",xn),s.addEventListener("pointercancel",Cn);const Ln=()=>it();s.addEventListener("dblclick",Ln),s.addEventListener("keydown",Bn),s.addEventListener("keyup",kn);const Tn=e=>{e.stopPropagation()};s.addEventListener("click",Tn),s.clientWidth,C(),$e?.();function it(){Y=null,k=null,C()}function It(){import("./userGuideHtml.js").then(e=>Li({buildWaferMap:xi,renderWaferMap,renderWaferGallery:void 0,analyzeWaferMap:wi},e.USER_GUIDE_HTML,$n,O))}return Le(),{setResult(e){be=e,_=e.wafer,ve=e.dies,G=e.hbinDefs,U=e.sbinDefs,ee=e.testDefs,pe=e.metadataFields,Jt=e.reticles?.length?e.reticles:void 0,en=e.reticleConfig,tn=e.view?.dataAxisFlip,ht=e.isLotStack,gt=e.aggrMethod,mt=e.lotSize,ei(),wt(),C(),q&&ue()},setOptions(e){un(e)},getOptions(){return{...d}},resetZoom:it,setSelection(e){M=new Set(e.map(t=>Be(t))),C()},clearSelection(){M=new Set,ce?.([]),C()},setFindingsNotice(e){rn=e,q?ue():F&&Ve()},setStatsSummary(e){if(se=e,ut(),St(),q)ue();else if(F)Ve();else if(e&&!Oe?.placement){const t=Oe?.defaultOpen??!Te;F=Nt("right",de,f),F.style.display=t?"block":"none";const n=w.parentElement,i=w.nextSibling;ae=Xt(w,F,"right"),n?.insertBefore(ae,i),Ve()}tt()},setSummaryVisible(e){K&&(K.style.display=e?"flex":"none")},setViewControlsVisible(e){L&&(L.style.display=e?"flex":"none")},setExpandVisible(e){Q&&(Q.style.display=e?"flex":"none")},openUserGuide:It,setInsightsOpen(e){Ie(e),H&&(e?(H.dataset.active="1",H.style.background=x.bgActive,H.style.color=x.iconActive):(delete H.dataset.active,H.style.background="transparent",H.style.color=x.icon))},destroy(){he?.close(),pn?.()?.remove(),Mt&&f.removeEventListener("click",Mt,!0),s.removeEventListener("wheel",gn),s.removeEventListener("pointerdown",yn),s.removeEventListener("pointermove",bn),s.removeEventListener("pointerup",vn),s.removeEventListener("pointerleave",xn),s.removeEventListener("pointercancel",Cn),s.removeEventListener("dblclick",Ln),s.removeEventListener("keydown",Bn),s.removeEventListener("keyup",kn),s.removeEventListener("click",Tn),Sn.disconnect(),ze.removeEventListener("change",nt),Mn.removeEventListener("change",En),B.removeEventListener("blur",Dn),qn(),I&&ct(f),ne?.remove(),Me&&(Me.parentElement?.insertBefore(w,Me),Me.remove()),ae&&(ae.parentElement?.insertBefore(w,ae),ae.remove()),w.remove(),s.style.cursor="",z?.destroy(),V?.destroy(),ke.remove()}}}
|
|
1
|
+
import{buildView as vi,buildHoverText as xi,findTestDef as dt,resolveTestNumber as zt,buildMapTitle as Ci}from"../renderer/buildView.js";import{drawMapCanvas as wi,BIN_LEGEND_W as Fn,BIN_LEGEND_W_COMPACT as Si,BIN_LEGEND_ADAPT_COMPACT as Mi,BIN_LEGEND_ADAPT_FLOATING as Ei}from"./toCanvas.js";import{buildWaferMap as Di,getTestPassStatus as Bi,isParametricTest as Yt}from"../renderer/buildWaferMap.js";import{analyzeWaferMap as ki}from"../stats/analyzeWaferMap.js";import{SHADOW as Li,LEADING as An,wireControlHover as Hn,SPACE as F,EDGE_GUTTER as Ti,RADIUS as Vn,FONT as ct,CLR as v,applyOverlayZ as Pi,getTooltip as zn,hideTooltip as ft,positionTooltip as Yn,createToolbarHelpers as Oi,buildModeMenuEl as Ri,openReparentedModal as Ii,openUserGuideWindow as Wi,makePaletteBtn as Fi,makeLogScaleBtn as Ai,makeLegendStyleBtn as Hi,makeOverlaysBtn as Vi,makeOrientationBtn as zi,menuLayerFor as Nn,saveImageBlob as Xn,markMenuTrigger as Ke,wireMenuA11y as jn,wireExpandToggle as Yi,nextFrame as Nt,requestedPassFailDisplay as Ni,overlayMenuRows as Xi,anyOverlayActive as ji,logWmapVersionOnce as _i,buildDataModeEntries as Ki,metadataKeyHasData as $i,metadataModeEntry as Gi}from"./toolbar.js";import{waferDisplayLabel as Ui,waferIdentityLabel as Zi}from"../core/waferLabel.js";import{metadataDisplayValue as Qi}from"../core/metadata.js";import{withExportContext as qi,noticeDownloadFilenameChange as Ji}from"./exportName.js";import{createSummaryPanelEl as Xt,wrapWithSummaryPanel as jt,renderWaferSummaryContent as eo}from"./summaryPanel.js";import{collectWarnings as to,buildWarningsMenuEl as no,severityOf as io}from"./warnings.js";import{ICONS as _n}from"./icons.js";import{createIdentityHeader as oo,collapsedLabel as _t}from"./identityHeader.js";import{getDieKey as Be,hasPosition as Kn,isPositionedDie as so}from"../core/dies.js";import{buildDieListSection as lo}from"./dieList.js";import{buildMaplessSummary as ao}from"./maplessSummary.js";import{resolveBinColors as ro,binColorWarning as co}from"../renderer/binColors.js";import{INPUT_DEFAULT_PASS_BINS as fo}from"../core/passBins.js";const $n=new Set(["binColorScheme","valueColorScheme","reverseValueScheme","useDefinedBinColors","rotation","flipX","flipY","showDieLabels","showPartialDies","showRingBoundaries","showQuadrantBoundaries","showReticle","showXYIndicator","legendPosition","logScale","colorbarRangeMode","markFailingDies","fallbackFormat"]);export const COLOR_KEYS=["binColorScheme","valueColorScheme","reverseValueScheme","useDefinedBinColors","binColors"];export function classifyChanged(P){const m=P.some(p=>$n.has(p)),b=P.some(p=>!$n.has(p));return m&&b?"mixed":m?"preference":"state"}export function toPublicViewOptions(P){const{metadataValueOrder:m,binColors:b,lotSize:p,...B}=P;return B}export function renderWaferMap(P,m,b={}){return renderWaferMapCard(P,m,b)}export function renderWaferMapCard(P,m,b={}){_i();const p=P.ownerDocument,B=p.defaultView??window,ke=qi(()=>{const e=Qi(V.metadata?.lot);return{lots:e!==void 0?[e]:[],...ee.isLotStack?{stackedWafers:h?.lotSize??!0}:{wafer:Zi({label:ee.label,wafer:V})}}},b.onSaveImage,b.onSaveText);Ji(b.downloadFilename);function Kt(){const e=h.plotMode==="softBin"||h.plotMode==="stackedSoftBins"?G:$,{primary:t,secondary:n}=Ci(h,d.fallbackFormat,e);return[t,ee.isLotStack?"":n].filter(Boolean).join(" ")||"wafer-map"}B.getComputedStyle(P).position==="static"&&(P.style.position="relative");const Gn=P.clientHeight;b.height!=null&&(P.style.height=typeof b.height=="number"?`${b.height}px`:b.height);const pt=m.dataCoverage?m.dataCoverage.unpositionedDies:m.dies.filter(e=>!Kn(e)).length,$e=(m.dataCoverage?m.dataCoverage.totalDies:m.dies.length-pt)===0&&pt>0,Le=p.createElement("div");Object.assign(Le.style,{display:"flex",flexDirection:"column",width:"100%",height:"100%"}),P.appendChild(Le);const ye=p.createElement("div");Object.assign(ye.style,{position:"relative",width:"100%",flex:"1 1 auto",minHeight:"0"});const ce=b.chromeInset??Ti,K=p.createElement("div");Object.assign(K.style,{display:"flex",alignItems:"stretch",gap:F.sm,background:v.canvasBg,paddingBottom:F.lg,paddingTop:ce,paddingLeft:ce,paddingRight:ce,flexShrink:"0",minWidth:"0"}),Le.appendChild(K),Le.appendChild(ye);function Te(){const e=[...K.children].some(t=>t.style.display!=="none");K.style.display=e?"flex":"none"}const w=p.createElement("div");Object.assign(w.style,{position:"relative",width:"100%",height:"100%"});const s=p.createElement("canvas");Object.assign(s.style,{width:"100%",height:"100%",display:"block"}),w.appendChild(s),ye.appendChild(w);let Ge=null;if(pt>0){let n=function(){if(t){const f=lo(e,m.testDefs,{...b.dieList,onSaveText:ke.onSaveText,waferMetadata:V.metadata,metadataFields:pe,ownerDocument:p});if(f)return f}const o=dt(m.testDefs,d.activeTest??0),r=Yt(o)?d.logScale??o?.logScale??!1:!1;return ao(e,m.testDefs,{plotMode:d.plotMode??"hardBin",activeTest:d.activeTest,hbinDefs:$,sbinDefs:G,binColors:h.binColors,valueColorScheme:d.valueColorScheme,reverseValueScheme:d.reverseValueScheme,logScale:r,colorbarRangeMode:d.colorbarRangeMode,valueRangeDies:m.dies})},i=function(o){const r=p.createElement("button");return r.type="button",Hn(r),Object.assign(r.style,{fontSize:ct.body,padding:`${F.xxs} ${F.sm}`,borderRadius:Vn.control,flexShrink:"0",border:`1px solid ${v.menuBorder}`,background:v.menuBg,color:v.text,cursor:"pointer"}),r.textContent=t?"View chart":"View die list",r.addEventListener("click",f=>{f.stopPropagation(),t=!t,r.textContent=t?"View chart":"View die list",o()}),r};const e=m.dies.filter(o=>!Kn(o));let t=!1;if($e){const o=p.createElement("div");Object.assign(o.style,{position:"absolute",inset:"0",background:v.panelBg,padding:F.xl,boxSizing:"border-box",overflow:"hidden",display:"flex",flexDirection:"column",gap:F.md,zIndex:"1"});const r=p.createElement("div");Object.assign(r.style,{display:"flex",justifyContent:"space-between",alignItems:"flex-start",gap:F.md});const f=p.createElement("span");Object.assign(f.style,{fontSize:ct.body,color:v.label,lineHeight:An.base}),f.textContent="No die position data for this wafer.",r.appendChild(f);const l=p.createElement("div");Object.assign(l.style,{flex:"1",minHeight:"0",overflow:"auto",display:"flex",flexDirection:"column"}),r.appendChild(i(()=>l.replaceChildren(n()))),o.appendChild(r),o.appendChild(l),w.appendChild(o),Ge=()=>{t||l.replaceChildren(n())}}else{const o=p.createElement("div");Object.assign(o.style,{position:"absolute",left:"0",right:"0",bottom:"0",zIndex:"3",background:v.panelBg,borderTop:`1px solid ${v.menuBorder}`,fontSize:ct.body,color:v.text,cursor:"pointer",padding:`${F.xs} ${F.md}`,display:"flex",alignItems:"center",justifyContent:"space-between",gap:F.md}),Hn(o,"bare");const r=p.createElement("span");r.textContent=`+${e.length} ${e.length===1?"die":"dies"} without position data`,o.appendChild(r);const f=p.createElement("span");f.textContent="\u25BE",Object.assign(f.style,{fontSize:ct.body,lineHeight:An.none,color:v.label,flexShrink:"0"}),o.appendChild(f),o.setAttribute("aria-expanded","false"),o.setAttribute("aria-label",`${e.length} dies without position data. Click to view.`);let l=null,a=null;Yi(o,c=>{if(f.textContent=c?"\u25B4":"\u25BE",o.setAttribute("aria-expanded",String(c)),c){l=p.createElement("div");const g=o.getBoundingClientRect().height||28;Object.assign(l.style,{position:"absolute",left:"0",right:"0",bottom:`${g}px`,top:"20%",zIndex:"2",background:v.panelBg,borderTop:`1px solid ${v.menuBorder}`,padding:F.md,boxSizing:"border-box",display:"flex",flexDirection:"column",gap:F.md}),l.addEventListener("click",se=>se.stopPropagation());const y=p.createElement("div");Object.assign(y.style,{display:"flex",justifyContent:"flex-end"}),y.appendChild(i(()=>{a&&a.replaceChildren(n())})),l.appendChild(y),a=p.createElement("div"),Object.assign(a.style,{flex:"1",minHeight:"0",overflow:"auto",display:"flex",flexDirection:"column"}),a.appendChild(n()),l.appendChild(a),w.appendChild(l)}else l&&(l.remove(),l=null,a=null)}),w.appendChild(o),Ge=()=>{a&&!t&&a.replaceChildren(n())}}}const{onHover:Ue,onClick:Un,onSelect:fe,onViewOptionsChange:Zn,showTooltip:Qn=!0,showToolbar:Pe=!0,showIdentity:$t=!0,summaryPanel:Oe,showHelpButton:Gt=!1,userGuideExtension:qn,onExpand:Ut,showExpandButton:Zt=!0,zIndex:Jn,insights:ut,warnings:Qt,viewOptions:ei={},...be}=b,Re=ut?.enabled??!1,ti=.4,ni=20,Ze=[...m.passBins??fo],qt=Qt?.display??!0,ii=Pi(Jn);let le=b.statsSummary,ae=[],Jt=!1,Qe=null,en=!1;function gt(){const e=to({result:m,statsSummary:le,extra:Qe?[Qe]:[]}),t=e.length!==ae.length||e.some((n,i)=>n.code!==ae[i]?.code||n.message!==ae[i]?.message);ae=e,(t||!Jt)&&(Jt=!0,Qt?.onWarning?.(e))}gt();let ee=m,V=m.wafer,ve=m.dies,M=new Set,$=m.hbinDefs,G=m.sbinDefs,te=m.testDefs,pe=m.metadataFields,tn=m.reticles?.length?m.reticles:void 0,nn=m.reticleConfig,on=m.view?.dataAxisFlip,ht=m.isLotStack??!1,mt=m.aggrMethod,yt=m.lotSize;const oi=Pe&ℜlet z=null,Q=null,q=null;$t&&(z=oo(_t(V.metadata??{},Ie())??"",V.metadata,{lotStack:Ie(),ownerDocument:p}),w.appendChild(z.metaPanel),z.metaPanel.style.visibility="visible",z.isEmpty()||(Q=sn(z.wrap),K.insertBefore(Q,K.firstChild),Te()));function sn(e){const t=p.createElement("div");return Object.assign(t.style,{display:"flex",alignItems:"center",padding:`${F.sm} ${F.lg}`,flex:"1 1 auto",minWidth:"0",overflow:"hidden",gap:F.sm}),Object.assign(e.style,{flex:"1",minWidth:"0"}),t.appendChild(e),t}function Ie(){return ht?{lotSize:yt??1,aggrMethod:mt}:void 0}function si(){if(!z)return;z.update(_t(V.metadata??{},Ie())??"",V.metadata,Ie());const e=Q?.isConnected??!1,t=!z.isEmpty();!t&&e?(Q.remove(),Q=null):t&&!e&&(Q=sn(z.wrap),Q.style.display="",K.insertBefore(Q,K.firstChild),Te())}const li=[...$??[],...G??[]].some(e=>e.color);let d={plotMode:"hardBin",showDieLabels:!1,showPartialDies:!0,showRingBoundaries:!1,showQuadrantBoundaries:!1,showReticle:!1,showXYIndicator:!1,rotation:0,flipX:!1,flipY:!1,legendPosition:"default",...ei},Y=null,ne=!1,ln=null;function ai(){return Re?Y?Promise.resolve(Y):(ln??=import("./insightsTab.js").then(({createInsightsTab:e})=>(Y=e({getItems:()=>[{wafer:V,dies:ve,hbinDefs:$,sbinDefs:G,testDefs:te,label:Ui({wafer:V},0),passBins:Ze,statsSummary:le}],getBinColors:()=>h.binColors,getRingCount:()=>ee.ringCount??4,onSaveImage:ke.onSaveImage,onSaveText:ke.onSaveText,defaultView:ut?.defaultView,showMetadataStrip:!1,contentInset:ce,backTab:oi?void 0:{label:"Map",onBack:()=>We(!1)},onOpenGuide:Gt&&!Pe?()=>Wt():void 0,focusTest:t=>{E({plotMode:"value",activeTest:t,highlightBin:void 0}),We(!1)},ownerDocument:p}),Object.assign(Y.el.style,{position:"absolute",inset:"0",background:v.canvasBg,overflowY:"auto",paddingTop:"0"}),Y.el.style.display="none",ye.appendChild(Y.el),Y)),ln):Promise.resolve(null)}let an=0;const bt=["wheel","touchstart","pointerdown","keydown"];function ri(e,t){if(t<=0)return;let n=!1;const i=[],o=()=>{n=!0;for(const f of i)B.clearTimeout(f);i.length=0;for(const f of bt)e.removeEventListener(f,o)},r=()=>n||!ne?!0:(e.scrollTop=t,e.scrollTop>=t);if(!r()){for(const f of bt)e.addEventListener(f,o,{passive:!0,once:!0});for(const f of[0,50,150,300,600])i.push(B.setTimeout(()=>{r()},f));i.push(B.setTimeout(()=>{for(const f of bt)e.removeEventListener(f,o)},700))}}function We(e){if(!Re)return;const t=ne;ne=e,Y&&!e&&t&&(an=Y.el.scrollTop),Y&&(Y.el.style.display=e?"flex":"none"),w.style.visibility=e?"hidden":"",A&&(A.style.display=e||$e?"none":"flex"),T&&(T.style.display=e?"none":"flex"),q&&(q.style.display=he?"none":"flex"),ie&&(ie.style.display="flex"),Q&&(Q.style.display=""),Te(),z&&e&&z.collapse(),nt(),H&&(H.innerHTML=e?_n.wafer:_n.analysis,H.ariaLabel=e?"Back to wafer view":"Insights"),e&&ai().then(n=>{!n||!ne||(n.el.style.display="flex",n.render(),ri(n.el,an))})}Re&&ut?.defaultOpen&&queueMicrotask(()=>We(!0));let h,rn,N=null,k=null,vt=[],xt;function dn(e){xt!==e&&(xt=e,x())}let Fe=null,Ct=be.legendOffset??{x:0,y:0},Ae=!1,xe=!1,He={x:0,y:0},wt={x:0,y:0},ue=!1,Ce=!1,X="pan",we={x:0,y:0},qe={x:0,y:0},O={x:0,y:0},R={x:0,y:0},Ve=!1,Se=!1;function St(){const e=d;h=vi(V,ve.filter(so),{plotMode:e.plotMode,binColorScheme:e.binColorScheme,valueColorScheme:e.valueColorScheme,reverseValueScheme:e.reverseValueScheme,useDefinedBinColors:e.useDefinedBinColors,binColors:e.binColors??ro(ve,{passBins:Ze,binColorScheme:e.binColorScheme,hbinDefs:$,sbinDefs:G,useDefinedBinColors:e.useDefinedBinColors}),passBins:Ze,showDieLabels:e.showDieLabels,showPartialDies:e.showPartialDies,showRingBoundaries:e.showRingBoundaries,showQuadrantBoundaries:e.showQuadrantBoundaries,showReticle:e.showReticle,showXYIndicator:e.showXYIndicator,reticles:tn,ringCount:ee.ringCount??4,highlightBin:e.highlightBin,highlightMetadataValue:e.highlightMetadataValue,activeTest:e.activeTest,activeMetadataKey:e.activeMetadataKey,testDefs:te,valueRange:e.valueRange,metadataValueOrder:e.metadataValueOrder,logScale:e.logScale,isLotStack:ht,aggregationMethod:mt??e.aggregationMethod,lotSize:yt??e.lotSize,dataAxisFlip:on,colorbarRangeMode:e.colorbarRangeMode,passFailDisplay:e.passFailDisplay,fallbackFormat:e.fallbackFormat,interactiveTransform:{rotation:e.rotation??0,flipX:e.flipX??!1,flipY:e.flipY??!1}},{hbinDefs:$,sbinDefs:G,metadataFields:pe}),rn=new Map(h.dies.map((n,i)=>[Be(n),i]));const t=e.binColors?null:co(h.binColors,h.plotMode);t?.message!==Qe?.message&&(Qe=t,gt(),en&&Mt())}St();let U=null,Me=null,Je=null,cn=b.findingsNotice,di={},I=null,re=null;function ci(e){const{kind:t,index:n}=e.variable;E(t==="test"?{plotMode:"value",activeTest:n??0,highlightBin:void 0}:t==="softBin"?{plotMode:"softBin",highlightBin:void 0}:{plotMode:"hardBin",highlightBin:void 0});const i=e.highlight;i.kind==="bin"?(Tt(i.dieKeys),E({highlightBin:i.bin})):(i.kind==="region"||i.kind==="dies")&&Tt(i.dieKeys)}function fn(e){eo(e,{wafer:V,dies:ve,yieldSummary:ee.yield,dataCoverage:ee.dataCoverage,hbinDefs:$,sbinDefs:G,testDefs:te,statsSummary:le,warnings:qt?ae:[],passBins:Ze,ringCount:ee.ringCount??4,binColors:h.binColors,plotMode:d.plotMode??"hardBin",metadataShownElsewhere:$t,fallbackFormat:d.fallbackFormat,activeFindingId:Je,findingsFilter:di,findingsNotice:cn,onFindingsFilterChange:ge,onSaveText:ke.onSaveText,metadataFields:pe,dieListOptions:b.dieList,onFindingClick:(t,n)=>{Je===t.id?(Je=null,Tt([]),E({highlightBin:void 0})):(Je=t.id,ci(t)),ge()}})}function ge(){U&&fn(U)}function ze(){I&&fn(I)}if(Oe?.placement){const e=Oe.placement;U=Xt(e,ce,p);const t=w.parentElement,n=w.nextSibling;Me=jt(w,U,e),t?.insertBefore(Me,n),ge()}else if(le){const e=Oe?.defaultOpen??!Pe;I=Xt("right",ce,p),I.style.display=e?"block":"none";const t=w.parentElement,n=w.nextSibling;re=jt(w,I,"right"),t?.insertBefore(re,n),ze()}const W=Qn?zn(p):null;let ie=null,L=null,A=null,T=null,et=null,j=null,pn=null,H=null,oe=null,tt=null;en=!0;function Mt(){if(!oe||!tt)return;const e=ae.length,t=e>0;if(oe.style.display=t?"flex":"none",tt.style.display=t?"":"none",!t)return;const n=io(ae[0]),i=`${e} data ${e===1?"warning":"warnings"}`;oe.style.color=n==="error"?v.errText:v.warnText,oe.ariaLabel=n==="error"?`${i} \u2014 the map may be positionally wrong`:i}let Et=null,un=null,Dt=null,Bt=null,kt=null,Lt=null;function Tt(e){M=new Set(e??[]),fe&&fe(It()),x()}function nt(){if(!j)return;const e=!!(U??I);j.style.display=le&&e&&!ne?"flex":"none";const t=U??I,n=t?t.style.display!=="none":!1;le?.hasNotableFindings&&!n?j.style.color=v.findingIndicator:j.dataset.active||(j.style.color=v.icon)}let gn=null;function hn(e){const t=U??I;t&&(t.style.display=e?"block":"none",j&&gn?.(j,e),nt())}if(Pe){let g=function(D){X=D,i(se,D==="zoom"),i(S,D==="pan"),et&&i(et,D==="select"),s.style.cursor=D==="pan"?"grab":"crosshair"};ie=p.createElement("div"),ie.dataset.wmapToolbar="single",Object.assign(ie.style,{marginLeft:"auto",flexShrink:"0",display:"flex",flexDirection:"row",alignItems:"center",flexWrap:"wrap-reverse",justifyContent:"flex-end",maxWidth:"100%",background:v.menuBg,border:`1px solid ${v.menuBorder}`,borderRadius:Vn.control,boxShadow:Li.panel,pointerEvents:"auto"});const e=zn(p),t=Oi(e),{makeBtn:n,setActive:i,makeSep:o,makeMenuRow:r,makeMenuSection:f,closeOpenMenu:l,getOpenMenu:a,setOpenMenu:c}=t;gn=i,Et=l,un=a,p.addEventListener("click",l,!0),A=p.createElement("div"),Object.assign(A.style,{display:$e?"none":"flex",alignItems:"center",gap:"0",flexWrap:"wrap",justifyContent:"flex-end"}),ie.appendChild(A);const y=n("download","Download PNG",ui);A.appendChild(y),A.appendChild(o());const se=n("zoomMode","Zoom (drag to zoom region)",()=>g("zoom")),De=n("zoomIn","Zoom in",()=>Ee(s.clientWidth/2,s.clientHeight/2,1.2)),J=n("zoomOut","Zoom out",()=>Ee(s.clientWidth/2,s.clientHeight/2,1/1.2)),de=n("reset","Reset zoom (double-click)",()=>ot());A.appendChild(se),A.appendChild(De),A.appendChild(J),A.appendChild(de),A.appendChild(o());const S=n("pan","Pan (drag to move)",()=>g("pan"));A.appendChild(S),et=n("boxSelect","Select (drag to select dies)",()=>g("select")),A.appendChild(et),i(S,!0);{let D=function(u){return u.plotMode!==(d.plotMode??"hardBin")?!1:u.plotMode==="value"?(d.activeTest??0)===(u.activeTest??0):u.plotMode==="metadata"?d.activeMetadataKey===u.activeMetadataKey:!0},Ft=function(u,C){u.activeTest!==void 0?E({plotMode:u.plotMode,activeTest:u.activeTest,activeMetadataKey:void 0,logScale:u.logScale}):u.activeMetadataKey!==void 0?E({plotMode:u.plotMode,activeTest:void 0,activeMetadataKey:u.activeMetadataKey,passFailDisplay:"off"}):E({plotMode:u.plotMode,activeTest:void 0,activeMetadataKey:void 0,passFailDisplay:"off"}),C.remove(),c(null),Ke(Z,!1)};L=p.createElement("div"),Object.assign(L.style,{display:"flex",alignItems:"center",gap:"0",flexWrap:"wrap",justifyContent:"flex-end"}),ie.appendChild(L),T=p.createElement("div"),Object.assign(T.style,{display:"flex",alignItems:"center",gap:"0"}),L.appendChild(T),T.appendChild(o());const st=()=>{const u=a();u&&(u.remove(),c(null)),Ke(Z,!1)},Z=n("mode","Plot mode",()=>{if(a()){st();return}const u=ve,C=h.testDefs,{testEntries:rt,binEntries:me,stackedEntries:Xe}=Ki(u,C,{includeStacked:h.isLotStack}),Vt=(pe??[]).filter(_e=>$i(u,_e.key)).map(Gi),je=Ri(Z.getBoundingClientRect(),rt,me,Xe,D,Ft,{makeMenuRow:r,makeMenuSection:f},d.plotMode??"hardBin",Z.ownerDocument.defaultView??window,Vt);Nn(Z).appendChild(je),c(je),Ke(Z,!0),jn(je,Z,st)});Ke(Z,!1);const{btn:lt,sync:Ne}=Fi(t,()=>({...d,plotMode:d.plotMode??"hardBin"}),()=>li,E);Bt=Ne,Bt();const At=Vi(t,()=>{const u=!!h.hasReticle,C=(d.plotMode??"hardBin")==="value",{testNumber:rt}=zt(d.activeTest??0,h.testDefs),me=dt(h.testDefs,rt),Xe=C&&me!==void 0&&!Yt(me),Vt=C&&!Xe&&(me?.limitLow!==void 0||me?.limitHigh!==void 0),je=C&&!Xe&&h.dies.some(_e=>Bi(_e,rt,me)!==void 0);return Xi(d,u,{functionalActive:Xe,hasLimits:Vt,hasRecorded:je,binMode:(d.plotMode??"hardBin")==="hardBin"||(d.plotMode??"hardBin")==="softBin"},_e=>E(_e))},()=>ji(d)),{btn:Ht,sync:gi}=Hi(t,()=>d,u=>E({legendPosition:u}));Dt=gi,Dt();const Wn=()=>{const{testNumber:u}=zt(d.activeTest??0,te),C=dt(te,u);return C!==void 0&&!Yt(C)},{btn:hi,sync:mi}=Ai(t,()=>({...d,functionalActive:Wn()}),u=>E(u));kt=mi,kt();const yi=()=>{const{testNumber:u}=zt(d.activeTest??0,te),C=dt(te,u);return C!==void 0&&(C.limitLow!==void 0||C.limitHigh!==void 0)},at=n("specRange","Colorbar range: spec limits",()=>{const u=d.colorbarRangeMode==="data"?"spec":"data";E({colorbarRangeMode:u})});Lt=()=>{const u=d.plotMode==="value"&&yi()&&Ni(d)==="off"&&!Wn();at.style.display=u?"":"none";const C=(d.colorbarRangeMode??"spec")==="spec";i(at,C),at.ariaLabel=C?"Colorbar range: spec limits (click for data range)":"Colorbar range: data range (click for spec limits)"},Lt();const bi=zi(t,()=>d,u=>E(u));T.appendChild(Z),T.appendChild(lt),T.appendChild(hi),T.appendChild(at),$e||(T.appendChild(o()),T.appendChild(At),T.appendChild(o()),T.appendChild(Ht),T.appendChild(o()),T.appendChild(bi)),le&&(j=n("findings","Summary panel",()=>{const u=U??I;u&&hn(u.style.display==="none")}),L.appendChild(o()),L.appendChild(j),I?.style.display!=="none"&&i(j,!0),nt()),qt&&(tt=o(),oe=n("warning","Data warnings",()=>{const u=a();if(l(new MouseEvent("click")),u)return;const C=no(oe.getBoundingClientRect(),ae,B);Nn(ye).appendChild(C),c(C),jn(C,oe,()=>l(new MouseEvent("click")))}),Ke(oe,!1),L.appendChild(tt),L.appendChild(oe),Mt()),Re&&(L.appendChild(o()),H=n("analysis","Insights",()=>{We(!ne),i(H,ne)}),H.dataset.wmapInsightsBtn="1",L.appendChild(H)),Zt&&(L.appendChild(o()),q=n("expand","Expand (E)",Ut??mn),L.appendChild(q)),Gt&&(L.appendChild(o()),pn=n("help","User guide",()=>Wt()),L.appendChild(pn))}K.appendChild(ie),Te()}let he=null;function mn(){he&&(he.close(),he=null);const e=ye;e.style.flex="1",e.style.minWidth="0",e.style.minHeight="0";const t=_t(V.metadata??{},Ie()),n=K.childElementCount>0?[K,e]:[e],i=Ii(n,{ownerDocument:p,boxSize:ne?{width:"min(96vw, 1600px)",height:"min(92vh, 1000px)"}:void 0,onClosed:()=>{he=null,q&&(q.style.display="flex"),ne||s.focus({preventScroll:!0})}});i&&(i.box.setAttribute("aria-label",t??"Expanded wafer map"),n.length>1&&(i.contentWrap.style.flexDirection="column"),he=i,q&&(q.style.display="none"))}function yn(e){("binColorScheme"in e||"useDefinedBinColors"in e)&&!("binColors"in e)&&d.binColors!==void 0&&(e={...e,binColors:void 0});const t=d.plotMode;d={...d,...e},e.plotMode!==void 0&&e.plotMode,Object.keys(e).every(r=>r==="legendPosition"||r==="showLegend"||r==="markFailingDies")||St(),Dt?.(),Bt?.(),kt?.(),Lt?.(),x();const i=e.plotMode!==void 0&&e.plotMode!==t,o=COLOR_KEYS.some(r=>r in e);(o||i)&&(ge(),ze()),(o||i||e.activeTest!==void 0||e.logScale!==void 0||e.colorbarRangeMode!==void 0)&&Ge?.()}function E(e){yn(e);const t=Object.keys(e);Zn?.(d,t,classifyChanged(t))}let Pt=!1;function Ot(){Pt||(Pt=!0,Nt(()=>{Pt=!1,x()},B))}function x(){const e=k??void 0,t=h.dies[0],n=t?{x:t.width,y:t.height}:be.diePitchMm,i=Math.floor(s.clientWidth||s.width),o=!!($?.length||G?.length||h.dies.some(y=>y.hbin!=null||y.sbin!=null)),r=d.legendPosition??"default",f=d.showLegend??!0,l=r==="default"||r==="compact",a=(be.colorbarWidth??16)+28,c=o&&l?r!=="default"?Math.max(Fn,a):i<Ei?0:i<Mi?Math.max(Si,a):Math.max(Fn,a):void 0,g=wi(s,h,{...be,minRightReserve:f?c:0,showColorbar:f&&(be.showColorbar??!0),markFailingDies:d.markFailingDies??!1,legendPosition:r,legendOffset:Ct,diePitchMm:n,fallbackFormat:d.fallbackFormat,showAxes:be.showAxes??k!==null,viewport:e,activeBin:d.plotMode==="metadata"?d.highlightMetadataValue:d.highlightBin,hoverBin:xt,hbinDefs:$,sbinDefs:G,metadataFields:pe});vt=g.binLegendRows,Fe=g.legendBox??null,k===null&&(N=g.viewport),M.size>0&&fi(),Ce&&pi()}function fi(){const e=_();if(!e)return;const t=s.getContext("2d"),n=h.hoverPoints,i=h.rectangles[0],o=i?i.width/2*e.ppm:e.ppm*.5,r=i?i.height/2*e.ppm:e.ppm*.5,f=Math.max(1,Math.min(3,o*.08)),l=o-f,a=r-f,c=[];for(const g of M){const y=rn.get(g);y!==void 0&&c.push({sx:e.originX+n[y].x*e.ppm,sy:e.originY-n[y].y*e.ppm})}if(c.length){t.save(),t.setLineDash([]),t.fillStyle="rgba(0,0,0,0.12)",t.beginPath();for(const{sx:g,sy:y}of c)t.rect(g-l,y-a,l*2,a*2);t.fill(),t.strokeStyle="rgba(255,255,255,0.9)",t.lineWidth=3,t.beginPath();for(const{sx:g,sy:y}of c)t.rect(g-l,y-a,l*2,a*2);t.stroke(),t.strokeStyle="rgba(0,0,0,0.9)",t.lineWidth=1.5,t.beginPath();for(const{sx:g,sy:y}of c)t.rect(g-l,y-a,l*2,a*2);t.stroke(),t.restore()}}function pi(){const e=s.getContext("2d"),t=Math.min(O.x,R.x),n=Math.min(O.y,R.y),i=Math.abs(R.x-O.x),o=Math.abs(R.y-O.y);e.save(),e.fillStyle="rgba(0,0,0,0.08)",e.fillRect(t,n,i,o),e.setLineDash([5,3]),e.strokeStyle="rgba(255,255,255,0.9)",e.lineWidth=3,e.strokeRect(t,n,i,o),e.strokeStyle="rgba(0,0,0,0.9)",e.lineWidth=1.5,e.strokeRect(t,n,i,o),e.restore()}function ui(){s.toBlob(e=>{e&&(b.downloadFilename!=null?Xn(e,b.downloadFilename,b.onSaveImage):Xn(e,Kt(),ke.onSaveImage))})}function bn(e){return N?Math.max(N.ppm*ti,Math.min(N.ppm*ni,e)):e}function Ee(e,t,n){const i=k??N;if(!i)return;const o=bn(i.ppm*n),r=o/i.ppm,f=e-(e-i.originX)*r,l=t-(t-i.originY)*r,a=(N?.snapDist??1)/(o/(N?.ppm??o));k={originX:f,originY:l,ppm:o,snapDist:a},x()}function _(){return k??N}function vn(e){if(e.ctrlKey||e.metaKey){e.preventDefault();const t=s.getBoundingClientRect(),n=e.deltaY<0?1.12:1/1.12;Ee(e.clientX-t.left,e.clientY-t.top,n)}else if(k!==null){e.preventDefault();const t=_(),n=k.snapDist;k={originX:t.originX-e.deltaX,originY:t.originY-e.deltaY,ppm:t.ppm,snapDist:n},x()}}function xn(e,t,n){return e>=n.x&&e<n.x+n.w&&t>=n.y&&t<n.y+n.h}function Cn(e){if(e.button!==0||!_())return;s.focus({preventScroll:!0}),s.setPointerCapture(e.pointerId);const t=s.getBoundingClientRect(),n=e.clientX-t.left,i=e.clientY-t.top;if(Fe&&d.legendPosition==="floating"&&xn(n,i,Fe)){xe=!0,He={x:n,y:i},wt={...Ct};return}if(Ve&&X!=="pan"){Se=!0,ue=!0,we={x:n,y:i},qe={x:_().originX,y:_().originY},s.style.cursor="grabbing";return}if(X==="zoom"||X==="select"){Ce=!0,O=R={x:n,y:i};return}ue=!0,we={x:n,y:i},qe={x:_().originX,y:_().originY},s.style.cursor="grabbing"}function wn(e){const t=s.getBoundingClientRect(),n=e.clientX-t.left,i=e.clientY-t.top;if(Ce){R={x:n,y:i},Ot();return}if(xe){const g=n-He.x,y=i-He.y;g*g+y*y>16&&(xe=!1,Ae=!0,s.style.cursor="grabbing")}if(Ae){Ct={x:wt.x+(n-He.x),y:wt.y+(i-He.y)},Ot();return}if(ue){const g=_(),y=k?.snapDist??N?.snapDist??1;k={originX:qe.x+(n-we.x),originY:qe.y+(i-we.y),ppm:g.ppm,snapDist:y},Ot();return}const o=_();if(!o)return;const r=(n-o.originX)/o.ppm,f=(o.originY-i)/o.ppm,a=Dn(r,f,o.snapDist)?.die??null,c=vt.find(g=>n>=g.x&&n<g.x+g.w&&i>=g.y&&i<g.y+g.h);if(dn(c?c.bin:void 0),c){s.style.cursor="pointer",W&&(W.textContent=c.label??`Bin ${c.bin}`,W.style.display="block",Yn(W,s,e.clientX,e.clientY)),Ue?.(null,e);return}X==="pan"&&(s.style.cursor=a?"crosshair":"grab"),W&&(a?(W.innerHTML=xi(a,h.plotMode,{testDefs:te,hbinDefs:$,sbinDefs:G,fallbackFormat:d.fallbackFormat,aggrMethod:h.aggrMethod,lotSize:h.lotSize,metadataFields:pe,activeTest:h.activeTest,reticleConfig:nn}),W.style.display="block",Yn(W,s,e.clientX,e.clientY)):W.style.display="none"),Ue?.(a,e)}function Sn(e){const t=s.getBoundingClientRect(),n=e.clientX-t.left,i=e.clientY-t.top,o=e.ctrlKey||e.metaKey;if(W&&(n<0||i<0||n>t.width||i>t.height)&&(W.style.display="none"),Ce){Ce=!1,R={x:n,y:i};const l=n-O.x,a=i-O.y,c=_();if(X==="zoom"){if(l*l+a*a<25)Ee(n,i,2);else if(c){const g=Math.min(O.x,R.x),y=Math.max(O.x,R.x),se=Math.min(O.y,R.y),De=Math.max(O.y,R.y),J=y-g,de=De-se;if(J>4&&de>4){const S=s.clientWidth,D=s.clientHeight,Ft=S/J,st=D/de,Z=Math.min(Ft,st),lt=bn(c.ppm*Z),Ne=lt/c.ppm,At=(g+y)/2,Ht=(se+De)/2;k={originX:S/2-(At-c.originX)*Ne,originY:D/2-(Ht-c.originY)*Ne,ppm:lt,snapDist:c.snapDist/Ne}}}x(),s.style.cursor="crosshair";return}if(l*l+a*a<25)Rt(n,i,o,e);else if(c){const g=(Math.min(O.x,R.x)-c.originX)/c.ppm,y=(Math.max(O.x,R.x)-c.originX)/c.ppm,se=(c.originY-Math.max(O.y,R.y))/c.ppm,De=(c.originY-Math.min(O.y,R.y))/c.ppm,J=h.hoverPoints,de=[];for(let S=0;S<J.length;S++)if(J[S].x>=g&&J[S].x<=y&&J[S].y>=se&&J[S].y<=De){const D=h.dies[S];D&&de.push(D)}if(o)for(const S of de){const D=Be(S);M.has(D)?M.delete(D):M.add(D)}else M=new Set(de.map(S=>Be(S)));fe?.(It())}x(),s.style.cursor="crosshair";return}if(xe){xe=!1,Rt(n,i,o,e);return}if(Ae){Ae=!1,s.style.cursor="grab";return}if(!ue)return;if(ue=!1,Se){Se=!1,s.style.cursor=Ve||X==="pan"?"grab":"crosshair";return}s.style.cursor=X==="pan"?"grab":"crosshair";const r=n-we.x,f=i-we.y;r*r+f*f<25&&Rt(n,i,o,e)}function Rt(e,t,n,i){for(const l of vt)if(e>=l.x&&e<l.x+l.w&&t>=l.y&&t<l.y+l.h){if(typeof l.bin=="number"){const a=d.highlightBin===l.bin?void 0:l.bin;E({highlightBin:a})}else{const a=d.highlightMetadataValue===l.bin?void 0:l.bin;E({highlightMetadataValue:a})}return}if(Fe&&xn(e,t,Fe))return;const o=_();if(!o)return;const f=Dn((e-o.originX)/o.ppm,(o.originY-t)/o.ppm,o.snapDist)?.die??null;if(f){Un?.(f,i);const l=Be(f);n?M.has(l)?M.delete(l):M.add(l):M=new Set([l]),fe?.(It()),x()}else n||(M=new Set,fe?.([]),x())}function It(){const e=[],t=h.hoverPoints;for(let n=0;n<t.length;n++){const i=h.dies[n];i&&M.has(Be(i))&&e.push(i)}return e}function Mn(){dn(void 0),W&&ft(p),Ue?.(null,new MouseEvent("mouseleave")),s.style.cursor=X==="pan"?"grab":"crosshair"}function En(){ue=!1,Se=!1,Ce=!1,xe=!1,Ae=!1,W&&ft(p),Ue?.(null,new MouseEvent("mouseleave")),s.style.cursor=X==="pan"?"grab":"crosshair",x()}function Dn(e,t,n){const i=h.hoverPoints,o=h.rectangles;for(let a=0;a<o.length;a++){const c=o[a];if(Math.abs(e-c.x)<=c.width/2&&Math.abs(t-c.y)<=c.height/2){const g=h.dies[a];return g?{die:g,index:a}:null}}let r=null,f=-1,l=n*n;for(let a=0;a<i.length;a++){const c=i[a].x-e,g=i[a].y-t,y=c*c+g*g;y<l&&(l=y,r=h.dies[a]??null,f=a)}return r?{die:r,index:f}:null}const Bn=new B.ResizeObserver(()=>{N=null,k=null,x()});Bn.observe(s),b.height==null&&Gn<=0&&Nt(()=>Nt(()=>{P.clientHeight>0||console.warn("[wafermap] The map container has zero height, so the map cannot render. renderWaferMap fills its container \u2014 give the container a resolved height: an explicit CSS `height` (e.g. 600px), a height-resolved flex/grid parent, or `position:absolute; inset:0`. Alternatively pass `{ height: 600 }` in the render options and the library will size it for you.")}));let Ye=B.matchMedia(`(resolution: ${B.devicePixelRatio}dppx)`);const it=()=>{Ye.removeEventListener("change",it),Ye=B.matchMedia(`(resolution: ${B.devicePixelRatio}dppx)`),Ye.addEventListener("change",it),x()};Ye.addEventListener("change",it);const kn=B.matchMedia("(prefers-color-scheme: dark)"),Ln=()=>x();kn.addEventListener("change",Ln);const Tn=()=>{W&&ft(p)};B.addEventListener("blur",Tn);function Pn(e){if(e.key==="Escape"&&M.size>0&&(M=new Set,fe?.([]),x()),(e.key==="e"||e.key==="E")&&Zt&&(e.stopPropagation(),(Ut??mn)()),(e.ctrlKey||e.metaKey)&&(e.key==="="||e.key==="+"?(e.preventDefault(),Ee(s.clientWidth/2,s.clientHeight/2,1.2)):e.key==="-"?(e.preventDefault(),Ee(s.clientWidth/2,s.clientHeight/2,1/1.2)):e.key==="0"&&(e.preventDefault(),ot())),!e.ctrlKey&&!e.metaKey&&!e.shiftKey){const n=_();if(n){const i=k?.snapDist??N?.snapDist??1;let o=0,r=0;e.key==="ArrowLeft"&&(o=20,e.preventDefault()),e.key==="ArrowRight"&&(o=-20,e.preventDefault()),e.key==="ArrowUp"&&(r=20,e.preventDefault()),e.key==="ArrowDown"&&(r=-20,e.preventDefault()),(o||r)&&(k={originX:n.originX+o,originY:n.originY+r,ppm:n.ppm,snapDist:i},x())}e.key===" "&&!Ve&&(e.preventDefault(),Ve=!0,X!=="pan"&&(s.style.cursor="grab"))}}function On(e){e.key===" "&&(Ve=!1,Se&&(ue=!1,Se=!1),s.style.cursor=X==="pan"?"grab":"crosshair")}s.style.cursor="grab",s.setAttribute("tabindex","0"),s.addEventListener("wheel",vn,{passive:!1}),s.addEventListener("pointerdown",Cn),s.addEventListener("pointermove",wn),s.addEventListener("pointerup",Sn),s.addEventListener("pointerleave",Mn),s.addEventListener("pointercancel",En);const Rn=()=>ot();s.addEventListener("dblclick",Rn),s.addEventListener("keydown",Pn),s.addEventListener("keyup",On);const In=e=>{e.stopPropagation()};s.addEventListener("click",In),s.clientWidth,x(),Ge?.();function ot(){N=null,k=null,x()}function Wt(){import("./userGuideHtml.js").then(e=>Wi({buildWaferMap:Di,renderWaferMap,renderWaferGallery:void 0,analyzeWaferMap:ki},e.USER_GUIDE_HTML,qn,P))}return Te(),{setResult(e){ee=e,V=e.wafer,ve=e.dies,$=e.hbinDefs,G=e.sbinDefs,te=e.testDefs,pe=e.metadataFields,tn=e.reticles?.length?e.reticles:void 0,nn=e.reticleConfig,on=e.view?.dataAxisFlip,ht=e.isLotStack,mt=e.aggrMethod,yt=e.lotSize,si(),St(),x(),U&&ge()},setOptions(e){yn(e)},getOptions(){return{...d}},resetZoom:ot,setSelection(e){M=new Set(e.map(t=>Be(t))),x()},clearSelection(){M=new Set,fe?.([]),x()},setFindingsNotice(e){cn=e,U?ge():I&&ze()},setStatsSummary(e){if(le=e,gt(),Mt(),U)ge();else if(I)ze();else if(e&&!Oe?.placement){const t=Oe?.defaultOpen??!Pe;I=Xt("right",ce,p),I.style.display=t?"block":"none";const n=w.parentElement,i=w.nextSibling;re=jt(w,I,"right"),n?.insertBefore(re,i),ze()}nt()},closeSummaryPanel(){hn(!1)},getExportTitle(){return Kt()},getBinColors(){return h.binColors},setSummaryVisible(e){j&&(j.style.display=e?"flex":"none")},setViewControlsVisible(e){L&&(L.style.display=e?"flex":"none")},setExpandVisible(e){q&&(q.style.display=e?"flex":"none")},openUserGuide:Wt,setInsightsOpen(e){We(e),H&&(e?(H.dataset.active="1",H.style.background=v.bgActive,H.style.color=v.iconActive):(delete H.dataset.active,H.style.background="transparent",H.style.color=v.icon))},destroy(){he?.close(),un?.()?.remove(),Et&&p.removeEventListener("click",Et,!0),s.removeEventListener("wheel",vn),s.removeEventListener("pointerdown",Cn),s.removeEventListener("pointermove",wn),s.removeEventListener("pointerup",Sn),s.removeEventListener("pointerleave",Mn),s.removeEventListener("pointercancel",En),s.removeEventListener("dblclick",Rn),s.removeEventListener("keydown",Pn),s.removeEventListener("keyup",On),s.removeEventListener("click",In),Bn.disconnect(),Ye.removeEventListener("change",it),kn.removeEventListener("change",Ln),B.removeEventListener("blur",Tn),ii(),W&&ft(p),ie?.remove(),Me&&(Me.parentElement?.insertBefore(w,Me),Me.remove()),re&&(re.parentElement?.insertBefore(w,re),re.remove()),w.remove(),s.style.cursor="",Y?.destroy(),z?.destroy(),Le.remove()}}}
|
|
@@ -2,6 +2,7 @@ import type { Wafer } from '../core/wafer.js';
|
|
|
2
2
|
import type { Die } from '../core/dies.js';
|
|
3
3
|
import { type BinDef, type TestDef, type YieldSummary, type MetadataFieldDef } from '../renderer/buildWaferMap.js';
|
|
4
4
|
import type { StatsFinding, StatsSummary, LotStatsSummary } from '../stats/types.js';
|
|
5
|
+
import { type ReportMap } from '../stats/renderSummaryReport.js';
|
|
5
6
|
import { type FindingsFilter } from '../stats/filterFindings.js';
|
|
6
7
|
import { type BinColors } from '../renderer/binColors.js';
|
|
7
8
|
import { buildWarningsBanner, type WaferWarning } from './warnings.js';
|
|
@@ -462,15 +463,29 @@ export declare function renderWaferSummaryContent(panel: HTMLDivElement, params:
|
|
|
462
463
|
metadataShownElsewhere?: boolean;
|
|
463
464
|
}): void;
|
|
464
465
|
/** Render lot-level content into the panel. Clears existing content. */
|
|
466
|
+
/** A gallery item as the lot report reads it — every field optional, since a slot may not have loaded. */
|
|
467
|
+
type ReportItem = {
|
|
468
|
+
label?: string;
|
|
469
|
+
wafer?: Wafer;
|
|
470
|
+
dies?: Die[];
|
|
471
|
+
passBins?: readonly number[];
|
|
472
|
+
ringCount?: number;
|
|
473
|
+
hbinDefs?: BinDef[];
|
|
474
|
+
sbinDefs?: BinDef[];
|
|
475
|
+
testDefs?: TestDef[];
|
|
476
|
+
statsSummary?: StatsSummary;
|
|
477
|
+
};
|
|
478
|
+
/**
|
|
479
|
+
* @internal Gallery items as report maps — the one conversion for the gallery's
|
|
480
|
+
* and the lot panel's report buttons. A slot not yet loaded is skipped, but each
|
|
481
|
+
* wafer keeps the label its position gives it, so a report names wafers exactly
|
|
482
|
+
* as the cards do. `passBins`/`ringCount` fill in only for an item built without them.
|
|
483
|
+
*/
|
|
484
|
+
export declare function reportMapsFromItems(items: ReadonlyArray<ReportItem | null | undefined>, passBins: readonly number[], ringCount: number): ReportMap[];
|
|
465
485
|
export declare function renderLotSummaryContent(panel: HTMLDivElement, params: {
|
|
466
486
|
lotSummary: LotStatsSummary;
|
|
467
487
|
/** `passBins` on an item is that wafer's own (`WaferMapResult.passBins`) and wins over the top-level fallback. */
|
|
468
|
-
items: Array<{
|
|
469
|
-
label?: string;
|
|
470
|
-
wafer?: Wafer;
|
|
471
|
-
dies?: Die[];
|
|
472
|
-
passBins?: readonly number[];
|
|
473
|
-
statsSummary?: StatsSummary;
|
|
488
|
+
items: Array<ReportItem & {
|
|
474
489
|
metadataFields?: MetadataFieldDef[];
|
|
475
490
|
} | null>;
|
|
476
491
|
hbinDefs?: BinDef[];
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{waferDisplayLabel as me}from"../core/waferLabel.js";import{itemPassBins as he,passBinsLabel as Ke}from"../core/passBins.js";import{isParametricTest as Ge}from"../renderer/buildWaferMap.js";import{buildRingRegions as Ue,buildQuadrantRegions as Qe,buildRegionYieldData as Xe}from"../stats/regions.js";import{computeFunctionalYield as Ze}from"../stats/analyzeWaferMap.js";import{renderSummaryReportHtml as Je,renderLotSummaryReportHtml as et}from"../stats/renderSummaryReport.js";import{buildFindingsNarrative as tt}from"../stats/findingsNarrative.js";import{filterFindings as nt}from"../stats/filterFindings.js";import{buildFacetTable as it,prettyKey as Ce}from"../stats/facets.js";import{commonMetadata as we}from"../stats/facets.js";import{resolveMetadataColumns as ot}from"../stats/metadataColumns.js";import{resolveBinColors as Se,resolveBinColorsByWafer as st}from"../renderer/binColors.js";import{NO_DATA_FILL as at}from"../renderer/colorMap.js";import{describeWaferPopulation as ve,populationLabel as rt}from"../stats/population.js";import{buildWarningsBanner as ge,collectWarnings as $e}from"./warnings.js";export{ge as buildWarningsBanner};import{fmt as ke,fmtAggregationMethod as lt,plainBinTerms as ne}from"../renderer/fmt.js";import{getUniqueTestNumbers as dt}from"../renderer/buildView.js";import{quantile as ie}from"../stats/math.js";import{buildCapabilityData as ct}from"../stats/capability.js";import{sortBinsForDisplay as pt}from"../stats/binPareto.js";import{poolFunctionalYield as ut}from"../stats/testPassRate.js";import{makeLabeledSelect as Be,makeSegmented as be}from"./charts/chartShell.js";import{SHADOW as Le,MOTION as Ne,LEADING as Q,TRACKING as re,wireControlHover as q,controlStyle as le,SPACE as y,RADIUS as _,FONT as E,CLR as L,sevColor as de,openModal as Fe,openReportModal as Ee,saveTextFile as De,wireTooltip as oe}from"./toolbar.js";import{buildDieListSection as ft}from"./dieList.js";export{csvField}from"../core/utils.js";import{medianOfSorted as mt,csvField as ce}from"../core/utils.js";import{metadataDisplayValue as ht}from"../core/metadata.js";const gt=L.panelBg,Re=`1px solid ${L.menuBorder}`,bt="12px",Y=L.label,K=L.value,Te="10px";function l(e,t,i,n=document){const o=n.createElement(e);return t&&Object.assign(o.style,t),i!==void 0&&(o.textContent=i),o}function J(e){return l("div",{fontSize:Te,fontWeight:"700",letterSpacing:re,textTransform:"uppercase",color:Y,marginBottom:y.sm},e)}const Me=new WeakMap,Ae=["regionYield","testValues","functionalTests"];function pe(e){if(!e)return{collapsed:new Set(Ae),regionMode:"ring",waferSort:"slot"};let t=Me.get(e);return t||(t={collapsed:new Set(Ae),regionMode:"ring",waferSort:"slot"},Me.set(e,t)),t}function X(e,t=!0,i,n){const o=l("div"),d=pe(n?.panel);n?.stateKey&&n.panel&&(t=!d.collapsed.has(n.stateKey));const s=document.createElement("button");s.type="button",Object.assign(s.style,{display:"flex",alignItems:"center",gap:y.xs,width:"100%",background:"none",border:"none",cursor:"pointer",padding:"0 0 6px",textAlign:"left"});const p=l("span",{fontSize:E.meta,color:Y,transition:`transform ${Ne.base}`,transform:t?"rotate(90deg)":"rotate(0deg)",display:"inline-block",lineHeight:Q.none,marginRight:"1px"},"\u25B6"),c=l("span",{fontSize:Te,fontWeight:"700",letterSpacing:re,textTransform:"uppercase",color:Y,flex:"1"},e);if(q(s,"bare"),s.setAttribute("aria-expanded",t?"true":"false"),s.appendChild(p),s.appendChild(c),i){const b=l("span",{fontSize:E.meta,fontWeight:"700",background:L.warnBg,color:L.warnText,borderRadius:_.pill,padding:"1px 5px"},i);s.appendChild(b)}const r=l("div");r.style.display=t?"block":"none";let a=t;if(s.addEventListener("click",()=>{a=!a,r.style.display=a?"block":"none",p.style.transform=a?"rotate(90deg)":"rotate(0deg)",s.setAttribute("aria-expanded",a?"true":"false"),n?.stateKey&&n.panel&&(a?d.collapsed.delete(n.stateKey):d.collapsed.add(n.stateKey))}),n?.control){const b=l("div",{display:"flex",alignItems:"center",gap:y.sm});s.style.width="auto",s.style.flex="1",b.appendChild(s);const u=()=>{r.innerHTML="",n.render?.(r)},S=n.control(u);S&&(S.style.marginBottom="6px",S.addEventListener("click",N=>N.stopPropagation()),b.appendChild(S)),o.appendChild(b)}else o.appendChild(s);return o.appendChild(r),n?.render?.(r),{outer:o,content:r}}function Ie(){return l("div",{height:"1px",background:L.separator,margin:`${bt} 0`,flexShrink:"0"})}function xe(e,t,i=L.barFill,n,o){const d=l("div",{marginBottom:"5px"}),s=l("div",{display:"flex",justifyContent:"space-between",fontSize:E.body,color:K,marginBottom:y.xxs}),p=l("span",{color:Y},e),c=l("span",{fontWeight:"600"},`${t.toFixed(1)}%`);s.appendChild(p),s.appendChild(c);const r=n!==void 0?n:Math.min(100,Math.max(0,t)),a=i,b=l("div",{position:"relative",height:"9px",background:L.bgActive,borderRadius:_.control,overflow:"hidden"}),u=l("div",{height:"100%",width:`${r}%`,background:a,borderRadius:_.control,transition:`width ${Ne.base}`});if(b.appendChild(u),o!==void 0){const S=l("div",{position:"absolute",top:"0",bottom:"0",left:`${o}%`,width:"2px",marginLeft:"-1px",background:L.value,opacity:"0.8"});b.appendChild(S)}return d.appendChild(s),d.appendChild(b),d}function We(){const e=l("div",{display:"flex",gap:y.sm,marginBottom:y.md});return e.finish=()=>{const t=e.lastElementChild;t&&Object.assign(t.style,{borderRight:"none",paddingRight:"0"})},e}function se(e,t,i){const n=l("div",{padding:`${y.xxs} ${y.md} ${y.xxs} 0`,borderRight:Re,textAlign:"center",flex:"1"}),o=l("div",{fontSize:E.heading,fontWeight:"700",color:K,lineHeight:Q.tight},e),d=l("div",{fontSize:E.body,color:Y,marginTop:y.xxs},t);return n.appendChild(o),n.appendChild(d),i&&n.appendChild(l("div",{fontSize:E.body,color:Y,opacity:"0.85"},i)),n}function Pe(e,t){const i=l("div",{display:"flex",justifyContent:"space-between",fontSize:E.body,gap:y.md,marginBottom:"3px"}),n=l("span",{color:Y,flexShrink:"0"},e),o=l("span",{color:K,textAlign:"right",fontWeight:"500",wordBreak:"break-all"},t);return i.appendChild(n),i.appendChild(o),i}function xt(e,t){const i=l("div",{display:"flex",fontSize:E.body,gap:y.sm,marginBottom:"3px"}),n=l("span",{color:Y,flexShrink:"0"},`${e}:`),o=l("span",{color:K,fontWeight:"500",wordBreak:"break-all"},t);return i.appendChild(n),i.appendChild(o),i}export function metadataEntries(e){const t=[];for(const[i,n]of Object.entries(e)){const o=ht(n);o!==void 0&&t.push([i,o])}return t}const yt=["lot","product","testprogram","split"],ue=e=>{const t=yt.indexOf(e.toLowerCase().replace(/[^a-z]/g,""));return t===-1?Number.MAX_SAFE_INTEGER:t};export function buildFacetSummaryChips(e,t=3){if(!e.length)return null;const i=l("div",{display:"flex",flexWrap:"wrap",alignItems:"baseline",gap:`${y.xs} ${y.lg}`}),n=[...e].sort((p,c)=>ue(p.key)-ue(c.key)),o=n.filter(p=>ue(p.key)!==Number.MAX_SAFE_INTEGER),d=n.filter(p=>ue(p.key)===Number.MAX_SAFE_INTEGER),s=p=>{const c=l("span",{whiteSpace:"nowrap"}),r=l("span",{color:Y},`${Ce(p.key)}: `);c.appendChild(r);const a=p.values.slice(0,t),b=p.values.length-a.length;let u=a.map(S=>S.value).join(", ");return b>0&&(u+=` +${b} more`),c.appendChild(document.createTextNode(u)),c};for(const p of o)i.appendChild(s(p));if(d.length){const p=l("span",{display:"none",flexWrap:"wrap",alignItems:"baseline",gap:`${y.xs} ${y.lg}`});for(const a of d)p.appendChild(s(a));const c=l("button",{background:"none",border:"none",padding:"0",cursor:"pointer",color:L.iconActive,fontSize:E.body,whiteSpace:"nowrap"});c.type="button",q(c,"bare");const r=a=>{p.style.display=a?"contents":"none",c.textContent=a?"less":`+${d.length} more`,c.setAttribute("aria-expanded",String(a))};r(!1),c.addEventListener("click",()=>r(c.getAttribute("aria-expanded")!=="true")),i.appendChild(p),i.appendChild(c)}return i}export function buildMetadataStripRow(e,t,i){const n=it(e,i),o=buildFacetSummaryChips(n);if(!o&&!t)return null;const d=l("div",{display:"flex",flexWrap:"wrap",alignItems:"baseline",gap:"4px 14px"});if(t){const s=l("span",{fontWeight:"500",whiteSpace:"nowrap"},t.aggrMethod?`${t.lotSize} wafers stacked \xB7 ${t.aggrMethod}`:`${t.lotSize} wafers stacked`);d.appendChild(s)}return o&&d.appendChild(o),d}const Ct={display:"flex",flexDirection:"column",gap:y.sm,background:L.menuBg,border:`1px solid ${L.menuBorder}`,borderRadius:_.container,padding:`${y.sm} ${y.lg}`,boxShadow:Le.panel,fontSize:E.body,lineHeight:Q.none,boxSizing:"border-box",width:"100%",minWidth:"0"};export function buildMetadataStripBox(e,t,i){const n=buildMetadataStripRow(e,t,i);if(!n)return null;const o=l("div",Ct);return o.appendChild(n),o}export function buildCompactMetadataRows(e){const t=metadataEntries(e);if(!t.length)return null;const i=l("div");for(const[n,o]of t)i.appendChild(xt(Ce(n),o));return i}export function buildMetadataInfoSection(e,t){const i=buildMetadataStripRow(e,t,{facetableOnly:e.length>1});if(!i)return null;const n=l("div");return n.appendChild(J("Wafer Info")),n.appendChild(i),n}export function buildYieldSection(e,t,i=[1]){const n=l("div");n.appendChild(J("Summary"));const o=We();if(o.appendChild(se(String(e.totalDies),"Total dies")),e.partialDies>0&&o.appendChild(se(String(e.partialDies),"Partial")),e.yieldPercent!==null){const d=Ke([i]);o.appendChild(se(`${e.yieldPercent.toFixed(1)}%`,"Yield",`pass: ${d}`))}return o.finish(),n.appendChild(o),e.edgeExcludedDies>0&&n.appendChild(Pe("Edge excluded (outer zone)",String(e.edgeExcludedDies))),n}export function buildBinSection(e,t,i,n,o,d){const s=new Map;if(o)for(const[r,a]of Object.entries(o))s.set(Number(r),a);else for(const r of e){if(r.partial||r.edgeExcluded)continue;const a=i==="hard"?r.hbin:r.sbin;a!=null&&s.set(a,(s.get(a)??0)+1)}if(!s.size)return null;const p=n??Se(e,{passBins:d,...i==="hard"?{hbinDefs:t}:{sbinDefs:t}}),c=l("div");c.appendChild(J(ze(i,[...s.values()].reduce((r,a)=>r+a,0))));for(const r of He(s,t,p[i],p.pass[i]))c.appendChild(r);return c}function ze(e,t){return`${e==="hard"?"Hard":"Soft"} Bin Breakdown \u2014 % of dies (N=${t})`}function He(e,t,i,n){const o=[...e.values()].reduce((p,c)=>p+c,0),d=t?new Map(t.map(p=>[p.bin,p])):null;return pt(e.entries(),n).map(([p,c])=>{const r=d?.get(p),a=r?.name?`Bin ${p} \xB7 ${r.name}`:`Bin ${p}`,b=c/o*100,u=i.get(p)??at;return xe(`${a} (${c})`,b,u)})}export function buildBinBreakdownSection(e){const{dies:t,hbinDefs:i,sbinDefs:n,hardCounts:o,softCounts:d,plotMode:s,passBins:p=[1],panel:c}=e,r=e.binColors??Se(t,{passBins:p,hbinDefs:i,sbinDefs:n}),a=m=>{const x=m==="hard"?o:d,C=new Map;if(x){for(const[v,k]of Object.entries(x))C.set(Number(v),k);return C}for(const v of t){if(v.partial||v.edgeExcluded)continue;const k=m==="hard"?v.hbin:v.sbin;k!=null&&C.set(k,(C.get(k)??0)+1)}return C},b=a("hard"),u=a("soft"),S=b.size>0,N=u.size>0;if(!S&&!N)return null;const I=pe(c),P=s==="softBin"||s==="stackedSoftBins"?"soft":s==="hardBin"||s==="stackedBins"?"hard":void 0;let R=I.binMode??P??(S?"hard":"soft");R==="hard"&&!S&&(R="soft"),R==="soft"&&!N&&(R="hard");const H=R==="hard"?b:u,h=R==="hard"?i:n,f=[...H.values()].reduce((m,x)=>m+x,0),{outer:w}=X(ze(R,f),!0,void 0,{stateKey:"bins",panel:c,render:m=>{const x=R==="hard"?r.hard:r.soft;for(const C of He(H,h,x,r.pass[R]))m.appendChild(C)},control:S&&N&&c?()=>be([["hard","Hard"],["soft","Soft"]],R,m=>{I.binMode=m;const x=buildBinBreakdownSection(e);x&&w.replaceWith(x)},c.ownerDocument,!0):void 0});return w}export function buildLotBinSection(e,t,i,n){return buildBinSection(e,t,i,n)}export function buildRegionYieldPanelSection(e){const{diesByWafer:t,allWafers:i,ringCount:n,passBins:o,panel:d}=e,s=pe(d),p=a=>Xe(t,i,n,o,a==="ring"?Ue:Qe);if(!p("ring").length&&!p("quadrant").length)return null;const c=s.regionMode,{outer:r}=X(c==="ring"?"Ring Yield":"Quadrant Yield",!0,void 0,{stateKey:"regionYield",panel:d,render:a=>{const b=p(c);if(!b.length){a.appendChild(l("div",{fontSize:E.body,color:Y},"No positioned dies for this breakdown."));return}for(const{label:u,n:S,yieldPercent:N}of b)a.appendChild(xe(`${u} (N=${S})`,N))},control:d?()=>be([["ring","Ring"],["quadrant","Quadrant"]],c,a=>{s.regionMode=a;const b=buildRegionYieldPanelSection(e);b&&r.replaceWith(b)},d.ownerDocument,!0):void 0});return r}export function buildLotOverviewSection(e,t=[]){const i=l("div"),n=ve(e.perWafer.map(s=>s.summary.wafer));i.appendChild(J(n.lotId!==void 0?"Lot Summary":"Summary"));const o=We();o.appendChild(se(String(e.stats.waferCount),"Wafers"));const d=e.perWafer.map(s=>s.summary.stats.yieldPercent).filter(s=>s!==null);if(d.length){const s=d.reduce((p,c)=>p+c,0)/d.length;o.appendChild(se(`${s.toFixed(1)}%`,"Mean per-wafer yield"))}if(o.finish(),i.appendChild(o),t.length){const s=t.reduce((c,r)=>c+r.stats.analyzedDies,0),p=t.reduce((c,r)=>c+r.stats.excludedDies,0);(s||p)&&i.appendChild(Pe("Dies analysed",p?`${s.toLocaleString()} (${p.toLocaleString()} excluded)`:s.toLocaleString()))}return i}export function buildPerWaferYieldSection(e,t,i,n,o){const d=e.perWafer.map(f=>({waferIndex:f.waferIndex,label:me(t[f.waferIndex],f.waferIndex).replace(/\s*·\s*\d+(\.\d+)?%$/,""),yieldPct:f.summary.stats.yieldPercent})).filter(f=>f.yieldPct!==null);if(!d.length)return null;const s=Math.min(...d.map(f=>f.yieldPct)),p=Math.max(...d.map(f=>f.yieldPct)),c=s===p?"":` (${s.toFixed(1)}\u2013${p.toFixed(1)}%)`,r=[...d.map(f=>f.yieldPct)].sort((f,w)=>f-w),a=mt(r),b=ie(r,.25),u=ie(r,.75),S=d.length>=5?b-1.5*(u-b):-1/0,N=pe(n),I=f=>{const w=N.waferSort==="yield"?[...d].sort((m,x)=>m.yieldPct-x.yieldPct):d;for(const{waferIndex:m,label:x,yieldPct:C}of w){const k=C<S?`${x} \xB7 low outlier`:x,T=xe(k,C,void 0,void 0,a),A=o?.(m);A?.total&&H(T,A),h(T,m,x,C,A),f.appendChild(T)}},P=` \xB7 median ${a.toFixed(1)}%`,{outer:R}=X("Wafer Yield"+c+P,!0,void 0,{stateKey:"waferYield",panel:n,render:I,control:n?f=>be([["slot","Slot"],["yield","Yield"]],N.waferSort,w=>{N.waferSort=w,f()},n.ownerDocument,!0):void 0});return R;function H(f,w){const m=w.unusual?"unusual":w.notable?"notable":"info",x=l("span",{marginLeft:y.sm,flexShrink:"0",background:de(m),color:"#fff",borderRadius:_.container,padding:"0 5px",fontSize:E.body,fontWeight:"600"},`${w.total}`);x.setAttribute("aria-hidden","true"),oe(x,`${w.total} finding${w.total===1?"":"s"}`+(w.unusual?`, ${w.unusual} unusual`:"")+(w.notable?`, ${w.notable} notable`:"")),f.firstElementChild?.firstElementChild?.appendChild(x)}function h(f,w,m,x,C){i&&(f.style.cursor="pointer",f.style.borderRadius="4px",f.style.padding="2px 3px",f.style.marginLeft="-3px",f.style.marginRight="-3px",f.setAttribute("role","button"),f.setAttribute("aria-label",`${m}, ${x.toFixed(1)}% yield`+(C?.total?`, ${C.total} finding${C.total===1?"":"s"}${C.unusual?`, ${C.unusual} unusual`:""}`:"")+" \u2014 open wafer"),f.tabIndex=0,f.addEventListener("mouseenter",()=>{f.style.background=L.bgHover}),f.addEventListener("mouseleave",()=>{f.style.background=""}),f.addEventListener("focus",()=>{f.style.background=L.bgHover}),f.addEventListener("blur",()=>{f.style.background=""}),f.addEventListener("click",()=>i(w)),f.addEventListener("keydown",v=>{(v.key==="Enter"||v.key===" ")&&(v.preventDefault(),i(w))}))}}function wt(e){const t=[...e].sort((o,d)=>o-d),i=e.reduce((o,d)=>o+d,0)/e.length,n=e.reduce((o,d)=>o+(d-i)**2,0)/e.length;return{min:t[0],max:t[t.length-1],mean:i,count:e.length,stddev:Math.sqrt(n),median:ie(t,.5),q1:ie(t,.25),q3:ie(t,.75)}}function Ye(e,t){if(!e)return[];const i=e.waferMetadata??(e.perWaferMetadata?we(e.perWaferMetadata.map(n=>({metadata:n}))):void 0);return!i||!Object.keys(i).length?[]:ot({waferMetadata:i,waferKeys:"identity",waferPlacement:"csv",reservedLabels:t}).columns}function Oe(e){return e?.populationLabel?[{key:"population",label:"Population",scope:"wafer",constant:e.populationLabel,get:()=>e.populationLabel,csvOnly:!0}]:[]}export function buildTestSection(e,t,i,n,o,d,s,p,c="full"){const r=e.filter(g=>!g.partial&&!g.edgeExcluded),a=new Map((n?.perTestStats??[]).map(g=>[g.testNumber,g])),b=new Map((n?.testSpecYield??[]).map(g=>[g.testNumber,g]));let u;if(t?.length?u=t.filter(Ge).map(g=>({testNumber:g.testNumber,name:g.name,unit:g.unit,limitLow:g.limitLow,limitHigh:g.limitHigh})):u=dt(r).map(F=>({testNumber:F,name:`Test ${F}`})),!u.length)return null;const S=u.filter(g=>r.some(F=>{const O=F.testValues?.[g.testNumber];return O!==void 0&&isFinite(O)}));if(!S.length)return null;const N=S.some(g=>g.limitLow!==void 0||g.limitHigh!==void 0),I=[];for(const g of S){const F=a.get(g.testNumber),O=F&&F.stddev!==void 0&&F.median!==void 0&&F.q1!==void 0&&F.q3!==void 0;let B;if(O){const $=F;B={testNumber:g.testNumber,min:$.min,max:$.max,mean:$.mean,count:$.count,stddev:$.stddev,median:$.median,q1:$.q1,q3:$.q3}}else{const $=r.map(D=>D.testValues?.[g.testNumber]).filter(D=>D!==void 0&&isFinite(D));if(!$.length)continue;B={testNumber:g.testNumber,...wt($)}}let M=null,z=0;if(g.limitLow!==void 0||g.limitHigh!==void 0){const $=b.get(g.testNumber);if($)({yieldPercent:M,totalDies:z}=$);else{const D=r.map(j=>j.testValues?.[g.testNumber]).filter(j=>j!==void 0&&isFinite(j)),Z=D.filter(j=>g.limitLow!==void 0&&j<g.limitLow||g.limitHigh!==void 0&&j>g.limitHigh).length;z=D.length,M=D.length>0?(D.length-Z)/D.length*100:null}}I.push({entry:g,stats:B,specYieldPct:M,specN:z})}if(!I.length)return null;const P=new Map;if(s?.length&&t?.length)for(const g of ct(s,t))g.hasSpec&&P.set(g.testNumber,g.ppk);const R=P.size>0,h=new Set(I.map(g=>g.stats.count)).size===1?I[0].stats.count:null,f=l("div"),w=l("div",{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:y.sm}),m=h!==null?` \xB7 N=${h.toLocaleString()}`:"",x=d?.populationLabel?`Test Values (${I.length}) \u2014 ${d.populationLabel}${m}`:`Test Values (${I.length})${m}`,C=J(x);C.style.marginBottom="0",w.appendChild(C);const v=document.createElement("button");v.type="button",v.textContent="Test values CSV",Object.assign(v.style,{...le("outlined")}),q(v),v.addEventListener("click",()=>{const g=["Test","Unit","N","Min","Q1","Median","Mean","Q3","Max","StdDev"];R&&g.push("Ppk");const F=I.some($=>$.specYieldPct!==null&&$.specN!==$.stats.count);N&&(g.push("LSL","USL","Spec Yield %"),F&&g.push("Spec Yield N"));const O=[...Ye(d,g),...Oe(d)],M=[[...O.map($=>$.label),...g].map(ce).join(",")],z=$=>ke($,void 0,"engineering");for(const{entry:$,stats:D,specYieldPct:Z,specN:j}of I){const ae=[...O.map(te=>te.constant??""),$.name,$.unit??"",String(D.count),z(D.min),z(D.q1),z(D.median),z(D.mean),z(D.q3),z(D.max),z(D.stddev)];if(R){const te=P.get($.testNumber);ae.push(te==null?"":te.toFixed(3))}N&&(ae.push($.limitLow!==void 0?z($.limitLow):"",$.limitHigh!==void 0?z($.limitHigh):"",Z!==null?Z.toFixed(1):""),F&&ae.push($.limitLow!==void 0||$.limitHigh!==void 0?String(j):"")),M.push(ae.map(ce).join(","))}De(M.join(`
|
|
2
|
-
`),"test-values.csv","text/csv",
|
|
3
|
-
`),"functional-tests.csv","text/csv",n)}),b.appendChild(N),a.appendChild(b);const I=l("table",{width:"100%",borderCollapse:"collapse",fontSize:E.body}),P=document.createElement("thead"),R=document.createElement("tr"),H=c===null?["Test","N","Pass","Fail","Pass rate"]:["Test","Pass","Fail","Pass rate"];for(const m of H)R.appendChild(l("th",{textAlign:m==="Test"?"left":"right",fontWeight:"700",fontSize:E.body,letterSpacing:re,textTransform:"uppercase",color:Y,padding:"3px 8px 5px",borderBottom:`1px solid ${L.menuBorder}`,whiteSpace:"nowrap"},m));P.appendChild(R),I.appendChild(P);const h=document.createElement("tbody");for(const m of s){const x=document.createElement("tr"),C=(v,k="right")=>{x.appendChild(l("td",{textAlign:k,padding:`${y.xs} ${y.md}`,borderBottom:`1px solid ${L.menuBorder}`,color:K,whiteSpace:"nowrap"},v))};C(m.label,"left"),c===null&&C(String(m.totalDies)),C(String(m.passDies)),C(String(m.failDies)),C(m.passRatePercent!==null?`${m.passRatePercent.toFixed(1)}%`:"\u2014"),h.appendChild(x)}I.appendChild(h);const f=l("div",{overflowX:"auto"});if(f.appendChild(I),!d)return a.appendChild(f),a;b.remove();const{outer:w}=X(u,!0,void 0,{stateKey:"functionalTests",panel:d,render:m=>m.appendChild(f),control:()=>N});return w}export function buildLotFunctionalSection(e,t,i,n,o){const d=i?.length?{perWaferMetadata:i.map(p=>p.wafer??{}),populationLabel:`${i.length} wafer${i.length===1?"":"s"} pooled`}:void 0,s=ut(i);return s?buildFunctionalTestSection(e,t,s,n,d,o):buildFunctionalTestSection(e,t,void 0,n,d,o)}const ee={unusual:0,notable:1,info:2};function ye(e){return l("span",{display:"inline-block",width:"7px",height:"7px",borderRadius:_.pill,background:de(e),flexShrink:"0"})}function _e(e,t){let i=e.summary;return t&&(i.startsWith(`${t} has `)?i=i.slice(t.length+5):i.startsWith(`${t} `)&&(i=i.slice(t.length+1))),i=ne(i),i.length?i[0].toUpperCase()+i.slice(1):i}export function buildFindingsSection(e,t,i,n,o=!1){if(!e.length)return null;const d=e.some(h=>h.severity==="unusual"||h.severity==="notable"),s=d?e.filter(h=>h.severity!=="info").length.toString():void 0,{outer:p,content:c}=o?(()=>{const h=l("div");return{outer:h,content:h}})():X(`Findings (${e.length})`,d,s);function r(h){return h.reduce((f,w)=>ee[w.severity]<ee[f]?w.severity:f,"info")}function a(h){const f=new Map;for(const m of h){const x=`${m.comparison.family}\0${m.comparison.left}`,C=f.get(x)??[];C.push(m),f.set(x,C)}const w=[...f.entries()].map(([m,x])=>{const C=[...x].sort((v,k)=>ee[v.severity]-ee[k.severity]);return{key:m,findings:C,worst:r(C)}});return w.sort((m,x)=>ee[m.worst]-ee[x.worst]),w}function b(h,f){const m={ring:"Ring",quadrant:"Quadrant",sector:"Sector","reticle-position":"Reticle","test-site":"Test site",cluster:"Cluster","edge-arc":"Edge arc",wafer:"Wafer"}[h]??h;return f.toLowerCase().startsWith(m.toLowerCase())?f:`${m}: ${f}`}const u=e.filter(h=>h.comparison.family==="spatial-pattern"),S=new Set([...u.flatMap(h=>h.relatedIds??[]),...e.flatMap(h=>h.absorbedIds??[])]),N=e.filter(h=>h.comparison.family!=="spatial-pattern"&&!S.has(h.id)),I=a(N);function P(h,f=!1,w){const m=n===h.id,x=document.createElement("button");return x.type="button",x.dataset.wmapFinding=h.id,x.textContent=_e(h,w),oe(x,h.summary),x.setAttribute("aria-current",m?"true":"false"),Object.assign(x.style,{border:`1px solid ${L.menuBorder}`,borderLeft:`3px solid ${de(h.severity)}`,background:m?L.bgActive:L.menuBg,borderRadius:_.container,padding:f?"6px 10px":"8px 10px",textAlign:"left",fontSize:f?"10px":"11px",fontWeight:m?"600":"400",color:L.text,cursor:"pointer",width:"100%",marginBottom:y.xs}),q(x,"bare"),x.addEventListener("click",()=>i(h,x)),x}const R=ne(tt(e)??"");if(R){const h=l("div",{background:L.bgActive,borderRadius:_.container,padding:`${y.md} ${y.lg}`,marginBottom:y.md,display:"flex",gap:y.md,alignItems:"flex-start"}),f=l("span",{flex:"1",fontSize:E.body,lineHeight:Q.base,color:L.text},R);h.appendChild(f);const w=l("button",{flexShrink:"0",border:"none",background:"none",fontSize:E.body,color:L.icon,cursor:"pointer",padding:"0",lineHeight:Q.base,whiteSpace:"nowrap"},"Detail \u25B8");w.type="button",q(w,"bare"),w.addEventListener("click",()=>{const m=Fe({title:"Findings Summary",onClose:()=>{},anchor:w}),x=l("p",{fontSize:"16px",lineHeight:Q.base,color:L.text,padding:`${y.xxl} ${y.xxxl} ${y.xxl}`,margin:"0",borderBottom:`1px solid ${L.menuBorder}`,flexShrink:"0"},R);m.contentWrap.appendChild(x);const C=l("div",{overflowY:"auto",padding:`${y.xxl} ${y.xxxl}`,flex:"1"}),v=(k,T)=>{const A=l("div",{display:"flex",alignItems:"center",gap:"7px",fontSize:E.sub,fontWeight:"600",color:K,marginTop:y.lg,marginBottom:y.xs});return A.appendChild(ye(k)),A.appendChild(l("span",{},T)),A};for(const k of u){C.appendChild(v(k.severity,k.comparison.left)),C.appendChild(l("div",{fontSize:E.body,color:L.text,padding:"4px 0 4px 15px",marginBottom:y.xxs},ne(k.summary)));const T=e.filter(A=>k.relatedIds?.includes(A.id));for(const A of T)C.appendChild(l("div",{fontSize:E.body,color:Y,padding:"2px 0 2px 23px",marginBottom:y.xxs},ne(A.summary)))}for(const k of I){const[T,A]=k.key.split("\0");C.appendChild(v(k.worst,b(T,A)));for(const W of k.findings)C.appendChild(l("div",{fontSize:E.body,color:L.text,padding:"4px 0 4px 15px",marginBottom:y.xxs},_e(W,A)))}m.contentWrap.appendChild(C),Object.assign(m.contentWrap.style,{flexDirection:"column",overflow:"hidden"})}),h.appendChild(w),c.appendChild(h)}let H=!0;for(const h of u){H||c.appendChild(l("div",{height:"1px",background:L.separator,margin:"4px 0"})),H=!1;const f=e.filter(v=>h.relatedIds?.includes(v.id)),w=f.length>0,m=l("div",{position:"relative",marginBottom:w?"2px":"4px"}),x=n===h.id,C=document.createElement("button");if(C.type="button",C.dataset.wmapFinding=h.id,Object.assign(C.style,{border:`1px solid ${L.menuBorder}`,borderLeft:`3px solid ${de(h.severity)}`,background:x?L.bgActive:L.menuBg,borderRadius:_.container,padding:"8px 32px 8px 10px",textAlign:"left",fontSize:E.body,fontWeight:x?"600":"500",color:L.text,cursor:"pointer",width:"100%"}),C.textContent=ne(h.summary),oe(C,h.summary),C.setAttribute("aria-current",x?"true":"false"),q(C,"bare"),C.addEventListener("click",()=>i(h,C)),m.appendChild(C),w){const v=l("div",{display:"none",paddingLeft:"12px",marginBottom:y.xs});for(const A of f)v.appendChild(P(A,!0));m.appendChild(v);let k=!1;const T=l("button",{position:"absolute",top:"50%",right:"8px",transform:"translateY(-50%)",border:"none",background:"none",fontSize:E.body,color:L.icon,cursor:"pointer",padding:`${y.xxs} ${y.xs}`,lineHeight:Q.none},"\u25B8");q(T,"bare"),T.type="button",oe(T),T.setAttribute("aria-label","Show supporting findings"),T.setAttribute("aria-expanded","false"),T.addEventListener("click",A=>{A.stopPropagation(),k=!k,v.style.display=k?"block":"none",T.textContent=k?"\u25BE":"\u25B8";const W=k?"Hide supporting findings":"Show supporting findings";T.setAttribute("aria-label",W),T.setAttribute("aria-expanded",String(k))}),m.appendChild(T)}c.appendChild(m)}for(const h of I){H||c.appendChild(l("div",{height:"1px",background:L.separator,margin:"4px 0"})),H=!1;const[f,w]=h.key.split("\0"),m=l("div",{display:"flex",alignItems:"center",gap:y.sm,fontSize:E.body,fontWeight:"600",color:K,margin:"2px 0 4px"});m.appendChild(ye(h.worst)),m.appendChild(l("span",{},b(f,w))),c.appendChild(m);for(const x of h.findings)c.appendChild(P(x,!1,w))}return p}const St=[{value:"",label:"All kinds"},{value:"yield",label:"Yield"},{value:"hardBin",label:"Hard bin"},{value:"softBin",label:"Soft bin"},{value:"test",label:"Test value"},{value:"functionalTest",label:"Functional test"},{value:"spatialPattern",label:"Spatial pattern"}],vt=[{value:"",label:"All regions"},{value:"ring",label:"Ring"},{value:"quadrant",label:"Quadrant"},{value:"reticle-position",label:"Reticle position"},{value:"test-site",label:"Test site"},{value:"wafer",label:"Wafer"},{value:"sector",label:"Sector"},{value:"cluster",label:"Cluster"},{value:"edge-arc",label:"Edge arc"},{value:"spatial-pattern",label:"Spatial pattern"}],$t=["unusual","notable","info"],kt={unusual:"Unusual",notable:"Notable",info:"Info"};function Bt(e,t,i){const n=l("div",{display:"flex",flexWrap:"wrap",alignItems:"center",gap:y.lg,marginBottom:y.lg,paddingBottom:"10px",borderBottom:`1px solid ${L.separator}`}),o={unusual:0,notable:0,info:0};for(const r of e)o[r.severity]++;const d=$t.filter(r=>o[r]>0),s=new Set(t.severity===void 0?d:Array.isArray(t.severity)?t.severity:[t.severity]),p=l("div",{display:"flex",gap:y.xs,flexWrap:"wrap"});for(const r of d){const a=document.createElement("button");a.type="button";const b=()=>{const u=s.has(r);a.setAttribute("aria-pressed",u?"true":"false"),Object.assign(a.style,{display:"inline-flex",alignItems:"center",gap:"5px",border:`1px solid ${L.menuBorder}`,borderRadius:_.pill,background:u?L.bgActive:"none",opacity:u?"1":"0.5",color:L.text,fontSize:E.body,padding:`${y.xxs} ${y.md}`,cursor:"pointer"}),a.dataset.on=u?"true":"false"};a.appendChild(ye(r)),a.appendChild(l("span",{},`${kt[r]} ${o[r]}`)),oe(a,()=>s.has(r)?"Click to hide these findings":"Click to show these findings"),b(),q(a,"bare"),a.addEventListener("click",()=>{s.has(r)?s.delete(r):s.add(r),t.severity=s.size===d.length?void 0:[...s],i()}),p.appendChild(a)}n.appendChild(p);const c=t.kind!==void 0||t.family!==void 0;return(e.length>=Lt||c)&&(n.appendChild(Be("Kind:",St,t.kind??"",r=>{t.kind=r||void 0,i()},{maxWidth:"130px"})),n.appendChild(Be("Region:",vt,t.family??"",r=>{t.family=r||void 0,i()},{maxWidth:"150px"}))),n}const Lt=8;function Nt(e,t){const i=l("div",{display:"flex",flexDirection:"column",gap:y.xs,padding:y.md,marginBottom:y.md,background:L.bgHover,borderRadius:_.control},void 0,t);if(i.appendChild(l("div",{fontSize:E.body,color:L.value},e.message,t)),e.detail&&i.appendChild(l("div",{fontSize:E.meta,color:Y},e.detail,t)),e.actionLabel&&e.onAction){const n=l("button",le("outlined"),e.actionLabel,t);n.type="button",n.style.alignSelf="flex-start",n.style.marginTop=y.xs,q(n),n.addEventListener("click",e.onAction),i.appendChild(n)}return i}export function buildFindingsSectionWithFilter(e,t,i,n,o,d,s){if(!e.findings.length&&!s)return null;const p=e.findings.some(N=>N.severity==="unusual"||N.severity==="notable"),c=p?e.findings.filter(N=>N.severity!=="info").length.toString():void 0,r=d?.ownerDocument??document,{outer:a,content:b}=X(`Findings (${e.findings.length})`,p||!!s,c,{stateKey:"findings",panel:d});if(s&&b.appendChild(Nt(s,r)),!e.findings.length)return a;b.appendChild(Bt(e.findings,n,o));const u=nt(e,n);if(!u.length)return b.appendChild(l("div",{color:Y,fontSize:E.body,textAlign:"center",padding:`${y.xxl} ${y.md}`},"No findings match the current filter.")),a;const S=buildFindingsSection(u,e,t,i,!0);return S&&b.appendChild(S),a}export function buildLotTestSection(e,t,i,n,o,d,s,p="full"){const c=n?.length?{perWaferMetadata:n.map(a=>a.wafer??{}),populationLabel:`${n.length} wafer${n.length===1?"":"s"} pooled`}:void 0;let r;if(n?.length&&n.every(a=>a.stats.perTestStats!==void 0)){const a=new Map;for(const b of n)for(const u of b.stats.perTestStats??[]){const S=a.get(u.testNumber);S?(S.n+=u.count,S.sum+=u.mean*u.count,S.min=Math.min(S.min,u.min),S.max=Math.max(S.max,u.max)):a.set(u.testNumber,{n:u.count,sum:u.mean*u.count,min:u.min,max:u.max})}r={perTestStats:[...a.entries()].map(([b,u])=>({testNumber:b,count:u.n,min:u.min,max:u.max,mean:u.sum/u.n}))}}if(n?.length&&n.every(a=>a.stats.testSpecYield!==void 0)){const a=new Map;for(const b of n)for(const u of b.stats.testSpecYield??[]){const S=a.get(u.testNumber);S?(S.passDies+=u.passDies,S.totalDies+=u.totalDies):a.set(u.testNumber,{passDies:u.passDies,totalDies:u.totalDies})}r={...r,testSpecYield:[...a.entries()].map(([b,u])=>({testNumber:b,totalDies:u.totalDies,yieldPercent:u.totalDies>0?u.passDies/u.totalDies*100:null}))}}return buildTestSection(e,t,i,r,o,c,d,s,p)}export function createSummaryPanelEl(e,t,i=document){const n=e==="top"||e==="bottom",o=l("div",{background:gt,color:L.text,fontVariantNumeric:"tabular-nums",border:Re,borderRadius:_.container,padding:y.xl,overflowY:"auto",overflowX:n?"auto":"hidden",flexShrink:"0",boxSizing:"border-box",fontFamily:E.family,fontSize:E.sub,boxShadow:Le.panel},void 0,i);return e==="right"&&(o.style.marginRight=t),e==="left"&&(o.style.marginLeft=t),e==="bottom"&&(o.style.marginBottom=t),n?(o.style.height="180px",o.style.width="100%"):(o.style.width="300px",o.style.maxHeight="100%"),o}export function wrapWithSummaryPanel(e,t,i){const n=i==="top"||i==="bottom",o=l("div",{display:"flex",flexDirection:n?"column":"row",gap:y.md,width:"100%",height:"100%",flex:"1 1 0",minHeight:"0",boxSizing:"border-box",alignItems:n?"flex-start":"stretch"});return e.style.flex="1 1 0",e.style.minWidth="0",e.style.minHeight="0",i==="right"||i==="bottom"?(o.appendChild(e),o.appendChild(t)):(o.appendChild(t),o.appendChild(e)),o}function je(e){return l("div",{fontSize:E.heading,fontWeight:"600",color:K,marginBottom:y.lg},e)}function fe(e,t){const i=l("button",le("outlined"),e);return i.type="button",q(i),i.addEventListener("click",t),i}function qe(...e){const t=e.filter(n=>!!n);if(!t.length)return null;const i=l("div",{display:"flex",flexWrap:"wrap",gap:y.sm,marginBottom:y.lg});for(const n of t)i.appendChild(n);return i}function Ve(e,t,i,n,o,d,s,p,c,r,a){const b=e.ownerDocument,u=Fe({title:"Die list",onClose:()=>{},anchor:e,ownerDocument:b});u.contentWrap.style.padding="14px 16px";const S=ft(t,i,{...s,title:n,onSaveText:p,waferMetadata:o,metadataFields:d,extraColumn:c,getWafer:r,ringCount:a,ownerDocument:b});S&&u.contentWrap.appendChild(S)}export function renderWaferSummaryContent(e,t){const i=e.scrollTop;e.innerHTML="";const{wafer:n,dies:o,yieldSummary:d,dataCoverage:s,hbinDefs:p,sbinDefs:c,testDefs:r,statsSummary:a,passBins:b=[1],ringCount:u=4,binColors:S,plotMode:N,fallbackFormat:I,onFindingClick:P,activeFindingId:R=null,findingsFilter:H,onFindingsFilterChange:h,findingsNotice:f,onSaveText:w,metadataFields:m,dieListOptions:x,metadataShownElsewhere:C}=t;e.appendChild(je("Wafer Summary"));const v=t.warnings??$e({statsSummary:a});v.length&&e.appendChild(ge(v,e.ownerDocument));const k=d&&s?fe("Summary report",()=>{Ee(Je({wafer:n,dies:o,yieldSummary:d,dataCoverage:s,hbinDefs:p,sbinDefs:c,testDefs:r,statsSummary:a,passBins:b,ringCount:u}),{anchor:e})}):null,T=(x?.enabled??!0)&&o.length?fe("View die list",()=>{Ve(e,o,r,`Die list \u2014 ${o.length} dies`,n.metadata,m,x,w,void 0,()=>n,u)}):null,A=qe(k,T);A&&e.appendChild(A);const W=[],V=a?.stats.isLotStack?a.stats:void 0,G=V?.lotSize!==void 0?{lotSize:V.lotSize,aggrMethod:lt(V.aggregationMethod)}:void 0;C||W.push(buildMetadataInfoSection([{metadata:n.metadata??void 0}],G)),d&&s&&W.push(buildYieldSection(d,s,b)),a&&P&&H&&h&&W.push(buildFindingsSectionWithFilter(a,P,R,H,h,e,f)),W.push(buildBinBreakdownSection({dies:o,hbinDefs:p,sbinDefs:c,binColors:S,hardCounts:a?.stats.hardBinCounts,softCounts:a?.stats.softBinCounts,plotMode:N,passBins:b,panel:e})),W.push(buildRegionYieldPanelSection({diesByWafer:[o],allWafers:[n],ringCount:u,passBins:b,panel:e}));const U=n.metadata?{waferMetadata:n.metadata}:void 0;W.push(buildTestSection(o,r,I,a?.stats,w,U,[{dies:o}],e,"compact")),W.push(buildFunctionalTestSection(o,r,a?.stats.functionalYield,w,U,e));let g=!0;for(const F of W)F&&(g||e.appendChild(Ie()),g=!1,e.appendChild(F));e.appendChild(l("div",{height:"12px",flexShrink:"0"})),e.scrollTop=i}export function renderLotSummaryContent(e,t){const i=e.scrollTop;e.innerHTML="";const{lotSummary:n,items:o,hbinDefs:d,sbinDefs:s,testDefs:p,passBins:c=[1],ringCount:r=4,binColors:a,plotMode:b,fallbackFormat:u,onFindingClick:S,activeFindingId:N=null,onWaferClick:I,findingsFilter:P,onFindingsFilterChange:R,findingsNotice:H,onSaveText:h,dieListOptions:f,findingsFor:w}=t;e.appendChild(je(`Summary \u2014 ${rt(ve(n.perWafer.map(B=>B.summary.wafer)))}`));const m=t.warnings??$e({lotStatsSummary:n});m.length&&e.appendChild(ge(m,e.ownerDocument));const x=fe("Summary report",()=>{Ee(et({items:o.map((B,M)=>({label:me(B,M),wafer:B?.wafer,dies:B?.dies,passBins:[...he(B,c)],statsSummary:B?.statsSummary})),hbinDefs:d,sbinDefs:s,testDefs:p,passBins:c,ringCount:r}),{anchor:e})}),C=[],v=[],k=[],T=[],A=[],W=new WeakMap,V=new WeakMap;for(let B=0;B<o.length;B++){const M=o[B];if(!M){v.push([]);continue}M.wafer&&(C.push(M.wafer),T.push(M.dies??[]),A.push(he(M,c)));const z=M.dies??[],$=me(M,B);for(const D of z)W.set(D,$),M.wafer&&V.set(D,M.wafer);v.push(z),k.push(...z)}const G=f?.enabled??!0?fe("View die list",()=>{k.length&&Ve(e,k,p,`Die list \u2014 ${k.length} dies across ${o.length} wafer${o.length===1?"":"s"}`,we(o.filter(B=>!!B).map(B=>({metadata:B.wafer?.metadata}))),o.find(B=>B?.metadataFields?.length)?.metadataFields,f,h,{label:"Wafer",get:B=>W.get(B)},B=>V.get(B),r)}):null,U=qe(x,G);U&&e.appendChild(U);const g=o.map(B=>B?.statsSummary).filter(B=>!!B),F=[buildLotOverviewSection(n,g)];S&&P&&R&&F.push(buildFindingsSectionWithFilter(n,S,N,P,R,e,H)),F.push(buildPerWaferYieldSection(n,o,I,e,w),buildBinBreakdownSection({dies:k,hbinDefs:d,sbinDefs:s,plotMode:b,passBins:c,panel:e,binColors:a??st(o.flatMap(B=>B?[{dies:B.dies??[],passBins:he(B,c)}]:[]),{hbinDefs:d,sbinDefs:s}).colors}),buildRegionYieldPanelSection({diesByWafer:T,allWafers:C,ringCount:r,passBins:B=>A[B],panel:e}),p?.length?buildLotTestSection(k,p,u,g,h,v.map(B=>({dies:B})),e,"compact"):null,p?.length?buildLotFunctionalSection(k,p,g,h,e):null);let O=!0;for(const B of F)B&&(O||e.appendChild(Ie()),O=!1,e.appendChild(B));e.appendChild(l("div",{height:"12px",flexShrink:"0"})),e.scrollTop=i}
|
|
1
|
+
import{waferDisplayLabel as me}from"../core/waferLabel.js";import{itemPassBins as he,passBinsLabel as Ke}from"../core/passBins.js";import{isParametricTest as Ge}from"../renderer/buildWaferMap.js";import{buildRingRegions as Ue,buildQuadrantRegions as Qe,buildRegionYieldData as Xe}from"../stats/regions.js";import{computeFunctionalYield as Ze}from"../stats/analyzeWaferMap.js";import{renderWaferReportHtml as Je,renderLotReportHtml as et}from"../stats/renderSummaryReport.js";import{buildFindingsNarrative as tt}from"../stats/findingsNarrative.js";import{filterFindings as nt}from"../stats/filterFindings.js";import{buildFacetTable as ot,prettyKey as Ce}from"../stats/facets.js";import{commonMetadata as we}from"../stats/facets.js";import{resolveMetadataColumns as it}from"../stats/metadataColumns.js";import{resolveBinColors as Se,resolveBinColorsByWafer as st}from"../renderer/binColors.js";import{NO_DATA_FILL as at}from"../renderer/colorMap.js";import{describeWaferPopulation as ve,populationLabel as rt}from"../stats/population.js";import{buildWarningsBanner as ge,collectWarnings as $e}from"./warnings.js";export{ge as buildWarningsBanner};import{fmt as ke,fmtAggregationMethod as lt,plainBinTerms as ne}from"../renderer/fmt.js";import{getUniqueTestNumbers as dt}from"../renderer/buildView.js";import{quantile as oe}from"../stats/math.js";import{buildCapabilityData as ct}from"../stats/capability.js";import{sortBinsForDisplay as pt}from"../stats/binPareto.js";import{poolFunctionalYield as ut}from"../stats/testPassRate.js";import{makeLabeledSelect as Be,makeSegmented as be}from"./charts/chartShell.js";import{SHADOW as Le,MOTION as Ne,LEADING as Q,TRACKING as re,wireControlHover as q,controlStyle as le,SPACE as y,RADIUS as _,FONT as E,CLR as B,sevColor as de,openModal as Fe,openReportModal as Ee,saveTextFile as De,wireTooltip as ie}from"./toolbar.js";import{buildDieListSection as ft}from"./dieList.js";export{csvField}from"../core/utils.js";import{medianOfSorted as mt,csvField as ce}from"../core/utils.js";import{metadataDisplayValue as ht}from"../core/metadata.js";const gt=B.panelBg,Re=`1px solid ${B.menuBorder}`,bt="12px",Y=B.label,K=B.value,Te="10px";function l(e,t,o,n=document){const i=n.createElement(e);return t&&Object.assign(i.style,t),o!==void 0&&(i.textContent=o),i}function J(e){return l("div",{fontSize:Te,fontWeight:"700",letterSpacing:re,textTransform:"uppercase",color:Y,marginBottom:y.sm},e)}const Me=new WeakMap,Ie=["regionYield","testValues","functionalTests"];function pe(e){if(!e)return{collapsed:new Set(Ie),regionMode:"ring",waferSort:"slot"};let t=Me.get(e);return t||(t={collapsed:new Set(Ie),regionMode:"ring",waferSort:"slot"},Me.set(e,t)),t}function X(e,t=!0,o,n){const i=l("div"),d=pe(n?.panel);n?.stateKey&&n.panel&&(t=!d.collapsed.has(n.stateKey));const s=document.createElement("button");s.type="button",Object.assign(s.style,{display:"flex",alignItems:"center",gap:y.xs,width:"100%",background:"none",border:"none",cursor:"pointer",padding:"0 0 6px",textAlign:"left"});const p=l("span",{fontSize:E.meta,color:Y,transition:`transform ${Ne.base}`,transform:t?"rotate(90deg)":"rotate(0deg)",display:"inline-block",lineHeight:Q.none,marginRight:"1px"},"\u25B6"),c=l("span",{fontSize:Te,fontWeight:"700",letterSpacing:re,textTransform:"uppercase",color:Y,flex:"1"},e);if(q(s,"bare"),s.setAttribute("aria-expanded",t?"true":"false"),s.appendChild(p),s.appendChild(c),o){const b=l("span",{fontSize:E.meta,fontWeight:"700",background:B.warnBg,color:B.warnText,borderRadius:_.pill,padding:"1px 5px"},o);s.appendChild(b)}const r=l("div");r.style.display=t?"block":"none";let a=t;if(s.addEventListener("click",()=>{a=!a,r.style.display=a?"block":"none",p.style.transform=a?"rotate(90deg)":"rotate(0deg)",s.setAttribute("aria-expanded",a?"true":"false"),n?.stateKey&&n.panel&&(a?d.collapsed.delete(n.stateKey):d.collapsed.add(n.stateKey))}),n?.control){const b=l("div",{display:"flex",alignItems:"center",gap:y.sm});s.style.width="auto",s.style.flex="1",b.appendChild(s);const u=()=>{r.innerHTML="",n.render?.(r)},S=n.control(u);S&&(S.style.marginBottom="6px",S.addEventListener("click",N=>N.stopPropagation()),b.appendChild(S)),i.appendChild(b)}else i.appendChild(s);return i.appendChild(r),n?.render?.(r),{outer:i,content:r}}function Ae(){return l("div",{height:"1px",background:B.separator,margin:`${bt} 0`,flexShrink:"0"})}function xe(e,t,o=B.barFill,n,i){const d=l("div",{marginBottom:"5px"}),s=l("div",{display:"flex",justifyContent:"space-between",fontSize:E.body,color:K,marginBottom:y.xxs}),p=l("span",{color:Y},e),c=l("span",{fontWeight:"600"},`${t.toFixed(1)}%`);s.appendChild(p),s.appendChild(c);const r=n!==void 0?n:Math.min(100,Math.max(0,t)),a=o,b=l("div",{position:"relative",height:"9px",background:B.bgActive,borderRadius:_.control,overflow:"hidden"}),u=l("div",{height:"100%",width:`${r}%`,background:a,borderRadius:_.control,transition:`width ${Ne.base}`});if(b.appendChild(u),i!==void 0){const S=l("div",{position:"absolute",top:"0",bottom:"0",left:`${i}%`,width:"2px",marginLeft:"-1px",background:B.value,opacity:"0.8"});b.appendChild(S)}return d.appendChild(s),d.appendChild(b),d}function We(){const e=l("div",{display:"flex",gap:y.sm,marginBottom:y.md});return e.finish=()=>{const t=e.lastElementChild;t&&Object.assign(t.style,{borderRight:"none",paddingRight:"0"})},e}function se(e,t,o){const n=l("div",{padding:`${y.xxs} ${y.md} ${y.xxs} 0`,borderRight:Re,textAlign:"center",flex:"1"}),i=l("div",{fontSize:E.heading,fontWeight:"700",color:K,lineHeight:Q.tight},e),d=l("div",{fontSize:E.body,color:Y,marginTop:y.xxs},t);return n.appendChild(i),n.appendChild(d),o&&n.appendChild(l("div",{fontSize:E.body,color:Y,opacity:"0.85"},o)),n}function Pe(e,t){const o=l("div",{display:"flex",justifyContent:"space-between",fontSize:E.body,gap:y.md,marginBottom:"3px"}),n=l("span",{color:Y,flexShrink:"0"},e),i=l("span",{color:K,textAlign:"right",fontWeight:"500",wordBreak:"break-all"},t);return o.appendChild(n),o.appendChild(i),o}function xt(e,t){const o=l("div",{display:"flex",fontSize:E.body,gap:y.sm,marginBottom:"3px"}),n=l("span",{color:Y,flexShrink:"0"},`${e}:`),i=l("span",{color:K,fontWeight:"500",wordBreak:"break-all"},t);return o.appendChild(n),o.appendChild(i),o}export function metadataEntries(e){const t=[];for(const[o,n]of Object.entries(e)){const i=ht(n);i!==void 0&&t.push([o,i])}return t}const yt=["lot","product","testprogram","split"],ue=e=>{const t=yt.indexOf(e.toLowerCase().replace(/[^a-z]/g,""));return t===-1?Number.MAX_SAFE_INTEGER:t};export function buildFacetSummaryChips(e,t=3){if(!e.length)return null;const o=l("div",{display:"flex",flexWrap:"wrap",alignItems:"baseline",gap:`${y.xs} ${y.lg}`}),n=[...e].sort((p,c)=>ue(p.key)-ue(c.key)),i=n.filter(p=>ue(p.key)!==Number.MAX_SAFE_INTEGER),d=n.filter(p=>ue(p.key)===Number.MAX_SAFE_INTEGER),s=p=>{const c=l("span",{whiteSpace:"nowrap"}),r=l("span",{color:Y},`${Ce(p.key)}: `);c.appendChild(r);const a=p.values.slice(0,t),b=p.values.length-a.length;let u=a.map(S=>S.value).join(", ");return b>0&&(u+=` +${b} more`),c.appendChild(document.createTextNode(u)),c};for(const p of i)o.appendChild(s(p));if(d.length){const p=l("span",{display:"none",flexWrap:"wrap",alignItems:"baseline",gap:`${y.xs} ${y.lg}`});for(const a of d)p.appendChild(s(a));const c=l("button",{background:"none",border:"none",padding:"0",cursor:"pointer",color:B.iconActive,fontSize:E.body,whiteSpace:"nowrap"});c.type="button",q(c,"bare");const r=a=>{p.style.display=a?"contents":"none",c.textContent=a?"less":`+${d.length} more`,c.setAttribute("aria-expanded",String(a))};r(!1),c.addEventListener("click",()=>r(c.getAttribute("aria-expanded")!=="true")),o.appendChild(p),o.appendChild(c)}return o}export function buildMetadataStripRow(e,t,o){const n=ot(e,o),i=buildFacetSummaryChips(n);if(!i&&!t)return null;const d=l("div",{display:"flex",flexWrap:"wrap",alignItems:"baseline",gap:"4px 14px"});if(t){const s=l("span",{fontWeight:"500",whiteSpace:"nowrap"},t.aggrMethod?`${t.lotSize} wafers stacked \xB7 ${t.aggrMethod}`:`${t.lotSize} wafers stacked`);d.appendChild(s)}return i&&d.appendChild(i),d}const Ct={display:"flex",flexDirection:"column",gap:y.sm,background:B.menuBg,border:`1px solid ${B.menuBorder}`,borderRadius:_.container,padding:`${y.sm} ${y.lg}`,boxShadow:Le.panel,fontSize:E.body,lineHeight:Q.none,boxSizing:"border-box",width:"100%",minWidth:"0"};export function buildMetadataStripBox(e,t,o){const n=buildMetadataStripRow(e,t,o);if(!n)return null;const i=l("div",Ct);return i.appendChild(n),i}export function buildCompactMetadataRows(e){const t=metadataEntries(e);if(!t.length)return null;const o=l("div");for(const[n,i]of t)o.appendChild(xt(Ce(n),i));return o}export function buildMetadataInfoSection(e,t){const o=buildMetadataStripRow(e,t,{facetableOnly:e.length>1});if(!o)return null;const n=l("div");return n.appendChild(J("Wafer Info")),n.appendChild(o),n}export function buildYieldSection(e,t,o=[1]){const n=l("div");n.appendChild(J("Summary"));const i=We();if(i.appendChild(se(String(e.totalDies),"Total dies")),e.partialDies>0&&i.appendChild(se(String(e.partialDies),"Partial")),e.yieldPercent!==null){const d=Ke([o]);i.appendChild(se(`${e.yieldPercent.toFixed(1)}%`,"Yield",`pass: ${d}`))}return i.finish(),n.appendChild(i),e.edgeExcludedDies>0&&n.appendChild(Pe("Edge excluded (outer zone)",String(e.edgeExcludedDies))),n}export function buildBinSection(e,t,o,n,i,d){const s=new Map;if(i)for(const[r,a]of Object.entries(i))s.set(Number(r),a);else for(const r of e){if(r.partial||r.edgeExcluded)continue;const a=o==="hard"?r.hbin:r.sbin;a!=null&&s.set(a,(s.get(a)??0)+1)}if(!s.size)return null;const p=n??Se(e,{passBins:d,...o==="hard"?{hbinDefs:t}:{sbinDefs:t}}),c=l("div");c.appendChild(J(ze(o,[...s.values()].reduce((r,a)=>r+a,0))));for(const r of He(s,t,p[o],p.pass[o]))c.appendChild(r);return c}function ze(e,t){return`${e==="hard"?"Hard":"Soft"} Bin Breakdown \u2014 % of dies (N=${t})`}function He(e,t,o,n){const i=[...e.values()].reduce((p,c)=>p+c,0),d=t?new Map(t.map(p=>[p.bin,p])):null;return pt(e.entries(),n).map(([p,c])=>{const r=d?.get(p),a=r?.name?`Bin ${p} \xB7 ${r.name}`:`Bin ${p}`,b=c/i*100,u=o.get(p)??at;return xe(`${a} (${c})`,b,u)})}export function buildBinBreakdownSection(e){const{dies:t,hbinDefs:o,sbinDefs:n,hardCounts:i,softCounts:d,plotMode:s,passBins:p=[1],panel:c}=e,r=e.binColors??Se(t,{passBins:p,hbinDefs:o,sbinDefs:n}),a=m=>{const x=m==="hard"?i:d,C=new Map;if(x){for(const[v,k]of Object.entries(x))C.set(Number(v),k);return C}for(const v of t){if(v.partial||v.edgeExcluded)continue;const k=m==="hard"?v.hbin:v.sbin;k!=null&&C.set(k,(C.get(k)??0)+1)}return C},b=a("hard"),u=a("soft"),S=b.size>0,N=u.size>0;if(!S&&!N)return null;const A=pe(c),P=s==="softBin"||s==="stackedSoftBins"?"soft":s==="hardBin"||s==="stackedBins"?"hard":void 0;let R=A.binMode??P??(S?"hard":"soft");R==="hard"&&!S&&(R="soft"),R==="soft"&&!N&&(R="hard");const H=R==="hard"?b:u,h=R==="hard"?o:n,f=[...H.values()].reduce((m,x)=>m+x,0),{outer:w}=X(ze(R,f),!0,void 0,{stateKey:"bins",panel:c,render:m=>{const x=R==="hard"?r.hard:r.soft;for(const C of He(H,h,x,r.pass[R]))m.appendChild(C)},control:S&&N&&c?()=>be([["hard","Hard"],["soft","Soft"]],R,m=>{A.binMode=m;const x=buildBinBreakdownSection(e);x&&w.replaceWith(x)},c.ownerDocument,!0):void 0});return w}export function buildLotBinSection(e,t,o,n){return buildBinSection(e,t,o,n)}export function buildRegionYieldPanelSection(e){const{diesByWafer:t,allWafers:o,ringCount:n,passBins:i,panel:d}=e,s=pe(d),p=a=>Xe(t,o,n,i,a==="ring"?Ue:Qe);if(!p("ring").length&&!p("quadrant").length)return null;const c=s.regionMode,{outer:r}=X(c==="ring"?"Ring Yield":"Quadrant Yield",!0,void 0,{stateKey:"regionYield",panel:d,render:a=>{const b=p(c);if(!b.length){a.appendChild(l("div",{fontSize:E.body,color:Y},"No positioned dies for this breakdown."));return}for(const{label:u,n:S,yieldPercent:N}of b)a.appendChild(xe(`${u} (N=${S})`,N))},control:d?()=>be([["ring","Ring"],["quadrant","Quadrant"]],c,a=>{s.regionMode=a;const b=buildRegionYieldPanelSection(e);b&&r.replaceWith(b)},d.ownerDocument,!0):void 0});return r}export function buildLotOverviewSection(e,t=[]){const o=l("div"),n=ve(e.perWafer.map(s=>s.summary.wafer));o.appendChild(J(n.lotId!==void 0?"Lot Summary":"Summary"));const i=We();i.appendChild(se(String(e.stats.waferCount),"Wafers"));const d=e.perWafer.map(s=>s.summary.stats.yieldPercent).filter(s=>s!==null);if(d.length){const s=d.reduce((p,c)=>p+c,0)/d.length;i.appendChild(se(`${s.toFixed(1)}%`,"Mean per-wafer yield"))}if(i.finish(),o.appendChild(i),t.length){const s=t.reduce((c,r)=>c+r.stats.analyzedDies,0),p=t.reduce((c,r)=>c+r.stats.excludedDies,0);(s||p)&&o.appendChild(Pe("Dies analysed",p?`${s.toLocaleString()} (${p.toLocaleString()} excluded)`:s.toLocaleString()))}return o}export function buildPerWaferYieldSection(e,t,o,n,i){const d=e.perWafer.map(f=>({waferIndex:f.waferIndex,label:me(t[f.waferIndex],f.waferIndex).replace(/\s*·\s*\d+(\.\d+)?%$/,""),yieldPct:f.summary.stats.yieldPercent})).filter(f=>f.yieldPct!==null);if(!d.length)return null;const s=Math.min(...d.map(f=>f.yieldPct)),p=Math.max(...d.map(f=>f.yieldPct)),c=s===p?"":` (${s.toFixed(1)}\u2013${p.toFixed(1)}%)`,r=[...d.map(f=>f.yieldPct)].sort((f,w)=>f-w),a=mt(r),b=oe(r,.25),u=oe(r,.75),S=d.length>=5?b-1.5*(u-b):-1/0,N=pe(n),A=f=>{const w=N.waferSort==="yield"?[...d].sort((m,x)=>m.yieldPct-x.yieldPct):d;for(const{waferIndex:m,label:x,yieldPct:C}of w){const k=C<S?`${x} \xB7 low outlier`:x,T=xe(k,C,void 0,void 0,a),M=i?.(m);M?.total&&H(T,M),h(T,m,x,C,M),f.appendChild(T)}},P=` \xB7 median ${a.toFixed(1)}%`,{outer:R}=X("Wafer Yield"+c+P,!0,void 0,{stateKey:"waferYield",panel:n,render:A,control:n?f=>be([["slot","Slot"],["yield","Yield"]],N.waferSort,w=>{N.waferSort=w,f()},n.ownerDocument,!0):void 0});return R;function H(f,w){const m=w.unusual?"unusual":w.notable?"notable":"info",x=l("span",{marginLeft:y.sm,flexShrink:"0",background:de(m),color:"#fff",borderRadius:_.container,padding:"0 5px",fontSize:E.body,fontWeight:"600"},`${w.total}`);x.setAttribute("aria-hidden","true"),ie(x,`${w.total} finding${w.total===1?"":"s"}`+(w.unusual?`, ${w.unusual} unusual`:"")+(w.notable?`, ${w.notable} notable`:"")),f.firstElementChild?.firstElementChild?.appendChild(x)}function h(f,w,m,x,C){o&&(f.style.cursor="pointer",f.style.borderRadius="4px",f.style.padding="2px 3px",f.style.marginLeft="-3px",f.style.marginRight="-3px",f.setAttribute("role","button"),f.setAttribute("aria-label",`${m}, ${x.toFixed(1)}% yield`+(C?.total?`, ${C.total} finding${C.total===1?"":"s"}${C.unusual?`, ${C.unusual} unusual`:""}`:"")+" \u2014 open wafer"),f.tabIndex=0,f.addEventListener("mouseenter",()=>{f.style.background=B.bgHover}),f.addEventListener("mouseleave",()=>{f.style.background=""}),f.addEventListener("focus",()=>{f.style.background=B.bgHover}),f.addEventListener("blur",()=>{f.style.background=""}),f.addEventListener("click",()=>o(w)),f.addEventListener("keydown",v=>{(v.key==="Enter"||v.key===" ")&&(v.preventDefault(),o(w))}))}}function wt(e){const t=[...e].sort((i,d)=>i-d),o=e.reduce((i,d)=>i+d,0)/e.length,n=e.reduce((i,d)=>i+(d-o)**2,0)/e.length;return{min:t[0],max:t[t.length-1],mean:o,count:e.length,stddev:Math.sqrt(n),median:oe(t,.5),q1:oe(t,.25),q3:oe(t,.75)}}function Ye(e,t){if(!e)return[];const o=e.waferMetadata??(e.perWaferMetadata?we(e.perWaferMetadata.map(n=>({metadata:n}))):void 0);return!o||!Object.keys(o).length?[]:it({waferMetadata:o,waferKeys:"identity",waferPlacement:"csv",reservedLabels:t}).columns}function Oe(e){return e?.populationLabel?[{key:"population",label:"Population",scope:"wafer",constant:e.populationLabel,get:()=>e.populationLabel,csvOnly:!0}]:[]}export function buildTestSection(e,t,o,n,i,d,s,p,c="full"){const r=e.filter(g=>!g.partial&&!g.edgeExcluded),a=new Map((n?.perTestStats??[]).map(g=>[g.testNumber,g])),b=new Map((n?.testSpecYield??[]).map(g=>[g.testNumber,g]));let u;if(t?.length?u=t.filter(Ge).map(g=>({testNumber:g.testNumber,name:g.name,unit:g.unit,limitLow:g.limitLow,limitHigh:g.limitHigh})):u=dt(r).map(F=>({testNumber:F,name:`Test ${F}`})),!u.length)return null;const S=u.filter(g=>r.some(F=>{const O=F.testValues?.[g.testNumber];return O!==void 0&&isFinite(O)}));if(!S.length)return null;const N=S.some(g=>g.limitLow!==void 0||g.limitHigh!==void 0),A=[];for(const g of S){const F=a.get(g.testNumber),O=F&&F.stddev!==void 0&&F.median!==void 0&&F.q1!==void 0&&F.q3!==void 0;let L;if(O){const $=F;L={testNumber:g.testNumber,min:$.min,max:$.max,mean:$.mean,count:$.count,stddev:$.stddev,median:$.median,q1:$.q1,q3:$.q3}}else{const $=r.map(D=>D.testValues?.[g.testNumber]).filter(D=>D!==void 0&&isFinite(D));if(!$.length)continue;L={testNumber:g.testNumber,...wt($)}}let I=null,z=0;if(g.limitLow!==void 0||g.limitHigh!==void 0){const $=b.get(g.testNumber);if($)({yieldPercent:I,totalDies:z}=$);else{const D=r.map(j=>j.testValues?.[g.testNumber]).filter(j=>j!==void 0&&isFinite(j)),Z=D.filter(j=>g.limitLow!==void 0&&j<g.limitLow||g.limitHigh!==void 0&&j>g.limitHigh).length;z=D.length,I=D.length>0?(D.length-Z)/D.length*100:null}}A.push({entry:g,stats:L,specYieldPct:I,specN:z})}if(!A.length)return null;const P=new Map;if(s?.length&&t?.length)for(const g of ct(s,t))g.hasSpec&&P.set(g.testNumber,g.ppk);const R=P.size>0,h=new Set(A.map(g=>g.stats.count)).size===1?A[0].stats.count:null,f=l("div"),w=l("div",{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:y.sm}),m=h!==null?` \xB7 N=${h.toLocaleString()}`:"",x=d?.populationLabel?`Test Values (${A.length}) \u2014 ${d.populationLabel}${m}`:`Test Values (${A.length})${m}`,C=J(x);C.style.marginBottom="0",w.appendChild(C);const v=document.createElement("button");v.type="button",v.textContent="Test values CSV",Object.assign(v.style,{...le("outlined")}),q(v),v.addEventListener("click",()=>{const g=["Test","Unit","N","Min","Q1","Median","Mean","Q3","Max","StdDev"];R&&g.push("Ppk");const F=A.some($=>$.specYieldPct!==null&&$.specN!==$.stats.count);N&&(g.push("LSL","USL","Spec Yield %"),F&&g.push("Spec Yield N"));const O=[...Ye(d,g),...Oe(d)],I=[[...O.map($=>$.label),...g].map(ce).join(",")],z=$=>ke($,void 0,"engineering");for(const{entry:$,stats:D,specYieldPct:Z,specN:j}of A){const ae=[...O.map(te=>te.constant??""),$.name,$.unit??"",String(D.count),z(D.min),z(D.q1),z(D.median),z(D.mean),z(D.q3),z(D.max),z(D.stddev)];if(R){const te=P.get($.testNumber);ae.push(te==null?"":te.toFixed(3))}N&&(ae.push($.limitLow!==void 0?z($.limitLow):"",$.limitHigh!==void 0?z($.limitHigh):"",Z!==null?Z.toFixed(1):""),F&&ae.push($.limitLow!==void 0||$.limitHigh!==void 0?String(j):"")),I.push(ae.map(ce).join(","))}De(I.join(`
|
|
2
|
+
`),"test-values.csv","text/csv",i)}),w.appendChild(v),f.appendChild(w);const k=l("table",{width:"100%",borderCollapse:"collapse",fontSize:E.body}),T=document.createElement("thead"),M=document.createElement("tr"),W=["Test"];h===null&&W.push("N"),c==="full"&&W.push("Min","Q1","Median"),W.push("Mean"),c==="full"&&W.push("Q3","Max","StdDev"),R&&W.push("Ppk"),c==="full"&&N&&W.push("LSL","USL"),N&&W.push("Spec yield");for(const g of W){const F=l("th",{textAlign:g==="Test"?"left":"right",fontWeight:"600",fontSize:E.meta,letterSpacing:re,textTransform:"uppercase",color:Y,padding:"3px 8px 5px",borderBottom:`1px solid ${B.menuBorder}`,whiteSpace:"nowrap"},g);M.appendChild(F)}T.appendChild(M),k.appendChild(T);const V=document.createElement("tbody");for(const{entry:g,stats:F,specYieldPct:O,specN:L}of A){const I=D=>ke(D,g.unit,o),z=document.createElement("tr"),$=(D,Z="right")=>{const j=l("td",{textAlign:Z,padding:`${y.xs} ${y.md}`,borderBottom:`1px solid ${B.menuBorder}`,color:B.text,whiteSpace:"nowrap"},D);z.appendChild(j)};if($(g.name,"left"),h===null&&$(`${F.count}`),c==="full"&&($(I(F.min)),$(I(F.q1)),$(I(F.median))),$(I(F.mean)),c==="full"&&($(I(F.q3)),$(I(F.max)),$(I(F.stddev))),R){const D=P.get(g.testNumber);$(D==null?"\u2014":D.toFixed(2))}c==="full"&&N&&($(g.limitLow!==void 0?I(g.limitLow):"\u2014"),$(g.limitHigh!==void 0?I(g.limitHigh):"\u2014")),N&&$(O!==null?h!==null&&L===h?`${O.toFixed(1)}%`:`${O.toFixed(1)}% (N=${L})`:"\u2014"),V.appendChild(z)}k.appendChild(V);const G=l("div",{overflowX:"auto"});if(G.appendChild(k),!p)return f.appendChild(G),f;w.remove();const{outer:U}=X(x,!0,void 0,{stateKey:"testValues",panel:p,render:g=>g.appendChild(G),control:()=>v});return U}export function buildFunctionalTestSection(e,t,o,n,i,d){const s=o??Ze(e,t);if(!s?.length)return null;const c=new Set(s.map(m=>m.totalDies)).size===1?s[0].totalDies:null,r=c!==null?` \xB7 N=${c.toLocaleString()}`:"",a=l("div"),b=l("div",{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:y.sm}),u=i?.populationLabel?`Functional Tests (${s.length}) \u2014 ${i.populationLabel}${r}`:`Functional Tests (${s.length})${r}`,S=J(u);S.style.marginBottom="0",b.appendChild(S);const N=document.createElement("button");N.type="button",N.textContent="Functional CSV",Object.assign(N.style,{...le("outlined")}),q(N),N.addEventListener("click",()=>{const m=["Test","N","Pass","Fail","Pass Rate %"],x=[...Ye(i,m),...Oe(i)],C=[[...x.map(v=>v.label),...m].map(ce).join(",")];for(const v of s)C.push([...x.map(k=>k.constant??""),v.label,String(v.totalDies),String(v.passDies),String(v.failDies),v.passRatePercent!==null?v.passRatePercent.toFixed(1):""].map(ce).join(","));De(C.join(`
|
|
3
|
+
`),"functional-tests.csv","text/csv",n)}),b.appendChild(N),a.appendChild(b);const A=l("table",{width:"100%",borderCollapse:"collapse",fontSize:E.body}),P=document.createElement("thead"),R=document.createElement("tr"),H=c===null?["Test","N","Pass","Fail","Pass rate"]:["Test","Pass","Fail","Pass rate"];for(const m of H)R.appendChild(l("th",{textAlign:m==="Test"?"left":"right",fontWeight:"700",fontSize:E.body,letterSpacing:re,textTransform:"uppercase",color:Y,padding:"3px 8px 5px",borderBottom:`1px solid ${B.menuBorder}`,whiteSpace:"nowrap"},m));P.appendChild(R),A.appendChild(P);const h=document.createElement("tbody");for(const m of s){const x=document.createElement("tr"),C=(v,k="right")=>{x.appendChild(l("td",{textAlign:k,padding:`${y.xs} ${y.md}`,borderBottom:`1px solid ${B.menuBorder}`,color:K,whiteSpace:"nowrap"},v))};C(m.label,"left"),c===null&&C(String(m.totalDies)),C(String(m.passDies)),C(String(m.failDies)),C(m.passRatePercent!==null?`${m.passRatePercent.toFixed(1)}%`:"\u2014"),h.appendChild(x)}A.appendChild(h);const f=l("div",{overflowX:"auto"});if(f.appendChild(A),!d)return a.appendChild(f),a;b.remove();const{outer:w}=X(u,!0,void 0,{stateKey:"functionalTests",panel:d,render:m=>m.appendChild(f),control:()=>N});return w}export function buildLotFunctionalSection(e,t,o,n,i){const d=o?.length?{perWaferMetadata:o.map(p=>p.wafer??{}),populationLabel:`${o.length} wafer${o.length===1?"":"s"} pooled`}:void 0,s=ut(o);return s?buildFunctionalTestSection(e,t,s,n,d,i):buildFunctionalTestSection(e,t,void 0,n,d,i)}const ee={unusual:0,notable:1,info:2};function ye(e){return l("span",{display:"inline-block",width:"7px",height:"7px",borderRadius:_.pill,background:de(e),flexShrink:"0"})}function _e(e,t){let o=e.summary;return t&&(o.startsWith(`${t} has `)?o=o.slice(t.length+5):o.startsWith(`${t} `)&&(o=o.slice(t.length+1))),o=ne(o),o.length?o[0].toUpperCase()+o.slice(1):o}export function buildFindingsSection(e,t,o,n,i=!1){if(!e.length)return null;const d=e.some(h=>h.severity==="unusual"||h.severity==="notable"),s=d?e.filter(h=>h.severity!=="info").length.toString():void 0,{outer:p,content:c}=i?(()=>{const h=l("div");return{outer:h,content:h}})():X(`Findings (${e.length})`,d,s);function r(h){return h.reduce((f,w)=>ee[w.severity]<ee[f]?w.severity:f,"info")}function a(h){const f=new Map;for(const m of h){const x=`${m.comparison.family}\0${m.comparison.left}`,C=f.get(x)??[];C.push(m),f.set(x,C)}const w=[...f.entries()].map(([m,x])=>{const C=[...x].sort((v,k)=>ee[v.severity]-ee[k.severity]);return{key:m,findings:C,worst:r(C)}});return w.sort((m,x)=>ee[m.worst]-ee[x.worst]),w}function b(h,f){const m={ring:"Ring",quadrant:"Quadrant",sector:"Sector","reticle-position":"Reticle","test-site":"Test site",cluster:"Cluster","edge-arc":"Edge arc",wafer:"Wafer"}[h]??h;return f.toLowerCase().startsWith(m.toLowerCase())?f:`${m}: ${f}`}const u=e.filter(h=>h.comparison.family==="spatial-pattern"),S=new Set([...u.flatMap(h=>h.relatedIds??[]),...e.flatMap(h=>h.absorbedIds??[])]),N=e.filter(h=>h.comparison.family!=="spatial-pattern"&&!S.has(h.id)),A=a(N);function P(h,f=!1,w){const m=n===h.id,x=document.createElement("button");return x.type="button",x.dataset.wmapFinding=h.id,x.textContent=_e(h,w),ie(x,h.summary),x.setAttribute("aria-current",m?"true":"false"),Object.assign(x.style,{border:`1px solid ${B.menuBorder}`,borderLeft:`3px solid ${de(h.severity)}`,background:m?B.bgActive:B.menuBg,borderRadius:_.container,padding:f?"6px 10px":"8px 10px",textAlign:"left",fontSize:f?"10px":"11px",fontWeight:m?"600":"400",color:B.text,cursor:"pointer",width:"100%",marginBottom:y.xs}),q(x,"bare"),x.addEventListener("click",()=>o(h,x)),x}const R=ne(tt(e)??"");if(R){const h=l("div",{background:B.bgActive,borderRadius:_.container,padding:`${y.md} ${y.lg}`,marginBottom:y.md,display:"flex",gap:y.md,alignItems:"flex-start"}),f=l("span",{flex:"1",fontSize:E.body,lineHeight:Q.base,color:B.text},R);h.appendChild(f);const w=l("button",{flexShrink:"0",border:"none",background:"none",fontSize:E.body,color:B.icon,cursor:"pointer",padding:"0",lineHeight:Q.base,whiteSpace:"nowrap"},"Detail \u25B8");w.type="button",q(w,"bare"),w.addEventListener("click",()=>{const m=Fe({title:"Findings Summary",onClose:()=>{},anchor:w}),x=l("p",{fontSize:"16px",lineHeight:Q.base,color:B.text,padding:`${y.xxl} ${y.xxxl} ${y.xxl}`,margin:"0",borderBottom:`1px solid ${B.menuBorder}`,flexShrink:"0"},R);m.contentWrap.appendChild(x);const C=l("div",{overflowY:"auto",padding:`${y.xxl} ${y.xxxl}`,flex:"1"}),v=(k,T)=>{const M=l("div",{display:"flex",alignItems:"center",gap:"7px",fontSize:E.sub,fontWeight:"600",color:K,marginTop:y.lg,marginBottom:y.xs});return M.appendChild(ye(k)),M.appendChild(l("span",{},T)),M};for(const k of u){C.appendChild(v(k.severity,k.comparison.left)),C.appendChild(l("div",{fontSize:E.body,color:B.text,padding:"4px 0 4px 15px",marginBottom:y.xxs},ne(k.summary)));const T=e.filter(M=>k.relatedIds?.includes(M.id));for(const M of T)C.appendChild(l("div",{fontSize:E.body,color:Y,padding:"2px 0 2px 23px",marginBottom:y.xxs},ne(M.summary)))}for(const k of A){const[T,M]=k.key.split("\0");C.appendChild(v(k.worst,b(T,M)));for(const W of k.findings)C.appendChild(l("div",{fontSize:E.body,color:B.text,padding:"4px 0 4px 15px",marginBottom:y.xxs},_e(W,M)))}m.contentWrap.appendChild(C),Object.assign(m.contentWrap.style,{flexDirection:"column",overflow:"hidden"})}),h.appendChild(w),c.appendChild(h)}let H=!0;for(const h of u){H||c.appendChild(l("div",{height:"1px",background:B.separator,margin:"4px 0"})),H=!1;const f=e.filter(v=>h.relatedIds?.includes(v.id)),w=f.length>0,m=l("div",{position:"relative",marginBottom:w?"2px":"4px"}),x=n===h.id,C=document.createElement("button");if(C.type="button",C.dataset.wmapFinding=h.id,Object.assign(C.style,{border:`1px solid ${B.menuBorder}`,borderLeft:`3px solid ${de(h.severity)}`,background:x?B.bgActive:B.menuBg,borderRadius:_.container,padding:"8px 32px 8px 10px",textAlign:"left",fontSize:E.body,fontWeight:x?"600":"500",color:B.text,cursor:"pointer",width:"100%"}),C.textContent=ne(h.summary),ie(C,h.summary),C.setAttribute("aria-current",x?"true":"false"),q(C,"bare"),C.addEventListener("click",()=>o(h,C)),m.appendChild(C),w){const v=l("div",{display:"none",paddingLeft:"12px",marginBottom:y.xs});for(const M of f)v.appendChild(P(M,!0));m.appendChild(v);let k=!1;const T=l("button",{position:"absolute",top:"50%",right:"8px",transform:"translateY(-50%)",border:"none",background:"none",fontSize:E.body,color:B.icon,cursor:"pointer",padding:`${y.xxs} ${y.xs}`,lineHeight:Q.none},"\u25B8");q(T,"bare"),T.type="button",ie(T),T.setAttribute("aria-label","Show supporting findings"),T.setAttribute("aria-expanded","false"),T.addEventListener("click",M=>{M.stopPropagation(),k=!k,v.style.display=k?"block":"none",T.textContent=k?"\u25BE":"\u25B8";const W=k?"Hide supporting findings":"Show supporting findings";T.setAttribute("aria-label",W),T.setAttribute("aria-expanded",String(k))}),m.appendChild(T)}c.appendChild(m)}for(const h of A){H||c.appendChild(l("div",{height:"1px",background:B.separator,margin:"4px 0"})),H=!1;const[f,w]=h.key.split("\0"),m=l("div",{display:"flex",alignItems:"center",gap:y.sm,fontSize:E.body,fontWeight:"600",color:K,margin:"2px 0 4px"});m.appendChild(ye(h.worst)),m.appendChild(l("span",{},b(f,w))),c.appendChild(m);for(const x of h.findings)c.appendChild(P(x,!1,w))}return p}const St=[{value:"",label:"All kinds"},{value:"yield",label:"Yield"},{value:"hardBin",label:"Hard bin"},{value:"softBin",label:"Soft bin"},{value:"test",label:"Test value"},{value:"functionalTest",label:"Functional test"},{value:"spatialPattern",label:"Spatial pattern"}],vt=[{value:"",label:"All regions"},{value:"ring",label:"Ring"},{value:"quadrant",label:"Quadrant"},{value:"reticle-position",label:"Reticle position"},{value:"test-site",label:"Test site"},{value:"wafer",label:"Wafer"},{value:"sector",label:"Sector"},{value:"cluster",label:"Cluster"},{value:"edge-arc",label:"Edge arc"},{value:"spatial-pattern",label:"Spatial pattern"}],$t=["unusual","notable","info"],kt={unusual:"Unusual",notable:"Notable",info:"Info"};function Bt(e,t,o){const n=l("div",{display:"flex",flexWrap:"wrap",alignItems:"center",gap:y.lg,marginBottom:y.lg,paddingBottom:"10px",borderBottom:`1px solid ${B.separator}`}),i={unusual:0,notable:0,info:0};for(const r of e)i[r.severity]++;const d=$t.filter(r=>i[r]>0),s=new Set(t.severity===void 0?d:Array.isArray(t.severity)?t.severity:[t.severity]),p=l("div",{display:"flex",gap:y.xs,flexWrap:"wrap"});for(const r of d){const a=document.createElement("button");a.type="button";const b=()=>{const u=s.has(r);a.setAttribute("aria-pressed",u?"true":"false"),Object.assign(a.style,{display:"inline-flex",alignItems:"center",gap:"5px",border:`1px solid ${B.menuBorder}`,borderRadius:_.pill,background:u?B.bgActive:"none",opacity:u?"1":"0.5",color:B.text,fontSize:E.body,padding:`${y.xxs} ${y.md}`,cursor:"pointer"}),a.dataset.on=u?"true":"false"};a.appendChild(ye(r)),a.appendChild(l("span",{},`${kt[r]} ${i[r]}`)),ie(a,()=>s.has(r)?"Click to hide these findings":"Click to show these findings"),b(),q(a,"bare"),a.addEventListener("click",()=>{s.has(r)?s.delete(r):s.add(r),t.severity=s.size===d.length?void 0:[...s],o()}),p.appendChild(a)}n.appendChild(p);const c=t.kind!==void 0||t.family!==void 0;return(e.length>=Lt||c)&&(n.appendChild(Be("Kind:",St,t.kind??"",r=>{t.kind=r||void 0,o()},{maxWidth:"130px"})),n.appendChild(Be("Region:",vt,t.family??"",r=>{t.family=r||void 0,o()},{maxWidth:"150px"}))),n}const Lt=8;function Nt(e,t){const o=l("div",{display:"flex",flexDirection:"column",gap:y.xs,padding:y.md,marginBottom:y.md,background:B.bgHover,borderRadius:_.control},void 0,t);if(o.appendChild(l("div",{fontSize:E.body,color:B.value},e.message,t)),e.detail&&o.appendChild(l("div",{fontSize:E.meta,color:Y},e.detail,t)),e.actionLabel&&e.onAction){const n=l("button",le("outlined"),e.actionLabel,t);n.type="button",n.style.alignSelf="flex-start",n.style.marginTop=y.xs,q(n),n.addEventListener("click",e.onAction),o.appendChild(n)}return o}export function buildFindingsSectionWithFilter(e,t,o,n,i,d,s){if(!e.findings.length&&!s)return null;const p=e.findings.some(N=>N.severity==="unusual"||N.severity==="notable"),c=p?e.findings.filter(N=>N.severity!=="info").length.toString():void 0,r=d?.ownerDocument??document,{outer:a,content:b}=X(`Findings (${e.findings.length})`,p||!!s,c,{stateKey:"findings",panel:d});if(s&&b.appendChild(Nt(s,r)),!e.findings.length)return a;b.appendChild(Bt(e.findings,n,i));const u=nt(e,n);if(!u.length)return b.appendChild(l("div",{color:Y,fontSize:E.body,textAlign:"center",padding:`${y.xxl} ${y.md}`},"No findings match the current filter.")),a;const S=buildFindingsSection(u,e,t,o,!0);return S&&b.appendChild(S),a}export function buildLotTestSection(e,t,o,n,i,d,s,p="full"){const c=n?.length?{perWaferMetadata:n.map(a=>a.wafer??{}),populationLabel:`${n.length} wafer${n.length===1?"":"s"} pooled`}:void 0;let r;if(n?.length&&n.every(a=>a.stats.perTestStats!==void 0)){const a=new Map;for(const b of n)for(const u of b.stats.perTestStats??[]){const S=a.get(u.testNumber);S?(S.n+=u.count,S.sum+=u.mean*u.count,S.min=Math.min(S.min,u.min),S.max=Math.max(S.max,u.max)):a.set(u.testNumber,{n:u.count,sum:u.mean*u.count,min:u.min,max:u.max})}r={perTestStats:[...a.entries()].map(([b,u])=>({testNumber:b,count:u.n,min:u.min,max:u.max,mean:u.sum/u.n}))}}if(n?.length&&n.every(a=>a.stats.testSpecYield!==void 0)){const a=new Map;for(const b of n)for(const u of b.stats.testSpecYield??[]){const S=a.get(u.testNumber);S?(S.passDies+=u.passDies,S.totalDies+=u.totalDies):a.set(u.testNumber,{passDies:u.passDies,totalDies:u.totalDies})}r={...r,testSpecYield:[...a.entries()].map(([b,u])=>({testNumber:b,totalDies:u.totalDies,yieldPercent:u.totalDies>0?u.passDies/u.totalDies*100:null}))}}return buildTestSection(e,t,o,r,i,c,d,s,p)}export function createSummaryPanelEl(e,t,o=document){const n=e==="top"||e==="bottom",i=l("div",{background:gt,color:B.text,fontVariantNumeric:"tabular-nums",border:Re,borderRadius:_.container,padding:y.xl,overflowY:"auto",overflowX:n?"auto":"hidden",flexShrink:"0",boxSizing:"border-box",fontFamily:E.family,fontSize:E.sub,boxShadow:Le.panel},void 0,o);return e==="right"&&(i.style.marginRight=t),e==="left"&&(i.style.marginLeft=t),e==="bottom"&&(i.style.marginBottom=t),n?(i.style.height="180px",i.style.width="100%"):(i.style.width="300px",i.style.maxHeight="100%"),i}export function wrapWithSummaryPanel(e,t,o){const n=o==="top"||o==="bottom",i=l("div",{display:"flex",flexDirection:n?"column":"row",gap:y.md,width:"100%",height:"100%",flex:"1 1 0",minHeight:"0",boxSizing:"border-box",alignItems:n?"flex-start":"stretch"});return e.style.flex="1 1 0",e.style.minWidth="0",e.style.minHeight="0",o==="right"||o==="bottom"?(i.appendChild(e),i.appendChild(t)):(i.appendChild(t),i.appendChild(e)),i}function je(e){return l("div",{fontSize:E.heading,fontWeight:"600",color:K,marginBottom:y.lg},e)}function fe(e,t){const o=l("button",le("outlined"),e);return o.type="button",q(o),o.addEventListener("click",t),o}function qe(...e){const t=e.filter(n=>!!n);if(!t.length)return null;const o=l("div",{display:"flex",flexWrap:"wrap",gap:y.sm,marginBottom:y.lg});for(const n of t)o.appendChild(n);return o}function Ve(e,t,o,n,i,d,s,p,c,r,a){const b=e.ownerDocument,u=Fe({title:"Die list",onClose:()=>{},anchor:e,ownerDocument:b});u.contentWrap.style.padding="14px 16px";const S=ft(t,o,{...s,title:n,onSaveText:p,waferMetadata:i,metadataFields:d,extraColumn:c,getWafer:r,ringCount:a,ownerDocument:b});S&&u.contentWrap.appendChild(S)}export function renderWaferSummaryContent(e,t){const o=e.scrollTop;e.innerHTML="";const{wafer:n,dies:i,yieldSummary:d,dataCoverage:s,hbinDefs:p,sbinDefs:c,testDefs:r,statsSummary:a,passBins:b=[1],ringCount:u=4,binColors:S,plotMode:N,fallbackFormat:A,onFindingClick:P,activeFindingId:R=null,findingsFilter:H,onFindingsFilterChange:h,findingsNotice:f,onSaveText:w,metadataFields:m,dieListOptions:x,metadataShownElsewhere:C}=t;e.appendChild(je("Wafer Summary"));const v=t.warnings??$e({statsSummary:a});v.length&&e.appendChild(ge(v,e.ownerDocument));const k=d&&s?fe("Summary report",()=>{Ee(Je({wafer:n,dies:i,yield:d,dataCoverage:s,hbinDefs:p,sbinDefs:c,testDefs:r,passBins:b,ringCount:u},a),{anchor:e})}):null,T=(x?.enabled??!0)&&i.length?fe("View die list",()=>{Ve(e,i,r,`Die list \u2014 ${i.length} dies`,n.metadata,m,x,w,void 0,()=>n,u)}):null,M=qe(k,T);M&&e.appendChild(M);const W=[],V=a?.stats.isLotStack?a.stats:void 0,G=V?.lotSize!==void 0?{lotSize:V.lotSize,aggrMethod:lt(V.aggregationMethod)}:void 0;C||W.push(buildMetadataInfoSection([{metadata:n.metadata??void 0}],G)),d&&s&&W.push(buildYieldSection(d,s,b)),a&&P&&H&&h&&W.push(buildFindingsSectionWithFilter(a,P,R,H,h,e,f)),W.push(buildBinBreakdownSection({dies:i,hbinDefs:p,sbinDefs:c,binColors:S,hardCounts:a?.stats.hardBinCounts,softCounts:a?.stats.softBinCounts,plotMode:N,passBins:b,panel:e})),W.push(buildRegionYieldPanelSection({diesByWafer:[i],allWafers:[n],ringCount:u,passBins:b,panel:e}));const U=n.metadata?{waferMetadata:n.metadata}:void 0;W.push(buildTestSection(i,r,A,a?.stats,w,U,[{dies:i}],e,"compact")),W.push(buildFunctionalTestSection(i,r,a?.stats.functionalYield,w,U,e));let g=!0;for(const F of W)F&&(g||e.appendChild(Ae()),g=!1,e.appendChild(F));e.appendChild(l("div",{height:"12px",flexShrink:"0"})),e.scrollTop=o}export function reportMapsFromItems(e,t,o){const n=[];return e.forEach((i,d)=>{!i?.wafer||!i.dies||n.push({...i,wafer:i.wafer,dies:i.dies,label:me(i,d),passBins:[...he(i,t)],ringCount:i.ringCount??o})}),n}export function renderLotSummaryContent(e,t){const o=e.scrollTop;e.innerHTML="";const{lotSummary:n,items:i,hbinDefs:d,sbinDefs:s,testDefs:p,passBins:c=[1],ringCount:r=4,binColors:a,plotMode:b,fallbackFormat:u,onFindingClick:S,activeFindingId:N=null,onWaferClick:A,findingsFilter:P,onFindingsFilterChange:R,findingsNotice:H,onSaveText:h,dieListOptions:f,findingsFor:w}=t;e.appendChild(je(`Summary \u2014 ${rt(ve(n.perWafer.map(L=>L.summary.wafer)))}`));const m=t.warnings??$e({lotStatsSummary:n});m.length&&e.appendChild(ge(m,e.ownerDocument));const x=fe("Summary report",()=>{Ee(et(reportMapsFromItems(i,c,r)),{anchor:e})}),C=[],v=[],k=[],T=[],M=[],W=new WeakMap,V=new WeakMap;for(let L=0;L<i.length;L++){const I=i[L];if(!I){v.push([]);continue}I.wafer&&(C.push(I.wafer),T.push(I.dies??[]),M.push(he(I,c)));const z=I.dies??[],$=me(I,L);for(const D of z)W.set(D,$),I.wafer&&V.set(D,I.wafer);v.push(z),k.push(...z)}const G=f?.enabled??!0?fe("View die list",()=>{k.length&&Ve(e,k,p,`Die list \u2014 ${k.length} dies across ${i.length} wafer${i.length===1?"":"s"}`,we(i.filter(L=>!!L).map(L=>({metadata:L.wafer?.metadata}))),i.find(L=>L?.metadataFields?.length)?.metadataFields,f,h,{label:"Wafer",get:L=>W.get(L)},L=>V.get(L),r)}):null,U=qe(x,G);U&&e.appendChild(U);const g=i.map(L=>L?.statsSummary).filter(L=>!!L),F=[buildLotOverviewSection(n,g)];S&&P&&R&&F.push(buildFindingsSectionWithFilter(n,S,N,P,R,e,H)),F.push(buildPerWaferYieldSection(n,i,A,e,w),buildBinBreakdownSection({dies:k,hbinDefs:d,sbinDefs:s,plotMode:b,passBins:c,panel:e,binColors:a??st(i.flatMap(L=>L?[{dies:L.dies??[],passBins:he(L,c)}]:[]),{hbinDefs:d,sbinDefs:s}).colors}),buildRegionYieldPanelSection({diesByWafer:T,allWafers:C,ringCount:r,passBins:L=>M[L],panel:e}),p?.length?buildLotTestSection(k,p,u,g,h,v.map(L=>({dies:L})),e,"compact"):null,p?.length?buildLotFunctionalSection(k,p,g,h,e):null);let O=!0;for(const L of F)L&&(O||e.appendChild(Ae()),O=!1,e.appendChild(L));e.appendChild(l("div",{height:"12px",flexShrink:"0"})),e.scrollTop=o}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{fontPx as Rt}from"./toolbar.js";import{findTestDef as Re,buildMapTitle as Ce}from"../renderer/buildView.js";import{sortBinsForDisplay as je}from"../stats/binPareto.js";import{affineInvert as Qe,affineVector as _e}from"../core/transforms.js";import{compareNatural as ve}from"../core/utils.js";import{resolveValueColorFn as to}from"../renderer/colorSchemes.js";import{NO_DATA_FILL as eo}from"../renderer/colorMap.js";import{SPEC_PASS_FILL as Be,SPEC_FAIL_LOW as oo,SPEC_FAIL_HIGH as Pe,contrastTextColor as De}from"../renderer/colorMap.js";import{fmt as We,fmtColorbarAxis as no}from"../renderer/fmt.js";import{resolveCanvasTheme as so}from"./canvasTheme.js";import{hitGridDims as lo}from"./hitGrid.js";function Ie(g,e,P,b,r){g.moveTo(e,P+r*b),g.lineTo(e-b*.9,P-r*b*.6),g.lineTo(e+b*.9,P-r*b*.6),g.closePath()}const io=new Set(["value","stackedValues","stackedBins","stackedSoftBins"]),ao=new Set(["hardBin","softBin","metadata"]),J=()=>`${Rt(-2)}px system-ui, sans-serif`,Fe=3,Vt=2,co=6,ro=20,fo=()=>`600 ${Rt()}px system-ui, sans-serif`,Ut=()=>`${Rt(-1)}px system-ui, sans-serif`,ho=()=>`600 ${Rt(-1)}px system-ui, sans-serif`,Kt=128,go=()=>`${Rt(-2)}px system-ui, sans-serif`,Ne=4,D=17,H=11;export const BIN_LEGEND_W=110,BIN_LEGEND_W_COMPACT=64,BIN_LEGEND_ADAPT_COMPACT=280,BIN_LEGEND_ADAPT_FLOATING=180,BIN_LEGEND_MIN_CANVAS_W=150,BIN_LEGEND_MIN_CANVAS_H=120;const qt=28,dt=5,ft=8,Oe=15,Ee=12,He=6;export function toCanvas(g,e,P={}){return drawMapCanvas(g,e,P)}export function drawMapCanvas(g,e,P={}){const b=so(g.parentElement??g),{padding:r=16,showColorbar:G=!0,markFailingDies:X=!1,colorbarWidth:B=16,background:gt=b.background,legendPosition:Z="default",legendOffset:mt,showAxes:ut=!1,diePitchMm:w,viewport:K,activeBin:O,hoverBin:q,fallbackFormat:bt,minRightReserve:Ct,hbinDefs:nt,sbinDefs:pt,metadataFields:xt,showTitle:U=!0}=P,W=Math.floor(g.clientWidth||g.width),Y=Math.floor(g.clientHeight||g.height),Mt=W>=BIN_LEGEND_MIN_CANVAS_W&&Y>=BIN_LEGEND_MIN_CANVAS_H,Tt=G&&Mt&&io.has(e.plotMode)&&e.passFailDisplay==="off",St=G&&Mt&&ao.has(e.plotMode),j=G&&Mt&&e.plotMode==="value"&&(e.passFailDisplay==="spec"&&e.specCounts!==void 0||e.passFailDisplay==="test"&&e.passFailCounts!==void 0),Q=St||j,_t=St&&e.plotMode!=="metadata"&&e.binCounts?je(e.binCounts.entries(),e.plotMode==="softBin"?e.binColors.pass.soft:e.binColors.pass.hard):[],Bt=St&&e.plotMode==="metadata"&&e.metadataCounts?[...e.metadataColorMap?.keys()??[...e.metadataCounts.keys()].sort(ve)].map(o=>[o,e.metadataCounts.get(o)??0]):[],v=[];if(j&&e.passFailDisplay==="test"){const o=e.passFailCounts;v.push({key:-1,color:Be,label:"Pass",compactLabel:"Pass",count:o.pass,tooltip:`Pass \xB7 ${o.pass} dies`}),v.push({key:-2,color:Pe,label:"Fail",compactLabel:"Fail",count:o.fail,tooltip:`Fail \xB7 ${o.fail} dies`})}else if(j){const o=e.specCounts,f=Re(e.testDefs,e.activeTest);v.push({key:-1,color:Be,label:"Pass",compactLabel:"Pass",count:o.pass,tooltip:`Pass \xB7 ${o.pass} dies`}),f?.limitHigh!==void 0&&v.push({key:-2,color:Pe,label:"Fail high",compactLabel:"Fail hi",count:o.failHigh,tooltip:`Fail high \xB7 ${o.failHigh} dies`}),f?.limitLow!==void 0&&v.push({key:-3,color:oo,label:"Fail low",compactLabel:"Fail lo",count:o.failLow,tooltip:`Fail low \xB7 ${o.failLow} dies`})}const Pt=j?v.length:e.plotMode==="metadata"?Bt.length:_t.length,p=(g.ownerDocument.defaultView??window).devicePixelRatio??1;if(W<=0||Y<=0)return{hitTarget:{getDieAtPoint:()=>null},viewport:{originX:0,originY:0,ppm:1,snapDist:1},binLegendRows:[]};const A=Z!=="default"?Z:W<BIN_LEGEND_ADAPT_FLOATING?"floating":W<BIN_LEGEND_ADAPT_COMPACT?"compact":"default",ht=A==="default"||A==="compact",fe=A==="left",Jt=A==="bottom",Lt=A==="top",kt=A==="floating",Dt=A==="compact"||A==="floating"?BIN_LEGEND_W_COMPACT:BIN_LEGEND_W,he=Math.floor((Y-2*r)/D),de=Pt>he?he-1:Pt,ge=Q&&Jt?de*D:0,Zt=Q&&Lt?de*D:0,jt=e.plotMode==="stackedBins"||e.plotMode==="stackedSoftBins",Qt=Re(e.testDefs,e.activeTest),Ye=jt?"Count":Qt?.name??(e.activeTest!=null?`Test ${e.activeTest}`:void 0),Ge=jt?void 0:Qt?.unit,[Wt,It]=e.valueRange,{tickFmt:Xe}=no(It,Ye,Ge,bt),Ft=e.allIntegerValues?o=>String(Math.round(o)):Xe;let vt=0;if(Tt){const o=g.getContext("2d");o.font=J();const f=[Ft(Wt),Ft(It)];Wt<0&&f.push(Ft(-Math.max(Math.abs(Wt),Math.abs(It))));for(const s of f)vt=Math.max(vt,o.measureText(s).width)}const me=Math.max(ro,Math.ceil(vt)+Fe+Vt+co-r),te=Tt?B+me+8:Q&&ht?Dt:0,ee=Q&&fe?Dt:0,oe=ut?32:0,Nt=ut?36:0,$e=Ct!=null?Math.max(te,Ct):te,we=W-2*r-$e-Nt-ee,ue=Y-2*r-oe-ge-Zt;g.width=Math.round(W*p),g.height=Math.round(Y*p);const t=g.getContext("2d");t.scale(p,p),t.fillStyle=gt,t.fillRect(0,0,W,Y);const $=e.hoverPoints;if(!$.length)return{hitTarget:{getDieAtPoint:()=>null},viewport:{originX:0,originY:0,ppm:1,snapDist:1},binLegendRows:[]};const Ot=e.rectangles[0],ne=Ot?Ot.width/2:0,se=Ot?Ot.height/2:0,Et=e.dieBounds,pe=(Et?.minX??0)-ne,Ve=(Et?.maxX??0)+ne,Ue=(Et?.minY??0)-se,xe=(Et?.maxY??0)+se,Me=Ve-pe,ye=xe-Ue;let tt,et,L;if(K)({originX:tt,originY:et,ppm:L}=K);else{const f=e.notchDir,s=f&&f.y>.1?13:0,a=f&&f.y<-.1?13:0,c=f&&f.x<-.1?13:0,h=f&&f.x>.1?13:0,d=we-c-h,i=ue-s-a;L=Math.min(d/Me,i/ye),tt=r+Nt+ee+c+(d-Me*L)/2-pe*L,et=r+Zt+s+(i-ye*L)/2+xe*L}const Ht=K?.snapDist??Math.max(ne,se,1)*1.5,Yt=tt+e.waferCenter.x*L,Ke=et-e.waferCenter.y*L,le=e.waferRadius*L,st=o=>{const f=Math.abs(o-Ke);return f>=le?0:Math.sqrt(le*le-f*f)},lt=(o,f,s,a,c,h,d=fo(),i=b.text)=>{if(!o)return;t.save(),t.fillStyle=i,t.font=d,t.textAlign=a,t.textBaseline=c;const y=a==="right"?f-h:h-f;let l=o;if(y>8&&t.measureText(l).width>y){for(;l.length>1&&t.measureText(l+"\u2026").width>y;)l=l.slice(0,-1);l=l+"\u2026"}y>8&&t.fillText(l,f,s),t.restore()};if(t.save(),t.setTransform(L*p,0,0,-L*p,tt*p,et*p),e.rectangles.length>0){const o=new Map;for(const s of e.rectangles){const a=String(s.fill);let c=o.get(a);c||(c=[],o.set(a,c)),c.push(s)}for(const[s,a]of o){t.beginPath();for(const c of a)t.rect(c.x-c.width/2,c.y-c.height/2,c.width,c.height);t.fillStyle=s,t.fill()}t.strokeStyle="rgba(0,0,0,0.18)",t.lineWidth=.5/(L*p),t.beginPath();for(const s of e.rectangles)t.rect(s.x-s.width/2,s.y-s.height/2,s.width,s.height);if(t.stroke(),X){const s=e.rectangles.filter(a=>a.binFail);if(s.length>0){const a=new Map;for(const c of s){const h=De(String(c.fill));let d=a.get(h);d||(d=[],a.set(h,d)),d.push(c)}t.save(),t.lineCap="butt";for(const[c,h]of a){t.strokeStyle=c,t.globalAlpha=.55,t.lineWidth=Math.max(.6/(L*p),Math.min(h[0].width,h[0].height)*.1);for(const d of h){const i=d.width/2,y=d.height/2,l=Math.max(1.6/(L*p),Math.min(d.width,d.height)/3);t.save(),t.beginPath(),t.rect(d.x-i,d.y-y,d.width,d.height),t.clip(),t.beginPath();for(let T=-(i+y);T<=i+y;T+=l)t.moveTo(d.x-i+T,d.y-y),t.lineTo(d.x-i+T+d.height,d.y+y);t.stroke(),t.restore()}}t.restore()}}const f=e.rectangles.filter(s=>s.specMark);if(f.length>0){const s=new Map;for(const c of f){const h=De(String(c.fill)),d=`${c.specMark}|${h}`;let i=s.get(d);i||(i=[],s.set(d,i)),i.push(c)}const a=2.5/(L*p);t.lineJoin="round";for(const[c,h]of s){const[d,i]=c.split("|"),y=i==="#000000"?"#ffffff":"#000000",l=d==="failHigh"?1:-1,T=Math.min(h[0].width,h[0].height),I=Math.max(2.5/(L*p),T*.3);t.beginPath();for(const R of h)Ie(t,R.x,R.y,I,l);t.strokeStyle=y,t.lineWidth=a,t.stroke(),t.fillStyle=i,t.fill()}}}for(const o of e.overlays){t.beginPath();for(const f of o.points){for(let s=0;s<f.length;s++)s===0?t.moveTo(f[s].x,f[s].y):t.lineTo(f[s].x,f[s].y);o.closed&&t.closePath()}o.fill&&!o.fill.startsWith("rgba(0,0,0,0)")&&(t.fillStyle=o.fill,t.fill()),o.kind==="ring-boundary"||o.kind==="quadrant-boundary"||o.kind==="reticle"?(t.strokeStyle="rgba(0,0,0,0.45)",t.lineWidth=3/(L*p),t.stroke(),t.strokeStyle="rgba(255,255,255,0.8)",t.lineWidth=1/(L*p),t.stroke()):(t.strokeStyle=o.lineColor,t.lineWidth=o.lineWidth/(L*p),t.stroke())}if(t.restore(),e.notchDir){const o=tt+e.waferCenter.x*L,f=et-e.waferCenter.y*L,s=e.notchDir.x,a=-e.notchDir.y,c=e.waferRadius*L,h=4,d=9,i=5,y=o+s*(c+h),l=f+a*(c+h),T=y+s*d,I=l+a*d,R={x:-a,y:s},F=r+Nt+ee,E=W-r-te,V=r+Zt,at=Y-r-ge-oe;t.save(),t.beginPath(),t.rect(F,V,E-F,at-V),t.clip(),t.beginPath(),t.moveTo(y,l),t.lineTo(T+R.x*i,I+R.y*i),t.lineTo(T-R.x*i,I-R.y*i),t.closePath(),t.fillStyle=b.text,t.fill(),t.restore()}t.save(),t.textAlign="center",t.textBaseline="middle";let be=0;if(e.rectangles.length>0){let o=1;for(const h of e.texts)h.role!=="indicator"&&h.text.length>o&&(o=h.text.length);const f=e.rectangles[0].width*L,s=e.rectangles[0].height*L,a=Math.min(f,s),c=f/o;be=Math.max(8,Math.min(64,Math.round(Math.min(a*.55,c*1.8))))}for(const o of e.texts){const f=tt+o.x*L,s=et-o.y*L;t.font=`${o.role==="indicator"?o.fontSize:be}px system-ui, sans-serif`,t.fillStyle=o.color,t.fillText(o.text,f,s)}if(t.restore(),ut&&mo(t,W,Y,tt,et,L,r,oe,Nt,w,e.gridToScreen,e.rotation,b),Tt){const o=to(e.valueColorScheme,e.reverseValueScheme),f=me,s=ue,a=Math.round(s*.75),c=r+Math.round((s-a)/2),h=W-r-B-f,d=Wt,i=It,y=i-d,l=e.plotMode==="stackedSoftBins"?pt:nt,{primary:T,secondary:I}=U?Ce(e,bt,l):{primary:"",secondary:""};if(U){const n=Math.max(c-6,r+11),m=Yt+Math.max(st(n),st(n-12))+8;lt(T,W-r,n,"right","bottom",m)}let R=c+a+4;const F=n=>Yt+Math.max(st(n),st(n+12))+8,E=e.logScale&&d>0?Math.log10(d):0,V=e.logScale&&i>0?Math.log10(i)-E:1,at=n=>e.logScale?(1-(Math.log10(n)-E)/V)*a:(1-(n-d)/y)*a;for(let n=0;n<Kt;n++){const m=1-n/(Kt-1),S=c+n/Kt*a,x=a/Kt+1;t.fillStyle=o(m),t.fillRect(h,S,B,x)}t.strokeStyle="rgba(0,0,0,0.25)",t.lineWidth=.5,t.strokeRect(h,c,B,a),t.fillStyle=b.text,t.font=J(),t.textAlign="left",t.strokeStyle="rgba(0,0,0,0.35)",t.lineWidth=.5;const k=Fe,N=36,ot=14,$t=e.logScale&&V>0?uo(d,i,a,N,ot,E,V):e.allIntegerValues?(()=>{const n=Math.max(1,zt(y*N/a)),m=[],S=Math.ceil(d/n)*n;for(let x=S;x<=i+n*1e-6;x+=n){const u=(1-(x-d)/y)*a;u>ot&&u<a-ot&&m.push(Math.round(x))}return m})():(()=>{const n=y>0?zt(y*N/a):0,m=[];if(n>0){const S=Math.ceil(d/n)*n;for(let x=S;x<=i+n*1e-6;x+=n){const u=(1-(x-d)/y)*a;u>ot&&u<a-ot&&m.push(x)}}return m})(),C=Qt,_=jt,M=Ft;t.textBaseline="middle";for(const n of $t){const m=c+at(n);t.beginPath(),t.moveTo(h+B,m),t.lineTo(h+B+k,m),t.stroke(),t.fillText(M(n),h+B+k+Vt,m)}if(t.beginPath(),t.moveTo(h+B,c),t.lineTo(h+B+k,c),t.stroke(),t.textBaseline="top",t.fillText(M(i),h+B+k+Vt,c),t.beginPath(),t.moveTo(h+B,c+a),t.lineTo(h+B+k,c+a),t.stroke(),t.textBaseline="bottom",t.fillText(M(d),h+B+k+Vt,c+a),!_&&C&&(C.limitLow!==void 0||C.limitHigh!==void 0)){const n=[],m=e.colorbarRangeMode==="spec";for(const[S,x]of[[C.limitLow,"LSL"],[C.limitHigh,"USL"]]){if(S===void 0||e.logScale&&S<=0)continue;const u=at(S);!m&&(u<-ot||u>a+ot)||n.push({value:S,label:x,py:Math.max(0,Math.min(a,u))})}if(n.length>0){t.save(),t.font=J(),t.textAlign="right",t.textBaseline="middle";for(const{py:S,label:x}of n){const u=c+S;m||(t.strokeStyle="rgba(255,255,255,0.85)",t.lineWidth=3,t.beginPath(),t.moveTo(h,u),t.lineTo(h+B,u),t.stroke(),t.strokeStyle="rgba(0,0,0,0.7)",t.lineWidth=1,t.beginPath(),t.moveTo(h,u),t.lineTo(h+B,u),t.stroke()),t.fillStyle=b.text,t.fillText(x,h-3,u);const ct=x==="USL"?-1:1,rt=4,yt=h-3-t.measureText(x).width-rt-4;t.beginPath(),Ie(t,yt,u,rt,ct),t.strokeStyle="#fff",t.lineWidth=2,t.lineJoin="round",t.stroke(),t.fillStyle=b.text,t.fill()}t.restore()}}if(!_){const n=e.logScale?"log\u2081\u2080":e.logScaleRequested?"linear \u2014 log n/a":null;n&&(t.save(),t.fillStyle=b.text,t.font=ho(),t.textAlign="right",t.textBaseline="top",t.fillText(n,W-r,R),t.restore(),R+=15)}U&&I&<(I,W-r,R,"right","top",F(R),Ut(),b.text)}const ie=[];let z;if(Q){const o=A==="compact",f=e.plotMode==="softBin"?pt:nt,s=f?new Map(f.map(l=>[l.bin,l])):null,a=e.plotMode==="softBin"?e.binColors.soft:e.binColors.hard,c=l=>a.get(l)??eo,h=(l,T)=>{const I=t.measureText(l).width,R=o?0:t.measureText(String(T)).width,F=H+dt+I+(R?qt:0);return{labelWidth:I,countWidth:R,totalWidth:F}},d=xt?.find(l=>l.key===e.activeMetadataKey),i=j?v.map(l=>{const T=o?l.compactLabel:l.label;return{key:l.key,color:l.color,count:l.count,label:T,tooltipLabel:l.tooltip,...h(T,l.count)}}):e.plotMode==="metadata"?Bt.map(([l,T])=>{const R=d?.values?.find(V=>V.value===l)?.label??l,F=o?l:R,E=e.metadataColorMap?.get(l)??"#d6d9dd";return{key:l,color:E,count:T,label:F,tooltipLabel:`${R} \xB7 ${T} dies`,...h(F,T)}}):_t.map(([l,T])=>{const I=s?.get(l),R=I?.name?`${l} \xB7 ${I.name}`:`Bin ${l}`,F=o?String(l):R;return{key:l,color:c(l),count:T,label:F,tooltipLabel:`${R} \xB7 ${T} dies`,...h(F,T)}}),y=W-r*2;if(i.length>0){const l=kt?ft*2+(U?Oe:0):U&&!Lt?Ee+He:0,T=Math.max(1,Math.floor((Y-2*r-l)/D));let I=i.length,R=1,F=I*D,E=[],V=0;const at=Jt||Lt;if(at){const C=Math.max(...i.map(M=>M.totalWidth)),_=Math.max(1,Math.min(i.length,Math.floor((y+8)/(C+8))));for(let M=_;M>=1;M--){const n=Math.ceil(i.length/M);if(n>T)continue;const m=new Array(M).fill(0);for(let x=0;x<i.length;x++){const u=x%M;m[u]=Math.max(m[u],i[x].totalWidth)}if(m.reduce((x,u)=>x+u,0)+(M-1)*8<=y||M===1){R=M,E=m,I=n,F=n*D;break}}}else I=Math.min(i.length,T),F=I*D,i.length>T&&(V=i.length-(T-1)),E=[Dt];let k,N;if(kt){const C=Math.max(...i.map(u=>H+dt+t.measureText(u.label).width+qt)),_=Math.ceil(C);E=[_];const M=U?Oe:0,n=_+ft*2,m=F+M+ft*2,S=mt?.x??0,x=mt?.y??0;k=Math.min(Math.max(W-r-n+S,r),W-r-n),N=Math.min(Math.max(Y-r-m+x,r),Y-r-m),z={x:k,y:N,w:n,h:m},t.save(),t.globalAlpha=.92,t.fillStyle=b.surface,t.fillRect(k,N,n,m),t.globalAlpha=1,t.strokeStyle=b.axisLine,t.lineWidth=1,t.strokeRect(k,N,n,m),t.restore(),k+=ft,N+=ft+M}else Jt?(k=r,N=Y-r-F):Lt?(k=r,N=r):fe?(k=r+4,N=Math.max(r+Math.round((Y-2*r-F)/2),r+l)):(k=W-r-Dt+4,N=Math.max(r+Math.round((Y-2*r-F)/2),r+l));if(U){const C=e.plotMode==="softBin"?pt:nt,{primary:_,secondary:M}=Ce(e,bt,C),n=He,m=u=>Yt-Math.max(st(u),st(u-12))-8,S=u=>ht?W-r:m(u),x=kt?z.y+z.h:N+F;if(Lt){const u=x+n;lt(_,k,u,"left","top",Yt-Math.max(st(u),st(u+12))-8),M&<(M,k,u+16,"left","top",m(u+16),Ut(),b.text)}else if(kt)lt(_,z.x+ft,z.y+ft,"left","top",z.x+z.w-ft),M&<(M,z.x,x+n,"left","top",z.x+z.w,Ut(),b.text);else{const u=Math.max(N-n,r+Ee);if(lt(_,k,u,"left","bottom",S(u)),M){const ct=x+n;lt(M,k,ct,"left","top",S(ct),Ut(),b.text)}}}t.save(),t.font=J();const ot=at?8:0,$t=(C,_)=>{if(t.measureText(C).width<=_)return C;let M=0,n=C.length;const m="\u2026",S=t.measureText(m).width;for(;M<n;){const x=M+n+1>>1;t.measureText(C.slice(0,x)).width+S<=_?M=x:n=x-1}return M===0?m:C.slice(0,M)+m};if(at){let C=0;for(let _=0;_<I;_++){let M=k;for(let n=0;n<R;n++){const m=i[C++];if(!m)break;const S=m.key===O,x=!S&&m.key===q,u=M,ct=M+H+dt,rt=N+_*D+D/2,yt=N+_*D+Math.round((D-H)/2),wt=E[n]-H-dt-qt;x&&(t.fillStyle=b.hoverRow,t.fillRect(M,N+_*D,E[n],D)),t.fillStyle=m.color,t.fillRect(u,yt,H,H),t.strokeStyle=S?b.accent:"rgba(0,0,0,0.25)",t.lineWidth=S?2:.75,t.strokeRect(u,yt,H,H),t.fillStyle=S?b.accent:b.text,t.font=S?`bold ${J()}`:J(),t.textAlign="left",t.textBaseline="middle",t.fillText($t(m.label,wt),ct,rt),t.fillStyle=b.textMuted,t.font=J(),t.textAlign="right",t.fillText(String(m.count),M+E[n]-2,rt),ie.push({bin:m.key,x:M,y:N+_*D,w:E[n],h:D,label:m.tooltipLabel}),M+=E[n]+ot}}}else{const C=E[0],_=A!=="compact",M=C-H-dt-(_?qt:0),n=k+C-2;let m=i;V>0&&(m=i.slice(0,T-1));let S=N;for(const x of m){const u=x.key===O,ct=!u&&x.key===q,rt=k,yt=k+H+dt,wt=S+D/2,Ae=S+Math.round((D-H)/2),Ze=x.label;ct&&(t.fillStyle=b.hoverRow,t.fillRect(k-3,S,C+3,D)),t.fillStyle=x.color,t.fillRect(rt,Ae,H,H),t.strokeStyle=u?b.accent:"rgba(0,0,0,0.25)",t.lineWidth=u?2:.75,t.strokeRect(rt,Ae,H,H),t.fillStyle=u?b.accent:b.text,t.font=u?`bold ${J()}`:J(),t.textAlign="left",t.textBaseline="middle",t.fillText($t(Ze,M),yt,wt),(_||kt)&&(t.fillStyle=b.textMuted,t.font=J(),t.textAlign="right",t.fillText(String(x.count),n,wt)),ie.push({bin:x.key,x:k,y:S,w:C,h:D,label:x.tooltipLabel}),S+=D}V>0&&(t.fillStyle=b.textMuted,t.font=J(),t.textAlign="left",t.textBaseline="middle",t.fillText(`+ ${V} more`,k+H+dt,S+D/2))}}i.length>0&&t.restore()}const qe={originX:tt,originY:et,ppm:L,snapDist:Ht},Te=e.rectangles[0]?.width??1,Se=e.rectangles[0]?.height??1,it=e.dieBounds,Gt=it?it.minX:$.length?Math.min(...$.map(o=>o.x)):0,Xt=it?it.minY:$.length?Math.min(...$.map(o=>o.y)):0,ze=it?it.maxX:$.length?Math.max(...$.map(o=>o.x)):1,Je=it?it.maxY:$.length?Math.max(...$.map(o=>o.y)):1,{cellW:ae,cellH:ce,nCols:At,nRows:re}=lo(ze-Gt,Je-Xt,Te*1.5,Se*1.5,$.length),Le=Array.from({length:At*re},()=>[]);for(let o=0;o<$.length;o++){const f=Math.floor(($[o].x-Gt)/ae),s=Math.floor(($[o].y-Xt)/ce),a=Number.isFinite(f)?Math.max(0,Math.min(At-1,f)):0,c=Number.isFinite(s)?Math.max(0,Math.min(re-1,s)):0;Le[c*At+a].push(o)}function ke(o,f,s){const a=Math.max(0,Math.floor((o-s-Gt)/ae)),c=Math.min(At-1,Math.floor((o+s-Gt)/ae)),h=Math.max(0,Math.floor((f-s-Xt)/ce)),d=Math.min(re-1,Math.floor((f+s-Xt)/ce)),i=[];for(let y=h;y<=d;y++)for(let l=a;l<=c;l++)for(const T of Le[y*At+l])i.push(T);return i}return{hitTarget:{getDieAtPoint(o,f){const s=(o-tt)/L,a=(et-f)/L,c=Math.max(Te,Se);for(const i of ke(s,a,c)){const y=e.rectangles[i];if(y&&Math.abs(s-y.x)<=y.width/2&&Math.abs(a-y.y)<=y.height/2)return e.dies[i]??null}let h=null,d=Ht*Ht;for(const i of ke(s,a,Ht)){const y=$[i].x-s,l=$[i].y-a,T=y*y+l*l;T<d&&(d=T,h=e.dies[i]??null)}return h}},viewport:qe,binLegendRows:ie,legendBox:z}}function mo(g,e,P,b,r,G,X,B,gt,Z,mt,ut,w){g.save(),g.font=go(),g.fillStyle=w.text,g.strokeStyle=w.axisLine,g.lineWidth=.5;const K=P-B+4,O=X+gt-4,q=Qe(mt),bt=_e(q,1,0),Ct=_e(q,0,1),nt=1e-9;function pt(p){return Z?Math.abs(p.y)<nt&&Math.abs(p.x)>nt?{pitch:Z.x,sign:Math.sign(p.x)}:Math.abs(p.x)<nt&&Math.abs(p.y)>nt?{pitch:Z.y,sign:Math.sign(p.y)}:null:null}const xt=pt(bt),U=pt(Ct);function W(p){return xt?Math.round(p*xt.sign/xt.pitch):p}function Y(p){return U?Math.round(p*U.sign/U.pitch):p}function Mt(p){if(!p)return zt(50/G);const A=50/(p*G);return Math.max(1,Math.round(A))*p}const Tt=xt?.pitch,St=U?.pitch,j=Mt(Tt),Q=Mt(St);g.textAlign="center",g.textBaseline="top";const _t=Math.ceil((X-b)/G/j)*j,Bt=(e-X-b)/G;for(let p=_t;p<=Bt;p+=j){const A=b+p*G;if(A<X||A>e-X)continue;g.beginPath(),g.moveTo(A,K-Ne),g.lineTo(A,K),g.stroke();const ht=Z?String(W(p)):We(p);g.fillText(ht,A,K+2)}g.textAlign="right",g.textBaseline="middle";const v=Math.ceil((r-(P-X))/G/Q)*Q,Pt=(r-X)/G;for(let p=v;p<=Pt;p+=Q){const A=r-p*G;if(A<X||A>P-X)continue;g.beginPath(),g.moveTo(O,A),g.lineTo(O+Ne,A),g.stroke();const ht=Z?String(Y(p)):We(p);g.fillText(ht,O-2,A)}g.restore()}function zt(g){const e=Math.pow(10,Math.floor(Math.log10(g))),P=g/e;return(P<1.5?1:P<3.5?2:P<7.5?5:10)*e}function uo(g,e,P,b,r,G,X){const B=[],gt=X;if(gt<1){const w=zt((e-g)*b/P);if(w>0){const K=Math.ceil(g/w)*w;for(let O=K;O<=e+w*1e-6;O+=w){if(O<=g||O>=e)continue;const q=(1-(Math.log10(O)-G)/X)*P;q>r&&q<P-r&&B.push(O)}}return B}const Z=gt<3?[1,2,5]:[1],mt=Math.floor(Math.log10(g)),ut=Math.ceil(Math.log10(e));for(let w=mt;w<=ut;w++)for(const K of Z){const O=K*Math.pow(10,w);if(O<=g||O>=e)continue;const q=(1-(Math.log10(O)-G)/X)*P;q>r&&q<P-r&&B.push(O)}return B}export{fmt,fmtColorbarAxis}from"../renderer/fmt.js";
|
|
1
|
+
import{fontPx as Ct}from"./toolbar.js";import{findTestDef as Ce,buildMapTitle as _e}from"../renderer/buildView.js";import{sortBinsForDisplay as ve}from"../stats/binPareto.js";import{affineInvert as to,affineVector as Be}from"../core/transforms.js";import{compareNatural as eo}from"../core/utils.js";import{resolveValueColorFn as oo}from"../renderer/colorSchemes.js";import{NO_DATA_FILL as no}from"../renderer/colorMap.js";import{SPEC_PASS_FILL as Pe,SPEC_FAIL_LOW as so,SPEC_FAIL_HIGH as De,contrastTextColor as We}from"../renderer/colorMap.js";import{fmt as Ie,fmtColorbarAxis as lo}from"../renderer/fmt.js";import{resolveCanvasTheme as io}from"./canvasTheme.js";import{hitGridDims as ao}from"./hitGrid.js";function Fe(g,e,P,b,r){g.moveTo(e,P+r*b),g.lineTo(e-b*.9,P-r*b*.6),g.lineTo(e+b*.9,P-r*b*.6),g.closePath()}const co=new Set(["value","stackedValues","stackedBins","stackedSoftBins"]),ro=new Set(["hardBin","softBin","metadata"]),J=()=>`${Ct(-2)}px system-ui, sans-serif`,Ne=3,Ut=2,fo=6,ho=20,go=()=>`600 ${Ct()}px system-ui, sans-serif`,Kt=()=>`${Ct(-1)}px system-ui, sans-serif`,mo=()=>`600 ${Ct(-1)}px system-ui, sans-serif`,qt=128,uo=()=>`${Ct(-2)}px system-ui, sans-serif`,Oe=4,D=17,H=11;export const BIN_LEGEND_W=110,BIN_LEGEND_W_COMPACT=64,BIN_LEGEND_ADAPT_COMPACT=280,BIN_LEGEND_ADAPT_FLOATING=180,BIN_LEGEND_MIN_CANVAS_W=150,BIN_LEGEND_MIN_CANVAS_H=120;const zt=28,gt=5,ft=8,Ee=15,He=12,Ye=6;export function toCanvas(g,e,P={}){return drawMapCanvas(g,e,P)}export function drawMapCanvas(g,e,P={}){const b=io(g.parentElement??g),{padding:r=16,showColorbar:G=!0,markFailingDies:X=!1,colorbarWidth:B=16,background:mt=b.background,legendPosition:Z="default",legendOffset:ut,showAxes:pt=!1,diePitchMm:w,viewport:K,activeBin:O,hoverBin:q,fallbackFormat:Tt,minRightReserve:_t,hbinDefs:nt,sbinDefs:xt,metadataFields:Mt,showTitle:U=!0}=P,W=Math.floor(g.clientWidth||g.width),Y=Math.floor(g.clientHeight||g.height),yt=W>=BIN_LEGEND_MIN_CANVAS_W&&Y>=BIN_LEGEND_MIN_CANVAS_H,St=G&&yt&&co.has(e.plotMode)&&e.passFailDisplay==="off",Lt=G&&yt&&ro.has(e.plotMode),j=G&&yt&&e.plotMode==="value"&&(e.passFailDisplay==="spec"&&e.specCounts!==void 0||e.passFailDisplay==="test"&&e.passFailCounts!==void 0),Q=Lt||j,Bt=Lt&&e.plotMode!=="metadata"&&e.binCounts?ve(e.binCounts.entries(),e.plotMode==="softBin"?e.binColors.pass.soft:e.binColors.pass.hard):[],Pt=Lt&&e.plotMode==="metadata"&&e.metadataCounts?[...e.metadataColorMap?.keys()??[...e.metadataCounts.keys()].sort(eo)].map(o=>[o,e.metadataCounts.get(o)??0]):[],v=[];if(j&&e.passFailDisplay==="test"){const o=e.passFailCounts;v.push({key:-1,color:Pe,label:"Pass",compactLabel:"Pass",count:o.pass,tooltip:`Pass \xB7 ${o.pass} dies`}),v.push({key:-2,color:De,label:"Fail",compactLabel:"Fail",count:o.fail,tooltip:`Fail \xB7 ${o.fail} dies`})}else if(j){const o=e.specCounts,f=Ce(e.testDefs,e.activeTest);v.push({key:-1,color:Pe,label:"Pass",compactLabel:"Pass",count:o.pass,tooltip:`Pass \xB7 ${o.pass} dies`}),f?.limitHigh!==void 0&&v.push({key:-2,color:De,label:"Fail high",compactLabel:"Fail hi",count:o.failHigh,tooltip:`Fail high \xB7 ${o.failHigh} dies`}),f?.limitLow!==void 0&&v.push({key:-3,color:so,label:"Fail low",compactLabel:"Fail lo",count:o.failLow,tooltip:`Fail low \xB7 ${o.failLow} dies`})}const Dt=j?v.length:e.plotMode==="metadata"?Pt.length:Bt.length,M=(g.ownerDocument.defaultView??window).devicePixelRatio??1;if(W<=0||Y<=0)return{hitTarget:{getDieAtPoint:()=>null},viewport:{originX:0,originY:0,ppm:1,snapDist:1},binLegendRows:[]};const k=Z!=="default"?Z:W<BIN_LEGEND_ADAPT_FLOATING?"floating":W<BIN_LEGEND_ADAPT_COMPACT?"compact":"default",ht=k==="default"||k==="compact",he=k==="left",Zt=k==="bottom",kt=k==="top",At=k==="floating",Wt=k==="compact"||k==="floating"?BIN_LEGEND_W_COMPACT:BIN_LEGEND_W,de=Math.floor((Y-2*r)/D),ge=Dt>de?de-1:Dt,me=Q&&Zt?ge*D:0,jt=Q&&kt?ge*D:0,Qt=e.plotMode==="stackedBins"||e.plotMode==="stackedSoftBins",vt=Ce(e.testDefs,e.activeTest),Ge=Qt?"Count":vt?.name??(e.activeTest!=null?`Test ${e.activeTest}`:void 0),Xe=Qt?void 0:vt?.unit,[It,Ft]=e.valueRange,{tickFmt:$e}=lo(Ft,Ge,Xe,Tt),Nt=e.allIntegerValues?o=>String(Math.round(o)):$e;let te=0;if(St){const o=g.getContext("2d");o.font=J();const f=[Nt(It),Nt(Ft)];It<0&&f.push(Nt(-Math.max(Math.abs(It),Math.abs(Ft))));for(const s of f)te=Math.max(te,o.measureText(s).width)}const ue=Math.max(ho,Math.ceil(te)+Ne+Ut+fo-r),ee=St?B+ue+8:Q&&ht?Wt:0,oe=Q&&he?Wt:0,ne=pt?32:0,Ot=pt?36:0,we=_t!=null?Math.max(ee,_t):ee,Ve=W-2*r-we-Ot-oe,pe=Y-2*r-ne-me-jt;g.width=Math.round(W*M),g.height=Math.round(Y*M);const t=g.getContext("2d");t.scale(M,M),t.fillStyle=mt,t.fillRect(0,0,W,Y);const $=e.hoverPoints;if(!$.length)return{hitTarget:{getDieAtPoint:()=>null},viewport:{originX:0,originY:0,ppm:1,snapDist:1},binLegendRows:[]};const Et=e.rectangles[0],se=Et?Et.width/2:0,le=Et?Et.height/2:0,Ht=e.dieBounds,xe=(Ht?.minX??0)-se,Ue=(Ht?.maxX??0)+se,Ke=(Ht?.minY??0)-le,Me=(Ht?.maxY??0)+le,ye=Ue-xe,be=Me-Ke;let tt,et,A;if(K)({originX:tt,originY:et,ppm:A}=K);else{const f=e.notchDir,s=f&&f.y>.1?13:0,a=f&&f.y<-.1?13:0,c=f&&f.x<-.1?13:0,h=f&&f.x>.1?13:0,d=Ve-c-h,i=pe-s-a;A=Math.min(d/ye,i/be),tt=r+Ot+oe+c+(d-ye*A)/2-xe*A,et=r+jt+s+(i-be*A)/2+Me*A}const Yt=K?.snapDist??Math.max(se,le,1)*1.5,Gt=tt+e.waferCenter.x*A,qe=et-e.waferCenter.y*A,ie=e.waferRadius*A,st=o=>{const f=Math.abs(o-qe);return f>=ie?0:Math.sqrt(ie*ie-f*f)},lt=(o,f,s,a,c,h,d=go(),i=b.text)=>{if(!o)return;t.save(),t.fillStyle=i,t.font=d,t.textAlign=a,t.textBaseline=c;const y=a==="right"?f-h:h-f;let l=o;if(y>8&&t.measureText(l).width>y){for(;l.length>1&&t.measureText(l+"\u2026").width>y;)l=l.slice(0,-1);l=l+"\u2026"}y>8&&t.fillText(l,f,s),t.restore()};t.save(),t.setTransform(A*M,0,0,-A*M,tt*M,et*M);const dt=1/A,ze=1/(A*M);if(e.rectangles.length>0){const o=new Map;for(const s of e.rectangles){const a=String(s.fill);let c=o.get(a);c||(c=[],o.set(a,c)),c.push(s)}for(const[s,a]of o){t.beginPath();for(const c of a)t.rect(c.x-c.width/2,c.y-c.height/2,c.width,c.height);t.fillStyle=s,t.fill()}t.strokeStyle="rgba(0,0,0,0.18)",t.lineWidth=.5*ze,t.beginPath();for(const s of e.rectangles)t.rect(s.x-s.width/2,s.y-s.height/2,s.width,s.height);if(t.stroke(),X){const s=e.rectangles.filter(a=>a.binFail);if(s.length>0){const a=new Map;for(const c of s){const h=We(String(c.fill));let d=a.get(h);d||(d=[],a.set(h,d)),d.push(c)}t.save(),t.lineCap="butt";for(const[c,h]of a){t.strokeStyle=c,t.globalAlpha=.55,t.lineWidth=Math.max(.6*dt,Math.min(h[0].width,h[0].height)*.1);for(const d of h){const i=d.width/2,y=d.height/2,l=Math.max(1.6*dt,Math.min(d.width,d.height)/3);t.save(),t.beginPath(),t.rect(d.x-i,d.y-y,d.width,d.height),t.clip(),t.beginPath();for(let T=-(i+y);T<=i+y;T+=l)t.moveTo(d.x-i+T,d.y-y),t.lineTo(d.x-i+T+d.height,d.y+y);t.stroke(),t.restore()}}t.restore()}}const f=e.rectangles.filter(s=>s.specMark);if(f.length>0){const s=new Map;for(const c of f){const h=We(String(c.fill)),d=`${c.specMark}|${h}`;let i=s.get(d);i||(i=[],s.set(d,i)),i.push(c)}const a=2.5*dt;t.lineJoin="round";for(const[c,h]of s){const[d,i]=c.split("|"),y=i==="#000000"?"#ffffff":"#000000",l=d==="failHigh"?1:-1,T=Math.min(h[0].width,h[0].height),I=Math.max(2.5*dt,T*.3);t.beginPath();for(const R of h)Fe(t,R.x,R.y,I,l);t.strokeStyle=y,t.lineWidth=a,t.stroke(),t.fillStyle=i,t.fill()}}}for(const o of e.overlays){t.beginPath();for(const f of o.points){for(let s=0;s<f.length;s++)s===0?t.moveTo(f[s].x,f[s].y):t.lineTo(f[s].x,f[s].y);o.closed&&t.closePath()}o.fill&&!o.fill.startsWith("rgba(0,0,0,0)")&&(t.fillStyle=o.fill,t.fill()),o.kind==="ring-boundary"||o.kind==="quadrant-boundary"||o.kind==="reticle"?(t.strokeStyle="rgba(0,0,0,0.45)",t.lineWidth=3*dt,t.stroke(),t.strokeStyle="rgba(255,255,255,0.8)",t.lineWidth=1*dt,t.stroke()):(t.strokeStyle=o.lineColor,t.lineWidth=o.lineWidth*dt,t.stroke())}if(t.restore(),e.notchDir){const o=tt+e.waferCenter.x*A,f=et-e.waferCenter.y*A,s=e.notchDir.x,a=-e.notchDir.y,c=e.waferRadius*A,h=4,d=9,i=5,y=o+s*(c+h),l=f+a*(c+h),T=y+s*d,I=l+a*d,R={x:-a,y:s},F=r+Ot+oe,E=W-r-ee,V=r+jt,at=Y-r-me-ne;t.save(),t.beginPath(),t.rect(F,V,E-F,at-V),t.clip(),t.beginPath(),t.moveTo(y,l),t.lineTo(T+R.x*i,I+R.y*i),t.lineTo(T-R.x*i,I-R.y*i),t.closePath(),t.fillStyle=b.text,t.fill(),t.restore()}t.save(),t.textAlign="center",t.textBaseline="middle";let Te=0;if(e.rectangles.length>0){let o=1;for(const h of e.texts)h.role!=="indicator"&&h.text.length>o&&(o=h.text.length);const f=e.rectangles[0].width*A,s=e.rectangles[0].height*A,a=Math.min(f,s),c=f/o;Te=Math.max(8,Math.min(64,Math.round(Math.min(a*.55,c*1.8))))}for(const o of e.texts){const f=tt+o.x*A,s=et-o.y*A;t.font=`${o.role==="indicator"?o.fontSize:Te}px system-ui, sans-serif`,t.fillStyle=o.color,t.fillText(o.text,f,s)}if(t.restore(),pt&&po(t,W,Y,tt,et,A,r,ne,Ot,w,e.gridToScreen,e.rotation,b),St){const o=oo(e.valueColorScheme,e.reverseValueScheme),f=ue,s=pe,a=Math.round(s*.75),c=r+Math.round((s-a)/2),h=W-r-B-f,d=It,i=Ft,y=i-d,l=e.plotMode==="stackedSoftBins"?xt:nt,{primary:T,secondary:I}=U?_e(e,Tt,l):{primary:"",secondary:""};if(U){const n=Math.max(c-6,r+11),m=Gt+Math.max(st(n),st(n-12))+8;lt(T,W-r,n,"right","bottom",m)}let R=c+a+4;const F=n=>Gt+Math.max(st(n),st(n+12))+8,E=e.logScale&&d>0?Math.log10(d):0,V=e.logScale&&i>0?Math.log10(i)-E:1,at=n=>e.logScale?(1-(Math.log10(n)-E)/V)*a:(1-(n-d)/y)*a;for(let n=0;n<qt;n++){const m=1-n/(qt-1),S=c+n/qt*a,p=a/qt+1;t.fillStyle=o(m),t.fillRect(h,S,B,p)}t.strokeStyle="rgba(0,0,0,0.25)",t.lineWidth=.5,t.strokeRect(h,c,B,a),t.fillStyle=b.text,t.font=J(),t.textAlign="left",t.strokeStyle="rgba(0,0,0,0.35)",t.lineWidth=.5;const L=Ne,N=36,ot=14,wt=e.logScale&&V>0?xo(d,i,a,N,ot,E,V):e.allIntegerValues?(()=>{const n=Math.max(1,Jt(y*N/a)),m=[],S=Math.ceil(d/n)*n;for(let p=S;p<=i+n*1e-6;p+=n){const u=(1-(p-d)/y)*a;u>ot&&u<a-ot&&m.push(Math.round(p))}return m})():(()=>{const n=y>0?Jt(y*N/a):0,m=[];if(n>0){const S=Math.ceil(d/n)*n;for(let p=S;p<=i+n*1e-6;p+=n){const u=(1-(p-d)/y)*a;u>ot&&u<a-ot&&m.push(p)}}return m})(),C=vt,_=Qt,x=Nt;t.textBaseline="middle";for(const n of wt){const m=c+at(n);t.beginPath(),t.moveTo(h+B,m),t.lineTo(h+B+L,m),t.stroke(),t.fillText(x(n),h+B+L+Ut,m)}if(t.beginPath(),t.moveTo(h+B,c),t.lineTo(h+B+L,c),t.stroke(),t.textBaseline="top",t.fillText(x(i),h+B+L+Ut,c),t.beginPath(),t.moveTo(h+B,c+a),t.lineTo(h+B+L,c+a),t.stroke(),t.textBaseline="bottom",t.fillText(x(d),h+B+L+Ut,c+a),!_&&C&&(C.limitLow!==void 0||C.limitHigh!==void 0)){const n=[],m=e.colorbarRangeMode==="spec";for(const[S,p]of[[C.limitLow,"LSL"],[C.limitHigh,"USL"]]){if(S===void 0||e.logScale&&S<=0)continue;const u=at(S);!m&&(u<-ot||u>a+ot)||n.push({value:S,label:p,py:Math.max(0,Math.min(a,u))})}if(n.length>0){t.save(),t.font=J(),t.textAlign="right",t.textBaseline="middle";for(const{py:S,label:p}of n){const u=c+S;m||(t.strokeStyle="rgba(255,255,255,0.85)",t.lineWidth=3,t.beginPath(),t.moveTo(h,u),t.lineTo(h+B,u),t.stroke(),t.strokeStyle="rgba(0,0,0,0.7)",t.lineWidth=1,t.beginPath(),t.moveTo(h,u),t.lineTo(h+B,u),t.stroke()),t.fillStyle=b.text,t.fillText(p,h-3,u);const ct=p==="USL"?-1:1,rt=4,bt=h-3-t.measureText(p).width-rt-4;t.beginPath(),Fe(t,bt,u,rt,ct),t.strokeStyle="#fff",t.lineWidth=2,t.lineJoin="round",t.stroke(),t.fillStyle=b.text,t.fill()}t.restore()}}if(!_){const n=e.logScale?"log\u2081\u2080":e.logScaleRequested?"linear \u2014 log n/a":null;n&&(t.save(),t.fillStyle=b.text,t.font=mo(),t.textAlign="right",t.textBaseline="top",t.fillText(n,W-r,R),t.restore(),R+=15)}U&&I&<(I,W-r,R,"right","top",F(R),Kt(),b.text)}const ae=[];let z;if(Q){const o=k==="compact",f=e.plotMode==="softBin"?xt:nt,s=f?new Map(f.map(l=>[l.bin,l])):null,a=e.plotMode==="softBin"?e.binColors.soft:e.binColors.hard,c=l=>a.get(l)??no,h=(l,T)=>{const I=t.measureText(l).width,R=o?0:t.measureText(String(T)).width,F=H+gt+I+(R?zt:0);return{labelWidth:I,countWidth:R,totalWidth:F}},d=Mt?.find(l=>l.key===e.activeMetadataKey),i=j?v.map(l=>{const T=o?l.compactLabel:l.label;return{key:l.key,color:l.color,count:l.count,label:T,tooltipLabel:l.tooltip,...h(T,l.count)}}):e.plotMode==="metadata"?Pt.map(([l,T])=>{const R=d?.values?.find(V=>V.value===l)?.label??l,F=o?l:R,E=e.metadataColorMap?.get(l)??"#d6d9dd";return{key:l,color:E,count:T,label:F,tooltipLabel:`${R} \xB7 ${T} dies`,...h(F,T)}}):Bt.map(([l,T])=>{const I=s?.get(l),R=I?.name?`${l} \xB7 ${I.name}`:`Bin ${l}`,F=o?String(l):R;return{key:l,color:c(l),count:T,label:F,tooltipLabel:`${R} \xB7 ${T} dies`,...h(F,T)}}),y=W-r*2;if(i.length>0){const l=At?ft*2+(U?Ee:0):U&&!kt?He+Ye:0,T=Math.max(1,Math.floor((Y-2*r-l)/D));let I=i.length,R=1,F=I*D,E=[],V=0;const at=Zt||kt;if(at){const C=Math.max(...i.map(x=>x.totalWidth)),_=Math.max(1,Math.min(i.length,Math.floor((y+8)/(C+8))));for(let x=_;x>=1;x--){const n=Math.ceil(i.length/x);if(n>T)continue;const m=new Array(x).fill(0);for(let p=0;p<i.length;p++){const u=p%x;m[u]=Math.max(m[u],i[p].totalWidth)}if(m.reduce((p,u)=>p+u,0)+(x-1)*8<=y||x===1){R=x,E=m,I=n,F=n*D;break}}}else I=Math.min(i.length,T),F=I*D,i.length>T&&(V=i.length-(T-1)),E=[Wt];let L,N;if(At){const C=Math.max(...i.map(u=>H+gt+t.measureText(u.label).width+zt)),_=Math.ceil(C);E=[_];const x=U?Ee:0,n=_+ft*2,m=F+x+ft*2,S=ut?.x??0,p=ut?.y??0;L=Math.min(Math.max(W-r-n+S,r),W-r-n),N=Math.min(Math.max(Y-r-m+p,r),Y-r-m),z={x:L,y:N,w:n,h:m},t.save(),t.globalAlpha=.92,t.fillStyle=b.surface,t.fillRect(L,N,n,m),t.globalAlpha=1,t.strokeStyle=b.axisLine,t.lineWidth=1,t.strokeRect(L,N,n,m),t.restore(),L+=ft,N+=ft+x}else Zt?(L=r,N=Y-r-F):kt?(L=r,N=r):he?(L=r+4,N=Math.max(r+Math.round((Y-2*r-F)/2),r+l)):(L=W-r-Wt+4,N=Math.max(r+Math.round((Y-2*r-F)/2),r+l));if(U){const C=e.plotMode==="softBin"?xt:nt,{primary:_,secondary:x}=_e(e,Tt,C),n=Ye,m=u=>Gt-Math.max(st(u),st(u-12))-8,S=u=>ht?W-r:m(u),p=At?z.y+z.h:N+F;if(kt){const u=p+n;lt(_,L,u,"left","top",Gt-Math.max(st(u),st(u+12))-8),x&<(x,L,u+16,"left","top",m(u+16),Kt(),b.text)}else if(At)lt(_,z.x+ft,z.y+ft,"left","top",z.x+z.w-ft),x&<(x,z.x,p+n,"left","top",z.x+z.w,Kt(),b.text);else{const u=Math.max(N-n,r+He);if(lt(_,L,u,"left","bottom",S(u)),x){const ct=p+n;lt(x,L,ct,"left","top",S(ct),Kt(),b.text)}}}t.save(),t.font=J();const ot=at?8:0,wt=(C,_)=>{if(t.measureText(C).width<=_)return C;let x=0,n=C.length;const m="\u2026",S=t.measureText(m).width;for(;x<n;){const p=x+n+1>>1;t.measureText(C.slice(0,p)).width+S<=_?x=p:n=p-1}return x===0?m:C.slice(0,x)+m};if(at){let C=0;for(let _=0;_<I;_++){let x=L;for(let n=0;n<R;n++){const m=i[C++];if(!m)break;const S=m.key===O,p=!S&&m.key===q,u=x,ct=x+H+gt,rt=N+_*D+D/2,bt=N+_*D+Math.round((D-H)/2),Vt=E[n]-H-gt-zt;p&&(t.fillStyle=b.hoverRow,t.fillRect(x,N+_*D,E[n],D)),t.fillStyle=m.color,t.fillRect(u,bt,H,H),t.strokeStyle=S?b.accent:"rgba(0,0,0,0.25)",t.lineWidth=S?2:.75,t.strokeRect(u,bt,H,H),t.fillStyle=S?b.accent:b.text,t.font=S?`bold ${J()}`:J(),t.textAlign="left",t.textBaseline="middle",t.fillText(wt(m.label,Vt),ct,rt),t.fillStyle=b.textMuted,t.font=J(),t.textAlign="right",t.fillText(String(m.count),x+E[n]-2,rt),ae.push({bin:m.key,x,y:N+_*D,w:E[n],h:D,label:m.tooltipLabel}),x+=E[n]+ot}}}else{const C=E[0],_=k!=="compact",x=C-H-gt-(_?zt:0),n=L+C-2;let m=i;V>0&&(m=i.slice(0,T-1));let S=N;for(const p of m){const u=p.key===O,ct=!u&&p.key===q,rt=L,bt=L+H+gt,Vt=S+D/2,Re=S+Math.round((D-H)/2),Qe=p.label;ct&&(t.fillStyle=b.hoverRow,t.fillRect(L-3,S,C+3,D)),t.fillStyle=p.color,t.fillRect(rt,Re,H,H),t.strokeStyle=u?b.accent:"rgba(0,0,0,0.25)",t.lineWidth=u?2:.75,t.strokeRect(rt,Re,H,H),t.fillStyle=u?b.accent:b.text,t.font=u?`bold ${J()}`:J(),t.textAlign="left",t.textBaseline="middle",t.fillText(wt(Qe,x),bt,Vt),(_||At)&&(t.fillStyle=b.textMuted,t.font=J(),t.textAlign="right",t.fillText(String(p.count),n,Vt)),ae.push({bin:p.key,x:L,y:S,w:C,h:D,label:p.tooltipLabel}),S+=D}V>0&&(t.fillStyle=b.textMuted,t.font=J(),t.textAlign="left",t.textBaseline="middle",t.fillText(`+ ${V} more`,L+H+gt,S+D/2))}}i.length>0&&t.restore()}const Je={originX:tt,originY:et,ppm:A,snapDist:Yt},Se=e.rectangles[0]?.width??1,Le=e.rectangles[0]?.height??1,it=e.dieBounds,Xt=it?it.minX:$.length?Math.min(...$.map(o=>o.x)):0,$t=it?it.minY:$.length?Math.min(...$.map(o=>o.y)):0,Ze=it?it.maxX:$.length?Math.max(...$.map(o=>o.x)):1,je=it?it.maxY:$.length?Math.max(...$.map(o=>o.y)):1,{cellW:ce,cellH:re,nCols:Rt,nRows:fe}=ao(Ze-Xt,je-$t,Se*1.5,Le*1.5,$.length),ke=Array.from({length:Rt*fe},()=>[]);for(let o=0;o<$.length;o++){const f=Math.floor(($[o].x-Xt)/ce),s=Math.floor(($[o].y-$t)/re),a=Number.isFinite(f)?Math.max(0,Math.min(Rt-1,f)):0,c=Number.isFinite(s)?Math.max(0,Math.min(fe-1,s)):0;ke[c*Rt+a].push(o)}function Ae(o,f,s){const a=Math.max(0,Math.floor((o-s-Xt)/ce)),c=Math.min(Rt-1,Math.floor((o+s-Xt)/ce)),h=Math.max(0,Math.floor((f-s-$t)/re)),d=Math.min(fe-1,Math.floor((f+s-$t)/re)),i=[];for(let y=h;y<=d;y++)for(let l=a;l<=c;l++)for(const T of ke[y*Rt+l])i.push(T);return i}return{hitTarget:{getDieAtPoint(o,f){const s=(o-tt)/A,a=(et-f)/A,c=Math.max(Se,Le);for(const i of Ae(s,a,c)){const y=e.rectangles[i];if(y&&Math.abs(s-y.x)<=y.width/2&&Math.abs(a-y.y)<=y.height/2)return e.dies[i]??null}let h=null,d=Yt*Yt;for(const i of Ae(s,a,Yt)){const y=$[i].x-s,l=$[i].y-a,T=y*y+l*l;T<d&&(d=T,h=e.dies[i]??null)}return h}},viewport:Je,binLegendRows:ae,legendBox:z}}function po(g,e,P,b,r,G,X,B,mt,Z,ut,pt,w){g.save(),g.font=uo(),g.fillStyle=w.text,g.strokeStyle=w.axisLine,g.lineWidth=.5;const K=P-B+4,O=X+mt-4,q=to(ut),Tt=Be(q,1,0),_t=Be(q,0,1),nt=1e-9;function xt(M){return Z?Math.abs(M.y)<nt&&Math.abs(M.x)>nt?{pitch:Z.x,sign:Math.sign(M.x)}:Math.abs(M.x)<nt&&Math.abs(M.y)>nt?{pitch:Z.y,sign:Math.sign(M.y)}:null:null}const Mt=xt(Tt),U=xt(_t);function W(M){return Mt?Math.round(M*Mt.sign/Mt.pitch):M}function Y(M){return U?Math.round(M*U.sign/U.pitch):M}function yt(M){if(!M)return Jt(50/G);const k=50/(M*G);return Math.max(1,Math.round(k))*M}const St=Mt?.pitch,Lt=U?.pitch,j=yt(St),Q=yt(Lt);g.textAlign="center",g.textBaseline="top";const Bt=Math.ceil((X-b)/G/j)*j,Pt=(e-X-b)/G;for(let M=Bt;M<=Pt;M+=j){const k=b+M*G;if(k<X||k>e-X)continue;g.beginPath(),g.moveTo(k,K-Oe),g.lineTo(k,K),g.stroke();const ht=Z?String(W(M)):Ie(M);g.fillText(ht,k,K+2)}g.textAlign="right",g.textBaseline="middle";const v=Math.ceil((r-(P-X))/G/Q)*Q,Dt=(r-X)/G;for(let M=v;M<=Dt;M+=Q){const k=r-M*G;if(k<X||k>P-X)continue;g.beginPath(),g.moveTo(O,k),g.lineTo(O+Oe,k),g.stroke();const ht=Z?String(Y(M)):Ie(M);g.fillText(ht,O-2,k)}g.restore()}function Jt(g){const e=Math.pow(10,Math.floor(Math.log10(g))),P=g/e;return(P<1.5?1:P<3.5?2:P<7.5?5:10)*e}function xo(g,e,P,b,r,G,X){const B=[],mt=X;if(mt<1){const w=Jt((e-g)*b/P);if(w>0){const K=Math.ceil(g/w)*w;for(let O=K;O<=e+w*1e-6;O+=w){if(O<=g||O>=e)continue;const q=(1-(Math.log10(O)-G)/X)*P;q>r&&q<P-r&&B.push(O)}}return B}const Z=mt<3?[1,2,5]:[1],ut=Math.floor(Math.log10(g)),pt=Math.ceil(Math.log10(e));for(let w=ut;w<=pt;w++)for(const K of Z){const O=K*Math.pow(10,w);if(O<=g||O>=e)continue;const q=(1-(Math.log10(O)-G)/X)*P;q>r&&q<P-r&&B.push(O)}return B}export{fmt,fmtColorbarAxis}from"../renderer/fmt.js";
|
|
@@ -320,6 +320,12 @@ export type SaveImageHandler = (blob: Blob, suggestedName: string) => void | Pro
|
|
|
320
320
|
* @param onSaveImage optional host hook; when present, bypasses `<a download>`
|
|
321
321
|
*/
|
|
322
322
|
export declare function saveImageBlob(blob: Blob, filename: string, onSaveImage?: SaveImageHandler): void;
|
|
323
|
+
/**
|
|
324
|
+
* The browser's default save: a `<a download>` click. The one copy, used when
|
|
325
|
+
* no host hook is supplied — by `saveImageBlob`, `saveTextFile`, and the
|
|
326
|
+
* export-naming wrappers in exportName.ts, which must fall back to it too.
|
|
327
|
+
*/
|
|
328
|
+
export declare function downloadBlob(blob: Blob, filename: string): void;
|
|
323
329
|
/**
|
|
324
330
|
* Host hook for saving a text file (CSV, etc). Mirrors `SaveImageHandler` —
|
|
325
331
|
* when provided, `saveTextFile` calls this instead of triggering a browser
|