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/3d/Axes.svelte
CHANGED
|
@@ -1,333 +1,324 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component Parent component for any plot, all other components should be nested inside `<Axes></Axes>`.
|
|
3
|
+
|
|
4
|
+
Main properties:
|
|
5
|
+
- `limX` - array with limits for x-axis (in plot units), default: `[0, 1]`.
|
|
6
|
+
- `limY` - array with limits for y-axis (in plot units), default: `[0, 1]`.
|
|
7
|
+
- `limZ` - array with limits for y-axis (in plot units), default: `[0, 1]`.
|
|
8
|
+
- `theta` - angle (in degrees) for orientation of projection plane, default: `-10`.
|
|
9
|
+
- `phi` - angle (in degrees) for orientation of projection plane, default: `-10`.
|
|
10
|
+
- `zoom` - zooming factor, default: `0.5`.
|
|
11
|
+
|
|
12
|
+
Properties for downloading the plot as PNG or SVG file or copying it to clipboard:
|
|
13
|
+
- `downloadLinks` - how to show download links panel (`'none'` - default, `'hover'`, `'fixed'`).
|
|
14
|
+
- `fileName` - file name for download (without extension), default: `'plot'`.
|
|
15
|
+
- `pngWidth` - width of PNG image in cm, default `8`
|
|
16
|
+
- `pngHeight` - height of PNG image in cm, default `8`.
|
|
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.
|
|
20
|
+
|
|
21
|
+
Example:
|
|
22
|
+
```jsx
|
|
23
|
+
<script>
|
|
24
|
+
import {Axes} from 'svelte-plots-basic/3d';
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<Axes limX={[-10, 10]} limY={[-10, 10]} limZ={[-10, 10]}>
|
|
28
|
+
//all other plotting components are here
|
|
29
|
+
</Axes>
|
|
30
|
+
```
|
|
31
|
+
-->
|
|
1
32
|
<script>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"xlarge": 15
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
// margin between plot series elements and data labels
|
|
39
|
-
const LABELS_MARGIN = {
|
|
40
|
-
"small": 5,
|
|
41
|
-
"medium": 10,
|
|
42
|
-
"large": 15,
|
|
43
|
-
"xlarge": 20
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
// line styles for different scales and types
|
|
47
|
-
const LINE_STYLES = {
|
|
48
|
-
small: ["0", "3,3", "1,1", "3,1"],
|
|
49
|
-
medium: ["0", "5,5", "2,2", "5,2"],
|
|
50
|
-
large: ["0", "7,7", "3,3", "7,3"],
|
|
51
|
-
xlarge: ["0", "9,9", "5,5", "9,5"],
|
|
33
|
+
import { matrix, Matrix } from 'mdatools/arrays';
|
|
34
|
+
import { setContext } from 'svelte';
|
|
35
|
+
import { PLOT_FONT_SIZE } from '../constants.js';
|
|
36
|
+
import { checkArray, getScale, getXAxisCoords3D, getYAxisCoords3D, getZAxisCoords3D,
|
|
37
|
+
downloadPNG, downloadSVG, copyToClipboard} from '../methods.js';
|
|
38
|
+
|
|
39
|
+
import AxisLines from './AxisLines.svelte';
|
|
40
|
+
import AxisTickLabels from './AxisTickLabels.svelte';
|
|
41
|
+
import TextLabels from './TextLabels.svelte';
|
|
42
|
+
|
|
43
|
+
/** @type {Props} */
|
|
44
|
+
let {
|
|
45
|
+
limX = [0, 1],
|
|
46
|
+
limY = [0, 1],
|
|
47
|
+
limZ = [0, 1],
|
|
48
|
+
theta = -10,
|
|
49
|
+
phi = -10,
|
|
50
|
+
zoom = 0.5,
|
|
51
|
+
downloadLinks = 'hover',
|
|
52
|
+
fileName = 'plot',
|
|
53
|
+
pngWidth = 8,
|
|
54
|
+
pngHeight = 8,
|
|
55
|
+
pngRes = 300,
|
|
56
|
+
clipboardWidth = 1200,
|
|
57
|
+
clipboardHeight = 800,
|
|
58
|
+
children
|
|
59
|
+
} = $props();
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
/* Copy plot to clipboard as PNG image. */
|
|
64
|
+
async function handleClickCopy(e) {
|
|
65
|
+
copyToClipboard(e.target, plotElement, clipboardWidth, clipboardHeight);
|
|
52
66
|
}
|
|
53
67
|
|
|
68
|
+
/* Download plot as SVG image when user clicks on corresponding button. */
|
|
69
|
+
function handleClickSVG() {
|
|
70
|
+
downloadSVG(plotElement, fileName);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* Download plot as PNG image when user clicks on corresponding button. */
|
|
74
|
+
function handleClickPNG() {
|
|
75
|
+
downloadPNG(plotElement, fileName, pngWidth, pngHeight, pngRes);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
54
79
|
// translation matrix to move points to center of a unit cube
|
|
55
80
|
const T1 = matrix([
|
|
56
|
-
1, 0, 0, 0,
|
|
57
|
-
0, 1, 0, 0,
|
|
58
|
-
0, 0, 1, 0,
|
|
59
|
-
0.5, 0.5, 0.5, 1
|
|
81
|
+
1.0, 0.0, 0.0, 0.0,
|
|
82
|
+
0.0, 1.0, 0.0, 0.0,
|
|
83
|
+
0.0, 0.0, 1.0, 0.0,
|
|
84
|
+
0.5, 0.5, 0.5, 1.0
|
|
60
85
|
], 4, 4);
|
|
61
86
|
|
|
62
87
|
// inverse translation matrix for T1
|
|
63
88
|
const T2 = matrix([
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
-0.5, -0.5, -0.5, 1
|
|
89
|
+
1.0, 0.0, 0.0, 0.0,
|
|
90
|
+
0.0, 1.0, 0.0, 0.0,
|
|
91
|
+
0.0, 0.0, 1.0, 0.0,
|
|
92
|
+
-0.5, -0.5, -0.5, 1.0
|
|
68
93
|
], 4, 4);
|
|
69
94
|
|
|
70
|
-
// constant to make clip path ID unique
|
|
71
|
-
const clipPathID = "plottingArea" + Math.round(Math.random() * 10000);
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
/*****************************************/
|
|
75
|
-
/* Variable parameters for internal use */
|
|
76
|
-
/*****************************************/
|
|
77
|
-
|
|
78
|
-
// bindings to plot DOM elements
|
|
79
|
-
let plotElement;
|
|
80
|
-
let axesElement;
|
|
81
|
-
let width, height = 100;
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
/*****************************************/
|
|
85
|
-
/* Helper functions */
|
|
86
|
-
/*****************************************/
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Transforms world coordinates to 2D scene pixels by applying the transformation matrix 'tM'.
|
|
90
|
-
*
|
|
91
|
-
* @param {Matrix} coords - matrix with coordinates [X, Y, Z]
|
|
92
|
-
* @param {Matrix} tM - transformation matrix
|
|
93
|
-
*
|
|
94
|
-
* @returns {Array} array with transformed coordinates as two vectors [x, y].
|
|
95
|
-
*
|
|
96
|
-
*/
|
|
97
|
-
const transform = function(coords, tM) {
|
|
98
|
-
// const coords2D = cbind(coords, Vector.ones(coords.nrows)).dot(tM);
|
|
99
|
-
// const coords2D = tcrossprod(tM, cbind(coords, Vector.ones(coords.nrows))).t();
|
|
100
|
-
const coords2D = cbind(coords, Vector.ones(coords.nrows)).dot(tM);
|
|
101
|
-
return [coords2D.getcolref(1).map(v => roundCoords(v)), coords2D.getcolref(2).map(v => roundCoords(v))];
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
/*****************************************/
|
|
106
|
-
/* Storage to share with children */
|
|
107
|
-
/*****************************************/
|
|
108
|
-
|
|
109
|
-
const tM = writable(Matrix.eye(4)); // transformation matrix
|
|
110
|
-
const scale = writable('medium'); // plot scale (small/medium/large)
|
|
111
|
-
const xLim = writable(limX); // x-axis limits in 3D (before projection)
|
|
112
|
-
const yLim = writable(limY); // y-axis limits in 3D (before projection)
|
|
113
|
-
const zLim = writable(limZ); // z-axis limits in 3D (before projection)
|
|
114
|
-
const isOk = writable(false); // indicator that axes works fine
|
|
115
|
-
|
|
116
95
|
|
|
117
|
-
/*****************************************/
|
|
118
|
-
/* Axes context */
|
|
119
|
-
/*****************************************/
|
|
120
|
-
|
|
121
|
-
let context = {
|
|
122
|
-
|
|
123
|
-
// methods
|
|
124
|
-
transform: transform,
|
|
125
|
-
|
|
126
|
-
// state proporties
|
|
127
|
-
scale: scale,
|
|
128
|
-
isOk: isOk,
|
|
129
|
-
xLim: xLim,
|
|
130
|
-
yLim: yLim,
|
|
131
|
-
zLim: zLim,
|
|
132
|
-
tM: tM,
|
|
133
|
-
|
|
134
|
-
// constants
|
|
135
|
-
LINE_STYLES: LINE_STYLES,
|
|
136
|
-
LABELS_MARGIN: LABELS_MARGIN,
|
|
137
|
-
TICK_NUM: TICK_NUM
|
|
138
|
-
}
|
|
139
96
|
|
|
140
|
-
|
|
97
|
+
// pointers to plot DOM element and its width and height
|
|
98
|
+
let plotElement = $state(0);
|
|
99
|
+
let width = $state(100);
|
|
100
|
+
let height = $state(100);
|
|
141
101
|
|
|
102
|
+
// scale factor and dependent font size
|
|
103
|
+
const scale = $derived(getScale(width, height));
|
|
104
|
+
const fontSize = $derived(PLOT_FONT_SIZE[scale]);
|
|
142
105
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
106
|
+
// check main plot parameters and set status
|
|
107
|
+
const isOk = $derived(
|
|
108
|
+
checkArray(limX, 2) &&
|
|
109
|
+
checkArray(limY, 2) &&
|
|
110
|
+
checkArray(limZ, 2) &&
|
|
111
|
+
limX[0] < limX[1] &&
|
|
112
|
+
limY[0] < limY[1] &&
|
|
113
|
+
limZ[0] < limZ[1] &&
|
|
114
|
+
width > 50 &&
|
|
115
|
+
height > 50
|
|
116
|
+
);
|
|
151
117
|
|
|
152
118
|
// projection matrix (step 1)
|
|
153
|
-
|
|
119
|
+
const P2 = $derived(matrix([
|
|
154
120
|
1, 0, 0, 0,
|
|
155
121
|
0, Math.cos(theta), Math.sin(theta), 0,
|
|
156
122
|
0, -Math.sin(theta), Math.cos(theta), 0,
|
|
157
123
|
0, 0, 0, 1,
|
|
158
|
-
], 4, 4);
|
|
124
|
+
], 4, 4));
|
|
159
125
|
|
|
160
126
|
// projection matrix (step 2)
|
|
161
|
-
|
|
127
|
+
const P1 = $derived(matrix([
|
|
162
128
|
Math.cos(phi), 0, -Math.sin(phi), 0,
|
|
163
129
|
0, 1, 0, 0,
|
|
164
130
|
Math.sin(phi), 0, Math.cos(phi), 0,
|
|
165
131
|
0, 0, 0, 1
|
|
166
|
-
], 4, 4);
|
|
132
|
+
], 4, 4));
|
|
167
133
|
|
|
168
134
|
// zoom matrix
|
|
169
|
-
|
|
135
|
+
const Z = $derived(matrix([
|
|
170
136
|
zoom, 0, 0, 0,
|
|
171
137
|
0, zoom, 0, 0,
|
|
172
138
|
0, 0, zoom, 0,
|
|
173
139
|
0, 0, 0, 1
|
|
174
|
-
], 4, 4);
|
|
140
|
+
], 4, 4));
|
|
175
141
|
|
|
176
|
-
// matrix for projection and zooming
|
|
142
|
+
// matrix for projection and zooming inside unit cube
|
|
177
143
|
// we shift [0, 1] cube to center, project, zoom, and then shift back
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
// update transformation matrix if angles of the norm vectors are changed
|
|
181
|
-
$: {
|
|
182
|
-
if ($isOk) {
|
|
183
|
-
// translate
|
|
184
|
-
const TT1 = matrix([
|
|
185
|
-
1, 0, 0, 0,
|
|
186
|
-
0, 1, 0, 0,
|
|
187
|
-
0, 0, 1, 0,
|
|
188
|
-
-$xLim[0], -$yLim[0], -$zLim[0], 1
|
|
189
|
-
], 4, 4);
|
|
190
|
-
|
|
191
|
-
// scale the whole cube to [0, 1] limits
|
|
192
|
-
const SS1 = matrix([
|
|
193
|
-
1 / ($xLim[1] - $xLim[0]) , 0, 0, 0,
|
|
194
|
-
0, 1 / ($yLim[1] - $yLim[0]), 0, 0,
|
|
195
|
-
0, 0, 1 / ($zLim[1] - $zLim[0]), 0,
|
|
196
|
-
0, 0, 0, 1
|
|
197
|
-
], 4, 4);
|
|
198
|
-
|
|
199
|
-
// scale to screen coordinates
|
|
200
|
-
const SS2 = matrix([
|
|
201
|
-
width, 0, 0, 0,
|
|
202
|
-
0, height, 0, 0,
|
|
203
|
-
0, 0, 1, 0,
|
|
204
|
-
0, 0, 0, 1
|
|
205
|
-
], 4, 4);
|
|
206
|
-
|
|
207
|
-
tM.update(x => SS2.dot(P.dot(SS1.dot(TT1))).t());
|
|
208
|
-
} else {
|
|
209
|
-
tM.update(x => Matrix.eye(4));
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
144
|
+
const P = $derived(T1.dot(Z.dot(P2.dot(P1.dot(T2)))));
|
|
213
145
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
const acr = axesElement.getBoundingClientRect();
|
|
230
|
-
width = acr.width;
|
|
231
|
-
height = acr.height;
|
|
232
|
-
}
|
|
233
|
-
});
|
|
146
|
+
// translation in world coordinates to origin (0, 0, 0)
|
|
147
|
+
const TT1 = $derived(isOk ? matrix([
|
|
148
|
+
1, 0, 0, 0,
|
|
149
|
+
0, 1, 0, 0,
|
|
150
|
+
0, 0, 1, 0,
|
|
151
|
+
-limX[0], -limY[0], -limZ[0], 1
|
|
152
|
+
], 4, 4) : null);
|
|
153
|
+
|
|
154
|
+
// scale world coordinates to unit cube
|
|
155
|
+
const SS1 = $derived(isOk ? matrix([
|
|
156
|
+
1 / (limX[1] - limX[0]) , 0, 0, 0,
|
|
157
|
+
0, 1 / (limY[1] - limY[0]), 0, 0,
|
|
158
|
+
0, 0, 1 / (limZ[1] - limZ[0]), 0,
|
|
159
|
+
0, 0, 0, 1
|
|
160
|
+
], 4, 4) : null);
|
|
234
161
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
162
|
+
// scale unit cube to screen coordinates
|
|
163
|
+
const SS2 = $derived(isOk ? matrix([
|
|
164
|
+
width, 0, 0, 0,
|
|
165
|
+
0, height, 0, 0,
|
|
166
|
+
0, 0, 1, 0,
|
|
167
|
+
0, 0, 0, 1
|
|
168
|
+
], 4, 4) : null);
|
|
169
|
+
|
|
170
|
+
// main transformation matrix
|
|
171
|
+
const tM = $derived(SS2 && P && SS1 && TT1 ?
|
|
172
|
+
SS2.dot(P.dot(SS1.dot(TT1))).t() :
|
|
173
|
+
Matrix.eye(4)
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
// containers for axis properties
|
|
177
|
+
let xaxis = $state({show: false, label: ""});
|
|
178
|
+
let yaxis = $state({show: false, label: ""});
|
|
179
|
+
let zaxis = $state({show: false, label: ""});
|
|
180
|
+
|
|
181
|
+
// axes context to share with children
|
|
182
|
+
setContext('axes', {
|
|
183
|
+
scale: () => scale,
|
|
184
|
+
tM: () => tM,
|
|
185
|
+
setXAxis: (v) => xaxis = v,
|
|
186
|
+
setYAxis: (v) => yaxis = v,
|
|
187
|
+
setZAxis: (v) => zaxis = v,
|
|
238
188
|
});
|
|
239
189
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
// check if everything is ok regarding the axis limits
|
|
246
|
-
$: isOk.update(v =>
|
|
247
|
-
!$yLim.some(v => v === undefined) &&
|
|
248
|
-
!$xLim.some(v => v === undefined) &&
|
|
249
|
-
!$zLim.some(v => v === undefined) &&
|
|
250
|
-
!$yLim.some(v => isNaN(v)) &&
|
|
251
|
-
!$xLim.some(v => isNaN(v)) &&
|
|
252
|
-
!$zLim.some(v => isNaN(v))
|
|
253
|
-
)
|
|
190
|
+
// compute screen coordinates for the axis
|
|
191
|
+
const xaxisCoords = $derived(xaxis && xaxis.show ? getXAxisCoords3D(xaxis, limX, limY, limZ, scale) : null);
|
|
192
|
+
const yaxisCoords = $derived(yaxis && yaxis.show ? getYAxisCoords3D(yaxis, limX, limY, limZ, scale) : null);
|
|
193
|
+
const zaxisCoords = $derived(zaxis && zaxis.show ? getZAxisCoords3D(zaxis, limX, limY, limZ, scale) : null);
|
|
254
194
|
</script>
|
|
255
195
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
<
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
{
|
|
196
|
+
<!-- snipped for axis -->
|
|
197
|
+
{#snippet axis(axis, coords)}
|
|
198
|
+
|
|
199
|
+
<g class="axis" >
|
|
200
|
+
|
|
201
|
+
<!-- grid -->
|
|
202
|
+
{#if axis.showGrid }
|
|
203
|
+
<AxisLines lineCoords={coords.grid1} lineColor={axis.gridColor} lineType={3} />
|
|
204
|
+
<AxisLines lineCoords={coords.grid2} lineColor={axis.gridColor} lineType={3} />
|
|
205
|
+
{/if}
|
|
206
|
+
|
|
207
|
+
<!-- main axis line -->
|
|
208
|
+
<AxisLines lineCoords={coords.axisLine} lineColor={axis.lineColor} lineType={1} />
|
|
209
|
+
|
|
210
|
+
<!-- ticks-->
|
|
211
|
+
<AxisLines lineCoords={[coords.tickCoords[0], coords.tickCoords[1]]} lineColor={axis.lineColor} lineType={1} />
|
|
212
|
+
<AxisLines lineCoords={[coords.tickCoords[0], coords.tickCoords[2]]} lineColor={axis.lineColor} lineType={1} />
|
|
213
|
+
|
|
214
|
+
<!-- labels -->
|
|
215
|
+
{#if coords.tickCoords }
|
|
216
|
+
<AxisTickLabels tickCoords={coords.tickCoords[4]} textColor={axis.textColor} tickLabels={coords.tickLabels} />
|
|
217
|
+
{/if}
|
|
218
|
+
|
|
219
|
+
<!-- title -->
|
|
220
|
+
{#if coords.titleCoords && axis.label !== ''}
|
|
221
|
+
<TextLabels
|
|
222
|
+
xValues={coords.titleCoords[0]} yValues={coords.titleCoords[1]} zValues={coords.titleCoords[2]}
|
|
223
|
+
faceColor={axis.textColor}
|
|
224
|
+
labels={axis.label}
|
|
225
|
+
textSize={1.0}
|
|
226
|
+
fontWeight="bold"
|
|
227
|
+
/>
|
|
228
|
+
{/if}
|
|
229
|
+
</g>
|
|
230
|
+
{/snippet}
|
|
231
|
+
|
|
232
|
+
<div class="plot-container show-download-links-{downloadLinks}" class:plot_error={!isOk}>
|
|
233
|
+
<svg class="plot" bind:this={plotElement} bind:clientWidth={width} bind:clientHeight={height}
|
|
234
|
+
xmlns="http://www.w3.org/2000/svg" style="font-size:{fontSize}px">
|
|
235
|
+
<style>
|
|
236
|
+
.plot {
|
|
237
|
+
font-family: Arial, Helvetica, sans-serif;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
polyline, line {
|
|
241
|
+
vector-effect: "non-scaling-stroke";
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.plot-labels text {
|
|
245
|
+
font-weight:bold;
|
|
246
|
+
text-anchor:middle;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.tick-labels text,
|
|
250
|
+
.tick-labels tspan,
|
|
251
|
+
.series-text text,
|
|
252
|
+
.series-text tspan,
|
|
253
|
+
.series-points text,
|
|
254
|
+
.series-points tspan {
|
|
255
|
+
dominant-baseline: middle;
|
|
256
|
+
cursor: default;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.series-text text,
|
|
260
|
+
.series-text tspan {
|
|
261
|
+
text-anchor: middle;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.tick-labels text,
|
|
265
|
+
.tick-labels tspan {
|
|
266
|
+
font-size:1em;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
text, tspan {
|
|
270
|
+
user-select: none;
|
|
271
|
+
-webkit-user-select: none;
|
|
272
|
+
}
|
|
273
|
+
</style>
|
|
274
|
+
|
|
275
|
+
<!-- axis -->
|
|
276
|
+
{#if xaxis && xaxis.show} {@render axis(xaxis, xaxisCoords)} {/if}
|
|
277
|
+
{#if yaxis && yaxis.show} {@render axis(yaxis, yaxisCoords)} {/if}
|
|
278
|
+
{#if zaxis && zaxis.show} {@render axis(zaxis, zaxisCoords)} {/if}
|
|
279
|
+
|
|
280
|
+
<!-- main plot content -->
|
|
281
|
+
<g class="axes-content" >
|
|
282
|
+
{@render children?.()}
|
|
283
|
+
</g>
|
|
284
|
+
</svg>
|
|
285
|
+
|
|
286
|
+
{#if !isOk}
|
|
287
|
+
<p class="message_error">
|
|
288
|
+
Axes component was not properly initialized. <br />
|
|
289
|
+
Add plot series (check that coordinates are numeric) or define axes limits manually.
|
|
290
|
+
</p>
|
|
291
|
+
{:else}
|
|
292
|
+
<div class="download-links">
|
|
293
|
+
<button onclick={handleClickSVG} onkeydown={handleClickSVG}>⇩ svg</button>
|
|
294
|
+
<button onclick={handleClickPNG} onkeydown={handleClickPNG}>⇩ png</button>
|
|
295
|
+
<button onclick={handleClickCopy} onkeydown={handleClickCopy}>⧉ copy</button>
|
|
285
296
|
</div>
|
|
286
|
-
|
|
287
|
-
|
|
297
|
+
{/if}
|
|
288
298
|
</div>
|
|
289
299
|
|
|
290
300
|
<style>
|
|
291
301
|
|
|
292
|
-
/* Plot
|
|
293
|
-
.plot {
|
|
302
|
+
/* Plot container */
|
|
303
|
+
.plot-container {
|
|
294
304
|
font-family: Arial, Helvetica, sans-serif;
|
|
295
|
-
|
|
296
|
-
display: grid;
|
|
297
|
-
grid-template-columns: min-content auto;
|
|
298
|
-
grid-template-rows: min-content auto min-content;
|
|
299
|
-
grid-template-areas:
|
|
300
|
-
". title"
|
|
301
|
-
"ylab axes"
|
|
302
|
-
". xlab";
|
|
303
|
-
|
|
304
305
|
box-sizing: border-box;
|
|
306
|
+
position: relative;
|
|
305
307
|
min-width: 100px;
|
|
306
308
|
min-height: 50px;
|
|
307
309
|
width: 100%;
|
|
308
310
|
height: 100%;
|
|
309
311
|
padding: 0;
|
|
310
312
|
margin: 0;
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
:global(.plot_small) {
|
|
315
|
-
font-size: 11px;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
:global(.plot_medium) {
|
|
319
|
-
font-size: 13px;
|
|
313
|
+
overflow: hidden;
|
|
314
|
+
background: #fff;
|
|
320
315
|
}
|
|
321
316
|
|
|
322
|
-
|
|
323
|
-
font-size: 16px;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
:global(.plot_error) {
|
|
317
|
+
.plot_error {
|
|
327
318
|
display: flex;
|
|
328
319
|
}
|
|
329
320
|
|
|
330
|
-
|
|
321
|
+
.plot_error > .plot {
|
|
331
322
|
display: none;
|
|
332
323
|
}
|
|
333
324
|
|
|
@@ -339,107 +330,74 @@
|
|
|
339
330
|
width: 100%;
|
|
340
331
|
}
|
|
341
332
|
|
|
342
|
-
|
|
343
|
-
.axes-wrapper {
|
|
344
|
-
grid-area: axes;
|
|
345
|
-
position:relative;
|
|
346
|
-
box-sizing: border-box;
|
|
347
|
-
display: flex;
|
|
348
|
-
width: 100%;
|
|
349
|
-
height: 100%;
|
|
350
|
-
padding: 0;
|
|
351
|
-
margin: 0;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
.axes {
|
|
333
|
+
.plot {
|
|
355
334
|
display: block;
|
|
356
335
|
box-sizing: border-box;
|
|
357
336
|
position:absolute;
|
|
358
|
-
user-select: none;
|
|
359
|
-
cursor: default;
|
|
360
337
|
padding: 0;
|
|
361
338
|
margin: 0;
|
|
362
|
-
|
|
339
|
+
left: 0;
|
|
340
|
+
top: 0;
|
|
341
|
+
bottom: 0;
|
|
342
|
+
right: 0;
|
|
363
343
|
width: 100%;
|
|
364
|
-
|
|
365
|
-
max-width: 100%;
|
|
366
|
-
min-height: 100%;
|
|
367
|
-
min-width: 100%;
|
|
344
|
+
height: 100%;
|
|
368
345
|
}
|
|
369
346
|
|
|
370
|
-
.axes :global(text) {
|
|
371
|
-
-webkit-user-select: none;
|
|
372
|
-
user-select: none;
|
|
373
|
-
cursor: default;
|
|
374
|
-
}
|
|
375
347
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
height: 100%;
|
|
380
|
-
width: 100%;
|
|
381
|
-
max-height: 100%;
|
|
382
|
-
max-width: 100%;
|
|
383
|
-
min-height: 100%;
|
|
384
|
-
min-width: 100%;
|
|
348
|
+
.show-download-links-none > .download-links{
|
|
349
|
+
display: none;
|
|
350
|
+
}
|
|
385
351
|
|
|
352
|
+
.show-download-links-hover:hover > .download-links {
|
|
353
|
+
bottom: 0;
|
|
386
354
|
}
|
|
387
355
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
font-size: 1.0em;
|
|
391
|
-
font-weight: 600;
|
|
392
|
-
padding: 0.25em;
|
|
393
|
-
text-align: center;
|
|
356
|
+
.show-download-links-fixed > .download-links{
|
|
357
|
+
bottom: 0;
|
|
394
358
|
}
|
|
395
359
|
|
|
360
|
+
.download-links {
|
|
361
|
+
box-sizing: border-box;
|
|
362
|
+
position: absolute;
|
|
363
|
+
font-size: 0.8em;
|
|
364
|
+
bottom: -50%;
|
|
365
|
+
right: 0;
|
|
366
|
+
z-index: 10;
|
|
367
|
+
padding: 0.5em 1em 0.5em 1em;
|
|
368
|
+
background: #fefefe;
|
|
369
|
+
border-radius: 0.5em;
|
|
370
|
+
transition: bottom 0.35s ease;
|
|
371
|
+
box-shadow: 0 0 0.75em #00000060;
|
|
372
|
+
margin: 0.6em;
|
|
373
|
+
box-sizing: border-box;
|
|
396
374
|
|
|
397
|
-
:global(.axes__ylabel) {
|
|
398
|
-
grid-area: ylab;
|
|
399
|
-
font-size: 1.0em;
|
|
400
|
-
font-weight: 600;
|
|
401
|
-
padding: 0.25em;
|
|
402
|
-
text-align: center;
|
|
403
|
-
vertical-align: middle;
|
|
404
375
|
display: flex;
|
|
376
|
+
align-items: center;
|
|
377
|
+
justify-content: center;
|
|
405
378
|
}
|
|
406
379
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
:global(.axes__title) {
|
|
417
|
-
background: transparent;
|
|
418
|
-
grid-area: title;
|
|
419
|
-
|
|
420
|
-
font-size: 1.3em;
|
|
421
|
-
font-weight: bold;
|
|
422
|
-
line-height: 1.2em;
|
|
423
|
-
padding: 0.5em 0;
|
|
424
|
-
text-align: center;
|
|
380
|
+
.download-links > button{
|
|
381
|
+
box-sizing: border-box;
|
|
382
|
+
color: #606060;
|
|
383
|
+
border: none;
|
|
384
|
+
box-shadow: none;
|
|
385
|
+
background: #fafafa;
|
|
386
|
+
border-radius: 0.35em;
|
|
387
|
+
padding: 0.25em 0.5em;
|
|
425
388
|
}
|
|
426
389
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
font-size: 0.95em;
|
|
390
|
+
.download-links > button:hover{
|
|
391
|
+
background: #443333;
|
|
392
|
+
color: #fafafa;
|
|
431
393
|
}
|
|
432
394
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
fill: #606060;
|
|
436
|
-
font-size: 0.90em;
|
|
395
|
+
.download-links > :global(button.error){
|
|
396
|
+
background: #ee4433;
|
|
437
397
|
}
|
|
438
398
|
|
|
439
|
-
:global(.
|
|
440
|
-
|
|
441
|
-
transition:visibility 0.25s linear, opacity 0.25s linear;
|
|
442
|
-
opacity: 0;
|
|
399
|
+
.download-links > :global(button.copied){
|
|
400
|
+
background: #4488ee;
|
|
443
401
|
}
|
|
444
402
|
|
|
445
403
|
</style>
|