svelte-plots-basic 1.1.4 → 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.
- package/README.md +53 -67
- package/package.json +10 -4
- package/src/2d/Area.svelte +61 -0
- package/src/2d/Axes.svelte +500 -0
- package/src/2d/Axis.svelte +50 -0
- package/src/2d/AxisLines.svelte +54 -0
- package/src/2d/AxisTickLabels.svelte +82 -0
- package/src/2d/Bars.svelte +65 -0
- package/src/2d/Box.svelte +50 -0
- package/src/2d/ColorLegend.svelte +36 -0
- package/src/2d/Legend.svelte +148 -0
- package/src/2d/Lines.svelte +49 -0
- package/src/2d/Multilines.svelte +67 -0
- package/src/2d/Points.svelte +79 -0
- package/src/2d/Rectangles.svelte +74 -0
- package/src/2d/Segments.svelte +65 -0
- package/src/2d/TextLabels.svelte +107 -0
- package/src/2d/TextLegend.svelte +53 -0
- package/src/2d/XAxis.svelte +99 -0
- package/src/2d/YAxis.svelte +99 -0
- package/src/{index.js → 2d/index.js} +10 -6
- package/src/3d/Axes.svelte +445 -0
- package/src/3d/Axis.svelte +64 -0
- package/src/3d/AxisLines.svelte +50 -0
- package/src/3d/AxisTickLabels.svelte +54 -0
- package/src/3d/Lines.svelte +49 -0
- package/src/3d/Mesh.svelte +188 -0
- package/src/3d/Points.svelte +61 -0
- package/src/3d/Segments.svelte +69 -0
- package/src/3d/TextLabels.svelte +79 -0
- package/src/3d/XAxis.svelte +123 -0
- package/src/3d/YAxis.svelte +123 -0
- package/src/3d/ZAxis.svelte +123 -0
- package/src/3d/index.js +13 -0
- package/src/Colors.js +36 -1
- package/src/Utils.js +205 -0
- package/src/AreaSeries.svelte +0 -53
- package/src/Axes.svelte +0 -550
- package/src/BarSeries.svelte +0 -68
- package/src/Box.svelte +0 -35
- package/src/LineSeries.svelte +0 -50
- package/src/Rectangles.svelte +0 -64
- package/src/ScatterSeries.svelte +0 -69
- package/src/Segments.svelte +0 -52
- package/src/TextLabels.svelte +0 -88
- package/src/TextLegend.svelte +0 -38
- package/src/XAxis.svelte +0 -69
- package/src/YAxis.svelte +0 -72
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
/****************************************************
|
|
3
|
+
* Bars *
|
|
4
|
+
* -------------------- *
|
|
5
|
+
* shows series of bars on a plot *
|
|
6
|
+
*****************************************************/
|
|
7
|
+
|
|
8
|
+
import { max, diff } from 'mdatools/stat';
|
|
9
|
+
import { Vector } from 'mdatools/arrays';
|
|
10
|
+
import { Colors } from '../Colors';
|
|
11
|
+
import { checkCoords } from '../Utils';
|
|
12
|
+
|
|
13
|
+
import Rectangles from './Rectangles.svelte';
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
/*****************************************/
|
|
17
|
+
/* Input parameters */
|
|
18
|
+
/*****************************************/
|
|
19
|
+
|
|
20
|
+
export let xValues; // vector with x-coordinates of middle points of the bars
|
|
21
|
+
export let yValues; // vector with y-coordinates of top points of the bars
|
|
22
|
+
export let barWidth = 0.8; // width of bars as per cent of maximum width
|
|
23
|
+
export let faceColor = Colors.PRIMARY; // face color of the bars
|
|
24
|
+
export let borderColor = Colors.PRIMARY; // border color of the bars
|
|
25
|
+
export let title = ''; // title of the bar series (reserved for future use)
|
|
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
|
+
}
|
|
40
|
+
|
|
41
|
+
if (barWidth <= 0 || barWidth > 1) {
|
|
42
|
+
throw Error('BarSeries: parameters "barWidth" should be between 0 and 1.');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// compute maximum bar width and position of left side
|
|
46
|
+
const xv = checkCoords(xValues, 'BarSeries');
|
|
47
|
+
const w = max(diff(xv)) * barWidth;
|
|
48
|
+
left = xv.subtract(w/2);
|
|
49
|
+
width = Vector.fill(w, xv.length);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// reactive code for computing position of top sides and bar height
|
|
53
|
+
$: {
|
|
54
|
+
|
|
55
|
+
const yv = checkCoords(yValues, 'BarSeries');
|
|
56
|
+
if (yv.length !== left.length) {
|
|
57
|
+
throw Error('BarSeries: parameters "yValues" must be vector of the same length as "xValues".');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
top = yv.apply(v => v > 0 ? v : 0);
|
|
61
|
+
height = yv.apply(v => Math.abs(v));
|
|
62
|
+
}
|
|
63
|
+
</script>
|
|
64
|
+
|
|
65
|
+
<Rectangles className="series_bar" {left} {top} {width} {height} {borderColor} {faceColor} {title} />
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
/****************************************************
|
|
3
|
+
* Box *
|
|
4
|
+
* -------------------- *
|
|
5
|
+
* shows border box around axes *
|
|
6
|
+
*****************************************************/
|
|
7
|
+
|
|
8
|
+
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
|
+
|
|
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
|
+
// box style
|
|
29
|
+
const rectStyleStr = `fill:transparent;stroke:${Colors.DARKGRAY};stroke-width:1px;`;
|
|
30
|
+
|
|
31
|
+
// get axes context and reactive variables needed to compute coordinates
|
|
32
|
+
const axes = getContext('axes');
|
|
33
|
+
const xLim = axes.xLim;
|
|
34
|
+
const yLim = axes.yLim;
|
|
35
|
+
const isOk = axes.isOk;
|
|
36
|
+
const tX = axes.tX;
|
|
37
|
+
const tY = axes.tY;
|
|
38
|
+
|
|
39
|
+
// reactive variables for coordinates of box points in pixels
|
|
40
|
+
$: xx = $isOk ? axes.transform($xLim, $tX.coords) : undefined;
|
|
41
|
+
$: yy = $isOk ? axes.transform($yLim, $tY.coords) : undefined;
|
|
42
|
+
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
{#if $isOk}
|
|
46
|
+
<g style="pointer-events:none" class="mdaplot__axes-box">
|
|
47
|
+
<rect x={xx[0]} y={yy[1]} width={xx[1] - xx[0]} height={yy[0] - yy[1]} style={rectStyleStr} />
|
|
48
|
+
</g>
|
|
49
|
+
{/if}
|
|
50
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
/****************************************************
|
|
3
|
+
* ColorLegend *
|
|
4
|
+
* -------------------- *
|
|
5
|
+
* shows color legend on top part of the plot *
|
|
6
|
+
*****************************************************/
|
|
7
|
+
|
|
8
|
+
import { getContext } from 'svelte';
|
|
9
|
+
import { Colors } from '../Colors';
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
/*****************************************/
|
|
13
|
+
/* Input parameters */
|
|
14
|
+
/*****************************************/
|
|
15
|
+
|
|
16
|
+
export let colormap; // colormap returned by method getcolormap() from colors
|
|
17
|
+
|
|
18
|
+
/*****************************************/
|
|
19
|
+
/* Component code */
|
|
20
|
+
/*****************************************/
|
|
21
|
+
|
|
22
|
+
const axes = getContext('axes');
|
|
23
|
+
const xLim = axes.xLim;
|
|
24
|
+
const yLim = axes.yLim;
|
|
25
|
+
const tX = axes.tX;
|
|
26
|
+
const tY = axes.tY;
|
|
27
|
+
const isOk = axes.isOk;
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
// TODO: will be implemented as a sequence of rectangles and text labels beneath them
|
|
31
|
+
|
|
32
|
+
// compute coordinates of rectangles and their colors
|
|
33
|
+
|
|
34
|
+
// compute coordinates of text labels
|
|
35
|
+
</script>
|
|
36
|
+
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
/****************************************************
|
|
3
|
+
* Legend *
|
|
4
|
+
* -------------------- *
|
|
5
|
+
* shows legend for plot components *
|
|
6
|
+
*****************************************************/
|
|
7
|
+
|
|
8
|
+
import { mean } from 'mdatools/stat';
|
|
9
|
+
import { getContext } from 'svelte';
|
|
10
|
+
import { Colors } from '../Colors';
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
/*****************************************/
|
|
14
|
+
/* Input parameters */
|
|
15
|
+
/*****************************************/
|
|
16
|
+
|
|
17
|
+
export let items; // array with text labels for each legend element
|
|
18
|
+
export let position = "topleft"; // position of the legend ("topleft", "top", "topright", "right", "bottomright", etc).
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
/*****************************************/
|
|
22
|
+
/* Component code */
|
|
23
|
+
/*****************************************/
|
|
24
|
+
|
|
25
|
+
const axes = getContext('axes');
|
|
26
|
+
const scale = axes.scale;
|
|
27
|
+
const xLim = axes.xLim;
|
|
28
|
+
const yLim = axes.yLim;
|
|
29
|
+
const tX = axes.tX;
|
|
30
|
+
const tY = axes.tY;
|
|
31
|
+
const isOk = axes.isOk;
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Computes width of text element for given font.
|
|
36
|
+
*
|
|
37
|
+
* @param {string} text - string with text
|
|
38
|
+
* @param {string} font - font name and size, e.g. '12px Arial'
|
|
39
|
+
*
|
|
40
|
+
* @return {number} size of element in pixels
|
|
41
|
+
*/
|
|
42
|
+
function getTextWidth(text, font) {
|
|
43
|
+
const element = document.createElement('canvas');
|
|
44
|
+
const context = element.getContext('2d');
|
|
45
|
+
context.font = font;
|
|
46
|
+
return context.measureText(text).width;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Compute size of main legend elements.
|
|
51
|
+
*
|
|
52
|
+
* @param {Array} items - array of legend items and their properties.
|
|
53
|
+
* @param {number} fontSize - font size of a legend element.
|
|
54
|
+
* @param {string} position - position of the legend.
|
|
55
|
+
*
|
|
56
|
+
* @return {Array} array with height and width og graphical part of legend item, padding size,
|
|
57
|
+
* height and width of text labels (all in pixels).
|
|
58
|
+
*/
|
|
59
|
+
function getLegendSize(items, fontSize, position) {
|
|
60
|
+
|
|
61
|
+
// compute size of graphical elements
|
|
62
|
+
const elHeight = fontSize; // height of legend element without padding
|
|
63
|
+
const elPadding = elHeight / 4; // top and bottom padding
|
|
64
|
+
const elWidth = elHeight * 1.5; // width of legend element without padding
|
|
65
|
+
|
|
66
|
+
// compute size of text label elements
|
|
67
|
+
// TODO: implement one row legend if position is "top" or "bottom"
|
|
68
|
+
const lbHeight = elHeight;
|
|
69
|
+
let lbWidth = 0;
|
|
70
|
+
for (let i = 0; i < items.length; i++) {
|
|
71
|
+
const w = getTextWidth(' ' + items[i].label + ' ', fontSize + 'px Arial');
|
|
72
|
+
lbWidth = w > lbWidth ? w : lbWidth;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return [elHeight, elWidth, elPadding, lbHeight, lbWidth];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// reactive expression to compute all sizes and coordinates
|
|
79
|
+
let left, top, elHeight, elWidth, elPadding, lbHeight, lbWidth, legendHeight, legendWidth, fontSize;
|
|
80
|
+
$: if ($isOk) {
|
|
81
|
+
|
|
82
|
+
fontSize = axes.LEGEND_FONT_SIZE[$scale];
|
|
83
|
+
|
|
84
|
+
// compute size of elements
|
|
85
|
+
[elHeight, elWidth, elPadding, lbHeight, lbWidth] = getLegendSize(items, fontSize, position);
|
|
86
|
+
|
|
87
|
+
// compute size of whole legend box
|
|
88
|
+
legendHeight = (elHeight + 2 * elPadding) * items.length;
|
|
89
|
+
legendWidth = (elWidth + 2 * elPadding + lbWidth);
|
|
90
|
+
|
|
91
|
+
// compute coordinates of top left corner of the legend box
|
|
92
|
+
const xLimPx = axes.transform($xLim, $tX.coords);
|
|
93
|
+
left = position.includes("left") ? xLimPx[0] + axes.TICK_SIZE[$scale] :
|
|
94
|
+
position.includes("right") ? xLimPx[1] - legendWidth - axes.TICK_SIZE[$scale] :
|
|
95
|
+
mean(xLimPx) - legendWidth/2;
|
|
96
|
+
|
|
97
|
+
const yLimPx = axes.transform($yLim, $tY.coords);
|
|
98
|
+
top = position.includes("top") ? yLimPx[1] + axes.TICK_SIZE[$scale] :
|
|
99
|
+
position.includes("bottom") ? yLimPx[0] - legendHeight - axes.TICK_SIZE[$scale] :
|
|
100
|
+
mean(yLimPx) - legendHeight/2;
|
|
101
|
+
}
|
|
102
|
+
</script>
|
|
103
|
+
|
|
104
|
+
{#if $isOk }
|
|
105
|
+
|
|
106
|
+
<!-- outer legend box, background and frame -->
|
|
107
|
+
<svg x="{left}px" y="{top}px" height="{legendHeight}px" width="{legendWidth}">
|
|
108
|
+
<rect height="100%" width="100%" style="fill:white;stroke:{Colors.MIDDLEGRAY};"></rect>
|
|
109
|
+
|
|
110
|
+
{#each items as item, i}
|
|
111
|
+
|
|
112
|
+
<!-- individual legend item -->
|
|
113
|
+
<svg x="{0}px" y="{i * (elHeight + 2 * elPadding)}px" width="{legendWidth}px" height="{elHeight + 2 * elPadding}px">
|
|
114
|
+
|
|
115
|
+
<!-- line -->
|
|
116
|
+
{#if item.lineType && item.lineType > 0 && item.lineType <= 4}
|
|
117
|
+
<line x1={elPadding} x2={elPadding + elWidth} y1={(elHeight + elPadding * 2)/2} y2={(elHeight + elPadding * 2)/2} style={`
|
|
118
|
+
stroke:${item.lineColor ? item.lineColor : Colors.PRIMARY};
|
|
119
|
+
stroke-width: ${item.lineWidth ? item.lineWidth : 1}px;
|
|
120
|
+
stroke-dasharray:${axes.LINE_STYLES[$scale][item.lineType - 1]}
|
|
121
|
+
`}/>
|
|
122
|
+
{/if}
|
|
123
|
+
|
|
124
|
+
<!-- marker -->
|
|
125
|
+
{#if item.marker && item.marker > 0 && item.marker < axes.MARKER_SYMBOLS.length}
|
|
126
|
+
<text x="{(elWidth + 2 * elPadding)/2}px" y="{(elHeight + 2 * elPadding)/2}px"
|
|
127
|
+
dominant-baseline="middle"
|
|
128
|
+
style={`
|
|
129
|
+
fill:${item.faceColor ? item.faceColor : "transparent"};
|
|
130
|
+
stroke-width:${item.borderWidth ? item.borderWidth : 1}px;
|
|
131
|
+
stroke:${item.borderColor ? item.borderColor : Colors.PRIMARY};
|
|
132
|
+
font-size:${fontSize}px;
|
|
133
|
+
text-anchor:middle;`}
|
|
134
|
+
>{axes.MARKER_SYMBOLS[item.marker - 1]}</text>
|
|
135
|
+
{/if}
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
<!-- text -->
|
|
140
|
+
<text x="{elWidth + elPadding * 3}px" y="{elPadding}px"
|
|
141
|
+
dominant-baseline="hanging"
|
|
142
|
+
style={`text-anchor:start;fill:${Colors.LEGEND};font-size:${fontSize}px`};
|
|
143
|
+
>{@html ' ' + item.label}</text>
|
|
144
|
+
|
|
145
|
+
</svg>
|
|
146
|
+
{/each}
|
|
147
|
+
</svg>
|
|
148
|
+
{/if}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
/****************************************************
|
|
3
|
+
* Lines *
|
|
4
|
+
* -------------------- *
|
|
5
|
+
* shows lines connected sequence of points *
|
|
6
|
+
*****************************************************/
|
|
7
|
+
|
|
8
|
+
import { getContext } from 'svelte';
|
|
9
|
+
import { Colors } from '../Colors';
|
|
10
|
+
import { val2p } from '../Utils';
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
/*****************************************/
|
|
14
|
+
/* Input parameters */
|
|
15
|
+
/*****************************************/
|
|
16
|
+
|
|
17
|
+
export let xValues; // vector or array with x-coordinates of the points
|
|
18
|
+
export let yValues; // vector or array with y-coordinates of the points
|
|
19
|
+
export let lineWidth = 1; // width (thickness) of the lines
|
|
20
|
+
export let lineColor = Colors.PRIMARY; // color of the lines
|
|
21
|
+
export let lineType = 1; // type of the lines (1 - solid, 2 - dashed, 3 - dotted, 4 - dashdot)
|
|
22
|
+
export let title = ''; // title of the bar series (reserved for future use)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
/*****************************************/
|
|
26
|
+
/* Component code */
|
|
27
|
+
/*****************************************/
|
|
28
|
+
|
|
29
|
+
// get axes context
|
|
30
|
+
const axes = getContext('axes');
|
|
31
|
+
|
|
32
|
+
const scale = axes.scale;
|
|
33
|
+
const isOk = axes.isOk;
|
|
34
|
+
const tX = axes.tX;
|
|
35
|
+
const tY = axes.tY;
|
|
36
|
+
|
|
37
|
+
// compute polynomial coordinates as string
|
|
38
|
+
$: p = $isOk ? val2p(xValues, yValues, $tX, $tY, axes) : undefined;
|
|
39
|
+
|
|
40
|
+
// reactive variables for coordinates of data points in pixels
|
|
41
|
+
$: lineStyleStr = `fill:transparent;stroke:${lineColor};stroke-width: ${lineWidth}px; stroke-dasharray:${axes.LINE_STYLES[$scale][lineType-1]}`;
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
{#if $isOk && p !== undefined}
|
|
45
|
+
<g class="series series_line" style={lineStyleStr} title={title}>
|
|
46
|
+
<polyline class="line" points={p}/>
|
|
47
|
+
</g>
|
|
48
|
+
{/if}
|
|
49
|
+
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
/****************************************************
|
|
3
|
+
* Multilines *
|
|
4
|
+
* -------------------- *
|
|
5
|
+
* shows series of lines components *
|
|
6
|
+
*****************************************************/
|
|
7
|
+
|
|
8
|
+
import { getContext } from 'svelte';
|
|
9
|
+
import { ismatrix } from 'mdatools/arrays';
|
|
10
|
+
import { Colors } from '../Colors';
|
|
11
|
+
import { val2p } from '../Utils';
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
/*****************************************/
|
|
15
|
+
/* Input parameters */
|
|
16
|
+
/*****************************************/
|
|
17
|
+
|
|
18
|
+
export let xValues; // vector or array with x-coordinates of the points
|
|
19
|
+
export let yValues; // matrix (!) with y-coordinates of the points - every column is separate line
|
|
20
|
+
export let lineWidth = 1; // width (thickness) of the lines
|
|
21
|
+
export let lineColor = Colors.PRIMARY; // color of the lines
|
|
22
|
+
export let lineType = 1; // type of the lines (1 - solid, 2 - dashed, 3 - dotted, 4 - dashdot)
|
|
23
|
+
export let title = ''; // title of the bar series (reserved for future use)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
/*****************************************/
|
|
27
|
+
/* Component code */
|
|
28
|
+
/*****************************************/
|
|
29
|
+
|
|
30
|
+
// get axes context
|
|
31
|
+
const axes = getContext('axes');
|
|
32
|
+
|
|
33
|
+
const scale = axes.scale;
|
|
34
|
+
const isOk = axes.isOk;
|
|
35
|
+
const tX = axes.tX;
|
|
36
|
+
const tY = axes.tY;
|
|
37
|
+
|
|
38
|
+
// compute polynomial coordinates as string
|
|
39
|
+
let pp;
|
|
40
|
+
$: if ($isOk) {
|
|
41
|
+
|
|
42
|
+
if (!ismatrix(yValues)) {
|
|
43
|
+
throw Error('Multilines: parameter "yValues" must be a matrix.');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (xValues.length !== yValues.nrows) {
|
|
47
|
+
throw Error('Multilines: parameter "xValues" must have the same number of values as number of rows in "yValues".');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
pp = new Array(yValues.ncols);
|
|
51
|
+
for (let i = 0; i < pp.length; i++) {
|
|
52
|
+
pp[i] = val2p(xValues, yValues.getcolumn(i + 1), $tX, $tY, axes);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// reactive variables for coordinates of data points in pixels
|
|
57
|
+
$: lineStyleStr = `fill:transparent;stroke:${lineColor};stroke-width: ${lineWidth}px; stroke-dasharray:${axes.LINE_STYLES[$scale][lineType-1]}`;
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
{#if $isOk && pp !== undefined && pp.length > 0}
|
|
61
|
+
<g class="series series_multiline" style={lineStyleStr} title={title}>
|
|
62
|
+
{#each pp as p}
|
|
63
|
+
<polyline class="line" points={p}/>
|
|
64
|
+
{/each}
|
|
65
|
+
</g>
|
|
66
|
+
{/if}
|
|
67
|
+
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
/****************************************************
|
|
3
|
+
* Points *
|
|
4
|
+
* -------------------- *
|
|
5
|
+
* shows series of points/markers on a plot *
|
|
6
|
+
*****************************************************/
|
|
7
|
+
|
|
8
|
+
import { getContext } from 'svelte';
|
|
9
|
+
import { Colors } from '../Colors';
|
|
10
|
+
import { checkCoords } from '../Utils';
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
/*****************************************/
|
|
14
|
+
/* Input parameters */
|
|
15
|
+
/*****************************************/
|
|
16
|
+
|
|
17
|
+
export let xValues; // array of vector with x-coordinates of points
|
|
18
|
+
export let yValues; // array of vector with y-coordinates of points
|
|
19
|
+
export let marker = 1 // index for point symbol (from 1 to 8): "●", "◼", "▲", "▼", "⬥", "+", "*", "✕"
|
|
20
|
+
export let faceColor = 'transparent'; // face (fill) color of the points
|
|
21
|
+
export let borderColor = Colors.PRIMARY; // border color of the points
|
|
22
|
+
export let borderWidth = 1; // width (thickness) of the points
|
|
23
|
+
export let markerSize = 1; // size of the marker symbols
|
|
24
|
+
export let title = ''; // title of the point series - required for handling mouse click events
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
/*****************************************/
|
|
28
|
+
/* Component code */
|
|
29
|
+
/*****************************************/
|
|
30
|
+
|
|
31
|
+
// get axes context and adjust x margins
|
|
32
|
+
const axes = getContext('axes');
|
|
33
|
+
const tX = axes.tX;
|
|
34
|
+
const tY = axes.tY;
|
|
35
|
+
const isOk = axes.isOk;
|
|
36
|
+
|
|
37
|
+
let x, y, markerSymbol;
|
|
38
|
+
|
|
39
|
+
// reactive calculations triggered by changes in coordinates and plot parameters
|
|
40
|
+
$: if ($isOk) {
|
|
41
|
+
|
|
42
|
+
if (typeof(marker) !== "number" || marker < 1 || marker > axes.MARKER_SYMBOLS.length) {
|
|
43
|
+
throw Error(`ScatterSeries: parameter "marker" must be a number from 1 to ${axes.MARKER_SYMBOLS.length}.`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
markerSymbol = axes.MARKER_SYMBOLS[marker - 1];
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
x = axes.transform(checkCoords(xValues, 'Points'), $tX.coords);
|
|
50
|
+
y = axes.transform(checkCoords(yValues, 'Points'), $tY.coords);
|
|
51
|
+
|
|
52
|
+
// sanity check for input parameters
|
|
53
|
+
if (x.length !== y.length) {
|
|
54
|
+
throw Error('Points: parameters "xValues" and "yValues" must be vectors of the same length.')
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
// styles for the elements
|
|
60
|
+
$: textStyleStr = `dominant-baseline:middle;fill:${faceColor};stroke-width:${borderWidth}px;stroke:${borderColor};
|
|
61
|
+
font-size:${markerSize}em; text-anchor:middle;cursor:default;user-select:none;`;
|
|
62
|
+
</script>
|
|
63
|
+
|
|
64
|
+
{#if $isOk && x !== undefined && y !== undefined}
|
|
65
|
+
<g class="series series_points" title={title} style={textStyleStr} >
|
|
66
|
+
{#each x as v, i}
|
|
67
|
+
<text x={x[i]} y={y[i]}>{markerSymbol}</text>
|
|
68
|
+
{/each}
|
|
69
|
+
</g>
|
|
70
|
+
{/if}
|
|
71
|
+
|
|
72
|
+
<style>
|
|
73
|
+
text, text > :global(tspan) {
|
|
74
|
+
dominant-baseline: middle;
|
|
75
|
+
text-anchor: middle;
|
|
76
|
+
cursor: default;
|
|
77
|
+
user-select: none;
|
|
78
|
+
}
|
|
79
|
+
</style>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
/****************************************************
|
|
3
|
+
* Rectangles *
|
|
4
|
+
* -------------------- *
|
|
5
|
+
* shows series of rectangles *
|
|
6
|
+
*****************************************************/
|
|
7
|
+
|
|
8
|
+
import { getContext } from 'svelte';
|
|
9
|
+
import { Vector } from 'mdatools/arrays';
|
|
10
|
+
import { Colors } from '../Colors';
|
|
11
|
+
import { checkCoords } from '../Utils';
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
/*****************************************/
|
|
15
|
+
/* Input parameters */
|
|
16
|
+
/*****************************************/
|
|
17
|
+
|
|
18
|
+
export let left; // array of vector with coordinates of left sides of the bars
|
|
19
|
+
export let top; // array of vector with coordinates of top sides of the bars
|
|
20
|
+
export let width; // single value (same for all) or vector/array with bar width
|
|
21
|
+
export let height; // single value (same for all) or vector/array with bar height
|
|
22
|
+
export let faceColor = Colors.PRIMARY; // color of bar faces (fill)
|
|
23
|
+
export let borderColor = faceColor; // color of bar borders
|
|
24
|
+
export let lineWidth = 1; // width (thickness) of bar border lines
|
|
25
|
+
export let className = 'series_rect'; // CSS class name of the SVG group
|
|
26
|
+
export let title = ''; // title of the rectangle series (reserved for future use)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
/*****************************************/
|
|
30
|
+
/* Component code */
|
|
31
|
+
/*****************************************/
|
|
32
|
+
|
|
33
|
+
// get axes context and reactive variables needed to compute coordinates
|
|
34
|
+
const axes = getContext('axes');
|
|
35
|
+
const tX = axes.tX;
|
|
36
|
+
const tY = axes.tY;
|
|
37
|
+
const isOk = axes.isOk;
|
|
38
|
+
|
|
39
|
+
let rx, ry, rw, rh = undefined;
|
|
40
|
+
$: {
|
|
41
|
+
if ($isOk) {
|
|
42
|
+
rx = axes.transform(checkCoords(left, 'Rectangles'), $tX.coords);
|
|
43
|
+
ry = axes.transform(checkCoords(top, 'Rectangles'), $tY.coords);
|
|
44
|
+
|
|
45
|
+
if (rx.length !== ry.length) {
|
|
46
|
+
throw Error('Rectangles: parameters "left" and "top" must be vectors of the same length.');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (typeof width !== 'object') {
|
|
50
|
+
width = Vector.fill(width, left.length);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (typeof height !== 'object') {
|
|
54
|
+
height = Vector.fill(height, left.length);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
rw = axes.transform(width, $tX.objects);
|
|
58
|
+
rh = axes.transform(height, $tY.objects);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// styles for bars and labels
|
|
63
|
+
$: barsStyleStr = `fill:${faceColor};stroke:${borderColor};stroke-width:${lineWidth}px;`;
|
|
64
|
+
</script>
|
|
65
|
+
|
|
66
|
+
{#if $isOk}
|
|
67
|
+
<g class="series {className}" title={title} style={barsStyleStr}>
|
|
68
|
+
{#each left as v, i}
|
|
69
|
+
<rect x={rx[i]} y={ry[i]} width={rw[i]} height={rh[i]} />
|
|
70
|
+
{/each}
|
|
71
|
+
</g>
|
|
72
|
+
{/if}
|
|
73
|
+
|
|
74
|
+
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
/****************************************************
|
|
3
|
+
* Segments *
|
|
4
|
+
* -------------------- *
|
|
5
|
+
* shows series of line segments *
|
|
6
|
+
*****************************************************/
|
|
7
|
+
|
|
8
|
+
import { getContext } from 'svelte';
|
|
9
|
+
import { Colors } from '../Colors';
|
|
10
|
+
import { checkCoords } from '../Utils';
|
|
11
|
+
|
|
12
|
+
/*****************************************/
|
|
13
|
+
/* Input parameters */
|
|
14
|
+
/*****************************************/
|
|
15
|
+
|
|
16
|
+
export let xStart; // vector or array with x-coordinates of starting points
|
|
17
|
+
export let xEnd; // vector or array with x-coordinates of end points
|
|
18
|
+
export let yStart; // vector or array with y-coordinates of starting points
|
|
19
|
+
export let yEnd; // vector or array with y-coordinates of end points
|
|
20
|
+
export let lineColor = Colors.PRIMARY; // color of segment lines
|
|
21
|
+
export let lineType = 1; // type of segment lines (1 - solid, 2 - dashed, 3 - dotted, 4 - dashdot)
|
|
22
|
+
export let lineWidth = 1; // width (thickness) of segment lines
|
|
23
|
+
export let className = 'series_seg'; // CSS class name of the SVG group
|
|
24
|
+
export let title = ''; // title of the segment series (reserved for future use)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
/*****************************************/
|
|
28
|
+
/* Component code */
|
|
29
|
+
/*****************************************/
|
|
30
|
+
|
|
31
|
+
// get axes context and reactive variables needed to compute coordinates
|
|
32
|
+
const axes = getContext('axes');
|
|
33
|
+
const scale = axes.scale;
|
|
34
|
+
const isOk = axes.isOk;
|
|
35
|
+
const tX = axes.tX;
|
|
36
|
+
const tY = axes.tY;
|
|
37
|
+
|
|
38
|
+
let x1, x2, y1, y2 = undefined;
|
|
39
|
+
$: {
|
|
40
|
+
if ($isOk) {
|
|
41
|
+
|
|
42
|
+
x1 = axes.transform(checkCoords(xStart, 'Segments'), $tX.coords);
|
|
43
|
+
y1 = axes.transform(checkCoords(yStart, 'Segments'), $tY.coords);
|
|
44
|
+
x2 = axes.transform(checkCoords(xEnd, 'Segments'), $tX.coords);
|
|
45
|
+
y2 = axes.transform(checkCoords(yEnd, 'Segments'), $tY.coords);
|
|
46
|
+
|
|
47
|
+
const n = x1.length;
|
|
48
|
+
if (x2.length !== n || y1.length !== n || y2.length !== n) {
|
|
49
|
+
throw Error('Segments: parameters "xStart", "yStart", "xEnd" and "yEnd" should have the same length.');
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// reactive variables for coordinates of data points in pixels (and line style)
|
|
55
|
+
$: lineStyleStr = `stroke:${lineColor};stroke-width: ${lineWidth}px;stroke-dasharray:${axes.LINE_STYLES[$scale][lineType-1]}`;
|
|
56
|
+
</script>
|
|
57
|
+
|
|
58
|
+
{#if $isOk}
|
|
59
|
+
<g class="series {className}" title={title} style={lineStyleStr}>
|
|
60
|
+
{#each x1 as v, i}
|
|
61
|
+
<line x1={x1[i]} x2={x2[i]} y1={y1[i]} y2={y2[i]} />
|
|
62
|
+
{/each}
|
|
63
|
+
</g>
|
|
64
|
+
{/if}
|
|
65
|
+
|