Socket
Socket
Sign inDemoInstall

@vx/tooltip

Package Overview
Dependencies
6
Maintainers
3
Versions
34
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

    @vx/tooltip

vx tooltip


Version published
Weekly downloads
70K
decreased by-0.13%
Maintainers
3
Install size
2.07 MB
Created
Weekly downloads
 

Changelog

Source

v0.0.199

:boom: Breaking Changes

  • [scale] Deprecate rangeRound field in the input of scaleLinear(), scaleLog(), scalePoint(), scalePower(), scaleSqrt(), scaleTime() and scaleUtc(). #766 Instead of
    scaleLinear({ rangeRound: xxx })
    
    Do this instead
    scaleLinear({ range: xxx, round: true });
    
  • [scale] Deprecate ticks and tickFormat in the input of scaleQuantize(). It was not really doing anything anyway as both scale.ticks() and scale.tickFormat() do not mutate the scale. #766
  • [scale] Remove scale.type field that was attached to the d3 scales. #766
  • [grid] @vx/grid components now accept D3 Scale as generic type instead of ScaleInput. Developers should not expect to specify this generic type as it can be inferred from the passed scale. #775
  • [grid] Renames GridColumnProps => GridColumnsProps (+s) to match GridRowsProps. #787
  • [legend] Update generic types for legend components. #777
  • [marker] remove old <Marker /> implementation of a Line and some Text. #783

:rocket: Enhancements

  • [scale] new functions & New fields for the scale configs. #766
  • [scale] add meta scale types. #770
  • [scale] Add fallback overload for createScale. #791
  • [scale] add new types: AnyD3Scale, InferD3ScaleOutput, InferD3ScaleDiscreteInput, InferD3ScaleThresholdInput and ScaleInput. Add new utilities functions: getTicks, coerceNumber and toString. #773
  • [scale] add reverse field to scale config. This will reverse the range. Useful when the ranges are programmatically supplied to the scale factories such as in XYChart and developers want easy way to reverse the dynamic range. #780
  • [legend] exports @vx/legend shapes from the index for convenience / non-deep imports. #772
  • [grid] adds children prop to GridRows + GridColumns to support animated rendering. #787
  • [shape] add <BarRounded /> shape. #774
  • [shape] Create new factory functions for d3-shape and export as part of vx/shape (arc, area, line, pie, radialLine), similar to vx/scale has factories for d3-scale. #776
  • [shape] add SplitLinePath component to @vx/shape that allows you to create a line path split into multiple smaller line paths that can be styled independently. #778
  • [axis] consistent and compatible typings across vx/scale and vx/axis. More fields passed to child render props of Axis. #773
  • [axis] Axis is refactored to accept a ticksComponent which allows us to animate them. #779
  • [axis] adds a third argument values to tickFormat(value, index, values) so that format logic can more easily leverage all ticks (because numTicks is approximate, lib consumers do not know how many tick values exist a priori). #779
  • [marker] add new <Marker /> that matches actual SVG <marker>. #783
  • [marker] add <MarkerArrow />, <MarkerCross />, <MarkerX />, <MarkerCircle />, <MarkerLine />. #783
  • [react-spring] adds a new package @vx/react-spring that includes react-spring as a peerDep and can be a home for things that depend on react-spring. #779
  • [react-spring] Adds an <AnimatedAxis /> and <AnimatedTicksRender /> in @vx/react-spring. #779
  • [react-spring] updates the vx-demo/axis demo to use <AnimatedAxis />. #779
  • [react-spring] adds AnimatedGridRows + AnimatedGridColumns. #787
  • [react-spring] modularizes AnimatedTicks/useAnimatedTicksConfig to spring-configs/useAnimatedLineTransitionConfig so it can power both animated tick + grid lines. #787
  • [react-spring] adds animationTrajectory=outside | inside | min | max to AnimatedAxis and AnimatedGridRows/Columns. #787
:bug: Bug Fix
  • [responsive] exclude enableDebounceLeadingCall prop being passed into div. #763
  • [responsive] fix prettier format. #764
  • [text] fix warning for NaN or invalid values are passed as x or y. #790

:memo: Documentation

  • [scale] Improve documentation of the fields in scale configs. #766

:house: Internal

  • [scale] rewrite individual scale factory with composition of shared operators. This ensure order of operators and simplified code. #766
  • [scale] add 100+ unit tests to make this vx/scale package has 100% test coverage. #766
  • [stats] use updated @vx/scale types. #770
  • [legend] extract defaultDomain helper. #777
  • [demo] updated curves demo to use new <Marker>. #783
  • [demo] updates the /axis demo to include AnimatedGrid* and a animationTrajectory config. #787
  • [jest] ignore vx-demo, vx-vx code coverage. #784
  • [annotation] 100% coverage. #784
  • [bounds] 100% coverage. #784
  • [brush] add utils test. #786
  • [event] add tests. #786
  • [test] add tests for vx/grid, vx/zoom, vx/threshold, vx/shape. #793
:trophy: Contributors
 - @vx/annotation: 0.0.198 => 0.0.199
 - @vx/axis: 0.0.198 => 0.0.199
 - @vx/bounds: 0.0.198 => 0.0.199
 - @vx/brush: 0.0.198 => 0.0.199
 - @vx/chord: 0.0.198 => 0.0.199
 - @vx/clip-path: 0.0.198 => 0.0.199
 - @vx/curve: 0.0.198 => 0.0.199
 - @vx/demo: 0.0.198 => 0.0.199
 - @vx/drag: 0.0.198 => 0.0.199
 - @vx/event: 0.0.198 => 0.0.199
 - @vx/geo: 0.0.198 => 0.0.199
 - @vx/glyph: 0.0.198 => 0.0.199
 - @vx/gradient: 0.0.198 => 0.0.199
 - @vx/grid: 0.0.198 => 0.0.199
 - @vx/group: 0.0.198 => 0.0.199
 - @vx/heatmap: 0.0.198 => 0.0.199
 - @vx/hierarchy: 0.0.198 => 0.0.199
 - @vx/legend: 0.0.198 => 0.0.199
 - @vx/marker: 0.0.198 => 0.0.199
 - @vx/mock-data: 0.0.198 => 0.0.199
 - @vx/network: 0.0.198 => 0.0.199
 - @vx/pattern: 0.0.198 => 0.0.199
 - @vx/point: 0.0.198 => 0.0.199
 - @vx/react-spring: 0.0.198 => 0.0.199
 - @vx/responsive: 0.0.198 => 0.0.199
 - @vx/scale: 0.0.198 => 0.0.199
 - @vx/shape: 0.0.198 => 0.0.199
 - @vx/stats: 0.0.198 => 0.0.199
 - @vx/text: 0.0.198 => 0.0.199
 - @vx/threshold: 0.0.198 => 0.0.199
 - @vx/tooltip: 0.0.198 => 0.0.199
 - @vx/voronoi: 0.0.198 => 0.0.199
 - @vx/vx: 0.0.198 => 0.0.199
 - @vx/xychart: 0.0.0 => 0.0.199 (private)
 - @vx/zoom: 0.0.198 => 0.0.199

Readme

Source

@vx/tooltip

The @vx/tooltip package provides utilities for making it easy to add Tooltips to a visualization and includes hooks, higher-order component (HOC) enhancers, and Tooltip components.

Installation

npm install --save @vx/tooltip

Hooks and Enhancers

This package provides two ways to add tooltip state logic to your chart components:

  • a hook: useTooltip()
  • a higher order component (HOC): withTooltip()

The useTooltip hook is the recommended way to add tooltip state logic to your components, but can only be used in functional components. The withTooltip HOC can be used with both functional and class components, and is the recommended way to add tooltip state logic to class components.

Both useTooltip and withTooltip expose the same values and functions for use in your component:

NameTypeDescription
showTooltipfuncCall this function with the signature func({ tooltipData, tooltipLeft, tooltipTop }) to set the tooltip state to the specified values.
hideTooltipfuncCall this function to close a tooltip, i.e., set the showTooltip state to false.
tooltipOpenboolWhether the tooltip state is open or closed
tooltipLeftnumberThe tooltipLeft position passed to the showTooltip func, intended to be used for tooltip positioning
tooltipTopnumberThe tooltipTop position passed to the showTooltip func, intended to be used for tooltip positioning
tooltipDataanyThe tooltipData value passed to the showTooltip func, intended to be used for any data that your tooltip might need to render
updateTooltipfuncCall this function with the signature func({ tooltipOpen, tooltipLeft, tooltipTop, tooltipData }) to set the tooltip state to the specified values.

In the case of useTooltip, these will be returned from the useTooltip() call in your component. In the case of withTooltip, they will be passed as props to your wrapped component. Refer to the Examples section for a basic demo of each approach.

useTooltip()

If you would like to add tooltip state logic to a functional component, you may use the useTooltip() hook which will return an object with several properties that you can use to manage the tooltip state of your component. For correct tooltip positioning, it is important to wrap your component in an element (e.g., div) with relative positioning. This is handled for you by the withTooltip HOC, but not with the useTooltip() hook.

withTooltip(BaseComponent [, containerProps [, renderContainer]])

If you would like to add tooltip state logic to a class component, you may wrap it in withTooltip(BaseComponent [, containerProps [, renderContainer]).

The HOC will wrap your component in a div with relative positioning by default and handle state for tooltip positioning, visibility, and content by injecting the following props into your BaseComponent:

You may override the container by specifying containerProps as the second argument to withTooltip, or by specifying renderContainer as the third argument to withTooltip.

Components

Tooltip components render tooltip state and can be used in conjunction with useTooltip and withTooltip above.

Tooltip

This is a simple Tooltip container component meant to be used to actually render a Tooltip. It accepts the following props, and will spread any additional props on the tooltip container div (i.e., ...restProps):

NameTypeDefaultDescription
leftnumber or string--Sets style.left of the tooltip container
topnumber or string--Sets style.top of the tooltip container
classNamestring--Adds a class (in addition to vx-tooltip-portal) to the tooltip container
styleobject--Sets / overrides any styles on the tooltip container (including top and left)
childrennode--Sets the children of the tooltip, i.e., the actual content
unstyledbooltrueWhether the tooltip should use styles from the style prop or not
TooltipWithBounds

This tooltip component is exactly the same as Tooltip above, but it is aware of its boundaries meaning that it will flip left/right and bottom/top based on whether it would overflow its parent's boundaries. It accepts the following props, and will spread any additional props on the Tooltip component (i.e., ...restProps):

NameTypeDefaultDescription
leftnumber--The horizontal position of the cursor, tooltip will be place to the left or right of this coordinate depending on the width of the tooltip and the size of the parent container.
topnumber--The vertical position of the cursor, tooltip will be place to the bottom or top of this coordinate depending on the height of the tooltip and the size of the parent container.
offsetLeftnumber10Horizontal offset of the tooltip from the passed left value, functions as a horizontal padding.
offsetRightnumber10Vertical offset of the tooltip from the passed top value, functions as a vertical padding.
styleobject--Sets / overrides any styles on the tooltip container (including top and left)
childrennode--Sets the children of the tooltip, i.e., the actual content
unstyledbooltrueWhether the tooltip should use styles from the style prop or not

Note that this component is positioned using a transform, so overriding left and top via styles may have no effect.

useTooltipInPortal
⚠️ ResizeObserver dependency

This hook relies on ResizeObservers. If you need a polyfill, you can either polute the window object or inject it cleanly using the polyfill config option below.

useTooltipInPortal is a hook which gives you a TooltipInPortal component for rendering Tooltip or TooltipWithBounds in a Portal, outside of your component DOM tree which can be useful in many circumstances (see below for more on Portals).

API

type Options = {
  /** whether TooltipWithBounds should be used to auto-detect (page) boundaries and reposition itself. */
  detectBounds?: boolean;
  /** Debounce resize or scroll events in milliseconds (needed for positioning) **/
  debounce?: number | { scroll: number; resize: number }
  /** React to nested scroll changes, don't use this if you know your view is static */
  scroll?: boolean
  /** You can optionally inject a resize-observer polyfill */
  polyfill?: { new (cb: ResizeObserverCallback): ResizeObserver }
}

useTooltipInPortal(
  options: Options = { debounce: 0, scroll: true, detectBounds: true }
): {
  /** Set `ref={containerRef}` on the element corresponding to the coordinate system that `left/top` (passed to `TooltipInPortal`) are relative to. */
  containerRef: React.MutableRefObject<HTMLElement | SVGElement>;
  /** Access to the container's bounding box if useful to you. This will be empty on first render. */
  containterBounds: RectReadOnly;
  /** React.FunctionComponent<TooltipProps> with the same API as Tooltip, which will be rendered in a Portal. */
  TooltipInPortal ({ top: containerTop, left: containerLeft, ...tooltipProps }: TooltipProps) => ReactNode;


interface RectReadOnly {
  readonly x: number
  readonly y: number
  readonly width: number
  readonly height: number
  readonly top: number
  readonly right: number
  readonly bottom: number
  readonly left: number
}

Portal

Portal is a component which simply renders its children inside a div element appended to document.body created by ReactDOM. A Portal can be an effective strategy for solving the (z-index stacking context problem)[rg/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context] for Tooltips.

For example, if your chart is rendered inside a stacking context with a lower z-index than a surrounding container, it may get clipped by that container even if you specify a higher z-index. This is solvable with a Portal because the separate container will not be subject to the stacking context of your chart.

To use a Portal, simply pass your Tooltip as a child: <Portal><Tooltip {...} /></Portal>. You will also need to correct the left and top positions to be in page coordinates, not the coordinates of your container which you would use when not using a Portal. If reacting to a mouse event, you can use event.pageX/Y. Alternatively, if you have container coordinates, you can convert them to page coordinates using the following (note: useTooltipInPortal does handles this for you):

const pageX = containerX + containerBoundingBox.left + window.scrollLeft;
const pageY = containerY + containerBoundingBox.top + window.scrollTop;

Examples

useTooltip and useTooltipInPortal For Functional Components
import { useTooltip, useTooltipInPortal, TooltipWithBounds } from '@vx/tooltip';
import { localPoint } from '@vx/event';

const ChartWithTooltip = () => {
  const {
    tooltipData,
    tooltipLeft,
    tooltipTop,
    tooltipOpen,
    showTooltip,
    hideTooltip,
  } = useTooltip();

  // If you don't want to use a Portal, simply replace `TooltipInPortal` below with
  // `Tooltip` or `TooltipWithBounds` and remove `containerRef`
  const { containerRef, TooltipInPortal } = useTooltipInPortal({
    // use TooltipWithBounds
    detectBounds: true,
    // when tooltip containers are scrolled, this will correctly update the Tooltip position
    scroll: true,
  })

  const handleMouseOver = (event, datum) => {
    const coords = localPoint(event.target.ownerSVGElement, event);
    showTooltip({
      tooltipLeft: coords.x,
      tooltipTop: coords.y,
      tooltipData: datum
    });
  };

  return (
    // Set `ref={containerRef}` on the element corresponding to the coordinate system that
    // `left/top` (passed to `TooltipInPortal`) are relative to.
    <>
      <svg ref={containerRef} width={...} height={...}>
        // Chart here...
        <SomeChartElement
          onMouseOver={this.handleMouseOver}
          onMouseOut={hideTooltip}
        />
      </svg>

      {tooltipOpen && (
        <TooltipInPortal
          // set this to random so it correctly updates with parent bounds
          key={Math.random()}
          top={tooltipTop}
          left={tooltipLeft}
        >
          Data value <strong>{tooltipData}</strong>
        </TooltipInPortal>
      )}
    </>
  )
};

render(<ChartWithTooltip />, document.getElementById("root"));
withTooltip For Class Components
import { withTooltip, TooltipWithBounds } from '@vx/tooltip';
import { localPoint } from '@vx/event';

class Chart extends React.Component {
  handleMouseOver = (event, datum) => {
    const coords = localPoint(event.target.ownerSVGElement, event);
    this.props.showTooltip({
      tooltipLeft: coords.x,
      tooltipTop: coords.y,
      tooltipData: datum
    });
  };

  render() {
    const {
      tooltipData,
      tooltipLeft,
      tooltipTop,
      tooltipOpen,
      hideTooltip
    } = this.props;

    return (
      // note React.Fragment is only available in >= react@16.2
      <React.Fragment>
        <svg width={...} height={...}>
          // Chart here...
          <SomeChartElement onMouseOver={this.handleMouseOver} onMouseOut={hideTooltip} />
        </svg>

        {tooltipOpen && (
          <TooltipWithBounds
            // set this to random so it correctly updates with parent bounds
            key={Math.random()}
            top={tooltipTop}
            left={tooltipLeft}
          >
            Data value <strong>{tooltipData}</strong>
          </TooltipWithBounds>
        )}
      </React.Fragment>
    );
  }
}

const ChartWithTooltip = withTooltip(Chart);

render(<ChartWithTooltip />, document.getElementById("root"));

Example codesandbox here.

Keywords

FAQs

Last updated on 09 Sep 2020

Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc