Skip to content

Commit 877b43c

Browse files
committed
v0.1.8
1 parent 3b524c1 commit 877b43c

File tree

11 files changed

+120
-35
lines changed

11 files changed

+120
-35
lines changed

changelog.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
# Changelog
22

3+
## [v0.1.8](https://github.com/janosh/matterviz/compare/v0.1.7...v0.1.8)
4+
5+
> 17 August 2025
6+
7+
### 🛠 Enhancements
8+
9+
- Measure distances and angles between selected `Structure` sites by @janosh in https://github.com/janosh/matterviz/pull/137
10+
- Optimade page 3-column layout (providers, suggestions, structure) by @janosh in https://github.com/janosh/matterviz/pull/126
11+
12+
### 🐛 Bug Fixes
13+
14+
- Fix parsing `mof-issue-127.cif` by @janosh in https://github.com/janosh/matterviz/pull/128
15+
- Disable `Structure`/`Trajectory` fullscreen buttons in non-browser contexts by @janosh in https://github.com/janosh/matterviz/pull/133
16+
- Set VSCode preferred extension location by @janosh in https://github.com/janosh/matterviz/pull/136
17+
318
## [v0.1.7](https://github.com/janosh/matterviz/compare/v0.1.6...v0.1.7)
419

520
> 11 August 2025

extensions/vscode/package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "matterviz",
33
"displayName": "MatterViz",
44
"description": "Visualize crystal structures and MD trajectories in VSCode",
5-
"version": "0.1.7",
5+
"version": "0.1.8",
66
"publisher": "janosh",
77
"icon": "icon.png",
88
"repository": "https://github.com/janosh/matterviz",
@@ -17,7 +17,10 @@
1717
"vscode": "^1.96.0"
1818
},
1919
"main": "./dist/extension.cjs",
20-
"extensionKind": ["ui", "workspace"],
20+
"extensionKind": [
21+
"ui",
22+
"workspace"
23+
],
2124
"activationEvents": [
2225
"onStartupFinished"
2326
],

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"homepage": "https://janosh.github.io/matterviz",
66
"repository": "https://github.com/janosh/matterviz",
77
"license": "MIT",
8-
"version": "0.1.7",
8+
"version": "0.1.8",
99
"type": "module",
1010
"svelte": "./dist/index.js",
1111
"bugs": "https://github.com/janosh/matterviz/issues",

src/lib/math.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ export type Vec3 = [number, number, number]
44
export type Matrix3x3 = [Vec3, Vec3, Vec3]
55
export type NdVector = number[]
66

7-
export const LOG_EPS = 1e-9 // Constants
7+
export const LOG_EPS = 1e-9
88
export const EPS = 1e-10
9+
export const RAD_TO_DEG = 180 / Math.PI
10+
export const DEG_TO_RAD = Math.PI / 180
911

1012
// Calculate all lattice parameters in a single efficient pass
1113
export function calc_lattice_params(
@@ -31,10 +33,9 @@ export function calc_lattice_params(
3133
const dot_bc = b_vec[0] * c_vec[0] + b_vec[1] * c_vec[1] + b_vec[2] * c_vec[2]
3234

3335
// Convert to angles in degrees
34-
const rad_to_deg = 180 / Math.PI
35-
const alpha = Math.acos(dot_bc / (b * c)) * rad_to_deg
36-
const beta = Math.acos(dot_ac / (a * c)) * rad_to_deg
37-
const gamma = Math.acos(dot_ab / (a * b)) * rad_to_deg
36+
const alpha = Math.acos(dot_bc / (b * c)) * RAD_TO_DEG
37+
const beta = Math.acos(dot_ac / (a * c)) * RAD_TO_DEG
38+
const gamma = Math.acos(dot_ab / (a * b)) * RAD_TO_DEG
3839

3940
return { a, b, c, alpha, beta, gamma, volume }
4041
}
@@ -173,10 +174,11 @@ export function dot(vec1: NdVector, vec2: NdVector): number | number[] | number[
173174
if (!mat2.every((row) => row.length === cols)) {
174175
throw new Error(`Second matrix must be rectangular`)
175176
}
176-
return mat1.map((_, i) =>
177+
return mat1.map((_, ii) =>
177178
Array.from(
178179
{ length: cols },
179-
(_, j) => mat1[i].reduce((sum, _val, k) => sum + mat1[i][k] * mat2[k][j], 0),
180+
(_, jj) =>
181+
mat1[ii].reduce((sum, _val, kk) => sum + mat1[ii][kk] * mat2[kk][jj], 0),
180182
)
181183
)
182184
}
@@ -247,9 +249,9 @@ export function cell_to_lattice_matrix(
247249
gamma: number,
248250
): Matrix3x3 {
249251
// Convert angles to radians
250-
const alpha_rad = (alpha * Math.PI) / 180
251-
const beta_rad = (beta * Math.PI) / 180
252-
const gamma_rad = (gamma * Math.PI) / 180
252+
const alpha_rad = alpha * DEG_TO_RAD
253+
const beta_rad = beta * DEG_TO_RAD
254+
const gamma_rad = gamma * DEG_TO_RAD
253255

254256
const cos_alpha = Math.cos(alpha_rad)
255257
const cos_beta = Math.cos(beta_rad)

src/lib/periodic-table/PeriodicTable.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@
364364
position: absolute;
365365
transform: translate(-50%, -10%);
366366
background: var(--tooltip-bg, rgba(0, 0, 0, 0.8));
367-
color: var(--tooltip-color, white);
367+
color: var(--tooltip-color, light-dark(black, white));
368368
padding: var(--tooltip-padding, 4px 6px);
369369
border-radius: var(--tooltip-border-radius, 6px);
370370
font-size: var(--tooltip-font-size, 14px);

src/lib/plot/ScatterPlot.svelte

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1843,16 +1843,13 @@
18431843
// 5. Final fallback
18441844
return `rgba(0, 0, 0, 0.7)`
18451845
})()}
1846-
18471846
{@const cx = x_format?.startsWith(`%`) ? x_scale_fn(new Date(x)) : x_scale_fn(x)}
18481847
{@const cy = (hovered_series?.y_axis === `y2` ? y2_scale_fn : y_scale_fn)(y)}
18491848
{@const x_formatted = format_value(x, x_format)}
18501849
{@const y_formatted = format_value(y, y_format)}
18511850
{@const label = point_label?.text ?? null}
1852-
18531851
{@const tooltip_lum = luminance(tooltip_bg_color ?? `rgba(0, 0, 0, 0.7)`)}
18541852
{@const tooltip_text_color = tooltip_lum > 0.5 ? `#000000` : `#ffffff`}
1855-
18561853
<foreignObject x={cx + 5} y={cy}>
18571854
<div
18581855
class="tooltip"
@@ -2038,7 +2035,7 @@
20382035
opacity: 0.8;
20392036
}
20402037
.tooltip {
2041-
color: var(--scatter-tooltip-color, white);
2038+
color: var(--scatter-tooltip-color, light-dark(black, white));
20422039
padding: var(--scatter-tooltip-padding, 1px 4px);
20432040
border-radius: var(--scatter-tooltip-border-radius, 3px);
20442041
font-size: var(--scatter-tooltip-font-size, 0.8em);

src/routes/[slug]/+page.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@
106106

107107
{#if (element?.discoverer && !element.discoverer.startsWith(`unknown`)) ||
108108
element?.year}
109-
<p class="discovery">
109+
<p style="text-align: center">
110110
Discovered
111111
{#if element?.discoverer && !element.discoverer.startsWith(`unknown`)}
112112
by <strong>{element.discoverer}</strong>

src/site/PeriodicTableControls.svelte

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
value_font_size?: number
1313
tooltip_font_size?: number
1414
tooltip_bg_color?: string
15-
tooltip_text_color?: string
1615
tile_border_radius?: number
1716
inner_transition_offset?: number
1817
tile_font_color?: string
@@ -35,7 +34,6 @@
3534
value_font_size = $bindable(18),
3635
tooltip_font_size = $bindable(14),
3736
tooltip_bg_color = $bindable(`#000000`),
38-
tooltip_text_color = $bindable(`#ffffff`),
3937
tile_border_radius = $bindable(1),
4038
inner_transition_offset = $bindable(0.5),
4139
tile_font_color = $bindable(`#ffffff`),
@@ -60,7 +58,6 @@
6058
value_font_size: 18,
6159
tooltip_font_size: 14,
6260
tooltip_bg_color: `#000000`,
63-
tooltip_text_color: `#ffffff`,
6461
tile_border_radius: 1,
6562
inner_transition_offset: 0.5,
6663
tile_font_color: `#ffffff`,
@@ -85,7 +82,6 @@
8582
'--elem-value-font-size': `${value_font_size}cqw`,
8683
'--tooltip-font-size': `${tooltip_font_size}px`,
8784
'--tooltip-bg': tooltip_bg_color,
88-
'--tooltip-color': tooltip_text_color,
8985
'--elem-tile-border-radius': `${tile_border_radius}pt`,
9086
'--ptable-spacer-ratio': `${1 / inner_transition_offset}`,
9187
'--elem-tile-font-color': tile_font_color,
@@ -126,7 +122,6 @@
126122
else if (prop === `value_font_size`) value_font_size = default_value as number
127123
else if (prop === `tooltip_font_size`) tooltip_font_size = default_value as number
128124
else if (prop === `tooltip_bg_color`) tooltip_bg_color = default_value as string
129-
else if (prop === `tooltip_text_color`) tooltip_text_color = String(default_value)
130125
else if (prop === `tile_border_radius`) tile_border_radius = Number(default_value)
131126
else if (prop === `inner_transition_offset`) {
132127
inner_transition_offset = Number(default_value)
@@ -177,7 +172,6 @@
177172
let tooltip_modified = $derived(
178173
tooltip_font_size !== defaults.tooltip_font_size ||
179174
tooltip_bg_color !== defaults.tooltip_bg_color ||
180-
tooltip_text_color !== defaults.tooltip_text_color ||
181175
tooltip_border_radius !== defaults.tooltip_border_radius ||
182176
tooltip_padding !== defaults.tooltip_padding ||
183177
tooltip_line_height !== defaults.tooltip_line_height ||
@@ -212,7 +206,6 @@
212206
function reset_tooltip(): void {
213207
tooltip_font_size = defaults.tooltip_font_size
214208
tooltip_bg_color = defaults.tooltip_bg_color
215-
tooltip_text_color = defaults.tooltip_text_color
216209
tooltip_border_radius = defaults.tooltip_border_radius
217210
tooltip_padding = defaults.tooltip_padding
218211
tooltip_line_height = defaults.tooltip_line_height
@@ -425,12 +418,6 @@
425418
<button onclick={() => reset_property(`tooltip_bg_color`)}>reset</button>
426419
</label>
427420

428-
<label>
429-
<span>Text color</span>
430-
<input type="color" bind:value={tooltip_text_color} />
431-
<button onclick={() => reset_property(`tooltip_text_color`)}>reset</button>
432-
</label>
433-
434421
<label>
435422
<span>Border radius (px)</span>
436423
<input type="range" min="0" max="20" step="1" bind:value={tooltip_border_radius} />

src/site/PeriodicTableDemo.svelte

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
let value_font_size: number = $state(18)
2222
let tooltip_font_size: number = $state(14)
2323
let tooltip_bg_color: string = $state(`rgba(0, 0, 0, 0.8)`)
24-
let tooltip_text_color: string = $state(`white`)
2524
let tile_border_radius: number = $state(1)
2625
let inner_transition_offset: number = $state(0.5)
2726
let tile_font_color: string = $state(`#ffffff`)
@@ -147,7 +146,6 @@
147146
bind:value_font_size
148147
bind:tooltip_font_size
149148
bind:tooltip_bg_color
150-
bind:tooltip_text_color
151149
bind:tile_border_radius
152150
bind:inner_transition_offset
153151
bind:tile_font_color

tests/vitest/colors.test.ts

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { element_color_schemes, is_color } from '$lib/colors'
1+
import {
2+
element_color_schemes,
3+
get_bg_color,
4+
is_color,
5+
luminance,
6+
pick_color_for_contrast,
7+
} from '$lib/colors'
28
import { elem_symbols } from '$lib/labels'
39
import { describe, expect, test } from 'vitest'
410

@@ -227,3 +233,58 @@ describe(`is_color function`, () => {
227233
expect(is_color(element_color_schemes.Vesta.He)).toBe(true)
228234
})
229235
})
236+
237+
test.each([
238+
[`#000000`, 0, `black`],
239+
[`#ffffff`, 1, `white`],
240+
[`#ff0000`, 0.299, `red`],
241+
[`#00ff00`, 0.587, `green`],
242+
[`#0000ff`, 0.114, `blue`],
243+
[`#808080`, 0.502, `gray`],
244+
[`#ff8000`, 0.594, `orange`],
245+
[`red`, 0.299, `named color`],
246+
[`rgb(255, 0, 0)`, 0.299, `rgb format`],
247+
[`hsl(0, 100%, 50%)`, 0.299, `hsl format`],
248+
])(`luminance(%s) = %s (%s)`, (color, expected) => {
249+
expect(luminance(color)).toBeCloseTo(expected, 3)
250+
})
251+
252+
test.each([
253+
[null, undefined, `rgba(0, 0, 0, 0)`, `null element`],
254+
[document.createElement(`div`), `#ff0000`, `#ff0000`, `explicit bg_color`],
255+
])(`get_bg_color: %s`, (elem, bg_color, expected, _desc) => {
256+
expect(get_bg_color(elem, bg_color)).toBe(expected)
257+
})
258+
259+
test(`get_bg_color returns transparent for transparent background`, () => {
260+
const mock_elem = document.createElement(`div`)
261+
Object.defineProperty(window, `getComputedStyle`, {
262+
value: () => ({ backgroundColor: `rgba(0, 0, 0, 0)` }),
263+
writable: true,
264+
})
265+
expect(get_bg_color(mock_elem)).toBe(`rgba(0, 0, 0, 0)`)
266+
})
267+
268+
test.each([
269+
[`#ffffff`, `black`, `light background`],
270+
[`#000000`, `white`, `dark background`],
271+
])(`pick_color_for_contrast: %s → %s (%s)`, (bg_color, expected) => {
272+
const mock_elem = document.createElement(`div`)
273+
expect(pick_color_for_contrast(mock_elem, bg_color)).toBe(expected)
274+
})
275+
276+
test(`pick_color_for_contrast uses custom threshold`, () => {
277+
const mock_elem = document.createElement(`div`)
278+
expect(pick_color_for_contrast(mock_elem, `#808080`, 0.5)).toBe(`black`)
279+
})
280+
281+
test(`pick_color_for_contrast uses custom colors`, () => {
282+
const mock_elem = document.createElement(`div`)
283+
expect(pick_color_for_contrast(mock_elem, `#000000`, 0.7, [`blue`, `yellow`])).toBe(
284+
`yellow`,
285+
)
286+
})
287+
288+
test(`pick_color_for_contrast handles null element gracefully`, () => {
289+
expect(pick_color_for_contrast(null, `#ffffff`)).toBe(`black`)
290+
})

0 commit comments

Comments
 (0)