svelte-plots-basic 2.5.7 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,99 +1,123 @@
1
+ <!--
2
+ @component Adds a heatmap visializing values of a matrix.
3
+
4
+ Main properties:
5
+ - `values` - matrix (object of class `Matrix` from `mdatools` package) with values to visualize.
6
+ - `breaks` - array (or vector) with interval breaks boundaries (optional).
7
+ - `colmap` - array with colors for each break (optional).
8
+
9
+ Example:
10
+
11
+ ```svelte
12
+ <script>
13
+ import { Matrix } from 'mdatools/arrays';
14
+ import { Axes, Heatmap } from 'svelte-plots-basic/2d';
15
+
16
+ // create matrix with 5 rows and 10 columns filled with 5random values.
17
+ const x = Matrix.rand(5, 10);
18
+ </script>
19
+
20
+ <Axes>
21
+ <Heatmap values={x} />
22
+ </Axes>
23
+ ```
24
+ -->
1
25
  <script>
2
- /*********************************************************
3
- * Heatmap *
4
- * -------------------- *
5
- * shows matrix values as a heatmap *
6
- **********************************************************/
7
26
 
8
27
  import { getContext } from 'svelte';
9
- import { Vector, ismatrix } from 'mdatools/arrays';
28
+ import { ismatrix, isvector } from 'mdatools/arrays';
10
29
  import { expandgrid } from 'mdatools/misc';
11
30
  import { split } from 'mdatools/stat';
12
31
 
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
- }
32
+ import { getcolmap, transformObjects, transformCoords, seq } from '../methods';
33
+ import { HEATMAP_NUM_SPLITS } from '../constants';
34
+
35
+
36
+ /** @type {Props} */
37
+ let {
38
+ values, // Matrix with values to show heatmap for
39
+ breaks, // vector with breaks to distribute the values in
40
+ colmap = null, // array with colors for each interval
41
+ } = $props();
42
+
43
+
44
+ // check that values are provided as a matrix
45
+ let v = $derived(ismatrix(values) && values.nrows > 0 && values.ncols > 0 ? values : null);
46
+
47
+ // check and process left values for breaks
48
+ let lb = $derived.by(() => {
49
+ if (!v) return null;
50
+ if (breaks && Array.isArray(breaks)) return breaks;
51
+ if (breaks && isvector(breaks)) return breaks.v;
52
+ return split(v.v, HEATMAP_NUM_SPLITS).v;
53
+ });
54
+
55
+ // check and process colormap values
56
+ let lc = $derived.by(() => {
57
+ if (colmap) {
58
+ if (!Array.isArray(colmap)) {
59
+ console.error('Heatmap: parameter "colmap" must be array with colors.');
60
+ return null;
61
+ }
62
+ if (colmap.length !== breaks.length - 1) {
63
+ console.error('Heatmap: number of color values in colormap does not match number of intervals defined by breaks.');
64
+ return null;
65
+ }
66
+ return colmap;
67
+ }
68
+ return getcolmap(lb.length - 1);
69
+ });
70
+
71
+ // compute coordinates of heatmap elements (left top corners)
72
+ let l = $derived(v ? seq(v.ncols) : null);
73
+ let t = $derived(v ? seq(v.nrows) : null);
74
+ let lt = $derived(l && t ? expandgrid(t, l) : null);
75
+
76
+ // compute world coordinates of the elements for each interval in world coordinates
77
+ let wc = $derived.by( () => {
78
+ if (!lt || !lb || !lc) return null;
79
+ const [top, left] = lt;
80
+ const nv = left.length; // number of values in matrix
81
+ const nb = lb.length; // number of breaks
82
+ const rl = Array(nb).fill().map(() => []); // coordinates of left for every break
83
+ const rt = Array(nb).fill().map(() => []); // coordinates of top for every break
84
+
85
+ // adjust left side for the first break and right side for the last
86
+ const llb = lb.slice();
87
+ const w = llb[1] - llb[0];
88
+ llb[0] = llb[0] - 0.1 * w;
89
+ llb[nb - 1] = llb[nb - 1] + 0.1 * w;
90
+
91
+ // loop over all breaks
92
+ for (let j = 0; j < nv; j++) {
93
+ const vj = v.v[j];
94
+ for (let i = 0; i < nb - 1; i++) {
95
+ if (vj > llb[i] && vj <= llb[i + 1]) {
96
+ rl[i].push(left.v[j] - 0.5);
97
+ rt[i].push(v.nrows - top.v[j] + 1.5);
98
+ break;
99
+ }
100
+ }
101
+ };
102
+ return {rl, rt};
103
+ });
47
104
 
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
105
 
52
- // get axes context and reactive variables needed to compute coordinates
106
+ // get axes context and compute screen coordinates
53
107
  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
- };
108
+ let rx = $derived(wc ? wc.rl.map(v => v.length > 0 ? transformCoords(v, axes.tX()) : []) : null);
109
+ let ry = $derived(wc ? wc.rt.map(v => v.length > 0 ? transformCoords(v, axes.tY()) : []) : null);
110
+ let rw = $derived(transformObjects([1], axes.tX()));
111
+ let rh = $derived(transformObjects([1], axes.tY()));
90
112
 
113
+ // check status
114
+ let isOk = $derived(rx && ry && rx.length === ry.length);
91
115
  </script>
92
116
 
93
- {#if $isOk && rx.length > 0}
94
- <g class="series {className}" title={title} style="stroke:0;stroke-width:0px;">
117
+ {#if isOk}
118
+ <g class="heatmap" style="stroke:0;stroke-width:0px;">
95
119
  <!-- loop over colors/intervals -->
96
- {#each lColmap as col, i}
120
+ {#each lc as col, i}
97
121
  <g title="heatmap-group" style="fill:{col};">
98
122
  {#if rx[i].length > 0}
99
123
  <!-- loop over elements which fall into the interval -->
@@ -105,5 +129,3 @@
105
129
  {/each}
106
130
  </g>
107
131
  {/if}
108
-
109
-
@@ -1,140 +1,129 @@
1
+ <!--
2
+ @component Adds legend for groups of series.
3
+
4
+ Main properties:
5
+ - `items` - array with text labels and their visual properties for each legend element.
6
+ - `position` - position of the legend ("topleft", "top", "topright", "right", etc), default: `"topleft"`.
7
+ - `lineColor` - color of the legend box line, default: `Colors.LEGEND`.
8
+ - `lineWidth` - width (thickness) of the legend box line in pixels: `1`.
9
+ - `faceColor` - color of the legend box background: `'#fff'`.
10
+ - `fontSize` - font size for the legend labels in em, default `0.85`.
11
+
12
+ Example:
13
+
14
+ ```svelte
15
+ <script>
16
+ import {Vector} from 'mdatools/array';
17
+
18
+ const x = Vector.seq(-10, 10, 0.1);
19
+ const y1 = x.apply(v => Math.cos(v));
20
+ const y2 = x.apply(v => Math.sin(v));
21
+ </script>
22
+
23
+ <Axes limX={[-10, 10]} limY={[-1.1, 1.1]} >
24
+
25
+ <Lines xValues={x} yValues={y1} lineColor="red" lineType="3" />
26
+ <Lines xValues={x} yValues={y2} lineColor="blue" lineType="1" />
27
+ <Points xValues={x} yValues={y2} faceColor="white" borderColor="blue" />
28
+
29
+ <Legend
30
+ position="topright"
31
+ items = {[
32
+ {"label": "cos(x)", "lineType": 1, "lineColor": "red"},
33
+ {"label": "sin(x)", "lineType": 1, "lineColor": "blue", "marker": 1, "faceColor": "white", "borderColor": "blue"},
34
+ ]}
35
+ />
36
+
37
+ <Box />
38
+ <XAxis label="x" showGrid={true} />
39
+ <YAxis label="f(x)" showGrid={true} />
40
+ </Axes>
41
+ -->
1
42
  <script>
2
- /****************************************************
3
- * Legend *
4
- * -------------------- *
5
- * shows legend for plot components *
6
- *****************************************************/
7
-
8
- import { mean } from 'mdatools/stat';
9
43
  import { getContext } from 'svelte';
10
- import { Colors } from '../Colors';
11
-
44
+ import { Colors, MARKER_SYMBOLS } from '../constants';
45
+ import { text2svg } from '../methods';
12
46
 
13
- /*****************************************/
14
- /* Input parameters */
15
- /*****************************************/
47
+ let {
48
+ items, // array with text labels and their visual properties for each legend element.
49
+ position = 'topleft', // position of the legend ("topleft", "top", "topright", "right", "bottomright", etc).
50
+ lineColor = Colors.LEGEND, // color of the legend box line
51
+ lineWidth = 1, // width (thickness) of the legend box line
52
+ faceColor = '#fff', // background color of the legend box
53
+ fontSize = 0.85 // font size for labels in em.
54
+ } = $props();
16
55
 
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
56
 
57
+ /* check if user provided position is correct */
58
+ function checkPosition(position) {
20
59
 
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.replace(/<(.|\n)*?>/g, '')).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;
60
+ if (typeof position !== 'string') {
61
+ console.error('Legend: value of "position" must be a string.');
62
+ return null;
73
63
  }
74
64
 
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;
65
+ if (!['top', 'left', 'right', 'topleft', 'topright', 'bottom', 'bottomleft', 'bottomright'].includes(position)) {
66
+ console.error('Legend: wrong value of "position" property');
67
+ return null;
68
+ }
69
+ return position;
101
70
  }
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%" fill="white" stroke="{Colors.MIDDLEGRAY}"></rect>
109
71
 
110
- {#each items as item, i}
72
+ /* check if user provided items are correct, transform text labels and set default values if they are absent */
73
+ function processItems(items) {
111
74
 
112
- <!-- individual legend item -->
113
- <svg x="{0}px" y="{i * (elHeight + 2 * elPadding)}px" width="{legendWidth}px" height="{elHeight + 2 * elPadding}px">
75
+ if (!items || !Array.isArray(items) || items.length < 1) {
76
+ console.error('Legend: property "items" must be provided as array of JSONs.');
77
+ return null;
78
+ }
114
79
 
115
- <style>
116
- .legend-text,
117
- .legend-text tspan {
118
- dominant-baseline: hanging;
80
+ for (let i = 0; i < items.length; i++) {
81
+ const item = items[i];
82
+
83
+ // check and transform label
84
+ if (!item.label) {
85
+ console.error('Legend: all elements of "items" must include at least one field: "label".');
86
+ return null;
87
+ }
88
+
89
+ const newLabel = text2svg(item.label);
90
+ const labelHeight = newLabel.length === item.label ? 1 : 1.4;
91
+ item.label = newLabel;
92
+ item['labelHeight'] = labelHeight;
93
+
94
+ // set default values for lines
95
+ if (item.line) {
96
+ if (!item.line.lineType) item.line['lineType'] = 1
97
+ if (!(item.line.lineType > 0 && item.line.lineType <= 4)) {
98
+ console.error('Legend: parameter "lineType" for legend item ' + (i + 1) + ' is incorrect.');
99
+ }
100
+ item.line.lineColor = item.line.lineColor ? item.line.lineColor : Colors.PRIMARY;
101
+ item.line.lineWidth = item.line.lineWidth ? item.line.lineWidth : 1;
102
+ }
103
+
104
+ // set default values for markers
105
+ if (item.point) {
106
+ if (!item.point.marker) item.point['marker'] = 1
107
+ if (!(item.point.marker > 0 && item.point.marker <= MARKER_SYMBOLS.length)) {
108
+ console.error('Legend: parameter "marker" for legend item ' + (i + 1) + ' is incorrect.');
109
+ }
110
+ item.point.faceColor = item.point.faceColor ? item.point.faceColor : 'transparent';
111
+ item.point.lineWidth = item.point.lineWidth ? item.point.lineWidth : 1;
112
+ item.point.lineColor = item.point.lineColor ? item.point.lineColor : Colors.PRIMARY;
113
+ }
114
+ }
115
+ return items;
119
116
  }
120
- </style>
121
117
 
122
- <!-- line -->
123
- {#if item.lineType && item.lineType > 0 && item.lineType <= 4}
124
- <line x1={elPadding} x2={elPadding + elWidth} y1={(elHeight + elPadding * 2)/2} y2={(elHeight + elPadding * 2)/2} stroke="{item.lineColor ? item.lineColor : Colors.PRIMARY}" stroke-width="{item.lineWidth ? item.lineWidth : 1}px" stroke-dasharray="{axes.LINE_STYLES[$scale][item.lineType - 1]}"/>
125
- {/if}
126
-
127
- <!-- marker -->
128
- {#if item.marker && item.marker > 0 && item.marker < axes.MARKER_SYMBOLS.length}
129
- <text x="{(elWidth + 2 * elPadding)/2}px" y="{(elHeight + 2 * elPadding)/2}px"
130
- dominant-baseline="middle" fill="{item.faceColor ? item.faceColor : 'transparent'}" stroke-width="{item.borderWidth ? item.borderWidth : 1}px" stroke="{item.borderColor ? item.borderColor : Colors.PRIMARY}" font-size="{fontSize}px" text-anchor="middle">{axes.MARKER_SYMBOLS[item.marker - 1]}</text>
131
- {/if}
132
-
133
-
134
- <!-- text -->
135
- <text class="legend-text" xml:space="preserve" x="{elWidth + elPadding * 3}px" y="{elPadding}px" text-anchor="start" fill="{Colors.LEGEND}" font-size="{fontSize}px"> {@html item.label}</text>
136
-
137
- </svg>
138
- {/each}
139
- </svg>
140
- {/if}
118
+ // get context and update group legend parameters reactivey
119
+ const axes = getContext('axes');
120
+ $effect(() => {
121
+ const newItems = processItems(items);
122
+ const newPosition = checkPosition(position);
123
+ axes.setGroupLegend(
124
+ newItems && newPosition ?
125
+ {show: true, position, items, lineColor, faceColor, lineWidth, fontSize} :
126
+ {show: false, position: null, items: null}
127
+ );
128
+ });
129
+ </script>
@@ -1,49 +1,63 @@
1
+ <!--
2
+ @component Adds a series of lines connecting points with provided coordinates (polyline).
3
+
4
+ Main properties:
5
+ - `xValues` - array of vector with x-coordinates of the points.
6
+ - `yValues` - array of vector with y-coordinates of the points.
7
+ - `lineColor` - lines color, default: `Colors.PRIMARY`.
8
+ - `lineWidth` - width (thickness) of the lines in pixels, defailt: `1`.
9
+ - `lineType` - type of lines (`1` - solid, `2` - dashed, `3` - dotted, `4` - dashdot).
10
+ - `onclick` - function (callback) to be called when user clicks on a polyline.
11
+
12
+ Example:
13
+
14
+ ```svelte
15
+ <script>
16
+ import { Axes, Lines } from 'svelte-plots-basic/2d';
17
+
18
+ const xValues = [-3, -2, -1, 0, 1, 2, 3];
19
+ const yValues = [9, 4, 1, 0, 1, 4, 9];
20
+ </script>
21
+
22
+ <Axes limX={[-4, 4]} limY={[-2, 10]}>
23
+ <Lines {xValues} {yValues} />
24
+ </Axes>
25
+ ```
26
+ -->
1
27
  <script>
2
- /****************************************************
3
- * Lines *
4
- * -------------------- *
5
- * shows lines connected sequence of points *
6
- *****************************************************/
7
-
8
28
  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
29
+ import { Colors } from '../constants';
30
+ import { val2p, checkCoords, handleClick } from '../methods';
31
+ import { LINE_STYLES } from '../constants';
32
+
33
+ /** @type {Props} */
34
+ let {
35
+ xValues, // vector or array with x-coordinates of the points
36
+ yValues, // vector or array with y-coordinates of the points
37
+ lineColor = Colors.PRIMARY, // color of segment lines
38
+ lineType = 1, // type of segment lines (1 - solid, 2 - dashed, 3 - dotted, 4 - dashdot)
39
+ lineWidth = 1, // width (thickness) of segment lines
40
+ onclick, // function to be called if onclick event fires
41
+ } = $props();
42
+
43
+
44
+ // check user provided coordinates
45
+ const xv = $derived(checkCoords(xValues, 'Lines'));
46
+ const yv = $derived(xv ? checkCoords(yValues, 'Lines', xv.length) : null);
47
+
48
+ // get axes context and compute coordinates of polyline
30
49
  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;
50
+ const p = $derived(xv && yv ? val2p(xv, yv, axes.tX(), axes.tY()) : null);
39
51
 
40
52
  // 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]}`;
53
+ const lineStyleStr = $derived(`fill:transparent;stroke:${lineColor};stroke-width: ${lineWidth}px; stroke-dasharray:${LINE_STYLES[axes.scales().plot][lineType-1]}`);
42
54
  </script>
43
55
 
44
- {#if $isOk && p !== undefined}
45
- <g class="series series-line" style={lineStyleStr} title={title}>
46
- <polyline class="line" points={p}/>
47
- </g>
56
+ {#if p}
57
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
58
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
59
+ <g onclick={(e) => handleClick(e, 'polyline', onclick)} class="series series-line" style={lineStyleStr} >
60
+ <polyline class="line" points={p}/>
61
+ </g>
48
62
  {/if}
49
63