/** * A fading copy of the level a drilldown is leaving. * * A drilldown replaces the geometry in one synchronous draw, and no camera move * can hide that: the parent's neighbours (the rest of the United States around * California) do not exist at the child level, so they blink out, and the * child's internal boundaries have nothing to fade up from. Framing the feature * first only lines up the *one* shape both levels share. * * So the outgoing level is copied to a layer above the incoming one and faded * out. Only the copy animates: the incoming level stays fully opaque * underneath, which is what keeps a cross-fade from dipping through the * background in the middle. What the reader sees is the parent fill dissolving * to reveal the counties already drawn under it, and the neighbours dissolving * with it. * * The copy is a snapshot, so it cannot follow the camera by itself. `track` * pushes the affine between the camera the copy is registered with and the live * one, so a settle move after the swap carries both together instead of sliding * the copy off its original. That transform scales the copy's screen-space * content (labels, bubbles) which a real camera move would only reposition, and * it is left that way on purpose: the settle is a few percent, and the layer it * distorts is on its way to zero opacity. * * The camera it is registered with is the one set *after* the swap, not the one * it was captured under: `anchor` exists to say so. A level change replaces the * projection, so the outgoing level's camera describes world coordinates that no * longer mean anything, and treating it as the reference would scale the copy by * the ratio between two unrelated fits the moment the new level landed. * * A clone is stripped of the classes and keys its original was found by, so for * the length of the transition the map still answers "one path per feature" to * a hit test, an export, a `querySelectorAll` or an assertion. A copy that kept * them would be indistinguishable from live content for a quarter of a second, * which is exactly long enough for a `drilldown` handler to read the wrong * count. * * @module renderers/LevelGhost */ import type { CameraState } from '../types'; export interface GhostSource { /** The plot box, which is the positioning context the copy is laid over. */ plot: HTMLElement | null; svg: SVGSVGElement | null; /** * Clone the SVG. A clone is DOM proportional to the outgoing mark count, so * the caller decides against its motion budget. */ cloneSvg?: boolean; } export declare class LevelGhost { private container; /** The camera the copy is registered with. Null until `anchor` says. */ private from; private constructor(); /** * Copy what is currently on screen, mounted above it. * * Returns null when there was nothing to copy: no plot, no SVG, or the clone * declined by the motion budget. A caller treats that as "no cross-fade" * rather than as an error. */ static capture({ plot, svg, cloneSvg }: GhostSource): LevelGhost | null; /** * Declare the camera the copy currently lines up with, which is the one the * incoming level was handed. Until this is called the copy is left alone, since * a snapshot with nothing to be relative to is already in the right place. */ anchor(camera: CameraState): void; /** Keep the copy registered with the live level as its camera settles. */ track(camera: CameraState): void; /** Start the fade. The caller removes the copy when the move it rides ends. */ fade(duration: number): void; destroy(): void; } //# sourceMappingURL=LevelGhost.d.ts.map