@jjlmoya/utils-chrono 1.11.0 → 1.17.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/package.json +1 -1
- package/src/category/index.ts +6 -0
- package/src/entries.ts +10 -1
- package/src/tests/locale_completeness.test.ts +1 -1
- package/src/tests/tool_validation.test.ts +1 -1
- package/src/tool/gear-train-explorer/i18n/de.ts +1 -1
- package/src/tool/gear-train-explorer/i18n/es.ts +1 -1
- package/src/tool/gear-train-explorer/i18n/fr.ts +1 -1
- package/src/tool/gear-train-explorer/i18n/id.ts +1 -1
- package/src/tool/gear-train-explorer/i18n/it.ts +1 -1
- package/src/tool/gear-train-explorer/i18n/nl.ts +1 -1
- package/src/tool/gear-train-explorer/i18n/pl.ts +1 -1
- package/src/tool/gear-train-explorer/i18n/pt.ts +1 -1
- package/src/tool/gear-train-explorer/i18n/ru.ts +1 -1
- package/src/tool/gear-train-explorer/i18n/sv.ts +1 -1
- package/src/tool/gear-train-explorer/i18n/tr.ts +1 -1
- package/src/tool/gmt-world-timer/bibliography.astro +11 -0
- package/src/tool/gmt-world-timer/bibliography.ts +7 -0
- package/src/tool/gmt-world-timer/client.ts +250 -0
- package/src/tool/gmt-world-timer/component.astro +13 -0
- package/src/tool/gmt-world-timer/components/GmtPanel.astro +18 -0
- package/src/tool/gmt-world-timer/entry.ts +34 -0
- package/src/tool/gmt-world-timer/gmt-world-timer.css +239 -0
- package/src/tool/gmt-world-timer/helpers.ts +28 -0
- package/src/tool/gmt-world-timer/i18n/de.ts +72 -0
- package/src/tool/gmt-world-timer/i18n/en.ts +72 -0
- package/src/tool/gmt-world-timer/i18n/es.ts +72 -0
- package/src/tool/gmt-world-timer/i18n/fr.ts +72 -0
- package/src/tool/gmt-world-timer/i18n/id.ts +72 -0
- package/src/tool/gmt-world-timer/i18n/it.ts +72 -0
- package/src/tool/gmt-world-timer/i18n/ja.ts +72 -0
- package/src/tool/gmt-world-timer/i18n/ko.ts +72 -0
- package/src/tool/gmt-world-timer/i18n/nl.ts +72 -0
- package/src/tool/gmt-world-timer/i18n/pl.ts +72 -0
- package/src/tool/gmt-world-timer/i18n/pt.ts +72 -0
- package/src/tool/gmt-world-timer/i18n/ru.ts +72 -0
- package/src/tool/gmt-world-timer/i18n/sv.ts +72 -0
- package/src/tool/gmt-world-timer/i18n/tr.ts +72 -0
- package/src/tool/gmt-world-timer/i18n/zh.ts +72 -0
- package/src/tool/gmt-world-timer/index.ts +11 -0
- package/src/tool/gmt-world-timer/seo.astro +11 -0
- package/src/tool/perpetual-calendar/bibliography.astro +16 -0
- package/src/tool/perpetual-calendar/bibliography.ts +16 -0
- package/src/tool/perpetual-calendar/calendar.ts +24 -0
- package/src/tool/perpetual-calendar/client.ts +98 -0
- package/src/tool/perpetual-calendar/component.astro +17 -0
- package/src/tool/perpetual-calendar/components/CalendarPanel.astro +49 -0
- package/src/tool/perpetual-calendar/dial.ts +176 -0
- package/src/tool/perpetual-calendar/entry.ts +48 -0
- package/src/tool/perpetual-calendar/helpers.ts +49 -0
- package/src/tool/perpetual-calendar/i18n/de.ts +85 -0
- package/src/tool/perpetual-calendar/i18n/en.ts +102 -0
- package/src/tool/perpetual-calendar/i18n/es.ts +85 -0
- package/src/tool/perpetual-calendar/i18n/fr.ts +85 -0
- package/src/tool/perpetual-calendar/i18n/id.ts +85 -0
- package/src/tool/perpetual-calendar/i18n/it.ts +85 -0
- package/src/tool/perpetual-calendar/i18n/ja.ts +85 -0
- package/src/tool/perpetual-calendar/i18n/ko.ts +85 -0
- package/src/tool/perpetual-calendar/i18n/nl.ts +85 -0
- package/src/tool/perpetual-calendar/i18n/pl.ts +85 -0
- package/src/tool/perpetual-calendar/i18n/pt.ts +85 -0
- package/src/tool/perpetual-calendar/i18n/ru.ts +85 -0
- package/src/tool/perpetual-calendar/i18n/sv.ts +85 -0
- package/src/tool/perpetual-calendar/i18n/tr.ts +85 -0
- package/src/tool/perpetual-calendar/i18n/zh.ts +85 -0
- package/src/tool/perpetual-calendar/index.ts +11 -0
- package/src/tool/perpetual-calendar/perpetual-calendar.css +181 -0
- package/src/tool/perpetual-calendar/seo.astro +16 -0
- package/src/tool/perpetual-calendar/state.ts +26 -0
- package/src/tool/tourbillon-visualizer/bibliography.astro +11 -0
- package/src/tool/tourbillon-visualizer/bibliography.ts +7 -0
- package/src/tool/tourbillon-visualizer/client.ts +122 -0
- package/src/tool/tourbillon-visualizer/component.astro +126 -0
- package/src/tool/tourbillon-visualizer/components/TourbillonPanel.astro +66 -0
- package/src/tool/tourbillon-visualizer/entry.ts +51 -0
- package/src/tool/tourbillon-visualizer/helpers.ts +35 -0
- package/src/tool/tourbillon-visualizer/i18n/de.ts +96 -0
- package/src/tool/tourbillon-visualizer/i18n/en.ts +96 -0
- package/src/tool/tourbillon-visualizer/i18n/es.ts +96 -0
- package/src/tool/tourbillon-visualizer/i18n/fr.ts +96 -0
- package/src/tool/tourbillon-visualizer/i18n/id.ts +96 -0
- package/src/tool/tourbillon-visualizer/i18n/it.ts +96 -0
- package/src/tool/tourbillon-visualizer/i18n/ja.ts +96 -0
- package/src/tool/tourbillon-visualizer/i18n/ko.ts +96 -0
- package/src/tool/tourbillon-visualizer/i18n/nl.ts +96 -0
- package/src/tool/tourbillon-visualizer/i18n/pl.ts +96 -0
- package/src/tool/tourbillon-visualizer/i18n/pt.ts +96 -0
- package/src/tool/tourbillon-visualizer/i18n/ru.ts +96 -0
- package/src/tool/tourbillon-visualizer/i18n/sv.ts +96 -0
- package/src/tool/tourbillon-visualizer/i18n/tr.ts +96 -0
- package/src/tool/tourbillon-visualizer/i18n/zh.ts +96 -0
- package/src/tool/tourbillon-visualizer/index.ts +11 -0
- package/src/tool/tourbillon-visualizer/renderer/base.ts +78 -0
- package/src/tool/tourbillon-visualizer/renderer/cage.ts +115 -0
- package/src/tool/tourbillon-visualizer/renderer/esc.ts +160 -0
- package/src/tool/tourbillon-visualizer/seo.astro +11 -0
- package/src/tool/tourbillon-visualizer/state.ts +21 -0
- package/src/tool/tourbillon-visualizer/tourbillon.ts +9 -0
- package/src/tools.ts +6 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { getC, cl, CX, CY } from '../state';
|
|
2
|
+
|
|
3
|
+
function balanceRim(br: number) {
|
|
4
|
+
const c = getC();
|
|
5
|
+
c.beginPath();
|
|
6
|
+
c.arc(0, 0, br, 0, Math.PI * 2);
|
|
7
|
+
c.fillStyle = cl('#2a3040', '#d8d0c0');
|
|
8
|
+
c.fill();
|
|
9
|
+
c.strokeStyle = cl('#d4af37', '#b09050');
|
|
10
|
+
c.lineWidth = 2;
|
|
11
|
+
c.stroke();
|
|
12
|
+
c.beginPath();
|
|
13
|
+
c.arc(0, 0, br * 0.85, 0, Math.PI * 2);
|
|
14
|
+
c.strokeStyle = cl('rgba(212,175,55,0.3)', 'rgba(176,144,80,0.3)');
|
|
15
|
+
c.lineWidth = 1;
|
|
16
|
+
c.stroke();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function balanceScrews(br: number) {
|
|
20
|
+
const c = getC();
|
|
21
|
+
for (let i = 0; i < 16; i++) {
|
|
22
|
+
const a = (i / 16) * Math.PI * 2;
|
|
23
|
+
const x = Math.cos(a) * br, y = Math.sin(a) * br;
|
|
24
|
+
c.beginPath();
|
|
25
|
+
c.arc(x, y, 3, 0, Math.PI * 2);
|
|
26
|
+
const g = c.createRadialGradient(x - 0.5, y - 0.5, 0, x, y, 3);
|
|
27
|
+
g.addColorStop(0, cl('#e8f0f8', '#d0c8b8'));
|
|
28
|
+
g.addColorStop(0.5, cl('#c0d0e0', '#b0a898'));
|
|
29
|
+
g.addColorStop(1, cl('#8098b0', '#807868'));
|
|
30
|
+
c.fillStyle = g;
|
|
31
|
+
c.fill();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function drawBalance(angle: number, highlight: boolean) {
|
|
36
|
+
const c = getC();
|
|
37
|
+
const br = 55;
|
|
38
|
+
c.save();
|
|
39
|
+
c.translate(CX, CY);
|
|
40
|
+
c.rotate(angle);
|
|
41
|
+
balanceRim(br);
|
|
42
|
+
balanceScrews(br);
|
|
43
|
+
const cl2 = br * 0.6;
|
|
44
|
+
c.strokeStyle = cl('#c0d0e0', '#b0a898');
|
|
45
|
+
c.lineWidth = 2;
|
|
46
|
+
c.beginPath(); c.moveTo(-cl2, 0); c.lineTo(cl2, 0); c.stroke();
|
|
47
|
+
c.beginPath(); c.moveTo(0, -cl2); c.lineTo(0, cl2); c.stroke();
|
|
48
|
+
c.beginPath(); c.arc(0, 0, 4, 0, Math.PI * 2);
|
|
49
|
+
c.fillStyle = cl('#d4af37', '#b89850');
|
|
50
|
+
c.fill();
|
|
51
|
+
if (highlight) {
|
|
52
|
+
c.beginPath();
|
|
53
|
+
c.arc(0, 0, br + 4, 0, Math.PI * 2);
|
|
54
|
+
c.strokeStyle = 'rgba(212,175,55,0.6)';
|
|
55
|
+
c.lineWidth = 2;
|
|
56
|
+
c.setLineDash([3, 3]);
|
|
57
|
+
c.stroke();
|
|
58
|
+
c.setLineDash([]);
|
|
59
|
+
}
|
|
60
|
+
c.restore();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function drawHairspring(phase: number, hz: number, highlight: boolean) {
|
|
64
|
+
const c = getC();
|
|
65
|
+
const expand = Math.sin(phase) * (0.08 + hz * 0.02);
|
|
66
|
+
c.save();
|
|
67
|
+
c.translate(CX, CY);
|
|
68
|
+
c.beginPath();
|
|
69
|
+
for (let i = 0; i < 200; i++) {
|
|
70
|
+
const t = i / 200;
|
|
71
|
+
const r = 8 + t * 32 * (1 + expand);
|
|
72
|
+
const a = t * Math.PI * 8 + Math.sin(phase) * 0.3;
|
|
73
|
+
if (i === 0) c.moveTo(Math.cos(a) * r, Math.sin(a) * r);
|
|
74
|
+
else c.lineTo(Math.cos(a) * r, Math.sin(a) * r);
|
|
75
|
+
}
|
|
76
|
+
c.strokeStyle = highlight ? 'rgba(255,215,0,0.8)' : cl('rgba(192,208,224,0.5)', 'rgba(144,136,120,0.4)');
|
|
77
|
+
c.lineWidth = highlight ? 1.2 : 0.7;
|
|
78
|
+
c.stroke();
|
|
79
|
+
c.restore();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function drawPallet(phase: number, highlight: boolean) {
|
|
83
|
+
const c = getC();
|
|
84
|
+
c.save();
|
|
85
|
+
c.translate(CX, CY + 70);
|
|
86
|
+
const a = Math.sin(phase) * 0.35;
|
|
87
|
+
c.rotate(a);
|
|
88
|
+
c.strokeStyle = highlight ? '#ffd700' : cl('#a0b0c0', '#908878');
|
|
89
|
+
c.lineWidth = 2.5;
|
|
90
|
+
c.lineCap = 'round';
|
|
91
|
+
c.beginPath(); c.moveTo(-12, -18); c.lineTo(0, 0); c.stroke();
|
|
92
|
+
c.beginPath(); c.moveTo(0, 0); c.lineTo(10, -14); c.stroke();
|
|
93
|
+
c.beginPath(); c.moveTo(0, 0); c.lineTo(-10, -14); c.stroke();
|
|
94
|
+
c.fillStyle = '#c02030';
|
|
95
|
+
c.beginPath(); c.arc(10, -14, 2.5, 0, Math.PI * 2); c.fill();
|
|
96
|
+
c.beginPath(); c.arc(-10, -14, 2.5, 0, Math.PI * 2); c.fill();
|
|
97
|
+
c.fillStyle = cl('#a0b0c0', '#908878');
|
|
98
|
+
c.beginPath(); c.arc(0, 0, 3.5, 0, Math.PI * 2); c.fill();
|
|
99
|
+
c.beginPath(); c.arc(-12, -18, 2.5, 0, Math.PI * 2); c.fill();
|
|
100
|
+
if (highlight) {
|
|
101
|
+
c.beginPath();
|
|
102
|
+
c.arc(0, 0, 22, 0, Math.PI * 2);
|
|
103
|
+
c.strokeStyle = 'rgba(212,175,55,0.6)';
|
|
104
|
+
c.lineWidth = 1.5;
|
|
105
|
+
c.setLineDash([3, 3]);
|
|
106
|
+
c.stroke();
|
|
107
|
+
c.setLineDash([]);
|
|
108
|
+
}
|
|
109
|
+
c.restore();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function drawEscapeTeeth() {
|
|
113
|
+
const c = getC();
|
|
114
|
+
for (let i = 0; i < 15; i++) {
|
|
115
|
+
const a = (i / 15) * Math.PI * 2;
|
|
116
|
+
const nextA = ((i + 1) / 15) * Math.PI * 2;
|
|
117
|
+
const midA = (a + nextA) / 2;
|
|
118
|
+
c.beginPath();
|
|
119
|
+
c.moveTo(Math.cos(a) * 18, Math.sin(a) * 18);
|
|
120
|
+
c.lineTo(Math.cos(midA) * 26, Math.sin(midA) * 26);
|
|
121
|
+
c.lineTo(Math.cos(nextA) * 18, Math.sin(nextA) * 18);
|
|
122
|
+
c.closePath();
|
|
123
|
+
c.fillStyle = cl('#d4af37', '#b89850');
|
|
124
|
+
c.fill();
|
|
125
|
+
c.strokeStyle = cl('rgba(180,150,80,0.3)', 'rgba(120,100,60,0.3)');
|
|
126
|
+
c.lineWidth = 0.5;
|
|
127
|
+
c.stroke();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function drawEscapeCenter() {
|
|
132
|
+
const c = getC();
|
|
133
|
+
c.beginPath();
|
|
134
|
+
c.arc(0, 0, 16, 0, Math.PI * 2);
|
|
135
|
+
c.fillStyle = cl('#b89440', '#a08040');
|
|
136
|
+
c.fill();
|
|
137
|
+
c.beginPath();
|
|
138
|
+
c.arc(0, 0, 4, 0, Math.PI * 2);
|
|
139
|
+
c.fillStyle = cl('#2a3040', '#d0c8b8');
|
|
140
|
+
c.fill();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function drawEscapeWheel(angle: number, highlight: boolean) {
|
|
144
|
+
const c = getC();
|
|
145
|
+
c.save();
|
|
146
|
+
c.translate(CX, CY + 130);
|
|
147
|
+
c.rotate(angle);
|
|
148
|
+
drawEscapeTeeth();
|
|
149
|
+
drawEscapeCenter();
|
|
150
|
+
if (highlight) {
|
|
151
|
+
c.beginPath();
|
|
152
|
+
c.arc(0, 0, 30, 0, Math.PI * 2);
|
|
153
|
+
c.strokeStyle = 'rgba(212,175,55,0.6)';
|
|
154
|
+
c.lineWidth = 1.5;
|
|
155
|
+
c.setLineDash([3, 3]);
|
|
156
|
+
c.stroke();
|
|
157
|
+
c.setLineDash([]);
|
|
158
|
+
}
|
|
159
|
+
c.restore();
|
|
160
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { SEORenderer } from '@jjlmoya/utils-shared';
|
|
3
|
+
import { tourbillonVisualizer } from './index';
|
|
4
|
+
import type { KnownLocale } from '../../types';
|
|
5
|
+
interface Props { locale?: KnownLocale; }
|
|
6
|
+
const { locale = 'en' } = Astro.props;
|
|
7
|
+
const loader = tourbillonVisualizer.i18n[locale] || tourbillonVisualizer.i18n.en;
|
|
8
|
+
const content = await loader?.();
|
|
9
|
+
if (!content) return null;
|
|
10
|
+
---
|
|
11
|
+
{content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
let _ctx: CanvasRenderingContext2D;
|
|
2
|
+
let _isDark = true;
|
|
3
|
+
let _ff = 'system-ui, sans-serif';
|
|
4
|
+
|
|
5
|
+
export function getC() { return _ctx; }
|
|
6
|
+
export function isD() { return _isDark; }
|
|
7
|
+
export function ff() { return _ff; }
|
|
8
|
+
|
|
9
|
+
export function setCtx(c: CanvasRenderingContext2D) {
|
|
10
|
+
_ctx = c;
|
|
11
|
+
_ff = getComputedStyle(document.body).fontFamily || _ff;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function detT() {
|
|
15
|
+
const b = getComputedStyle(document.body).backgroundColor;
|
|
16
|
+
_isDark = !b || b === 'rgba(0, 0, 0, 0)' || b === 'transparent' ? true : parseInt(b.replace(/[^\d,]/g, '').split(',')[0]) < 128;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function cl(h: string, l: string) { return _isDark ? h : l; }
|
|
20
|
+
|
|
21
|
+
export const W = 700, H = 700, CX = 350, CY = 350;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const BEAT_RATES = {
|
|
2
|
+
18000: { hz: 2.5, rpm: 20, bph: 18000 },
|
|
3
|
+
28800: { hz: 4, rpm: 32, bph: 28800 },
|
|
4
|
+
36000: { hz: 5, rpm: 40, bph: 36000 },
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export function calc(b: number): { hz: number; rpm: number; bph: number } {
|
|
8
|
+
return BEAT_RATES[b as keyof typeof BEAT_RATES] || BEAT_RATES[28800];
|
|
9
|
+
}
|
package/src/tools.ts
CHANGED
|
@@ -18,6 +18,9 @@ import { STRAP_LENGTH_CALCULATOR_TOOL } from './tool/strap-length-calculator';
|
|
|
18
18
|
import { TELEMETER_CALCULATOR_TOOL } from './tool/telemeter-calculator';
|
|
19
19
|
import { SIDEREAL_TIME_TRACKER_TOOL } from './tool/sidereal-time-tracker';
|
|
20
20
|
import { GEAR_TRAIN_EXPLORER_TOOL } from './tool/gear-train-explorer';
|
|
21
|
+
import { PERPETUAL_CALENDAR_TOOL } from './tool/perpetual-calendar';
|
|
22
|
+
import { TOURBILLON_VISUALIZER_TOOL } from './tool/tourbillon-visualizer';
|
|
23
|
+
import { GMT_WORLD_TIMER_TOOL } from './tool/gmt-world-timer';
|
|
21
24
|
|
|
22
25
|
export const ALL_TOOLS: ToolDefinition[] = [
|
|
23
26
|
WATCH_ACCURACY_TRACKER_TOOL,
|
|
@@ -38,6 +41,9 @@ export const ALL_TOOLS: ToolDefinition[] = [
|
|
|
38
41
|
TELEMETER_CALCULATOR_TOOL,
|
|
39
42
|
SIDEREAL_TIME_TRACKER_TOOL,
|
|
40
43
|
GEAR_TRAIN_EXPLORER_TOOL,
|
|
44
|
+
PERPETUAL_CALENDAR_TOOL,
|
|
45
|
+
TOURBILLON_VISUALIZER_TOOL,
|
|
46
|
+
GMT_WORLD_TIMER_TOOL,
|
|
41
47
|
];
|
|
42
48
|
|
|
43
49
|
|