| <script> |
| import { onMount } from 'svelte'; |
| |
| |
| export let visible = false; |
| export let x = -9999; |
| export let y = -9999; |
| export let title = ''; |
| export let subtitle = ''; |
| export let entries = []; |
| export let parentElement = null; |
| export let zIndex = 1000; |
| |
| let tooltipElement; |
| let tipHost; |
| |
| onMount(() => { |
| |
| console.log('ChartTooltip onMount - parentElement:', parentElement); |
| console.log('ChartTooltip onMount - parentElement classes:', parentElement?.className); |
| |
| const trackioEl = parentElement?.closest?.('.trackio') || (parentElement?.classList?.contains('trackio') ? parentElement : null); |
| |
| console.log('ChartTooltip onMount - trackioEl found:', trackioEl); |
| |
| if (trackioEl) { |
| |
| tipHost = document.createElement('div'); |
| tipHost.className = 'tip-host'; |
| tipHost.style.position = 'absolute'; |
| tipHost.style.top = '0'; |
| tipHost.style.left = '0'; |
| tipHost.style.width = '100%'; |
| tipHost.style.height = '100%'; |
| tipHost.style.pointerEvents = 'none'; |
| tipHost.style.zIndex = String(zIndex); |
| tipHost.style.overflow = 'visible'; |
| trackioEl.appendChild(tipHost); |
| |
| |
| if (tooltipElement && tipHost) { |
| tipHost.appendChild(tooltipElement); |
| } |
| } |
| |
| return () => { |
| if (tipHost && tipHost.parentNode) { |
| tipHost.parentNode.removeChild(tipHost); |
| } |
| }; |
| }); |
| |
| $: tooltipStyle = ` |
| transform: translate(${x}px, ${y}px); |
| pointer-events: none; |
| z-index: ${zIndex}; |
| `; |
| |
| $: tooltipClass = `d3-tooltip ${visible ? 'is-visible' : ''}`; |
| </script> |
|
|
| <div |
| bind:this={tooltipElement} |
| class={tooltipClass} |
| style={tooltipStyle} |
| > |
| <div class="d3-tooltip__inner"> |
| {#if title} |
| <div class="d3-tooltip__title">{@html title}</div> |
| {/if} |
| |
| {#if subtitle} |
| <div class="d3-tooltip__subtitle">{subtitle}</div> |
| {/if} |
| |
| {#each entries as entry} |
| <div class="d3-tooltip__entry"> |
| <span class="d3-tooltip__color-dot" style="background:{entry.color}"></span> |
| <strong class="d3-tooltip__entry-name">{entry.name}</strong> |
| <span class="d3-tooltip__entry-value">{entry.valueText}</span> |
| </div> |
| {/each} |
| </div> |
| </div> |
|
|
| <style> |
| |
| .d3-tooltip { |
| position: absolute; |
| top: 0; |
| left: 0; |
| transform: translate(-9999px, -9999px); |
| pointer-events: none; |
| padding: 10px 12px; |
| border-radius: 12px; |
| font-size: 12px; |
| line-height: 1.35; |
| border: 1px solid var(--border-color); |
| background: var(--surface-bg); |
| color: var(--text-color); |
| box-shadow: 0 8px 32px rgba(0,0,0,.12), 0 2px 8px rgba(0,0,0,.06); |
| opacity: 0; |
| transition: none; |
| z-index: var(--z-tooltip, 50); |
| backdrop-filter: saturate(1.12) blur(8px); |
| } |
| |
| .d3-tooltip.is-visible { |
| opacity: 1; |
| } |
| |
| .d3-tooltip__inner { |
| display: flex; |
| flex-direction: column; |
| gap: 6px; |
| min-width: 220px; |
| } |
| |
| .d3-tooltip__title { |
| font-weight: 800; |
| letter-spacing: 0.1px; |
| margin-bottom: 0; |
| color: var(--text-color); |
| } |
| |
| .d3-tooltip__subtitle { |
| font-size: 11px; |
| color: var(--muted-color); |
| display: block; |
| margin-top: -4px; |
| margin-bottom: 2px; |
| letter-spacing: 0.1px; |
| } |
| |
| .d3-tooltip__entry { |
| padding-top: 6px; |
| border-top: 1px solid var(--border-color); |
| display: flex; |
| align-items: center; |
| gap: 8px; |
| white-space: nowrap; |
| } |
| |
| .d3-tooltip__entry-name { |
| flex: 1; |
| font-weight: 500; |
| } |
| |
| .d3-tooltip__entry-value { |
| margin-left: auto; |
| text-align: right; |
| font-weight: 900; |
| } |
| |
| .d3-tooltip__color-dot { |
| display: inline-block; |
| width: 12px; |
| height: 12px; |
| border-radius: 3px; |
| border: 1px solid var(--border-color); |
| flex-shrink: 0; |
| } |
| |
| |
| :global(.trackio.theme--oblivion) .d3-tooltip { |
| border-radius: 8px; |
| border: none; |
| background: |
| radial-gradient(1200px 200px at 20% -10%, rgba(0,0,0,.05), transparent 80%), |
| radial-gradient(900px 200px at 80% 110%, rgba(0,0,0,.05), transparent 80%); |
| color: var(--trackio-text-primary); |
| box-shadow: 0 8px 32px rgba(127,241,255,.05), 0 2px 8px rgba(0,0,0,.10); |
| opacity: 0; |
| backdrop-filter: saturate(1.1) blur(10px); |
| } |
| |
| :global(.trackio.theme--oblivion) .d3-tooltip.is-visible { |
| opacity: 1; |
| } |
| |
| |
| :global([data-theme="dark"]) :global(.trackio.theme--oblivion) .d3-tooltip { |
| background: |
| radial-gradient(1400px 260px at 20% -10%, color-mix(in srgb, #ffffff 6.5%, transparent), transparent 80%), |
| radial-gradient(1100px 240px at 80% 110%, color-mix(in srgb, #ffffff 6%, transparent), transparent 80%), |
| linear-gradient(180deg, color-mix(in srgb, #ffffff 3.5%, transparent), transparent 45%); |
| color: var(--trackio-text-primary); |
| box-shadow: 0 8px 32px color-mix(in srgb, #ffffff 5%, transparent), 0 2px 8px color-mix(in srgb, black 10%, transparent); |
| } |
| |
| :global(.trackio.theme--oblivion) .d3-tooltip__title { |
| font-weight: 900; |
| letter-spacing: 0.18em; |
| text-transform: uppercase; |
| color: var(--trackio-oblivion-primary); |
| } |
| |
| :global(.trackio.theme--oblivion) .d3-tooltip__subtitle { |
| color: var(--trackio-oblivion-primary); |
| opacity: 0.4; |
| letter-spacing: 0.06em; |
| } |
| |
| :global(.trackio.theme--oblivion) .d3-tooltip__entry { |
| position: relative; |
| padding-top: 10px; |
| margin-top: 6px; |
| border-top: none; |
| } |
| |
| :global(.trackio.theme--oblivion) .d3-tooltip__entry::before { |
| content: ""; |
| position: absolute; |
| left: 0; |
| right: 0; |
| top: 0; |
| height: 1px; |
| background: color-mix(in srgb, #000000 10%, transparent); |
| } |
| |
| :global(.trackio.theme--oblivion) .d3-tooltip__entry::after { |
| content: ""; |
| position: absolute; |
| left: 0; |
| right: 0; |
| top: 1px; |
| height: 1px; |
| background: color-mix(in srgb, #ffffff 15%, transparent); |
| } |
| |
| |
| :global([data-theme="dark"]) :global(.trackio.theme--oblivion) .d3-tooltip__entry::before { |
| background: color-mix(in srgb, #ffffff 5%, transparent); |
| } |
| |
| :global([data-theme="dark"]) :global(.trackio.theme--oblivion) .d3-tooltip__entry::after { |
| background: color-mix(in srgb, #000000 10%, transparent); |
| } |
| |
| :global(.trackio.theme--oblivion) .d3-tooltip__color-dot { |
| border-radius: 2px; |
| border: 1px solid var(--obl-border, rgba(50, 50, 50, 0.22)); |
| box-shadow: 0 0 10px color-mix(in srgb, var(--obl-base, #323232) 20%, transparent) inset; |
| } |
| </style> |
|
|