4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Ruby+WebAssemblyでお絵描き

4
Last updated at Posted at 2023-04-08

はじめに

Ruby 3.2がリリースされてWebAssembly/WASIに対応しましたが、折角ブラウザでRubyが動くようになったのにHello, world!だけじゃ勿体ないので、もう一歩踏み込んでお絵描きをしてみます。

図形の描画

最初にJavascriptで書いてみます。HTML5のCanvasを用意してそこに簡単な図形を描画するコードです。

<html>
<canvas id="canvas"></canvas>
<script>
  var c=document.getElementById("canvas");
  var ctx=c.getContext("2d");

  ctx.fillStyle = "Orange";
  ctx.fillRect(25, 25, 50, 50);

  ctx.strokeStyle = "Red";
  ctx.lineWidth = 10;
  ctx.strokeRect(100, 25, 50, 50);
</script>
</html>

これをRubyに移植すると

<html>
  <script src="https://cdn.jsdelivr.net/npm/ruby-head-wasm-wasi@0.5.0/dist/browser.script.iife.js"></script>
  <canvas id="canvas"></canvas>
  <script type="text/ruby">
    require "js"
    Document = JS.global[:document]
    canvas = Document.getElementById("canvas")
    ctx = canvas.getContext("2d")

    ctx[:fillStyle] = "Orange"
    ctx.fillRect(25, 25, 50, 50)

    ctx[:strokeStyle] = "Red"
    ctx[:lineWidth] = 10
    ctx.strokeRect(100, 25, 50, 50)
  </script>
</html>

こんな感じです。
ctx[:fillStyle] という書き方が若干気になるのですが、Javascriptプロパティはこういう風に読み書きするようです。

localhost_8000_mandelbrot.html - 個人 - Microsoft​ Edge 2023_04_09 4_53_39.png

Rubyでブラウザに描画できました。

マンデルブロ集合を描いてみる

インターフェースさえ分かればあとは応用でなんでも描画できるはずということでマンデルブロ集合を描いてみます。マンデルブロのコードはAI(ChatGPT)に書いてもらいました(……が微妙に間違っていたので手直し)。

<html>
  <script src="https://cdn.jsdelivr.net/npm/ruby-head-wasm-wasi@0.5.0/dist/browser.script.iife.js"></script>
  <canvas id="canvas"></canvas>
  <script type="text/ruby">
    require "js"
    Document = JS.global[:document]
    canvas = Document.getElementById("canvas")
    ctx = canvas.getContext("2d")

    MAX_ITERATIONS = 100
    canvas[:width] = WIDTH = 512
    canvas[:height] = HEIGHT = 512

    def mandelbrot(z, c)
      MAX_ITERATIONS.times do |i|
        z = z * z + c
        return i if z.magnitude > 2.0
      end
      return MAX_ITERATIONS
    end

    xmin, xmax = -2.0, 1.0
    ymin, ymax = -1.5, 1.5

    colors = MAX_ITERATIONS.times.map do |i|
      r = (i * 3) % 256
      g = (i * 7) % 256
      b = (i * 11) % 256
      "rgb(#{r}, #{g}, #{b})"
    end
    colors << "black"
    
    HEIGHT.times do |j|
      WIDTH.times do |i|
        x = xmin + (xmax - xmin) * i.to_f / WIDTH
        y = ymin + (ymax - ymin) * j.to_f / HEIGHT
        c = Complex(x, y)
        n = mandelbrot(0, c)
        ctx[:fillStyle] = colors[n]
        ctx.fillRect(i, j, 1, 1)
      end
    end
  </script>
</html>

localhost_8000_mandelbrot.html - 個人 - Microsoft​ Edge 2023_04_09 4_55_55.png

AMD Ryzen 7 PRO 6850U で表示されるまで数十秒かかりました。重たい人は画像サイズを小さくすれば早く表示されます。

拡大して表示
min, xmax = -0.6, -0.5
ymin, ymax = -0.7, -0.6
localhost_8000_mandelbrot.html - 個人 - Microsoft​ Edge 2023_04_09 4_53_00.png

マンデルブロは無限に観ていられます。

感想

Rubyはグラフィック系が弱かったので、環境に依存せずに描けるようになったのは大きいです。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?