svelte-plots-basic 1.1.3 → 2.0.1

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.
Files changed (50) hide show
  1. package/README.md +54 -69
  2. package/package.json +28 -33
  3. package/src/2d/Area.svelte +61 -0
  4. package/src/2d/Axes.svelte +500 -0
  5. package/src/2d/Axis.svelte +50 -0
  6. package/src/2d/AxisLines.svelte +54 -0
  7. package/src/2d/AxisTickLabels.svelte +82 -0
  8. package/src/2d/Bars.svelte +65 -0
  9. package/src/2d/Box.svelte +50 -0
  10. package/src/2d/ColorLegend.svelte +36 -0
  11. package/src/2d/Legend.svelte +148 -0
  12. package/src/2d/Lines.svelte +49 -0
  13. package/src/2d/Multilines.svelte +67 -0
  14. package/src/2d/Points.svelte +79 -0
  15. package/src/2d/Rectangles.svelte +74 -0
  16. package/src/2d/Segments.svelte +65 -0
  17. package/src/2d/TextLabels.svelte +107 -0
  18. package/src/2d/TextLegend.svelte +53 -0
  19. package/src/2d/XAxis.svelte +99 -0
  20. package/src/2d/YAxis.svelte +99 -0
  21. package/src/{index.js → 2d/index.js} +10 -6
  22. package/src/3d/Axes.svelte +445 -0
  23. package/src/3d/Axis.svelte +64 -0
  24. package/src/3d/AxisLines.svelte +50 -0
  25. package/src/3d/AxisTickLabels.svelte +54 -0
  26. package/src/3d/Lines.svelte +49 -0
  27. package/src/3d/Mesh.svelte +188 -0
  28. package/src/3d/Points.svelte +61 -0
  29. package/src/3d/Segments.svelte +69 -0
  30. package/src/3d/TextLabels.svelte +79 -0
  31. package/src/3d/XAxis.svelte +123 -0
  32. package/src/3d/YAxis.svelte +123 -0
  33. package/src/3d/ZAxis.svelte +123 -0
  34. package/src/3d/index.js +13 -0
  35. package/src/Colors.js +36 -1
  36. package/src/Utils.js +205 -0
  37. package/dist/index.js +0 -4209
  38. package/dist/index.mjs +0 -4187
  39. package/src/AreaSeries.svelte +0 -53
  40. package/src/Axes.svelte +0 -538
  41. package/src/BarSeries.svelte +0 -78
  42. package/src/Box.svelte +0 -35
  43. package/src/LineSeries.svelte +0 -50
  44. package/src/Rectangles.svelte +0 -64
  45. package/src/ScatterSeries.svelte +0 -85
  46. package/src/Segments.svelte +0 -48
  47. package/src/TextLabels.svelte +0 -78
  48. package/src/TextLegend.svelte +0 -38
  49. package/src/XAxis.svelte +0 -69
  50. package/src/YAxis.svelte +0 -72
@@ -0,0 +1,500 @@
1
+ <script>
2
+ /****************************************************
3
+ * Axes *
4
+ * -------------------- *
5
+ * root item for any plot *
6
+ *****************************************************/
7
+
8
+ import { setContext, createEventDispatcher, onMount, onDestroy } from 'svelte';
9
+ import { writable } from 'svelte/store';
10
+ import { isvector, vector, Vector } from 'mdatools/arrays';
11
+ import { roundCoords, getScale } from '../Utils.js';
12
+
13
+
14
+ /*****************************************/
15
+ /* Input parameters */
16
+ /*****************************************/
17
+
18
+ export let limX; // array with limits for x-axis (in plot units) [min, max]
19
+ export let limY; // array with limits for y-axis (in plot units) [min, max]
20
+ export let title = ''; // title of the plot
21
+ export let xLabel = ''; // label for x-axis
22
+ export let yLabel = ''; // label for y-axis
23
+ export let margins = [0.034, 0.034, 0.034, 0.034]; // margins [bottom, left, top, right] )
24
+
25
+
26
+ /*****************************************/
27
+ /* Constants */
28
+ /*****************************************/
29
+
30
+ // event dispatcher
31
+ const dispatch = createEventDispatcher();
32
+
33
+ // how big are margins (number of pixels in unit margin value) between axis and plot area if axis are shown
34
+ const AXES_MARGIN_FACTORS = {
35
+ 'small': 30,
36
+ 'medium': 40,
37
+ 'large': 50,
38
+ 'xlarge': 60
39
+ }
40
+
41
+ // number of ticks along each axis
42
+ const TICK_NUM = {
43
+ 'small': 5,
44
+ 'medium': 8,
45
+ 'large': 12,
46
+ 'xlarge': 15
47
+ };
48
+
49
+ // size of ticks
50
+ const TICK_SIZE = {
51
+ 'small': 4,
52
+ 'medium': 6,
53
+ 'large': 8,
54
+ 'xlarge': 10
55
+ };
56
+
57
+ // font size for legend items in pixels
58
+ const LEGEND_FONT_SIZE = {
59
+ "small": 10,
60
+ "medium": 12,
61
+ "large": 14,
62
+ "xlarge": 16
63
+ };
64
+
65
+ // margin between plot series elements and data labels
66
+ const LABELS_MARGIN = {
67
+ 'small': 10,
68
+ 'medium': 13,
69
+ 'large': 15,
70
+ 'xlarge': 17
71
+ };
72
+
73
+ // line styles for different scales and types
74
+ const LINE_STYLES = {
75
+ small: ['0', '3,3', '1,1', '3,1'],
76
+ medium: ['0', '5,5', '2,2', '5,2'],
77
+ large: ['0', '7,7', '3,3', '7,3'],
78
+ xlarge: ['0', '9,9', '4,4', '9,3'],
79
+ }
80
+
81
+ // marker symbols
82
+ const MARKER_SYMBOLS = ["●", "◼", "▲", "▼", "⬥", "+", "*", "×"];
83
+
84
+ // constant to make clip path ID unique
85
+ const clipPathID = 'plottingArea' + Math.round(Math.random() * 10000);
86
+
87
+
88
+ /*****************************************/
89
+ /* Variable parameters for internal use */
90
+ /*****************************************/
91
+
92
+ /* parameters for internal use inside the component */
93
+ let plotElement;
94
+ let axesElement;
95
+ let width, height = 100;
96
+
97
+
98
+ /*****************************************/
99
+ /* Helper functions */
100
+ /*****************************************/
101
+
102
+ /**
103
+ * Dispatcher for click events.
104
+ * @param {string} eventName - name of the event.
105
+ * @param {HTMLDOMElement} el - DOM element the click was registered for.
106
+ *
107
+ */
108
+ function dispatchClickEvent(eventName, el) {
109
+ const id = Array.prototype.indexOf.call(el.parentNode.children, el)
110
+ dispatch(eventName, {seriesTitle: el.parentNode.getAttribute('title'), elementID: id});
111
+ }
112
+
113
+ /**
114
+ * Handler (router) for click events.
115
+ *
116
+ * @param {event} e - event object.
117
+ *
118
+ * @description
119
+ * Checks which element the click was made on and dispatch a corresponding event.
120
+ *
121
+ */
122
+ function handleClick(e) {
123
+
124
+ // click on scatter plot markers
125
+ if (e.target.tagName === 'text' && e.target.parentNode.classList.contains('series_points')) {
126
+ dispatchClickEvent('markerclick', e.target);
127
+ return;
128
+ }
129
+
130
+ // click on bar plot bars
131
+ if (e.target.tagName === 'rect' && e.target.parentNode.classList.contains('series_bar')) {
132
+ dispatchClickEvent('barclick', e.target);
133
+ return;
134
+ }
135
+
136
+ // click outside any plot element
137
+ dispatch('axesclick');
138
+ }
139
+
140
+ /**
141
+ * Generic function to transform x or y-values from plot coordinates to screen (SVG) coordinates.
142
+ *
143
+ * @param {Array|Vector} v - vector with coordinates (or objects size) in original plot coordinates.
144
+ * @param {Object} tA - array with scaling and translation factors.
145
+ *
146
+ * @returns {Vector} vector with rescaled values
147
+ *
148
+ */
149
+ const transform = function(v, tA) {
150
+
151
+ if (!$isOk || v === undefined || v === null) return undefined;
152
+ if (Array.isArray(v)) v = vector(v);
153
+ if (!isvector(v) || v.length < 1) return undefined;
154
+
155
+ return v.apply(a => roundCoords((a - tA[1]) * tA[0] + tA[2])).v;
156
+ }
157
+
158
+
159
+ /**
160
+ * Generic function to transform x or y-values from screen (SVG) coordinates to plot coordinates.
161
+ *
162
+ * @param {Array|Vector} v - vector with coordinates (or objects size) in screen (SVG) coordinates.
163
+ * @param {Object} tA - array with scaling and translation factors.
164
+ *
165
+ * @returns {Vector} vector plot coordinates.
166
+ *
167
+ */
168
+ const invTransform = function(v, tA) {
169
+
170
+ if (!$isOk || v === undefined || v === null) return undefined;
171
+ if (Array.isArray(v)) v = vector(v);
172
+ if (!isvector(v) || v.length < 1) return undefined;
173
+
174
+ return v.apply(a => (a - tA[2]) / tA[0] + tA[1]).v;
175
+ }
176
+
177
+ /*****************************************/
178
+ /* Storage to share with children */
179
+ /*****************************************/
180
+
181
+ const scale = writable('medium'); // scale factor (how big the shown plot is)
182
+ const tX = writable({'coords': [1, 0, 0], 'objects': [1, 0, 0]}); // scaling and translation factors for x-dimension
183
+ const tY = writable({'coords': [1, 0, 0], 'objects': [1, 0, 0]}); // scaling and translation factors for y-dimension
184
+ const isOk = writable(false); // are axes ready for drawing
185
+ const xLim = writable(limX);
186
+ const yLim = writable(limY);
187
+
188
+
189
+ /*****************************************/
190
+ /* Axes context */
191
+ /*****************************************/
192
+
193
+ let context = {
194
+
195
+ // methods
196
+ transform: transform,
197
+ invTransform: invTransform,
198
+
199
+ // variables
200
+ scale: scale,
201
+ isOk: isOk,
202
+ xLim: xLim,
203
+ yLim: yLim,
204
+ tX: tX,
205
+ tY: tY,
206
+
207
+ // constants
208
+ LINE_STYLES: LINE_STYLES,
209
+ LABELS_MARGIN: LABELS_MARGIN,
210
+ TICK_NUM: TICK_NUM,
211
+ TICK_SIZE: TICK_SIZE,
212
+ MARKER_SYMBOLS: MARKER_SYMBOLS,
213
+ LEGEND_FONT_SIZE: LEGEND_FONT_SIZE
214
+ }
215
+
216
+ setContext('axes', context);
217
+
218
+ /*****************************************/
219
+ /* Reactive updates of the parameters */
220
+ /*****************************************/
221
+
222
+ // computes real margins in pixels based on current scale
223
+ $: pxMargins = margins.map(v => v * AXES_MARGIN_FACTORS[$scale]);
224
+
225
+ // update limits if necessary
226
+ $: xLim.update(v => limX);
227
+ $: yLim.update(v => limY);
228
+
229
+ // computes status which tells that axes limits look fine and it is safe to draw
230
+ // the status is based on the axis limits validity
231
+ $: isOk.update(v =>
232
+ Array.isArray($yLim) &&
233
+ Array.isArray($xLim) &&
234
+ $xLim.length === 2 &&
235
+ $yLim.length === 2 &&
236
+ !$yLim.some(v => v === undefined) &&
237
+ !$xLim.some(v => v === undefined) &&
238
+ !$yLim.some(v => isNaN(v)) &&
239
+ !$xLim.some(v => isNaN(v)) &&
240
+ $xLim[1] !== $xLim[0] &&
241
+ $yLim[1] !== $yLim[0] &&
242
+ width > (pxMargins[1] + pxMargins[3]) &&
243
+ height > (pxMargins[0] + pxMargins[2])
244
+ )
245
+
246
+ // update transformation array for x-coordinates
247
+ $: {
248
+ if ($isOk) {
249
+ tX.update(v => ({
250
+ 'coords': [ (width - pxMargins[1] - pxMargins[3]) / ($xLim[1] - $xLim[0]), $xLim[0], pxMargins[1]],
251
+ 'objects': [ (width - pxMargins[1] - pxMargins[3]) / ($xLim[1] - $xLim[0]), 0, 0]
252
+ }));
253
+ }
254
+ };
255
+
256
+ // update transformation array for y-coordinates
257
+ $: {
258
+ if ($isOk) {
259
+ tY.update(v => ({
260
+ 'coords': [-(height - pxMargins[0] - pxMargins[2]) / ($yLim[1] - $yLim[0]), $yLim[1], pxMargins[2]],
261
+ 'objects': [ (height - pxMargins[0] - pxMargins[2]) / ($yLim[1] - $yLim[0]), 0, 0]
262
+ }));
263
+ }
264
+ };
265
+
266
+ // computes coordinates for clip path box
267
+ $: cpx = $isOk ? transform($xLim, $tX.coords) : [0, 1];
268
+ $: cpy = $isOk ? transform($yLim, $tY.coords) : [1, 0];
269
+
270
+
271
+ /*****************************************/
272
+ /* Events observers */
273
+ /*****************************************/
274
+
275
+ // observer for the plot area size — to update the scale
276
+ const ro1 = new ResizeObserver(entries => {
277
+ for (let entry of entries) {
278
+ const pcr = plotElement.getBoundingClientRect();
279
+ scale.update(x => getScale(pcr.width, pcr.height));
280
+ }
281
+ });
282
+
283
+ // observer for the axes area size - to update size of axes
284
+ const ro2 = new ResizeObserver(entries => {
285
+ for (let entry of entries) {
286
+ const acr = axesElement.getBoundingClientRect();
287
+ width = acr.width;
288
+ height = acr.height;
289
+ }
290
+ });
291
+
292
+ onMount(() => {
293
+ ro1.observe(plotElement);
294
+ ro2.observe(axesElement);
295
+ });
296
+
297
+ onDestroy(() => {
298
+ ro1.unobserve(plotElement);
299
+ ro2.unobserve(axesElement);
300
+ })
301
+
302
+ </script>
303
+
304
+ <div class="plot {'plot_' + $scale}" bind:this={plotElement} class:plot_error={!$isOk}>
305
+ <!-- plot title and axis labels -->
306
+ {#if title !== ''}<div class="axes__title">{@html title}</div>{/if}
307
+ {#if yLabel !== ''}<div class="axes__ylabel"><span>{@html yLabel}</span></div>{/if}
308
+ {#if xLabel !== ''}<div class="axes__xlabel"><span>{@html xLabel}</span></div>{/if}
309
+
310
+ <!-- axes (coordinate system) -->
311
+ <div class="axes-wrapper" bind:this={axesElement} >
312
+ <svg on:click={handleClick} on:keydown={handleClick} preserveAspectRatio="none" class="axes">
313
+
314
+ <!-- define clipping path -->
315
+ <defs>
316
+ <clipPath id={clipPathID}>
317
+ <rect style="pointer-events:none" x={cpx[0]} y={cpy[1]} width={cpx[1]-cpx[0]} height={cpy[0]-cpy[1]} />
318
+ </clipPath>
319
+ </defs>
320
+
321
+
322
+ <!-- axis and box -->
323
+ <slot name="xaxis"></slot>
324
+ <slot name="yaxis"></slot>
325
+
326
+ <!-- main plot content -->
327
+ <g class="axes-content" clip-path="url(#{clipPathID})">
328
+ <slot></slot>
329
+ </g>
330
+
331
+
332
+ <!-- axis and box -->
333
+ <slot name="box"></slot>
334
+
335
+ </svg>
336
+
337
+ {#if !$isOk}
338
+ <p class="message_error">
339
+ Axes component was not properly initialized. <br />
340
+ Check that you defined axes limits and margins correctly.
341
+ </p>
342
+ {/if}
343
+ </div>
344
+
345
+
346
+ </div>
347
+
348
+ <style>
349
+
350
+ /* Plot (main container) */
351
+ .plot {
352
+ font-family: Arial, Helvetica, sans-serif;
353
+
354
+ display: grid;
355
+ grid-template-columns: min-content auto;
356
+ grid-template-rows: min-content auto min-content;
357
+ grid-template-areas:
358
+ ". title"
359
+ "ylab axes"
360
+ ". xlab";
361
+
362
+ box-sizing: border-box;
363
+ /* background: #fefefe; */
364
+ min-width: 100px;
365
+ min-height: 50px;
366
+ width: 100%;
367
+ height: 100%;
368
+ padding: 0;
369
+ margin: 0;
370
+ }
371
+
372
+ .plot_small {
373
+ font-size: 11px;
374
+ }
375
+
376
+ .plot_medium {
377
+ font-size: 13px;
378
+ }
379
+
380
+ .plot_large {
381
+ font-size: 16px;
382
+ }
383
+
384
+ .plot_xlarge {
385
+ font-size: 19px;
386
+ }
387
+
388
+ .plot_error {
389
+ display: flex;
390
+ }
391
+
392
+ .plot_error > .axes-wrapper > svg {
393
+ display: none;
394
+ }
395
+
396
+ .message_error {
397
+ font-size: 1.2em;
398
+ color: crimson;
399
+ padding: 1em;
400
+ box-sizing: border-box;
401
+ text-align: center;
402
+ }
403
+
404
+ /* Axes (coordinate system) */
405
+ .axes-wrapper {
406
+ grid-area: axes;
407
+ position:relative;
408
+ box-sizing: border-box;
409
+ display: flex;
410
+ width: 100%;
411
+ height: 100%;
412
+ padding: 0;
413
+ margin: 0;
414
+ }
415
+
416
+ .axes {
417
+ display: block;
418
+ box-sizing: border-box;
419
+ position:absolute;
420
+
421
+ padding: 0;
422
+ margin: 0;
423
+ height: 100%;
424
+ width: 100%;
425
+ max-height: 100%;
426
+ max-width: 100%;
427
+ min-height: 100%;
428
+ min-width: 100%;
429
+ }
430
+
431
+ .axes-content {
432
+ padding: 0;
433
+ margin: 0;
434
+ height: 100%;
435
+ width: 100%;
436
+ max-height: 100%;
437
+ max-width: 100%;
438
+ min-height: 100%;
439
+ min-width: 100%;
440
+
441
+ }
442
+
443
+ .axes__xlabel {
444
+ grid-area: xlab;
445
+ font-size: 1.0em;
446
+ font-weight: 600;
447
+ padding: 0.25em;
448
+ text-align: center;
449
+ }
450
+
451
+
452
+ .axes__ylabel {
453
+ grid-area: ylab;
454
+ font-size: 1.0em;
455
+ font-weight: 600;
456
+ padding: 0.25em;
457
+ text-align: center;
458
+ vertical-align: middle;
459
+ display: flex;
460
+ }
461
+
462
+ .axes__ylabel > span {
463
+ width: 1.5em;
464
+ line-height: 1.5em;
465
+ display: inline-block;
466
+ writing-mode: vertical-rl;
467
+ transform: rotate(180deg);
468
+ }
469
+
470
+
471
+ .axes__title {
472
+ background: transparent;
473
+ grid-area: title;
474
+
475
+ font-size: 1.3em;
476
+ font-weight: bold;
477
+ line-height: 1.2em;
478
+ padding: 0.5em 0;
479
+ text-align: center;
480
+ }
481
+
482
+ /* Axis */
483
+ :global(.axis-labels) {
484
+ fill: #303030;
485
+ font-size: 0.95em;
486
+ }
487
+
488
+ /* Data labels */
489
+ :global(.labels) {
490
+ fill: #606060;
491
+ font-size: 0.90em;
492
+ }
493
+
494
+ :global(.labels) {
495
+ visibility: hidden;
496
+ transition:visibility 0.25s linear, opacity 0.25s linear;
497
+ opacity: 0;
498
+ }
499
+
500
+ </style>
@@ -0,0 +1,50 @@
1
+ <script>
2
+ /****************************************************
3
+ * Axis *
4
+ * --------------------------------- *
5
+ * generic element for X- or Y-axis *
6
+ * !!! not for users !!! *
7
+ *****************************************************/
8
+
9
+ import { Colors } from '../Colors.js';
10
+ import AxisLines from './AxisLines.svelte';
11
+ import AxisTickLabels from './AxisTickLabels.svelte';
12
+
13
+
14
+ /*****************************************/
15
+ /* Input parameters */
16
+ /*****************************************/
17
+
18
+ export let tickLabels = []; // vector with labels for each tick
19
+ export let showGrid = false; // logical, show or not grid lines
20
+ export let las = 1; // rotation of tick labels
21
+
22
+ export let pos = 1; // position of tick labels
23
+ export let className = ""; // name of CSS class for the axis
24
+ export let grid = []; // array with grid coordinates
25
+ export let axisLine = []; // array with coordinates of main axis line
26
+ export let tickCoords = []; // array with axis tick coordinates
27
+
28
+ export let lineColor = Colors.DARKGRAY; // color of main axis line
29
+ export let gridColor = Colors.MIDDLEGRAY; // color of grid lines
30
+ export let textColor = Colors.DARKGRAY; // color of tick labels
31
+ </script>
32
+
33
+ <g class="mdaplot__axis {className}">
34
+ <!-- grid -->
35
+ {#if showGrid }
36
+ <AxisLines lineCoords={grid} lineColor={gridColor} lineType={3} />
37
+ {/if}
38
+
39
+ <!-- main axis line -->
40
+ <AxisLines lineCoords={axisLine} lineColor={lineColor} lineType={1} />
41
+
42
+ <!-- ticks-->
43
+ <AxisLines lineCoords={tickCoords} lineColor={lineColor} lineType={1} />
44
+
45
+ <!-- labels -->
46
+ {#if tickCoords.length === 2 && tickLabels.length === tickCoords[1][0].length}
47
+ <AxisTickLabels {las} {pos} {tickCoords} {tickLabels} {textColor}/>
48
+ {/if}
49
+ </g>
50
+
@@ -0,0 +1,54 @@
1
+ <script>
2
+ /****************************************************
3
+ * Axis lines *
4
+ * -------------------- *
5
+ * generic component for axis lines (main, grid, ...)*
6
+ * !!! not for users !!! *
7
+ *****************************************************/
8
+
9
+ import { getContext } from 'svelte';
10
+ import { Colors } from '../Colors.js';
11
+
12
+
13
+ /*****************************************/
14
+ /* Input parameters */
15
+ /*****************************************/
16
+
17
+ export let lineCoords = []; // coordinates of start and end points of the lines
18
+ export let lineColor = Colors.DARKGRAY; // line color
19
+ export let lineType = 1; // line type
20
+ export let lineWidth = 1; // lined width (thickness)
21
+ export let className = ''; // CSS class name for the component
22
+
23
+
24
+ /*****************************************/
25
+ /* Component code */
26
+ /*****************************************/
27
+
28
+ // get axes context and adjust x margins
29
+ const axes = getContext('axes');
30
+ const scale = axes.scale;
31
+ const tX = axes.tX;
32
+ const tY = axes.tY;
33
+
34
+ // reactive variables for coordinates of axis lines
35
+ let x1, x2, y1, y2 = undefined;
36
+ $: if (lineCoords.length == 2) {
37
+ x1 = axes.transform(lineCoords[0][0], $tX.coords);
38
+ y1 = axes.transform(lineCoords[0][1], $tY.coords);
39
+ x2 = axes.transform(lineCoords[1][0], $tX.coords);
40
+ y2 = axes.transform(lineCoords[1][1], $tY.coords);
41
+ }
42
+
43
+ /* styles for axis and grid lines */
44
+ $: lineStyleStr = `stroke:${lineColor};stroke-width: ${lineWidth}px;stroke-dasharray:${axes.LINE_STYLES[$scale][lineType-1]}`;
45
+
46
+ </script>
47
+
48
+ {#if x1 !== undefined && y1 !== undefined && x2 !== undefined && y2 !== undefined}
49
+ <g class={className}>
50
+ {#each x1 as v, i}
51
+ <line vector-effect="non-scaling-stroke" x1={x1[i]} x2={x2[i]} y1={y1[i]} y2={y2[i]} style={lineStyleStr} />
52
+ {/each}
53
+ </g>
54
+ {/if}
@@ -0,0 +1,82 @@
1
+ <script>
2
+ /****************************************************
3
+ * AxisTickLabels *
4
+ * -------------------- *
5
+ * shows a series of tick labels along an axis *
6
+ * !!! not for users !!! *
7
+ *****************************************************/
8
+
9
+ import { getContext } from 'svelte';
10
+
11
+
12
+ /*****************************************/
13
+ /* Input parameters */
14
+ /*****************************************/
15
+
16
+ export let tickCoords; // array with tick coordinates
17
+ export let textColor; // color of tick labels
18
+ export let tickLabels; // array with tick labels
19
+ export let pos = 1; // position of tick labels
20
+ export let las = 1; // rotation of tick labels (1 - horizontal, 2 - vertical)
21
+
22
+
23
+ /*****************************************/
24
+ /* Component code */
25
+ /*****************************************/
26
+
27
+ // get axes context and reactive variables needed to compute coordinates
28
+ const axes = getContext('axes');
29
+ const scale = axes.scale;
30
+ const tX = axes.tX;
31
+ const tY = axes.tY;
32
+ const isOk = axes.isOk;
33
+
34
+
35
+ let x, y = undefined;
36
+ let dx = 0, dy = 0, textAnchor;
37
+
38
+ // reactive calculations triggered by changes in coordinates and plot parameters
39
+ $: if ($isOk) {
40
+ x = axes.transform(tickCoords[1][0], $tX.coords);
41
+ y = axes.transform(tickCoords[1][1], $tY.coords);
42
+ }
43
+
44
+ // reactive calculations triggered by changes in scale
45
+ $: m = axes.LABELS_MARGIN[$scale];
46
+
47
+ // reactive calculations triggered by changes in pos
48
+ $: {
49
+ textAnchor = (['middle', 'middle', 'start', 'middle', 'end'])[pos];
50
+ dx = ([0, 0, m, 0, -m])[pos];
51
+ dy = ([0, m, 0, -m, 0])[pos];
52
+ }
53
+
54
+ // styles for the elements
55
+ $: textStyleStr = `dominant-baseline:middle;fill:${textColor};font-size:1em; text-anchor:middle;`;
56
+ </script>
57
+
58
+ {#if x !== undefined && y !== undefined}
59
+ <g class="tick_labels" style={textStyleStr} >
60
+ {#if las === 2 && pos === 4}
61
+ {#each x as v, i}
62
+ <text data-id={i} x={x[i]} y={y[i]} dx={0} dy={dx*1.25} transform={`rotate(-90, ${x[i]}, ${y[i]})`} text-anchor={"middle"}>{@html tickLabels[i]}</text>
63
+ {/each}
64
+ {:else if las === 2 && pos === 1}
65
+ {#each x as v, i}
66
+ <text data-id={i} x={x[i]} y={y[i]} dx={-dy/2} dy={0} transform={`rotate(-90, ${x[i]}, ${y[i]})`} text-anchor={"end"}>{@html tickLabels[i]}</text>
67
+ {/each}
68
+ {:else}
69
+ {#each x as v, i}
70
+ <text data-id={i} x={x[i]} y={y[i]} dx={dx} dy={dy} text-anchor={textAnchor}>{@html tickLabels[i]}</text>
71
+ {/each}
72
+ {/if}
73
+ </g>
74
+ {/if}
75
+
76
+ <style>
77
+ text, text > :global(tspan) {
78
+ cursor: default;
79
+ user-select: none;
80
+ dominant-baseline: middle;
81
+ }
82
+ </style>