diff --git a/packages/nimble-components/src/wafer-map/index.ts b/packages/nimble-components/src/wafer-map/index.ts index b90c94f6ee..c721e5242e 100644 --- a/packages/nimble-components/src/wafer-map/index.ts +++ b/packages/nimble-components/src/wafer-map/index.ts @@ -11,7 +11,6 @@ import { styles } from './styles'; import { DataManager } from './modules/data-manager'; import { RenderingModule } from './modules/rendering'; import { EventCoordinator } from './modules/event-coordinator'; -import { EventCoordinator as ExperimentalEventCoordinator } from './modules/experimental/event-coordinator'; import { HoverDie, HoverDieOpacity, @@ -24,7 +23,7 @@ import { } from './types'; import { WaferMapUpdateTracker } from './modules/wafer-map-update-tracker'; import { WaferMapValidator } from './modules/wafer-map-validator'; -import { WorkerRenderer } from './modules/worker-renderer'; +import { WorkerRenderer } from './modules/experimental/worker-renderer'; declare global { interface HTMLElementTagNameMap { @@ -157,12 +156,7 @@ export class WaferMap extends FoundationElement { values: [] }; - private readonly stableEventCoordinator = new ExperimentalEventCoordinator( - this - ); - - private readonly experimentalEventCoordinator = new EventCoordinator(this); - private eventCoordinator: EventCoordinator | ExperimentalEventCoordinator = this.stableEventCoordinator; + private readonly eventCoordinator = new EventCoordinator(this); private readonly resizeObserver = this.createResizeObserver(); private readonly waferMapValidator = new WaferMapValidator(this); @@ -198,8 +192,12 @@ export class WaferMap extends FoundationElement { if (this.validity.invalidDiesTableSchema) { return; } + this.renderer = this.diesTable === undefined + ? this.mainRenderer + : this.workerRenderer; if (this.waferMapUpdateTracker.requiresEventsUpdate) { this.eventCoordinator.detachEvents(); + this.eventCoordinator.setStrategy(); if (this.waferMapUpdateTracker.requiresContainerDimensionsUpdate) { this.dataManager.updateContainerDimensions(); this.renderer.updateSortedDiesAndDrawWafer(); @@ -299,25 +297,11 @@ export class WaferMap extends FoundationElement { private diesChanged(): void { this.waferMapUpdateTracker.track('dies'); - this.renderer = this.diesTable === undefined - ? this.mainRenderer - : this.workerRenderer; - this.eventCoordinator?.detachEvents(); - this.eventCoordinator = this.diesTable === undefined - ? this.stableEventCoordinator - : this.experimentalEventCoordinator; this.waferMapUpdateTracker.queueUpdate(); } private diesTableChanged(): void { this.waferMapUpdateTracker.track('dies'); - this.renderer = this.diesTable === undefined - ? this.mainRenderer - : this.workerRenderer; - this.eventCoordinator?.detachEvents(); - this.eventCoordinator = this.diesTable === undefined - ? this.stableEventCoordinator - : this.experimentalEventCoordinator; this.waferMapUpdateTracker.queueUpdate(); } diff --git a/packages/nimble-components/src/wafer-map/modules/event-coordinator.ts b/packages/nimble-components/src/wafer-map/modules/event-coordinator.ts index 26d86f23b0..1e95778afc 100644 --- a/packages/nimble-components/src/wafer-map/modules/event-coordinator.ts +++ b/packages/nimble-components/src/wafer-map/modules/event-coordinator.ts @@ -2,6 +2,7 @@ import type { WaferMapDie } from '../types'; import { ZoomHandler } from './zoom-handler'; import type { WaferMap } from '..'; import { HoverHandler } from './hover-handler'; +import { HoverHandler as ExpHoverHandler } from './experimental/hover-handler'; export interface EventCoordinatorCallbacks { dieSelected: (die: WaferMapDie) => void; @@ -12,26 +13,35 @@ export interface EventCoordinatorCallbacks { */ export class EventCoordinator { private readonly zoomHandler; - private readonly hoverHandler; + private readonly stableHoverHandler; + private readonly expHoverHandler; + private hoverHandler: HoverHandler | ExpHoverHandler; public constructor(private readonly wafermap: WaferMap) { this.zoomHandler = new ZoomHandler(wafermap); - this.hoverHandler = new HoverHandler(wafermap); + this.stableHoverHandler = new HoverHandler(wafermap); + this.expHoverHandler = new ExpHoverHandler(wafermap); + this.hoverHandler = this.stableHoverHandler; + } + + public setStrategy(): void { + this.hoverHandler = this.wafermap.diesTable === undefined + ? this.stableHoverHandler + : this.expHoverHandler; } public attachEvents(): void { this.zoomHandler.createZoomBehavior(); this.wafermap.addEventListener('mousemove', this.onMouseMove); this.wafermap.addEventListener('mouseout', this.onMouseOut); - this.wafermap.canvas.addEventListener('wheel', this.onWheelMove, { + this.wafermap.addEventListener('wheel', this.onWheelMove, { passive: false }); } public detachEvents(): void { - this.zoomHandler.removeZoomBehavior(); this.wafermap.removeEventListener('mousemove', this.onMouseMove); this.wafermap.removeEventListener('mouseout', this.onMouseOut); - this.wafermap.canvas.removeEventListener('wheel', this.onWheelMove); + this.wafermap.removeEventListener('wheel', this.onWheelMove); } private readonly onWheelMove = (event: Event): void => { diff --git a/packages/nimble-components/src/wafer-map/modules/experimental/event-coordinator.ts b/packages/nimble-components/src/wafer-map/modules/experimental/event-coordinator.ts deleted file mode 100644 index cb314208f3..0000000000 --- a/packages/nimble-components/src/wafer-map/modules/experimental/event-coordinator.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { ZoomHandler } from './zoom-handler'; -import type { WaferMap } from '../..'; -import { HoverHandler } from './hover-handler'; - -/** - * EventCoordinator deals with user interactions and events - */ -export class EventCoordinator { - private readonly zoomHandler; - private readonly hoverHandler; - public constructor(private readonly wafermap: WaferMap) { - this.zoomHandler = new ZoomHandler(wafermap); - this.hoverHandler = new HoverHandler(wafermap); - } - - public attachEvents(): void { - this.zoomHandler.createZoomBehavior(); - this.wafermap.addEventListener('mousemove', this.onMouseMove); - this.wafermap.addEventListener('mouseout', this.onMouseOut); - this.wafermap.addEventListener('wheel', this.onWheelMove, { - passive: false - }); - } - - public detachEvents(): void { - this.zoomHandler.removeZoomBehavior(); - this.wafermap.removeEventListener('mousemove', this.onMouseMove); - this.wafermap.removeEventListener('mouseout', this.onMouseOut); - this.wafermap.removeEventListener('wheel', this.onWheelMove); - } - - private readonly onWheelMove = (event: Event): void => { - event.preventDefault(); - }; - - private readonly onMouseMove = (event: MouseEvent): void => { - this.hoverHandler.mousemove(event); - }; - - private readonly onMouseOut = (): void => { - this.hoverHandler.mouseout(); - }; -} diff --git a/packages/nimble-components/src/wafer-map/modules/experimental/hover-handler.ts b/packages/nimble-components/src/wafer-map/modules/experimental/hover-handler.ts index a074d18621..843956cf94 100644 --- a/packages/nimble-components/src/wafer-map/modules/experimental/hover-handler.ts +++ b/packages/nimble-components/src/wafer-map/modules/experimental/hover-handler.ts @@ -1,4 +1,5 @@ import { fromArrow } from 'arquero'; +import type ColumnTable from 'arquero/dist/types/table/column-table'; import type { WaferMap } from '../..'; import { PointCoordinates, WaferMapOriginLocation } from '../../types'; @@ -24,12 +25,17 @@ export class HoverHandler { x: invertedPoint[0], y: invertedPoint[1] }); - const table = fromArrow(this.wafermap.diesTable); + const table = fromArrow(this.wafermap.diesTable).params({ + dieCoordinates + }) as ColumnTable; const indices = table .filter( - (row: { colIndex: number, rowIndex: number }) => row.colIndex === dieCoordinates.x - && row.rowIndex === dieCoordinates.y + ( + row: { colIndex: number, rowIndex: number }, + params: { dieCoordinates: { x: number, y: number } } + ) => row.colIndex === params.dieCoordinates.x + && row.rowIndex === params.dieCoordinates.y ) .indices(); diff --git a/packages/nimble-components/src/wafer-map/modules/worker-renderer.ts b/packages/nimble-components/src/wafer-map/modules/experimental/worker-renderer.ts similarity index 95% rename from packages/nimble-components/src/wafer-map/modules/worker-renderer.ts rename to packages/nimble-components/src/wafer-map/modules/experimental/worker-renderer.ts index 24dbcc8a73..5556c7bfe2 100644 --- a/packages/nimble-components/src/wafer-map/modules/worker-renderer.ts +++ b/packages/nimble-components/src/wafer-map/modules/experimental/worker-renderer.ts @@ -1,5 +1,5 @@ -import type { WaferMap } from '..'; -import { HoverDieOpacity } from '../types'; +import type { WaferMap } from '../..'; +import { HoverDieOpacity } from '../../types'; /** * Responsible for drawing the dies inside the wafer map, adding dieText and scaling the canvas diff --git a/packages/nimble-components/src/wafer-map/modules/experimental/zoom-handler.ts b/packages/nimble-components/src/wafer-map/modules/experimental/zoom-handler.ts deleted file mode 100644 index 020d1f591d..0000000000 --- a/packages/nimble-components/src/wafer-map/modules/experimental/zoom-handler.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { select } from 'd3-selection'; -import { zoom, ZoomTransform } from 'd3-zoom'; -import type { WaferMap } from '../..'; - -interface ZoomEvent { - transform: ZoomTransform; -} - -/** - * ZoomHandler deals with user interactions and events like zooming - */ -export class ZoomHandler { - private readonly scaleExtent: [number, number] = [1, 100]; - private readonly minExtentPoint: [number, number] = [0, 0]; - - public constructor(private readonly wafermap: WaferMap) {} - - public createZoomBehavior(): void { - zoom() - .scaleExtent(this.scaleExtent) - .translateExtent([ - this.minExtentPoint, - [this.wafermap.canvasWidth, this.wafermap.canvasHeight] - ]) - .on('zoom', (event: ZoomEvent) => { - this.wafermap.transform = event.transform; - })(select(this.wafermap as Element)); - } - - public removeZoomBehavior(): void { - zoom().on('zoom', null)(select(this.wafermap as Element)); - } -} diff --git a/packages/nimble-components/src/wafer-map/modules/zoom-handler.ts b/packages/nimble-components/src/wafer-map/modules/zoom-handler.ts index 2fa7803c35..43bf5d5c6d 100644 --- a/packages/nimble-components/src/wafer-map/modules/zoom-handler.ts +++ b/packages/nimble-components/src/wafer-map/modules/zoom-handler.ts @@ -1,11 +1,5 @@ import { select } from 'd3-selection'; -import { - zoom, - ZoomBehavior, - zoomIdentity, - ZoomTransform, - zoomTransform -} from 'd3-zoom'; +import { zoom, ZoomTransform } from 'd3-zoom'; import type { WaferMap } from '..'; interface ZoomEvent { @@ -16,65 +10,22 @@ interface ZoomEvent { * ZoomHandler deals with user interactions and events like zooming */ export class ZoomHandler { - private zoomTransform: ZoomTransform = zoomIdentity; - private readonly minScale = 1.1; - private readonly minExtentPoint: [number, number] = [-100, -100]; - private readonly extentPadding = 100; - private zoomBehavior!: ZoomBehavior; + private readonly scaleExtent: [number, number] = [1, 100]; + private readonly minExtentPoint: [number, number] = [0, 0]; public constructor(private readonly wafermap: WaferMap) {} public createZoomBehavior(): void { - this.zoomBehavior = zoom() - .scaleExtent([ - 1.1, - this.getZoomMax( - this.wafermap.canvasWidth * this.wafermap.canvasHeight, - this.wafermap.dataManager.containerDimensions.width - * this.wafermap.dataManager.containerDimensions.height - ) - ]) + zoom() + .scaleExtent(this.scaleExtent) .translateExtent([ this.minExtentPoint, - [ - this.wafermap.canvasWidth + this.extentPadding, - this.wafermap.canvasHeight + this.extentPadding - ] + [this.wafermap.canvasWidth, this.wafermap.canvasHeight] ]) - .filter((event: Event) => { - const transform = zoomTransform(this.wafermap.canvas); - const filterEval = transform.k >= this.minScale || event.type === 'wheel'; - return filterEval; - }) .on('zoom', (event: ZoomEvent) => { // D3 will automatically remove existing handlers when adding new ones // See: https://github.com/d3/d3-zoom/blob/v3.0.0/README.md#zoom_on - this.rescale(event); - }); - - this.zoomBehavior(select(this.wafermap.canvas as Element)); - } - - public removeZoomBehavior(): void { - zoom().on('zoom', null)(select(this.wafermap.canvas as Element)); - } - - private rescale(event: ZoomEvent): void { - const transform = event.transform; - if (transform.k === this.minScale) { - this.zoomTransform = zoomIdentity; - this.zoomBehavior.transform( - select(this.wafermap.canvas as Element), - zoomIdentity - ); - } else { - this.zoomTransform = transform; - } - - this.wafermap.transform = this.zoomTransform; - } - - private getZoomMax(canvasArea: number, dataArea: number): number { - return Math.ceil((dataArea / canvasArea) * 100); + this.wafermap.transform = event.transform; + })(select(this.wafermap as Element)); } } diff --git a/packages/nimble-components/src/wafer-map/tests/wafer-map.spec.ts b/packages/nimble-components/src/wafer-map/tests/wafer-map.spec.ts index 36a17709df..e443b632ee 100644 --- a/packages/nimble-components/src/wafer-map/tests/wafer-map.spec.ts +++ b/packages/nimble-components/src/wafer-map/tests/wafer-map.spec.ts @@ -9,7 +9,7 @@ import { WaferMapOriginLocation } from '../types'; import { RenderingModule } from '../modules/rendering'; -import { WorkerRenderer } from '../modules/worker-renderer'; +import { WorkerRenderer } from '../modules/experimental/worker-renderer'; async function setup(): Promise> { return fixture(html``); @@ -88,24 +88,12 @@ describe('WaferMap', () => { expect(spy).toHaveBeenCalledTimes(1); }); - it('will use RenderingModule after dies change', () => { - element.dies = [{ x: 1, y: 1, value: '1' }]; - processUpdates(); - expect(element.renderer instanceof RenderingModule).toBeTrue(); - }); - it('will update once after diesTable change', () => { element.diesTable = new Table(); processUpdates(); expect(spy).toHaveBeenCalledTimes(1); }); - it('will use WorkerRenderer after diesTable change', () => { - element.diesTable = new Table(); - processUpdates(); - expect(element.renderer instanceof WorkerRenderer).toBeTrue(); - }); - it('will update once after colorScale changes', () => { element.colorScale = { colors: ['red', 'red'], values: ['1', '1'] }; processUpdates(); @@ -158,6 +146,28 @@ describe('WaferMap', () => { renderHoverSpy = spyOn(element.workerRenderer, 'renderHover'); }); + it('will use RenderingModule after dies change', () => { + element.dies = [{ x: 1, y: 1, value: '1' }]; + processUpdates(); + expect(element.renderer instanceof RenderingModule).toBeTrue(); + }); + + it('will use WorkerRenderer after supported diesTable change', () => { + element.diesTable = tableFromArrays({ + colIndex: Int32Array.from([]), + rowIndex: Int32Array.from([]), + value: Float64Array.from([]) + }); + processUpdates(); + expect(element.renderer instanceof WorkerRenderer).toBeTrue(); + }); + + it('will use RenderingModule after unsupported diesTable change', () => { + element.diesTable = new Table(); + processUpdates(); + expect(element.renderer instanceof RenderingModule).toBeTrue(); + }); + it('will call renderHover after supported diesTable change', () => { element.diesTable = tableFromArrays({ colIndex: Int32Array.from([]), @@ -190,63 +200,9 @@ describe('WaferMap', () => { expect(initialValue).toBe('translate(0,0) scale(1)'); }); - it('will zoom in the wafer-map', () => { - element.canvas.dispatchEvent( - new WheelEvent('wheel', { deltaY: -2, deltaMode: -1 }) - ); - processUpdates(); - const zoomedValue = getTransform(); - expect(zoomedValue).not.toBe(initialValue); - }); - - it('will zoom out to identity', () => { - element.canvas.dispatchEvent( - new WheelEvent('wheel', { deltaY: -2, deltaMode: -1 }) - ); - - processUpdates(); - const zoomedValue = getTransform(); - expect(zoomedValue).not.toEqual(initialValue); - - element.canvas.dispatchEvent( - new WheelEvent('wheel', { deltaY: 2, deltaMode: -1 }) - ); - - processUpdates(); - const zoomedOut = getTransform(); - expect(zoomedOut).toBe(initialValue); - }); - - it('will not zoom out when at identity', () => { - element.canvas.dispatchEvent( - new WheelEvent('wheel', { deltaY: 2, deltaMode: -1 }) - ); - processUpdates(); - const zoomedOut = getTransform(); - expect(zoomedOut).toBe(initialValue); - }); - }); - - xdescribe('experimental zoom flow', () => { - let initialValue: string | undefined; - - beforeEach(() => { - element.canvasWidth = 500; - element.canvasHeight = 500; - element.diesTable = tableFromArrays({ - colIndex: Int32Array.from([1]), - rowIndex: Int32Array.from([1]), - value: Float64Array.from([1]) - }); - element.colorScale = { colors: ['red', 'red'], values: ['1', '1'] }; - processUpdates(); - initialValue = getTransform(); - expect(initialValue).toBe('translate(0,0) scale(1)'); - }); - it('will zoom in the wafer-map', () => { element.dispatchEvent( - new WheelEvent('wheel', { deltaY: -100, deltaMode: 0 }) + new WheelEvent('wheel', { deltaY: -2, deltaMode: -1 }) ); processUpdates(); const zoomedValue = getTransform(); @@ -312,7 +268,7 @@ describe('WaferMap', () => { expect(initialHeight).toBe(460); expect(initialWidth).toBe(460); - element.canvas.dispatchEvent( + element.dispatchEvent( new WheelEvent('wheel', { deltaY: -2, deltaMode: -1 }) ); processUpdates(); @@ -331,7 +287,7 @@ describe('WaferMap', () => { processUpdates(); const initialTransform = element.hoverTransform; expect(initialTransform).not.toEqual(''); - element.canvas.dispatchEvent( + element.dispatchEvent( new WheelEvent('wheel', { deltaY: -2, deltaMode: -1 }) ); processUpdates();