svelte-plots-basic 4.1.0 → 4.1.2

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/NEWS.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  This file contains the full release history of `svelte-plots-basic`. The [README](README.md) shows only the most recent releases.
4
4
 
5
+ ## 4.1.2
6
+
7
+ * Fixed `Bars` on a reversed x-axis: bars are now centred on their x-values. In 4.1.1 they were drawn shifted by one bar width.
8
+ * Fixed `Bars` and `Rectangles` on a reversed y-axis, where they were not shown.
9
+ * Fixed `Heatmap` on a reversed x- or y-axis, where its cells were not shown.
10
+ * Documented how `Rectangles` positions are interpreted on reversed axes: `left` and `top` are the sides drawn on the left and on top of the plot, so on a reversed x-axis `left` is the larger x-value and on a reversed y-axis `top` is the smaller y-value. Output on axes that are not reversed is unchanged.
11
+
12
+ ## 4.1.1
13
+
14
+ * Fixed `Rectangles` on a reversed x-axis, where they were not shown. The rectangle width is now always positive and rectangles extend to the right of `left` on screen.
15
+
5
16
  ## 4.1.0
6
17
 
7
18
  * Added a `svelte` export condition to every entry point, so bundlers recognize the package as a Svelte library. This matters when `prebundleSvelteLibraries` is disabled, where the components must be excluded from dependency pre-bundling.
package/README.md CHANGED
@@ -15,6 +15,17 @@ These websites and web-applications use `svelte-plots-basic` library:
15
15
 
16
16
  ## News
17
17
 
18
+ ### 4.1.2
19
+
20
+ * Fixed `Bars` on a reversed x-axis: bars are now centred on their x-values. In 4.1.1 they were drawn shifted by one bar width.
21
+ * Fixed `Bars` and `Rectangles` on a reversed y-axis, where they were not shown.
22
+ * Fixed `Heatmap` on a reversed x- or y-axis, where its cells were not shown.
23
+ * Documented how `Rectangles` positions are interpreted on reversed axes: `left` and `top` are the sides drawn on the left and on top of the plot, so on a reversed x-axis `left` is the larger x-value and on a reversed y-axis `top` is the smaller y-value. Output on axes that are not reversed is unchanged.
24
+
25
+ ### 4.1.1
26
+
27
+ * Fixed `Rectangles` on a reversed x-axis, where they were not shown. The rectangle width is now always positive and rectangles extend to the right of `left` on screen.
28
+
18
29
  ### 4.1.0
19
30
 
20
31
  * Added a `svelte` export condition to every entry point, so bundlers recognize the package as a Svelte library. This matters when `prebundleSvelteLibraries` is disabled, where the components must be excluded from dependency pre-bundling.
@@ -28,30 +39,6 @@ These websites and web-applications use `svelte-plots-basic` library:
28
39
  * Made subscripts, superscripts, and tick-factor labels consistent across modern browsers.
29
40
  * Updated to `mdatools ^1.5.0`, now declared as a peer dependency to prevent incompatible duplicate instances.
30
41
 
31
- ### 3.4.0
32
-
33
- * Added the `plotActions` property to `Axes` for adding custom buttons to the download panel.
34
- * Added advanced validation for axis limits, text-label positions, heatmap breaks, and custom plot actions.
35
- * Fixed text-label positioning and rotation when individual positions are provided.
36
- * Fixed heatmaps with automatic, custom, or constant-value breaks.
37
- * Added support for rectangular and constant-height 3D meshes.
38
- * Improved PNG, SVG, and clipboard export by serializing a clone instead of modifying the visible plot.
39
- * Fixed the advanced PNG export dialog so a default resolution is always selected, falling back to 300 dpi when necessary.
40
- * Prevented plot controls from submitting an enclosing HTML form.
41
- * Added package validation before publishing and synchronized Svelte 5 peer-dependency metadata.
42
- * Fixed conditionally rendered axes, boxes, and legends so their parent state is cleared when they are removed.
43
- * Improved heatmap interval processing and added automatically generated colormaps with more than 16 colors.
44
- * Fixed `TextLegend` positioning at zero and strengthened finite-range validation for 3D axes.
45
- * Reduced reactive and repeated allocation overhead for axis configuration, text measurement, PNG export, and colormap generation.
46
- * Added dependency-free regression tests and made them run automatically before packaging.
47
- * Documented the trust requirements for labels rendered as SVG/HTML markup.
48
-
49
- ### 3.3.0
50
-
51
- * Added advanced "save as PNG" option where user can select size and resolution of the image as well as change the filename.
52
- * several small improvements and bug fixes.
53
-
54
-
55
42
  Notes for earlier releases, including the list of breaking changes introduced in 3.0.0 when the library was re-written using Svelte 5, are available in the [full release notes](https://github.com/svkucheryavski/svelte-plots-basic/blob/main/NEWS.md).
56
43
 
57
44
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "svelte-plots-basic",
3
3
  "description": "Svelte components for creating simple plots",
4
- "version": "4.1.0",
4
+ "version": "4.1.2",
5
5
  "author": "Sergey Kucheryavskiy",
6
6
  "license": "MIT",
7
7
  "private": false,
@@ -27,6 +27,7 @@
27
27
  ```
28
28
  -->
29
29
  <script>
30
+ import { getContext } from 'svelte';
30
31
  import { Vector } from 'mdatools/arrays';
31
32
  import { Colors } from '../constants';
32
33
  import { checkCoords } from '../methods';
@@ -74,6 +75,13 @@
74
75
  return {provided: true, value};
75
76
  });
76
77
 
78
+ // get axes context, on reversed x-axis the edge drawn on the left is the larger value
79
+ const axes = getContext('axes');
80
+ const dir = $derived(Math.sign(axes.tX().objects[0]) || 1);
81
+
82
+ // on reversed y-axis the edge drawn on top is the smaller value
83
+ const dirY = $derived(Math.sign(axes.tY().objects[0]) || 1);
84
+
77
85
  const x = $derived.by(() => {
78
86
  if (bw === null || exactWidth === null) return null;
79
87
  const xv = checkCoords(xValues, 'BarSeries');
@@ -100,7 +108,7 @@
100
108
  const left = Vector.zeros(n);
101
109
  const width = Vector.zeros(n);
102
110
  for (let i = 0; i < n; i++) {
103
- left.v[i] = xv.v[i] - whalf;
111
+ left.v[i] = xv.v[i] - dir * whalf;
104
112
  width.v[i] = w;
105
113
  }
106
114
 
@@ -122,7 +130,7 @@
122
130
 
123
131
  for (let i = 0; i < n; i++) {
124
132
  const v = yv.v[i];
125
- top.v[i] = (v > 0 ? v : 0);
133
+ top.v[i] = dirY > 0 ? (v > 0 ? v : 0) : (v < 0 ? v : 0);
126
134
  height.v[i] = Math.abs(v);
127
135
  }
128
136
 
@@ -149,6 +149,12 @@
149
149
  let t = $derived(v ? seq(v.nrows) : null);
150
150
  let lt = $derived(l && t ? expandgrid(t, l) : null);
151
151
 
152
+ // get axes context, on reversed axes the edge drawn on the left is the larger x value
153
+ // and the edge drawn on top is the smaller y value
154
+ const axes = getContext('axes');
155
+ const dirX = $derived(Math.sign(axes.tX().objects[0]) || 1);
156
+ const dirY = $derived(Math.sign(axes.tY().objects[0]) || 1);
157
+
152
158
  // compute world coordinates of the elements for each interval in world coordinates
153
159
  let wc = $derived.by( () => {
154
160
  if (!lt || !lb || !lc) return null;
@@ -173,8 +179,8 @@
173
179
  const i = findInterval(vj, llb);
174
180
  if (i === -1) continue;
175
181
 
176
- rl[i].push(left.v[j] - 0.5);
177
- rt[i].push(v.nrows - top.v[j] + 1.5);
182
+ rl[i].push(dirX > 0 ? left.v[j] - 0.5 : left.v[j] + 0.5);
183
+ rt[i].push(dirY > 0 ? v.nrows - top.v[j] + 1.5 : v.nrows - top.v[j] + 0.5);
178
184
  rr[i].push(top.v[j]);
179
185
  rc[i].push(left.v[j]);
180
186
  };
@@ -182,8 +188,7 @@
182
188
  });
183
189
 
184
190
 
185
- // get axes context and compute screen coordinates
186
- const axes = getContext('axes');
191
+ // compute screen coordinates
187
192
  let rx = $derived(wc ? wc.rl.map(v => v.length > 0 ? transformCoords(v, axes.tX()) : []) : null);
188
193
  let ry = $derived(wc ? wc.rt.map(v => v.length > 0 ? transformCoords(v, axes.tY()) : []) : null);
189
194
  let rw = $derived(transformObjects([1], axes.tX()));
@@ -219,7 +224,7 @@
219
224
  {#if rx[i].length > 0}
220
225
  <!-- loop over elements which fall into the interval -->
221
226
  {#each rx[i] as v, j}
222
- <rect x={rx[i][j]} y={ry[i][j]} width={rw} height={rh} data-row={wc.rr[i][j]} data-col={wc.rc[i][j]}/>
227
+ <rect x={rx[i][j]} y={ry[i][j]} width={Math.abs(rw[0])} height={Math.abs(rh[0])} data-row={wc.rr[i][j]} data-col={wc.rc[i][j]}/>
223
228
  {/each}
224
229
  {/if}
225
230
  </g>
@@ -12,6 +12,9 @@
12
12
  - `className` - CSS class name for the rectangles group, default: `'series-rect'`.
13
13
  - `onclick` - function (callback) to be called when user clicks on any rectangle.
14
14
 
15
+ Width and height are always non-negative and rectangles extend from `left` to the right and
16
+ from `top` downwards on screen. So on a reversed x-axis `left` must be the larger value of the
17
+ two sides, and on a reversed y-axis `top` must be the smaller one.
15
18
 
16
19
  Example:
17
20
  ```svelte
@@ -104,7 +107,7 @@
104
107
  <!-- svelte-ignore a11y_no_static_element_interactions -->
105
108
  <g class="series {className}" style={barsStyleStr} onclick={(e) => handleClick(e, 'rect', onclick)} >
106
109
  {#each left as v, i}
107
- <rect x={rx[i]} y={ry[i]} width={rw[i]} height={rh[i]} />
110
+ <rect x={rx[i]} y={ry[i]} width={Math.abs(rw[i])} height={Math.abs(rh[i])} />
108
111
  {/each}
109
112
  </g>
110
113
  {/if}