Menu

Quadtree.percent-range.html.svelte component

Creates an interaction layer (in HTML) using d3-quadtree to find the nearest datapoint to the mouse. This component creates a slot that exposes variables x, y, found (the found datapoint), visible (a Boolean whether any data was found) and e (the event object). This component works with a percent range so the x and y values coming back will be percentages.

The quadtree searches across both the x and y dimensions at the same time. But if you want to only search across one, set the x and y props to the same value. For example, the shared tooltip component sets y='x' since it's nicer behavior to only pick up on the nearest x-value.

Param Default Required Description
x String 'x'
no
The dimension to search across when moving the mouse left and right.
y String 'y'
no
The dimension to search across when moving the mouse up and down.
searchRadius String None
no
The number of pixels to search around the mouse's location. This is the third argument passed to quadtree.find and by default a value of undefined means an unlimited range.
dataset Array None
no
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.
<!--
  @component
  Creates an interaction layer (in HTML) using [d3-quadtree](https://github.com/d3/d3-quadtree) to find the nearest datapoint to the mouse. This component creates a slot that exposes variables `x`, `y`, `found` (the found datapoint), `visible` (a Boolean whether any data was found) and `e` (the event object). This component works with a percent range so the `x` and `y` values coming back will be percentages.

  The quadtree searches across both the x and y dimensions at the same time. But if you want to only search across one, set the `x` and `y` props to the same value. For example, the [shared tooltip component](https://layercake.graphics/components/SharedTooltip.html.svelte) sets `y='x'` since it's nicer behavior to only pick up on the nearest x-value.
 -->
<script>
  import { getContext } from 'svelte';
  import { quadtree } from 'd3-quadtree';

  const { data, xGet, yGet, width, height } = getContext('LayerCake');

  let visible = false;
  let found = {};
  let e = {};

  /** @type {String} [x='x'] - The dimension to search across when moving the mouse left and right. */
  export let x = 'x';

  /** @type {String} [y='y'] - The dimension to search across when moving the mouse up and down. */
  export let y = 'y';

  /** @type {String} [searchRadius] - The number of pixels to search around the mouse's location. This is the third argument passed to [`quadtree.find`](https://github.com/d3/d3-quadtree#quadtree_find) and by default a value of `undefined` means an unlimited range. */
  export let searchRadius = undefined;

  /** @type {Array} [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;

  $: xGetter = x === 'x' ? $xGet : $yGet;
  $: yGetter = y === 'y' ? $yGet : $xGet;

  function findItem (evt) {
    e = evt;

    const xLayerKey = `layer${x.toUpperCase()}`;
    const yLayerKey = `layer${y.toUpperCase()}`;

    const xLayerVal = (evt[xLayerKey] / (x === 'x' ? $width : $height)) * 100;
    const yLayerVal = (evt[yLayerKey] / (y === 'y' ? $height : $width)) * 100;

    found = finder.find(xLayerVal, yLayerVal, searchRadius) || {};

    visible = Object.keys(found).length > 0;
  }

  $: finder = quadtree()
    .extent([[-1, -1], [$width + 1, $height + 1]])
    .x(xGetter)
    .y(yGetter)
    .addAll(dataset || $data);
</script>

<style>
  .bg {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
  }
</style>

<div
  class="bg"
  on:mousemove="{findItem}"
  on:mouseout="{() => visible = false}"
  on:blur="{() => visible = false}"
></div>
<slot
  x={xGetter(found) || 0}
  y={yGetter(found) || 0}
  {found}
  {visible}
  {e}
></slot>