* Create and show tooltip for a span
(span)
| 369 | * Create and show tooltip for a span |
| 370 | */ |
| 371 | function showSpanTooltip(span) { |
| 372 | hideSpanTooltip(); |
| 373 | |
| 374 | const samples = parseInt(span.dataset.samples) || 0; |
| 375 | const maxSamples = parseInt(span.dataset.maxSamples) || 1; |
| 376 | const pct = span.dataset.pct || '0'; |
| 377 | const opcodes = span.dataset.opcodes || ''; |
| 378 | |
| 379 | if (samples === 0) return; |
| 380 | |
| 381 | const intensity = samples / maxSamples; |
| 382 | const isHot = intensity > 0.7; |
| 383 | const isWarm = intensity > 0.3; |
| 384 | const hotnessText = isHot ? 'Hot' : isWarm ? 'Warm' : 'Cold'; |
| 385 | const hotnessClass = isHot ? 'hot' : isWarm ? 'warm' : 'cold'; |
| 386 | |
| 387 | // Build opcodes rows - each opcode on its own row |
| 388 | let opcodesHtml = ''; |
| 389 | if (opcodes) { |
| 390 | const opcodeList = opcodes.split(',').map(op => op.trim()).filter(op => op); |
| 391 | if (opcodeList.length > 0) { |
| 392 | opcodesHtml = ` |
| 393 | <div class="span-tooltip-section">Opcodes:</div> |
| 394 | ${opcodeList.map(op => `<div class="span-tooltip-opcode">${op}</div>`).join('')} |
| 395 | `; |
| 396 | } |
| 397 | } |
| 398 | |
| 399 | const tooltip = document.createElement('div'); |
| 400 | tooltip.className = 'span-tooltip'; |
| 401 | tooltip.innerHTML = ` |
| 402 | <div class="span-tooltip-header ${hotnessClass}">${hotnessText}</div> |
| 403 | <div class="span-tooltip-row"> |
| 404 | <span class="span-tooltip-label">Samples:</span> |
| 405 | <span class="span-tooltip-value${isHot ? ' highlight' : ''}">${samples.toLocaleString()}</span> |
| 406 | </div> |
| 407 | <div class="span-tooltip-row"> |
| 408 | <span class="span-tooltip-label">% of line:</span> |
| 409 | <span class="span-tooltip-value">${pct}%</span> |
| 410 | </div> |
| 411 | ${opcodesHtml} |
| 412 | `; |
| 413 | |
| 414 | document.body.appendChild(tooltip); |
| 415 | activeTooltip = tooltip; |
| 416 | |
| 417 | // Position tooltip above the span |
| 418 | const rect = span.getBoundingClientRect(); |
| 419 | const tooltipRect = tooltip.getBoundingClientRect(); |
| 420 | |
| 421 | let left = rect.left + (rect.width / 2) - (tooltipRect.width / 2); |
| 422 | let top = rect.top - tooltipRect.height - 8; |
| 423 | |
| 424 | // Keep tooltip in viewport |
| 425 | if (left < 5) left = 5; |
| 426 | if (left + tooltipRect.width > window.innerWidth - 5) { |
| 427 | left = window.innerWidth - tooltipRect.width - 5; |
| 428 | } |
no test coverage detected
searching dependent graphs…