blob: c1143bf5a5cf8e4363531821ed70a98d05a5801b [file] [log] [blame]
Rahul Ravikumar9c70b8f2023-06-15 13:29:04 -07001<script lang="ts">
Rahul Ravikumara5805d12023-08-22 12:38:40 -07002 import type { ChartType, LegendItem, Point, TooltipItem } from "chart.js";
Rahul Ravikumar9c70b8f2023-06-15 13:29:04 -07003 import { Chart } from "chart.js/auto";
Rahul Ravikumar4b6dfd12023-08-18 16:51:41 -07004 import { createEventDispatcher, onMount } from "svelte";
Rahul Ravikumar333932c2023-07-20 14:49:49 -07005 import { writable, type Writable } from "svelte/store";
Rahul Ravikumar333932c2023-07-20 14:49:49 -07006 import { saveToClipboard as save } from "../clipboard.js";
Rahul Ravikumara5805d12023-08-22 12:38:40 -07007 import { LegendPlugin } from "../plugins.js";
8 import type { Data } from "../types/chart.js";
Rahul Ravikumar4b6dfd12023-08-18 16:51:41 -07009 import type { Controls, ControlsEvent } from "../types/events.js";
Rahul Ravikumara5805d12023-08-22 12:38:40 -070010 import Legend from "./Legend.svelte";
11 import { isSampled } from "../transforms/standard-mappers.js";
Rahul Ravikumar9c70b8f2023-06-15 13:29:04 -070012
Rahul Ravikumar333932c2023-07-20 14:49:49 -070013 export let data: Data;
14 export let chartType: ChartType = "line";
Rahul Ravikumare39246d2023-07-26 16:49:05 -070015 export let isExperimental: boolean = false;
Rahul Ravikumar4b6dfd12023-08-18 16:51:41 -070016 export let showHistogramControls: boolean = false;
Rahul Ravikumar9c70b8f2023-06-15 13:29:04 -070017
Rahul Ravikumar333932c2023-07-20 14:49:49 -070018 // State
Rahul Ravikumar4b6dfd12023-08-18 16:51:41 -070019 let controlsDispatcher = createEventDispatcher<ControlsEvent>();
Rahul Ravikumar333932c2023-07-20 14:49:49 -070020 let element: HTMLCanvasElement;
Rahul Ravikumar4b6dfd12023-08-18 16:51:41 -070021 let buckets: Writable<number> = writable(100);
Rahul Ravikumar333932c2023-07-20 14:49:49 -070022 let chart: Writable<Chart | null> = writable(null);
23 let items: Writable<LegendItem[] | null> = writable(null);
24
Rahul Ravikumar16ffa9e2024-11-07 15:09:35 -080025 $: {
26 if ($chart) {
27 $chart.data = data;
28 $chart.update();
29 }
30 }
31
Rahul Ravikumar333932c2023-07-20 14:49:49 -070032 // Effects
Rahul Ravikumar9c70b8f2023-06-15 13:29:04 -070033 onMount(() => {
Rahul Ravikumar16ffa9e2024-11-07 15:09:35 -080034 const onUpdate = (updated: Chart) => {
35 $chart = updated;
Rahul Ravikumare39246d2023-07-26 16:49:05 -070036 // Bad typings.
Rahul Ravikumar16ffa9e2024-11-07 15:09:35 -080037 const legend = updated.options.plugins?.legend as any;
38 $items = legend.labels.generateLabels($chart);
Rahul Ravikumar9c70b8f2023-06-15 13:29:04 -070039 };
40 const plugins = {
Rahul Ravikumara5805d12023-08-22 12:38:40 -070041 tooltip: {
42 callbacks: {
Rahul Ravikumarab5ea662024-06-06 16:05:41 -070043 label: (context: TooltipItem<typeof chartType>): string | void | string[] => {
Rahul Ravikumara5805d12023-08-22 12:38:40 -070044 // TODO: Configure Tooltips
45 // https://www.chartjs.org/docs/latest/configuration/tooltip.html
46 const label = context.dataset.label;
47 const rp = context.raw as Point;
48 const frequency = context.parsed.y;
49 if (isSampled(label)) {
50 const fx = rp.x.toFixed(2);
51 return `${label}: ${fx} F(${frequency})`;
52 } else {
53 // Fallback to default behavior
Rahul Ravikumarab5ea662024-06-06 16:05:41 -070054 return;
Rahul Ravikumara5805d12023-08-22 12:38:40 -070055 }
56 },
57 },
58 },
Rahul Ravikumar9c70b8f2023-06-15 13:29:04 -070059 legend: {
60 display: false,
61 },
62 benchmark: {
63 onUpdate: onUpdate,
64 },
65 };
Rahul Ravikumar333932c2023-07-20 14:49:49 -070066 $chart = new Chart(element, {
67 data: data,
68 type: chartType,
69 plugins: [LegendPlugin],
70 options: {
71 plugins: plugins,
72 },
73 });
Rahul Ravikumar9c70b8f2023-06-15 13:29:04 -070074 });
75
Rahul Ravikumar333932c2023-07-20 14:49:49 -070076 // Copy to clip board
77 async function copy(event: Event) {
Rahul Ravikumar9c70b8f2023-06-15 13:29:04 -070078 if ($chart) {
Rahul Ravikumar333932c2023-07-20 14:49:49 -070079 await save($chart);
Rahul Ravikumar9c70b8f2023-06-15 13:29:04 -070080 }
81 }
Rahul Ravikumar4b6dfd12023-08-18 16:51:41 -070082
83 function onHistogramChanged(event: Event) {
84 const element = event.target as EventTarget & HTMLInputElement;
85 const oldValue = $buckets;
86 $buckets = parseInt(element.value, 10);
87 if (oldValue != $buckets) {
88 let controls: Controls = {
89 buckets: $buckets,
90 };
91 controlsDispatcher("controls", controls);
92 }
93 }
Rahul Ravikumar9c70b8f2023-06-15 13:29:04 -070094</script>
95
96<article>
Rahul Ravikumar333932c2023-07-20 14:49:49 -070097 <div class="toolbar">
98 <button
99 class="btn outline"
100 data-tooltip="Copy chart to clipboard."
101 on:click={copy}
102 >
103
104 </button>
105 </div>
Rahul Ravikumar16ffa9e2024-11-07 15:09:35 -0800106 <canvas class="chart" bind:this={element}> </canvas>
Rahul Ravikumar4b6dfd12023-08-18 16:51:41 -0700107 {#if showHistogramControls}
108 <div class="controls">
109 <label for="buckets">
110 Histogram
111 <input
112 type="range"
113 data-tooltip={$buckets}
114 data-placement="right"
115 min="10"
116 max="250"
117 value={$buckets}
118 id="buckets"
119 name="buckets"
120 on:change={onHistogramChanged}
121 />
122 </label>
123 </div>
124 {/if}
Rahul Ravikumare39246d2023-07-26 16:49:05 -0700125 {#if isExperimental}
126 <footer class="slim">
127 <section class="experimental">
128 <kbd>Experimental</kbd>
129 </section>
130 </footer>
131 {/if}
Rahul Ravikumar9c70b8f2023-06-15 13:29:04 -0700132</article>
133
Rahul Ravikumarab5ea662024-06-06 16:05:41 -0700134{#if $chart && $items}
Rahul Ravikumar333932c2023-07-20 14:49:49 -0700135 <Legend chart={$chart} items={$items} />
Rahul Ravikumar9c70b8f2023-06-15 13:29:04 -0700136{/if}
137
138<style>
Rahul Ravikumar9c70b8f2023-06-15 13:29:04 -0700139 .chart {
140 width: 100%;
141 }
Rahul Ravikumar333932c2023-07-20 14:49:49 -0700142 .toolbar {
143 padding: 0;
Rahul Ravikumar9c70b8f2023-06-15 13:29:04 -0700144 display: flex;
145 flex-direction: row;
Rahul Ravikumar333932c2023-07-20 14:49:49 -0700146 justify-content: flex-end;
Rahul Ravikumar9c70b8f2023-06-15 13:29:04 -0700147 }
Rahul Ravikumar333932c2023-07-20 14:49:49 -0700148 .toolbar .btn {
149 width: auto;
150 height: auto;
151 border: none;
152 padding: 5px;
Rahul Ravikumar9c70b8f2023-06-15 13:29:04 -0700153 }
Rahul Ravikumar4b6dfd12023-08-18 16:51:41 -0700154 .controls {
155 margin-top: 20px;
156 width: 100%;
157 }
Rahul Ravikumare39246d2023-07-26 16:49:05 -0700158 .slim {
159 margin-bottom: 0px;
160 padding: 0;
161 }
Rahul Ravikumare39246d2023-07-26 16:49:05 -0700162 .experimental {
163 display: flex;
164 flex-direction: row;
165 flex-wrap: nowrap;
166 justify-content: center;
167 margin-bottom: 0px;
168 }
Rahul Ravikumar9c70b8f2023-06-15 13:29:04 -0700169</style>