svelte-plots-basic 1.1.4 → 2.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.
Files changed (51) hide show
  1. package/README.md +59 -67
  2. package/package.json +10 -4
  3. package/src/2d/Area.svelte +61 -0
  4. package/src/2d/Axes.svelte +500 -0
  5. package/src/2d/Axis.svelte +67 -0
  6. package/src/2d/AxisLines.svelte +54 -0
  7. package/src/2d/AxisTickLabels.svelte +82 -0
  8. package/src/2d/Bars.svelte +65 -0
  9. package/src/2d/Box.svelte +50 -0
  10. package/src/2d/ColorLegend.svelte +36 -0
  11. package/src/2d/ColormapLegend.svelte +100 -0
  12. package/src/2d/Heatmap.svelte +109 -0
  13. package/src/2d/Legend.svelte +148 -0
  14. package/src/2d/Lines.svelte +49 -0
  15. package/src/2d/Multilines.svelte +67 -0
  16. package/src/2d/Points.svelte +79 -0
  17. package/src/2d/Rectangles.svelte +74 -0
  18. package/src/2d/Segments.svelte +65 -0
  19. package/src/2d/TextLabels.svelte +107 -0
  20. package/src/2d/TextLegend.svelte +53 -0
  21. package/src/2d/XAxis.svelte +109 -0
  22. package/src/2d/YAxis.svelte +109 -0
  23. package/src/2d/index.js +21 -0
  24. package/src/3d/Axes.svelte +445 -0
  25. package/src/3d/Axis.svelte +64 -0
  26. package/src/3d/AxisLines.svelte +50 -0
  27. package/src/3d/AxisTickLabels.svelte +54 -0
  28. package/src/3d/Lines.svelte +49 -0
  29. package/src/3d/Mesh.svelte +185 -0
  30. package/src/3d/Points.svelte +61 -0
  31. package/src/3d/Segments.svelte +69 -0
  32. package/src/3d/TextLabels.svelte +79 -0
  33. package/src/3d/XAxis.svelte +123 -0
  34. package/src/3d/YAxis.svelte +123 -0
  35. package/src/3d/ZAxis.svelte +123 -0
  36. package/src/3d/index.js +13 -0
  37. package/src/Colors.js +36 -1
  38. package/src/Utils.js +243 -0
  39. package/src/AreaSeries.svelte +0 -53
  40. package/src/Axes.svelte +0 -550
  41. package/src/BarSeries.svelte +0 -68
  42. package/src/Box.svelte +0 -35
  43. package/src/LineSeries.svelte +0 -50
  44. package/src/Rectangles.svelte +0 -64
  45. package/src/ScatterSeries.svelte +0 -69
  46. package/src/Segments.svelte +0 -52
  47. package/src/TextLabels.svelte +0 -88
  48. package/src/TextLegend.svelte +0 -38
  49. package/src/XAxis.svelte +0 -69
  50. package/src/YAxis.svelte +0 -72
  51. package/src/index.js +0 -16
@@ -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.v)) * 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,100 @@
1
+ <script>
2
+ /*********************************************************
3
+ * ColormapLegend *
4
+ * -------------------- *
5
+ * shows color map legend on a plot *
6
+ **********************************************************/
7
+
8
+ import { getContext } from 'svelte';
9
+ import { checkCoords } from '../Utils';
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
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
21
+ export let labelColor = '#909090'; // color of labels
22
+ export let fontSize = 0.85; // font size for labels in em
23
+
24
+
25
+ /*****************************************/
26
+ /* Component code */
27
+ /*****************************************/
28
+
29
+ // constant parameters
30
+ const WIDTH_RATIO = 0.80; // legend will span 80% of plot width
31
+ const HEIGHT_RATIO = 0.02; // legend will span 2% of plot height
32
+ const TOP_MARGIN = 0.25; // legend top margin is 25% of its height
33
+
34
+ // height of the legend elements in pixels
35
+ const EL_HEIGHTS_PX = {'small': 5, 'medium': 10, 'large': 15, 'xlarge': 20};
36
+
37
+ // check breaks values
38
+ $: if (!breaks || breaks.length < 2) {
39
+ throw new Error('ColormapLegend: breaks values must be provided.');
40
+ }
41
+
42
+ // check colormap values
43
+ $: if (!colmap || colmap.length !== breaks.length - 1) {
44
+ throw new Error('ColormapLegend: number of color values in colormap does not match number of intervals defined by breaks.');
45
+ }
46
+
47
+ // define local variables for breaks and prepare breaks labels
48
+ $: lBreaks = isvector(breaks) ? breaks.v : breaks;
49
+ $: lLabels = labels && labels.length === lBreaks.length ?
50
+ labels :
51
+ Array.from(lBreaks).map(v => v.toFixed(decNum).toString());
52
+
53
+ // get axes context and reactive variables needed to compute coordinates
54
+ const axes = getContext('axes');
55
+ const tX = axes.tX;
56
+ const tY = axes.tY;
57
+ const xLim = axes.xLim;
58
+ const yLim = axes.yLim;
59
+ const scale = axes.scale;
60
+ const isOk = axes.isOk;
61
+
62
+ // number of elements
63
+ $: n = colmap.length;
64
+
65
+ // compute screen coordinates of the elements
66
+ let rx, ry, rw, rh = undefined;
67
+ $: {
68
+ if ($isOk) {
69
+ // compute size of the whole block in plot coordinates
70
+ const axesWidth = $xLim[1] - $xLim[0];
71
+ const axesHeight = $yLim[1] - $yLim[0];
72
+ const width = axesWidth * WIDTH_RATIO;
73
+ const height = axesHeight * HEIGHT_RATIO;
74
+
75
+ // compute elements size and position
76
+ const elWidth = width / n;
77
+ const left = $xLim[0] + axesWidth * (1 - WIDTH_RATIO) * 0.5 ;
78
+ const elTop = $yLim[1] - height * TOP_MARGIN;
79
+
80
+ // compute screen coordinates and sized
81
+ ry = axes.transform(checkCoords([elTop], 'Rectangles'), $tY.coords);
82
+ rx = axes.transform(Vector.seq(0, n).apply(v => left + v * elWidth), $tX.coords);
83
+ rw = axes.transform([elWidth], $tX.objects);
84
+ rh = EL_HEIGHTS_PX[$scale];
85
+ }
86
+ };
87
+ </script>
88
+
89
+ {#if $isOk && rx.length > 0}
90
+ <g class="series colormap_legend" style="stroke:0;stroke-width:0px;">
91
+ {#each colmap as col, i}
92
+ <rect x={rx[i]} y={ry} width={rw} height={rh} fill="{col}"/>
93
+ <text x={rx[i]} y={ry} dx={0} dy={rh * 1.25} alignment-baseline="hanging" fill={labelColor} font-size="{fontSize}em" text-anchor="middle">{@html lLabels[i]}</text>
94
+ {/each}
95
+ <text x={rx[n]} y={ry} dx={0} dy={rh * 1.25} alignment-baseline="hanging" fill={labelColor} font-size="{fontSize}em" text-anchor="middle">{@html lLabels[n]}</text>
96
+ </g>
97
+ {/if}
98
+
99
+
100
+
@@ -0,0 +1,109 @@
1
+ <script>
2
+ /*********************************************************
3
+ * Heatmap *
4
+ * -------------------- *
5
+ * shows matrix values as a heatmap *
6
+ **********************************************************/
7
+
8
+ import { getContext } from 'svelte';
9
+ import { Vector, ismatrix } from 'mdatools/arrays';
10
+ import { expandgrid } from 'mdatools/misc';
11
+ import { split } from 'mdatools/stat';
12
+
13
+ import { getcolmap } from '../Colors';
14
+ import { checkCoords } from '../Utils';
15
+
16
+
17
+ /*****************************************/
18
+ /* Input parameters */
19
+ /*****************************************/
20
+
21
+ export let values; // Matrix with values to show heatmap for
22
+ export let breaks = null; // vector with breaks to distribute the values in
23
+ export let colmap = null; // array with colors for each interval
24
+
25
+ export let className = 'series_heatmap'; // 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
+ // check values
34
+ $: if (!ismatrix(values) || values.v.length === 0) {
35
+ throw new Error('Heatmap: parameter "values" must be a matrix.');
36
+ }
37
+
38
+ // check breaks values
39
+ $: if (!lBreaks || lBreaks.length < 2) {
40
+ throw new Error('Heatmap: breaks values are neither defined nor can not be computed.');
41
+ }
42
+
43
+ // check colormap values
44
+ $: if (!lColmap || lColmap.length !== lBreaks.length - 1) {
45
+ throw new Error('Heatmap: number of color values in colormap does not match number of intervals defined by breaks.');
46
+ }
47
+
48
+ // define local variables for breaks and colormap
49
+ $: lBreaks = breaks ? breaks.v : split(values.v, 13).v;
50
+ $: lColmap = colmap ? colmap : getcolmap(lBreaks.length - 1);
51
+
52
+ // get axes context and reactive variables needed to compute coordinates
53
+ const axes = getContext('axes');
54
+ const tX = axes.tX;
55
+ const tY = axes.tY;
56
+ const isOk = axes.isOk;
57
+
58
+ // compute combinations of heatmap element positions
59
+ let top, left;
60
+ $: {
61
+ const x = Vector.seq(1, values.ncols);
62
+ const y = Vector.seq(1, values.nrows);
63
+ [top, left] = expandgrid(y.v, x.v);
64
+ }
65
+
66
+ // compute screen coordinates of the elements for each interval
67
+ let rx, ry, rw, rh = undefined;
68
+ $: {
69
+ if ($isOk) {
70
+ rx = [];
71
+ ry = [];
72
+ for (let i = 1; i < lBreaks.length; i++) {
73
+ let lleft = [];
74
+ let ltop = [];
75
+ for (let j = 0; j < values.v.length; j++) {
76
+ const v = values.v[j];
77
+ if (v > lBreaks[i - 1] && v <= lBreaks[i]) {
78
+ lleft.push(left.v[j] - 0.5);
79
+ ltop.push(top.v[j] + 0.5);
80
+ }
81
+ }
82
+ rx.push(lleft.length === 0 ? [] : axes.transform(checkCoords(lleft, 'Rectangles'), $tX.coords));
83
+ ry.push(ltop.length === 0 ? [] : axes.transform(checkCoords(ltop, 'Rectangles'), $tY.coords));
84
+ };
85
+
86
+ rw = axes.transform([1], $tX.objects);
87
+ rh = axes.transform([1], $tY.objects);
88
+ }
89
+ };
90
+
91
+ </script>
92
+
93
+ {#if $isOk && rx.length > 0}
94
+ <g class="series {className}" title={title} style="stroke:0;stroke-width:0px;">
95
+ <!-- loop over colors/intervals -->
96
+ {#each lColmap as col, i}
97
+ <g title="heatmap_group" style="fill:{col};">
98
+ {#if rx[i].length > 0}
99
+ <!-- loop over elements which fall into the interval -->
100
+ {#each rx[i] as v, j}
101
+ <rect x={rx[i][j]} y={ry[i][j]} width={rw} height={rh} />
102
+ {/each}
103
+ {/if}
104
+ </g>
105
+ {/each}
106
+ </g>
107
+ {/if}
108
+
109
+
@@ -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 '&nbsp;' + 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
+