@wafertools/wafermap 0.29.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 +26 -17
- package/CHANGELOG.md +410 -0
- package/README.md +6 -6
- 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 +7 -0
- package/dist/packages/canvas-adapter/deprecated.js +1 -0
- package/dist/packages/canvas-adapter/dieList.d.ts +1 -3
- package/dist/packages/canvas-adapter/dieList.js +7 -7
- package/dist/packages/canvas-adapter/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 -3
- package/dist/packages/canvas-adapter/index.js +1 -1
- package/dist/packages/canvas-adapter/insightsTab.d.ts +0 -1
- package/dist/packages/canvas-adapter/insightsTab.js +1 -1
- package/dist/packages/canvas-adapter/maplessSummary.js +1 -1
- package/dist/packages/canvas-adapter/renderWaferGallery.d.ts +23 -40
- package/dist/packages/canvas-adapter/renderWaferGallery.js +1 -1
- package/dist/packages/canvas-adapter/renderWaferMap.d.ts +96 -104
- package/dist/packages/canvas-adapter/renderWaferMap.js +1 -1
- package/dist/packages/canvas-adapter/summaryPanel.d.ts +31 -13
- package/dist/packages/canvas-adapter/summaryPanel.js +3 -3
- package/dist/packages/canvas-adapter/toCanvas.d.ts +20 -12
- package/dist/packages/canvas-adapter/toCanvas.js +1 -1
- package/dist/packages/canvas-adapter/toolbar.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 +26 -15
- 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 +60 -0
- package/dist/packages/core/deprecated.js +1 -0
- package/dist/packages/core/index.d.ts +1 -3
- package/dist/packages/core/index.js +1 -1
- package/dist/packages/core/passBins.d.ts +33 -0
- package/dist/packages/core/passBins.js +1 -0
- package/dist/packages/core/utils.d.ts +12 -0
- package/dist/packages/core/utils.js +1 -1
- package/dist/packages/core/waferLabel.d.ts +35 -0
- package/dist/packages/core/waferLabel.js +1 -0
- package/dist/packages/renderer/binColors.d.ts +105 -13
- package/dist/packages/renderer/binColors.js +1 -1
- package/dist/packages/renderer/buildView.d.ts +8 -9
- package/dist/packages/renderer/buildView.js +1 -1
- package/dist/packages/renderer/buildWaferMap.d.ts +76 -17
- package/dist/packages/renderer/buildWaferMap.js +1 -1
- package/dist/packages/renderer/colorMap.d.ts +4 -3
- package/dist/packages/renderer/colorSchemes.d.ts +8 -6
- package/dist/packages/renderer/deprecate.d.ts +31 -0
- package/dist/packages/renderer/deprecate.js +1 -0
- package/dist/packages/renderer/deprecated.d.ts +45 -0
- package/dist/packages/renderer/deprecated.js +1 -0
- package/dist/packages/renderer/index.d.ts +4 -4
- package/dist/packages/renderer/index.js +1 -1
- package/dist/packages/stats/analyzeWaferLot.js +1 -1
- package/dist/packages/stats/analyzeWaferMap.js +1 -1
- package/dist/packages/stats/binPareto.d.ts +6 -1
- package/dist/packages/stats/capability.d.ts +16 -1
- package/dist/packages/stats/capability.js +1 -1
- package/dist/packages/stats/clusterDetection.d.ts +0 -2
- package/dist/packages/stats/deprecated.d.ts +82 -0
- package/dist/packages/stats/deprecated.js +1 -0
- package/dist/packages/stats/index.d.ts +5 -14
- 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 +9 -2
- package/dist/packages/stats/regions.js +1 -1
- package/dist/packages/stats/renderFindingsReport.js +1 -1
- package/dist/packages/stats/renderSummaryReport.d.ts +42 -1
- package/dist/packages/stats/renderSummaryReport.js +34 -34
- 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 -43
- package/dist/packages/stats/yield.d.ts +12 -6
- package/dist/packages/stats/yield.js +1 -1
- package/package.json +1 -1
|
@@ -46,9 +46,17 @@ export interface WaferPreferences {
|
|
|
46
46
|
showQuadrantBoundaries?: boolean;
|
|
47
47
|
showReticle?: boolean;
|
|
48
48
|
showXYIndicator?: boolean;
|
|
49
|
-
ringCount?: number;
|
|
50
49
|
/** Legend position for bin modes. Default 'default'. */
|
|
51
50
|
legendPosition?: 'default' | 'compact' | 'bottom' | 'top' | 'left' | 'floating';
|
|
51
|
+
/**
|
|
52
|
+
* Format for unitless values outside the normal display range [0.1, 9999].
|
|
53
|
+
* `'engineering'` (default): multiples-of-3 exponent notation (e.g. `12E-6`).
|
|
54
|
+
* `'si'`: SI prefix with no unit suffix (e.g. `12 µ`).
|
|
55
|
+
* Values with a unit always use SI prefix regardless of this setting.
|
|
56
|
+
* Set it like any other preference — `viewOptions` or `setOptions` — the one
|
|
57
|
+
* place it is set (it used to have four).
|
|
58
|
+
*/
|
|
59
|
+
fallbackFormat?: 'si' | 'engineering';
|
|
52
60
|
/**
|
|
53
61
|
* Draw this map's own legend block — the categorical bin legend, the spec/
|
|
54
62
|
* pass-fail legend, or the value colorbar, whichever the plot mode calls for.
|
|
@@ -133,24 +141,6 @@ export interface WaferDisplayState {
|
|
|
133
141
|
test: number;
|
|
134
142
|
range: [number, number];
|
|
135
143
|
};
|
|
136
|
-
/**
|
|
137
|
-
* The full, ordered list of metadata values to assign colours from in
|
|
138
|
-
* `metadata` plot mode — applied only when `key` matches `activeMetadataKey`.
|
|
139
|
-
* Set by a host rendering several wafers together (`renderWaferGallery` does
|
|
140
|
-
* it for you) so every map indexes into ONE list; without it each map derives
|
|
141
|
-
* the order from its own dies, and a wafer missing a value the others have
|
|
142
|
-
* paints every later value in the next map's colour. See `ViewOptions`.
|
|
143
|
-
*/
|
|
144
|
-
metadataValueOrder?: {
|
|
145
|
-
key: string;
|
|
146
|
-
values: string[];
|
|
147
|
-
};
|
|
148
|
-
/**
|
|
149
|
-
* Bin colours resolved over the whole population being shown together —
|
|
150
|
-
* set by `renderWaferGallery` so a bin is one colour on every card. A lone
|
|
151
|
-
* map leaves it unset and resolves over its own dies. See `ViewOptions.binColors`.
|
|
152
|
-
*/
|
|
153
|
-
binColors?: BinColors;
|
|
154
144
|
/**
|
|
155
145
|
* Aggregation method for `stackedValues` mode.
|
|
156
146
|
* Drives both the per-die aggregation and the hover tooltip label.
|
|
@@ -158,11 +148,6 @@ export interface WaferDisplayState {
|
|
|
158
148
|
* Defaults to `'mean'` when not set.
|
|
159
149
|
*/
|
|
160
150
|
aggregationMethod?: string;
|
|
161
|
-
/**
|
|
162
|
-
* Total number of wafers in the lot — used to compute bin occurrence percentage
|
|
163
|
-
* in `stackedBins` hover tooltips.
|
|
164
|
-
*/
|
|
165
|
-
lotSize?: number;
|
|
166
151
|
}
|
|
167
152
|
/**
|
|
168
153
|
* All scene-level options that the toolbar can control.
|
|
@@ -179,7 +164,7 @@ export type WaferViewOptions = WaferPreferences & WaferDisplayState;
|
|
|
179
164
|
*
|
|
180
165
|
* That inheritance leaked 16 low-level fields onto the top-level render API, and
|
|
181
166
|
* five of them were **accepted and silently ignored** — `renderWaferMap` computes
|
|
182
|
-
* or overrides them on every draw (`topClearance`
|
|
167
|
+
* or overrides them on every draw (`topClearance` was always 0, and has since been removed from `toCanvas` too;
|
|
183
168
|
* `minRightReserve` is derived from the legend, and `markFailingDies`/`activeBin`/
|
|
184
169
|
* `hoverBin` are read from `viewOptions` and internal hover state instead). An
|
|
185
170
|
* option that is typed, documented and ignored costs a caller a debugging session
|
|
@@ -194,7 +179,7 @@ export type WaferViewOptions = WaferPreferences & WaferDisplayState;
|
|
|
194
179
|
* of the ten options that DO work in exchange for tidiness alone, and the defect
|
|
195
180
|
* here was the five that don't.
|
|
196
181
|
*/
|
|
197
|
-
type ForwardedDrawOptions = Pick<ToCanvasOptions, 'padding' | 'background' | 'showColorbar' | 'colorbarWidth' | 'showAxes' | 'showTitle' | '
|
|
182
|
+
type ForwardedDrawOptions = Pick<ToCanvasOptions, 'padding' | 'background' | 'showColorbar' | 'colorbarWidth' | 'showAxes' | 'showTitle' | 'legendOffset' | 'diePitchMm' | 'metadataFields'>;
|
|
198
183
|
export interface RenderOptions extends ForwardedDrawOptions {
|
|
199
184
|
/** Initial scene display options. All are overridable via the toolbar. */
|
|
200
185
|
viewOptions?: WaferViewOptions;
|
|
@@ -230,48 +215,23 @@ export interface RenderOptions extends ForwardedDrawOptions {
|
|
|
230
215
|
* result has no metadata/lot-stack context.
|
|
231
216
|
*/
|
|
232
217
|
showIdentity?: boolean;
|
|
233
|
-
/**
|
|
234
|
-
* Inset for this map's own chrome row (identity + toolbar) and for a Summary
|
|
235
|
-
* panel docked inside the map area, from the edge of the map area.
|
|
236
|
-
*
|
|
237
|
-
* Defaults to `EDGE_GUTTER` — correct for a standalone map, where the map
|
|
238
|
-
* area IS the region and its chrome is a bounded surface against that edge.
|
|
239
|
-
* Pass the smaller `MAP_CHROME_INSET` when the map is embedded in a surface
|
|
240
|
-
* that already provides its own inset (this is what `renderWaferGallery`
|
|
241
|
-
* passes for its cards); a second full gutter inside one stacks two, which
|
|
242
|
-
* reads as a toolbar standing well off the side of the card.
|
|
243
|
-
*/
|
|
244
|
-
chromeInset?: string;
|
|
245
218
|
/** Optional precomputed wafer-level stats summary. Enables the summary panel toggle button in the toolbar. */
|
|
246
219
|
statsSummary?: StatsSummary;
|
|
247
220
|
/**
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
* 'full' (default) shows all toolbar controls.
|
|
255
|
-
* 'view-only' shows only zoom, reset, box-select, and download — used by gallery cards.
|
|
256
|
-
*/
|
|
257
|
-
toolbarControls?: 'full' | 'view-only';
|
|
258
|
-
/**
|
|
259
|
-
* Show the plot mode selector in the toolbar. Default true.
|
|
260
|
-
* Set to false when the host application manages mode switching itself.
|
|
221
|
+
* Name for the map's PNG download, without extension. When omitted, the PNG
|
|
222
|
+
* is named for its lot, wafer and map title (`LOT123_W05_hard-bin.png`); CSV
|
|
223
|
+
* exports are always named that way. See docs/api.md §5.4.5.
|
|
224
|
+
*
|
|
225
|
+
* **Changes in 0.31.0:** this becomes a prefix for every file the map saves,
|
|
226
|
+
* with the lot, wafer and content appended. Passing it logs a one-time notice.
|
|
261
227
|
*/
|
|
262
|
-
showPlotModeSelector?: boolean;
|
|
263
|
-
/** Minimum zoom relative to fit. Default 0.4. */
|
|
264
|
-
minZoom?: number;
|
|
265
|
-
/** Maximum zoom relative to fit. Default 20. */
|
|
266
|
-
maxZoom?: number;
|
|
267
|
-
/** Filename for the PNG download (without extension). Default `'wafermap'`. */
|
|
268
228
|
downloadFilename?: string;
|
|
269
229
|
/**
|
|
270
230
|
* Host hook for persisting the rendered PNG. When provided, the toolbar's save
|
|
271
231
|
* action calls `onSaveImage(blob, suggestedName)` instead of triggering a
|
|
272
232
|
* browser `<a download>` — letting embedded hosts (Tauri, Electron, WebView2)
|
|
273
233
|
* route the image through a native save dialog. `suggestedName` includes the
|
|
274
|
-
* `.png` extension and is
|
|
234
|
+
* `.png` extension and is the generated name (see `downloadFilename`). When omitted, the
|
|
275
235
|
* default browser download behaviour is unchanged.
|
|
276
236
|
*/
|
|
277
237
|
onSaveImage?: SaveImageHandler;
|
|
@@ -313,12 +273,6 @@ export interface RenderOptions extends ForwardedDrawOptions {
|
|
|
313
273
|
* identity data into an export.
|
|
314
274
|
*/
|
|
315
275
|
dieList?: DieListDisplayOptions;
|
|
316
|
-
/**
|
|
317
|
-
* Custom tooltip renderer. When provided, replaces the built-in tooltip content.
|
|
318
|
-
* Return a string (set as innerHTML), an HTMLElement (appended directly), or null to suppress the tooltip.
|
|
319
|
-
* The built-in tooltip wrapper (positioning, show/hide behaviour) is preserved.
|
|
320
|
-
*/
|
|
321
|
-
renderTooltip?: (die: Die) => string | HTMLElement | null;
|
|
322
276
|
/**
|
|
323
277
|
* Show a help button in the toolbar that opens the built-in end-user guide in a modal.
|
|
324
278
|
* Default false. Enable in applications that want to surface the guide without linking externally.
|
|
@@ -330,8 +284,6 @@ export interface RenderOptions extends ForwardedDrawOptions {
|
|
|
330
284
|
* has one help button instead of two. See `UserGuideExtension`.
|
|
331
285
|
*/
|
|
332
286
|
userGuideExtension?: UserGuideExtension;
|
|
333
|
-
/** Override the expand action for both the expand button and the E key. Used by the gallery to route through its own modal logic. */
|
|
334
|
-
onExpand?: () => void;
|
|
335
287
|
/**
|
|
336
288
|
* Show the expand button in the toolbar and enable the E-key shortcut.
|
|
337
289
|
* Default true. Independent of `showIdentity` — expand is a view control,
|
|
@@ -350,15 +302,6 @@ export interface RenderOptions extends ForwardedDrawOptions {
|
|
|
350
302
|
* inset, or an explicit CSS height). Width always comes from the container.
|
|
351
303
|
*/
|
|
352
304
|
height?: number | string;
|
|
353
|
-
/**
|
|
354
|
-
* Cap the map's rendered width and height at this many CSS pixels. When
|
|
355
|
-
* the container is larger, the map sits top-left aligned within it rather
|
|
356
|
-
* than stretching to fill it. Number only (a fixed pixel ceiling, not a
|
|
357
|
-
* responsive length like `height`). Omit for no cap (fills the container,
|
|
358
|
-
* current behaviour). The expand button/E-key still opens the map at full
|
|
359
|
-
* size, unaffected by this cap.
|
|
360
|
-
*/
|
|
361
|
-
maxSize?: number;
|
|
362
305
|
/**
|
|
363
306
|
* Base `z-index` for wmap's transient overlays — toolbar menus, the die
|
|
364
307
|
* tooltip, the expand modal, and the user-guide modal. wmap layers its own
|
|
@@ -394,8 +337,6 @@ export interface RenderOptions extends ForwardedDrawOptions {
|
|
|
394
337
|
warnings?: WarningsOptions;
|
|
395
338
|
}
|
|
396
339
|
export interface WaferMapController {
|
|
397
|
-
/** Update the die data (e.g. after a data reload) — rebuilds scene, preserves zoom/pan. */
|
|
398
|
-
setDies(dies: Die[]): void;
|
|
399
340
|
/** Replace the wafer map result entirely — updates both wafer geometry and die data, preserves zoom/pan. */
|
|
400
341
|
setResult(result: WaferMapResult): void;
|
|
401
342
|
/** Merge scene option overrides — rebuilds scene, preserves zoom/pan. */
|
|
@@ -414,50 +355,38 @@ export interface WaferMapController {
|
|
|
414
355
|
clearSelection(): void;
|
|
415
356
|
/** Reset zoom and pan to fitted view. */
|
|
416
357
|
resetZoom(): void;
|
|
417
|
-
/** Update the fallback format for unitless values and re-render. */
|
|
418
|
-
setFallbackFormat(format: 'si' | 'engineering'): void;
|
|
419
358
|
/** Replace the current stats summary used by the built-in Summary panel. */
|
|
420
359
|
setStatsSummary(summary: StatsSummary | undefined): void;
|
|
421
|
-
/**
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
360
|
+
/**
|
|
361
|
+
* Close the Summary panel if it is open; no-op if it is closed or the map has
|
|
362
|
+
* none. For a host that needs the map's full width back — loading a new file,
|
|
363
|
+
* opening its own dialog, moving to a narrower layout. The user reopens it from
|
|
364
|
+
* the toolbar's Summary button.
|
|
365
|
+
*/
|
|
366
|
+
closeSummaryPanel(): void;
|
|
367
|
+
/**
|
|
368
|
+
* The bin colours this map draws, with the palette currently chosen — for a
|
|
369
|
+
* host surface of its own (a table swatch, an export). Inside a gallery these
|
|
370
|
+
* are the gallery-wide colours. Hard and soft bins are separate maps.
|
|
371
|
+
*/
|
|
372
|
+
getBinColors(): BinColors;
|
|
431
373
|
/**
|
|
432
374
|
* Opens the built-in end-user guide window — the same action the help
|
|
433
375
|
* toolbar button performs, but callable directly. Works regardless of
|
|
434
|
-
* `showHelpButton
|
|
376
|
+
* `showHelpButton`, so a host that
|
|
435
377
|
* hides wmap's own help button (e.g. to fold it into its own combined help
|
|
436
378
|
* menu) can still trigger the guide without a DOM query against wmap's
|
|
437
379
|
* internal button markup.
|
|
438
380
|
*/
|
|
439
381
|
openUserGuide(): void;
|
|
440
|
-
/** Close the auto-mounted Summary panel if it is open. No-op if no panel exists. */
|
|
441
|
-
closeSummaryPanel(): void;
|
|
442
382
|
/** Programmatically open/close the Insights tab. No-op if `insights.enabled` was not set. */
|
|
443
383
|
setInsightsOpen(open: boolean): void;
|
|
444
|
-
/** Move the floating tooltip into a different parent (e.g. a maximized modal box). */
|
|
445
|
-
setTooltipParent(parent: HTMLElement): void;
|
|
446
|
-
/**
|
|
447
|
-
* Returns the current legend entries in `hardBin`/`softBin`/`metadata` modes, `null` in other
|
|
448
|
-
* modes. Each entry includes the bin number (or metadata value string), display name, and color.
|
|
449
|
-
*/
|
|
450
|
-
getActiveLegend(): Array<{
|
|
451
|
-
bin: number | string;
|
|
452
|
-
name: string;
|
|
453
|
-
color: string;
|
|
454
|
-
}> | null;
|
|
455
384
|
/** Remove all event listeners and DOM elements. */
|
|
456
385
|
destroy(): void;
|
|
457
386
|
}
|
|
458
387
|
/** Options that change die colours without changing what the view contains —
|
|
459
388
|
* any of them means every colour-bearing surface (panels, footer) redraws. */
|
|
460
|
-
export declare const COLOR_KEYS: readonly (keyof
|
|
389
|
+
export declare const COLOR_KEYS: readonly (keyof CardViewOptions)[];
|
|
461
390
|
export declare function classifyChanged(keys: (keyof WaferViewOptions)[]): 'preference' | 'state' | 'mixed';
|
|
462
391
|
/**
|
|
463
392
|
* What `renderWaferMap` actually needs: a wafer and its dies, plus anything
|
|
@@ -474,7 +403,70 @@ export declare function classifyChanged(keys: (keyof WaferViewOptions)[]): 'pref
|
|
|
474
403
|
* and each such read had to be found the hard way. Declaring them optional
|
|
475
404
|
* hands that job back to the compiler.
|
|
476
405
|
*/
|
|
406
|
+
/** @internal State a gallery shares with every card so one lot reads as one lot. */
|
|
407
|
+
export interface CardSharedState {
|
|
408
|
+
/**
|
|
409
|
+
* The full, ordered list of metadata values to assign colours from in
|
|
410
|
+
* `metadata` plot mode — applied only when `key` matches `activeMetadataKey`.
|
|
411
|
+
* Set by a host rendering several wafers together (`renderWaferGallery` does
|
|
412
|
+
* it for you) so every map indexes into ONE list; without it each map derives
|
|
413
|
+
* the order from its own dies, and a wafer missing a value the others have
|
|
414
|
+
* paints every later value in the next map's colour. See `ViewOptions`.
|
|
415
|
+
*/
|
|
416
|
+
metadataValueOrder?: {
|
|
417
|
+
key: string;
|
|
418
|
+
values: string[];
|
|
419
|
+
};
|
|
420
|
+
/**
|
|
421
|
+
* Bin colours resolved over the whole population being shown together —
|
|
422
|
+
* set by `renderWaferGallery` so a bin is one colour on every card. A lone
|
|
423
|
+
* map leaves it unset and resolves over its own dies. See `ViewOptions.binColors`.
|
|
424
|
+
*/
|
|
425
|
+
binColors?: BinColors;
|
|
426
|
+
/**
|
|
427
|
+
* Total number of wafers in the lot — the percentage denominator in
|
|
428
|
+
* `stackedBins`/`stackedSoftBins` hover tooltips.
|
|
429
|
+
*/
|
|
430
|
+
lotSize?: number;
|
|
431
|
+
}
|
|
432
|
+
/** @internal */
|
|
433
|
+
export type CardViewOptions = WaferViewOptions & CardSharedState;
|
|
434
|
+
/** @internal Options only renderWaferGallery passes. */
|
|
435
|
+
export interface CardRenderOptions extends Omit<RenderOptions, 'viewOptions'> {
|
|
436
|
+
viewOptions?: CardViewOptions;
|
|
437
|
+
/**
|
|
438
|
+
* Inset for this map's own chrome row (identity + toolbar) and for a Summary
|
|
439
|
+
* panel docked inside the map area, from the edge of the map area.
|
|
440
|
+
*
|
|
441
|
+
* Defaults to `EDGE_GUTTER` — correct for a standalone map, where the map
|
|
442
|
+
* area IS the region and its chrome is a bounded surface against that edge.
|
|
443
|
+
* Pass the smaller `MAP_CHROME_INSET` when the map is embedded in a surface
|
|
444
|
+
* that already provides its own inset (this is what `renderWaferGallery`
|
|
445
|
+
* passes for its cards); a second full gutter inside one stacks two, which
|
|
446
|
+
* reads as a toolbar standing well off the side of the card.
|
|
447
|
+
*/
|
|
448
|
+
chromeInset?: string;
|
|
449
|
+
/** Replaces the expand action for both the expand button and the E key. */
|
|
450
|
+
onExpand?: () => void;
|
|
451
|
+
}
|
|
452
|
+
/** @internal */
|
|
453
|
+
export interface CardController extends WaferMapController {
|
|
454
|
+
setOptions(opts: Partial<CardViewOptions>): void;
|
|
455
|
+
getOptions(): CardViewOptions;
|
|
456
|
+
/** Show or hide the Summary toolbar button without affecting the panel's content. */
|
|
457
|
+
setSummaryVisible(visible: boolean): void;
|
|
458
|
+
/** Show or hide the view-control toolbar buttons (mode, orientation, etc). */
|
|
459
|
+
setViewControlsVisible(visible: boolean): void;
|
|
460
|
+
/** Show or hide the expand toolbar button. */
|
|
461
|
+
setExpandVisible(visible: boolean): void;
|
|
462
|
+
/** The map's title as a file-name content part — the gallery names its composite PNG by it. */
|
|
463
|
+
getExportTitle(): string;
|
|
464
|
+
}
|
|
465
|
+
/** @internal The public view of a card's options: everything but the gallery's shared state. */
|
|
466
|
+
export declare function toPublicViewOptions(opts: CardViewOptions): WaferViewOptions;
|
|
477
467
|
export type RenderableWaferMap = Pick<WaferMapResult, 'wafer' | 'dies'> & Partial<Omit<WaferMapResult, 'wafer' | 'dies'>>;
|
|
478
468
|
export declare function renderWaferMap(container: HTMLElement, result: RenderableWaferMap, options?: RenderOptions): WaferMapController;
|
|
469
|
+
/** @internal renderWaferMap plus the gallery-only options and controller methods. */
|
|
470
|
+
export declare function renderWaferMapCard(container: HTMLElement, result: RenderableWaferMap, options?: CardRenderOptions): CardController;
|
|
479
471
|
export {};
|
|
480
472
|
//# sourceMappingURL=renderWaferMap.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{buildView as vi,buildHoverText as xi,findTestDef as ct,resolveTestNumber as Nt}from"../renderer/buildView.js";import{toCanvas as Ci,BIN_LEGEND_W as Fn,BIN_LEGEND_W_COMPACT as wi,BIN_LEGEND_ADAPT_COMPACT as Si,BIN_LEGEND_ADAPT_FLOATING as Mi}from"./toCanvas.js";import{buildWaferMap as Ei,getTestPassStatus as Di,isParametricTest as jt}from"../renderer/buildWaferMap.js";import{analyzeWaferMap as Bi}from"../stats/analyzeWaferMap.js";import{SHADOW as ki,LEADING as An,wireControlHover as Vn,SPACE as W,EDGE_GUTTER as Li,RADIUS as zn,FONT as ft,CLR as x,applyOverlayZ as Ti,getTooltip as Yn,hideTooltip as pt,reparentTooltip as Oi,positionTooltip as Kt,createToolbarHelpers as Pi,buildModeMenuEl as Ri,openReparentedModal as Ii,openUserGuideWindow as Wi,makePaletteBtn as Hi,makeLogScaleBtn as Fi,makeLegendStyleBtn as Ai,makeOverlaysBtn as Vi,makeOrientationBtn as zi,menuLayerFor as Xn,saveImageBlob as Yi,markMenuTrigger as _e,wireMenuA11y as Nn,wireExpandToggle as Xi,nextFrame as _t,requestedPassFailDisplay as Ni,overlayMenuRows as ji,anyOverlayActive as Ki,logWmapVersionOnce as _i,buildDataModeEntries as $i,metadataKeyHasData as Gi,metadataModeEntry as Ui}from"./toolbar.js";import{createSummaryPanelEl as $t,wrapWithSummaryPanel as Gt,renderWaferSummaryContent as Zi}from"./summaryPanel.js";import{collectWarnings as Qi,buildWarningsMenuEl as qi,severityOf as Ji}from"./warnings.js";import{ICONS as jn}from"./icons.js";import{metadataValueColor as eo,NO_DATA_FILL as to}from"../renderer/colorMap.js";import{createIdentityHeader as no,collapsedLabel as Ut}from"./identityHeader.js";import{getDieKey as Be,hasPosition as Kn,isPositionedDie as io}from"../core/dies.js";import{buildDieListSection as oo}from"./dieList.js";import{buildMaplessSummary as so}from"./maplessSummary.js";import{resolveBinColors as lo,binColorWarning as ao}from"../renderer/binColors.js";const _n=new Set(["binColorScheme","valueColorScheme","reverseValueScheme","useDefinedBinColors","rotation","flipX","flipY","showDieLabels","showPartialDies","showRingBoundaries","showQuadrantBoundaries","showReticle","showXYIndicator","ringCount","legendPosition","logScale","colorbarRangeMode","markFailingDies"]);export const COLOR_KEYS=["binColorScheme","valueColorScheme","reverseValueScheme","useDefinedBinColors","binColors"];export function classifyChanged(K){const y=K.some(g=>_n.has(g)),C=K.some(g=>!_n.has(g));return y&&C?"mixed":y?"preference":"state"}export function renderWaferMap(K,y,C={}){_i();const g=K.ownerDocument,H=g.defaultView??window;H.getComputedStyle(K).position==="static"&&(K.style.position="relative");const $n=K.clientHeight;C.height!=null&&(K.style.height=typeof C.height=="number"?`${C.height}px`:C.height);const ut=y.dataCoverage?y.dataCoverage.unpositionedDies:y.dies.filter(e=>!Kn(e)).length,$e=(y.dataCoverage?y.dataCoverage.totalDies:y.dies.length-ut)===0&&ut>0,ke=g.createElement("div");Object.assign(ke.style,{display:"flex",flexDirection:"column",width:"100%",height:"100%"}),K.appendChild(ke);const le=g.createElement("div");Object.assign(le.style,{position:"relative",width:"100%",flex:"1 1 auto",minHeight:"0"}),C.maxSize!=null&&(le.style.maxWidth=`${C.maxSize}px`,le.style.maxHeight=`${C.maxSize}px`);const ge=C.chromeInset??Li,_=g.createElement("div");Object.assign(_.style,{display:"flex",alignItems:"stretch",gap:W.sm,background:x.canvasBg,paddingBottom:W.lg,paddingTop:ge,paddingLeft:ge,paddingRight:ge,flexShrink:"0",minWidth:"0"}),ke.appendChild(_),ke.appendChild(le);function ve(){const e=[..._.children].some(t=>t.style.display!=="none");_.style.display=e?"flex":"none"}const S=g.createElement("div");Object.assign(S.style,{position:"relative",width:"100%",height:"100%"});const a=g.createElement("canvas");Object.assign(a.style,{width:"100%",height:"100%",display:"block"}),S.appendChild(a),le.appendChild(S);let Ge=null;if(ut>0){let n=function(){if(t){const d=oo(e,y.testDefs,{...C.dieList,onSaveText:C.onSaveText,waferMetadata:$.metadata,metadataFields:ce,ownerDocument:g});if(d)return d}const o=ct(y.testDefs,c.activeTest??0),s=jt(o)?c.logScale??o?.logScale??!1:!1;return so(e,y.testDefs,{plotMode:c.plotMode??"hardBin",activeTest:c.activeTest,hbinDefs:G,sbinDefs:U,binColors:m.binColors,valueColorScheme:c.valueColorScheme,reverseValueScheme:c.reverseValueScheme,logScale:s,colorbarRangeMode:c.colorbarRangeMode,valueRangeDies:y.dies})},i=function(o){const s=g.createElement("button");return s.type="button",Vn(s),Object.assign(s.style,{fontSize:ft.body,padding:`${W.xxs} ${W.sm}`,borderRadius:zn.control,flexShrink:"0",border:`1px solid ${x.menuBorder}`,background:x.menuBg,color:x.text,cursor:"pointer"}),s.textContent=t?"View chart":"View die list",s.addEventListener("click",d=>{d.stopPropagation(),t=!t,s.textContent=t?"View chart":"View die list",o()}),s};const e=y.dies.filter(o=>!Kn(o));let t=!1;if($e){const o=g.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 s=g.createElement("div");Object.assign(s.style,{display:"flex",justifyContent:"space-between",alignItems:"flex-start",gap:W.md});const d=g.createElement("span");Object.assign(d.style,{fontSize:ft.body,color:x.label,lineHeight:An.base}),d.textContent="No die position data for this wafer.",s.appendChild(d);const r=g.createElement("div");Object.assign(r.style,{flex:"1",minHeight:"0",overflow:"auto",display:"flex",flexDirection:"column"}),s.appendChild(i(()=>r.replaceChildren(n()))),o.appendChild(s),o.appendChild(r),S.appendChild(o),Ge=()=>{t||r.replaceChildren(n())}}else{const o=g.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:ft.body,color:x.text,cursor:"pointer",padding:`${W.xs} ${W.md}`,display:"flex",alignItems:"center",justifyContent:"space-between",gap:W.md}),Vn(o,"bare");const s=g.createElement("span");s.textContent=`+${e.length} ${e.length===1?"die":"dies"} without position data`,o.appendChild(s);const d=g.createElement("span");d.textContent="\u25BE",Object.assign(d.style,{fontSize:ft.body,lineHeight:An.none,color:x.label,flexShrink:"0"}),o.appendChild(d),o.setAttribute("aria-expanded","false"),o.setAttribute("aria-label",`${e.length} dies without position data. Click to view.`);let r=null,l=null;Xi(o,f=>{if(d.textContent=f?"\u25B4":"\u25BE",o.setAttribute("aria-expanded",String(f)),f){r=g.createElement("div");const p=o.getBoundingClientRect().height||28;Object.assign(r.style,{position:"absolute",left:"0",right:"0",bottom:`${p}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}),r.addEventListener("click",Q=>Q.stopPropagation());const h=g.createElement("div");Object.assign(h.style,{display:"flex",justifyContent:"flex-end"}),h.appendChild(i(()=>{l&&l.replaceChildren(n())})),r.appendChild(h),l=g.createElement("div"),Object.assign(l.style,{flex:"1",minHeight:"0",overflow:"auto",display:"flex",flexDirection:"column"}),l.appendChild(n()),r.appendChild(l),S.appendChild(r)}else r&&(r.remove(),r=null,l=null)}),S.appendChild(o),Ge=()=>{l&&!t&&l.replaceChildren(n())}}}const{onHover:Ue,onClick:Gn,onSelect:he,onViewOptionsChange:Un,showTooltip:Zn=!0,showToolbar:Le=!0,showIdentity:Zt=!0,toolbarControls:gt="full",showPlotModeSelector:Qn=!0,minZoom:qn=.4,maxZoom:Jn=20,summaryPanel:Te,renderTooltip:Qt,passBins:Ze=[1],showHelpButton:qt=!1,userGuideExtension:ei,onExpand:Jt,showExpandButton:en=!0,zIndex:ti,insights:ht,warnings:tn,viewOptions:ni={},...ae}=C,Oe=ht?.enabled??!1,nn=tn?.display??!0,ii=Ti(ti);let Pe=ae.fallbackFormat,re=C.statsSummary,de=[],on=!1,Qe=null,sn=!1;function mt(){const e=Qi({result:y,statsSummary:re,extra:Qe?[Qe]:[]}),t=e.length!==de.length||e.some((n,i)=>n.code!==de[i]?.code||n.message!==de[i]?.message);de=e,(t||!on)&&(on=!0,tn?.onWarning?.(e))}mt();let yt=y,$=y.wafer,te=y.dies,E=new Set,G=y.hbinDefs,U=y.sbinDefs,ne=y.testDefs,ce=y.metadataFields,ln=y.reticles?.length?y.reticles:void 0,an=y.reticleConfig,rn=y.view?.dataAxisFlip,bt=y.isLotStack??!1,vt=y.aggrMethod,xt=y.lotSize;const oi=Le&>!=="view-only"&&Oe;let Ct=!1,Z=null,V=null,J=null;Zt&&(Z=no(Ut($.metadata??{},Re())??"",$.metadata,{lotStack:Re(),ownerDocument:g}),S.appendChild(Z.metaPanel),Z.isEmpty()||(V=dn(Z.wrap),_.insertBefore(V,_.firstChild),ve()));function dn(e){const t=g.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 bt?{lotSize:xt??1,aggrMethod:vt}:void 0}function si(){if(!Z)return;Z.update(Ut($.metadata??{},Re())??"",$.metadata,Re());const e=V?.isConnected??!1,t=!Z.isEmpty();!t&&e?(V.remove(),V=null):t&&!e&&(V=dn(Z.wrap),V.style.display=Ct?"none":"",_.insertBefore(V,_.firstChild),ve())}const li=[...G??[],...U??[]].some(e=>e.color);let c={plotMode:"hardBin",showDieLabels:!1,showPartialDies:!0,showRingBoundaries:!1,showQuadrantBoundaries:!1,showReticle:!1,showXYIndicator:!1,ringCount:4,rotation:0,flipX:!1,flipY:!1,legendPosition:ae.legendPosition??"default",...ni},z=null,ie=!1,cn=null;function ai(){return Oe?z?Promise.resolve(z):(cn??=import("./insightsTab.js").then(({createInsightsTab:e})=>(z=e({getItems:()=>[{wafer:$,dies:te,hbinDefs:G,sbinDefs:U,testDefs:ne,label:String($.metadata?.waferId??""),statsSummary:re}],getBinColors:()=>m.binColors,passBins:Ze,getRingCount:()=>c.ringCount??4,onSaveImage:C.onSaveImage,onSaveText:C.onSaveText,defaultView:ht?.defaultView,showMetadataStrip:!1,contentInset:ge,backTab:oi?void 0:{label:"Map",onBack:()=>Ie(!1)},onOpenGuide:qt&&!Le?()=>At():void 0,focusTest:t=>{D({plotMode:"value",activeTest:t,highlightBin:void 0}),Ie(!1)},ownerDocument:g}),Object.assign(z.el.style,{position:"absolute",inset:"0",background:x.canvasBg,overflowY:"auto",paddingTop:"0"}),z.el.style.display="none",le.appendChild(z.el),z)),cn):Promise.resolve(null)}let fn=0;const wt=["wheel","touchstart","pointerdown","keydown"];function ri(e,t){if(t<=0)return;let n=!1;const i=[],o=()=>{n=!0;for(const d of i)H.clearTimeout(d);i.length=0;for(const d of wt)e.removeEventListener(d,o)},s=()=>n||!ie?!0:(e.scrollTop=t,e.scrollTop>=t);if(!s()){for(const d of wt)e.addEventListener(d,o,{passive:!0,once:!0});for(const d of[0,50,150,300,600])i.push(H.setTimeout(()=>{s()},d));i.push(H.setTimeout(()=>{for(const d of wt)e.removeEventListener(d,o)},700))}}function Ie(e){if(!Oe)return;const t=ie;ie=e,z&&!e&&t&&(fn=z.el.scrollTop),z&&(z.el.style.display=e?"flex":"none"),F&&(F.style.display=e||$e?"none":"flex"),T&&(T.style.display=e?"none":"flex"),J&&(J.style.display=ye?"none":"flex"),oe&&(oe.style.display="flex"),V&&(V.style.display=Ct?"none":""),ve(),Z&&e&&Z.collapse(),it(),A&&(A.innerHTML=e?jn.wafer:jn.analysis,A.ariaLabel=e?"Back to wafer view":"Insights"),e&&ai().then(n=>{!n||!ie||(n.el.style.display="flex",n.render(),ri(n.el,fn))})}Oe&&ht?.defaultOpen&&queueMicrotask(()=>Ie(!0));let m,pn,Y=null,k=null,St=[],Mt;function un(e){Mt!==e&&(Mt=e,v())}let We=null,Et=ae.legendOffset??{x:0,y:0},He=!1,xe=!1,Fe={x:0,y:0},Dt={x:0,y:0},me=!1,Ce=!1,X="pan",we={x:0,y:0},qe={x:0,y:0},O={x:0,y:0},P={x:0,y:0},Ae=!1,Se=!1;function Ve(){const e=c;m=vi($,te.filter(io),{plotMode:e.plotMode,binColorScheme:e.binColorScheme,valueColorScheme:e.valueColorScheme,reverseValueScheme:e.reverseValueScheme,useDefinedBinColors:e.useDefinedBinColors,binColors:e.binColors??lo(te,{passBins:Ze,binColorScheme:e.binColorScheme,hbinDefs:G,sbinDefs:U,useDefinedBinColors:e.useDefinedBinColors}),passBins:Ze,showDieLabels:e.showDieLabels,showPartialDies:e.showPartialDies,showRingBoundaries:e.showRingBoundaries,showQuadrantBoundaries:e.showQuadrantBoundaries,showReticle:e.showReticle,showXYIndicator:e.showXYIndicator,reticles:ln,ringCount:e.ringCount,highlightBin:e.highlightBin,highlightMetadataValue:e.highlightMetadataValue,activeTest:e.activeTest,activeMetadataKey:e.activeMetadataKey,testDefs:ne,valueRange:e.valueRange,metadataValueOrder:e.metadataValueOrder,logScale:e.logScale,isLotStack:bt,aggregationMethod:vt??e.aggregationMethod,lotSize:xt??e.lotSize,dataAxisFlip:rn,colorbarRangeMode:e.colorbarRangeMode,passFailDisplay:e.passFailDisplay,fallbackFormat:Pe,interactiveTransform:{rotation:e.rotation??0,flipX:e.flipX??!1,flipY:e.flipY??!1}},{hbinDefs:G,sbinDefs:U,metadataFields:ce}),pn=new Map(m.dies.map((n,i)=>[Be(n),i]));const t=e.binColors?null:ao(m.binColors,m.plotMode);t?.message!==Qe?.message&&(Qe=t,mt(),sn&&Bt())}Ve();let N=null,Me=null,Je=null,gn=C.findingsNotice,di={},R=null,fe=null;function ci(e){const{kind:t,index:n}=e.variable;D(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"?(Rt(i.dieKeys),D({highlightBin:i.bin})):(i.kind==="region"||i.kind==="dies")&&Rt(i.dieKeys)}function hn(e){Zi(e,{wafer:$,dies:te,yieldSummary:yt.yield,dataCoverage:yt.dataCoverage,hbinDefs:G,sbinDefs:U,testDefs:ne,statsSummary:re,warnings:nn?de:[],passBins:Ze,ringCount:c.ringCount??4,binColors:m.binColors,plotMode:c.plotMode??"hardBin",metadataShownElsewhere:Zt,fallbackFormat:Pe,activeFindingId:Je,findingsFilter:di,findingsNotice:gn,onFindingsFilterChange:pe,onSaveText:C.onSaveText,metadataFields:ce,dieListOptions:C.dieList,onFindingClick:(t,n)=>{Je===t.id?(Je=null,Rt([]),D({highlightBin:void 0})):(Je=t.id,ci(t)),pe()}})}function pe(){N&&hn(N)}function ze(){R&&hn(R)}if(Te?.placement){const e=Te.placement;N=$t(e,ge,g);const t=S.parentElement,n=S.nextSibling;Me=Gt(S,N,e),t?.insertBefore(Me,n),pe()}else if(re){const e=Te?.defaultOpen??!Le;R=$t("right",ge,g),R.style.display=e?"block":"none";const t=S.parentElement,n=S.nextSibling;fe=Gt(S,R,"right"),t?.insertBefore(fe,n),ze()}const w=Zn?Yn(g):null;let oe=null,L=null,F=null,T=null,et=null,I=null,tt=null,A=null,se=null,nt=null;sn=!0;function Bt(){if(!se||!nt)return;const e=de.length,t=e>0;if(se.style.display=t?"flex":"none",nt.style.display=t?"":"none",!t)return;const n=Ji(de[0]),i=`${e} data ${e===1?"warning":"warnings"}`;se.style.color=n==="error"?x.errText:x.warnText,se.ariaLabel=n==="error"?`${i} \u2014 the map may be positionally wrong`:i}let kt=null,mn=null,Lt=null,Tt=null,Ot=null,Pt=null;function Rt(e){E=new Set(e??[]),he&&he(Ft()),v()}function it(){if(!I)return;const e=!!(N??R);I.style.display=re&&e&&!ie?"flex":"none";const t=N??R,n=t?t.style.display!=="none":!1;re?.hasNotableFindings&&!n?I.style.color=x.findingIndicator:I.dataset.active||(I.style.color=x.icon)}if(Le){let p=function(B){X=B,i(Q,B==="zoom"),i(M,B==="pan"),et&&i(et,B==="select"),a.style.cursor=B==="pan"?"grab":"crosshair"};oe=g.createElement("div"),oe.dataset.wmapToolbar="single",Object.assign(oe.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:zn.control,boxShadow:ki.panel,pointerEvents:"auto"});const e=Yn(g),t=Pi(e),{makeBtn:n,setActive:i,makeSep:o,makeMenuRow:s,makeMenuSection:d,closeOpenMenu:r,getOpenMenu:l,setOpenMenu:f}=t;kt=r,mn=l,g.addEventListener("click",r,!0),F=g.createElement("div"),Object.assign(F.style,{display:$e?"none":"flex",alignItems:"center",gap:"0",flexWrap:"wrap",justifyContent:"flex-end"}),oe.appendChild(F);const h=n("download","Download PNG",ui);F.appendChild(h),F.appendChild(o());const Q=n("zoomMode","Zoom (drag to zoom region)",()=>p("zoom")),De=n("zoomIn","Zoom in",()=>Ee(a.clientWidth/2,a.clientHeight/2,1.2)),ee=n("zoomOut","Zoom out",()=>Ee(a.clientWidth/2,a.clientHeight/2,1/1.2)),ue=n("reset","Reset zoom (double-click)",()=>st());F.appendChild(Q),F.appendChild(De),F.appendChild(ee),F.appendChild(ue),F.appendChild(o());const M=n("pan","Pan (drag to move)",()=>p("pan"));if(F.appendChild(M),et=n("boxSelect","Select (drag to select dies)",()=>p("select")),F.appendChild(et),i(M,!0),gt!=="view-only"){let B=function(u){return u.plotMode!==(c.plotMode??"hardBin")?!1:u.plotMode==="value"?(c.activeTest??0)===(u.activeTest??0):u.plotMode==="metadata"?c.activeMetadataKey===u.activeMetadataKey:!0},Vt=function(u,b){u.activeTest!==void 0?D({plotMode:u.plotMode,activeTest:u.activeTest,activeMetadataKey:void 0,logScale:u.logScale}):u.activeMetadataKey!==void 0?D({plotMode:u.plotMode,activeTest:void 0,activeMetadataKey:u.activeMetadataKey,passFailDisplay:"off"}):D({plotMode:u.plotMode,activeTest:void 0,activeMetadataKey:void 0,passFailDisplay:"off"}),b.remove(),f(null),_e(q,!1)};L=g.createElement("div"),Object.assign(L.style,{display:"flex",alignItems:"center",gap:"0",flexWrap:"wrap",justifyContent:"flex-end"}),oe.appendChild(L),T=g.createElement("div"),Object.assign(T.style,{display:"flex",alignItems:"center",gap:"0"}),L.appendChild(T),T.appendChild(o());const lt=()=>{const u=l();u&&(u.remove(),f(null)),_e(q,!1)},q=n("mode","Plot mode",()=>{if(l()){lt();return}const u=te,b=m.testDefs,{testEntries:dt,binEntries:be,stackedEntries:Ne}=$i(u,b,{includeStacked:m.isLotStack}),Xt=(ce??[]).filter(Ke=>Gi(u,Ke.key)).map(Ui),je=Ri(q.getBoundingClientRect(),dt,be,Ne,B,Vt,{makeMenuRow:s,makeMenuSection:d},c.plotMode??"hardBin",q.ownerDocument.defaultView??window,Xt);Xn(q).appendChild(je),f(je),_e(q,!0),Nn(je,q,lt)});_e(q,!1);const{btn:at,sync:Xe}=Hi(t,()=>({...c,plotMode:c.plotMode??"hardBin"}),()=>li,D);Tt=Xe,Tt();const zt=Vi(t,()=>{const u=!!m.hasReticle,b=(c.plotMode??"hardBin")==="value",{testNumber:dt}=Nt(c.activeTest??0,m.testDefs),be=ct(m.testDefs,dt),Ne=b&&be!==void 0&&!jt(be),Xt=b&&!Ne&&(be?.limitLow!==void 0||be?.limitHigh!==void 0),je=b&&!Ne&&m.dies.some(Ke=>Di(Ke,dt,be)!==void 0);return ji(c,u,{functionalActive:Ne,hasLimits:Xt,hasRecorded:je,binMode:(c.plotMode??"hardBin")==="hardBin"||(c.plotMode??"hardBin")==="softBin"},Ke=>D(Ke))},()=>Ki(c)),{btn:Yt,sync:gi}=Ai(t,()=>c,u=>D({legendPosition:u}));Lt=gi,Lt();const Hn=()=>{const{testNumber:u}=Nt(c.activeTest??0,ne),b=ct(ne,u);return b!==void 0&&!jt(b)},{btn:hi,sync:mi}=Fi(t,()=>({...c,functionalActive:Hn()}),u=>D(u));Ot=mi,Ot();const yi=()=>{const{testNumber:u}=Nt(c.activeTest??0,ne),b=ct(ne,u);return b!==void 0&&(b.limitLow!==void 0||b.limitHigh!==void 0)},rt=n("specRange","Colorbar range: spec limits",()=>{const u=c.colorbarRangeMode==="data"?"spec":"data";D({colorbarRangeMode:u})});Pt=()=>{const u=c.plotMode==="value"&&yi()&&Ni(c)==="off"&&!Hn();rt.style.display=u?"":"none";const b=(c.colorbarRangeMode??"spec")==="spec";i(rt,b),rt.ariaLabel=b?"Colorbar range: spec limits (click for data range)":"Colorbar range: data range (click for spec limits)"},Pt();const bi=zi(t,()=>c,u=>D(u));Qn&&T.appendChild(q),T.appendChild(at),T.appendChild(hi),T.appendChild(rt),$e||(T.appendChild(o()),T.appendChild(zt),T.appendChild(o()),T.appendChild(Yt),T.appendChild(o()),T.appendChild(bi)),re&&(I=n("findings","Summary panel",()=>{const u=N??R;if(!u)return;const b=u.style.display!=="none";u.style.display=b?"none":"block",i(I,!b),it()}),L.appendChild(o()),L.appendChild(I),R?.style.display!=="none"&&i(I,!0),it()),nn&&(nt=o(),se=n("warning","Data warnings",()=>{const u=l();if(r(new MouseEvent("click")),u)return;const b=qi(se.getBoundingClientRect(),de,H);Xn(le).appendChild(b),f(b),Nn(b,se,()=>r(new MouseEvent("click")))}),_e(se,!1),L.appendChild(nt),L.appendChild(se),Bt()),Oe&&(L.appendChild(o()),A=n("analysis","Insights",()=>{Ie(!ie),i(A,ie)}),A.dataset.wmapInsightsBtn="1",L.appendChild(A)),en&&(L.appendChild(o()),J=n("expand","Expand (E)",Jt??yn),L.appendChild(J)),qt&&(L.appendChild(o()),tt=n("help","User guide",()=>At()),L.appendChild(tt))}_.appendChild(oe),ve()}let ye=null;function yn(){ye&&(ye.close(),ye=null);const e=le;e.style.flex="1",e.style.minWidth="0",e.style.minHeight="0";const t=e.style.maxWidth,n=e.style.maxHeight;e.style.maxWidth="none",e.style.maxHeight="none";const i=Ut($.metadata??{},Re()),o=_.childElementCount>0?[_,e]:[e],s=Ii(o,{ownerDocument:g,boxSize:ie?{width:"min(96vw, 1600px)",height:"min(92vh, 1000px)"}:void 0,onClosed:()=>{ye=null,e.style.maxWidth=t,e.style.maxHeight=n,J&&(J.style.display="flex"),ie||a.focus({preventScroll:!0})}});s&&(s.box.setAttribute("aria-label",i??"Expanded wafer map"),o.length>1&&(s.contentWrap.style.flexDirection="column"),ye=s,J&&(J.style.display="none"))}function bn(e){const t=c.plotMode;c={...c,...e},e.plotMode!==void 0&&e.plotMode,Object.keys(e).every(s=>s==="legendPosition"||s==="showLegend"||s==="markFailingDies")||Ve(),Lt?.(),Tt?.(),Ot?.(),Pt?.(),v();const i=e.plotMode!==void 0&&e.plotMode!==t,o=COLOR_KEYS.some(s=>s in e);(o||i)&&(pe(),ze()),(o||i||e.activeTest!==void 0||e.logScale!==void 0||e.colorbarRangeMode!==void 0)&&Ge?.()}function D(e){bn(e);const t=Object.keys(e);Un?.(c,t,classifyChanged(t))}let It=!1;function Wt(){It||(It=!0,_t(()=>{It=!1,v()},H))}function v(){const e=k??void 0,t=m.dies[0],n=t?{x:t.width,y:t.height}:ae.diePitchMm,i=Math.floor(a.clientWidth||a.width),o=!!(G?.length||U?.length||m.dies.some(h=>h.hbin!=null||h.sbin!=null)),s=c.legendPosition??"default",d=c.showLegend??!0,r=s==="default"||s==="compact",l=(ae.colorbarWidth??16)+28,f=o&&r?s!=="default"?Math.max(Fn,l):i<Mi?0:i<Si?Math.max(wi,l):Math.max(Fn,l):void 0,p=Ci(a,m,{...ae,topClearance:0,minRightReserve:d?f:0,showColorbar:d&&(ae.showColorbar??!0),markFailingDies:c.markFailingDies??!1,legendPosition:s,legendOffset:Et,diePitchMm:n,fallbackFormat:Pe,showAxes:ae.showAxes??k!==null,viewport:e,activeBin:c.plotMode==="metadata"?c.highlightMetadataValue:c.highlightBin,hoverBin:Mt,hbinDefs:G,sbinDefs:U,metadataFields:ce});St=p.binLegendRows,We=p.legendBox??null,k===null&&(Y=p.viewport),E.size>0&&fi(),Ce&&pi()}function fi(){const e=j();if(!e)return;const t=a.getContext("2d"),n=m.hoverPoints,i=m.rectangles[0],o=i?i.width/2*e.ppm:e.ppm*.5,s=i?i.height/2*e.ppm:e.ppm*.5,d=Math.max(1,Math.min(3,o*.08)),r=o-d,l=s-d,f=[];for(const p of E){const h=pn.get(p);h!==void 0&&f.push({sx:e.originX+n[h].x*e.ppm,sy:e.originY-n[h].y*e.ppm})}if(f.length){t.save(),t.setLineDash([]),t.fillStyle="rgba(0,0,0,0.12)",t.beginPath();for(const{sx:p,sy:h}of f)t.rect(p-r,h-l,r*2,l*2);t.fill(),t.strokeStyle="rgba(255,255,255,0.9)",t.lineWidth=3,t.beginPath();for(const{sx:p,sy:h}of f)t.rect(p-r,h-l,r*2,l*2);t.stroke(),t.strokeStyle="rgba(0,0,0,0.9)",t.lineWidth=1.5,t.beginPath();for(const{sx:p,sy:h}of f)t.rect(p-r,h-l,r*2,l*2);t.stroke(),t.restore()}}function pi(){const e=a.getContext("2d"),t=Math.min(O.x,P.x),n=Math.min(O.y,P.y),i=Math.abs(P.x-O.x),o=Math.abs(P.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(){a.toBlob(e=>{e&&Yi(e,C.downloadFilename??"wafermap",C.onSaveImage)})}function vn(e){return Y?Math.max(Y.ppm*qn,Math.min(Y.ppm*Jn,e)):e}function Ee(e,t,n){const i=k??Y;if(!i)return;const o=vn(i.ppm*n),s=o/i.ppm,d=e-(e-i.originX)*s,r=t-(t-i.originY)*s,l=(Y?.snapDist??1)/(o/(Y?.ppm??o));k={originX:d,originY:r,ppm:o,snapDist:l},v()}function j(){return k??Y}function xn(e){if(e.ctrlKey||e.metaKey){e.preventDefault();const t=a.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=j(),n=k.snapDist;k={originX:t.originX-e.deltaX,originY:t.originY-e.deltaY,ppm:t.ppm,snapDist:n},v()}}function Cn(e,t,n){return e>=n.x&&e<n.x+n.w&&t>=n.y&&t<n.y+n.h}function wn(e){if(e.button!==0||!j())return;a.focus({preventScroll:!0}),a.setPointerCapture(e.pointerId);const t=a.getBoundingClientRect(),n=e.clientX-t.left,i=e.clientY-t.top;if(We&&c.legendPosition==="floating"&&Cn(n,i,We)){xe=!0,Fe={x:n,y:i},Dt={...Et};return}if(Ae&&X!=="pan"){Se=!0,me=!0,we={x:n,y:i},qe={x:j().originX,y:j().originY},a.style.cursor="grabbing";return}if(X==="zoom"||X==="select"){Ce=!0,O=P={x:n,y:i};return}me=!0,we={x:n,y:i},qe={x:j().originX,y:j().originY},a.style.cursor="grabbing"}function Sn(e){const t=a.getBoundingClientRect(),n=e.clientX-t.left,i=e.clientY-t.top;if(Ce){P={x:n,y:i},Wt();return}if(xe){const p=n-Fe.x,h=i-Fe.y;p*p+h*h>16&&(xe=!1,He=!0,a.style.cursor="grabbing")}if(He){Et={x:Dt.x+(n-Fe.x),y:Dt.y+(i-Fe.y)},Wt();return}if(me){const p=j(),h=k?.snapDist??Y?.snapDist??1;k={originX:qe.x+(n-we.x),originY:qe.y+(i-we.y),ppm:p.ppm,snapDist:h},Wt();return}const o=j();if(!o)return;const s=(n-o.originX)/o.ppm,d=(o.originY-i)/o.ppm,l=Bn(s,d,o.snapDist)?.die??null,f=St.find(p=>n>=p.x&&n<p.x+p.w&&i>=p.y&&i<p.y+p.h);if(un(f?f.bin:void 0),f){a.style.cursor="pointer",w&&(w.innerHTML=f.label??`Bin ${f.bin}`,w.style.display="block",Kt(w,a,e.clientX,e.clientY)),Ue?.(null,e);return}if(X==="pan"&&(a.style.cursor=l?"crosshair":"grab"),w)if(l)if(Qt){const p=Qt(l);p===null?w.style.display="none":(typeof p=="string"?w.innerHTML=p:(w.innerHTML="",w.appendChild(p)),w.style.display="block",Kt(w,a,e.clientX,e.clientY))}else w.innerHTML=xi(l,m.plotMode,{testDefs:ne,hbinDefs:G,sbinDefs:U,fallbackFormat:Pe,aggrMethod:m.aggrMethod,lotSize:m.lotSize,metadataFields:ce,activeTest:m.activeTest,reticleConfig:an}),w.style.display="block",Kt(w,a,e.clientX,e.clientY);else w.style.display="none";Ue?.(l,e)}function Mn(e){const t=a.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,P={x:n,y:i};const r=n-O.x,l=i-O.y,f=j();if(X==="zoom"){if(r*r+l*l<25)Ee(n,i,2);else if(f){const p=Math.min(O.x,P.x),h=Math.max(O.x,P.x),Q=Math.min(O.y,P.y),De=Math.max(O.y,P.y),ee=h-p,ue=De-Q;if(ee>4&&ue>4){const M=a.clientWidth,B=a.clientHeight,Vt=M/ee,lt=B/ue,q=Math.min(Vt,lt),at=vn(f.ppm*q),Xe=at/f.ppm,zt=(p+h)/2,Yt=(Q+De)/2;k={originX:M/2-(zt-f.originX)*Xe,originY:B/2-(Yt-f.originY)*Xe,ppm:at,snapDist:f.snapDist/Xe}}}v(),a.style.cursor="crosshair";return}if(r*r+l*l<25)Ht(n,i,o,e);else if(f){const p=(Math.min(O.x,P.x)-f.originX)/f.ppm,h=(Math.max(O.x,P.x)-f.originX)/f.ppm,Q=(f.originY-Math.max(O.y,P.y))/f.ppm,De=(f.originY-Math.min(O.y,P.y))/f.ppm,ee=m.hoverPoints,ue=[];for(let M=0;M<ee.length;M++)if(ee[M].x>=p&&ee[M].x<=h&&ee[M].y>=Q&&ee[M].y<=De){const B=m.dies[M];B&&ue.push(B)}if(o)for(const M of ue){const B=Be(M);E.has(B)?E.delete(B):E.add(B)}else E=new Set(ue.map(M=>Be(M)));he?.(Ft())}v(),a.style.cursor="crosshair";return}if(xe){xe=!1,Ht(n,i,o,e);return}if(He){He=!1,a.style.cursor="grab";return}if(!me)return;if(me=!1,Se){Se=!1,a.style.cursor=Ae||X==="pan"?"grab":"crosshair";return}a.style.cursor=X==="pan"?"grab":"crosshair";const s=n-we.x,d=i-we.y;s*s+d*d<25&&Ht(n,i,o,e)}function Ht(e,t,n,i){for(const r of St)if(e>=r.x&&e<r.x+r.w&&t>=r.y&&t<r.y+r.h){if(typeof r.bin=="number"){const l=c.highlightBin===r.bin?void 0:r.bin;D({highlightBin:l})}else{const l=c.highlightMetadataValue===r.bin?void 0:r.bin;D({highlightMetadataValue:l})}return}if(We&&Cn(e,t,We))return;const o=j();if(!o)return;const d=Bn((e-o.originX)/o.ppm,(o.originY-t)/o.ppm,o.snapDist)?.die??null;if(d){Gn?.(d,i);const r=Be(d);n?E.has(r)?E.delete(r):E.add(r):E=new Set([r]),he?.(Ft()),v()}else n||(E=new Set,he?.([]),v())}function Ft(){const e=[],t=m.hoverPoints;for(let n=0;n<t.length;n++){const i=m.dies[n];i&&E.has(Be(i))&&e.push(i)}return e}function En(){un(void 0),w&&pt(g),Ue?.(null,new MouseEvent("mouseleave")),a.style.cursor=X==="pan"?"grab":"crosshair"}function Dn(){me=!1,Se=!1,Ce=!1,xe=!1,He=!1,w&&pt(g),Ue?.(null,new MouseEvent("mouseleave")),a.style.cursor=X==="pan"?"grab":"crosshair",v()}function Bn(e,t,n){const i=m.hoverPoints,o=m.rectangles;for(let l=0;l<o.length;l++){const f=o[l];if(Math.abs(e-f.x)<=f.width/2&&Math.abs(t-f.y)<=f.height/2){const p=m.dies[l];return p?{die:p,index:l}:null}}let s=null,d=-1,r=n*n;for(let l=0;l<i.length;l++){const f=i[l].x-e,p=i[l].y-t,h=f*f+p*p;h<r&&(r=h,s=m.dies[l]??null,d=l)}return s?{die:s,index:d}:null}const kn=new H.ResizeObserver(()=>{Y=null,k=null,v()});kn.observe(a),C.height==null&&$n<=0&&_t(()=>_t(()=>{K.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=H.matchMedia(`(resolution: ${H.devicePixelRatio}dppx)`);const ot=()=>{Ye.removeEventListener("change",ot),Ye=H.matchMedia(`(resolution: ${H.devicePixelRatio}dppx)`),Ye.addEventListener("change",ot),v()};Ye.addEventListener("change",ot);const Ln=H.matchMedia("(prefers-color-scheme: dark)"),Tn=()=>v();Ln.addEventListener("change",Tn);const On=()=>{w&&pt(g)};H.addEventListener("blur",On);function Pn(e){if(e.key==="Escape"&&E.size>0&&(E=new Set,he?.([]),v()),(e.key==="e"||e.key==="E")&>!=="view-only"&&en&&(e.stopPropagation(),(Jt??yn)()),(e.ctrlKey||e.metaKey)&&(e.key==="="||e.key==="+"?(e.preventDefault(),Ee(a.clientWidth/2,a.clientHeight/2,1.2)):e.key==="-"?(e.preventDefault(),Ee(a.clientWidth/2,a.clientHeight/2,1/1.2)):e.key==="0"&&(e.preventDefault(),st())),!e.ctrlKey&&!e.metaKey&&!e.shiftKey){const n=j();if(n){const i=k?.snapDist??Y?.snapDist??1;let o=0,s=0;e.key==="ArrowLeft"&&(o=20,e.preventDefault()),e.key==="ArrowRight"&&(o=-20,e.preventDefault()),e.key==="ArrowUp"&&(s=20,e.preventDefault()),e.key==="ArrowDown"&&(s=-20,e.preventDefault()),(o||s)&&(k={originX:n.originX+o,originY:n.originY+s,ppm:n.ppm,snapDist:i},v())}e.key===" "&&!Ae&&(e.preventDefault(),Ae=!0,X!=="pan"&&(a.style.cursor="grab"))}}function Rn(e){e.key===" "&&(Ae=!1,Se&&(me=!1,Se=!1),a.style.cursor=X==="pan"?"grab":"crosshair")}a.style.cursor="grab",a.setAttribute("tabindex","0"),a.addEventListener("wheel",xn,{passive:!1}),a.addEventListener("pointerdown",wn),a.addEventListener("pointermove",Sn),a.addEventListener("pointerup",Mn),a.addEventListener("pointerleave",En),a.addEventListener("pointercancel",Dn);const In=()=>st();a.addEventListener("dblclick",In),a.addEventListener("keydown",Pn),a.addEventListener("keyup",Rn);const Wn=e=>{e.stopPropagation()};a.addEventListener("click",Wn),a.clientWidth,v(),Ge?.();function st(){Y=null,k=null,v()}function At(){import("./userGuideHtml.js").then(e=>Wi({buildWaferMap:Ei,renderWaferMap,renderWaferGallery:void 0,analyzeWaferMap:Bi},e.USER_GUIDE_HTML,ei,K))}return ve(),{setDies(e){te=e,Ve(),v(),N&&pe()},setResult(e){yt=e,$=e.wafer,te=e.dies,G=e.hbinDefs,U=e.sbinDefs,ne=e.testDefs,ce=e.metadataFields,ln=e.reticles?.length?e.reticles:void 0,an=e.reticleConfig,rn=e.view?.dataAxisFlip,bt=e.isLotStack,vt=e.aggrMethod,xt=e.lotSize,si(),Ve(),v(),N&&pe()},setOptions(e){bn(e)},getOptions(){return{...c}},resetZoom:st,setSelection(e){E=new Set(e.map(t=>Be(t))),v()},clearSelection(){E=new Set,he?.([]),v()},setFallbackFormat(e){Pe=e,Ve(),v()},setFindingsNotice(e){gn=e,N?pe():R&&ze()},setStatsSummary(e){if(re=e,mt(),Bt(),N)pe();else if(R)ze();else if(e&&!Te?.placement){const t=Te?.defaultOpen??!Le;R=$t("right",ge,g),R.style.display=t?"block":"none";const n=S.parentElement,i=S.nextSibling;fe=Gt(S,R,"right"),n?.insertBefore(fe,i),ze()}it()},setSummaryVisible(e){I&&(I.style.display=e?"flex":"none")},setViewControlsVisible(e){L&&(L.style.display=e?"flex":"none")},setExpandVisible(e){J&&(J.style.display=e?"flex":"none")},setHelpButtonVisible(e){tt&&(tt.style.display=e?"flex":"none")},setIdentityVisible(e){Ct=!e,V&&(V.style.display=e?"":"none"),ve()},openUserGuide:At,setInsightsOpen(e){Ie(e),A&&(e?(A.dataset.active="1",A.style.background=x.bgActive,A.style.color=x.iconActive):(delete A.dataset.active,A.style.background="transparent",A.style.color=x.icon))},closeSummaryPanel(){const e=N??R;!e||e.style.display==="none"||(e.style.display="none",I&&(delete I.dataset.active,I.style.background="transparent",I.style.color=x.icon))},setTooltipParent(e){w&&Oi(e)},getActiveLegend(){const e=c.plotMode;if(e==="metadata"){const s=c.activeMetadataKey;if(!s)return null;const d=ce?.find(l=>l.key===s),r=[...new Set(te.map(l=>l.metadata?.[s]).filter(l=>l!=null&&(typeof l=="string"||typeof l=="number"||typeof l=="boolean")).map(String))].sort();return r.length?r.map((l,f)=>{const p=d?.values?.find(Q=>Q.value===l),h=p?.color??eo(f);return{bin:l,name:p?.label??l,color:h}}):null}if(e!=="hardBin"&&e!=="softBin")return null;const t=e==="hardBin",n=t?G:U,i=[...new Set(te.map(s=>t?s.hbin:s.sbin).filter(s=>s!==void 0))].sort((s,d)=>s-d);if(!i.length)return null;const o=t?m.binColors.hard:m.binColors.soft;return i.map(s=>{const d=n?.find(r=>r.bin===s);return{bin:s,name:d?.name??`Bin ${s}`,color:o.get(s)??to}})},destroy(){ye?.close(),mn?.()?.remove(),kt&&g.removeEventListener("click",kt,!0),a.removeEventListener("wheel",xn),a.removeEventListener("pointerdown",wn),a.removeEventListener("pointermove",Sn),a.removeEventListener("pointerup",Mn),a.removeEventListener("pointerleave",En),a.removeEventListener("pointercancel",Dn),a.removeEventListener("dblclick",In),a.removeEventListener("keydown",Pn),a.removeEventListener("keyup",Rn),a.removeEventListener("click",Wn),kn.disconnect(),Ye.removeEventListener("change",ot),Ln.removeEventListener("change",Tn),H.removeEventListener("blur",On),ii(),w&&pt(g),oe?.remove(),Me&&(Me.parentElement?.insertBefore(S,Me),Me.remove()),fe&&(fe.parentElement?.insertBefore(S,fe),fe.remove()),S.remove(),a.style.cursor="",z?.destroy(),Z?.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';
|
|
@@ -90,19 +91,19 @@ export declare function buildYieldSection(yieldSummary: YieldSummary, dataCovera
|
|
|
90
91
|
}, passBins?: number[]): HTMLDivElement;
|
|
91
92
|
export declare function buildBinSection(dies: Die[], binDefs: BinDef[] | undefined, mode: 'hard' | 'soft',
|
|
92
93
|
/**
|
|
93
|
-
* The map's resolved
|
|
94
|
-
* so bars match die fills
|
|
95
|
-
*
|
|
94
|
+
* The map's resolved bin colours (`View.binColors`) — colours AND pass
|
|
95
|
+
* verdicts, so bars match die fills and pass rows sit where the map's legend
|
|
96
|
+
* puts them. Omitted ⇒ resolved here from `dies` — never a second rule.
|
|
96
97
|
*/
|
|
97
|
-
binColors?:
|
|
98
|
+
binColors?: BinColors,
|
|
98
99
|
/**
|
|
99
100
|
* Precomputed counts (e.g. `StatsSummary.stats.hardBinCounts`/`.softBinCounts`,
|
|
100
101
|
* already scoped to the yield-eligible population) — used directly instead
|
|
101
102
|
* of re-walking `dies` when supplied.
|
|
102
103
|
*/
|
|
103
104
|
precomputedCounts?: Record<number, number>,
|
|
104
|
-
/**
|
|
105
|
-
passBins?: number[]): HTMLDivElement | null;
|
|
105
|
+
/** Used only to resolve colours and verdicts when `binColors` is omitted. */
|
|
106
|
+
passBins?: readonly number[]): HTMLDivElement | null;
|
|
106
107
|
/**
|
|
107
108
|
* The panels' bin section: identical bars to `buildBinSection`, wrapped in a
|
|
108
109
|
* collapsible shell with a Hard/Soft selector.
|
|
@@ -134,7 +135,7 @@ export declare function buildBinBreakdownSection(params: {
|
|
|
134
135
|
* precomputed bin counts exist (`hardBinCounts`/`softBinCounts` are
|
|
135
136
|
* per-wafer only), so this scans the pooled `Die[]` directly, same as
|
|
136
137
|
* `buildBinSection` does when it has no `precomputedCounts`. */
|
|
137
|
-
export declare function buildLotBinSection(allDies: Die[], binDefs: BinDef[] | undefined, mode: 'hard' | 'soft', binColors?:
|
|
138
|
+
export declare function buildLotBinSection(allDies: Die[], binDefs: BinDef[] | undefined, mode: 'hard' | 'soft', binColors?: BinColors): HTMLDivElement | null;
|
|
138
139
|
/**
|
|
139
140
|
* Region yield as ONE section with a Ring/Quadrant selector, replacing the two
|
|
140
141
|
* always-on stacked sections (`Ring Yield` + `Quadrant Yield`) this used to render.
|
|
@@ -155,7 +156,8 @@ export declare function buildRegionYieldPanelSection(params: {
|
|
|
155
156
|
diesByWafer: Die[][];
|
|
156
157
|
allWafers: Wafer[];
|
|
157
158
|
ringCount: number;
|
|
158
|
-
|
|
159
|
+
/** One set for every wafer, or a lookup by index into `allWafers` — see `buildRegionYieldData`. */
|
|
160
|
+
passBins: readonly number[] | ((waferIndex: number) => readonly number[]);
|
|
159
161
|
panel?: HTMLElement;
|
|
160
162
|
}): HTMLDivElement | null;
|
|
161
163
|
/** Lot overview — wafer count and mean (unweighted arithmetic mean of each
|
|
@@ -461,13 +463,29 @@ export declare function renderWaferSummaryContent(panel: HTMLDivElement, params:
|
|
|
461
463
|
metadataShownElsewhere?: boolean;
|
|
462
464
|
}): void;
|
|
463
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[];
|
|
464
485
|
export declare function renderLotSummaryContent(panel: HTMLDivElement, params: {
|
|
465
486
|
lotSummary: LotStatsSummary;
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
wafer?: Wafer;
|
|
469
|
-
dies?: Die[];
|
|
470
|
-
statsSummary?: StatsSummary;
|
|
487
|
+
/** `passBins` on an item is that wafer's own (`WaferMapResult.passBins`) and wins over the top-level fallback. */
|
|
488
|
+
items: Array<ReportItem & {
|
|
471
489
|
metadataFields?: MetadataFieldDef[];
|
|
472
490
|
} | null>;
|
|
473
491
|
hbinDefs?: BinDef[];
|