DocumentationCharts

Custom Tooltip

Every chart shows a tooltip when a data point is hovered. By default it is the point's key and value. Project an <ng-template pcacTooltip> into a chart and that template is rendered instead — a real Angular template with the hovered data bound into it, so pipes, control flow, your own components and styles all work as they would anywhere else.

Try It

Hover the charts below. Each one has its own template; the bar and line tooltips use parent to show the point's share of its group / series, and the bar chart's thresholds are flagged via isThreshold.

Grouped bar

parent is the group

Line

parent is the series

Pie

No parent: slices are top level

Markup

Import PcacTooltipDirective alongside the chart component, then put an <ng-template pcacTooltip> inside the chart element. The hovered datum is the template's implicit value (let-point, or whatever name you like); the rest of the context is picked up by name.

import { PcacBarVerticalChart, PcacTooltipDirective } from '@pioneer-code/pioneer-charts';

@Component({
  imports: [PcacBarVerticalChart, PcacTooltipDirective],
  // ...
})
<!-- Project an <ng-template pcacTooltip> into any chart. -->
<pcac-bar-vertical-chart [config]="config">
  <ng-template pcacTooltip let-point let-group="parent" let-threshold="isThreshold">
    <div class="my-tooltip">
      <strong>{{ group?.key }}</strong>
      <span>{{ point.key }}: {{ point.value | number }}</span>
      @if (threshold) {
        <em>threshold</em>
      }
    </div>
  </ng-template>
</pcac-bar-vertical-chart>

Template Context

The template is type-checked against PcacTooltipContext under strictTemplates, so point.value and friends are checked as PcacData.

interface PcacTooltipContext {
  // The hovered datum: a bar, a line/area/plot point, a pie slice, or a threshold.
  $implicit: PcacData;

  // What it sits inside: the group a bar belongs to, the series a point belongs to, or for a
  // threshold the data group it's drawn against. null when there is no enclosing level
  // (pie slices, a chart-wide threshold).
  parent: PcacData | null;

  // True when a bar chart threshold marker is hovered rather than a data point.
  isThreshold: boolean;

  // Position of the hovered datum in parent.data (or in the top-level data when there is no
  // parent, e.g. a pie slice). For a threshold, its position in thresholds.
  index: number;

  // Position of parent in the top-level data; null whenever parent is.
  parentIndex: number | null;

  // Every *other* datum drawn at exactly the same coordinate as the hovered one, in data order,
  // each located the same way ({ data, parent, index, parentIndex }). Set by the line, area and
  // plot charts - whether or not the plot chart's pointFanOut has spread them apart - and empty
  // on the other charts and whenever nothing shares the point.
  coincident: PcacTooltipCoincident[];
}

Your Own Data

A PcacData only carries a key and a value, but the tooltip often wants more — the customer behind an order, the unit a reading was taken in. The context's index and parentIndex give the hovered datum's position in data, and charts never reorder data, so if the collection you built it from is parallel (same order, nothing filtered out) those two indexes reach straight back into it:

// Your source collection, grouped the same way the chart is: one entry per group,
// one item per bar. Build the chart's data from it without reordering or filtering.
regions: Region[] = [
  { name: 'North', orders: [{ customer: 'Acme', total: 1200 }, { customer: 'Globex', total: 800 }] },
  { name: 'South', orders: [{ customer: 'Initech', total: 950 }] },
];

config: PcacBarVerticalChartConfig = {
  ...new PcacBarVerticalChartConfig(),
  data: this.regions.map(region => ({
    key: region.name, value: null, hide: false,
    data: region.orders.map(order => ({ key: order.customer, value: order.total, hide: false, data: [] })),
  })),
};
<!-- parentIndex picks the region, index picks the order within it. -->
<pcac-bar-vertical-chart [config]="config">
  <ng-template pcacTooltip let-point let-i="index" let-g="parentIndex">
    @let order = regions[g!].orders[i];
    <div class="my-tooltip">
      <strong>{{ order.customer }}</strong>
      <span>{{ order.total | currency }}</span>
    </div>
  </ng-template>
</pcac-bar-vertical-chart>

parentIndex is null when there is no enclosing level (a pie slice, or a chart-wide threshold), so for a pie use items[index] directly. For a threshold, index is its position in thresholds (or in thresholds[parentIndex].data for a per-bar threshold). If your collection isn't parallel to data — you filter, sort or group on the way in — look the item up by key instead, or keep a map from key to item; a positional link would silently point at the wrong row.

Styling

With a template present the library applies none of its own tooltip styling — no background, padding, font or color. It only positions the rendered template (centered above the cursor) and keeps it from intercepting the mouse. The template owns the whole box.

/* The template owns the whole box; give it whatever look you want. */
.my-tooltip {
  padding: 0.5rem 0.75rem;
  border-radius: 6px;
  background: #fff;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
  white-space: nowrap;
}

The tooltip is rendered into <body> so it can float over anything, but its nodes are still stamped with your component's style scope, so component styles like the one above reach it without ::ng-deep or global CSS.

Notes

  • Every chart supports it. Bar (vertical and horizontal, including thresholds), line, area, plot, pie and donut. Leave the template out and the default key/value tooltip is used, formatted per the chart's xAxis.format / yAxis.format as before; those formats are not applied to a custom template, which gets the raw PcacData.
  • It's a live view. The template is created when a hover starts, updated in place as the mouse moves, and destroyed when the hover ends. While shown it takes part in change detection like any other view, so a signal read inside it keeps updating.
  • One template per chart. Only the first pcacTooltip template inside a chart element is used.
  • Points that share a coordinate. On the line, area and plot charts the context's coincident lists every other point at the hovered one's coordinate, so a template can say who else is there — the Plot Chart page's last demo does this alongside pointFanOut, which spreads such points apart so each can be hovered in the first place.