わいや。おっさんとはわいのことや。おっさんが言ったことの全てが間違っているとは思わんが確かに受け入れにくい"きもちわるさ"みたいなものを感じ取ったと思う。殺伐とした世の中で、そういう気持ちを忘れないで欲しい。そう思ってこの記事を書いたんだ。って前置きはそのぐらいにして今のとこ毎日書きまくってるな。書きなぐって丸めてぽいするブログみたいな感覚だ。マークダウンも##と```のハイライトしか使ってない。フォロワーが増えることはもうないと悟った。4記事目にして住人として世界の無常さを悟るが如く俺の書く記事ではフォロワーが増えないという事実の目の当たりにし愕然とした。希望などない。だから俺が希望になるよ。QIITAに変わるサービスを作ろうと思った。って前置きを入れて解説してくよ。
何作った
箇条書き。ってよく書くはずだ。学生でも社会人でも隣のおばちゃん家もそうさ。多分誰もが書く。1マス空けて。2マス開けて...それを樹形図に出来たら更に判りやすくなるんじゃねぇかな。って発想で作った。議事録もメモ程度なら箇条書きにする。するとこうなる...
縦に長くなる箇条書きより判りやすい
機能について
save tree imageを押せばSVG形式でダウンロードできる。
save indented textを押せばTXT形式でダウンロードできる。
木の高さも深さも調整可能だ。ドラッグでパンできてホイールでズームできる。
resize:bothしてあるおかげでウィンドウ自体も拡縮できる
ドッキングパネル化するフレームワークのおかげでエディタもビュアーも移動可能だ
利用しているライブラリ
入力/設定/出力とドッキングパネル化する (golden-layout)
テキストエリアをタブ入力可能にする (TabIndent.js)
ウィンドウのリサイズを検知する (resize-event)
箇条書きをjSON化する (indent2obj)
ソース
<!doctype html><html><head><title></title><metacharset='utf-8'><metacontent=''name='author'><metacontent=''name='application-name'><metacontent=''name='description'><metacontent='telephone=no,address=no,email=no,date=no,url=no'name='format-detection'><metacontent='noimageindex,notranslate,nosnippet,noarchive,nofollow,noindex'name='robots'><metacontent='width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no'name='viewport'><linkhref='js/jquery/golden-layout/theme/base.css'rel='stylesheet'><linkhref='asset/manifest.json'rel='manifest'><linkhref='asset/favicon.ico'rel='icon'><style>@font-face{font-family:'M+2VM+IPAG circle';src:url('asset/m+2vm+ipag-circle.ttf');}html,body{margin:0;width:100%;height:100%;font-size:12px;}/*
* 中央
*/main{top:50%;left:50%;position:absolute;transform:translate(-50%,-50%);}/*
* 背景
*/.lm_goldenlayout.lm_content{background:white;}/*
* 変更
*/main.wrap{width:80vw;height:80vh;resize:both;overflow:scroll;}/*
* 見栄
*/main.wrap{border-bottom:2pxsolidrgba(34,36,38,.15);box-shadow:rgba(16,36,94,0.4)02px6px0;}/*
* 設定
*/.proper.dg,.proper.dg.close-button{width:100%!important;}.proper.dg.main.close-button{display:none;}</style></head><body><main><divid='ui'class='wrap'></div></main></body></html><!-- native --><script src='js/native/d3-5.12.0.min.js'></script><script src='js/native/dat-gui/0.7.6.min.js'></script><script src='js/native/tab-indent-0.1.8.min.js'></script><script src='js/native/indent2obj-0.0.3.min.js'></script><!-- jquery --><script src='js/jquery/3.4.1.min.js'></script><script src='js/jquery/golden-layout/1.5.9.min.js'></script><script src='js/jquery/resize-event-1.2.1.min.js'></script><script>varapp={layout:{content:[{type:'row',content:[{width:29.3,type:'column',content:[{type:'component',componentName:'view',title:'editor'},{type:'component',componentName:'view',title:'proper'}]},{width:70.7,type:'stack',content:[{type:'component',componentName:'view',title:'viewer'}]}]}]},plugin:{editor:{elem:'<textarea></textarea>',option:{width:'100%',height:'100%',addClass:'tabIndent',css:{font:"12px 'M+2VM+IPAG circle",outline:'none',border:'none'}}},viewer:{elem:'<div></div>',option:{id:'svg',addClass:'tree',css:{background:'white'}}}},config:{save:function(){localStorage.setItem('tree',$editor.val())},download:function(){vardata=d3.select('svg').node().outerHTMLvarblob=newBlob([data])varlink=document.createElement("a")link.href=URL.createObjectURL(blob)link.download=newDate().toISOString()+'.svg'link.click()},height:0.3,width:11,}}var$ui=$('#ui')/*
* 最低限
*/vardat=newdat.GUI({autoPlace:false})vargolden=newGoldenLayout(app.layout,$ui)// GOLDENを初期化()すると呼び出されるDOM挿入先の$コンテナを準備golden.registerComponent('view',function(container,state){varkey=container._config.title,ele=container.getElement()ele.addClass(key)golden[key]=ele})/*
* 1.初期化
*/functioninit(){golden.init()}/*
* DOM生成
*/var$editor=$(app.plugin.editor.elem,app.plugin.editor.option),$viewer=$(app.plugin.viewer.elem,app.plugin.viewer.option),$proper=$(this.dat.domElement)$editor.on('keyup',function(){update()})/*
* 2.GOLDENにDOMを構築
*/functionconstruct(){// 生成したDOMを$コンテナに挿入golden['proper'].append($proper)golden['editor'].append($editor)golden['viewer'].append($viewer)}/*
* 3.ビュアーをセットアップ
*/functionsetup(){dat.add(app.config,'height').onChange(update).name('tree height')dat.add(app.config,'width').onChange(update).name('tree width')dat.add(app.config,'download').name('save tree image')dat.add(app.config,'save').name('save indented text')$(window).on('resize',function(){golden.updateSize()})$ui.onResize({},function(){golden.updateSize()})}/*
* ツリーはSVG
*/varview=d3.select($viewer.get(0)).append('svg')view.append('g')view.attr("xmlns","http://www.w3.org/2000/svg")view.append('style').text(`
circle
{
stroke-width:2px;
stroke:#05668D;
fill:white;
r:6;
}
text
{
font:12px 'M+2VM+IPAG circle';
}
rect
{
transform:translateY(-5px);
stroke:#0cf;
width:10px;
heiht:10px;
fill:white;
}
path
{
storke-width:2px;
stroke:#ccc;
fill:none;
}
`)functiongetLinks(arr){returnarr.enter().append('path').attr('d',d3.linkHorizontal().x(function(d){returnd.y}).y(function(d){returnd.x}))}functiongetNodes(arr){returnarr.enter().append('g').attr('class',function(d){return'node '+(d.children?'node--internal':'node--leaf')}).attr('transform',function(d){return"translate("+d.y+","+d.x+")";})}functionupdate(){varw=golden.viewer.width()varh=golden.viewer.height()view.attr('width',w).attr('height',h)varg=d3.select('svg > g')d3.select('svg > g').selectAll("*").remove()view.call(d3.zoom().on('zoom',function(){g.attr('transform',d3.event.transform)}))varvData=indent2obj($editor.val(),'\t')varvRoot=d3.hierarchy(vData[0]);varvNodes=vRoot.descendants();varvLayout=d3.tree().size([app.config.width*vNodes.reverse().length,app.config.height*h]);varvLinks=vLayout(vRoot).links();varmaxDepth=d3.max(vNodes,function(d){returnd.depth})varlinks=getLinks(g.selectAll('.link').data(vLinks))varnodes=getNodes(g.selectAll(".node").data(vNodes))nodes.append('circle')nodes.append('text').attr('dy','.35em').attr('x',function(d){returnd.children?-13:13;}).attr('text-anchor',function(d){returnd.children||d._children?'end':'start'}).text(function(d){returnd.data.name})}document.addEventListener('DOMContentLoaded',function(){init()construct()setup()if('tree'inlocalStorage){$editor.val(localStorage.getItem('tree'))update()}tabIndent.config.tab='\t';tabIndent.renderAll()})</script><style>@importurl('js/jquery/golden-layout/theme/light.css');@importurl('js/native/dat-gui/theme/light.min.css');</style/>
備考
ウィンドウの陰影が恰好よくねぇ?