generated at
ScrapCalc
( = % に変更しました)

Scrapboxのテキスト中の式を計算/表示できるようにしてみた。ショートカットキーを押すと [% 式] の中の式を順番に評価して計算結果を表示し、もう一度押すと元に戻る。式の中に % が有るときは式の評価だけ行ない結果は表示しない。

Ctrl-Cで表示をトグルしているところ

サンプル
家計簿
預金1 = 100万円, 預金2 = 200万円, 預金総額 = 預金1 + 預金2万円
簡単な計算
a = 10 b = 20 a \times b = a * b
\sqrt{2}= Math.sqrt(2)
\pi = Math.atan(1) * 4
レポート採点
成績評価 = function(平均){ return 平均 > 90 ? 'S' : 平均 > 80 ? 'A' : 平均 > 70 ? 'B' : 'C'};
山田: レポート1 = 90 レポート2 = 80 平均 = (レポート1+レポート2)/2 成績: 成績評価(平均)
佐藤: レポート1 = 70 レポート2 = 50 平均 = (レポート1+レポート2)/2 成績: 成績評価(平均)
年齢計算 (ちょっと辛い)
増井俊之Math.floor((((1900+(new Date).getYear())+("00"+((new Date).getMonth()+1)).substr(-2)+("00"+(new Date).getDate()).substr(-2))-19590711) / 10000)
グラフを描く
増井俊之 の体重
'I'.repeat(99.1) 2020/3/27 99.1
'I'.repeat(97.8) 2020/4/17 97.8
'I'.repeat(95.1) 2021/2/2 95.1
'I'.repeat(93.1) 2021/2/25 93.1
所要時間計算
仕事開始 = new Date('2021-03-16T09:10:00')
仕事終了 = new Date('2021-03-16T10:20:00')
仕事時間: (仕事終了 - 仕事開始) / (60 * 1000)
ワリカン計算
増井 = 2000円 (ビール)
山田 = 3000円 (ツマミ)
田中 = 0
平均 = (増井 + 山田 + 田中) / 3
増井支払い: -Math.floor(増井 - 平均)

導入
以下のUserCSSとUserScriptを自分のページに貼ると使える
ScrapScript
code:script.js import '/api/code/masui/ScrapCalc/script.js' code:style.css @import url("/api/code/masui/ScrapCalc/style.css");
コードを自分のページにコピーしてカスタマイズした方が良いかも

参考文献
ScrapCalcはBoomborg計算にインスパイヤされたものです
Jupyterにも少し似てるかも?

注意
変数名に日本語は使えますが 100円玉 みたいに数字ではじまる名前や記号を含む名前は使えません
JavaScriptで変数名として利用できる文字を使ってください
Ctrl-Cは良くないかも
WindowsやChromeOSでは困りそう
Scrapboxシステムが新しくなったわけではありません。UserScriptで無理矢理実現したものです。
(0,eval)(text) を実行すると strict が無効になる(globalで実行する)ようなのだが原理が不明
ここに説明がある

感想
無理矢理だけど動くところが興味深い
計算と考察を同時にできるのはとても大事
家計簿とか採点とかにすぐ使えるけど、思わぬ応用もあるかも
グラフも描きたくなったりして
p5.js で小さなキャンバス作って配置する?

style.css
.deco-\% { color: #111; background-color: #ffddff; padding: 0.1em 0.2em 0.1em 0.2em; } .scrapcalc_result { font-style:italic; font-weight:bold; background-color:yellow; }

script.js
function scrapcalc_exec(){ for(let e of document.querySelectorAll('.deco-\\%')){ let text = e.innerText; // 全角カギカッコを配列などで使えるようにする苦しい工夫 let expr = decodeURI(text).replaceAll('[','[').replaceAll(']',']') if(text.match(/=/)){ (0,eval)(expr); // 何故かこれでstrictが有効でなくなる? } else { let span = document.createElement('span'); span.classList.add("scrapcalc_result"); span.innerText = (0,eval)(expr); e.parentNode.appendChild(span) e.classList.add("scrapcalc_exp") e.style.display = 'none'; } } } function scrapcalc_reset(){ for(let e of document.querySelectorAll('.scrapcalc_result')){ e.remove(); } for(let e of document.querySelectorAll('.scrapcalc_exp')){ e.style.display = 'inline'; } } document.addEventListener('keydown', e => { if (e.key == 'c' && e.ctrlKey){ // Ctrl-Cで実行 if(document.querySelectorAll('.scrapcalc_result').length == 0){ scrapcalc_exec(); } else { scrapcalc_reset(); } } })