diff --git a/package.json b/package.json index e0b17a6..4af8da3 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "@fortawesome/free-solid-svg-icons": "^6.6.0", "@risai/bim": "^1.4.2", "@tanstack/svelte-virtual": "^3.10.8", - "@typek/signalhead": "npm:@jsr/typek__signalhead@^0.0.39", + "@typek/signalhead": "npm:@jsr/typek__signalhead@^0.0.40", "@typek/typek": "npm:@jsr/typek__typek@^0.10.0", "@types/lodash-es": "^4.17.12", "@types/seedrandom": "^3.0.8", @@ -86,7 +86,7 @@ }, "peerDependencies": { "fraction.js": "^4.3.7", - "unitlib": "^0.8.11" + "unitlib": "^0.9.0" }, "packageManager": "pnpm@9.1.1+sha256.9551e803dcb7a1839fdf5416153a844060c7bce013218ce823410532504ac10b", "browserslist": [ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4c1fc76..9d2fcd5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,8 +18,8 @@ importers: specifier: ^3.10.8 version: 3.10.8(svelte@4.2.19) '@typek/signalhead': - specifier: npm:@jsr/typek__signalhead@^0.0.39 - version: '@jsr/typek__signalhead@0.0.39' + specifier: npm:@jsr/typek__signalhead@^0.0.40 + version: '@jsr/typek__signalhead@0.0.40' '@typek/typek': specifier: npm:@jsr/typek__typek@^0.10.0 version: '@jsr/typek__typek@0.10.0' @@ -63,8 +63,8 @@ importers: specifier: ^5.3.1 version: 5.3.1 unitlib: - specifier: ^0.8.11 - version: 0.8.11(fraction.js@4.3.7)(typescript@5.6.2) + specifier: ^0.9.0 + version: 0.9.0(fraction.js@4.3.7)(typescript@5.6.2) vite-plugin-wasm: specifier: ^3.3.0 version: 3.3.0(vite@5.4.6(@types/node@22.5.5)(sass@1.78.0)) @@ -335,8 +335,8 @@ packages: '@jsr/std__internal@1.0.3': resolution: {integrity: sha512-6R6UBR4hz0uwYkoYR2KmKj9r8kI1IbbVF8Yxvl0YwE4U8k3YzeCoG1MB/2GjoVNxWyn/bhj0UZSCz7jJb1P0zA==, tarball: https://npm.jsr.io/~/11/@jsr/std__internal/1.0.3.tgz} - '@jsr/typek__signalhead@0.0.39': - resolution: {integrity: sha512-vhbbYLpe57q1UYFeKFOySkvbAtOvXnAGWCWmqHgo2XndVmdvtgvTCEwzmTdYpidt8ztNlwQg3Bu0B1/gzaLQjg==, tarball: https://npm.jsr.io/~/11/@jsr/typek__signalhead/0.0.39.tgz} + '@jsr/typek__signalhead@0.0.40': + resolution: {integrity: sha512-171refcfiPkU7v04w5bpOuOWt+U6Ff1ijLsgJPQ3VTtIPB2t5QNZSIAhUNIHe00f4u7feZS0FMiM1oPYH1CTlA==, tarball: https://npm.jsr.io/~/11/@jsr/typek__signalhead/0.0.40.tgz} '@jsr/typek__typek@0.10.0': resolution: {integrity: sha512-oTfZURkJmmmUMyzp5F3/AoQEfrPT1B1xgzGDZ7bTt38t81CkViABkI0YoEnqU38hhVmoJQWeKmewASlvO88kZg==, tarball: https://npm.jsr.io/~/11/@jsr/typek__typek/0.10.0.tgz} @@ -1313,8 +1313,8 @@ packages: undici-types@6.19.8: resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} - unitlib@0.8.11: - resolution: {integrity: sha512-K+Go3DCiM9JUnAb38P5gwXmioWJ3SSunEEw5ZOS0bO9h/VXO7j/GqgBJLwOA8VdNOVe4Dmgc9lpXJRUkYCdPxA==} + unitlib@0.9.0: + resolution: {integrity: sha512-PuxSgKxM4DIO1FS7wRoYfg6b/gu/EmS9EwVco4CzD5G2DQJPbroSmOD2eC/l5THwp0Vem1Zpfnf1rNe01KvE0w==} peerDependencies: fraction.js: ^4.2.1 @@ -1577,7 +1577,7 @@ snapshots: '@jsr/std__internal@1.0.3': {} - '@jsr/typek__signalhead@0.0.39': + '@jsr/typek__signalhead@0.0.40': dependencies: '@jsr/typek__typek': 0.6.7 @@ -2559,7 +2559,7 @@ snapshots: undici-types@6.19.8: {} - unitlib@0.8.11(fraction.js@4.3.7)(typescript@5.6.2): + unitlib@0.9.0(fraction.js@4.3.7)(typescript@5.6.2): dependencies: fraction.js: 4.3.7 yeet-ts: 1.0.3(typescript@5.6.2) diff --git a/src/App.svelte b/src/App.svelte index 98e43b5..975fb4c 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -149,6 +149,7 @@ ], }), ); + const fullscreen$ = mut(false);
@@ -175,6 +176,8 @@ legendPosition="bottom" hoverPointsInterpolation="nearest" {commonXRange$} + {fullscreen$} + class={$fullscreen$ ? "bg" : ""} > +  1
 1000
 3/3
- + --> {/await}
+ + diff --git a/src/lib/components/Chart.svelte b/src/lib/components/Chart.svelte index d644678..c7dc623 100644 --- a/src/lib/components/Chart.svelte +++ b/src/lib/components/Chart.svelte @@ -38,9 +38,9 @@ import type { InterpolationStrategy } from "../../../dist/wasm/libchartium.js"; import type { ChartStyleSheet } from "../state/core/style.js"; import { derived } from "@typek/signalhead"; + import { filter } from "@typek/typek"; import RulerBubble from "./RulerBubble.svelte"; import { setContext } from "../utils/svelte-context.js"; - import { filter } from "@typek/typek"; // SECTION Props let klass: string = ""; @@ -118,6 +118,8 @@ export let hideXBubble: boolean = false; /** Hides the coordinate bubble by the odge of the graph */ export let hideYBubble: boolean = false; + /** Shrinks Y bubble if it is too wide and would overflow */ + export let scaleYBubble: boolean = false; /** Hides the tooltips shown next to cursor */ export let hideTooltip: boolean = false; @@ -164,7 +166,7 @@ ); /** Charts supplied with the same FlockRegistry will have y axis of the same width */ - export let commonYAxisWidth$: FlockRegistry | undefined = undefined; + export let commonYAxisWidth$: FlockRegistry = FlockRegistry(); $: yAxisWidth = mapOpt(commonYAxisWidth$, (f) => flockReduce(f, (a, b) => Math.max(a, b), 0), ); @@ -409,6 +411,7 @@
{/if} @@ -435,6 +441,7 @@ .fromQuantity($commonXRuler$) .toLogicalPixels(), }} + maxX={chart$.valueOnAxis("x").fromFraction(1).toLogicalPixels()} value={$commonXRuler$} displayUnit={$xDisplayUnit$} /> diff --git a/src/lib/components/RulerBubble.svelte b/src/lib/components/RulerBubble.svelte index 2af12ff..4bc0b8b 100644 --- a/src/lib/components/RulerBubble.svelte +++ b/src/lib/components/RulerBubble.svelte @@ -2,34 +2,61 @@ import type { ChartStyleSheet } from "../state/core/style.js"; import type { ChartValue, DisplayUnit, Point } from "../types.js"; import { formatChartValue } from "../units/mod.js"; + import { clamp } from "./position.js"; + import type { Signal } from "@typek/signalhead"; + import { measureText } from "../utils/format.js"; /** position relative to body; i.e. absolute :d */ export let position: Point; + export let maxX: number; + export let maxWidth$: Signal | undefined = undefined; export let value: ChartValue | undefined; export let axis: "x" | "y"; export let displayUnit: DisplayUnit; export let autoDecimalPlaces = 2; export let chartStylesheet: Partial = {}; + export let scaleIfTooLarge = false; const decimalPlaces = chartStylesheet?.[`bubbles.${axis}`]?.decimalPlaces ?? chartStylesheet?.bubbles?.decimalPlaces ?? autoDecimalPlaces; const bubbleClass = `${chartStylesheet?.[`bubbles.${axis}`]?.className ?? ""} ${chartStylesheet?.bubbles?.className ?? ""}`; - const bubbleStyle = `${chartStylesheet?.[`bubbles.${axis}`]?.style ?? ""} ${chartStylesheet?.bubbles?.style ?? ""}`; + let bubbleStyle = `${chartStylesheet?.[`bubbles.${axis}`]?.style ?? ""} ${chartStylesheet?.bubbles?.style ?? ""}`; + + let borderBoxSize: ResizeObserverSize[]; + $: clientWidth = borderBoxSize?.[0].inlineSize ?? 0; + $: clampedX = clamp(position.x, 0 + clientWidth / 2, maxX - clientWidth / 2); + $: bubbleText = formatChartValue(value ?? 0, { + unit: displayUnit, + decimalPlaces, + }); + let bubbleMeasure: HTMLDivElement; + $: scaling = chartStylesheet?.[`bubbles.y`]?.scaleToFitAxis + ? scaleIfTooLarge || $maxWidth$ === undefined || bubbleMeasure === undefined + ? undefined + : clamp( + $maxWidth$ / (measureText(bubbleText, bubbleMeasure).width + 20), + 0.65, + 1, + ) + : 1; $: positionedStyle = axis === "x" - ? `left: ${position.x.toFixed(1)}px; top: ${position.y.toFixed(1)}px; transform: translateX(-50%)` - : `right: ${position.x.toFixed(1)}px; top: ${position.y.toFixed(1)}px; transform: translateY(-50%)`; + ? `left: ${clampedX.toFixed(1)}px; top: ${position.y.toFixed(1)}px; transform: translateX(-50%) scale(${scaling}); transform-origin: right center` + : `right: ${position.x.toFixed(1)}px; top: ${position.y.toFixed(1)}px; transform: translateY(-50%) scale(${scaling}); transform-origin: right center`; -
+
+
- {formatChartValue(value ?? 0, { - unit: displayUnit, - decimalPlaces, - })} + {bubbleText}
diff --git a/src/lib/state/core/style.ts b/src/lib/state/core/style.ts index 58efbcd..f45be3e 100644 --- a/src/lib/state/core/style.ts +++ b/src/lib/state/core/style.ts @@ -39,6 +39,11 @@ export interface BubbleStyle { className: string; decimalPlaces: number; } + +export interface YBubbleStyle extends BubbleStyle { + scaleToFitAxis: boolean; +} + export interface TooltipStyle { manyTraces: Partial<{ style: string; @@ -71,7 +76,7 @@ export interface ChartStyleSheet { bubbles: Partial; "bubbles.x": Partial; - "bubbles.y": Partial; + "bubbles.y": Partial; tooltip: Partial;