ScrapCalc

ScrapCalc

( = % に変更しました)

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

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

サンプル
家計簿
預金1 = 100万円, 預金2 = 200万円, 預金総額 = 預金1 + 預金2万円
簡単な計算
a = 10 b = 20 = a * b
= Math.sqrt(2)
= 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
Copied!
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
Copied!
.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
Copied!
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();
}
}
})

Powered by Helpfeel