RustとWebAssemblyでアナログ時計作ってみた



# はじめに

下記でパラパラ文字作った時とほぼ同じ構成で1秒ごとに針進めればアナログ時計できそうと思ったので作ってみる

前回作ったパラパラ文字について

https://qiita.com/shisojuice/items/90c70d8218236e0325b3


# プロジェクトの作成

RustでJavascript側から時分秒を受け取る。

縦横320の無地の画像に半径155かつ太さ2の円と、半径5の円を用意。

次に時針分針秒針を書く。(三角関数忘れたのでGemini1.5proに聞く🤖)

```
(s as f64 / 60.0): 秒を分で表す（0.0 - 1.0）
*360.0: 分に対する角度を度数法で計算
-90.0: 0秒のときに秒針が12時方向を指すように90度補正

(m as f64 + s as f64/ 60.0): 分に秒による経過分を加算
/60.0: 分を時間で表す（0.0 - 1.0）
*360.0: 時間に対する角度を度数法で計算
-90.0: 0分のときに分針が12時方向を指すように90度補正

(h as f64 % 12.0 + m as f64 / 60.0 + s as f64 / 3600.0):
h % 12.0: 12時間制にするため、時を12で割った余りを計算
分と秒を時間に変換して加算
/12.0: 時を12時間で割って、12時間に対する割合を計算
*360.0: 12時間に対する角度を度数法で計算
-90.0: 0時のときに時針が12時方向を指すように90度補正
```

とのこと。(忘れすぎてて数学やり直したい📝)

最後に、Base64の文字列を返す。

```rust:lib.rs

// 省略

#[wasm_bindgen]
pub fn clock_png(h : u32,m : u32,s : u32) -> String{
    let mut img = DynamicImage::new_rgba8(320,320);
    // 円の中心座標
    let center_x = img.width() / 2;
    let center_y = img.height() / 2;
    draw_filled_circle_mut(&mut img, (center_x as i32, center_y as i32), 155, Rgba([0, 0, 0, 255]));
    draw_filled_circle_mut(&mut img, (center_x as i32, center_y as i32), 153, Rgba([0, 0, 0, 0]));
    draw_filled_circle_mut(&mut img, (center_x as i32, center_y as i32), 5, Rgba([0, 0, 0, 255]));

    let s_angle = ((s as f64 / 60.0) * 360.0- 90.0).to_radians();
    draw_line_segment_mut(&mut img,(center_x as f32, center_y as f32),(center_x as f32 + 140.0 * s_angle.cos() as f32,center_y as f32 + 140.0 * s_angle.sin() as f32),Rgba([0, 0, 0, 255])); // 秒針

    let m_angle = (((m as f64 + s  as f64/ 60.0) / 60.0) * 360.0 - 90.0).to_radians();
    draw_line_segment_mut(&mut img,(center_x as f32, center_y as f32),(center_x as f32 + 120.0 * m_angle.cos() as f32,center_y as f32 + 120.0 * m_angle.sin() as f32),Rgba([0, 0, 0, 255])); // 長針

    let h_angle = (((h as f64 % 12.0 + m as f64 / 60.0 + s as f64 / 3600.0) / 12.0) * 360.0 - 90.0).to_radians();
    draw_line_segment_mut(&mut img,(center_x as f32, center_y as f32),(center_x as f32 + 80.0 * h_angle.cos() as f32,center_y as f32 + 80.0 * h_angle.sin() as f32),Rgba([0, 0, 0, 255])); // 短針

    let mut buffer = Cursor::new(Vec::new());
    img.write_to(&mut buffer, ImageFormat::Png).unwrap();
    let base64_string = general_purpose::STANDARD.encode(buffer.get_ref());
    // データURL形式で返す
    format!("data:image/png;base64,{}", base64_string)
}


// 省略

```

JavascriptのsetIntervalで1秒ごとに

上記の関数を呼び出して動かす⏰

(このやり方だと最大1秒の遅延が発生するため😧

下記コメントで頂いた修正案を最新ソース・成果物には適用済みです💪

また、Javascript実行環境の時刻のため

正確な時刻ではない可能性があるので注意してください。⏳)

```Javascript:index.js

// 省略

setInterval(()=>{
  const now = new Date();
  const h = now.getHours();
  const m = now.getMinutes();
  const s = now.getSeconds();
  document.getElementById("mainImg").src = clock_png(h,m,s);
}, 1000);

// 省略

```

これでメインの機能は実装完了！！

# 今回の成果物

デモURL

https://shisojuice.github.io/Rust_Clock/


デモ画像

![RustとWebAssemblyでアナログ時計作ってみた_001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3777149/af41ff9d-077e-be91-60fa-0817211f86d9.jpeg)

ソース

https://github.com/shisojuice/Rust_Clock


# まとめ

今回はRustを使ってアナログ時計作ってみました。🧑‍🎨

数学忘れすぎてて、、何事も使わないと忘れてしまうと実感しました😧

定着するのって難しいから、

ささいなことでもOutputしていこうと思います💪


※間違い等ありましたら、ご指摘いただけると助かります。