SharedTooltip.html.svelte component
Generates a tooltip that works on multiseries datasets, like multiline charts. It creates a tooltip showing the name of the series and the current value. It finds the nearest data point using the QuadTree.html.svelte component.
Param | Default | Required | Description |
---|---|---|---|
formatTitle Function |
d => d |
A function to format the tooltip title, which is $config.x . |
|
formatValue Function |
d => isNaN(+d) ? d : commas(d) |
A function to format the value. | |
formatKey Function |
d => titleCase(d) |
A function to format the series name. | |
offset Number |
-20 |
A y-offset from the hover point, in pixels. | |
dataset (Array<Object> | undefined ) |
None | The dataset to work off of—defaults to $data if left unset. You can pass something custom in here in case you don't want to use the main data or it's in a strange format. |
Used in these examples:
<!--
@component
Generates a tooltip that works on multiseries datasets, like multiline charts. It creates a tooltip showing the name of the series and the current value. It finds the nearest data point using the [QuadTree.html.svelte](https://layercake.graphics/components/QuadTree.html.svelte) component.
-->
<script>
import { getContext } from 'svelte';
import { format } from 'd3-format';
import QuadTree from './QuadTree.html.svelte';
const { data, width, yScale, config } = getContext('LayerCake');
const commas = format(',');
const titleCase = d => d.replace(/^\w/, w => w.toUpperCase());
/** @type {Function} [formatTitle=d => d] - A function to format the tooltip title, which is `$config.x`. */
export let formatTitle = d => d;
/** @type {Function} [formatValue=d => isNaN(+d) ? d : commas(d)] - A function to format the value. */
export let formatValue = d => (isNaN(+d) ? d : commas(d));
/** @type {Function} [formatKey=d => titleCase(d)] - A function to format the series name. */
export let formatKey = d => titleCase(d);
/** @type {Number} [offset=-20] - A y-offset from the hover point, in pixels. */
export let offset = -20;
/** @type {Array<Object>|undefined} [dataset] - The dataset to work off of—defaults to $data if left unset. You can pass something custom in here in case you don't want to use the main data or it's in a strange format. */
export let dataset = undefined;
const w = 150;
const w2 = w / 2;
/* --------------------------------------------
* Sort the keys by the highest value
*/
function sortResult(result) {
if (Object.keys(result).length === 0) return [];
const rows = Object.keys(result)
.filter(d => d !== $config.x)
.map(key => {
return {
key,
value: result[key]
};
})
.sort((a, b) => b.value - a.value);
return rows;
}
</script>
<QuadTree dataset={dataset || $data} y="x" let:x let:y let:visible let:found let:e>
{@const foundSorted = sortResult(found)}
{#if visible === true}
<div style="left:{x}px;" class="line"></div>
<div
class="tooltip"
style="
width:{w}px;
display: {visible ? 'block' : 'none'};
top:{$yScale(foundSorted[0].value) + offset}px;
left:{Math.min(Math.max(w2, x), $width - w2)}px;"
>
<div class="title">{formatTitle(found[$config.x])}</div>
{#each foundSorted as row}
<div class="row">
<span class="key">{formatKey(row.key)}:</span>
{formatValue(row.value)}
</div>
{/each}
</div>
{/if}
</QuadTree>
<style>
.tooltip {
position: absolute;
font-size: 13px;
pointer-events: none;
border: 1px solid #ccc;
background: rgba(255, 255, 255, 0.85);
transform: translate(-50%, -100%);
padding: 5px;
z-index: 15;
pointer-events: none;
}
.line {
position: absolute;
top: 0;
bottom: 0;
width: 1px;
border-left: 1px dotted #666;
pointer-events: none;
}
.tooltip,
.line {
transition:
left 250ms ease-out,
top 250ms ease-out;
}
.title {
font-weight: bold;
}
.key {
color: #999;
}
</style>