@wafertools/wafermap 0.24.2 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +59 -0
- package/dist/packages/canvas-adapter/charts/barPanel.d.ts +5 -0
- package/dist/packages/canvas-adapter/charts/barPanel.js +1 -1
- package/dist/packages/canvas-adapter/charts/binCluster.d.ts +5 -0
- package/dist/packages/canvas-adapter/charts/binCluster.js +1 -1
- package/dist/packages/canvas-adapter/charts/boxplot.d.ts +5 -0
- package/dist/packages/canvas-adapter/charts/boxplot.js +1 -1
- package/dist/packages/canvas-adapter/charts/capability.d.ts +5 -0
- package/dist/packages/canvas-adapter/charts/capability.js +1 -1
- package/dist/packages/canvas-adapter/charts/chartShell.d.ts +24 -5
- package/dist/packages/canvas-adapter/charts/chartShell.js +1 -1
- package/dist/packages/canvas-adapter/charts/correlation.d.ts +5 -0
- package/dist/packages/canvas-adapter/charts/correlation.js +1 -1
- package/dist/packages/canvas-adapter/charts/histogram.d.ts +5 -0
- package/dist/packages/canvas-adapter/charts/histogram.js +1 -1
- package/dist/packages/canvas-adapter/charts/regionYieldDiagram.d.ts +5 -0
- package/dist/packages/canvas-adapter/charts/regionYieldDiagram.js +1 -1
- package/dist/packages/canvas-adapter/charts/scatter.d.ts +5 -0
- package/dist/packages/canvas-adapter/charts/scatter.js +1 -1
- package/dist/packages/canvas-adapter/dieList.d.ts +9 -0
- package/dist/packages/canvas-adapter/dieList.js +6 -6
- package/dist/packages/canvas-adapter/insightsTab.d.ts +5 -0
- package/dist/packages/canvas-adapter/insightsTab.js +1 -1
- package/dist/packages/canvas-adapter/metadataBadge.d.ts +4 -0
- package/dist/packages/canvas-adapter/metadataBadge.js +1 -1
- package/dist/packages/canvas-adapter/renderWaferGallery.d.ts +14 -1
- package/dist/packages/canvas-adapter/renderWaferGallery.js +7 -7
- package/dist/packages/canvas-adapter/renderWaferMap.d.ts +22 -0
- package/dist/packages/canvas-adapter/renderWaferMap.js +1 -1
- package/dist/packages/canvas-adapter/summaryPanel.d.ts +1 -1
- package/dist/packages/canvas-adapter/summaryPanel.js +3 -3
- package/dist/packages/canvas-adapter/toCanvas.d.ts +11 -0
- package/dist/packages/canvas-adapter/toCanvas.js +1 -1
- package/dist/packages/canvas-adapter/toolbar.d.ts +57 -8
- 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 +1 -1
- package/dist/packages/canvas-adapter/version.d.ts +2 -2
- package/dist/packages/canvas-adapter/version.js +1 -1
- package/dist/packages/canvas-adapter/warnings.d.ts +1 -1
- package/dist/packages/canvas-adapter/warnings.js +1 -1
- package/dist/packages/renderer/buildView.d.ts +22 -0
- package/dist/packages/renderer/buildView.js +1 -1
- package/dist/packages/stats/renderSummaryReport.js +1 -1
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
import{hasPosition as Ut}from"../core/dies.js";import{getReticleCell as Jt}from"../core/reticle.js";import{metadataCategoricalValue as Zt,metadataDisplayValue as te}from"../core/metadata.js";import{affineRotation as ft,affineMirror as Pt,affineCompose as at,affinePoint as X,affineVector as dt,affineSwapsAxes as ee}from"../core/transforms.js";import{contrastTextColor as Y,SPEC_PASS_FILL as ht,SPEC_FAIL_LOW as ne,SPEC_FAIL_HIGH as mt}from"./colorMap.js";import{getColorScheme as ae}from"./colorSchemes.js";import{getDieTestValue as R,getTestPassStatus as G,isParametricTest as pt}from"./buildWaferMap.js";import{fmt as yt,fmtColorbarAxis as gt,fmtAggregationMethod as Rt}from"./fmt.js";import{metadataValueColor as ie}from"./colorMap.js";import{compareNatural as se,clamp01 as Ct}from"../core/utils.js";import{prettyKey as Nt}from"../core/utils.js";export function resolveTestNumber(t,e){return e?.length?{testNumber:(findTestDef(e,t)??e[0]).testNumber}:{testNumber:t}}export function findTestDef(t,e){return t?.find(a=>a.testNumber===e)}export function getUniqueTestNumbers(t){return[...new Set(t.flatMap(e=>e.testValues?Object.keys(e.testValues).map(Number):[]))].sort((e,a)=>e-a)}const oe="#d3d6db",Ht="#e8e9ea",re="#eceef0",w="#d6d9dd";function it(t,e){return e?Zt(t.metadata?.[e]):void 0}export function classifySpec(t,e){return t===void 0?null:e?.limitLow!==void 0&&t<e.limitLow?"failLow":e?.limitHigh!==void 0&&t>e.limitHigh?"failHigh":"pass"}function le(t,e,a){const{x:i,y:s}=t.center,n=ft(t.orientation,i,s),o=at(Pt(e?.x??!1,e?.y??!1,i,s),ft(t.orientation,i,s)),r=at(Pt(a?.flipX??!1,a?.flipY??!1,i,s),ft(a?.rotation??0,i,s));return{bakedToScreen:r,physicalToScreen:at(r,n),gridToScreen:at(r,o)}}function E(t,e=!1){return{points:[t],closed:e}}function ce(t,e){const{center:a,radius:i,notch:s}=t;let n=a.x+i*Math.cos(e),o=a.y+i*Math.sin(e);if(!s)return{x:n,y:o};const r=Math.sqrt(i**2-(s.length/2)**2),u=s.length/2,y=n-a.x,p=o-a.y;return s.type==="bottom"&&p<-r?(o=a.y-r,n=a.x+Math.max(-u,Math.min(u,y))):s.type==="top"&&p>r?(o=a.y+r,n=a.x+Math.max(-u,Math.min(u,y))):s.type==="left"&&y<-r?(n=a.x-r,o=a.y+Math.max(-u,Math.min(u,p))):s.type==="right"&&y>r&&(n=a.x+r,o=a.y+Math.max(-u,Math.min(u,p))),{x:n,y:o}}function Ot(t,e){return t.map(e).join(" / ")}function ue(t,e=256){const a=Array.from({length:e},(i,s)=>t(s/(e-1)));return i=>a[Math.min(e-1,Math.max(0,Math.round(i*(e-1))))]}function fe(t,e){const a=Math.max(1,Math.min(t.width,t.height)),i=t.width/Math.max(e.length,1);return Math.max(8,Math.min(16,Math.round(Math.min(a*.55,i*1.8))))}function de(t,e,a){if(e?.length){const i=e.flatMap(s=>{const n=s.testNumber;if(!pt(s)){const u=G(t,n,s);return u===void 0?[]:[{key:n,label:s.name,value:u?"Pass":"Fail"}]}const o=R(t,n);if(o===void 0)return[];const r=t.testPass?.[n]===!1?" <i>(recorded fail)</i>":"";return[{key:n,label:s.name,value:`${yt(o,s.unit,a)}${r}`}]});if(i.length)return i}return t.testValues&&Object.keys(t.testValues).length>0?Object.entries(t.testValues).map(([i,s])=>({key:Number(i),label:`Test ${i}`,value:yt(s,void 0,a)})):t.testPass&&Object.keys(t.testPass).length>0?Object.entries(t.testPass).map(([i,s])=>({key:Number(i),label:`Test ${i}`,value:s?"Pass":"Fail"})):[]}export function buildHoverText(t,e,a={}){const{testDefs:i,hbinDefs:s,sbinDefs:n,fallbackFormat:o,aggrMethod:r,lotSize:u,waferMeta:y,activeTest:p,reticleConfig:B,metadataFields:D}=a,v=s?new Map(s.map(l=>[l.bin,l])):null,L=n?new Map(n.map(l=>[l.bin,l])):null,m=[`Die (${t.x}, ${t.y})`];if(B&&Ut(t)){const l=Jt(t,B);m.push(`Reticle (${l.column}, ${l.row})`)}if(e==="stackedValues"){const l=R(t,0);if(l!==void 0){const f=i?.[0],d=f?.testNumber,g=f?.name??(d!=null?`Test ${d}`:"Value"),$=r?` (${r})`:"";m.push(`${g}${$}: ${yt(l,f?.unit,o)}`)}}else if(e==="stackedBins"||e==="stackedSoftBins"){const l=R(t,0),f=e==="stackedSoftBins"?t.sbin:t.hbin;if(l!==void 0){const d=e==="stackedSoftBins"?L:v,g=f!==void 0?d?.get(f)?.name?`${f} \xB7 ${d.get(f).name}`:`Bin ${f}`:"Bin";let $;if(r==="percent")$=`${l.toFixed(0)}%`;else{const H=u?` (${(l/u*100).toFixed(0)}% of lot)`:"";$=`${l}${H}`}const x=r?` [${Rt(r)}]`:"";m.push(`${g}: ${$}${x}`)}}else{const l=de(t,i,o);if(e==="value"&&l.length){const{testNumber:f}=resolveTestNumber(p??0,i),d=findTestDef(i,f),g=R(t,f);let $=l.findIndex(S=>S.key===f);$<0&&($=0);const x=l[$];let H=`<b>${x.label}: ${x.value}</b>`;if(x.key===f&&d){const S=classifySpec(g,d);(S==="failLow"||S==="failHigh")&&(H+=" <i>(out of spec)</i>")}m.push(H);const _=l.length-1;_>0&&m.push(`<i>+${_} more test${_===1?"":"s"}</i>`)}else if(l.length){const f=l.length;m.push(`<i>${f} test result${f===1?"":"s"} recorded</i>`)}if(t.hbin!==void 0||t.sbin!==void 0){const f=[];if(t.hbin!==void 0){const d=v?.get(t.hbin)?.name,g=d?`${t.hbin} \xB7 ${d}`:String(t.hbin);f.push(`HBin: ${g}`)}if(t.sbin!==void 0){const d=L?.get(t.sbin)?.name,g=d?`${t.sbin} \xB7 ${d}`:String(t.sbin);f.push(`SBin: ${g}`)}m.push(f.join(" \xB7 "))}}t.retestCount!==void 0&&m.push(`Retests: ${t.retestCount}`),t.siteNum!==void 0&&m.push(`Site: ${t.siteNum}`),t.partId!==void 0&&m.push(`Part ID: ${t.partId}`),t.partial&&m.push("<i>partial die</i>"),t.probeIndex!==void 0&&m.push(`Probe: #${t.probeIndex}`);const M={...y??{},...t.metadata??{}};for(const[l,f]of Object.entries(M)){const d=te(f);if(d===void 0)continue;const g=D?.find($=>$.key===l)?.label??Nt(l);m.push(`${g}: ${d}`)}return m.join("<br>")}export function buildMapTitle(t,e="engineering",a){const i=t.isLotStack&&t.lotSize!==void 0?`stacked (${t.lotSize} ${t.lotSize===1?"wafer":"wafers"})`:"stacked",s=n=>{const o=a?.length===1?a[0]:void 0;return o===void 0?`${n} Bin`:o.name?`${n} Bin ${o.bin} \xB7 ${o.name}`:`${n} Bin ${o.bin}`};switch(t.plotMode){case"hardBin":return{primary:"Hard Bin",secondary:""};case"softBin":return{primary:"Soft Bin",secondary:""};case"stackedBins":return{primary:s("Hard"),secondary:i};case"stackedSoftBins":return{primary:s("Soft"),secondary:i};case"metadata":{const n=t.metadataFields?.find(r=>r.key===t.activeMetadataKey),o=t.activeMetadataKey?Nt(t.activeMetadataKey):"Metadata";return{primary:n?.label??o,secondary:""}}case"stackedValues":{const n=t.testDefs?.[0],o=t.valueRange[1]||t.valueRange[0]||0,{axisLabel:r}=gt(o,n?.name,n?.unit,e),u=r||"Value",y=t.aggrMethod?` \xB7 ${Rt(t.aggrMethod)}`:"";return{primary:`${u}${y}`,secondary:i}}default:{const n=findTestDef(t.testDefs,t.activeTest),o=t.valueRange[1]||t.valueRange[0]||0,{axisLabel:r}=gt(o,n?.name,n?.unit,e),u=r||n?.name;if(t.passFailDisplay!=="off"){const y=n?.testNumber??t.activeTest,p=u?`${u} \xB7 #${y}`:`Test ${y}`,B=t.passFailDisplay==="spec"?"Spec pass/fail":n!==void 0&&!pt(n)?"Functional pass/fail":"Tester pass/fail";return{primary:p,secondary:B}}return{primary:u??`Test ${t.activeTest}`,secondary:""}}}}export function generateTextOverlay(t,e,a){const{plotMode:i,colorFns:s,normalize:n,activeTest:o,valueRange:r,testDefs:u,fallbackFormat:y,passFailDisplay:p="off",activeMetadataKey:B,metadataColorMap:D}=a,v=findTestDef(u,o),{tickFmt:L}=gt(r[1],v?.name,v?.unit,y),{testNumber:m}=resolveTestNumber(o,u);return t.flatMap((M,l)=>{let f="",d="#111111";if(i==="value"&&p==="test"){const x=G(M,m,v);if(x===void 0)return[];f=x?"P":"F",d=Y(x?ht:mt)}else if(i==="value"){const x=R(M,m);if(x===void 0)return[];f=Ot([x],L),d=Y(s.forValue(n(x)))}else if(i==="hardBin"||i==="softBin"){const x=i==="softBin"?M.sbin:M.hbin;if(x===void 0)return[];f=String(x),d=Y(s.forBin(x))}else if(i==="metadata"){const x=it(M,B);if(x===void 0)return[];f=x,d=Y(D?.get(f)??w)}else{const x=R(M,0);if(x===void 0)return[];f=Ot([x],L),d=Y(s.forValue(n(x)))}const g=e?e[l*2]:M.physX,$=e?e[l*2+1]:M.physY;return[{x:g,y:$,text:f,fontSize:fe(M,f),color:d,align:"center"}]})}function At(t){return t==="top"?Math.PI/2:t==="bottom"?-Math.PI/2:t==="left"?Math.PI:0}function he(t,e,a=720){const{center:i,radius:s,notch:n}=t,o=m=>X(e,m.x,m.y);if(!(n!==void 0&&t.diameter>150)){const m=[];for(let M=0;M<=a;M++){const l=2*Math.PI*M/a;m.push(o(ce(t,l)))}return[{kind:"wafer-boundary",...E(m,!0),lineColor:"#888888",lineWidth:1}]}const u=1.25,y=n.length,p=At(n.type),B=Math.atan2(y,s),D=s-u,v=[];let L=!1;for(let m=0;m<=a;m++){const M=2*Math.PI*m/a;let l=M-p;for(;l>Math.PI;)l-=2*Math.PI;for(;l<-Math.PI;)l+=2*Math.PI;if(Math.abs(l)<=B){if(!L){L=!0;const f={x:i.x+s*Math.cos(p-B),y:i.y+s*Math.sin(p-B)},d={x:i.x+D*Math.cos(p),y:i.y+D*Math.sin(p)},g={x:i.x+s*Math.cos(p+B),y:i.y+s*Math.sin(p+B)};v.push(o(f),o(d),o(g))}continue}v.push(o({x:i.x+s*Math.cos(M),y:i.y+s*Math.sin(M)}))}return[{kind:"wafer-boundary",...E(v,!0),lineColor:"#888888",lineWidth:1}]}function me(t,e,a,i=360){const s=[],n=Math.max(1,Math.floor(a));for(let o=1;o<n;o++){const r=t.radius*o/n,u=[];for(let y=0;y<=i;y++){const p=2*Math.PI*y/i,B={x:t.center.x+r*Math.cos(p),y:t.center.y+r*Math.sin(p)};u.push(X(e,B.x,B.y))}s.push({kind:"ring-boundary",...E(u,!0),lineColor:"rgba(255,255,255,0.7)",lineWidth:1.5})}return s}function pe(t,e,a,i){const{x:s,y:n}=t.center,o=t.radius,r=(M,l)=>X(e,M,l),u=a-s,y=Math.sqrt(Math.max(0,o*o-u*u)),p=r(a,n-y),B=r(a,n+y),D=i-n,v=Math.sqrt(Math.max(0,o*o-D*D)),L=r(s-v,i),m=r(s+v,i);return[{kind:"quadrant-boundary",...E([p,B]),lineColor:"rgba(255,255,255,0.7)",lineWidth:1.5},{kind:"quadrant-boundary",...E([L,m]),lineColor:"rgba(255,255,255,0.7)",lineWidth:1.5}]}function ye(t,e){return t.map(a=>{const i=a.width/2,s=a.height/2;return{kind:"reticle",points:[[[a.x-i,a.y-s],[a.x+i,a.y-s],[a.x+i,a.y+s],[a.x-i,a.y+s]].map(([o,r])=>X(e,o,r))],closed:!0,lineColor:"rgba(255,255,255,0.7)",lineWidth:1.5,fill:"rgba(0,0,0,0)"}})}function ge(t){const e=t.filter(a=>a.probeIndex!==void 0).sort((a,i)=>(a.probeIndex??0)-(i.probeIndex??0));return e.length?[{kind:"probe-path",...E(e.map(a=>({x:a.physX,y:a.physY}))),lineColor:"rgba(220,80,0,0.55)",lineWidth:1}]:[]}function xe(t,e,a,i,s,n,o,r,u,y,p,B,D,v="off",L,m,M){const l=e.width-o,f=e.height-o,d=n?f:l,g=n?l:f,$=S=>s==="softBin"?S.sbin:S.hbin,x=S=>it(S,L);if(e.partial){t.push({x:a,y:i,width:d,height:g,fill:oe,type:"stacked",metadata:e.metadata});return}if(e.edgeExcluded){t.push({x:a,y:i,width:d,height:g,fill:re,type:"stacked",metadata:e.metadata});return}if(u!==void 0&&(s==="hardBin"||s==="softBin")&&$(e)!==u){t.push({x:a,y:i,width:d,height:g,fill:Ht,type:"hardBin",metadata:e.metadata});return}if(M!==void 0&&s==="metadata"&&x(e)!==M){t.push({x:a,y:i,width:d,height:g,fill:Ht,type:"metadata",metadata:e.metadata});return}if(s==="value"){if(v==="test"){const U=G(e,p,D),st=U===void 0?w:U?ht:mt;t.push({x:a,y:i,width:d,height:g,fill:st,type:"value",metadata:e.metadata});return}const S=R(e,p),F=classifySpec(S,D);let W,Q;S===void 0?W=w:v==="spec"?W=F==="failLow"?ne:F==="failHigh"?mt:ht:(W=r.forValue(y(S)),(F==="failLow"||F==="failHigh")&&(Q=F)),t.push({x:a,y:i,width:d,height:g,fill:W,type:"value",specMark:Q,metadata:e.metadata});return}if(s==="hardBin"||s==="softBin"){const S=$(e),F=S!=null?r.forBin(S):w;t.push({x:a,y:i,width:d,height:g,fill:F,type:s,metadata:e.metadata});return}if(s==="metadata"){const S=x(e),F=S!==void 0?m?.get(S)??w:w;t.push({x:a,y:i,width:d,height:g,fill:F,type:"metadata",metadata:e.metadata});return}const H=R(e,0),_=H!==void 0?r.forValue(y(H)):w;t.push({x:a,y:i,width:d,height:g,fill:_,type:"value",metadata:e.metadata})}function be(t,e,a){const i=t.radius*.15,s=dt(e,i,0),n=dt(e,0,i),o=s.x+n.x>=0?-1:1,r=s.y+n.y>=0?-1:1,u={x:t.center.x+o*t.radius*.9,y:t.center.y+r*t.radius*.9},y={x:u.x+s.x,y:u.y+s.y},p={x:u.x+n.x,y:u.y+n.y};return a.push({x:y.x+s.x*.35,y:y.y+s.y*.35,text:"+X",fontSize:10,color:"#cc3300",align:"center",role:"indicator"},{x:p.x+n.x*.35,y:p.y+n.y*.35,text:"+Y",fontSize:10,color:"#0044cc",align:"center",role:"indicator"}),[{kind:"xy-indicator",...E([u,y]),lineColor:"#cc3300",lineWidth:2},{kind:"xy-indicator",...E([u,p]),lineColor:"#0044cc",lineWidth:2}]}export function buildView(t,e,a={},i){const s=a.reticles??[],{plotMode:n="value",showDieLabels:o=!1,showReticle:r=!1,showProbePath:u=!1,ringCount:y=4,showRingBoundaries:p=!1,showQuadrantBoundaries:B=!1,showXYIndicator:D=!1,dieGap:v=1,colorScheme:L="default",highlightBin:m,highlightMetadataValue:M,interactiveTransform:l,valueRange:f,testDefs:d,activeTest:g=0,activeMetadataKey:$,fallbackFormat:x="engineering",aggregationMethod:H,lotSize:_,dataAxisFlip:S,isLotStack:F=!1,logScale:W,colorbarRangeMode:Q="spec",passFailDisplay:U,showPartialDies:st=!0}=a,xt=U??"off",bt=i?.hbinDefs,Mt=i?.sbinDefs,St=i?.metadataFields,Et=St?.find(c=>c.key===$),_t={x:(S?.x??!1)!==(l?.flipX??!1),y:(S?.y??!1)!==(l?.flipY??!1)},wt=bt?new Map(bt.map(c=>[c.bin,c])):null,Wt=Mt?new Map(Mt.map(c=>[c.bin,c])):null,ot=n==="softBin"?Wt:wt,rt=ae(L),$t={forValue:ue(rt.forValue),forBin:L==="custom"&&ot?c=>ot.get(c)?.color??rt.forBin(c):rt.forBin};let{testNumber:O}=resolveTestNumber(g,d);if(!d?.length&&n==="value"&&!e.some(h=>h.testValues&&O in h.testValues)){const h=e.reduce((b,I)=>{if(!I.testValues)return b;const k=Object.keys(I.testValues).map(Number),K=k.length?Math.min(...k):void 0;return K!==void 0&&(b===void 0||K<b)?K:b},void 0);h!==void 0&&(O=h)}let J;if(Array.isArray(f))J=f;else if(f){const{testNumber:c}=resolveTestNumber(f.test,d);J=c===O?f.range:void 0}const T=findTestDef(d,O),kt=n==="value"&&T!==void 0&&!pt(T),jt=T!==void 0&&(T.limitLow!==void 0||T.limitHigh!==void 0);let C="off";n==="value"&&(kt?C="test":xt==="spec"&&jt?C="spec":xt==="test"&&e.some(c=>G(c,O,T)!==void 0)&&(C="test"));const Bt=C==="spec"?"spec":Q;let P,N,vt=!1;if(J)[P,N]=J;else{const c=n==="stackedValues"||n==="stackedBins"||n==="stackedSoftBins",h=!c&&n==="value"&&Bt==="spec"&&T&&(T.limitLow!==void 0||T.limitHigh!==void 0);let b=1/0,I=-1/0,k=!0;for(const K of e){const q=c?R(K,0):R(K,O);q!==void 0&&(q<b&&(b=q),q>I&&(I=q),Number.isInteger(q)||(k=!1))}isFinite(b)||(k=!1),vt=k,h?(P=T.limitLow!==void 0?T.limitLow:isFinite(b)?b:0,N=T.limitHigh!==void 0?T.limitHigh:isFinite(I)?I:1):(P=isFinite(b)?b:0,N=isFinite(I)?I:1)}P===N&&(N=P+1);const Tt=kt?!1:W??T?.logScale??!1,It=Tt&&P>0&&N>0,zt=It;let Z;if(It){const c=Math.log10(P),h=Math.log10(N)-c;Z=b=>b<=0?0:Ct((Math.log10(b)-c)/h)}else Z=c=>Ct((c-P)/(N-P));const V=le(t,S,l);let Lt=null;if(t.notch){const c=At(t.notch.type),h=dt(V.physicalToScreen,Math.cos(c)*t.radius,Math.sin(c)*t.radius),b=Math.hypot(h.x,h.y);b>0&&(Lt={x:h.x/b,y:h.y/b})}let j=1/0;for(let c=0;c<e.length;c++){const h=e[c];h.width<j&&(j=h.width),h.height<j&&(j=h.height)}const Kt=j!==1/0?Math.min(v,j*.12):v,Vt=[],lt=[],qt=V.bakedToScreen.a===1&&V.bakedToScreen.b===0&&V.bakedToScreen.c===0&&V.bakedToScreen.d===1&&V.bakedToScreen.e===0&&V.bakedToScreen.f===0;let A=null;if(!qt){A=new Float64Array(e.length*2);for(let c=0;c<e.length;c++){const h=X(V.bakedToScreen,e[c].physX,e[c].physY);A[c*2]=h.x,A[c*2+1]=h.y}}const Xt=ee(V.gridToScreen),Yt=n==="hardBin"||n==="softBin"||n==="stackedBins"||n==="stackedSoftBins",Gt=n==="softBin"||n==="stackedSoftBins";let tt=Yt?new Map:void 0;const ct=n==="value"&&C==="spec"?{pass:0,failHigh:0,failLow:0}:void 0,ut=n==="value"&&C==="test"?{pass:0,fail:0}:void 0,Dt=n==="metadata";let et=Dt?new Map:void 0,nt=null;if(Dt&&$){const c=new Set;for(const b of e){if(b.partial||b.edgeExcluded)continue;const I=it(b,$);I!==void 0&&c.add(I)}const h=[...c].sort(se);nt=new Map(h.map((b,I)=>[b,Et?.values?.find(k=>k.value===b)?.color??ie(I)]))}for(let c=0;c<e.length;c++){const h=e[c],b=A?A[c*2]:h.physX,I=A?A[c*2+1]:h.physY;if(lt.push({x:b,y:I}),tt&&!h.partial&&!h.edgeExcluded){const k=Gt?h.sbin:h.hbin;k!=null&&tt.set(k,(tt.get(k)??0)+1)}if(ct&&!h.partial&&!h.edgeExcluded){const k=classifySpec(R(h,O),T);k&&ct[k]++}if(ut&&!h.partial&&!h.edgeExcluded){const k=G(h,O,T);k!==void 0&&ut[k?"pass":"fail"]++}if(et&&!h.partial&&!h.edgeExcluded){const k=it(h,$);k!==void 0&&et.set(k,(et.get(k)??0)+1)}h.partial&&!st||xe(Vt,h,b,I,n,Xt,Kt,$t,m,Z,O,ot,T,C,$,nt,M)}const Ft=o?generateTextOverlay(e,A,{plotMode:n,colorFns:$t,normalize:Z,activeTest:g,valueRange:[P,N],testDefs:d,fallbackFormat:x,passFailDisplay:C,activeMetadataKey:$,metadataColorMap:nt}):[],z=he(t,V.physicalToScreen);p&&z.push(...me(t,V.physicalToScreen,y)),B&&z.push(...pe(t,V.physicalToScreen,t.center.x,t.center.y)),r&&z.push(...ye(s,V.gridToScreen)),u&&z.push(...ge(e)),D&&z.push(...be(t,V.gridToScreen,Ft));const Qt=lt.length>0?{minX:t.center.x-t.radius,maxX:t.center.x+t.radius,minY:t.center.y-t.radius,maxY:t.center.y+t.radius}:null;return{rectangles:Vt,hoverPoints:lt,texts:Ft,overlays:z,plotMode:n,colorScheme:L,metadata:t.metadata??null,dies:e,valueRange:[P,N],allIntegerValues:vt,testDefs:d,activeTest:g,logScale:zt,logScaleRequested:Tt,aggrMethod:H,lotSize:_,axisFlip:_t,dataAxisFlip:{x:S?.x??!1,y:S?.y??!1},gridToScreen:V.gridToScreen,rotation:((t.orientation+(l?.rotation??0))%360+360)%360,hasReticle:s.length>0,isLotStack:F,passFailDisplay:C,colorBySpec:C==="spec",colorbarRangeMode:Bt,waferCenter:t.center,waferRadius:t.radius,notchDir:Lt,binCounts:tt,metadataCounts:et,metadataColorMap:nt,activeMetadataKey:$,metadataFields:St,specCounts:ct,passFailCounts:ut,dieBounds:Qt}}export{getDieKey}from"../core/dies.js";
|
|
1
|
+
import{hasPosition as Zt}from"../core/dies.js";import{getReticleCell as te}from"../core/reticle.js";import{metadataCategoricalValue as ee,metadataDisplayValue as ne}from"../core/metadata.js";import{affineRotation as dt,affineMirror as Rt,affineCompose as it,affinePoint as Y,affineVector as ht,affineSwapsAxes as ae}from"../core/transforms.js";import{contrastTextColor as G,SPEC_PASS_FILL as pt,SPEC_FAIL_LOW as ie,SPEC_FAIL_HIGH as mt}from"./colorMap.js";import{getColorScheme as se}from"./colorSchemes.js";import{getDieTestValue as R,getTestPassStatus as Q,isParametricTest as yt}from"./buildWaferMap.js";import{fmt as gt,fmtColorbarAxis as xt,fmtAggregationMethod as Ct}from"./fmt.js";import{metadataValueColor as oe}from"./colorMap.js";import{compareNatural as re,clamp01 as Nt}from"../core/utils.js";import{prettyKey as Ht}from"../core/utils.js";export function resolveTestNumber(t,e){return e?.length?{testNumber:(findTestDef(e,t)??e[0]).testNumber}:{testNumber:t}}export function findTestDef(t,e){return t?.find(a=>a.testNumber===e)}export function getUniqueTestNumbers(t){return[...new Set(t.flatMap(e=>e.testValues?Object.keys(e.testValues).map(Number):[]))].sort((e,a)=>e-a)}const le="#d3d6db",Ot="#e8e9ea",ce="#eceef0",j="#d6d9dd";function st(t,e){return e?ee(t.metadata?.[e]):void 0}export function classifySpec(t,e){return t===void 0?null:e?.limitLow!==void 0&&t<e.limitLow?"failLow":e?.limitHigh!==void 0&&t>e.limitHigh?"failHigh":"pass"}function ue(t,e,a){const{x:i,y:s}=t.center,n=dt(t.orientation,i,s),o=it(Rt(e?.x??!1,e?.y??!1,i,s),dt(t.orientation,i,s)),r=it(Rt(a?.flipX??!1,a?.flipY??!1,i,s),dt(a?.rotation??0,i,s));return{bakedToScreen:r,physicalToScreen:it(r,n),gridToScreen:it(r,o)}}function W(t,e=!1){return{points:[t],closed:e}}function fe(t,e){const{center:a,radius:i,notch:s}=t;let n=a.x+i*Math.cos(e),o=a.y+i*Math.sin(e);if(!s)return{x:n,y:o};const r=Math.sqrt(i**2-(s.length/2)**2),u=s.length/2,x=n-a.x,y=o-a.y;return s.type==="bottom"&&y<-r?(o=a.y-r,n=a.x+Math.max(-u,Math.min(u,x))):s.type==="top"&&y>r?(o=a.y+r,n=a.x+Math.max(-u,Math.min(u,x))):s.type==="left"&&x<-r?(n=a.x-r,o=a.y+Math.max(-u,Math.min(u,y))):s.type==="right"&&x>r&&(n=a.x+r,o=a.y+Math.max(-u,Math.min(u,y))),{x:n,y:o}}function At(t,e){return t.map(e).join(" / ")}function de(t,e=256){const a=Array.from({length:e},(i,s)=>t(s/(e-1)));return i=>a[Math.min(e-1,Math.max(0,Math.round(i*(e-1))))]}function he(t,e){const a=Math.max(1,Math.min(t.width,t.height)),i=t.width/Math.max(e.length,1);return Math.max(8,Math.min(16,Math.round(Math.min(a*.55,i*1.8))))}function pe(t,e,a){if(e?.length){const i=e.flatMap(s=>{const n=s.testNumber;if(!yt(s)){const u=Q(t,n,s);return u===void 0?[]:[{key:n,label:s.name,value:u?"Pass":"Fail"}]}const o=R(t,n);if(o===void 0)return[];const r=t.testPass?.[n]===!1?" <i>(recorded fail)</i>":"";return[{key:n,label:s.name,value:`${gt(o,s.unit,a)}${r}`}]});if(i.length)return i}return t.testValues&&Object.keys(t.testValues).length>0?Object.entries(t.testValues).map(([i,s])=>({key:Number(i),label:`Test ${i}`,value:gt(s,void 0,a)})):t.testPass&&Object.keys(t.testPass).length>0?Object.entries(t.testPass).map(([i,s])=>({key:Number(i),label:`Test ${i}`,value:s?"Pass":"Fail"})):[]}export function buildHoverText(t,e,a={}){const{testDefs:i,hbinDefs:s,sbinDefs:n,fallbackFormat:o,aggrMethod:r,lotSize:u,waferMeta:x,activeTest:y,reticleConfig:B,metadataFields:V}=a,v=s?new Map(s.map(c=>[c.bin,c])):null,T=n?new Map(n.map(c=>[c.bin,c])):null,m=[`Die (${t.x}, ${t.y})`];if(B&&Zt(t)){const c=te(t,B);m.push(`Reticle (${c.column}, ${c.row})`)}if(e==="stackedValues"){const c=R(t,0);if(c!==void 0){const f=i?.[0],h=f?.testNumber,g=f?.name??(h!=null?`Test ${h}`:"Value"),M=r?` (${r})`:"";m.push(`${g}${M}: ${gt(c,f?.unit,o)}`)}}else if(e==="stackedBins"||e==="stackedSoftBins"){const c=R(t,0),f=e==="stackedSoftBins"?t.sbin:t.hbin;if(c!==void 0){const h=e==="stackedSoftBins"?T:v,g=f!==void 0?h?.get(f)?.name?`${f} \xB7 ${h.get(f).name}`:`Bin ${f}`:"Bin";let M;if(r==="percent")M=`${c.toFixed(0)}%`;else{const H=u?` (${(c/u*100).toFixed(0)}% of lot)`:"";M=`${c}${H}`}const p=r?` [${Ct(r)}]`:"";m.push(`${g}: ${M}${p}`)}}else{const c=pe(t,i,o);if(e==="value"&&c.length){const{testNumber:f}=resolveTestNumber(y??0,i),h=findTestDef(i,f),g=R(t,f);let M=c.findIndex(E=>E.key===f);M<0&&(M=0);const p=c[M];let H=`<b>${p.label}: ${p.value}</b>`;if(p.key===f&&h){const E=classifySpec(g,h);(E==="failLow"||E==="failHigh")&&(H+=" <i>(out of spec)</i>")}m.push(H);const A=c.length-1;A>0&&m.push(`<i>+${A} more test${A===1?"":"s"}</i>`)}else if(c.length){const f=c.length;m.push(`<i>${f} test result${f===1?"":"s"} recorded</i>`)}if(t.hbin!==void 0||t.sbin!==void 0){const f=[];if(t.hbin!==void 0){const h=v?.get(t.hbin)?.name,g=h?`${t.hbin} \xB7 ${h}`:String(t.hbin);f.push(`HBin: ${g}`)}if(t.sbin!==void 0){const h=T?.get(t.sbin)?.name,g=h?`${t.sbin} \xB7 ${h}`:String(t.sbin);f.push(`SBin: ${g}`)}m.push(f.join(" \xB7 "))}}t.retestCount!==void 0&&m.push(`Retests: ${t.retestCount}`),t.siteNum!==void 0&&m.push(`Site: ${t.siteNum}`),t.partId!==void 0&&m.push(`Part ID: ${t.partId}`),t.partial&&m.push("<i>partial die</i>"),t.probeIndex!==void 0&&m.push(`Probe: #${t.probeIndex}`);const S={...x??{},...t.metadata??{}};for(const[c,f]of Object.entries(S)){const h=ne(f);if(h===void 0)continue;const g=V?.find(M=>M.key===c)?.label??Ht(c);m.push(`${g}: ${h}`)}return m.join("<br>")}export function buildMapTitle(t,e="engineering",a){const i=t.isLotStack&&t.lotSize!==void 0?`stacked (${t.lotSize} ${t.lotSize===1?"wafer":"wafers"})`:"stacked",s=n=>{const o=a?.length===1?a[0]:void 0;return o===void 0?`${n} Bin`:o.name?`${n} Bin ${o.bin} \xB7 ${o.name}`:`${n} Bin ${o.bin}`};switch(t.plotMode){case"hardBin":return{primary:"Hard Bin",secondary:""};case"softBin":return{primary:"Soft Bin",secondary:""};case"stackedBins":return{primary:s("Hard"),secondary:i};case"stackedSoftBins":return{primary:s("Soft"),secondary:i};case"metadata":{const n=t.metadataFields?.find(r=>r.key===t.activeMetadataKey),o=t.activeMetadataKey?Ht(t.activeMetadataKey):"Metadata";return{primary:n?.label??o,secondary:""}}case"stackedValues":{const n=t.testDefs?.[0],o=t.valueRange[1]||t.valueRange[0]||0,{axisLabel:r}=xt(o,n?.name,n?.unit,e),u=r||"Value",x=t.aggrMethod?` \xB7 ${Ct(t.aggrMethod)}`:"";return{primary:`${u}${x}`,secondary:i}}default:{const n=findTestDef(t.testDefs,t.activeTest),o=t.valueRange[1]||t.valueRange[0]||0,{axisLabel:r}=xt(o,n?.name,n?.unit,e),u=r||n?.name;if(t.passFailDisplay!=="off"){const x=n?.testNumber??t.activeTest,y=u?`${u} \xB7 #${x}`:`Test ${x}`,B=t.passFailDisplay==="spec"?"Spec pass/fail":n!==void 0&&!yt(n)?"Functional pass/fail":"Tester pass/fail";return{primary:y,secondary:B}}return{primary:u??`Test ${t.activeTest}`,secondary:""}}}}export function generateTextOverlay(t,e,a){const{plotMode:i,colorFns:s,normalize:n,activeTest:o,valueRange:r,testDefs:u,fallbackFormat:x,passFailDisplay:y="off",activeMetadataKey:B,metadataColorMap:V}=a,v=findTestDef(u,o),{tickFmt:T}=xt(r[1],v?.name,v?.unit,x),{testNumber:m}=resolveTestNumber(o,u);return t.flatMap((S,c)=>{let f="",h="#111111";if(i==="value"&&y==="test"){const p=Q(S,m,v);if(p===void 0)return[];f=p?"P":"F",h=G(p?pt:mt)}else if(i==="value"){const p=R(S,m);if(p===void 0)return[];f=At([p],T),h=G(s.forValue(n(p)))}else if(i==="hardBin"||i==="softBin"){const p=i==="softBin"?S.sbin:S.hbin;if(p===void 0)return[];f=String(p),h=G(s.forBin(p))}else if(i==="metadata"){const p=st(S,B);if(p===void 0)return[];f=p,h=G(V?.get(f)??j)}else{const p=R(S,0);if(p===void 0)return[];f=At([p],T),h=G(s.forValue(n(p)))}const g=e?e[c*2]:S.physX,M=e?e[c*2+1]:S.physY;return[{x:g,y:M,text:f,fontSize:he(S,f),color:h,align:"center"}]})}function Et(t){return t==="top"?Math.PI/2:t==="bottom"?-Math.PI/2:t==="left"?Math.PI:0}function me(t,e,a=720){const{center:i,radius:s,notch:n}=t,o=m=>Y(e,m.x,m.y);if(!(n!==void 0&&t.diameter>150)){const m=[];for(let S=0;S<=a;S++){const c=2*Math.PI*S/a;m.push(o(fe(t,c)))}return[{kind:"wafer-boundary",...W(m,!0),lineColor:"#888888",lineWidth:1}]}const u=1.25,x=n.length,y=Et(n.type),B=Math.atan2(x,s),V=s-u,v=[];let T=!1;for(let m=0;m<=a;m++){const S=2*Math.PI*m/a;let c=S-y;for(;c>Math.PI;)c-=2*Math.PI;for(;c<-Math.PI;)c+=2*Math.PI;if(Math.abs(c)<=B){if(!T){T=!0;const f={x:i.x+s*Math.cos(y-B),y:i.y+s*Math.sin(y-B)},h={x:i.x+V*Math.cos(y),y:i.y+V*Math.sin(y)},g={x:i.x+s*Math.cos(y+B),y:i.y+s*Math.sin(y+B)};v.push(o(f),o(h),o(g))}continue}v.push(o({x:i.x+s*Math.cos(S),y:i.y+s*Math.sin(S)}))}return[{kind:"wafer-boundary",...W(v,!0),lineColor:"#888888",lineWidth:1}]}function ye(t,e,a,i=360){const s=[],n=Math.max(1,Math.floor(a));for(let o=1;o<n;o++){const r=t.radius*o/n,u=[];for(let x=0;x<=i;x++){const y=2*Math.PI*x/i,B={x:t.center.x+r*Math.cos(y),y:t.center.y+r*Math.sin(y)};u.push(Y(e,B.x,B.y))}s.push({kind:"ring-boundary",...W(u,!0),lineColor:"rgba(255,255,255,0.7)",lineWidth:1.5})}return s}function ge(t,e,a,i){const{x:s,y:n}=t.center,o=t.radius,r=(S,c)=>Y(e,S,c),u=a-s,x=Math.sqrt(Math.max(0,o*o-u*u)),y=r(a,n-x),B=r(a,n+x),V=i-n,v=Math.sqrt(Math.max(0,o*o-V*V)),T=r(s-v,i),m=r(s+v,i);return[{kind:"quadrant-boundary",...W([y,B]),lineColor:"rgba(255,255,255,0.7)",lineWidth:1.5},{kind:"quadrant-boundary",...W([T,m]),lineColor:"rgba(255,255,255,0.7)",lineWidth:1.5}]}function xe(t,e){return t.map(a=>{const i=a.width/2,s=a.height/2;return{kind:"reticle",points:[[[a.x-i,a.y-s],[a.x+i,a.y-s],[a.x+i,a.y+s],[a.x-i,a.y+s]].map(([o,r])=>Y(e,o,r))],closed:!0,lineColor:"rgba(255,255,255,0.7)",lineWidth:1.5,fill:"rgba(0,0,0,0)"}})}function be(t){const e=t.filter(a=>a.probeIndex!==void 0).sort((a,i)=>(a.probeIndex??0)-(i.probeIndex??0));return e.length?[{kind:"probe-path",...W(e.map(a=>({x:a.physX,y:a.physY}))),lineColor:"rgba(220,80,0,0.55)",lineWidth:1}]:[]}function Me(t,e,a,i,s,n,o,r,u,x,y,B,V,v,T="off",m,S,c){const f=e.width-o,h=e.height-o,g=n?h:f,M=n?f:h,p=$=>s==="softBin"?$.sbin:$.hbin,H=$=>st($,m);if(e.partial){t.push({x:a,y:i,width:g,height:M,fill:le,type:"stacked",metadata:e.metadata});return}if(e.edgeExcluded){t.push({x:a,y:i,width:g,height:M,fill:ce,type:"stacked",metadata:e.metadata});return}if(u!==void 0&&(s==="hardBin"||s==="softBin")&&p(e)!==u){t.push({x:a,y:i,width:g,height:M,fill:Ot,type:"hardBin",metadata:e.metadata});return}if(c!==void 0&&s==="metadata"&&H(e)!==c){t.push({x:a,y:i,width:g,height:M,fill:Ot,type:"metadata",metadata:e.metadata});return}if(s==="value"){if(T==="test"){const J=Q(e,y,v),ot=J===void 0?j:J?pt:mt;t.push({x:a,y:i,width:g,height:M,fill:ot,type:"value",metadata:e.metadata});return}const $=R(e,y),D=classifySpec($,v);let _,U;$===void 0?_=j:T==="spec"?_=D==="failLow"?ie:D==="failHigh"?mt:pt:(_=r.forValue(x($)),(D==="failLow"||D==="failHigh")&&(U=D)),t.push({x:a,y:i,width:g,height:M,fill:_,type:"value",specMark:U,metadata:e.metadata});return}if(s==="hardBin"||s==="softBin"){const $=p(e),D=$!=null?r.forBin($):j,_=$!=null&&!V.has($)?!0:void 0;t.push({x:a,y:i,width:g,height:M,fill:D,type:s,binFail:_,metadata:e.metadata});return}if(s==="metadata"){const $=H(e),D=$!==void 0?S?.get($)??j:j;t.push({x:a,y:i,width:g,height:M,fill:D,type:"metadata",metadata:e.metadata});return}const A=R(e,0),E=A!==void 0?r.forValue(x(A)):j;t.push({x:a,y:i,width:g,height:M,fill:E,type:"value",metadata:e.metadata})}function Se(t,e,a){const i=t.radius*.15,s=ht(e,i,0),n=ht(e,0,i),o=s.x+n.x>=0?-1:1,r=s.y+n.y>=0?-1:1,u={x:t.center.x+o*t.radius*.9,y:t.center.y+r*t.radius*.9},x={x:u.x+s.x,y:u.y+s.y},y={x:u.x+n.x,y:u.y+n.y};return a.push({x:x.x+s.x*.35,y:x.y+s.y*.35,text:"+X",fontSize:10,color:"#cc3300",align:"center",role:"indicator"},{x:y.x+n.x*.35,y:y.y+n.y*.35,text:"+Y",fontSize:10,color:"#0044cc",align:"center",role:"indicator"}),[{kind:"xy-indicator",...W([u,x]),lineColor:"#cc3300",lineWidth:2},{kind:"xy-indicator",...W([u,y]),lineColor:"#0044cc",lineWidth:2}]}export function buildView(t,e,a={},i){const s=a.reticles??[],{plotMode:n="value",showDieLabels:o=!1,showReticle:r=!1,showProbePath:u=!1,ringCount:x=4,showRingBoundaries:y=!1,showQuadrantBoundaries:B=!1,showXYIndicator:V=!1,dieGap:v=1,colorScheme:T="default",passBins:m=[1],highlightBin:S,highlightMetadataValue:c,interactiveTransform:f,valueRange:h,testDefs:g,activeTest:M=0,activeMetadataKey:p,fallbackFormat:H="engineering",aggregationMethod:A,lotSize:E,dataAxisFlip:$,isLotStack:D=!1,logScale:_,colorbarRangeMode:U="spec",passFailDisplay:J,showPartialDies:ot=!0}=a,bt=J??"off",Mt=i?.hbinDefs,St=i?.sbinDefs,$t=i?.metadataFields,_t=$t?.find(l=>l.key===p),wt={x:($?.x??!1)!==(f?.flipX??!1),y:($?.y??!1)!==(f?.flipY??!1)},Wt=Mt?new Map(Mt.map(l=>[l.bin,l])):null,jt=St?new Map(St.map(l=>[l.bin,l])):null,rt=n==="softBin"?jt:Wt,lt=se(T),zt=new Set(m),kt={forValue:de(lt.forValue),forBin:T==="custom"&&rt?l=>rt.get(l)?.color??lt.forBin(l):lt.forBin};let{testNumber:O}=resolveTestNumber(M,g);if(!g?.length&&n==="value"&&!e.some(d=>d.testValues&&O in d.testValues)){const d=e.reduce((b,F)=>{if(!F.testValues)return b;const k=Object.keys(F.testValues).map(Number),q=k.length?Math.min(...k):void 0;return q!==void 0&&(b===void 0||q<b)?q:b},void 0);d!==void 0&&(O=d)}let Z;if(Array.isArray(h))Z=h;else if(h){const{testNumber:l}=resolveTestNumber(h.test,g);Z=l===O?h.range:void 0}const I=findTestDef(g,O),Bt=n==="value"&&I!==void 0&&!yt(I),Kt=I!==void 0&&(I.limitLow!==void 0||I.limitHigh!==void 0);let C="off";n==="value"&&(Bt?C="test":bt==="spec"&&Kt?C="spec":bt==="test"&&e.some(l=>Q(l,O,I)!==void 0)&&(C="test"));const vt=C==="spec"?"spec":U;let P,N,Tt=!1;if(Z)[P,N]=Z;else{const l=n==="stackedValues"||n==="stackedBins"||n==="stackedSoftBins",d=!l&&n==="value"&&vt==="spec"&&I&&(I.limitLow!==void 0||I.limitHigh!==void 0);let b=1/0,F=-1/0,k=!0;for(const q of e){const X=l?R(q,0):R(q,O);X!==void 0&&(X<b&&(b=X),X>F&&(F=X),Number.isInteger(X)||(k=!1))}isFinite(b)||(k=!1),Tt=k,d?(P=I.limitLow!==void 0?I.limitLow:isFinite(b)?b:0,N=I.limitHigh!==void 0?I.limitHigh:isFinite(F)?F:1):(P=isFinite(b)?b:0,N=isFinite(F)?F:1)}P===N&&(N=P+1);const It=Bt?!1:_??I?.logScale??!1,Ft=It&&P>0&&N>0,qt=Ft;let tt;if(Ft){const l=Math.log10(P),d=Math.log10(N)-l;tt=b=>b<=0?0:Nt((Math.log10(b)-l)/d)}else tt=l=>Nt((l-P)/(N-P));const L=ue(t,$,f);let Lt=null;if(t.notch){const l=Et(t.notch.type),d=ht(L.physicalToScreen,Math.cos(l)*t.radius,Math.sin(l)*t.radius),b=Math.hypot(d.x,d.y);b>0&&(Lt={x:d.x/b,y:d.y/b})}let z=1/0;for(let l=0;l<e.length;l++){const d=e[l];d.width<z&&(z=d.width),d.height<z&&(z=d.height)}const Xt=z!==1/0?Math.min(v,z*.12):v,Vt=[],ct=[],Yt=L.bakedToScreen.a===1&&L.bakedToScreen.b===0&&L.bakedToScreen.c===0&&L.bakedToScreen.d===1&&L.bakedToScreen.e===0&&L.bakedToScreen.f===0;let w=null;if(!Yt){w=new Float64Array(e.length*2);for(let l=0;l<e.length;l++){const d=Y(L.bakedToScreen,e[l].physX,e[l].physY);w[l*2]=d.x,w[l*2+1]=d.y}}const Gt=ae(L.gridToScreen),Qt=n==="hardBin"||n==="softBin"||n==="stackedBins"||n==="stackedSoftBins",Ut=n==="softBin"||n==="stackedSoftBins";let et=Qt?new Map:void 0;const ut=n==="value"&&C==="spec"?{pass:0,failHigh:0,failLow:0}:void 0,ft=n==="value"&&C==="test"?{pass:0,fail:0}:void 0,Dt=n==="metadata";let nt=Dt?new Map:void 0,at=null;if(Dt&&p){const l=new Set;for(const b of e){if(b.partial||b.edgeExcluded)continue;const F=st(b,p);F!==void 0&&l.add(F)}const d=[...l].sort(re);at=new Map(d.map((b,F)=>[b,_t?.values?.find(k=>k.value===b)?.color??oe(F)]))}for(let l=0;l<e.length;l++){const d=e[l],b=w?w[l*2]:d.physX,F=w?w[l*2+1]:d.physY;if(ct.push({x:b,y:F}),et&&!d.partial&&!d.edgeExcluded){const k=Ut?d.sbin:d.hbin;k!=null&&et.set(k,(et.get(k)??0)+1)}if(ut&&!d.partial&&!d.edgeExcluded){const k=classifySpec(R(d,O),I);k&&ut[k]++}if(ft&&!d.partial&&!d.edgeExcluded){const k=Q(d,O,I);k!==void 0&&ft[k?"pass":"fail"]++}if(nt&&!d.partial&&!d.edgeExcluded){const k=st(d,p);k!==void 0&&nt.set(k,(nt.get(k)??0)+1)}d.partial&&!ot||Me(Vt,d,b,F,n,Gt,Xt,kt,S,tt,O,rt,zt,I,C,p,at,c)}const Pt=o?generateTextOverlay(e,w,{plotMode:n,colorFns:kt,normalize:tt,activeTest:M,valueRange:[P,N],testDefs:g,fallbackFormat:H,passFailDisplay:C,activeMetadataKey:p,metadataColorMap:at}):[],K=me(t,L.physicalToScreen);y&&K.push(...ye(t,L.physicalToScreen,x)),B&&K.push(...ge(t,L.physicalToScreen,t.center.x,t.center.y)),r&&K.push(...xe(s,L.gridToScreen)),u&&K.push(...be(e)),V&&K.push(...Se(t,L.gridToScreen,Pt));const Jt=ct.length>0?{minX:t.center.x-t.radius,maxX:t.center.x+t.radius,minY:t.center.y-t.radius,maxY:t.center.y+t.radius}:null;return{rectangles:Vt,hoverPoints:ct,texts:Pt,overlays:K,plotMode:n,colorScheme:T,metadata:t.metadata??null,dies:e,valueRange:[P,N],allIntegerValues:Tt,testDefs:g,activeTest:M,logScale:qt,logScaleRequested:It,aggrMethod:A,lotSize:E,axisFlip:wt,dataAxisFlip:{x:$?.x??!1,y:$?.y??!1},gridToScreen:L.gridToScreen,rotation:((t.orientation+(f?.rotation??0))%360+360)%360,hasReticle:s.length>0,isLotStack:D,passFailDisplay:C,colorBySpec:C==="spec",colorbarRangeMode:vt,waferCenter:t.center,waferRadius:t.radius,notchDir:Lt,binCounts:et,metadataCounts:nt,metadataColorMap:at,activeMetadataKey:p,metadataFields:$t,specCounts:ut,passFailCounts:ft,dieBounds:Jt}}export{getDieKey}from"../core/dies.js";
|
|
@@ -48,7 +48,7 @@ ${R()}
|
|
|
48
48
|
<body>
|
|
49
49
|
${V(S,w,e)}
|
|
50
50
|
</body>
|
|
51
|
-
</html>`}const m=r.title??"Lot Summary",p=o.map(u=>{const{lotSummary:w,sections:x}=q(u.items,n,l,t,s,c,d),S=u.varying.includes("lot")?void 0:w.lot?.lot??w.lot?.lotId,y=S?`${u.label} \xB7 Lot ${String(S)}`:u.label;return V(`${m} \u2014 ${y}`,x,e)}),g=`<p style="max-width:1080px;margin:0 auto 8px;padding:8px 12px;background:var(--report-surface
|
|
51
|
+
</html>`}const m=r.title??"Lot Summary",p=o.map(u=>{const{lotSummary:w,sections:x}=q(u.items,n,l,t,s,c,d),S=u.varying.includes("lot")?void 0:w.lot?.lot??w.lot?.lotId,y=S?`${u.label} \xB7 Lot ${String(S)}`:u.label;return V(`${m} \u2014 ${y}`,x,e)}),g=`<p style="max-width:1080px;margin:0 auto 8px;padding:8px 12px;background:var(--report-surface);border:1px solid var(--report-line);border-radius:4px;font-size:12px;color:var(--report-muted);">This load spans ${o.length} groups by identity \u2014 shown separately below so stats are never pooled across them.</p>`,b=p.map((u,w)=>`${w===0?"":'<hr style="max-width:1080px;margin:32px auto 0;border:none;border-top:3px solid var(--report-line-strong);">'}
|
|
52
52
|
${u}`).join(`
|
|
53
53
|
`);return`<!DOCTYPE html>
|
|
54
54
|
<html lang="en">
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wafertools/wafermap",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Interactive wafer map visualization and yield analysis for semiconductor test data. Hard bins, soft bins, test values, retests, edge exclusion, reticle overlays, spatial statistics, failure clustering, and lot-level trend analysis
|
|
3
|
+
"version": "0.25.0",
|
|
4
|
+
"description": "Interactive wafer map visualization and yield analysis for semiconductor test data. Hard bins, soft bins, test values, retests, edge exclusion, reticle overlays, spatial statistics, failure clustering, and lot-level trend analysis — pure ES modules, no runtime dependencies, no server required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": {
|
|
@@ -75,13 +75,13 @@
|
|
|
75
75
|
"build": "node scripts/build-user-guide.mjs && node scripts/sync-icons.mjs && node scripts/sync-version.mjs && rm -rf dist && tsc -p tsconfig.build.json",
|
|
76
76
|
"build:guide": "node scripts/build-user-guide.mjs",
|
|
77
77
|
"clean": "rm -rf dist",
|
|
78
|
-
"check": "node scripts/build-user-guide.mjs && node scripts/sync-version.mjs && tsc --noEmit -p tsconfig.json && node scripts/check-examples-manifest.mjs && node scripts/build-agents-page.mjs --check && node scripts/check-agents-guide.mjs && node scripts/check-toolbar-docs.mjs && node scripts/check-changelog.mjs && node scripts/help.mjs --check",
|
|
78
|
+
"check": "node scripts/build-user-guide.mjs && node scripts/sync-version.mjs && tsc --noEmit -p tsconfig.json && node scripts/check-examples-manifest.mjs && node scripts/build-agents-page.mjs --check && node scripts/check-agents-guide.mjs && node scripts/check-toolbar-docs.mjs && node scripts/check-overlay-conventions.mjs && node scripts/check-changelog.mjs && node scripts/help.mjs --check",
|
|
79
79
|
"build:examples-index": "node scripts/build-examples-index.mjs",
|
|
80
80
|
"check:drift": "node scripts/check-drift.mjs",
|
|
81
81
|
"dev": "rm -rf docs/dist && cp -r dist docs/dist && ./.venv/bin/zensical serve --dev-addr localhost:8001",
|
|
82
82
|
"test": "npm run build && node --test tests/*.test.mjs",
|
|
83
83
|
"build:site": "rm -rf docs/dist && cp -r dist docs/ && ${ZENSICAL:-.venv/bin/zensical} build --clean && cp -r docs/data site/data && cp llms.txt site/llms.txt && rm -rf docs/dist && node scripts/bundle-docs.mjs && node scripts/build-examples-archive.mjs",
|
|
84
|
-
"preview:site": "npm run build:site && echo \"\\nServing bundled site at http://localhost:8002/examples/
|
|
84
|
+
"preview:site": "npm run build:site && echo \"\\nServing bundled site at http://localhost:8002/examples/ — Ctrl-C to stop\\n\" && cd site && python3 -m http.server 8002",
|
|
85
85
|
"prepack": "npm run build && node scripts/minify-dist.mjs",
|
|
86
86
|
"pack:check": "npm pack --dry-run",
|
|
87
87
|
"prepublishOnly": "npm test",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"preversion": "npm run verify",
|
|
90
90
|
"version": "node scripts/check-changelog.mjs",
|
|
91
91
|
"postversion": "echo \"\\nTagged v$npm_package_version. Next:\\n git push && git push origin v$npm_package_version\\n npm publish\\n\"",
|
|
92
|
-
"postpublish": "echo \"\\ndist/ was minified for publish
|
|
92
|
+
"postpublish": "echo \"\\ndist/ was minified for publish — run 'npm run build' to restore the readable dev build.\\n\"",
|
|
93
93
|
"screenshots": "node scripts/capture-screenshots.mjs",
|
|
94
94
|
"screenshots:list": "node scripts/capture-screenshots.mjs --list",
|
|
95
95
|
"build:images": "npm run build && node scripts/capture-screenshots.mjs",
|