MAIDR JavaScript API
    Preparing search index...

    Class BoxTrace

    Concrete implementation of a box plot trace supporting vertical and horizontal orientations. Handles boxplot sections (min, Q1, Q2, Q3, max, outliers) and rotor-based navigation.

    This is a pure box plot — violin-specific behavior lives in ViolinBoxTrace.

    Hierarchy (View Summary)

    Index

    Constructors

    Properties

    observers: Observer<TraceState>[]
    isWarning: boolean
    isComputingStateAt: boolean

    True while AbstractTrace.getStateAt computes state at a temporarily moved cursor. Enforces (structurally, not just by documentation) that state getters never notify observers.

    id: string
    type: TraceType
    title: string
    name: string | undefined

    What this layer is, when the producer named it. See MaidrLayer.name.

    layer: MaidrLayer
    supportsExtrema: false

    Abstract property that subclasses must implement to indicate extrema support

    movable: Movable
    highlightValues: (SVGElement | SVGElement[])[][] | null

    highlightValues[row][col], or null for the whole trace when it highlights nothing.

    A single cell may also be null, meaning the chart drew no element there. That is a narrower claim than the trace-wide null: the rest of the grid still highlights, and only this position falls back to the out-of-bounds state. A Google Charts calendar is the case it exists for -- its first and last columns are ragged, so a handful of grid positions have no rect at all while every other day does (#1174).

    highlightCenters:
        | {
            x: number;
            y: number;
            row: number;
            col: number;
            element: SVGElement;
        }[]
        | null

    Accessors

    • get isInitialEntry(): boolean

      Returns boolean

    • set isInitialEntry(value: boolean): void

      Parameters

      • value: boolean

      Returns void

    • get row(): number

      Returns number

    • set row(value: number): void

      Parameters

      • value: number

      Returns void

    • get col(): number

      Returns number

    • set col(value: number): void

      Parameters

      • value: number

      Returns void

    • get xAxis(): string

      The x axis's name, falling back to a generic one the layer authored none.

      A getter rather than a field set in the constructor: the fallback is a translated word, and a trace outlives a language change — a name resolved once at construction would keep the language the chart was built in.

      Returns string

    • get yAxis(): string

      The y axis's name, or a generic one. See xAxis.

      Returns string

    • get z(): string

      The z axis's name, or a generic one. See xAxis.

      Returns string

    • get isEmptyAtCursor(): boolean

      Whether the cursor has no point to report.

      Read from dimension rather than from any one trace's data, because that is the one shape every trace already answers in. It is also evaluated at the cursorLineTrace returns the current series' length as cols — so this covers a ragged layer, where one series has points and another has none, and not only a layer that is empty throughout.

      Returns boolean

      True when there is nothing at (row, col) to describe

    • get state(): TraceState

      Gets the current state of the trace including audio, braille, text, and highlight information.

      Returns TraceState

      The current TraceState

    • get outOfBoundsState(): TraceEmptyState

      The state pushed to observers when navigation leaves the data.

      Declared as TraceEmptyState rather than the whole TraceState union because that is what every implementation actually returns — the accessor exists so AbstractPlot.notifyOutOfBounds has an empty state to push. Narrowing it here is what lets the braille and highlight callers hand the value straight on: those states accept the empty trace shape but not a populated one, so a wider declaration would force each of them to cast, and a cast is exactly what stops the compiler from noticing if an override ever starts returning a populated state.

      Returns TraceEmptyState

      The empty trace state, positioned for out-of-bounds audio panning.

    • get hasMultiPoints(): boolean

      Returns boolean

    • get layerLabel(): string

      How this layer names itself in the description dialog's layer tabs.

      The producer's name when there is one, and the chart-type label otherwise — the same fallback order TextService.layerIdentity uses for the spoken layer-switch announcement, so a tab and the announcement single out the same layer by the same name. The two differ only in register: the announcement says "point plot" where the dialog says "Scatter Plot", because that written form is what the dialog's own Chart Type line has always shown and a tab sitting above it should agree with it.

      Returns string

    • get orientationLabel(): string | undefined

      Which way this chart is drawn, or undefined for a type that has no orientation to speak of.

      Entering the chart already announces it -- "This is a maidr plot of type: horizontal bar" -- but the description dialog said only "Chart Type: Bar Chart", and for the box, violin and boxen families the orientation also silently reverses the order of the rows in the table underneath, because their constructors reverse the groups when the chart is horizontal. A reader comparing the table with what they walked had no way to know why the two disagreed.

      Exposed here, and read once by the description service, rather than pushed as a stat by each of the thirty-odd traces that has one. Named apart from the bar and distribution families' own orientation fields, which hold the declared* value and default it to vertical for every type -- including the ones that have no orientation at all.

      Returns string | undefined

      horizontal or vertical, or undefined when the type has no orientation to report.

    • get traceType(): TraceType

      The trace's chart type. Lightweight alternative to reading state.traceType, which eagerly computes the full audio/braille/text/ highlight state just to expose this one string.

      Returns TraceType

    • get level(): "trace"

      Returns "trace"

      Trace.level

    • get values(): (number | number[])[][]

      Returns (number | number[])[][]

    Methods

    • Runs action with this element's observers muted.

      A cursor move normally is the announcement -- moveToIndex notifies, and everything downstream of it speaks, brailles and highlights. That is wrong for a move the reader did not make and is not waiting to hear: the description dialog's layer tabs relocate the reader in the chart while the modal is open, and the trace's announcement would land in the same live region the dialog is using, so one of the two is dropped. The caller announces afterwards, once, when the reader is back on the chart.

      Nesting is safe and the flag is restored on every path, including a throw, because a flag left raised would silence the chart for good.

      Parameters

      • action: () => void

        The moves to make in silence

      Returns void

    • Gets safe row and column indices to prevent accessing undefined values

      Returns { row: number; col: number }

      Object with safe row and column indices

    • Parameters

      • a: number

        Utility function to compare point values for rotor functionality

      • b: number
      • type: "lower" | "higher"

      Returns boolean

      boolean value

    • Rotor compare search along one row of numeric values.

      Steps from the current column in the given direction and moves to the first value that satisfies the comparison; reports the rotor boundary when nothing further qualifies. For the traces whose values are a plain numeric grid indexed [row][col]; a trace with a richer layout (the bar's orientation-normalised rows, the candlestick's segments) keeps its own.

      Parameters

      • rowValues: readonly number[]

        The values of the row being searched

      • direction: "left" | "right"

        Which way to search

      • type: "lower" | "higher"

        Whether a lower or a higher value is sought

      Returns boolean

      True when a matching value was found and moved to

    • Returns true if this trace supports compare (lower/higher value) navigation. Override to false for trace types that don't use compare modes (e.g., scatter, which is all we currently have).

      Returns boolean

    • Returns the display name for the default data navigation mode. Override to provide a trace-specific name (e.g., "ROW AND COLUMN NAVIGATION" for scatter).

      Returns string

    • Get all highlight SVG elements for this trace Used by HighlightService for high contrast mode

      Returns SVGElement[]

      Array of all SVG elements, or empty array if none

    • Get all original (visible) SVG elements for this trace. These are the actual rendered elements, not the hidden clones used for highlighting. Used by HighlightService for high contrast mode color changes.

      Returns SVGElement[]

      Array of all original SVG elements, or empty array if none

    • Computes the trace state at an arbitrary position without moving the user's cursor or notifying observers. Used by monitor mode to sonify and announce a newly appended point while the user stays put.

      The state getters read this.row/this.col internally, so the cursor is moved temporarily and always restored in a finally block — this method is the single owner of that pattern.

      Re-entrancy hazard: this is only safe because the entire call chain is synchronous (no await points), so timers (e.g. autoplay ticks) cannot interleave before the finally-restore, and state getters never notify observers. If a getter ever becomes async or triggers notifications, callers could observe the temporary cursor.

      Parameters

      • row: number

        The row of the position to compute state for

      • col: number

        The column of the position to compute state for

      Returns TraceState

      The trace state at the requested position

    • Returns a human-readable label for this trace's chart type (e.g., 'Bar Chart', 'Scatter Plot') for display in the description modal. Falls back to the raw layer type if no mapping is registered.

      Returns string

    • Builds the axes object for the description state, carrying only the axes the layer actually authored a label for. Subclasses should call this instead of constructing the axes object inline so charts without a real z dimension don't surface the placeholder default.

      Every axis is gated, not just z. xAxis and yAxis fall back to the literal 'X' and 'Y' when the JSON authors no label -- legal, and common in adapter-generated specs -- and the dialog rendered that as "X: X", a line that says nothing twice. The figure-level branch of the description already showed only authored labels (DescriptionService.getFigureAxes), so gating here is what makes the two levels of the same dialog follow one rule.

      Blankness is tested with trim(), the same rule named applies when it decides whether to substitute the fallback in the first place. A whitespace-only z label is truthy but blank, so the untrimmed guard used to pass it through and then print the 'Level' placeholder the guard existed to keep out.

      Returns { x?: string; y?: string; z?: string }

    • Returns true if this trace supports intersection navigation mode. Opt-in per trace type: override to return true (possibly conditionally, e.g. based on data shape) for trace types that expose point intersections between series. Intersection navigation is a trace-level capability — it has no meaning at the figure or subplot level, which is why it lives on AbstractTrace rather than AbstractPlot.

      Returns boolean

    • Returns true if this trace supports point-by-point navigation mode. Opt-in per trace type: override to return true for traces that expose individual data points navigable in reading order (left/right) and column-major order (up/down). Currently only ScatterTrace.

      Returns boolean

    • Notifies the trace that the rotor is entering or leaving INTERSECTION_MODE. Default is a no-op; line-style traces don't need to track mode state because their state output is unchanged by the rotor mode. Traces whose audio/text output differs in intersection mode (e.g. ScatterTrace, which normally plays the whole x-column as a chord and must instead focus a single point) override this to flip an internal flag.

      Parameters

      • _enabled: boolean

        True when entering intersection mode, false when leaving.

      Returns void

    • Trace-specific rotor filter units appended to the rotor cycle after the built-in data/compare/grid/intersection modes. Each unit restricts navigation to points matching a predicate (e.g. only bullish candles). Default: none. Override to opt in (e.g. Candlestick exposes bullish/bearish/neutral units). The returned list is treated as read-only by the rotor service.

      Returns readonly RotorFilterUnit[]

    • Moves within an active rotor filter unit along the filtered axis.

      Called by RotorNavigationService when the current rotor mode is one of this trace's getRotorFilterUnits. Filter units navigate a single axis, so only left/right are dispatched here — the service announces up/down as unavailable without calling the model (matching intersection mode). Implementations should move to the nearest point matching the unit identified by key and notify observers, returning true; when no such point exists they should call notifyRotorBounds and return false.

      Default is a no-op that reports bounds, so a trace advertising a filter unit but forgetting to implement movement fails safe (announces "no point found") rather than moving unexpectedly.

      Parameters

      • _key: string

        The RotorFilterUnit.key of the active unit

      • _direction: "left" | "right"

        The direction to search

      Returns boolean

      True if the cursor moved, false otherwise

    • Moves the active point to the pointer location and returns directional guidance toward the nearest data geometry in a single call.

      Combining both operations avoids running findNearestPoint twice per pointermove event — important on dense plots where the scan is the hot path.

      Parameters

      • x: number

        Screen-space x position of the pointer/finger

      • y: number

        Screen-space y position of the pointer/finger

      Returns PointerGuidanceState | null

      Guidance state relative to nearest point, or null when unavailable

    • Checks if the specified coordinates are within bounds of the element.

      Parameters

      • x: number

        The x-coordinate

      • y: number

        The y-coordinate

      • element: NearestPoint

        Object containing the SVG element and its position

        • element: SVGElement
        • row: number
        • col: number
        • centerX: number
        • centerY: number

      Returns boolean

      True if the point is in bounds, false otherwise

    • Cleans up trace resources including values and highlighted SVG elements.

      Only removes elements MAIDR created (hidden clones, synthetic markers); traces that highlight the chart's original live elements in place (e.g. heatmap cells, line dots) merely drop their references so the visible chart geometry survives focusout and live-data rebuilds.

      Returns void

    • The elements whose geometry is the box as the chart drew it. Empty when the selectors did not resolve, so a caller can fall back in one check.

      Returns SVGElement[]

    • Moves to the next boxplot section that matches the comparison criteria.

      Parameters

      • direction: "left" | "right" | "up" | "down"
      • type: "lower" | "higher"

      Returns boolean

    • Sets the current point based on direction and index.

      Parameters

      • direction: "left" | "right" | "up" | "down"
      • pointIndex: number

      Returns void

    • Moves up in rotor mode, optionally filtering by lower or higher values.

      Parameters

      • mode: "lower" | "higher"

      Returns boolean

      Error always - subclasses must override this method

    • Moves down in rotor mode, optionally filtering by lower or higher values.

      Parameters

      • mode: "lower" | "higher"

      Returns boolean

      Error always - subclasses must override this method

    • Moves left in rotor mode, optionally filtering by lower or higher values.

      Parameters

      • mode: "lower" | "higher"

      Returns boolean

      Error always - subclasses must override this method

    • Moves right in rotor mode, optionally filtering by lower or higher values.

      Parameters

      • mode: "lower" | "higher"

      Returns boolean

      Error always - subclasses must override this method

    • Returns { x: number; y: number; row: number; col: number; element: SVGElement }[] | null

    • Hover-driven movement is disabled for boxplots, but pointer guidance still surfaces directional cues toward the nearest box element.

      Parameters retained on the signature (rather than the zero-arg form TypeScript permits) so the override matches the base contract at a glance.

      Parameters

      Returns void