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);