@coreusa/final-barline 0.1.0 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +71 -2
- package/dist/Barline.svelte +60 -39
- package/package.json +1 -1
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
# Final Barline
|
|
2
2
|
|
|
3
|
+
<img width="764" height="209" alt="image" src="https://github.com/user-attachments/assets/d2e7626f-95d9-4579-89eb-e8747d8008ab" />
|
|
4
|
+
|
|
3
5
|
A high-performance SVG Chart library for Svelte 5. Supports bar and line type of graphs with option to export the graph and a wide support for customization. Responsive by default.
|
|
4
6
|
|
|
7
|
+
**NOTE**: Final Barline is in early development 🛠️. Please file [issues](https://github.com/Coreusa/final-barline/issues) and we'll get to them as soon as we can.
|
|
8
|
+
|
|
5
9
|
<img width="630" height="496" alt="image" src="https://github.com/user-attachments/assets/ffe674c0-9fbc-4799-87ec-9bf275faa361" />
|
|
6
10
|
|
|
7
11
|
<img width="630" height="496" alt="image" src="https://github.com/user-attachments/assets/2d67a102-5b6b-42f7-a49d-f5fcac708da7" />
|
|
8
12
|
|
|
9
|
-
##
|
|
13
|
+
## Get started
|
|
10
14
|
|
|
11
15
|
```sh
|
|
12
16
|
# install Final Barline
|
|
@@ -20,9 +24,11 @@ npm install @coreusa/final-barline
|
|
|
20
24
|
yarn add @coreusa/final-barline
|
|
21
25
|
```
|
|
22
26
|
|
|
27
|
+
## General use
|
|
28
|
+
|
|
23
29
|
```sh
|
|
24
30
|
# import the component
|
|
25
|
-
import Barline from '@coreusa/final-barline';
|
|
31
|
+
import { Barline } from '@coreusa/final-barline';
|
|
26
32
|
```
|
|
27
33
|
|
|
28
34
|
```sh
|
|
@@ -37,5 +43,68 @@ import Barline from '@coreusa/final-barline';
|
|
|
37
43
|
lineWidth={2}
|
|
38
44
|
yMaxValuePadding={1}
|
|
39
45
|
/>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Data series
|
|
49
|
+
|
|
50
|
+
Data is expected as an array of data series objects. Please note that each data series must have the same length, as different lengths is not currently supported.
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
# Data structure
|
|
54
|
+
data = [
|
|
55
|
+
{
|
|
56
|
+
label: 'Some interesting data',
|
|
57
|
+
values: [0, 1, 2, 3, 4, 5]
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
label: 'Even more interesting data',
|
|
61
|
+
values: [15, 22, 14, 30, 20, 18]
|
|
62
|
+
},
|
|
63
|
+
...and so on...
|
|
64
|
+
]
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Custom X values
|
|
68
|
+
By default x values are set to the index of the dataseries, meaning the X-axis will go from 0 -> N where N is the data series length. You can provide custom X values if the standard x values aren't desired:
|
|
69
|
+
|
|
70
|
+
```sh
|
|
71
|
+
# Setup custom X Values
|
|
72
|
+
let customXValues = ['A', 'B', 'C', 'D', 'E', 'F']
|
|
40
73
|
|
|
74
|
+
<Barline
|
|
75
|
+
data={data}
|
|
76
|
+
xValues={customXValues}
|
|
77
|
+
type="line"
|
|
78
|
+
height={400}
|
|
79
|
+
width={600}
|
|
80
|
+
title="Chart title"
|
|
81
|
+
lineWidth={2}
|
|
82
|
+
yMaxValuePadding={1}
|
|
83
|
+
/>
|
|
41
84
|
```
|
|
85
|
+
|
|
86
|
+
## Options
|
|
87
|
+
Final Barline has a wide array of customization options to alter the chart to your liking.
|
|
88
|
+
|
|
89
|
+
- `responsive` - Turn responsiveness of the chart on or off. Default: `TRUE`
|
|
90
|
+
- `title` - Title of the chart. Placed top center if provided. Default: NONE
|
|
91
|
+
- `width` - Provide a custom width for the chart. Note that this requires `responsive` to be `FALSE`
|
|
92
|
+
- `height` - Provide a custom height for the chart. Default: `220`
|
|
93
|
+
- `xValueSuffix` - Text placed after each X tick label (also shown in tooltip when hovering the graph)
|
|
94
|
+
- `yValueSuffix` - Text placed after each Y tick label (also shown in tooltip header when hovering the graph)
|
|
95
|
+
- `lineWidth` - Width of each data serie's graph line. Only applicable when `type = line` (line graph)
|
|
96
|
+
- `paddingSides` - Provide your own padding to each side of the chart. Options are:
|
|
97
|
+
- `paddingSides.left` - Padding to the left of the chart
|
|
98
|
+
- `paddingSides.right` - Padding to the right of the chart
|
|
99
|
+
- `paddingSides.top` - Padding to the top of the chart
|
|
100
|
+
- `paddingSides.bottom` - Padding to the bottom of the chart
|
|
101
|
+
- `xValueCulling` - By default all x values are shown. Sometimes when there are alot of data points, the graph will get unreadable. Use xValueCulling to limit how many x values are shown
|
|
102
|
+
- `yValueCulling` - Same as `xValueCulling`, but for the y values
|
|
103
|
+
- `xMin, xMax, yMin, yMax` - By default Final Barline calculates the min/max for x and y. If you'd instead like to set these values yourself, use these
|
|
104
|
+
- `showLegend` - Turn on/off the data series legend. Default: `TRUE`
|
|
105
|
+
- `xValuePrecision, yValuePrecision` - Number precision formatting to apply to the x and y values
|
|
106
|
+
- `showHorizontalGridLines` - Whether or not to display horizontal (Y axis and to the right) gridlines. Default: `TRUE`
|
|
107
|
+
- `showVerticalGridLines` - Whether or not to display vertical gridlines (X axis and down). Default: `TRUE`
|
|
108
|
+
- `yMaxValuePadding` - Apply padding to the max value of Y. Useful if some additional space is needed at the top. Not to be confused with `paddingSides.top` which alters where the chart starts. Default: `0`
|
|
109
|
+
|
|
110
|
+
_Header image credit: Square Enix_
|
package/dist/Barline.svelte
CHANGED
|
@@ -81,6 +81,7 @@
|
|
|
81
81
|
} = $props();
|
|
82
82
|
|
|
83
83
|
let chartContainerWidth = $state(0);
|
|
84
|
+
let tooltipWidth = $state(0);
|
|
84
85
|
let showGraphGrid = $state(true);
|
|
85
86
|
let svgChartElement: SVGSVGElement;
|
|
86
87
|
// Start position of the X/Y axis, to the right of the Y axis
|
|
@@ -117,9 +118,8 @@
|
|
|
117
118
|
const xScale = (x: number) => {
|
|
118
119
|
// TODO: Add padding to computedXMax if need for padding on the right side
|
|
119
120
|
// NOTE: Added padding to the right side to ensure scale factor has enough room
|
|
120
|
-
const ratio = (x - computedXMin) / (computedXMax
|
|
121
|
-
const res =
|
|
122
|
-
chartSafetyMarginX / 2 + paddingSides.left + paddingSides.right + ratio * chartWidth;
|
|
121
|
+
const ratio = (x - computedXMin) / (computedXMax - computedXMin);
|
|
122
|
+
const res = ratio * chartWidth;
|
|
123
123
|
// Clamp to the drawable area
|
|
124
124
|
return Math.max(paddingSides.left + paddingSides.right, Math.min(chartWidth, res));
|
|
125
125
|
};
|
|
@@ -162,7 +162,15 @@
|
|
|
162
162
|
*/
|
|
163
163
|
let mouseHoverX = $derived(dataHoverIndex >= 0 ? xScale(dataHoverIndex) : 0);
|
|
164
164
|
|
|
165
|
-
let tooltipX = $derived(
|
|
165
|
+
let tooltipX = $derived.by(() => {
|
|
166
|
+
// Determine when the mouse is hovering so far to the right that there's not enough space to show the tooltip and its width
|
|
167
|
+
if (mouseHoverX > chartWidth - tooltipWidth - 10) {
|
|
168
|
+
return mouseHoverX - tooltipWidth;
|
|
169
|
+
} else {
|
|
170
|
+
// Mouse is hovering to the left half of the chart, tooltip is shown to the right of the mouse cursor
|
|
171
|
+
return mouseHoverX + 5;
|
|
172
|
+
}
|
|
173
|
+
});
|
|
166
174
|
let tooltipY = $state(0);
|
|
167
175
|
|
|
168
176
|
let isHoveringChart = $state(false);
|
|
@@ -207,8 +215,8 @@
|
|
|
207
215
|
// Convert from the dimensions of the image to a corresponding data index in the chart
|
|
208
216
|
const relative = mouseX / chartWidth;
|
|
209
217
|
const index = Math.round(computedXMin + relative * (computedXMax - computedXMin));
|
|
210
|
-
tooltipY = event.clientY - rect.top
|
|
211
|
-
dataHoverIndex = Math.max(0, Math.min(pointCount
|
|
218
|
+
tooltipY = event.clientY - rect.top; // 10px below the mouse
|
|
219
|
+
dataHoverIndex = Math.max(0, Math.min(pointCount, index));
|
|
212
220
|
isHoveringChart = true;
|
|
213
221
|
};
|
|
214
222
|
|
|
@@ -225,14 +233,14 @@
|
|
|
225
233
|
return [];
|
|
226
234
|
}
|
|
227
235
|
|
|
228
|
-
const barWidth = innerWidth / pointCount;
|
|
236
|
+
const barWidth = innerWidth / pointCount / 2;
|
|
229
237
|
|
|
230
238
|
const groups = Array.from({ length: pointCount }, (_, dataSeriesIndex) => {
|
|
231
239
|
const xBaseLine = xScale(dataSeriesIndex);
|
|
232
240
|
return data.map((series, seriesIndex) => {
|
|
233
241
|
const v = series.values[dataSeriesIndex];
|
|
234
242
|
const x = xBaseLine + seriesIndex * barWidth - barWidth / 2;
|
|
235
|
-
const y =
|
|
243
|
+
const y = yScale(v);
|
|
236
244
|
const h = innerHeight + (paddingSides.top + paddingSides.bottom) - y;
|
|
237
245
|
return {
|
|
238
246
|
x,
|
|
@@ -249,10 +257,13 @@
|
|
|
249
257
|
* Creates values for X, taking into account any x culling settings
|
|
250
258
|
*/
|
|
251
259
|
const xTicks = $derived.by(() => {
|
|
260
|
+
// Ensure the culling value isn't larger than max number of data points
|
|
261
|
+
const xCulling = Math.min(xValueCulling, pointCount - 1);
|
|
262
|
+
|
|
252
263
|
const range = computedXMax - computedXMin;
|
|
253
|
-
const step = Math.max(1, Math.floor(range /
|
|
264
|
+
const step = Math.max(1, Math.floor(range / xCulling));
|
|
254
265
|
|
|
255
|
-
const indexes = Array.from({ length:
|
|
266
|
+
const indexes = Array.from({ length: xCulling + 1 }, (_, i) => computedXMin + i * step);
|
|
256
267
|
|
|
257
268
|
// Use a set to ensure unique values
|
|
258
269
|
const unique = Array.from(new Set(indexes));
|
|
@@ -260,12 +271,20 @@
|
|
|
260
271
|
return unique.map((index) => {
|
|
261
272
|
// TODO: Using base index as fallback will cause issues when adding a xValuePadding and using custom xValues
|
|
262
273
|
const value = xValues?.[index] !== undefined ? xValues[index] : index;
|
|
274
|
+
let position = xScale(index);
|
|
275
|
+
let labelPosition = position;
|
|
276
|
+
if (index === 0) {
|
|
277
|
+
labelPosition = position + 10;
|
|
278
|
+
} else if (index === pointCount - 1) {
|
|
279
|
+
labelPosition = position - 10;
|
|
280
|
+
}
|
|
263
281
|
return {
|
|
264
282
|
value:
|
|
265
283
|
timeFormatting && value === 0
|
|
266
284
|
? 'Now'
|
|
267
285
|
: `${value.toFixed(xValuePrecision)}${xValueSuffix}`,
|
|
268
|
-
position:
|
|
286
|
+
position: position,
|
|
287
|
+
labelPosition: labelPosition
|
|
269
288
|
};
|
|
270
289
|
});
|
|
271
290
|
});
|
|
@@ -391,7 +410,7 @@
|
|
|
391
410
|
{#if isEnoughDataForPresentation}
|
|
392
411
|
<!-- Axis labels and grid lines -->
|
|
393
412
|
<!-- X-axis -->
|
|
394
|
-
{#each xTicks as { value, position }, index (`x-axis-label-${index}`)}
|
|
413
|
+
{#each xTicks as { value, position, labelPosition }, index (`x-axis-label-${index}`)}
|
|
395
414
|
{#if showGraphGrid}
|
|
396
415
|
<!-- LINES - Vertical -->
|
|
397
416
|
<line
|
|
@@ -405,7 +424,7 @@
|
|
|
405
424
|
{/if}
|
|
406
425
|
<!-- LABELS - X axis -->
|
|
407
426
|
<text
|
|
408
|
-
x={
|
|
427
|
+
x={labelPosition}
|
|
409
428
|
y={innerHeight + verticalPadding + 15}
|
|
410
429
|
text-anchor="middle"
|
|
411
430
|
font-size="12"
|
|
@@ -421,8 +440,8 @@
|
|
|
421
440
|
{#if showGraphGrid}
|
|
422
441
|
<!-- LINES - Horizontal -->
|
|
423
442
|
<line
|
|
424
|
-
x1={showHorizontalGridLines ? chartSafetyMarginX / 2
|
|
425
|
-
x2={showHorizontalGridLines ? chartWidth
|
|
443
|
+
x1={showHorizontalGridLines ? chartSafetyMarginX / 2 : verticalPadding}
|
|
444
|
+
x2={showHorizontalGridLines ? chartWidth : horizontalPadding - 5}
|
|
426
445
|
y1={y}
|
|
427
446
|
y2={y}
|
|
428
447
|
stroke="#ccc"
|
|
@@ -504,8 +523,8 @@
|
|
|
504
523
|
<line
|
|
505
524
|
x1={0}
|
|
506
525
|
x2={chartContainerWidth}
|
|
507
|
-
y1={tooltipY
|
|
508
|
-
y2={tooltipY
|
|
526
|
+
y1={tooltipY + 1}
|
|
527
|
+
y2={tooltipY + 1}
|
|
509
528
|
stroke="#2B9C6A"
|
|
510
529
|
stroke-width="1"
|
|
511
530
|
stroke-dasharray="4 4"
|
|
@@ -527,6 +546,7 @@
|
|
|
527
546
|
<!-- Tooltip for the graph -->
|
|
528
547
|
{#if isHoveringChart && dataHoverIndex >= 0}
|
|
529
548
|
<div
|
|
549
|
+
bind:clientWidth={tooltipWidth}
|
|
530
550
|
class="barline-tooltip"
|
|
531
551
|
style="
|
|
532
552
|
left: {tooltipX}px;
|
|
@@ -557,14 +577,14 @@
|
|
|
557
577
|
</div>
|
|
558
578
|
</div>
|
|
559
579
|
{/if}
|
|
560
|
-
<div class="
|
|
580
|
+
<div class="export-button-container">
|
|
561
581
|
<button
|
|
562
582
|
class="barline-export-chart-button"
|
|
563
583
|
onclick={() => {
|
|
564
584
|
exportSvg(svgChartElement);
|
|
565
585
|
}}
|
|
566
586
|
>
|
|
567
|
-
Export
|
|
587
|
+
🖼️ Export
|
|
568
588
|
</button>
|
|
569
589
|
</div>
|
|
570
590
|
</div>
|
|
@@ -572,22 +592,7 @@
|
|
|
572
592
|
<style>
|
|
573
593
|
.barline-chart {
|
|
574
594
|
font-family: 'Open Sans', 'Lato', 'Helvetica', 'Ubuntu', sans-serif;
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
.barline-export-chart-button {
|
|
578
|
-
background-color: #222;
|
|
579
|
-
color: #fff;
|
|
580
|
-
border: none;
|
|
581
|
-
padding: 8px 16px;
|
|
582
|
-
border-radius: 4px;
|
|
583
|
-
font-size: 14px;
|
|
584
|
-
cursor: pointer;
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
.barline-export-chart-button:hover {
|
|
588
|
-
background-color: #3f3f3f;
|
|
589
|
-
color: #ffac11;
|
|
590
|
-
transition: all 0.25s ease-in-out;
|
|
595
|
+
position: relative;
|
|
591
596
|
}
|
|
592
597
|
|
|
593
598
|
.barline-tooltip {
|
|
@@ -600,10 +605,6 @@
|
|
|
600
605
|
z-index: 500;
|
|
601
606
|
}
|
|
602
607
|
|
|
603
|
-
.barline-chart-title {
|
|
604
|
-
font-weight: bold;
|
|
605
|
-
}
|
|
606
|
-
|
|
607
608
|
.barline-tooltip-header {
|
|
608
609
|
/*bg-dark-blue-horizontal-gradient text-white p-2*/
|
|
609
610
|
background-color: #222;
|
|
@@ -621,4 +622,24 @@
|
|
|
621
622
|
.barline-tooltip-content dd {
|
|
622
623
|
margin: 0;
|
|
623
624
|
}
|
|
625
|
+
|
|
626
|
+
.barline-export-chart-button {
|
|
627
|
+
background-color: #222;
|
|
628
|
+
color: #fff;
|
|
629
|
+
border: none;
|
|
630
|
+
padding: 8px 16px;
|
|
631
|
+
border-radius: 4px;
|
|
632
|
+
font-size: 14px;
|
|
633
|
+
cursor: pointer;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
.barline-export-chart-button:hover {
|
|
637
|
+
background-color: #3f3f3f;
|
|
638
|
+
color: #ffac11;
|
|
639
|
+
transition: all 0.25s ease-in-out;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
.barline-chart-title {
|
|
643
|
+
font-weight: bold;
|
|
644
|
+
}
|
|
624
645
|
</style>
|