vis-networkでscrapboxのネットワークを可視化する
やってみる
開発動機
仕様
URL parameter経由で任意のprojectのグラフを作れるようにする
preactとかは使わないで作れそう
execute script
2021-08-10 21:08:03 むりそう
CSPを設定すればrequst自体は通せるのだが、CORSに阻まれてresponseが帰ってこない ちなみにscrapbox.ioからgyazo.comへはrequestを通せる
回避策
自分のserverを経由させてfetchする
どうやらweb browser以外ならscrapboxのAPIをfetchできるようだ
非公開projectのAPIを叩きにくいのが面倒
cookie.sidをuserに手入力させないといけない
うーん、localhostだけで完結させたいので使いたくない……
ScrapboxのUserScriptとして実装する
これが一番早いと思います
code:sh
code:start.ts
const html = await (await fetch(new URL("index.html", import.meta.url))).text();
const js = await (await fetch(new URL("index.js", import.meta.url))).text();
const app = createApp();
app.handle("/", async (req) => {
await req.respond({
status: 200,
headers: new Headers({
"content-type": "text/html; charset=UTF-8",
"Content-Security-Policy": "script-src 'self' unpkg.com 'unsafe-eval'",
}),
body: html,
});
});
app.handle("/index.js", async (req) => {
await req.respond({
status: 200,
headers: new Headers({
"content-type": "application/javascript; charset=UTF-8",
"Content-Security-Policy": "connect-src scrapbox.io;",
}),
body: js,
});
});
const port = 8899;
app.listen({ port });
console.log(open http://localhost:${port});
↓CSPを設定していなかったのでうまく行かなかったshell script
code:sh
↑のcurlの時点でページが存在しないというエラーがでて、shell scriptを取得できない……
なんでだ?
base64でエンコードしたらdownloadできるようになった
前までは日本語でもいけたはずなんだけど……なんでだめになったんだろう?
code:start.sh
HTML
code:index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"></meta>
<title>My test page</title>
<script type="module" src="./index.js"></script>
<style>
height: 100%;
}
</style>
</head>
<body>
<div id="network"></div>
</body>
</html>
JS
URL parameterからscrapbox projectを取得する
code:index.js
const params = Object.fromEntries(
);
const project = params.project ?? 'help-jp';
code:index.js
async function fetchLinks(project) {
let followingId = null;
const linksData = [];
const promises = []; //処理待ち用
do {
const response = await (!followingId ?
fetch(https://scrapbox.io/api/pages/${project}/search/titles) :
fetch(https://scrapbox.io/api/pages/${project}/search/titles?followingId=${followingId})
)
followingId = response.headers.get('X-Following-Id');
promises.push(response.json().then(links => linksData.push(...links)));
} while(followingId);
// 全てのリンク情報を配列に格納し終わったら返す
await Promise.all(promises);
return linksData;
}
const links = await fetchLinks(project);
code:index.js
const nodes = new DataSet(
.map(title => ({id: title, label: title}))
);
const edges = new DataSet(
links.flatMap(
({title, links}) => links.map(link => ({from: title, to: link}))
)
);
// create a network
new Network(
document.getElementById("network"),
{
nodes,
edges,
},
{}
);