/** * The level a drilldown arrives at, developing out of the shape it came from. * * `LevelGhost` dissolves the level being left, which covers the surroundings * disappearing but says nothing about the level arriving: 58 counties are drawn * complete under the copy, so every boundary surfaces at the same moment and at * the same rate. What is missing is the part a reader reads as a morph, the * parent shape *dividing*. * * So the incoming marks are seeded with the parent's own fill and no boundaries, * which makes the new level start as a flat copy of the one shape both levels * share, and are then released in bands ordered by distance from the middle. Each * mark's fill and boundary arrive together, so the division ripples outwards from * the centre of the feature that was clicked. * * The two beats are deliberately sequenced rather than simultaneous: while the * copy is still fading, the only thing changing inside the parent shape is * nothing at all, because the seeded level is the same flat colour. The * surroundings go first, then the shape divides. * * Bands rather than a per-mark `transition-delay`, which is the obvious * implementation and the wrong one: a delay has to be written to each mark and * then taken off again, and until it is, that mark answers the reader's hover * late. A band is one timer for a slice of the level, nothing is written that has * to be cleaned up, and at a dozen bands over the spread each is about a frame * apart, which is as fine-grained as a display can show anyway. * * The transitions themselves are the ones `ApexMaps.css` already declares on * `--apexmaps-anim`. That is what keeps the effect free of any per-frame cost, * and it is also what makes it honour `chart.animations.speed` and the motion * budget without knowing they exist. * * @module renderers/LevelReveal */ /** One mark to develop, and where it sits in the order. */ export interface RevealMark { el: SVGElement; /** 0 for the mark at the origin of the ripple, 1 for the furthest out. */ order: number; } export declare class LevelReveal { private bands; private frame; private timers; private constructor(); /** * Seed every mark, then release them band by band. * * Returns null when there is nothing to develop or no motion to do it with, so * a caller can treat "no reveal" as a normal outcome rather than a failure. * * @param seed The fill the marks start from: the parent feature's own. * @param spread How long the ripple takes to reach the furthest band, in ms. */ static run({ marks, seed, spread, }: { marks: RevealMark[]; seed: string; spread: number; }): LevelReveal | null; /** Put one band's marks back to what they were drawn as, and let them transition. */ private releaseBand; /** * Stop now, wherever it got to. Every mark ends up as drawn either way: a * reveal cut short must never leave the level holding a borrowed colour. */ destroy(): void; } /** * Order items by how far they sit from a point, nearest first. * * Squared distances throughout the comparison: the ordering is identical and the * result is normalised against the furthest item anyway, so a square root per * item buys nothing. Items with no position sort last rather than being dropped, * so every mark in the level is accounted for by exactly one of the two paths. */ export declare function orderFromPoint(items: readonly T[], origin: readonly [number, number], positionOf: (item: T) => readonly [number, number] | undefined): { item: T; order: number; }[]; //# sourceMappingURL=LevelReveal.d.ts.map