12. SVGとD3.js
https://www.youtube.com/watch?v=10jzXUePqSs
https://scrapbox.io/files/5f28bee7ed5bde001e8cfaf2.svg
SVGとは
Scalable Vector Graphics
2次元ベクターイメージ用の画像形式
XMLベース
アニメーション可能
ユーザインタラクション可能
ブラウザ上で表示可能
Standard Generalized Markup Language
文書のためのマークアップ言語
構造化テキスト
階層的
IBMが1980ごろ作成
HTMLの階層
https://gyazo.com/95841b7a0e0c166fb72d3b3a788d2e73
SGMLの例
code:sgml
<!DOCTYPE memo PUBLIC "-//SuzukiCorp//DTD Memo//JP">
<memo>
<from>木村
<to>富田様
<date>2001/10/01
<subject>役員会議
<para>役員会議の場所は会議室Bに変更になりました。
</memo>
SGMLの拡張
WWWで標準化
W3Cが開発
2000ごろから
XMLの例
code:xml
<レシピ 名前="パン" 準備時間="5分" 調理時間="3時間">
<料理>基本的なパン</料理>
<材料 量='3' 単位='カップ'>小麦粉</材料>
<材料 量='0.25' 単位='オンス'>イースト</材料>
<材料 量='1.5' 単位='カップ' 状態="温かい">水</材料>
<材料 量="1" 単位="ティースプーン">食塩</材料>
<要領>
<手順>全ての材料を一緒にして混ぜます。</手順>
<手順>十分にこねます。</手順>
<手順>布で覆い、暖かい部屋で1時間そのままにしておきます。</手順>
<手順>もう一度こねます。</手順>
<手順>パン焼きの容器に入れます</手順>
<手順>布で覆い、暖かい部屋で1時間そのままにしておきます。</手順>
<手順>オーブンに入れて温度を180℃にして30分間焼きます。</手順>
</要領>
</レシピ>
HTMLとXML
ともにSGMLの拡張
XML
ユーザが定義したタグを用いて文章構造を記述するマークアップ言語
データ交換のための汎用のデータ形式
HTML
Webページを記述するための言語
SVG (Scalable Vector Graphics)
ベクトル型式の描画システム
かなり昔からの標準化仕様
XMLの拡張
グラフィクスを宣言的に記述
ほとんどのブラウザで実装されている
<img>タグの中に書ける
Content-Type: image/svg+xml が必要
SVGの歴史
1999/2/11 SVGのドラフト版を公表
2001/9/4 SVG 1.0
2003/1/14 SVG 1.1, SVG Tiny・SVG Basic
2008/12/22 SVG Tiny 1.2
2011/8/16 SVG 1.1 (Second Edition)
2018/10/4 SVG 2
宣言的記述 vs 手続き的記述
宣言的記述
e.g. Excel
自動再計算
手続き的記述
e.g. 普通のプログラミング言語
〜を〜する
SVG情報
矩形描画
code:rect.svg
<rect x="5" y="5" width="70" height="40" fill="red" />
<rect x="15" y="15" width="70" height="40" fill="orange" />
<rect x="25" y="25" width="70" height="40" fill="yellow" />
</svg>
描画結果
http://gyazo.com/3ac4f9f16144b0fea50f9a67c322969e.png
線分描画
code:line.svg
<path d="M 100 100 L 300 100 L 200 300 z" fill="none" stroke="blue" stroke-width="3" />
<path d="M36,203L184,203L184,79L36,79" fill="none" stroke="red" stroke-width="3" />
</svg>
描画結果
http://gyazo.com/33d63493ee5dc57628610aa9e00a8e91.png
アニメーション
https://svg-hosting.vercel.app/scrapbox.io/villagepump/コードブロック記法に書いたsvgを表示する/animation.svg
画像表示の例
code:image.svg
viewBox="0 0 570 500" width="570" height="500">
x="0" y="0" width="570" height="500"
xlink:href="data:png;base64,iVBORw0KGgoAAAANSUhEUgAA...">
</image>
</svg>
画像の扱い
https://nextpublishing.jp/book/13148.html https://gyazo.com/7d442e5c7569b3f8e4454aa12d4c7c8a
一般的な描画システムとの違い
一般的な描画システム:
Canvas, OpenGL, X11, Quartz (Mac), PostScript, ...
指示通り順番に描画を行なっていく
線分を描く
矩形を描く
画面をクリヤ
SVGの利点
HTMLとの融合
SVG中にAタグなどを記述可能
アニメーション
インタラクション
宣言的記述
再描画不要
SVGの問題
インタラクションやアニメーションはオーバースペック
ScrapboxでSVGを表示する
SVGファイルをScrapboxにアップロード
SVG-hostingのような外部サービスを使う
[SVGテキストのURL] だけでは駄目
SVG-hosting
by @takker 氏
https://svg-hosting.vercel.app/api/svg?url=https://scrapbox.io/api/code/sfc-vis2021/12._SVG%E3%81%A8D3.js/test.svg
code:test.svg
<rect x="0" y="0" width="100" height="20" fill="#ff0" />
<polygon points="50 10, 70 30, 50 50, 30 30" fill="#f00" />
</svg>
SVGの活用
動的な画像生成
アニメーションするsparklines
D3.js (Data-Driven Documents) JavaScriptの情報視覚化システム
お絵描きライブラリとしても利用可能
SVGのDOMをビジュアライズ
SVG要素に値を関連づける
値をSVGの属性に反映させることにより再描画が行なわれる
Mike Bostock氏が開発
New York Timesで利用
2010からD3を作成/配付
http://gyazo.com/de8d809e2d27f77f76300a6d854fb322.png
Mike Bostock氏
http://gyazo.com/f72348e5c77e7e3f484b6537137d4c1e.png
Treemap, Sunburst, etc.
https://gyazo.com/0ce5bf9f70ca6f12d3946ef661ca30e2
Visualization of Scrapbox links
https://gyazo.com/750fcfca435be7c85e384ea47a7d9723
http://gyazo.com/78195b75ea63a1f901f4986d35e40be8.png
http://gyazo.com/8abce282d17e4875f6f389b4cf2abd91.png
http://gyazo.com/105523c43eea6892fba4a76694f5a5bc.png
D3.js references
https://gyazo.com/a3535d8eb76508fc60f8ab3e43092a21 https://shimz.me/blog/d3-js/5022
Video: Design is a search problem
https://www.youtube.com/watch?v=fThhbt23SGM
D3.jsを使ったお絵描きシステム
https://gyazo.com/6ab47e029ae216659a006578a433c065 http://www.pitecan.com/SDraw/sdraw.html
https://gyazo.com/4fd22526469208fb49d280edbc724f0a
一般的な描画システムとの違い
一般的な描画システム:
Canvas, OpenGL, X11, Quartz (Mac), PostScript, ...
指示通り順番に描画を行なっていく
線分を描く
矩形を描く
画面をクリヤ
SVGの利点
HTMLと融合させられる
SVG中にAタグなどを記述可能
Scrapbox上のD3プログラムを動かす
GitHubのD3実行環境
JSファイルを指定して実行
https://masui.github.io/rund3/?code=JSのURL
円グラフ
https://gyazo.com/18726f8b9d236749c38504e131def940
code:d3sample1.js
var canvas = d3.select("body")
.append("svg")
.attr("width", 500)
.attr("height", 500);
var g = canvas.append("g")
.attr("transform", "translate(300, 300)");
//var arc = d3.svg.arc()
var arc = d3.arc()
.innerRadius(130)
.outerRadius(200);
var pie = d3.pie()
.value(function(d) { return d; });
var arcs = g.selectAll(".arc")
.data(pie(data))
.enter()
.append("g")
.attr("class", "arc");
var color = d3.scaleOrdinal()
arcs.append("path")
.attr("d", arc)
.attr("fill", function (d) { return color(d.data); });
arcs.append("text")
.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
.attr("text-anchor", "middle")
.attr("text-size", "10px")
.text(function(d) { return d.data; });
棒グラフ
code:graph.js
// 1. データの準備
var dataset = [
{ "name": "A", "value": 5 },
{ "name": "B", "value": 6 },
{ "name": "C", "value": 8 },
{ "name": "D", "value": 1 },
{ "name": "E", "value": 2 },
{ "name": "F", "value": 6 },
{ "name": "G", "value": 8 },
{ "name": "H", "value": 6 },
{ "name": "I", "value": 10 },
{ "name": "J", "value": 9 }
]
var width = 400; // グラフの幅
var height = 300; // グラフの高さ
var padding = 30; // スケール表示用マージン
// 2. SVG領域の設定
var svg = d3.select("body").append("svg").attr("width", width).attr("height", height);
// 3. 軸スケールの設定
var xScale = d3.scaleBand()
.padding(0.1)
.domain(dataset.map(function(d) { return d.name; }));
var yScale = d3.scaleLinear()
// 4. 軸の表示
svg.append("g")
.attr("transform", "translate(" + 0 + "," + (height - padding) + ")")
.call(d3.axisBottom(xScale));
svg.append("g")
.attr("transform", "translate(" + padding + "," + 0 + ")")
.call(d3.axisLeft(yScale));
// 5. バーの表示
svg.append("g")
.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function(d) { return xScale(d.name); })
.attr("y", function(d) { return yScale(d.value); })
.attr("width", xScale.bandwidth())
.attr("height", function(d) { return height - padding - yScale(d.value); })
.attr("fill", "steelblue");
丸
https://gyazo.com/4e3437b060a422db4c9714414912a652
code:circles.js
var svg = d3.select("body").append("svg").attr("width", 500).attr("height", 100);
var circles = svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle");
circles.attr("cx", function(d, i) {
return (i * 50) + 25;
})
.attr("cy", 50)
.attr("r", function(d) {
return 5*d;
})
.attr("fill", "yellow")
.attr("stroke", "orange")
.attr("stroke-width", function(d) {
return d;
});
点プロット
https://gyazo.com/faadffbc4cbc90730a03ae98b59973ef
code:scatter.js
var svg = d3.select("body").append("svg").attr("width", 500).attr("height", 100);
var dataset =
[ 5, 20, 480, 90, 250, 50, 100, 33, 330, 95, svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) { return d0; }) .attr("cy", function(d) { return d1; }) .attr("r", 4);
Treemap
code:treemap.js
// 1. 描画用のデータ準備
var width = 800;
var height = 600;
var svg = d3.select("body").append("svg").attr("width", width).attr("height", height);
var data = {
"name": "A",
"children": [
{ "name": "B", "value": 25 },
{
"name": "C",
"children": [
{ "name": "D", "value": 10 },
{ "name": "E", "value": 15 },
{ "name": "F", "value": 10 }
]
},
{ "name": "G", "value": 15 },
{
"name": "H",
"children": [
{ "name": "I", "value": 20 },
{ "name": "J", "value": 10 }
]
},
{ "name": "K", "value": 10 }
]
};
// 2. 描画用のデータ変換
root = d3.hierarchy(data);
root
.sum(function(d) { return d.value; })
.sort(function(a, b) { return b.height - a.height || b.value - a.value; });
var treemap = d3.treemap()
.padding(1)
.round(true);
treemap(root);
// 3. svg要素の配置
var g = d3.select("svg")
.selectAll(".node")
.data(root.leaves())
.enter()
.append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + d.x0 + "," + (d.y0) + ")"; });
g.append("rect")
.style("width", function(d) { return d.x1 - d.x0; })
.style("height", function(d) { return d.y1 - d.y0; })
.style("fill", function(d) {
while(d.depth > 1) d = d.parent;
})
.style("opacity", 0.6)
g.append("text")
.attr("text-anchor", "start")
.attr("x", 5)
.attr("dy", 30)
.attr("font-size", "150%")
.attr("class", "node-label")
.text(function(d) { return d.data.name + " : " + d.value; });
棒グラフ
https://gyazo.com/fe5e995c565e222df21ab5f5bd84c73b
CSSも指定が必要
code:bar.css
div.bar {
display: inline-block;
width: 20px;
height: 75px;
background-color: teal;
}
code:bar.js
d3.select("body")
.selectAll("div")
.data(dataset)
.enter()
.append("div")
.attr("class", "bar")
.style("height", function(d) {
var barHeight = d * 5; // 高さを 5 倍にします
return barHeight + "px";
});