svelte-plots-basic 3.4.0 → 4.1.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/NEWS.md +76 -0
- package/README.md +39 -49
- package/package.json +13 -12
- package/src/2d/Area.svelte +8 -7
- package/src/2d/Axes.svelte +10 -8
- package/src/2d/AxisLines.svelte +4 -6
- package/src/2d/AxisTickLabels.svelte +1 -3
- package/src/2d/Bars.svelte +30 -9
- package/src/2d/Heatmap.svelte +15 -6
- package/src/2d/Legend.svelte +74 -30
- package/src/2d/Lines.svelte +6 -5
- package/src/2d/Multilines.svelte +9 -8
- package/src/2d/Points.svelte +9 -9
- package/src/2d/Rectangles.svelte +47 -18
- package/src/2d/Segments.svelte +3 -3
- package/src/2d/TextLabels.svelte +12 -10
- package/src/2d/TextLegend.svelte +49 -11
- package/src/2d/YAxis.svelte +1 -1
- package/src/3d/Axes.svelte +5 -7
- package/src/3d/AxisLines.svelte +3 -4
- package/src/3d/AxisTickLabels.svelte +2 -2
- package/src/3d/Lines.svelte +8 -8
- package/src/3d/Mesh.svelte +15 -13
- package/src/3d/Points.svelte +8 -9
- package/src/3d/Segments.svelte +11 -13
- package/src/3d/TextLabels.svelte +27 -14
- package/src/3d/XAxis.svelte +2 -4
- package/src/3d/YAxis.svelte +4 -6
- package/src/3d/ZAxis.svelte +4 -6
- package/src/ExportDialog.svelte +236 -66
- package/src/methods.js +241 -127
package/src/2d/Legend.svelte
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
Main properties:
|
|
5
5
|
- `items` - array with text labels and their visual properties for each legend element.
|
|
6
6
|
- `position` - position of the legend ("topleft", "top", "topright", "right", etc), default: `"topleft"`.
|
|
7
|
+
- `orientation` - arrangement of legend items (`"vertical"` or `"horizontal"`), default: `"vertical"`.
|
|
7
8
|
- `lineColor` - color of the legend box line, default: `Colors.LEGEND`.
|
|
8
9
|
- `lineWidth` - width (thickness) of the legend box line in pixels: `1`.
|
|
9
10
|
- `faceColor` - color of the legend box background: `'#fff'`.
|
|
@@ -13,41 +14,47 @@
|
|
|
13
14
|
|
|
14
15
|
```svelte
|
|
15
16
|
<script>
|
|
16
|
-
import {Vector} from 'mdatools/
|
|
17
|
+
import { Vector } from 'mdatools/arrays';
|
|
18
|
+
import { Axes, Box, Legend, Lines, Points, XAxis, YAxis } from 'svelte-plots-basic/2d';
|
|
17
19
|
|
|
18
20
|
const x = Vector.seq(-10, 10, 0.1);
|
|
19
21
|
const y1 = x.apply(v => Math.cos(v));
|
|
20
22
|
const y2 = x.apply(v => Math.sin(v));
|
|
23
|
+
|
|
24
|
+
const line1 = { lineType: 3, lineColor: 'red' };
|
|
25
|
+
const line2 = { lineType: 1, lineColor: 'blue' };
|
|
26
|
+
const point2 = { marker: 1, faceColor: 'white', lineColor: 'blue' };
|
|
27
|
+
|
|
28
|
+
const items = [
|
|
29
|
+
{ label: 'cos(x)', line: line1 },
|
|
30
|
+
{ label: 'sin(x)', line: line2, point: point2 }
|
|
31
|
+
];
|
|
21
32
|
</script>
|
|
22
33
|
|
|
23
34
|
<Axes limX={[-10, 10]} limY={[-1.1, 1.1]} >
|
|
24
35
|
|
|
25
|
-
<Lines xValues={x} yValues={y1}
|
|
26
|
-
<Lines xValues={x} yValues={y2}
|
|
27
|
-
<Points xValues={x} yValues={y2}
|
|
36
|
+
<Lines xValues={x} yValues={y1} {...line1} />
|
|
37
|
+
<Lines xValues={x} yValues={y2} {...line2} />
|
|
38
|
+
<Points xValues={x} yValues={y2} {...point2} />
|
|
28
39
|
|
|
29
|
-
<Legend
|
|
30
|
-
position="topright"
|
|
31
|
-
items = {[
|
|
32
|
-
{"label": "cos(x)", "lineType": 1, "lineColor": "red"},
|
|
33
|
-
{"label": "sin(x)", "lineType": 1, "lineColor": "blue", "marker": 1, "faceColor": "white", "borderColor": "blue"},
|
|
34
|
-
]}
|
|
35
|
-
/>
|
|
40
|
+
<Legend position="top" orientation="horizontal" {items} />
|
|
36
41
|
|
|
37
42
|
<Box />
|
|
38
43
|
<XAxis label="x" showGrid={true} />
|
|
39
44
|
<YAxis label="f(x)" showGrid={true} />
|
|
40
45
|
</Axes>
|
|
46
|
+
```
|
|
41
47
|
-->
|
|
42
48
|
<script>
|
|
43
49
|
import { getContext, onDestroy } from 'svelte';
|
|
44
50
|
import { Colors, MARKER_SYMBOLS } from '../constants';
|
|
45
|
-
import { text2svg } from '../methods';
|
|
51
|
+
import { text2svg, normalizeLineType } from '../methods';
|
|
46
52
|
|
|
47
53
|
let {
|
|
48
54
|
items, // array with text labels and their visual properties for each legend element.
|
|
49
55
|
show = true, // logical, use to hide the element
|
|
50
|
-
|
|
56
|
+
position = 'topleft', // position of the legend ("topleft", "top", "topright", "right", "bottomright", etc).
|
|
57
|
+
orientation = 'vertical', // arrangement of legend items ("vertical" or "horizontal")
|
|
51
58
|
lineColor = Colors.LEGEND, // color of the legend box line
|
|
52
59
|
lineWidth = 1, // width (thickness) of the legend box line
|
|
53
60
|
faceColor = '#fff', // background color of the legend box
|
|
@@ -70,6 +77,21 @@
|
|
|
70
77
|
return position;
|
|
71
78
|
}
|
|
72
79
|
|
|
80
|
+
/* check if user provided orientation is correct */
|
|
81
|
+
function checkOrientation(orientation) {
|
|
82
|
+
|
|
83
|
+
if (typeof orientation !== 'string') {
|
|
84
|
+
console.error('Legend: value of "orientation" must be a string.');
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!['vertical', 'horizontal'].includes(orientation)) {
|
|
89
|
+
console.error('Legend: wrong value of "orientation" property');
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
return orientation;
|
|
93
|
+
}
|
|
94
|
+
|
|
73
95
|
/* check if user provided items are correct, transform text labels and set default values if they are absent */
|
|
74
96
|
function processItems(items) {
|
|
75
97
|
|
|
@@ -96,25 +118,35 @@
|
|
|
96
118
|
// set default values for lines
|
|
97
119
|
if (item.line) {
|
|
98
120
|
item.line = {...item.line};
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
121
|
+
item.line.lineType = normalizeLineType(
|
|
122
|
+
item.line.lineType ?? 1,
|
|
123
|
+
`Legend item ${i + 1}`
|
|
124
|
+
);
|
|
103
125
|
item.line.lineColor = item.line.lineColor ? item.line.lineColor : Colors.PRIMARY;
|
|
104
|
-
item.line.lineWidth = item.line.lineWidth
|
|
126
|
+
item.line.lineWidth = item.line.lineWidth ?? 1;
|
|
105
127
|
}
|
|
106
128
|
|
|
107
129
|
// set default values for markers
|
|
108
130
|
if (item.point) {
|
|
109
131
|
item.point = {...item.point};
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
132
|
+
const canConvertMarker =
|
|
133
|
+
typeof item.point.marker === 'number' ||
|
|
134
|
+
(typeof item.point.marker === 'string' && item.point.marker.trim() !== '');
|
|
135
|
+
const marker = item.point.marker == null ? 1 :
|
|
136
|
+
canConvertMarker ? Number(item.point.marker) : NaN;
|
|
137
|
+
|
|
138
|
+
if (!Number.isInteger(marker) || marker < 1 || marker > MARKER_SYMBOLS.length) {
|
|
139
|
+
console.error(
|
|
140
|
+
`Legend item ${i + 1}: parameter "marker" must be a whole number from 1 to ${MARKER_SYMBOLS.length}.`
|
|
141
|
+
);
|
|
142
|
+
item.point = null;
|
|
143
|
+
} else {
|
|
144
|
+
item.point.marker = marker;
|
|
145
|
+
item.point.faceColor = item.point.faceColor ? item.point.faceColor : 'transparent';
|
|
146
|
+
item.point.lineWidth = item.point.lineWidth ?? 1;
|
|
147
|
+
item.point.markerSize = item.point.markerSize ?? 1;
|
|
148
|
+
item.point.lineColor = item.point.lineColor ? item.point.lineColor : Colors.PRIMARY;
|
|
113
149
|
}
|
|
114
|
-
item.point.faceColor = item.point.faceColor ? item.point.faceColor : 'transparent';
|
|
115
|
-
item.point.lineWidth = item.point.lineWidth ? item.point.lineWidth : 1;
|
|
116
|
-
item.point.markerSize = item.point.markerSize ? item.point.markerSize : 1;
|
|
117
|
-
item.point.lineColor = item.point.lineColor ? item.point.lineColor : Colors.PRIMARY;
|
|
118
150
|
}
|
|
119
151
|
|
|
120
152
|
result.push(item);
|
|
@@ -122,14 +154,26 @@
|
|
|
122
154
|
return result;
|
|
123
155
|
}
|
|
124
156
|
|
|
125
|
-
//
|
|
157
|
+
// Validate and transform only when the corresponding input changes.
|
|
158
|
+
const processedItems = $derived(processItems(items));
|
|
159
|
+
const validPosition = $derived(checkPosition(position));
|
|
160
|
+
const validOrientation = $derived(checkOrientation(orientation));
|
|
161
|
+
|
|
162
|
+
// get context and update group legend parameters reactively
|
|
126
163
|
const axes = getContext('axes');
|
|
127
164
|
$effect(() => {
|
|
128
|
-
const newItems = processItems(items);
|
|
129
|
-
const newPosition = checkPosition(position);
|
|
130
165
|
axes.setGroupLegend(
|
|
131
|
-
|
|
132
|
-
{
|
|
166
|
+
processedItems && validPosition && validOrientation ?
|
|
167
|
+
{
|
|
168
|
+
show,
|
|
169
|
+
position: validPosition,
|
|
170
|
+
orientation: validOrientation,
|
|
171
|
+
items: processedItems,
|
|
172
|
+
lineColor,
|
|
173
|
+
faceColor,
|
|
174
|
+
lineWidth,
|
|
175
|
+
fontSize
|
|
176
|
+
} :
|
|
133
177
|
{show: false, position: null, items: null}
|
|
134
178
|
);
|
|
135
179
|
});
|
package/src/2d/Lines.svelte
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
@component Adds a series of lines connecting points with provided coordinates (polyline).
|
|
3
3
|
|
|
4
4
|
Main properties:
|
|
5
|
-
- `xValues` - array
|
|
6
|
-
- `yValues` - array
|
|
5
|
+
- `xValues` - array or vector with x-coordinates of the points.
|
|
6
|
+
- `yValues` - array or vector with y-coordinates of the points.
|
|
7
7
|
- `lineColor` - lines color, default: `Colors.PRIMARY`.
|
|
8
|
-
- `lineWidth` - width (thickness) of the lines in pixels,
|
|
8
|
+
- `lineWidth` - width (thickness) of the lines in pixels, default: `1`.
|
|
9
9
|
- `lineType` - type of lines (`1` - solid, `2` - dashed, `3` - dotted, `4` - dashdot).
|
|
10
10
|
- `onclick` - function (callback) to be called when user clicks on a polyline.
|
|
11
11
|
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
<script>
|
|
28
28
|
import { getContext } from 'svelte';
|
|
29
29
|
import { Colors } from '../constants';
|
|
30
|
-
import { val2p, checkCoords, handleClick } from '../methods';
|
|
30
|
+
import { val2p, checkCoords, handleClick, normalizeLineType } from '../methods';
|
|
31
31
|
import { LINE_STYLES } from '../constants';
|
|
32
32
|
|
|
33
33
|
let {
|
|
@@ -43,13 +43,14 @@
|
|
|
43
43
|
// check user provided coordinates
|
|
44
44
|
const xv = $derived(checkCoords(xValues, 'Lines'));
|
|
45
45
|
const yv = $derived(xv ? checkCoords(yValues, 'Lines', xv.length) : null);
|
|
46
|
+
const validLineType = $derived(normalizeLineType(lineType, 'Lines'));
|
|
46
47
|
|
|
47
48
|
// get axes context and compute coordinates of polyline
|
|
48
49
|
const axes = getContext('axes');
|
|
49
50
|
const p = $derived(xv && yv ? val2p(xv, yv, axes.tX(), axes.tY()) : null);
|
|
50
51
|
|
|
51
52
|
// reactive variables for coordinates of data points in pixels
|
|
52
|
-
const lineStyleStr = $derived(`fill:transparent;stroke:${lineColor};stroke-width: ${lineWidth}px; stroke-dasharray:${LINE_STYLES[axes.scales().plot][
|
|
53
|
+
const lineStyleStr = $derived(`fill:transparent;stroke:${lineColor};stroke-width: ${lineWidth}px; stroke-dasharray:${LINE_STYLES[axes.scales().plot][validLineType - 1]}`);
|
|
53
54
|
</script>
|
|
54
55
|
|
|
55
56
|
{#if p}
|
package/src/2d/Multilines.svelte
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
@component Adds a series of polylines (like `<Lines>` but with several of those).
|
|
3
3
|
|
|
4
4
|
Main properties:
|
|
5
|
-
- `xValues` - array
|
|
6
|
-
- `yValues` - Matrix (object of class `Matrix` from `mdatools/
|
|
5
|
+
- `xValues` - array or vector with x-coordinates of the points.
|
|
6
|
+
- `yValues` - Matrix (object of class `Matrix` from `mdatools/arrays`) with y-coordinates of the points.
|
|
7
7
|
- `lineColor` - lines color, default: `Colors.PRIMARY`.
|
|
8
|
-
- `lineWidth` - width (thickness) of the lines in pixels,
|
|
8
|
+
- `lineWidth` - width (thickness) of the lines in pixels, default: `1`.
|
|
9
9
|
- `lineType` - type of segment lines (`1` - solid, `2` - dashed, `3` - dotted, `4` - dashdot).
|
|
10
10
|
- `onclick` - function (callback) to be called when user clicks on a polyline.
|
|
11
11
|
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
import { Vector, cbind } from 'mdatools/arrays';
|
|
17
17
|
import { Axes, Multilines } from 'svelte-plots-basic/2d';
|
|
18
18
|
|
|
19
|
-
const xValues = Vector.seq(0,
|
|
20
|
-
const
|
|
19
|
+
const xValues = Vector.seq(0, 10, 0.1);
|
|
20
|
+
const yValues = cbind(
|
|
21
21
|
xValues.apply(v => Math.sin(v)),
|
|
22
22
|
xValues.apply(v => Math.sin(v + 0.5) + 0.1),
|
|
23
23
|
xValues.apply(v => Math.sin(v - 0.5) - 0.1),
|
|
@@ -35,12 +35,12 @@
|
|
|
35
35
|
import { getContext } from 'svelte';
|
|
36
36
|
import { ismatrix } from 'mdatools/arrays';
|
|
37
37
|
import { Colors } from '../constants';
|
|
38
|
-
import { val2p, checkCoords, handleClick } from '../methods';
|
|
38
|
+
import { val2p, checkCoords, handleClick, normalizeLineType } from '../methods';
|
|
39
39
|
import { LINE_STYLES } from '../constants';
|
|
40
40
|
|
|
41
41
|
let {
|
|
42
42
|
xValues, // vector or array with x-coordinates of the points
|
|
43
|
-
yValues, //
|
|
43
|
+
yValues, // matrix with y-coordinates of the points
|
|
44
44
|
lineColor = Colors.PRIMARY, // color of segment lines
|
|
45
45
|
lineType = 1, // type of segment lines (1 - solid, 2 - dashed, 3 - dotted, 4 - dashdot)
|
|
46
46
|
lineWidth = 1, // width (thickness) of segment lines
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
|
|
50
50
|
// check user provided coordinates
|
|
51
51
|
const xv = $derived(checkCoords(xValues, 'Multilines'));
|
|
52
|
+
const validLineType = $derived(normalizeLineType(lineType, 'Multilines'));
|
|
52
53
|
const yv = $derived.by(() => {
|
|
53
54
|
|
|
54
55
|
if (!xv) return null;
|
|
@@ -79,7 +80,7 @@
|
|
|
79
80
|
});
|
|
80
81
|
|
|
81
82
|
// reactive variables for coordinates of data points in pixels
|
|
82
|
-
const lineStyleStr = $derived(`fill:transparent;stroke:${lineColor};stroke-width: ${lineWidth}px; stroke-dasharray:${LINE_STYLES[axes.scales().plot][
|
|
83
|
+
const lineStyleStr = $derived(`fill:transparent;stroke:${lineColor};stroke-width: ${lineWidth}px; stroke-dasharray:${LINE_STYLES[axes.scales().plot][validLineType - 1]}`);
|
|
83
84
|
</script>
|
|
84
85
|
|
|
85
86
|
{#if pp && pp.length > 0}
|
package/src/2d/Points.svelte
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
@component Adds a series of points.
|
|
3
3
|
|
|
4
4
|
Main properties:
|
|
5
|
-
- `xValues` - array
|
|
6
|
-
- `yValues` - array
|
|
5
|
+
- `xValues` - array or vector with x-coordinates of the points.
|
|
6
|
+
- `yValues` - array or vector with y-coordinates of the points.
|
|
7
7
|
- `marker` - index for a point symbol (from 1 - default - to 8): `"●", "◼", "▲", "▼", "⬥", "+", "*", "✕"`.
|
|
8
8
|
- `faceColor` - face (fill) color of the markers, default: `'transparent'`.
|
|
9
9
|
- `lineColor` - border color of the markers, default: `Colors.PRIMARY`.
|
|
10
|
-
- `lineWidth` - width (thickness) of the markers' border in pixels,
|
|
11
|
-
- `markerSize` - size of the markers in em,
|
|
10
|
+
- `lineWidth` - width (thickness) of the markers' border in pixels, default: `1`.
|
|
11
|
+
- `markerSize` - size of the markers in em, default: `1`.
|
|
12
12
|
- `onclick` - function (callback) to be called when user clicks on a marker.
|
|
13
13
|
|
|
14
14
|
Example:
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
import { checkCoords, transformCoords, handleClick } from '../methods';
|
|
33
33
|
|
|
34
34
|
let {
|
|
35
|
-
xValues, // array
|
|
36
|
-
yValues, // array
|
|
35
|
+
xValues, // array or vector with x-coordinates of points
|
|
36
|
+
yValues, // array or vector with y-coordinates of points
|
|
37
37
|
marker = 1, // index for point symbol (from 1 to 8): "●", "◼", "▲", "▼", "⬥", "+", "*", "✕"
|
|
38
38
|
faceColor = 'transparent', // face (fill) color of the points
|
|
39
39
|
lineColor = Colors.PRIMARY, // border color of the points
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
|
|
46
46
|
// select which symbol to use as a marker
|
|
47
47
|
const markerSymbol = $derived.by(() => {
|
|
48
|
-
if (
|
|
49
|
-
console.error('Points: parameter "marker" must be a number from 1 to ' + MARKER_SYMBOLS.length + '.');
|
|
48
|
+
if (!Number.isInteger(marker) || marker < 1 || marker > MARKER_SYMBOLS.length) {
|
|
49
|
+
console.error('Points: parameter "marker" must be a whole number from 1 to ' + MARKER_SYMBOLS.length + '.');
|
|
50
50
|
return null;
|
|
51
51
|
}
|
|
52
52
|
return MARKER_SYMBOLS[marker - 1]
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
const className = $derived(['◼', '⬥', '+', '✳', '✕'].includes(markerSymbol) ? 'series-points2' : 'series-points1');
|
|
71
71
|
|
|
72
72
|
// check if all coordinates are correct
|
|
73
|
-
const isOk = $derived(x && y && x.length === y.length);
|
|
73
|
+
const isOk = $derived(markerSymbol && x && y && x.length === y.length);
|
|
74
74
|
</script>
|
|
75
75
|
|
|
76
76
|
{#if isOk}
|
package/src/2d/Rectangles.svelte
CHANGED
|
@@ -3,20 +3,19 @@
|
|
|
3
3
|
|
|
4
4
|
Main properties:
|
|
5
5
|
- `left` - array or vector with world coordinates of left side of the rectangles.
|
|
6
|
-
- `top` - array or vector with world coordinates of
|
|
6
|
+
- `top` - array or vector with world coordinates of top side of the rectangles.
|
|
7
7
|
- `width` - width of the rectangles (one value or array/vector with individual values).
|
|
8
8
|
- `height` - height of the rectangles (one value or array/vector with individual values).
|
|
9
|
-
- `
|
|
9
|
+
- `faceColor` - face color of the rectangles (same for all).
|
|
10
10
|
- `lineColor` - border color of each rectangle.
|
|
11
11
|
- `lineWidth` - width (thickness) of border lines in pixels.
|
|
12
|
-
- `className
|
|
12
|
+
- `className` - CSS class name for the rectangles group, default: `'series-rect'`.
|
|
13
13
|
- `onclick` - function (callback) to be called when user clicks on any rectangle.
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
Example:
|
|
17
|
-
```
|
|
17
|
+
```svelte
|
|
18
18
|
<script>
|
|
19
|
-
import { Matrix } from 'mdatools/arrays';
|
|
20
19
|
import { Axes, Rectangles } from 'svelte-plots-basic/2d';
|
|
21
20
|
|
|
22
21
|
const left = [0, 10, 20, 30];
|
|
@@ -32,27 +31,58 @@
|
|
|
32
31
|
-->
|
|
33
32
|
<script>
|
|
34
33
|
import { getContext } from 'svelte';
|
|
35
|
-
import { Vector } from 'mdatools/arrays';
|
|
34
|
+
import { Vector, isvector } from 'mdatools/arrays';
|
|
36
35
|
import { Colors } from '../constants';
|
|
37
36
|
import { checkCoords, transformCoords, transformObjects, handleClick } from '../methods';
|
|
38
37
|
|
|
39
38
|
let {
|
|
40
|
-
left, // array
|
|
41
|
-
top, // array
|
|
42
|
-
width, // single value (same for all) or vector/array with
|
|
43
|
-
height, // single value (same for all) or vector/array with
|
|
44
|
-
faceColor = Colors.PRIMARY, // color of
|
|
45
|
-
lineColor = faceColor,
|
|
46
|
-
lineWidth = 1, // width (thickness) of
|
|
39
|
+
left, // array or vector with coordinates of left sides of the rectangles
|
|
40
|
+
top, // array or vector with coordinates of top sides of the rectangles
|
|
41
|
+
width, // single value (same for all) or vector/array with rectangle width
|
|
42
|
+
height, // single value (same for all) or vector/array with rectangle height
|
|
43
|
+
faceColor = Colors.PRIMARY, // color of rectangle faces (fill)
|
|
44
|
+
lineColor = faceColor, // color of rectangle borders
|
|
45
|
+
lineWidth = 1, // width (thickness) of rectangle border lines
|
|
47
46
|
className = 'series-rect', // CSS class name of the SVG group
|
|
48
47
|
onclick, // function to be called if onclick event fires
|
|
49
48
|
} = $props();
|
|
50
49
|
|
|
50
|
+
function checkDimensions(value, name, len) {
|
|
51
|
+
const canConvert =
|
|
52
|
+
typeof value === 'number' ||
|
|
53
|
+
(typeof value === 'string' && value.trim() !== '');
|
|
54
|
+
let dimensions;
|
|
55
|
+
|
|
56
|
+
if (canConvert) {
|
|
57
|
+
const scalar = Number(value);
|
|
58
|
+
if (!Number.isFinite(scalar) || scalar < 0) {
|
|
59
|
+
console.error(`Rectangles: parameter "${name}" must contain only finite non-negative values.`);
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
dimensions = Vector.fill(scalar, len);
|
|
63
|
+
} else if (Array.isArray(value) || isvector(value)) {
|
|
64
|
+
dimensions = checkCoords(value, `Rectangles (${name})`, len);
|
|
65
|
+
if (!dimensions) return null;
|
|
66
|
+
} else {
|
|
67
|
+
console.error(`Rectangles: parameter "${name}" must be a number, array, or Vector.`);
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
for (let i = 0; i < dimensions.length; i++) {
|
|
72
|
+
if (dimensions.v[i] < 0) {
|
|
73
|
+
console.error(`Rectangles: parameter "${name}" must contain only finite non-negative values.`);
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return dimensions;
|
|
79
|
+
}
|
|
80
|
+
|
|
51
81
|
// process provided values and compute world coordinates of rectangles
|
|
52
82
|
const l = $derived(checkCoords(left, 'Rectangles (left)'));
|
|
53
83
|
const t = $derived(l ? checkCoords(top, 'Rectangles (top)', l.length) : null);
|
|
54
|
-
const w = $derived(t ? (
|
|
55
|
-
const h = $derived(t ? (
|
|
84
|
+
const w = $derived(t ? checkDimensions(width, 'width', l.length) : null);
|
|
85
|
+
const h = $derived(t ? checkDimensions(height, 'height', l.length) : null);
|
|
56
86
|
|
|
57
87
|
// get axes context and compute screen coordinates
|
|
58
88
|
const axes = getContext('axes');
|
|
@@ -62,11 +92,11 @@
|
|
|
62
92
|
const rw = $derived(w ? transformObjects(w, axes.tX()) : null);
|
|
63
93
|
const rh = $derived(h ? transformObjects(h, axes.tY()) : null);
|
|
64
94
|
|
|
65
|
-
// styles for
|
|
95
|
+
// styles for rectangles
|
|
66
96
|
const barsStyleStr = $derived(`fill:${faceColor};stroke:${lineColor};stroke-width:${lineWidth}px;`);
|
|
67
97
|
|
|
68
98
|
// check if all coordinates are correct
|
|
69
|
-
const isOk = $derived(rx && ry && rw && rh
|
|
99
|
+
const isOk = $derived(rx && ry && rw && rh);
|
|
70
100
|
</script>
|
|
71
101
|
|
|
72
102
|
{#if isOk}
|
|
@@ -78,4 +108,3 @@
|
|
|
78
108
|
{/each}
|
|
79
109
|
</g>
|
|
80
110
|
{/if}
|
|
81
|
-
|
package/src/2d/Segments.svelte
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
<script>
|
|
32
32
|
import { getContext } from 'svelte';
|
|
33
33
|
import { Colors } from '../constants';
|
|
34
|
-
import { checkCoords, transformCoords, handleClick } from '../methods';
|
|
34
|
+
import { checkCoords, transformCoords, handleClick, normalizeLineType } from '../methods';
|
|
35
35
|
import { LINE_STYLES } from '../constants';
|
|
36
36
|
|
|
37
37
|
let {
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
const sy = $derived(sx ? checkCoords(yStart, 'Segments', sx.length) : null);
|
|
52
52
|
const ex = $derived(sy ? checkCoords(xEnd, 'Segments', sx.length) : null);
|
|
53
53
|
const ey = $derived(ex ? checkCoords(yEnd, 'Segments', sx.length) : null);
|
|
54
|
+
const validLineType = $derived(normalizeLineType(lineType, 'Segments'));
|
|
54
55
|
|
|
55
56
|
// get axes context and reactive variables needed to compute coordinates
|
|
56
57
|
const axes = getContext('axes');
|
|
@@ -60,7 +61,7 @@
|
|
|
60
61
|
const y2 = $derived(ey ? transformCoords(ey, axes.tY()) : null);
|
|
61
62
|
|
|
62
63
|
// reactive variables for coordinates of data points in pixels (and line style)
|
|
63
|
-
const lineStyleStr = $derived(`stroke:${lineColor};stroke-width: ${lineWidth}px;stroke-dasharray:${LINE_STYLES[axes.scales().plot][
|
|
64
|
+
const lineStyleStr = $derived(`stroke:${lineColor};stroke-width: ${lineWidth}px;stroke-dasharray:${LINE_STYLES[axes.scales().plot][validLineType - 1]}`);
|
|
64
65
|
|
|
65
66
|
// local status
|
|
66
67
|
const isOk = $derived(x1 && x2 && y1 && y2);
|
|
@@ -75,4 +76,3 @@
|
|
|
75
76
|
{/each}
|
|
76
77
|
</g>
|
|
77
78
|
{/if}
|
|
78
|
-
|
package/src/2d/TextLabels.svelte
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
<!--
|
|
2
|
-
@component Adds
|
|
2
|
+
@component Adds text labels at specified plot coordinates.
|
|
3
3
|
|
|
4
4
|
Main properties:
|
|
5
|
-
- `xValues
|
|
6
|
-
- `yValues
|
|
7
|
-
- `labels
|
|
8
|
-
- `pos
|
|
9
|
-
- `faceColor
|
|
10
|
-
- `lineColor
|
|
11
|
-
- `lineWidth
|
|
12
|
-
- `textSize
|
|
13
|
-
- `rotateAngle
|
|
5
|
+
- `xValues` - vector or array with x-coordinates for each label.
|
|
6
|
+
- `yValues` - vector or array with y-coordinates for each label.
|
|
7
|
+
- `labels` - single string used at every coordinate or array with one string per coordinate.
|
|
8
|
+
- `pos` - one position used for every label, or an array/typed array with one position per label (`0` - middle - default, `1` - bottom, `2` - left, `3` - top, `4` - right).
|
|
9
|
+
- `faceColor` - text fill color, default: `Colors.PRIMARY_TEXT`.
|
|
10
|
+
- `lineColor` - text outline color, default: `'transparent'`.
|
|
11
|
+
- `lineWidth` - text outline width in pixels, default: `0`.
|
|
12
|
+
- `textSize` - text size in em, default: `1`.
|
|
13
|
+
- `rotateAngle` - angle to rotate labels, default: `0`.
|
|
14
14
|
- `onclick` - function (callback) to be called when user clicks on a label.
|
|
15
15
|
|
|
16
|
+
Values in `labels` are rendered as raw SVG/HTML markup. Only pass trusted content.
|
|
17
|
+
|
|
16
18
|
Example:
|
|
17
19
|
|
|
18
20
|
```svelte
|
package/src/2d/TextLegend.svelte
CHANGED
|
@@ -1,7 +1,38 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component Adds a vertical text legend at a specified plot position.
|
|
3
|
+
|
|
4
|
+
Main properties:
|
|
5
|
+
- `left` - x-coordinate of the legend in plot units.
|
|
6
|
+
- `top` - y-coordinate of the legend in plot units.
|
|
7
|
+
- `elements` - non-empty array of text labels. SVG/HTML markup is supported.
|
|
8
|
+
- `dx` - horizontal text offset, default: `"0"`.
|
|
9
|
+
- `dy` - vertical spacing between labels, default: `"1.25em"`.
|
|
10
|
+
- `faceColor` - text fill color, default: `Colors.PRIMARY_TEXT`.
|
|
11
|
+
- `lineColor` - text outline color, default: `"transparent"`.
|
|
12
|
+
- `lineWidth` - text outline width in pixels, default: `0`.
|
|
13
|
+
- `textSize` - text size in em, default: `1`.
|
|
14
|
+
|
|
15
|
+
Values in `elements` are rendered as raw SVG/HTML markup. Only pass trusted content.
|
|
16
|
+
|
|
17
|
+
Example:
|
|
18
|
+
|
|
19
|
+
```svelte
|
|
20
|
+
<script>
|
|
21
|
+
import { Axes, TextLegend } from 'svelte-plots-basic/2d';
|
|
22
|
+
|
|
23
|
+
const elements = ['First group', 'Second group'];
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<Axes limX={[0, 10]} limY={[0, 10]}>
|
|
27
|
+
<TextLegend left={1} top={9} {elements} />
|
|
28
|
+
</Axes>
|
|
29
|
+
```
|
|
30
|
+
-->
|
|
31
|
+
|
|
1
32
|
<script>
|
|
2
33
|
import { getContext } from 'svelte';
|
|
3
34
|
import { Colors } from '../constants';
|
|
4
|
-
import { transformCoords } from '../methods';
|
|
35
|
+
import { checkCoords, transformCoords } from '../methods';
|
|
5
36
|
|
|
6
37
|
let {
|
|
7
38
|
left, // vector/array with coordinates of lef side of each text box
|
|
@@ -16,24 +47,31 @@
|
|
|
16
47
|
} = $props()
|
|
17
48
|
|
|
18
49
|
const axes = getContext('axes');
|
|
19
|
-
const
|
|
20
|
-
left !== undefined && left !== null
|
|
21
|
-
? transformCoords([left], axes.tX())
|
|
22
|
-
: null
|
|
50
|
+
const lx = $derived(
|
|
51
|
+
left !== undefined && left !== null ? checkCoords([left], 'TextLegend (left)') : null
|
|
23
52
|
);
|
|
24
|
-
const
|
|
25
|
-
top !== undefined && top !== null
|
|
26
|
-
? transformCoords([top], axes.tY())
|
|
27
|
-
: null
|
|
53
|
+
const ty = $derived(
|
|
54
|
+
top !== undefined && top !== null ? checkCoords([top], 'TextLegend (top)') : null
|
|
28
55
|
);
|
|
56
|
+
const x = $derived(lx ? transformCoords(lx, axes.tX()) : null);
|
|
57
|
+
const y = $derived(ty ? transformCoords(ty, axes.tY()) : null);
|
|
58
|
+
|
|
59
|
+
const validElements = $derived.by(() => {
|
|
60
|
+
if (!Array.isArray(elements) || elements.length < 1) {
|
|
61
|
+
console.error('TextLegend: parameter "elements" must be a non-empty array.');
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return elements;
|
|
66
|
+
});
|
|
29
67
|
|
|
30
68
|
// styles for bars and labels
|
|
31
69
|
const textStyleStr = $derived(`fill:${faceColor};stroke-width:${lineWidth}px;stroke:${lineColor};font-size:${textSize}em;`);
|
|
32
70
|
</script>
|
|
33
71
|
|
|
34
|
-
{#if x && y &&
|
|
72
|
+
{#if x && y && validElements}
|
|
35
73
|
<text style={textStyleStr} x={x} y={y} dx={dx} dy={dy} dominant-baseline="middle" text-anchor="start">
|
|
36
|
-
{#each
|
|
74
|
+
{#each validElements as el, i}
|
|
37
75
|
<tspan {x} {dx} dy={i === 0 ? 0 : dy}>{@html el}</tspan>
|
|
38
76
|
{/each}
|
|
39
77
|
</text>
|
package/src/2d/YAxis.svelte
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
Main properties:
|
|
5
5
|
- `label` - text label for the axis (optional).
|
|
6
6
|
- `showGrid` - logical, show or not horizontal grid lines, default: `false`.
|
|
7
|
-
- `ticks` - array or vector with tick positions (by default will be generated automatically based on `
|
|
7
|
+
- `ticks` - array or vector with tick positions (by default will be generated automatically based on `limY`).
|
|
8
8
|
- `tickLabels` - array with tick labels to show at each tick (by default will be generated automatically).
|
|
9
9
|
- `las` - orientation of tick labels (`1` - horizontal - default, `2` - vertical).
|
|
10
10
|
- `whole` - logical, show numeric tick labels as whole numbers (without decimals) or not, default: `false`.
|
package/src/3d/Axes.svelte
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
Main properties:
|
|
5
5
|
- `limX` - array with limits for x-axis (in plot units), default: `[0, 1]`.
|
|
6
6
|
- `limY` - array with limits for y-axis (in plot units), default: `[0, 1]`.
|
|
7
|
-
- `limZ` - array with limits for
|
|
7
|
+
- `limZ` - array with limits for z-axis (in plot units), default: `[0, 1]`.
|
|
8
8
|
- `theta` - angle (in radians) for orientation of projection plane, default: `-10`.
|
|
9
9
|
- `phi` - angle (in radians) for orientation of projection plane, default: `-10`.
|
|
10
10
|
- `zoom` - zooming factor, default: `0.5`.
|
|
@@ -15,18 +15,16 @@
|
|
|
15
15
|
- `pngWidth` - width of PNG image in cm, default `8`
|
|
16
16
|
- `pngHeight` - height of PNG image in cm, default `8`.
|
|
17
17
|
- `pngRes` - resolution of PNG image (pixels per inch), default `300`.
|
|
18
|
-
- `clipboardWidth` - width of plot image to copy to clipboard in pixels
|
|
19
|
-
- `clipboardHeight` - height of plot image to copy to clipboard in pixels
|
|
18
|
+
- `clipboardWidth` - width of plot image to copy to clipboard in pixels, default `1200`.
|
|
19
|
+
- `clipboardHeight` - height of plot image to copy to clipboard in pixels, default `800`.
|
|
20
20
|
|
|
21
21
|
Example:
|
|
22
|
-
```
|
|
22
|
+
```svelte
|
|
23
23
|
<script>
|
|
24
24
|
import {Axes} from 'svelte-plots-basic/3d';
|
|
25
25
|
</script>
|
|
26
26
|
|
|
27
|
-
<Axes limX={[-10, 10]} limY={[-10, 10]} limZ={[-10, 10]}
|
|
28
|
-
//all other plotting components are here
|
|
29
|
-
</Axes>
|
|
27
|
+
<Axes limX={[-10, 10]} limY={[-10, 10]} limZ={[-10, 10]} />
|
|
30
28
|
```
|
|
31
29
|
-->
|
|
32
30
|
<script>
|
package/src/3d/AxisLines.svelte
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!--
|
|
2
|
-
@component
|
|
2
|
+
@component Draws line segments for axis elements (ticks, etc.); not intended for direct use.
|
|
3
3
|
-->
|
|
4
4
|
<script>
|
|
5
5
|
import { getContext } from 'svelte';
|
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
lineWidth = 1, // line width (thickness) in pixels.
|
|
14
14
|
} = $props();
|
|
15
15
|
|
|
16
|
-
// get axes context and
|
|
16
|
+
// get axes context and compute screen coordinates
|
|
17
17
|
const axes = getContext('axes');
|
|
18
|
-
const s1 = $derived(lineCoords.length
|
|
18
|
+
const s1 = $derived(lineCoords.length === 2 ? transform3D(lineCoords[0], axes.tM()) : null);
|
|
19
19
|
const s2 = $derived(s1 ? transform3D(lineCoords[1], axes.tM()) : null);
|
|
20
20
|
|
|
21
21
|
// line style
|
|
@@ -29,4 +29,3 @@
|
|
|
29
29
|
{/each}
|
|
30
30
|
</g>
|
|
31
31
|
{/if}
|
|
32
|
-
|