svelte-plots-basic 2.0.1 → 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.
- package/README.md +7 -1
- package/package.json +1 -1
- package/src/2d/Axis.svelte +18 -1
- package/src/2d/Bars.svelte +1 -1
- package/src/2d/ColormapLegend.svelte +100 -0
- package/src/2d/Heatmap.svelte +109 -0
- package/src/2d/Points.svelte +1 -1
- package/src/2d/XAxis.svelte +14 -4
- package/src/2d/YAxis.svelte +14 -4
- package/src/2d/index.js +2 -1
- package/src/3d/Mesh.svelte +0 -3
- package/src/Utils.js +40 -2
package/README.md
CHANGED
|
@@ -4,7 +4,13 @@ The library is under development and breaking changes may occur in the coming ve
|
|
|
4
4
|
|
|
5
5
|
## News
|
|
6
6
|
|
|
7
|
-
New release (v. 2.0.0) introduces many breaking changes as the library was completely re-written. If you use previous versions of `svelte-plots-basic` in your projects, and do not want to change anything, stick to the latest 1.x.x version (v. 1.1.4).
|
|
7
|
+
New major release (v. 2.0.0) introduces many breaking changes as the library was completely re-written. If you use previous versions of `svelte-plots-basic` in your projects, and do not want to change anything, stick to the latest 1.x.x version (v. 1.1.4).
|
|
8
|
+
|
|
9
|
+
### 2.1.0
|
|
10
|
+
|
|
11
|
+
* Added new elements, `Heatmap` and `ColormapLegend`.
|
|
12
|
+
* Improvements to tick labels, in particular if values are too small (< 0.01) or too large (>99) the values are adjusted and a common factor is shown at the end of axis. This is applied only to automatic ticks, manually provided ticks and tick labels are shown as is.
|
|
13
|
+
* Small improvements and bug fixes.
|
|
8
14
|
|
|
9
15
|
## Description
|
|
10
16
|
|
package/package.json
CHANGED
package/src/2d/Axis.svelte
CHANGED
|
@@ -24,10 +24,22 @@
|
|
|
24
24
|
export let grid = []; // array with grid coordinates
|
|
25
25
|
export let axisLine = []; // array with coordinates of main axis line
|
|
26
26
|
export let tickCoords = []; // array with axis tick coordinates
|
|
27
|
+
export let tfCoords = []; // array with tick factor coordinates
|
|
28
|
+
export let tickFactor = 0; // tick factor (as power of 10)
|
|
27
29
|
|
|
28
30
|
export let lineColor = Colors.DARKGRAY; // color of main axis line
|
|
29
31
|
export let gridColor = Colors.MIDDLEGRAY; // color of grid lines
|
|
30
32
|
export let textColor = Colors.DARKGRAY; // color of tick labels
|
|
33
|
+
|
|
34
|
+
// generate text for tick factor label
|
|
35
|
+
function getTickFactorLabel(tf) {
|
|
36
|
+
if (tf === 0) return '';
|
|
37
|
+
if (tf < 0) {
|
|
38
|
+
return `×10<tspan baseline-shift = "super">${(tf).toString()}</tspan>`;
|
|
39
|
+
} else {
|
|
40
|
+
return `×10<tspan baseline-shift = "super">${(tf).toString()}</tspan>`;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
31
43
|
</script>
|
|
32
44
|
|
|
33
45
|
<g class="mdaplot__axis {className}">
|
|
@@ -44,7 +56,12 @@
|
|
|
44
56
|
|
|
45
57
|
<!-- labels -->
|
|
46
58
|
{#if tickCoords.length === 2 && tickLabels.length === tickCoords[1][0].length}
|
|
47
|
-
<AxisTickLabels {las} {pos} {tickCoords} {tickLabels} {textColor}/>
|
|
59
|
+
<AxisTickLabels {las} {pos} {tickCoords} {tickLabels} {textColor} />
|
|
60
|
+
{/if}
|
|
61
|
+
|
|
62
|
+
<!-- tick factor -->
|
|
63
|
+
{#if tickFactor !== 0}
|
|
64
|
+
<AxisTickLabels {pos} tickCoords={tfCoords} tickLabels={[getTickFactorLabel(tickFactor)]} {textColor} />
|
|
48
65
|
{/if}
|
|
49
66
|
</g>
|
|
50
67
|
|
package/src/2d/Bars.svelte
CHANGED
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
|
|
45
45
|
// compute maximum bar width and position of left side
|
|
46
46
|
const xv = checkCoords(xValues, 'BarSeries');
|
|
47
|
-
const w = max(diff(xv)) * barWidth;
|
|
47
|
+
const w = max(diff(xv.v)) * barWidth;
|
|
48
48
|
left = xv.subtract(w/2);
|
|
49
49
|
width = Vector.fill(w, xv.length);
|
|
50
50
|
}
|
|
@@ -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
|
+
|
package/src/2d/Points.svelte
CHANGED
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
$: if ($isOk) {
|
|
41
41
|
|
|
42
42
|
if (typeof(marker) !== "number" || marker < 1 || marker > axes.MARKER_SYMBOLS.length) {
|
|
43
|
-
throw Error(`
|
|
43
|
+
throw Error(`Points: parameter "marker" must be a number from 1 to ${axes.MARKER_SYMBOLS.length}.`);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
markerSymbol = axes.MARKER_SYMBOLS[marker - 1];
|
package/src/2d/XAxis.svelte
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { getContext } from 'svelte';
|
|
9
9
|
import { Vector, vector } from 'mdatools/arrays';
|
|
10
10
|
import { Colors } from '../Colors.js';
|
|
11
|
-
import { getAxisTicks } from '../Utils.js';
|
|
11
|
+
import { getAxisTicks, getTickLabels } from '../Utils.js';
|
|
12
12
|
import Axis from './Axis.svelte';
|
|
13
13
|
|
|
14
14
|
|
|
@@ -50,6 +50,8 @@
|
|
|
50
50
|
let grid = [];
|
|
51
51
|
let axisLine = [];
|
|
52
52
|
let tickCoords = [];
|
|
53
|
+
let tfCoords = [];
|
|
54
|
+
let tickFactor = 0;
|
|
53
55
|
|
|
54
56
|
// compute coordinates for ticks, grid and axis line
|
|
55
57
|
$: if ($isOk) {
|
|
@@ -66,8 +68,11 @@
|
|
|
66
68
|
// compute coordinates for the ends of grid
|
|
67
69
|
const gridYEnd = Vector.fill($yLim[1], tickNum);
|
|
68
70
|
|
|
69
|
-
// tick labels
|
|
70
|
-
|
|
71
|
+
// tick labels and tick factor
|
|
72
|
+
if (ticks === undefined || tickLabels === undefined) {
|
|
73
|
+
[tickFactor, tickLabels] = getTickLabels(ticksX.v);
|
|
74
|
+
}
|
|
75
|
+
|
|
71
76
|
if (tickLabels.length !== ticksX.length) {
|
|
72
77
|
throw('XAxis: "tickLabels" must be a array of the same size as ticks.')
|
|
73
78
|
}
|
|
@@ -87,6 +92,11 @@
|
|
|
87
92
|
[ticksX, ticksY2],
|
|
88
93
|
[ticksX, ticksY1]
|
|
89
94
|
];
|
|
95
|
+
|
|
96
|
+
tfCoords = [
|
|
97
|
+
[null, null],
|
|
98
|
+
[[$xLim[1]], [ticksY1.v[tickNum - 1]]],
|
|
99
|
+
];
|
|
90
100
|
}
|
|
91
101
|
</script>
|
|
92
102
|
|
|
@@ -94,6 +104,6 @@
|
|
|
94
104
|
<Axis
|
|
95
105
|
className="mdaplot__xaxis" pos={1}
|
|
96
106
|
{lineColor} {gridColor} {textColor}
|
|
97
|
-
{showGrid} {grid} {axisLine} {tickCoords} {tickLabels} {las}
|
|
107
|
+
{showGrid} {grid} {axisLine} {tickCoords} {tickLabels} {tfCoords} {tickFactor} {las}
|
|
98
108
|
/>
|
|
99
109
|
{/if}
|
package/src/2d/YAxis.svelte
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { getContext } from 'svelte';
|
|
9
9
|
import { Vector, vector } from 'mdatools/arrays';
|
|
10
10
|
import { Colors } from '../Colors.js';
|
|
11
|
-
import { getAxisTicks } from '../Utils.js';
|
|
11
|
+
import { getAxisTicks, getTickLabels } from '../Utils.js';
|
|
12
12
|
import Axis from './Axis.svelte';
|
|
13
13
|
|
|
14
14
|
|
|
@@ -50,6 +50,8 @@
|
|
|
50
50
|
let grid = [];
|
|
51
51
|
let axisLine = [];
|
|
52
52
|
let tickCoords = [];
|
|
53
|
+
let tfCoords = [];
|
|
54
|
+
let tickFactor = 0;
|
|
53
55
|
|
|
54
56
|
// compute tick x-coordinates
|
|
55
57
|
$: if ($isOk) {
|
|
@@ -66,8 +68,11 @@
|
|
|
66
68
|
// coordinates for the ends of grid
|
|
67
69
|
const gridXEnd = Vector.fill($xLim[1], tickNum);
|
|
68
70
|
|
|
69
|
-
// tick labels
|
|
70
|
-
|
|
71
|
+
// tick labels and tick factor
|
|
72
|
+
if (ticks === undefined || tickLabels === undefined) {
|
|
73
|
+
[tickFactor, tickLabels] = getTickLabels(ticksY.v)
|
|
74
|
+
}
|
|
75
|
+
|
|
71
76
|
if (tickLabels.length !== ticksY.length) {
|
|
72
77
|
throw('YAxis: "tickLabels" must be a array of the same size as ticks.')
|
|
73
78
|
}
|
|
@@ -87,6 +92,11 @@
|
|
|
87
92
|
[ticksX1, ticksY],
|
|
88
93
|
[ticksX2, ticksY]
|
|
89
94
|
];
|
|
95
|
+
|
|
96
|
+
tfCoords = [
|
|
97
|
+
[[], []],
|
|
98
|
+
[[ticksX1.v[tickNum - 1]], [$yLim[1]]],
|
|
99
|
+
];
|
|
90
100
|
}
|
|
91
101
|
</script>
|
|
92
102
|
|
|
@@ -94,6 +104,6 @@
|
|
|
94
104
|
<Axis
|
|
95
105
|
className="mdaplot__yaxis" pos={4}
|
|
96
106
|
{lineColor} {gridColor} {textColor}
|
|
97
|
-
{showGrid} {grid} {axisLine} {tickCoords} {tickLabels} {las}
|
|
107
|
+
{showGrid} {grid} {axisLine} {tickCoords} {tickLabels} {tfCoords} {tickFactor} {las}
|
|
98
108
|
/>
|
|
99
109
|
{/if}
|
package/src/2d/index.js
CHANGED
|
@@ -12,9 +12,10 @@ export { default as Bars } from './Bars.svelte';
|
|
|
12
12
|
export { default as Points } from './Points.svelte';
|
|
13
13
|
export { default as Lines } from './Lines.svelte';
|
|
14
14
|
export { default as Multilines } from './Multilines.svelte';
|
|
15
|
+
export { default as Heatmap } from './Heatmap.svelte';
|
|
15
16
|
|
|
16
|
-
export { default as ColorLegend } from './ColorLegend.svelte';
|
|
17
17
|
export { default as Legend } from './Legend.svelte';
|
|
18
18
|
export { default as TextLegend } from './TextLegend.svelte';
|
|
19
|
+
export { default as ColormapLegend } from './ColormapLegend.svelte';
|
|
19
20
|
|
|
20
21
|
export { getcolmap, Colors } from '../Colors.js';
|
package/src/3d/Mesh.svelte
CHANGED
|
@@ -60,8 +60,6 @@
|
|
|
60
60
|
const left = nr[0] - dnr;
|
|
61
61
|
const right = nr[1] + dnr;
|
|
62
62
|
const span = right - left;
|
|
63
|
-
console.log(nr)
|
|
64
|
-
console.log([left, right, span])
|
|
65
63
|
|
|
66
64
|
// compute coordinates for mesh segments lines
|
|
67
65
|
xMesh1Start = Vector.zeros((nx - 1) * nz);
|
|
@@ -171,7 +169,6 @@
|
|
|
171
169
|
}
|
|
172
170
|
};
|
|
173
171
|
|
|
174
|
-
$: console.log(meshColor1)
|
|
175
172
|
$: lineStyleStr = `stroke-width: ${lineWidth}px;stroke-dasharray:${axes.LINE_STYLES[$scale][lineType-1]};`;
|
|
176
173
|
</script>
|
|
177
174
|
|
package/src/Utils.js
CHANGED
|
@@ -1,4 +1,40 @@
|
|
|
1
1
|
import { cbind, vector, isvector, Vector } from 'mdatools/arrays';
|
|
2
|
+
import { min, max, diff } from 'mdatools/stat';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Generate vector with axis tick labels and tick factor based on numeric tick values.
|
|
7
|
+
*
|
|
8
|
+
* @param {Vector} ticks - vector with numeric tick values.
|
|
9
|
+
*
|
|
10
|
+
* @returns {Array} an array with tick factor and array with tick labels.
|
|
11
|
+
*/
|
|
12
|
+
export function getTickLabels(ticks) {
|
|
13
|
+
|
|
14
|
+
if (ticks === undefined) return undefined;
|
|
15
|
+
|
|
16
|
+
const step = Math.abs(min(diff(ticks)));
|
|
17
|
+
let tickFactor = 0;
|
|
18
|
+
if (step < 1 && Math.abs(max(ticks)) < 1) {
|
|
19
|
+
// values between 0 and 1 (absolute)
|
|
20
|
+
let decNum = Math.ceil(-Math.log10(step));
|
|
21
|
+
if (decNum <= 2) {
|
|
22
|
+
return [0, Array.from(ticks).map(v => v.toFixed(decNum).toString())];
|
|
23
|
+
}
|
|
24
|
+
tickFactor = decNum - 2;
|
|
25
|
+
decNum = 2;
|
|
26
|
+
return [-tickFactor, Array.from(ticks).map(v => (v * Math.pow(10, tickFactor)).toFixed(decNum).toString())];
|
|
27
|
+
} else {
|
|
28
|
+
let decNum = Math.ceil(Math.log10(step));
|
|
29
|
+
if (decNum <= 2) {
|
|
30
|
+
return [0, Array.from(ticks).map(v => v.toString())];
|
|
31
|
+
}
|
|
32
|
+
tickFactor = decNum - 2;
|
|
33
|
+
decNum = 2;
|
|
34
|
+
return [tickFactor, Array.from(ticks).map(v => (v / Math.pow(10, tickFactor)).toString())];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
2
38
|
|
|
3
39
|
/**
|
|
4
40
|
* Check coordinates and convert them to vector if necessary.
|
|
@@ -26,6 +62,7 @@ export function checkCoords(x, source) {
|
|
|
26
62
|
return x;
|
|
27
63
|
}
|
|
28
64
|
|
|
65
|
+
|
|
29
66
|
/**
|
|
30
67
|
* Create string with coordinates of SVG polygon in 3D.
|
|
31
68
|
*
|
|
@@ -130,10 +167,11 @@ export function getAxisTicks(ticks, lim, maxTickNum, round = true) {
|
|
|
130
167
|
// create a sequence of ticks
|
|
131
168
|
ticks = Vector.seq(tickMin, tickMax, tickSpacing);
|
|
132
169
|
|
|
133
|
-
// if step is smaller than 1 round values to remove small decimals
|
|
170
|
+
// if step is smaller than 1 round values to remove small decimals accidentially added by JS
|
|
134
171
|
if (Math.abs(tickSpacing) < 1) {
|
|
172
|
+
const decNum = Math.round(-Math.log10(tickSpacing));
|
|
135
173
|
const r = Math.pow(10, 1 + Math.round(-Math.log10(tickSpacing)));
|
|
136
|
-
ticks = ticks.apply(v => Math.round((v + Number.EPSILON) * r) / r)
|
|
174
|
+
ticks = ticks.apply(v => (Math.round((v + Number.EPSILON) * r) / r));
|
|
137
175
|
}
|
|
138
176
|
|
|
139
177
|
// make sure the ticks are not aligned with axes limits
|