github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/webapp/javascript/components/TimelineChart/TimelineChartPlugin.ts (about)

     1  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
     2  // @ts-nocheck
     3  import getFormatLabel from './getFormatLabel';
     4  
     5  (function ($) {
     6    const options = {}; // no options
     7  
     8    function init(plot) {
     9      const plotOptions = plot.getOptions();
    10  
    11      this.selecting = false;
    12      this.tooltipY = 0;
    13      this.selectingFrom = {
    14        label: '',
    15        x: 0,
    16        pageX: 0,
    17        width: 0,
    18      };
    19      this.selectingTo = {
    20        label: '',
    21        x: 0,
    22        pageX: 0,
    23        width: 0,
    24      };
    25  
    26      const onPlotHover = (target, position) => {
    27        const { xaxis } = plot.getAxes();
    28  
    29        this.tooltipY = target.currentTarget.getBoundingClientRect().bottom - 28;
    30        if (!position.x) return;
    31        if (!this.selecting) {
    32          this.selectingFrom = {
    33            label: getFormatLabel({
    34              date: position.x,
    35              xaxis,
    36              timezone: plotOptions.xaxis.timezone,
    37            }),
    38            x: position.x,
    39            pageX: position.pageX,
    40          };
    41        } else {
    42          this.selectingTo = {
    43            label: getFormatLabel({
    44              date: position.x,
    45              xaxis,
    46              timezone: plotOptions.xaxis.timezone,
    47            }),
    48            x: position.x,
    49            pageX: position.pageX,
    50          };
    51        }
    52        updateTooltips();
    53      };
    54  
    55      const updateTooltips = () => {
    56        const { xaxis } = plot.getAxes();
    57  
    58        if (!this.selecting) {
    59          // If we arn't in selection mode
    60          this.$tooltip.html(this.selectingFrom.label).show();
    61          this.selectingFrom.width = $(this.$tooltip).outerWidth();
    62          setTooltipPosition(this.$tooltip, {
    63            x: this.selectingFrom.pageX,
    64            y: this.tooltipY,
    65          });
    66        } else {
    67          // Render Intersection
    68          this.$tooltip.html(
    69            `${getFormatLabel({
    70              date: Math.min(this.selectingFrom.x, this.selectingTo.x),
    71              xaxis,
    72              timezone: plotOptions.xaxis.timezone,
    73            })} - 
    74               ${getFormatLabel({
    75                 date: Math.max(this.selectingFrom.x, this.selectingTo.x),
    76                 xaxis,
    77                 timezone: plotOptions.xaxis.timezone,
    78               })}`
    79          );
    80  
    81          // Stick to left selection
    82          setTooltipPosition(this.$tooltip, {
    83            x: this.selectingTo.pageX,
    84            y: this.tooltipY,
    85          });
    86        }
    87      };
    88  
    89      const onLeave = () => {
    90        // Save tooltips while selecting
    91        if (!this.selecting) {
    92          this.$tooltip.hide();
    93        }
    94      };
    95  
    96      function onMove() {}
    97  
    98      const setTooltipPosition = ($tip, pos, center = true) => {
    99        const totalTipWidth = $tip.outerWidth();
   100        const totalTipHeight = $tip.outerHeight();
   101        if (
   102          pos.x - $(window).scrollLeft() >
   103          $(window).innerWidth() - totalTipWidth
   104        ) {
   105          pos.x -= center ? totalTipWidth / 2 : totalTipWidth;
   106          pos.x = Math.max(pos.x, 0);
   107          $tip.css({
   108            left: 'auto',
   109            right: `0px`,
   110            top: `${pos.y}px`,
   111          });
   112          return;
   113        }
   114        if (
   115          pos.y - $(window).scrollTop() >
   116          $(window).innerWidth() - totalTipHeight
   117        ) {
   118          pos.y -= totalTipHeight;
   119        }
   120  
   121        $tip.css({
   122          left: `${pos.x - (center ? Math.floor(totalTipWidth / 2) : 0)}px`,
   123          top: `${pos.y}px`,
   124          right: 'auto',
   125        });
   126      };
   127  
   128      const onSelected = () => {
   129        // Clean up selection state and hide tooltips
   130        this.selecting = false;
   131        this.$tooltip.hide();
   132      };
   133  
   134      // Trying to mimic flot.selection.js
   135      const onMouseDown = () => {
   136        // Save selection state
   137        this.selecting = true;
   138      };
   139  
   140      const onMouseUp = () => {
   141        this.selecting = false;
   142      };
   143  
   144      const createDomElement = () => {
   145        if (this.$tooltip) return;
   146        const tooltipStyle = {
   147          background: '#fff',
   148          color: 'black',
   149          'z-index': '1040',
   150          padding: '0.4em 0.6em',
   151          'border-radius': '0.5em',
   152          'font-size': '0.8em',
   153          border: '1px solid #111',
   154          'white-space': 'nowrap',
   155        };
   156        const $tip = $('<div data-testid="timeline-tooltip1"></div>');
   157  
   158        $tip.appendTo('body').hide();
   159        $tip.css({ position: 'absolute', left: 0, top: 0 });
   160        $tip.css(tooltipStyle);
   161        this.$tooltip = $tip;
   162      };
   163  
   164      function bindEvents(plot, eventHolder) {
   165        const o = plot.getOptions();
   166  
   167        if (o.onHoverDisplayTooltip) {
   168          return;
   169        }
   170  
   171        plot.getPlaceholder().bind('plothover', onPlotHover);
   172        plot.getPlaceholder().bind('plotselected', onSelected);
   173  
   174        $(eventHolder).bind('mousemove', onMove);
   175        $(eventHolder).bind('mouseout', onLeave);
   176        $(eventHolder).bind('mouseleave', onLeave);
   177  
   178        $(eventHolder).bind('mouseup', onMouseUp);
   179        $(eventHolder).bind('mousedown', onMouseDown);
   180      }
   181  
   182      function shutdown(plot, eventHolder) {
   183        const o = plot.getOptions();
   184  
   185        if (o.onHoverDisplayTooltip) {
   186          return;
   187        }
   188  
   189        plot.getPlaceholder().unbind('plothover', onPlotHover);
   190        // plot.getPlaceholder().unbind('plotselecting', onSelecting);
   191        plot.getPlaceholder().unbind('plotselected', onSelected);
   192        $(eventHolder).unbind('mousemove', onMove);
   193        $(eventHolder).unbind('mouseout', onLeave);
   194        $(eventHolder).unbind('mouseleave', onLeave);
   195      }
   196  
   197      createDomElement();
   198  
   199      plot.hooks.bindEvents.push(bindEvents);
   200      plot.hooks.shutdown.push(shutdown);
   201    }
   202  
   203    $.plot.plugins.push({
   204      init,
   205      options,
   206      name: 'pyro-tooltip',
   207      version: '0.1',
   208    });
   209  })(jQuery);