Overlap chart
A Venn diagram of two or three sets, where each circle is a set and each shared area counts the members of exactly that combination.
How two or three groups overlap: users on web, mobile and the API, customers who bought each of three products, people with each of three skills. Each set is a circle, each shared area is labelled with the number of members in exactly that combination, and hovering a region names it and gives its share of the whole.
Engine. The diagram is drawn by ECharts through its custom series, like the pie
and gauge charts, so it shares their tooltip, legend, theme and loading states. The circle positions are solved by
@upsetjs/venn.js, a small dependency installed with the package.
Import
import '@c2n/components/chart/overlap-chart'This chart draws with ECharts, a peer dependency it loads on first draw: npm install echarts.
Usage
Data
Declare each set with a c2-chart-series, where field is the set’s key and label its name. Then pass one row per
combination, with the number of members in all of its sets, which is the shape most analytics exports and
venn.js use:
<c2-overlap-chart
data='[
{ "sets": ["web"], "size": 18420 },
{ "sets": ["web", "mobile"], "size": 6880 },
{ "sets": ["web", "mobile", "api"], "size": 740 }
]'
>
<c2-chart-series field="web" label="Web app"></c2-chart-series>
<c2-chart-series field="mobile" label="Mobile app"></c2-chart-series>
<c2-chart-series field="api" label="Public API"></c2-chart-series>
</c2-overlap-chart>A combination you leave out counts as 0. The chart works out every exclusive region from those totals: 740 users in
all three sets means the “Web app + Mobile app” region holds 6,880 − 740 = 6,140. If your rows name their fields
differently, point sets-field and size-field at them.
The regions property returns the exclusive regions largest first, each with sets, size (members in exactly those
sets), total (members in all of them) and share, ready for a table next to the chart.
Layout
layout="proportional" (the default) sizes each circle by its set and places them so each pairwise overlap has the
right area. With three sets the triple overlap is a best fit, because three circles cannot match every combination
exactly; the labels and the tooltip always show the exact counts. layout="uniform" draws equal circles instead, so
every region has room for its label even when it is tiny or empty.
A region too small for its number gets the number outside, joined to it by a leader line. labels switches the
numbers between count, percent (share of all members), count-percent (both, as in the “Click a circle” example)
and none.
Interaction
Hovering a region shows its name, its count, its share and the total for the combination, and fires region-hover.
Clicking fires region-click.
Hovering a set’s entry in the legend (or its name, with set-labels="around") highlights its whole circle; the tooltip then describes the set: its
members, its share of the whole, and how many belong to no other set. set-hover and set-click report the set. Clicking a set’s name also highlights it, as a click on a series does on every
chart; clicking it again clears the highlight, and preventDefault() on set-click keeps it as it is.
highlighted does the same from your application, for instance while the pointer is on a row of a table next to
the chart.
With selectable, clicking a region selects that region and clicking a set’s name (with set-labels="around") selects the
whole set. Add
selection="set" to make a click anywhere inside a circle select that whole circle, as the “Click a circle” example
above does: in an overlap the smallest circle under the pointer comes first, and each further click on the same spot
moves to the next circle there, then clears. While the pointer is over the circles, the one a click would select is
highlighted. selected
holds the region’s set keys, selected-set the set’s key, and selection-change fires with both; a second click
clears the selection. None of these events bubble, so listen on the element itself.
<c2-overlap-chart selectable highlighted="api" data="…">…</c2-overlap-chart>
<script>
const chart = document.querySelector('c2-overlap-chart')
chart.addEventListener('selection-change', (event) => {
const { selected, selectedSet } = event.detail // ['web', 'api'] and null, or [] and 'web'
})
</script>The sets are named in the chart’s legend, all together in one place: below the plot by default, or wherever
legend="top|start|end" puts it. set-labels="around" writes each set’s name and total beside its circle instead
(pair it with legend="none", as several gallery cards do), and hovering or clicking a name then works like its legend
entry. The legend can be replaced like any chart’s, through the legend slot, renderLegendItem or a linked
c2-chart-legend. A legend click highlights the set, as highlighted does; with legend-action="toggle" it switches
the set off and lays the diagram out again without it. The plot is one tab stop: the arrow keys move
through the sets and then the regions from the largest to the smallest, Enter selects, and Escape clears. A table of
every region is rendered for assistive technology.
A circle diagram cannot draw every region of four or more sets, so with more than three the chart shows its error state.
Custom tooltip
The tooltip is customised the way it is on every chart: markup in the tooltip slot, a renderTooltip function, or a
linked c2-chart-tooltip placed anywhere on the page. renderTooltip and the tooltip-change event receive the
shared tooltip model plus the hovered region (with sets, size, total and share) or the hovered set (with
label, total, only and share):
chart.renderTooltip = ({ region, set }) =>
set
? `${set.label}: ${set.total.toLocaleString()} members, ${set.only.toLocaleString()} in no other set`
: `${chart.regionName(region)}: ${region.size.toLocaleString()} (${Math.round(region.share * 100)}%)`Theming
Circles take the shared palette, --c2-chart__series-1--color to --c2-chart__series-3--color, at
--c2-chart__set--fill-opacity with a full-strength outline of --c2-chart__set--stroke-width. Overlaps read darker
because the fills stack. The hovered and selected regions get a wash in the text colour, set by
--c2-chart__region__hover--opacity and --c2-chart__region__selected--opacity. A highlighted set comes forward: its
circle fills to --c2-chart__set__highlight--fill-opacity, its outline is drawn on top with a glow, and each part it
shares with another circle is tinted in that circle’s colour at --c2-chart__set-overlap__highlight--fill-opacity,
so the mixed zones stand out and show which set they are shared with. The other circles keep their colour at
--c2-chart__set__dimmed--opacity of their usual fill and outline. They can also change look: --c2-chart__set__dimmed--color repaints them in one colour (the
default transparent keeps each set’s own), and --c2-chart__set__dimmed--fill-style fills them with solid,
hatch (diagonal lines), dots, or none for outlines only.
<style>
.focus-view {
--c2-chart__set__dimmed--color: #a1a1aa;
--c2-chart__set__dimmed--fill-style: hatch;
}
</style>
<c2-overlap-chart class="focus-view" highlighted="api" data="…">…</c2-overlap-chart>The labels always use the text colours, so every circle is named in words rather than by colour alone.