Interaktive Uhr
Python steuert die Zeiger einer React-Komponente. Alle Winkel sind in Grad angegeben.
import Clock from '@tdev/pyodide/clock/src/components/Clock';
<Clock clockId="sbb-uhr" />
```py live_pyo id=e63340b1-3821-4b70-99af-602272a48d8d title=Interaktive_Uhr
from clock import use_clock
from time import sleep
uhr = use_clock("sbb-uhr")
while True:
uhr.set_seconds(uhr.seconds + 1)
if uhr.seconds % 360 == 0:
sleep(0.99)
uhr.set_minutes(uhr.minutes + 6)
if uhr.minutes % 360 == 0:
uhr.set_hours(uhr.hours + 30)
sleep(0.01)
```
Uhr: sbb-uhr
from clock import use_clock
from time import sleep
uhr = use_clock("sbb-uhr")
while True:
uhr.set_seconds(uhr.seconds + 1)
if uhr.seconds % 360 == 0:
sleep(0.99)
uhr.set_minutes(uhr.minutes + 6)
if uhr.minutes % 360 == 0:
uhr.set_hours(uhr.hours + 30)
sleep(0.01)
Auf der eigenen Website einrichten
Voraussetzung ist das 👉 installierte Pyodide-Package.
-
Kopiere den vollständigen Ordner 👉 clock nach website/pyodide/clock. Er enthält Komponenten, Styles, Browser-Store und Python-Modul.
-
Ergänze den Ordner in der bestehenden
extensions-Liste des 👉 Pyodide-Plugins:siteConfig.tsextensions: ['./website/pyodide/clock'] -
Starte den Entwicklungsserver neu. Danach kannst du das MDX-Beispiel oben verwenden.
Die extension.json im kopierten Ordner legt den Namen und die Einstiegspunkte fest. Der Browser-Store wird automatisch initialisiert; der SiteStore deiner Website benötigt keine Ergänzungen.
Aufbau der Erweiterung
Die Uhr verwendet die allgemeine 👉 Erweiterungs-API. Nachrichtentypen, Worker, Browser-Store und React-Komponente liegen gemeinsam im kopierbaren Ordner.
Gemeinsamer Nachrichtentyp
export interface ClockTime {
hours: number;
minutes: number;
seconds: number;
}
export type ClockUpdate = Partial<ClockTime>;
Eine Nachricht kann einzelne Zeiger oder die ganze Uhr ändern. Worker und Browser-Handler verwenden ClockUpdate als Typparameter.
Python-Modul im Worker
import { defineWorkerExtension } from '@tdev/pyodide-code/extensions';
import type { ClockTime, ClockUpdate } from './protocol';
export default defineWorkerExtension<ClockUpdate>((context) => ({
clock: {
use_clock: (id: string) => {
const time: ClockTime = { hours: 0, minutes: 0, seconds: 0 };
const update = (values: Partial<ClockTime>) => {
Object.assign(time, values);
context.send(id, values);
};
return {
get hours() {
return time.hours;
},
get minutes() {
return time.minutes;
},
get seconds() {
return time.seconds;
},
reset: () => update({ hours: 0, minutes: 0, seconds: 0 }),
set_time: (hours: number, minutes: number, seconds: number) =>
update({ hours, minutes, seconds }),
set_hours: (hours: number) => update({ hours }),
set_minutes: (minutes: number) => update({ minutes }),
set_seconds: (seconds: number) => update({ seconds })
};
}
}
}));
Browser-Store und React
import { defineClientExtension } from '@tdev/pyodide-code/extensions';
import type { ClockUpdate } from './protocol';
import ClockStore from './src/stores/ClockStore';
export default defineClientExtension<ClockUpdate, ClockStore>({
createStore: () => new ClockStore(),
handleMessage: (store, { targetId, payload }) => {
const clock = store.useClock(targetId);
if (payload.hours !== undefined) {
clock.setHours(payload.hours);
}
if (payload.minutes !== undefined) {
clock.setMinutes(payload.minutes);
}
if (payload.seconds !== undefined) {
clock.setSeconds(payload.seconds);
}
}
});
Der Handler aktualisiert den 👉 ClockStore und dessen 👉 Clock-Modelle. Die 👉 React-Komponente greift innerhalb ihrer Funktion auf denselben Store zu:
import { useExtensionStore } from '@tdev/pyodide-code/hooks/useExtensionStore';
import clockExtension from '../../../client';
const clockStore = useExtensionStore(clockExtension);
const clock = clockStore.useClock(clockId);
Python-Handle
use_clock(id)- Verbindet den Handle mit der
clockIdder React-Komponente. Jeder Aufruf erzeugt einen eigenen Handle mit lokalen Nullwerten. hours,minutes,seconds- Lesen die letzten Winkel dieses Handles, nicht den Browser-Store oder andere Handles.
set_hours(winkel),set_minutes(winkel),set_seconds(winkel)- Ändern jeweils nur den zugehörigen Zeiger im Browser.
set_time(stunden, minuten, sekunden)- Setzt alle drei Zeiger. Die Argumente sind Winkel in Grad.
reset()- Setzt alle Zeiger auf null.
Zustand und Lebensdauer
Mehrere Komponenten mit derselben clockId teilen den Zustand im Browser-Store. Dieser bleibt nach Ende oder Abbruch eines Skripts erhalten; ein Neustart setzt ihn nicht automatisch zurück. Ein unbekanntes Ziel wird beim ersten Update im ClockStore angelegt, auch wenn noch keine React-Komponente dafür angezeigt wird.
Ein neuer Python-Handle beginnt dagegen wieder bei null und verändert die Anzeige erst mit seinem ersten Update. Die Erweiterung bietet keine Rückfragen vom Browser an Python.
Für Hilfsmodule, die Handles oder Factory-Referenzen speichern, gelten die Hinweise zur 👉 Wiederverwendung von Workern.