2
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?

Pluto.jl ノートブックの上で JavaScript/CSS を使ってカスタムウィジェットを作ったよ

Last updated at Posted at 2024-10-14

本日は

Qiita のダークモードは良いですね.最近は Pluto.jl を使った Julia のノートブック環境でJulia パッケージのチュートリアル作成・整備を行なっています.人の欲望は無限大なので Pluto.jl でいろんなことをしたいし不足部分は自分の裁量でカスタムしたいことも出てきています.

最近作ったもの

PlutoMonacoEditor.jl

Julia 以外のコードの編集を快適にするためのツールです.エディタは Monaco Editor を使っていますので VS Code を使った編集体験に慣れている方であれば作ったパッケージは役に立つのかなと思っています.以下の図は Rust の簡単なコードを編集する画面をセットアップし,エディタで入力されたコードを main.rs に一時ディレクトリに保存,それを裏で rustc main.rs を叩いで実行するデモを表しています.単にエディタを提供するだけでなく,編集したコードを Julia 側に対して String 型の値として渡すことができます:

image.png

Monaco Editor については下記の記事で解説がなされています.ブラウザで表示させるやり方も参考にしました.

PlutoEditorColorThemes.jl

もう一つ紹介します.こちらは Pluto Notebook の上で入力するセルをカスタマイズできるパッケージです.デフォルトでは下記のように Monokai 風になります.私はリッチなテキストエディタは Sublime Text から入門した人なので Monokai のようなカラフルなのが好きです.

image.png

setcolortheme! 関数を実行することで Pluto.jl が持っているコードのシンタックスハイライトを担う CSS を上書きさせています.

PlutoUI.jl について

PlutoUI.jl はノートブックユーザがスライダー,チェックボックス,ドロップダウンなどのUIを構成する部品(以下ではウィジェットと呼ぶ)を提供します.

上記の例はスライダーが一個しかないですが,

にて紹介されているように複数のウィジェットを組み合わせて作ることもできます.ササッと対話環境を作る分には PlutoUI.jl で十分ワークします.

他にも下記のような Julia パッケージがあり色々面白い UI をユーザに提供することができます.

@bind による Julia との連携

Pluto ノートブックの上でウィジェットの値と Julia の変数を結びつけるためにはセルに下記のような Julia のコードを挿入することになります.

@bind <Juliaの変数> <HTMLを返却・表示する関数呼び出し>

例えば下記の例は -4 から 4 の範囲を 0.1 刻みで動くスライダーを定義します.

# 事前に using PlutoUI を実行する
@bind x Slider(-4:0.1:4, defaut=2)

このようにすると初回の評価では xdefault で指定した 2 が格納されます.ノートブックユーザがマウスでグリグリ動かすと x の値はそれによって動きます.それによって x に依存している別のセルも自動的に実行・反映されます.Slider の実装は下記のリンクに対応します.

以下は物足りない人・オレオレ実装を作りたい人向け

Web 開発者カモン!

JavaScript によるウィジェットを作る能力を持つ読者が Julia に参入する余地は十分にあります.

開発者は h1, div, span, input のようなHTMLを含むソースコードを返す「関数を実装する」または・「表示する仕組みを持つ構造体」用意すればOKです.関数の実装は極端にシンプルな例は下記のような Julia の関数を実装することを指しています.

begin
    function myh1()
        return html"<h1>Hi myh1 function</h1>"
   end

   myh1()
end

html を文字リテラルの前につけることで HTML オブジェクトを作ります.

julia> html"Hi" |> typeof
HTML{String}

julia> (@html_str "Hi") |> typeof
HTML{String}

後者の表示する仕組みを作るというのは自作の構造体(MyType に対応)を用意し Base.show(io::IO, m::MIME"text/html", mytype::MyType) を実装することに対応します.

begin
    using HypertextLiteral: @htl
    struct MyType
        msg::String
    end
    
    function Base.show(io::IO, m::MIME"text/html", mytype::MyType)
        show(io, m, @htl "<h1>$(mytype.msg)</h1>")
    end

    mt = MyType("Hi, MyType")
end

実行した結果は次のとおりです.

image.png

ここで @htl マクロは "<h1>$(mytype.msg)</h1>" を適切に文字列補間するために用いています.この部分を仮に html"<h1>$(mytype.msg)</h1>" にするとドルマークを含めた $(mytype.msg) という文字列が大きいフォントで表示されます.@htl はこの問題を回避するために用いられます.

image.png

プラクティカルなパッケージの開発だと @htl マクロを使うことが多いです.PlutoUI.jl の実装を眺めてみるとわかります.

Julia と連携したい

@bind マクロを使うんでしたよね?

@bind x MyType("Hi, MyType")

image.png

連携してないじゃねーか!はい...もう少し実装を詳しく書く必要があります.x とHTML
を構成するどの要素の値と紐付けしなければいけないかを開発者は指定する必要があります.

begin
    struct MyType2
    end
    
    function Base.show(io::IO, m::MIME"text/html", mytype::MyType2)
		ret = @htl """
		<span>
			<script>
			  	const span = currentScript.parentElement;
			  	span.value = "AAA";
			</script>
		</span>
		"""
        show(io, m, ret)
    end
end

実行例は下記のようになります.

image.png

もう少しプラクティカルな例

CounterButton の実装がわかりやすいと思います.

上記の実装から HTML の要素を抜き出し整形をかけると次のようになります.<span>...</span> という構造を持つHTMLを表示させていることがわかりますね.

<span>
  <input type="button" value="$(button.label)">
  <script>
    let count = 0
  	const span = currentScript.parentElement
  	const button = span.firstElementChild
  	
  	span.value = count
  	
  	button.addEventListener("click", (e) => {
      	count += 1
      	span.value = count
      	span.dispatchEvent(new CustomEvent("input"))
      	e.stopPropagation()
  	})
  </script>
</span>

currentScript で上記の <script> 要素を指し parentElement<script> 要素の親 <span>...</span> としている span を指します.dispatchEvent, addEventListener を用いてイベントハンドラの設定をしています.span.value = count にあるように value に入っている値と @bind x <...> で指定した x が紐づきます.

ややごちゃごちゃしてます(自分がかなり誤魔化して書いてるのもありますが)が,なんとなく実装の方針は伝わったかなと思います.

ちょっと Julia に興味がある Web 開発者の参入お待ちしてます.

2
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
2
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?