svelte-plots-basic 2.5.7 → 3.0.0
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/README.md +530 -445
- package/package.json +5 -2
- package/src/2d/Area.svelte +56 -48
- package/src/2d/Axes.svelte +409 -373
- package/src/2d/AxisLines.svelte +37 -36
- package/src/2d/AxisTickLabels.svelte +41 -49
- package/src/2d/Bars.svelte +102 -47
- package/src/2d/Box.svelte +21 -41
- package/src/2d/ColormapLegend.svelte +47 -111
- package/src/2d/Heatmap.svelte +107 -85
- package/src/2d/Legend.svelte +115 -126
- package/src/2d/Lines.svelte +54 -40
- package/src/2d/Multilines.svelte +73 -46
- package/src/2d/Points.svelte +76 -58
- package/src/2d/Rectangles.svelte +67 -58
- package/src/2d/Segments.svelte +59 -46
- package/src/2d/TextLabels.svelte +102 -72
- package/src/2d/TextLegend.svelte +17 -39
- package/src/2d/XAxis.svelte +49 -98
- package/src/2d/YAxis.svelte +47 -93
- package/src/2d/index.js +2 -1
- package/src/3d/Axes.svelte +306 -348
- package/src/3d/AxisLines.svelte +19 -37
- package/src/3d/AxisTickLabels.svelte +15 -32
- package/src/3d/Lines.svelte +59 -32
- package/src/3d/Mesh.svelte +106 -128
- package/src/3d/Points.svelte +56 -36
- package/src/3d/Segments.svelte +68 -52
- package/src/3d/TextLabels.svelte +63 -49
- package/src/3d/XAxis.svelte +36 -113
- package/src/3d/YAxis.svelte +36 -113
- package/src/3d/ZAxis.svelte +37 -114
- package/src/3d/index.js +2 -1
- package/src/constants.js +103 -0
- package/src/methods.js +1484 -0
- package/src/2d/Axis.svelte +0 -60
- package/src/3d/Axis.svelte +0 -64
- package/src/Colors.js +0 -51
- package/src/Utils.js +0 -626
package/src/2d/AxisLines.svelte
CHANGED
|
@@ -1,51 +1,52 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component Draws line segments for axis elements (axis, ticks, etc.).
|
|
3
|
+
|
|
4
|
+
Main properties:
|
|
5
|
+
- `lineCoords` - coordinates of the line segments as 2D array.
|
|
6
|
+
- `lineColor` - color of the box line, default: `Colors.DARKGRAY`.
|
|
7
|
+
- `lineWidth` - width of box line in pixels, default: `1`.
|
|
8
|
+
- `lineType` - line type (`1` - solid (default), `2` - dashed, `3` - dotted, `4` - dashdot).
|
|
9
|
+
- `className` - string with classname to be added to `<g></g>` tag wrapping the lines.
|
|
10
|
+
|
|
11
|
+
**Description:**
|
|
12
|
+
|
|
13
|
+
The coordinates msut be provided in form of nested arrays. Each element of this array contains
|
|
14
|
+
`Vector` or `Array` with the coordinates in world (not screen) coordinate system:
|
|
15
|
+
- `lineCoords[0][0]` - x-coordinates of start points of segments.
|
|
16
|
+
- `lineCoords[1][0]` - x-coordinates of end points of segments.
|
|
17
|
+
- `lineCoords[0][1]` - y-coordinates of start points of segments.
|
|
18
|
+
- `lineCoords[1][1]` - y-coordinates of end points of segments.
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
-->
|
|
1
22
|
<script>
|
|
2
|
-
/****************************************************
|
|
3
|
-
* Axis lines *
|
|
4
|
-
* -------------------- *
|
|
5
|
-
* generic component for axis lines (main, grid, ...)*
|
|
6
|
-
* !!! not for users !!! *
|
|
7
|
-
*****************************************************/
|
|
8
|
-
|
|
9
23
|
import { getContext } from 'svelte';
|
|
10
|
-
import { Colors } from '../
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
/*****************************************/
|
|
14
|
-
/* Input parameters */
|
|
15
|
-
/*****************************************/
|
|
24
|
+
import { Colors, LINE_STYLES } from '../constants.js';
|
|
25
|
+
import { transformCoords } from '../methods.js';
|
|
16
26
|
|
|
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
27
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
let {
|
|
29
|
+
lineCoords = [], // coordinates of start and end points of the lines
|
|
30
|
+
lineColor = Colors.DARKGRAY, // line color
|
|
31
|
+
lineType = 1, // line type
|
|
32
|
+
lineWidth = 1, // lined width (thickness)
|
|
33
|
+
className = '' // CSS class name for the component
|
|
34
|
+
} = $props();
|
|
27
35
|
|
|
28
36
|
// get axes context and adjust x margins
|
|
29
37
|
const axes = getContext('axes');
|
|
30
|
-
const scale = axes.scale;
|
|
31
|
-
const tX = axes.tX;
|
|
32
|
-
const tY = axes.tY;
|
|
33
38
|
|
|
34
39
|
// reactive variables for coordinates of axis lines
|
|
35
|
-
let x1
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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]}`;
|
|
40
|
+
let x1 = $derived(transformCoords(lineCoords[0][0], axes.tX()));
|
|
41
|
+
let x2 = $derived(transformCoords(lineCoords[1][0], axes.tX()));
|
|
42
|
+
let y1 = $derived(transformCoords(lineCoords[0][1], axes.tY()));
|
|
43
|
+
let y2 = $derived(transformCoords(lineCoords[1][1], axes.tY()));
|
|
45
44
|
|
|
45
|
+
// line style
|
|
46
|
+
let lineStyleStr = $derived(`stroke:${lineColor};stroke-width: ${lineWidth}px;stroke-dasharray:${LINE_STYLES[axes.scales().plot][lineType-1]}`);
|
|
46
47
|
</script>
|
|
47
48
|
|
|
48
|
-
{#if x1
|
|
49
|
+
{#if x1 && y1 && x2 }
|
|
49
50
|
<g class={className}>
|
|
50
51
|
{#each x1 as v, i}
|
|
51
52
|
<line vector-effect="non-scaling-stroke" x1={x1[i]} x2={x2[i]} y1={y1[i]} y2={y2[i]} style={lineStyleStr} />
|
|
@@ -1,66 +1,59 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
1
|
+
<!--
|
|
2
|
+
@component Adds axis tick labels.
|
|
11
3
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
4
|
+
Main properties:
|
|
5
|
+
- `tickCoords` - coordinates of the positions of the ticks line segments in world coordinates.
|
|
6
|
+
- `textColor` - color of the labels' text.
|
|
7
|
+
- `tickLabels` - array with the labels (strings).
|
|
8
|
+
- `pos` - position of the labels related to coordinates (`0` - on, `1` - under - default, `2` - left, `3` - over, `4` - right).
|
|
9
|
+
- `las` - orientation of the labels (`1` - horizontal - default, `2` - vertical).
|
|
15
10
|
|
|
16
|
-
|
|
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)
|
|
11
|
+
**Description:**
|
|
21
12
|
|
|
13
|
+
The ticks coordinates are provided in form of nested arrays. Each element of this array contains
|
|
14
|
+
`Vector` or `Array` with the coordinates in world (not screen) coordinate system:
|
|
15
|
+
- `tickCoords[0][0]` - x-coordinates of start points of tick segments.
|
|
16
|
+
- `tickCoords[1][0]` - x-coordinates of end points of tick segments.
|
|
17
|
+
- `tickCoords[0][1]` - y-coordinates of start points of tick segments.
|
|
18
|
+
- `tickCoords[1][1]` - y-coordinates of end points of tick segments.
|
|
22
19
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
```
|
|
21
|
+
-->
|
|
22
|
+
<script>
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const tX = axes.tX;
|
|
31
|
-
const tY = axes.tY;
|
|
32
|
-
const isOk = axes.isOk;
|
|
24
|
+
import { getContext } from 'svelte';
|
|
25
|
+
import { transformCoords } from '../methods';
|
|
26
|
+
import { LABELS_MARGIN } from '../constants';
|
|
33
27
|
|
|
34
|
-
let el;
|
|
35
28
|
|
|
36
|
-
let
|
|
37
|
-
|
|
29
|
+
let {
|
|
30
|
+
tickCoords, // nested array with tick coordinates
|
|
31
|
+
textColor, // color of tick labels
|
|
32
|
+
tickLabels, // array with tick labels
|
|
33
|
+
pos = 1, // position of tick labels
|
|
34
|
+
las = 1, // rotation of tick labels (1 - horizontal, 2 - vertical)
|
|
35
|
+
} = $props();
|
|
38
36
|
|
|
39
|
-
// reactive calculations triggered by changes in coordinates and plot parameters
|
|
40
|
-
$: if ($isOk) {
|
|
41
|
-
x = axes.transform(tickCoords[1][0], $tX.coords);
|
|
42
|
-
y = axes.transform(tickCoords[1][1], $tY.coords);
|
|
43
|
-
}
|
|
44
37
|
|
|
45
|
-
// reactive
|
|
46
|
-
|
|
38
|
+
// reactive selection of labels' position and line style
|
|
39
|
+
let textAnchor = $derived((['middle', 'middle', 'start', 'middle', 'end'])[pos]);
|
|
40
|
+
let textStyleStr = $derived(`fill:${textColor};`);
|
|
47
41
|
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
dy = ([0, m, 0, -m, 0])[pos];
|
|
53
|
-
}
|
|
42
|
+
// get axes context and compute screen coordinates
|
|
43
|
+
const axes = getContext('axes');
|
|
44
|
+
let x = $derived(transformCoords(tickCoords[1][0], axes.tX()));
|
|
45
|
+
let y = $derived(transformCoords(tickCoords[1][1], axes.tY()));
|
|
54
46
|
|
|
55
|
-
//
|
|
56
|
-
|
|
47
|
+
// compute coordinate shifts based on position and plot scales
|
|
48
|
+
let m = $derived(LABELS_MARGIN[axes.scales().plot]);
|
|
49
|
+
let dx = $derived(([0, 0, m, 0, -m])[pos]);
|
|
50
|
+
let dy = $derived(([0, m, 0, -m, 0])[pos]);
|
|
57
51
|
</script>
|
|
58
52
|
|
|
59
|
-
|
|
60
|
-
<g class="tick-labels" bind:this={el} style={textStyleStr} >
|
|
53
|
+
<g class="tick-labels" style={textStyleStr} >
|
|
61
54
|
{#if las === 2 && pos === 4}
|
|
62
55
|
{#each x as v, i}
|
|
63
|
-
<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=
|
|
56
|
+
<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>
|
|
64
57
|
{/each}
|
|
65
58
|
{:else if las === 2 && pos === 1}
|
|
66
59
|
{#each x as v, i}
|
|
@@ -72,4 +65,3 @@
|
|
|
72
65
|
{/each}
|
|
73
66
|
{/if}
|
|
74
67
|
</g>
|
|
75
|
-
{/if}
|
package/src/2d/Bars.svelte
CHANGED
|
@@ -1,65 +1,120 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component Adds a series of bars.
|
|
3
|
+
|
|
4
|
+
Main properties:
|
|
5
|
+
- `xValues` - vector with x-coordinates of middle points of the bars.
|
|
6
|
+
- `yValues` - vector with y-coordinates of top points of the bars.
|
|
7
|
+
- `barWidth` - width of bars as per cent of maximum width, defaul: `0.8`.
|
|
8
|
+
- `faceColor` - face color of the bars, default: `Colors.PRIMARY`.
|
|
9
|
+
- `lineColor` - border color of the bars, default: `Colors.PRIMARY`.
|
|
10
|
+
- `lineWidth` - width (thickness) of border line in pixels, default: `1`.
|
|
11
|
+
- `onclick` - function (callback) to be called when user clicks on any bar.
|
|
12
|
+
|
|
13
|
+
Example:
|
|
14
|
+
|
|
15
|
+
```svelte
|
|
16
|
+
<script>
|
|
17
|
+
import { Matrix } from 'mdatools/arrays';
|
|
18
|
+
import { Axes, Bars } from 'svelte-plots-basic/2d';
|
|
19
|
+
|
|
20
|
+
const xValues = [2000, 2010, 2020, 2030, 2040];
|
|
21
|
+
const yValues = [1, 100, 200, 300, -150];
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<Axes limX={[1990, 2050]} limY={[-200, 350]}>
|
|
25
|
+
<Bars {xValues} {yValues} lineColor="red" faceColor="pink" />
|
|
26
|
+
</Axes>
|
|
27
|
+
```
|
|
28
|
+
-->
|
|
1
29
|
<script>
|
|
2
|
-
/****************************************************
|
|
3
|
-
* Bars *
|
|
4
|
-
* -------------------- *
|
|
5
|
-
* shows series of bars on a plot *
|
|
6
|
-
*****************************************************/
|
|
7
|
-
|
|
8
|
-
import { max, diff } from 'mdatools/stat';
|
|
9
30
|
import { Vector } from 'mdatools/arrays';
|
|
10
|
-
import { Colors } from '../
|
|
11
|
-
import { checkCoords } from '../
|
|
31
|
+
import { Colors } from '../constants';
|
|
32
|
+
import { checkCoords } from '../methods';
|
|
12
33
|
|
|
13
34
|
import Rectangles from './Rectangles.svelte';
|
|
14
35
|
|
|
15
36
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
/*****************************************/
|
|
29
|
-
/* Component code */
|
|
30
|
-
/*****************************************/
|
|
31
|
-
|
|
32
|
-
let width, left, top, height;
|
|
33
|
-
|
|
34
|
-
// reactive code for computing position of left sides and bar width
|
|
35
|
-
$: {
|
|
36
|
-
|
|
37
|
-
if (!barWidth) {
|
|
38
|
-
barWidth = 0.8;
|
|
39
|
-
}
|
|
37
|
+
/** @type {Props} */
|
|
38
|
+
let {
|
|
39
|
+
xValues, // vector with x-coordinates of middle points of the bars.
|
|
40
|
+
yValues, // vector with y-coordinates of top points of the bars.
|
|
41
|
+
barWidth = 0.8, // width of bars as per cent of maximum width, defaul: `0.8`.
|
|
42
|
+
barWidthExact, // 100% bar width in world coordinates (if not provided computed automatically).
|
|
43
|
+
faceColor = Colors.PRIMARY, // face color of the bars, default: `Colors.PRIMARY`.
|
|
44
|
+
lineColor = Colors.PRIMARY, // border color of the bars, default: `Colors.PRIMARY`.
|
|
45
|
+
lineWidth = 1, // width (thickness) of border line in pixels, default: 1.
|
|
46
|
+
onclick
|
|
47
|
+
} = $props();
|
|
40
48
|
|
|
49
|
+
const bw = $derived.by(() => {
|
|
41
50
|
if (barWidth <= 0 || barWidth > 1) {
|
|
42
|
-
|
|
51
|
+
console.error('Bars: parameter "barWidth" should be between 0 and 1.');
|
|
52
|
+
return null;
|
|
43
53
|
}
|
|
54
|
+
return barWidth;
|
|
55
|
+
});
|
|
44
56
|
|
|
45
|
-
|
|
57
|
+
const x = $derived.by(() => {
|
|
58
|
+
if (!bw) return null;
|
|
46
59
|
const xv = checkCoords(xValues, 'BarSeries');
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
60
|
+
if (!xv) return null;
|
|
61
|
+
const n = xv.length;
|
|
62
|
+
if (n < 1) return null;
|
|
63
|
+
|
|
64
|
+
let w;
|
|
65
|
+
if (barWidthExact) {
|
|
66
|
+
w = barWidthExact;
|
|
67
|
+
} else if (n == 1) {
|
|
68
|
+
console.error('Bars: if only one bar must be shown, value for property "barWidthExact" should be provided.');
|
|
69
|
+
return null;
|
|
70
|
+
} else {
|
|
71
|
+
w = 0;
|
|
72
|
+
let lw = 0;
|
|
73
|
+
for (let i = 1; i < n; i++) {
|
|
74
|
+
lw = Math.abs(xv.v[i - 1] - xv.v[i]);
|
|
75
|
+
if (lw > w) w = lw;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
w = w * barWidth;
|
|
80
|
+
const whalf = w / 2;
|
|
81
|
+
const left = Vector.zeros(n);
|
|
82
|
+
const width = Vector.zeros(n);
|
|
83
|
+
for (let i = 0; i < n; i++) {
|
|
84
|
+
left.v[i] = xv.v[i] - whalf;
|
|
85
|
+
width.v[i] = w;
|
|
86
|
+
}
|
|
51
87
|
|
|
52
|
-
|
|
53
|
-
|
|
88
|
+
return {left, width};
|
|
89
|
+
})
|
|
54
90
|
|
|
91
|
+
const y = $derived.by(() => {
|
|
92
|
+
if (!x) return null;
|
|
55
93
|
const yv = checkCoords(yValues, 'BarSeries');
|
|
56
|
-
if (yv
|
|
57
|
-
|
|
94
|
+
if (!yv) return null;
|
|
95
|
+
const n = yv.length;
|
|
96
|
+
if (n !== x.left.length) {
|
|
97
|
+
console.error('BarSeries: parameters "yValues" must be vector of the same length as "xValues".');
|
|
98
|
+
return null;
|
|
58
99
|
}
|
|
59
100
|
|
|
60
|
-
top =
|
|
61
|
-
height =
|
|
62
|
-
|
|
101
|
+
const top = Vector.zeros(n);
|
|
102
|
+
const height = Vector.zeros(n);
|
|
103
|
+
|
|
104
|
+
for (let i = 0; i < n; i++) {
|
|
105
|
+
const v = yv.v[i];
|
|
106
|
+
top.v[i] = (v > 0 ? v : 0);
|
|
107
|
+
height.v[i] = Math.abs(v);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return {top, height};
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
// local check
|
|
114
|
+
const isOk = $derived(x && y);
|
|
63
115
|
</script>
|
|
64
116
|
|
|
65
|
-
|
|
117
|
+
{#if isOk}
|
|
118
|
+
<Rectangles className="series series-bar" left={x.left} width={x.width} top={y.top} height={y.height}
|
|
119
|
+
lineWidth={lineWidth} {lineColor} {faceColor} {onclick} />
|
|
120
|
+
{/if}
|
package/src/2d/Box.svelte
CHANGED
|
@@ -1,48 +1,28 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component Shows box around axes.
|
|
3
|
+
|
|
4
|
+
Main properties:
|
|
5
|
+
- `lineWidth` - width of box line in pixels, default: `1`.
|
|
6
|
+
- `lineColor` - color of the box line, default: `'#606060'`.
|
|
7
|
+
|
|
8
|
+
Example:
|
|
9
|
+
```svelte
|
|
10
|
+
<script>
|
|
11
|
+
import {Axes, Box} from 'svelte-plots-basic/2d';
|
|
12
|
+
</script>
|
|
13
|
+
<Axes>
|
|
14
|
+
<Box />
|
|
15
|
+
</Axes>
|
|
16
|
+
```
|
|
17
|
+
-->
|
|
1
18
|
<script>
|
|
2
|
-
/****************************************************
|
|
3
|
-
* Box *
|
|
4
|
-
* -------------------- *
|
|
5
|
-
* shows border box around axes *
|
|
6
|
-
*****************************************************/
|
|
7
|
-
|
|
8
19
|
import { getContext } from 'svelte';
|
|
9
|
-
import { Colors } from '../Colors';
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
/*****************************************/
|
|
13
|
-
/* Input parameters */
|
|
14
|
-
/*****************************************/
|
|
15
|
-
|
|
16
|
-
export let slot; // slot name, must be "box"
|
|
17
|
-
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
/* Component code */
|
|
21
|
-
/*****************************************/
|
|
22
|
-
|
|
23
|
-
// check that the box is located in a correct slot
|
|
24
|
-
if (slot !== 'box') {
|
|
25
|
-
throw('Component Box must have \'slot="box"\' attribute.')
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
// get axes context and reactive variables needed to compute coordinates
|
|
21
|
+
let {lineWidth = 1, lineColor = '#606060'} = $props();
|
|
30
22
|
const axes = getContext('axes');
|
|
31
|
-
const xLim = axes.xLim;
|
|
32
|
-
const yLim = axes.yLim;
|
|
33
|
-
const isOk = axes.isOk;
|
|
34
|
-
const tX = axes.tX;
|
|
35
|
-
const tY = axes.tY;
|
|
36
|
-
|
|
37
|
-
// reactive variables for coordinates of box points in pixels
|
|
38
|
-
$: xx = $isOk ? axes.transform($xLim, $tX.coords) : undefined;
|
|
39
|
-
$: yy = $isOk ? axes.transform($yLim, $tY.coords) : undefined;
|
|
40
23
|
|
|
24
|
+
$effect(() => {
|
|
25
|
+
axes.setBox({show:true, lineWidth, lineColor});
|
|
26
|
+
});
|
|
41
27
|
</script>
|
|
42
28
|
|
|
43
|
-
{#if $isOk}
|
|
44
|
-
<g style="pointer-events:none" class="mdaplot__axes-box">
|
|
45
|
-
<rect stroke="{Colors.DARKGRAY}" stroke-width="0.1em" fill="transparent" x={xx[0]} y={yy[1]} width={xx[1] - xx[0]} height={yy[0] - yy[1]} />
|
|
46
|
-
</g>
|
|
47
|
-
{/if}
|
|
48
|
-
|
|
@@ -1,121 +1,57 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component Adds colormap legend.
|
|
3
|
+
|
|
4
|
+
Main properties:
|
|
5
|
+
- `breaks` - array (or vector) with interval breaks boundaries.
|
|
6
|
+
- `colmap` - array with colors for each break.
|
|
7
|
+
- `labels` - array with the labels (strings) for breaks or boundaries (optional).
|
|
8
|
+
- `labelColor` - color of labels, default: `Colors.CLEGEND_LABELS`.
|
|
9
|
+
- `fontSize` - font size for the labels in em, default `0.85`.
|
|
10
|
+
|
|
11
|
+
**Description:**
|
|
12
|
+
|
|
13
|
+
Shows legend as a sequence of colors from `colormap` which correspond to the breaks. Number of
|
|
14
|
+
colors must be equal to the number of elements in array `breaks` minus one.
|
|
15
|
+
|
|
16
|
+
The labels can correspond to each value of the `breaks` array (boundaries) or to each break.
|
|
17
|
+
In the latter the labels will be shown in the middle of each break. If `labels` are not provided,
|
|
18
|
+
the values from `breaks` will be used as the labels.
|
|
19
|
+
|
|
20
|
+
Example:
|
|
21
|
+
|
|
22
|
+
```svelte
|
|
23
|
+
<script>
|
|
24
|
+
import { Axes, ColormapLegend } from 'svelte-plots-basic/2d';
|
|
25
|
+
|
|
26
|
+
const breaks = [0, 1, 2, 3, 4];
|
|
27
|
+
const colmap = ['blue', 'green', 'orange', 'red'];
|
|
28
|
+
const labels = ['A', 'B', 'C', 'D'];
|
|
29
|
+
</script>
|
|
30
|
+
<Axes>
|
|
31
|
+
// all other plotting components are here
|
|
32
|
+
<ColormapLegend {breaks} {colmap} {labels} />
|
|
33
|
+
</Axes>
|
|
34
|
+
```
|
|
35
|
+
-->
|
|
1
36
|
<script>
|
|
2
|
-
/*********************************************************
|
|
3
|
-
* ColormapLegend *
|
|
4
|
-
* -------------------- *
|
|
5
|
-
* shows color map legend on a plot *
|
|
6
|
-
**********************************************************/
|
|
7
|
-
|
|
8
37
|
import { getContext } from 'svelte';
|
|
9
|
-
import {
|
|
10
|
-
import { Vector, isvector } from 'mdatools/arrays';
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
/*****************************************/
|
|
14
|
-
/* Input parameters */
|
|
15
|
-
/*****************************************/
|
|
16
|
-
|
|
17
|
-
export let breaks; // vector with breaks for color intervals or vector with their indices
|
|
18
|
-
export let colmap; // array with colors for each interval
|
|
19
|
-
export let decNum = 1; // number of decimals to show the interval boundaries with
|
|
20
|
-
export let labels = null; // optional vector with labels for interval boundaries or elements
|
|
21
|
-
export let labelColor = '#909090'; // color of labels
|
|
22
|
-
export let fontSize = 0.85; // font size for labels in em
|
|
23
|
-
|
|
24
|
-
// if number of breaks is the same as number of elements in color map
|
|
25
|
-
// the corresponding labels will be placed in the middle inder each color element in the legend
|
|
26
|
-
// if this number is by one larger, the labels will be placed on the boundaries
|
|
27
|
-
|
|
28
|
-
/*****************************************/
|
|
29
|
-
/* Component code */
|
|
30
|
-
/*****************************************/
|
|
31
|
-
|
|
32
|
-
// constant parameters
|
|
33
|
-
const WIDTH_RATIO = 0.80; // legend will span 80% of plot width
|
|
34
|
-
const HEIGHT_RATIO = 0.02; // legend will span 2% of plot height
|
|
35
|
-
const TOP_MARGIN = 0.25; // legend top margin is 25% of its height
|
|
36
|
-
|
|
37
|
-
// height of the legend elements in pixels
|
|
38
|
-
const EL_HEIGHTS_PX = {'small': 5, 'medium': 8, 'large': 12, 'xlarge': 15};
|
|
39
|
-
|
|
40
|
-
// check breaks values
|
|
41
|
-
$: if (!breaks || breaks.length < 2) {
|
|
42
|
-
throw new Error('ColormapLegend: breaks values must be provided.');
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// check colormap values
|
|
46
|
-
$: if (!colmap || !(colmap.length === breaks.length - 1 || colmap.length === breaks.length )) {
|
|
47
|
-
throw new Error('ColormapLegend: number of color values in colormap does not match number of intervals defined by breaks.');
|
|
48
|
-
}
|
|
38
|
+
import { Colors } from '../constants';
|
|
49
39
|
|
|
50
|
-
// define local variables for breaks and prepare breaks labels
|
|
51
|
-
$: lBreaks = isvector(breaks) ? breaks.v : breaks;
|
|
52
40
|
|
|
53
|
-
let
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
41
|
+
let {
|
|
42
|
+
breaks, // vector with breaks for color intervals or vector with their indices
|
|
43
|
+
colmap, // array with colors for each interval
|
|
44
|
+
labels = null, // optional vector with labels for interval boundaries or elements
|
|
45
|
+
labelColor = Colors.CLEGEND_LABELS, // color of labels
|
|
46
|
+
fontSize = 0.85, // font size for labels in em
|
|
47
|
+
} = $props();
|
|
60
48
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// get axes context and reactive variables needed to compute coordinates
|
|
49
|
+
// get axes context and set the parameters of colormap legend (the rest will be done by Axes component)
|
|
64
50
|
const axes = getContext('axes');
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const yLim = axes.yLim;
|
|
69
|
-
const scale = axes.scale;
|
|
70
|
-
const isOk = axes.isOk;
|
|
71
|
-
|
|
72
|
-
// number of elements
|
|
73
|
-
$: n = colmap.length;
|
|
74
|
-
$: isCentered = lLabels && lLabels.length === n;
|
|
75
|
-
|
|
76
|
-
// compute screen coordinates of the elements
|
|
77
|
-
let dxl, rx, ry, rw, rh = undefined;
|
|
78
|
-
$: {
|
|
79
|
-
if ($isOk) {
|
|
80
|
-
// compute size of the whole block in plot coordinates
|
|
81
|
-
const axesWidth = $xLim[1] - $xLim[0];
|
|
82
|
-
const axesHeight = $yLim[1] - $yLim[0];
|
|
83
|
-
const width = axesWidth * WIDTH_RATIO;
|
|
84
|
-
const height = axesHeight * HEIGHT_RATIO;
|
|
85
|
-
|
|
86
|
-
// compute elements size and position
|
|
87
|
-
const elWidth = width / (n + (breakFactor !== 0));
|
|
88
|
-
const left = $xLim[0] + axesWidth * (1 - WIDTH_RATIO) * 0.5 ;
|
|
89
|
-
const elTop = $yLim[1] - height * TOP_MARGIN;
|
|
90
|
-
|
|
91
|
-
// compute screen coordinates and sized
|
|
92
|
-
ry = axes.transform(checkCoords([elTop], 'Rectangles'), $tY.coords);
|
|
93
|
-
rx = axes.transform(Vector.seq(0, n).apply(v => left + v * elWidth), $tX.coords);
|
|
94
|
-
rw = axes.transform([elWidth], $tX.objects);
|
|
95
|
-
rh = EL_HEIGHTS_PX[$scale];
|
|
96
|
-
dxl = isCentered ? rw[0] / 2 : 0
|
|
97
|
-
}
|
|
98
|
-
};
|
|
51
|
+
$effect(() => {
|
|
52
|
+
axes.setColmapLegend({show: true, breaks, colmap, labels, labelColor, fontSize})
|
|
53
|
+
});
|
|
99
54
|
</script>
|
|
100
55
|
|
|
101
|
-
{#if $isOk && rx.length > 0}
|
|
102
|
-
<g class="series colormap_legend" style="stroke:0;stroke-width:0px;">
|
|
103
|
-
{#each colmap as col, i}
|
|
104
|
-
<rect x={rx[i]} y={ry} width={rw} height={rh} fill="{col}"/>
|
|
105
|
-
<text x={rx[i]} y={ry} dx={dxl} dy={rh * 1.25} dominant-baseline="hanging" fill={labelColor} font-size="{fontSize}em" text-anchor="middle">{@html lLabels[i]}</text>
|
|
106
|
-
{/each}
|
|
107
|
-
{#if !isCentered}
|
|
108
|
-
<text x={rx[n]} y={ry} dx={0} dy={rh * 1.25} dominant-baseline="hanging" fill={labelColor} font-size="{fontSize}em" text-anchor="middle">{@html lLabels[n]}</text>
|
|
109
|
-
{/if}
|
|
110
|
-
|
|
111
|
-
{#if breakFactor !== 0}
|
|
112
|
-
<text x={rx[n] + rw[0] * 0.85} y={ry[0] + rh * 2.2} dx={0} dy={0} dominant-baseline="hanging" fill={labelColor} font-size="{fontSize}em" text-anchor="middle">{@html getTickFactorLabel(breakFactor)}</text>
|
|
113
|
-
{/if}
|
|
114
|
-
|
|
115
|
-
</g>
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
{/if}
|
|
119
|
-
|
|
120
56
|
|
|
121
57
|
|