svelte-plots-basic 1.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.
@@ -0,0 +1,50 @@
1
+ <script>
2
+
3
+ import { getContext } from 'svelte';
4
+ import { mrange } from 'mdatools/stat';
5
+ import { Colors } from './Colors';
6
+
7
+ // input parameters
8
+ export let xValues;
9
+ export let yValues;
10
+ export let title = "";
11
+ export let lineWidth = 1;
12
+ export let lineColor = Colors.PRIMARY;
13
+ export let lineType = 1;
14
+
15
+ /* sanity check of input parameters */
16
+ if (!Array.isArray(xValues) || !Array.isArray(yValues) || xValues.length != yValues.length) {
17
+ throw("LineSeries: parameters 'xValues' and 'yValues' must be numeric vectors of the same length.");
18
+ }
19
+
20
+ // compute ranges for x and y values
21
+ const xValuesRange = mrange(xValues, 0.05);
22
+ const yValuesRange = mrange(yValues, 0.05);
23
+
24
+ // get axes context and adjust axes limits
25
+ const axes = getContext('axes');
26
+ axes.adjustXAxisLimits(xValuesRange);
27
+ axes.adjustYAxisLimits(yValuesRange);
28
+
29
+ // get reactive variables needed to compute coordinates
30
+ const xLim = axes.xLim;
31
+ const yLim = axes.yLim;
32
+ const axesWidth = axes.width;
33
+ const axesHeight = axes.height;
34
+ const scale = axes.scale;
35
+
36
+ // reactive variables for coordinates of data points in pixels
37
+ $: x = axes.scaleX(xValues, $xLim, $axesWidth);
38
+ $: y = axes.scaleY(yValues, $yLim, $axesHeight);
39
+ $: p = x !== undefined && y !== undefined ? x.map((v, i) => `${v},${y[i]}`).join(' ') : undefined;
40
+ $: lineStyleStr = `fill:transparent;stroke:${lineColor};stroke-width: ${lineWidth}px;stroke-dasharray:${axes.LINE_STYLES[$scale][lineType - 1]}`;
41
+ </script>
42
+
43
+ {#if p !== undefined}
44
+ <g class="series lineseries" style="{lineStyleStr}" title="{title}">
45
+ <polyline class="line" points="{p}"/>
46
+ </g>
47
+ {/if}
48
+
49
+ <style>
50
+ </style>
@@ -0,0 +1,58 @@
1
+ <script>
2
+ import { getContext } from 'svelte';
3
+ import { Colors } from './Colors';
4
+
5
+ /* input parameters */
6
+ export let left;
7
+ export let top;
8
+ export let width;
9
+ export let height;
10
+ export let labels = undefined;
11
+ export let faceColor = Colors.PRIMARY;
12
+ export let borderColor = faceColor;
13
+ export let lineWidth = 1;
14
+
15
+ // styles for bars and labels
16
+ const barsStyleStr = `fill:${faceColor};stroke:${borderColor};stroke-width: ${lineWidth}px;`;
17
+
18
+ // multiply width and height values if needed
19
+ if (!Array.isArray(left) || !Array.isArray(top) || left.length < 1 || left.length != top.length) {
20
+ throw("Rectangles: parameters 'left' and 'top' must be vectors of the same size.")
21
+ }
22
+
23
+ // we make this reactive in case if left and right has been changed but not width
24
+ const n = left.length;
25
+ if (!Array.isArray(height)) height = Array(n).fill(height);
26
+ if (!Array.isArray(width)) width = Array(n).fill(width);
27
+
28
+ /* sanity check for input parameters */
29
+ if (top.length !== n || width.length !== n || height.length !== n) {
30
+ throw("Rectangles: x, y, w and h should have the same length (w and h can be single values).")
31
+ }
32
+
33
+ if (labels !== undefined && (!Array.isArray(labels) || labels.length !== n)) {
34
+ throw("Rectangles: vector with labels should have the same length as vectors with x and y coordinates.")
35
+ }
36
+
37
+ // get axes context and reactive variables needed to compute coordinates
38
+ const axes = getContext('axes');
39
+ const xLim = axes.xLim;
40
+ const yLim = axes.yLim;
41
+ const axesWidth = axes.width;
42
+ const axesHeight = axes.height;
43
+
44
+ // reactive variables for coordinates of data points in pixels
45
+ $: rx = axes.scaleX(left, $xLim, $axesWidth);
46
+ $: ry = axes.scaleY(top, $yLim, $axesHeight);
47
+ $: rw = axes.scaleX(width, $xLim, $axesWidth, true);
48
+ $: rh = axes.scaleY(height, $yLim, $axesHeight, true);
49
+ </script>
50
+
51
+ {#if rx !== undefined && ry !== undefined}
52
+ {#each left as v, i}
53
+ <rect x="{rx[i]}" y="{ry[i]}" width="{rw[i]}" height="{rh[i]}" style="{barsStyleStr}"></rect>
54
+ {/each}
55
+ {/if}
56
+
57
+ <style>
58
+ </style>
@@ -0,0 +1,81 @@
1
+ <script>
2
+
3
+ import { getContext } from 'svelte';
4
+ import { mrange } from 'mdatools/stat';
5
+ import { Colors } from './Colors';
6
+ import TextLabels from './TextLabels.svelte';
7
+
8
+ // input parameters
9
+ export let xValues;
10
+ export let yValues;
11
+ export let marker = 1
12
+ export let title = "";
13
+ export let faceColor = "transparent";
14
+ export let borderColor = Colors.PRIMARY;
15
+ export let borderWidth = 1;
16
+ export let markerSize = 1;
17
+
18
+ // TODO: implement later
19
+ //export let labels = yValues;
20
+ //export let showLabels = "no"; // can be "no", "hover", "always"
21
+
22
+ const markers = ["●", "◼", "▲", "▼", "⬥", "+", "*", "⨯"];
23
+ let markerSymbol;
24
+
25
+ /* sanity check of input parameters */
26
+ if (typeof(marker) !== "number" || marker < 1 || marker > markers.length) {
27
+ throw(`ScatterSeries: parameter 'marker' must be a number from 1 to ${markers.length}."`);
28
+ }
29
+
30
+ // to access shared parameters and methods from Axes
31
+ const axes = getContext('axes');
32
+
33
+ /* reactive actions related to x-values, fires when there are changes in:
34
+ * - xValues
35
+ * - marker
36
+ */
37
+ $: {
38
+ if (!Array.isArray(xValues)) {
39
+ throw("ScatterSeries: parameter 'xValues' must be a numeric vector.");
40
+ }
41
+
42
+ const xValuesRange = mrange(xValues, 0.05);
43
+ axes.adjustXAxisLimits(xValuesRange);
44
+
45
+ markerSymbol = "";
46
+ markerSymbol = markers[marker - 1];
47
+ }
48
+
49
+ /* reactive actions related to y-values, fires when there are changes in:
50
+ * - yValues
51
+ */
52
+ $: {
53
+ if (!Array.isArray(yValues) || xValues.length != yValues.length) {
54
+ throw("BarSeries: parameter 'yValues' must be a numeric vector of the same length as 'xValues'.");
55
+ }
56
+
57
+ const yValuesRange = mrange(yValues, 0.05);
58
+ axes.adjustYAxisLimits(yValuesRange);
59
+ }
60
+
61
+ </script>
62
+
63
+ <g class="series series_scatter" title="{title}">
64
+ <TextLabels {xValues} {yValues} labels="{markerSymbol}" textSize="{markerSize}" {faceColor} {borderColor} {borderWidth} />
65
+ </g>
66
+
67
+ <style>
68
+ :global(.marker) {
69
+ font-size: 1em;
70
+ cursor: default;
71
+ }
72
+
73
+ :global(.marker:hover) {
74
+ opacity: 90%;
75
+ }
76
+
77
+ :global(.series_scatter > *:hover + .labels_hover) {
78
+ visibility: visible;
79
+ opacity: 1;
80
+ }
81
+ </style>
@@ -0,0 +1,48 @@
1
+ <script>
2
+ import { getContext } from 'svelte';
3
+ import { Colors } from './Colors';
4
+
5
+ /* input parameters */
6
+ export let xStart;
7
+ export let xEnd;
8
+ export let yStart;
9
+ export let yEnd;
10
+ export let lineColor = Colors.PRIMARY;
11
+ export let lineType = 1;
12
+ export let lineWidth = 1;
13
+
14
+ /* sanity check for input parameters */
15
+ if (!Array.isArray(xStart) || !Array.isArray(xEnd) || !Array.isArray(yStart) || !Array.isArray(yEnd)) {
16
+ throw("Segments: parameters 'xStart', 'yStart', 'xEnd' and 'yEnd' must be vectors.")
17
+ }
18
+
19
+ const n = xStart.length;
20
+ if (xEnd.length !== n || yStart.length !== n || yEnd.length !== n) {
21
+ throw("Segments: parameters 'xStart', 'yStart', 'xEnd' and 'yEnd' should have the same length.")
22
+ }
23
+
24
+ // get axes context and reactive variables needed to compute coordinates
25
+ const axes = getContext('axes');
26
+ const xLim = axes.xLim;
27
+ const yLim = axes.yLim;
28
+ const axesWidth = axes.width;
29
+ const axesHeight = axes.height;
30
+ const scale = axes.scale;
31
+
32
+ // reactive variables for coordinates of data points in pixels (and line style)
33
+ $: x1 = axes.scaleX(xStart, $xLim, $axesWidth);
34
+ $: x2 = axes.scaleX(xEnd, $xLim, $axesWidth);
35
+ $: y1 = axes.scaleY(yStart, $yLim, $axesHeight);
36
+ $: y2 = axes.scaleY(yEnd, $yLim, $axesHeight);
37
+ $: lineStyleStr = `stroke:${lineColor};stroke-width: ${lineWidth}px;stroke-dasharray:${axes.LINE_STYLES[$scale][lineType - 1]}`;
38
+
39
+ </script>
40
+
41
+ {#if x1 !== undefined && y1 !== undefined}
42
+ {#each x1 as v, i}
43
+ <line x1="{x1[i]}" x2="{x2[i]}" y1="{y1[i]}" y2="{y2[i]}" style="{lineStyleStr}"></line>
44
+ {/each}
45
+ {/if}
46
+
47
+ <style>
48
+ </style>
@@ -0,0 +1,63 @@
1
+ <script>
2
+ import { getContext } from 'svelte';
3
+ import { Colors } from './Colors';
4
+
5
+ /* input parameters */
6
+ export let xValues;
7
+ export let yValues;
8
+ export let labels;
9
+ export let pos = 0;
10
+ export let faceColor = Colors.PRIMARY_TEXT;
11
+ export let borderColor = "transparent";
12
+ export let borderWidth = 0;
13
+ export let textSize = 1;
14
+
15
+ // text-anchor values depending on position
16
+ const textAnchors = ["middle", "middle", "start", "middle", "end"];
17
+
18
+ /* sanity check for input parameters */
19
+ if (!Array.isArray(xValues) || !Array.isArray(yValues) || xValues.length !== yValues.length) {
20
+ throw("TextLabels: parameters 'xValues' and 'yValues' must be vectors of the same length.")
21
+ }
22
+
23
+ // multiply labels values if needed
24
+ $: {
25
+ const n = xValues.length;
26
+ if (!Array.isArray(labels)) labels = Array(n).fill(labels);
27
+
28
+ // workaround for an issue when xValues and yValues are changed in parent app
29
+ // but array of labels is still the same as in the
30
+ if (labels.length != n) labels = Array(n).fill(labels[0]);
31
+
32
+ // check that the length of labels vector is correct
33
+ if (labels.length !== n) {
34
+ throw("TextLabels: parameter 'labels' must be a single text value or a vector of the same size as 'x' and 'y'.")
35
+ }
36
+ }
37
+
38
+ // get axes context and reactive variables needed to compute coordinates
39
+ const axes = getContext('axes');
40
+ const xLim = axes.xLim;
41
+ const yLim = axes.yLim;
42
+ const axesWidth = axes.width;
43
+ const axesHeight = axes.height;
44
+ const scale = axes.scale;
45
+
46
+ // reactive variables for coordinates of data points in pixels
47
+ $: x = axes.scaleX(xValues, $xLim, $axesWidth);
48
+ $: y = axes.scaleY(yValues, $yLim, $axesHeight);
49
+ $: dx = [0, 0, 1, 0, -1][pos] * axes.LABELS_MARGIN[$scale];
50
+ $: dy = [0, 1, 0, -1, 0][pos] * axes.LABELS_MARGIN[$scale];
51
+
52
+ // styles for bars and labels
53
+ $: textStyleStr = `fill:${faceColor};stroke-width:${borderWidth}px;stroke:${borderColor};font-size:${textSize}em;`;
54
+ </script>
55
+
56
+ {#if x !== undefined && y !== undefined}
57
+ {#each x as v, i}
58
+ <text style={textStyleStr} x={x[i]} y={y[i]} dx={dx} dy={dy} dominant-baseline="middle" text-anchor={textAnchors[pos]}>{@html labels[i]}</text>
59
+ {/each}
60
+ {/if}
61
+
62
+ <style>
63
+ </style>
@@ -0,0 +1,38 @@
1
+ <script>
2
+ import { getContext } from 'svelte';
3
+ import { Colors } from './Colors';
4
+
5
+ /* input parameters */
6
+ export let left;
7
+ export let top;
8
+ export let dx = "0";
9
+ export let dy = "1.25em";
10
+ export let elements;
11
+ export let faceColor = Colors.PRIMARY_TEXT;
12
+ export let borderColor = "transparent";
13
+ export let borderWidth = 0;
14
+ export let textSize = 1;
15
+
16
+ // get axes context and reactive variables needed to compute coordinates
17
+ const axes = getContext('axes');
18
+ const xLim = axes.xLim;
19
+ const yLim = axes.yLim;
20
+ const axesWidth = axes.width;
21
+ const axesHeight = axes.height;
22
+ const scale = axes.scale;
23
+
24
+ // reactive variables for coordinates of data points in pixels
25
+ $: x = axes.scaleX([left], $xLim, $axesWidth);
26
+ $: y = axes.scaleY([top], $yLim, $axesHeight);
27
+
28
+ // styles for bars and labels
29
+ $: textStyleStr = `fill:${faceColor};stroke-width:${borderWidth}px;stroke:${borderColor};font-size:${textSize}em;`;
30
+ </script>
31
+
32
+ {#if x !== undefined && y !== undefined && elements.length > 0}
33
+ <text style={textStyleStr} x={x} y={y} dx={dx} dy={dy} dominant-baseline="middle" text-anchor="start">
34
+ {#each elements as el, i}
35
+ <tspan x={x} dx={dx} dy={i === 0 ? 0 : dy}>{@html el}</tspan>
36
+ {/each}
37
+ </text>
38
+ {/if}
@@ -0,0 +1,69 @@
1
+ <script>
2
+ import { getContext } from 'svelte';
3
+ import { Colors } from './Colors';
4
+
5
+ // input parameters
6
+ export let slot = "xaxis"; // slot the component must be placed in
7
+ export let ticks = undefined; // vector with numeric tick positions in plot units
8
+ export let tickLabels = ticks; // vector with labels for each tick
9
+ export let showGrid = false; // logical, show or not grid lines
10
+
11
+ // set up tick mode
12
+ const tickMode = ticks === undefined ? "auto" : "manual";
13
+
14
+ /* sanity checks of input parameters */
15
+ if (slot !== "xaxis") {
16
+ throw("Component XAxis must have \"slot='xaxis'\" attribute.")
17
+ }
18
+
19
+ if (ticks !== undefined && !Array.isArray(ticks)) {
20
+ throw("XAxis: 'ticks' must be a vector of numbers.")
21
+ }
22
+
23
+ if (ticks !== undefined && !(Array.isArray(tickLabels) && tickLabels.length == ticks.length)) {
24
+ throw("XAxis: 'tickLabels' must be a vector of the same size as ticks.")
25
+ }
26
+
27
+ /* styles for axis and grid lines */
28
+ const axisLineStyleStr = `stroke:${Colors.DARKGRAY};line-width:1px;`;
29
+ const gridLineStyleStr = `stroke:${Colors.MIDDLEGRAY};stroke-opacity:${showGrid?1:0};stroke-dasharray:2px;`;
30
+
31
+
32
+ // get axes context and adjust x margins
33
+ const axes = getContext('axes');
34
+ axes.addXAxisMargins();
35
+
36
+ // get reactive variables needed to compute coordinates
37
+ const xLim = axes.xLim;
38
+ const yLim = axes.yLim;
39
+ const axesWidth = axes.width;
40
+ const axesHeight = axes.height;
41
+ const scale = axes.scale;
42
+ const isOk = axes.isOk;
43
+
44
+ // reactive variables for coordinates of axis lines
45
+ $: x = axes.scaleX($xLim, $xLim, $axesWidth);
46
+ $: y = axes.scaleY($yLim, $yLim, $axesHeight);
47
+
48
+ // reactive variables for ticks and their coordinates
49
+ $: dy = $scale === "small" ? 7 : 10;
50
+ $: tickNum = axes.TICK_NUM[$scale];
51
+ $: ticks = tickMode === "auto" ? axes.getAxisTicks(undefined, $xLim, tickNum, true) : ticks;
52
+ $: tickLabels = tickMode === "auto" ? ticks : tickLabels;
53
+ $: ticksX = axes.scaleX(ticks, $xLim, $axesWidth);
54
+ $: ticksY = y === undefined ? undefined : [y[0], y[0] + dy];
55
+ </script>
56
+
57
+ {#if $isOk && x !== undefined && y !== undefined }
58
+ <g class="mdaplot__axis mdaplot__xaxis">
59
+ {#each ticksX as tx, i}
60
+ <line x1="{tx}" x2="{tx}" y1="{y[0]}" y2="{y[1]}" style="{gridLineStyleStr}"></line>
61
+ <line x1="{tx}" x2="{tx}" y1="{ticksY[0]}" y2="{ticksY[1]}" style="{axisLineStyleStr}"></line>
62
+ <text x="{tx}" y="{ticksY[1]}" dx="0" dy="{dy}" class="mdaplot__axis-labels" dominant-baseline="middle" text-anchor="middle">{tickLabels[i]}</text>
63
+ {/each}
64
+ <line x1="{x[0]}" x2="{x[1]}" y1="{y[0]}" y2="{y[0]}" style="{axisLineStyleStr}"></line>
65
+ </g>
66
+ {/if}
67
+
68
+ <style>
69
+ </style>
@@ -0,0 +1,72 @@
1
+ <script>
2
+ import { getContext } from 'svelte';
3
+ import { Colors } from './Colors';
4
+
5
+ // input parameters
6
+ export let slot = "yaxis"; // slot the component must be placed in
7
+ export let ticks = undefined; // vector with numeric tick positions in plot units
8
+ export let tickLabels = ticks; // vector with labels for each tick
9
+ export let showGrid = false; // logical, show or not grid lines
10
+ export let las = 1;
11
+
12
+ // set up tick mode
13
+ const tickMode = ticks === undefined ? "auto" : "manual";
14
+
15
+ // TODO: set up tick text translation
16
+ const transform = las > 1 ? "" : "";
17
+
18
+ /* sanity checks of input parameters */
19
+ if (slot !== "yaxis") {
20
+ throw("Component YAxis must have \"slot='yaxis'\" attribute.")
21
+ }
22
+
23
+ if (ticks !== undefined && !Array.isArray(ticks)) {
24
+ throw("YAxis: 'ticks' must be a vector of numbers.")
25
+ }
26
+
27
+ if (ticks !== undefined && !(Array.isArray(tickLabels) && tickLabels.length == ticks.length)) {
28
+ throw("YAxis: 'tickLabels' must be a vector of the same size as ticks.")
29
+ }
30
+
31
+ /* styles for axis and grid lines */
32
+ const axisLineStyleStr = `stroke:${Colors.DARKGRAY};line-width:1px;`;
33
+ const gridLineStyleStr = `stroke:${Colors.MIDDLEGRAY};stroke-opacity:${showGrid?1:0};stroke-dasharray:2px;`;
34
+
35
+
36
+ // get axes context and adjust x margins
37
+ const axes = getContext('axes');
38
+ axes.addYAxisMargins();
39
+
40
+ // get reactive variables needed to compute coordinates
41
+ const xLim = axes.xLim;
42
+ const yLim = axes.yLim;
43
+ const axesWidth = axes.width;
44
+ const axesHeight = axes.height;
45
+ const scale = axes.scale;
46
+
47
+ // reactive variables for coordinates of axis lines
48
+ $: x = axes.scaleX($xLim, $xLim, $axesWidth);
49
+ $: y = axes.scaleY($yLim, $yLim, $axesHeight);
50
+
51
+ // reactive variables for ticks and their coordinates
52
+ $: dx = $scale === "small" ? -4 : -6;
53
+ $: tickNum = axes.TICK_NUM[$scale];
54
+ $: ticks = tickMode === "auto" ? axes.getAxisTicks(undefined, $yLim, tickNum, true) : ticks;
55
+ $: tickLabels = tickMode === "auto" ? ticks : tickLabels;
56
+ $: ticksY = axes.scaleY(ticks, $yLim, $axesHeight);
57
+ $: ticksX = x === undefined ? undefined : [x[0] + dx, x[0]];
58
+ </script>
59
+
60
+ {#if x !== undefined && y !== undefined }
61
+ <g class="mdaplot__axis mdaplot__yaxis">
62
+ {#each ticksY as ty, i}
63
+ <line x1="{x[0]}" x2="{x[1]}" y1="{ty}" y2="{ty}" style="{gridLineStyleStr}"></line>
64
+ <line x1="{ticksX[0]}" x2="{ticksX[1]}" y1="{ty}" y2="{ty}" style="{axisLineStyleStr}" ></line>
65
+ <text x="{ticksX[0]}" y="{ty}" dx="{dx}" dy="{0}" {transform} style="background:red" class="mdaplot__axis-labels" dominant-baseline="middle" text-anchor="end">{tickLabels[i]}</text>
66
+ {/each}
67
+ <line x1="{x[0]}" x2="{x[0]}" y1="{y[0]}" y2="{y[1]}" style="{axisLineStyleStr}" ></line>
68
+ </g>
69
+ {/if}
70
+
71
+ <style>
72
+ </style>
package/src/index.js ADDED
@@ -0,0 +1,16 @@
1
+ export { default as Axes } from './Axes.svelte';
2
+ export { default as XAxis } from './XAxis.svelte';
3
+ export { default as YAxis } from './YAxis.svelte';
4
+ export { default as Box } from './Box.svelte';
5
+
6
+ export { default as Rectangles } from './Rectangles.svelte';
7
+ export { default as Segments } from './Segments.svelte';
8
+ export { default as TextLabels } from './TextLabels.svelte';
9
+ export { default as TextLegend } from './TextLegend.svelte';
10
+
11
+ export { default as BarSeries } from './BarSeries.svelte';
12
+ export { default as ScatterSeries } from './ScatterSeries.svelte';
13
+ export { default as LineSeries } from './LineSeries.svelte';
14
+ export { default as AreaSeries } from './AreaSeries.svelte';
15
+
16
+ export { Colors } from './Colors.js';