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