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