block by shimizu 11bc492af4498c76aa7f

楽天カード明細ツリーマップ

Full Screen

楽天カードの明細csvを読み込んで当月請求額を基準としたツリーマップを表示します。

csvはアップロードされるわけでは無く、フロントエンド(ブラウザ)上だけで処理されますが、不安な方は自サーバーなどにindex.htmlをアップしてためしてみてください。

なお、Chromeでしか動作確認してません。

index.html

<!DOCTYPE html>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<title>楽天カードツリーマップ</title>
<style>
body {
	margin: auto;
	position: relative;
	padding: 20px;
	height: 100%;
}
 
form {
	position: absolute;
	right: 10px;
	top: 10px;
}
 
.node {
	border: solid 1px white;
	line-height: 0.95;
	overflow: hidden;
	position: absolute;
	border-radius: 6px;
	text-shadow: -1px -1px 2px hsla(0,0%,100%,0.25),
		-1px -1px 2px hsla(0,0%,100%,0.25),
		-1px 1px 2px hsla(0,0%,100%,0.25),
		1px -1px 2px hsla(0,0%,100%,0.25),
		-1px 0px 2px hsla(0,0%,100%,0.25),
		1px 0px 2px hsla(0,0%,100%,0.25);
}

.node div {
	padding: 6px 4%;
}

#fileBtn {
	margin-bottom: 8px;
}
</style>

<body>
<input id="fileBtn"  type="file">

<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<!-- by //polygon-planet-log.blogspot.jp/2012/04/javascript.html-->
<script src="//cdn.rawgit.com/shimizu/9873aaff4961cf3f149d/raw/da5939d7096addf2379a3c48c6cae5179c9b1686/encoding.min.js"></script>
<script>
var fileBtn = document.querySelector("#fileBtn");
fileBtn.addEventListener('change', upload, false);

function draw(data){

	var childrenData = data.map(function(d){
		return {name: d['利用店名・商品名'], value: +d['当月請求額']}
	});

	var dataSet = {
		name: "tree",
		children: childrenData
	};
	
	var width = 960-40,
    height = 500-40,
    color = d3.scale.category20c(),
    div = d3.select("body").append("div").style("position", "relative");

	var treemap = d3.layout.treemap()
		.size([width, height])
		.sticky(true)
		.value(function(d) { return d.value; });
	 
	var node = div.datum(dataSet).selectAll(".node")
			.data(treemap.nodes)
			.enter()
			.append("div")
			.attr("class", "node")
			.call(position)
			.style("background-color", function(d) {
				return d.name == 'tree' ? '#fff' : color(d.name); })
			.append('div')
			.style("font-size", function(d) {
				return Math.max(20, 0.18*Math.sqrt(d.area))+'px'; })
			.text(function(d) { return d.children ? null : d.name; });
	 
	function position() {
		this.style("left", function(d) { return d.x + "px"; })
			.style("top", function(d) { return d.y + "px"; })
			.style("width", function(d) { return Math.max(0, d.dx - 1) + "px"; })
			.style("height", function(d) { return Math.max(0, d.dy - 1) + "px"; });
	}
		
}

function upload(evt) {
	if (!isFileUpload()) {
		console.log('お使いのブラウザはファイルAPIがサポートされていません');
	} else {
		var data = null;
		var file = evt.target.files[0];
		var reader = new FileReader();
		reader.readAsBinaryString(file);
		reader.onload = function(event) {
			var result = event.target.result;
			var sjisArray = str2Array(result);
			var uniArray = Encoding.convert(sjisArray, 'UNICODE', 'SJIS');
			var csvStr = Encoding.codeToString(uniArray);
			draw(d3.csv.parse(csvStr));

		};
		reader.onerror = function() {
			console.log('ファイルが読み込めませんでした。 ' + file.fileName);
		};
	}
}

function isFileUpload() {
		var isCompatible = false;
		if (window.File && window.FileReader && window.FileList && window.Blob) {
			isCompatible = true;
		}
		return isCompatible;
}

function str2Array(str) {
	var array = [],i,il=str.length;
	for(i=0;i<il;i++) array.push(str.charCodeAt(i));
	return array;
}

</script>