/* 変更可能な設定 - メニューとして表示したい名称 - 使いたい色リスト - valueNumの値をいくつかにグルーピング - 円の大きさの調整用 - 値と色を関連づける - 円の大きさと値を関連づける */ $(document).ready(function(){ var Eventer=function(){if(!(this instanceof Eventer))return new Eventer;this.publish=function(c,d){topics=b(c),topics.forEach(function(b){"object"==typeof a[b]&&a[b].forEach(function(a){a.apply(this,d||[])})})},this.subscribe=function(b,c){var d=[].concat(c);return d.forEach(function(c){a[b]||(a[b]=[]),a[b].push(c)}),[b,c]},this.unsubscribe=function(b,c){a[b]&&a[b].forEach(function(d,e){d==c&&a[b].splice(e,1)})},this.queue=function(){return a},this.on=this.subscribe,this.off=this.unsubscribe,this.trigger=this.publish;var a={},b=function(a){return"string"==typeof a?a.split(" "):a};return this}; var eventer = new Eventer; /* メニューとして表示したい名称 */ var varAll = "すべて"; //定性的データ var varString1 = "メーカー名"; var varString2 = "特徴";//aaaaa //定量的データ var varNum1 = "容量(g)"; var varNum2 = "エネルギー(kcal)"; var varNum3 = "1gあたりのエネルギー(kcal)";//aaaaa var kirikuchiLabel = [ varAll, varString1, varString2,//aaaaa varNum1, varNum2, varNum3//aaaaa ]; var keyString1, keyValue2; var varForColor; var labelsArray; //選択した項目の選択肢を表示を入れる入れ物。 /* 使いたい色リスト */ var colorArray = [ "#CA03B0", "#60B00A", "#AB1008", "#243753", "#D0ABE5", "#225232", "#F869B6", "#7E0B21", "#E96754" ]; /* valueNumの値をいくつかにグルーピング */ // varNum1 var lengthArray1 = [ {min: 80, max: 100}, {min: 101, max: 150}, {min: 151, max: 220} ]; // varNum2 var lengthArray2 = [ {min: 30, max: 90}, {min: 91, max: 120}, {min: 121, max: 150}, {min: 151, max: 180} ]; /* 円の大きさの調整用 */ var circleScale = 2; var Chart = function() { /* -------------------- 変数(データの入れ物)の設定 -------------------- */ var margin = 80; /* -------------------- 描画エリアの設定 -------------------- */ var width = 962 - margin * 2, height = 600 - margin * 2; var svg = d3.select('#content').append('svg') .attr('width', width + margin) .attr('height', height + margin); var dataContainer = svg.append("svg:g") .attr("id", "dataCircle") .attr('width', width + margin) .attr('height', height + margin) .attr('transform', 'translate(' + [margin/2, margin/2].join(',') + ')'); var peopleContainer = svg.append("svg:g") .attr("id", "peopleCircle") .attr('width', width + margin) .attr('height', height + margin) .attr('transform', 'translate(' + [margin/2, margin/2].join(',') + ')'); /* -------------------- スケールの設定 -------------------- */ var wScale = d3.scale.linear(); /* -------------------- イベントリスナー -------------------- */ var self = this; this.e = new Eventer; this.init = function() { this.e.subscribe( 'load', [this.getData] ); this.e.subscribe( 'load:data', [this.canvas.setup] ); this.e.subscribe( 'draw:menu', [this.drawMenu] ); this.e.subscribe( 'draw', [this.canvas.draw] ); this.e.publish( 'load' ); }; /* -------------------- 色んな機能 -------------------- */ //ボタンメニューの生成 this.drawMenu = function() { var menuItems = d3.select("#menuBlock").select('form').selectAll("span") .data( kirikuchiLabel ) .enter().append("span").attr("class", "navColumn"); menuItems.append("input") .attr({ type: "radio", class: "nav", name: "nav", value: function(d, i) {return i;} }) .attr('id', function(d, i) { return "id" + i; }) .attr('value', function(d, i) { return i; }) .property("checked", function(d, i) { if (i === 0) { return true; } else { return false; }; }) .on("change", function(d,i){ self.e.publish(['draw'], [self.data, {selected: i, value: this.value}]); }); menuItems.append("label") .attr('for', function(d, i) { return "id" + i; }) .text(function(d,i) { return d; }); } /* -------------------- データの取得 -------------------- */ this.getData = function() { d3.tsv('data.tsv', function(error, data){ //データ型を確定させる data.forEach(function(d){ d.valueString1 = String(d.valueString1); d.valueString2 = String(d.valueString2);//aaaaa d.valueNum1 = parseInt(d.valueNum1); d.valueNum2 = parseInt(d.valueNum2); }); self.data = data; self.e.publish('load:data', [data]); }); }; /* -------------------- データの描画 -------------------- */ this.canvas = { setup: function(data) { // force layoutの初期化 self.force = d3.layout.force().nodes(data); //定性的データに含まれるユニークな値を配列化する keyString1 = d3.set( data.map(function(d){ return d.valueString1 }) ).values(), options = keyString1.map(function(d) { return ''; }).join(''); keyString2 = d3.set( data.map(function(d){ return d.valueString2 }) ).values(), options = keyString2.map(function(d) { return '';//aaaaa }).join(''); /* 値と色を関連づける */ varForColor = keyString1; varForColor = keyString2;//aaaaa self.colors = {}; for(i = 0; i < varForColor.length; i++) { var key = varForColor[i]; self.colors[varForColor[i]] = [colorArray[i]].join(''); } self.e.publish('draw', [ data ]); self.e.publish('draw:menu'); self.e.publish('draw:emptyinfo'); }, draw: function(data, filter) { self.force .nodes(data) .charge(function(d){ return -d.valueNum1/2 }) .size([width, height / 2]) .on('tick', function(e){ var center = { x: width / 2, y: height / 2 + height / 4 }, centerx; self.data.forEach(function(o, i) { if((filter || {}).value) { switch (filter.selected){ case 0: labelsArray = [varAll]; centerx = 1; break; case 1: labelsArray = keyString1.slice(); var _l = keyString1.length; wScale.domain([0, _l]).range([0, 3]); for (var j=0; j<_l; j++) { if (o.valueString1 == keyString1[j]) { centerx = wScale(j); } }; break; case 2://aaaaa labelsArray = keyString2.slice(); var _l = keyString2.length; wScale.domain([0, _l]).range([0, 3]); for (var j=0; j<_l; j++) { if (o.valueString2 == keyString2[j]) { centerx = wScale(j); } }; break; case 3://aaaaa labelsArray.length=0; for (var i=0; i= parseInt(lengthArray1[j].min)) && (o.valueNum1 <= parseInt(lengthArray1[j].max))) { centerx = wScale(j); } }; break; case 4://aaaaa labelsArray.length=0; for (var i=0; i= parseInt(lengthArray2[j].min)) && (o.valueNum2 <= parseInt(lengthArray2[j].max))) { centerx = wScale(j); } }; break; } } else { labelsArray = [varAll]; centerx = 1; } o.x += (center.x * centerx - o.x) * e.alpha * 0.04; o.y += (center.y - o.y) * e.alpha * 0.04; }); d3.select("#labels").text( labelsArray.join(" - ") ); d3.selectAll('.peopleC').attr("transform", function(d) { return ['translate(', d.x, ', ', d.y, ')'].join(''); }); d3.selectAll('.dataC').attr("transform", function(d) { return ['translate(', d.x, ', ', d.y, ')'].join(''); }); }) .start(); /* 各円の中心にある白い円 */ var peopleCircles = peopleContainer.selectAll('.peopleC') .data(data) peopleCircles.enter() .append('circle') .attr('class', 'peopleC') .attr('r', 0) .attr('fill', "#FFF") .call( self.force.drag ) peopleCircles .transition() .duration(1100) .delay(function(d, i) { return i * 10; }) .attr('fill', "#FFF") .attr('r', 2); /* データによりサイズが変化する色のついた円 */ var dataCircles = dataContainer.selectAll('.dataC') .data(data) dataCircles.enter() .append('circle') .attr('class', 'dataC') .attr('r', 0) .attr('fill', function(d){ return "#FFFFFF"; }) .call( self.force.drag ) dataCircles .transition() .duration(1100) .delay(function(d, i) { return i * 10; }) /* 円を描画 */ .attr('fill', function(d){ return self.colors[d.valueString1]; }) .attr('fill', function(d){ return self.colors[d.valueString2]; })//aaaaa //円の大きさと値を関連づける .attr('r', function(d){ return Math.sqrt(d.valueNum1) * circleScale; }) //円の大きさと値を関連づける .attr('r', function(d){ var valueNum3 = d.valueNum2/d.valueNum1;//aaaaa return Math.sqrt(d.valueNum2) * circleScale; });//aaaaa dataCircles.on('mouseenter', function(d){ d3.select(this) .attr('class', 'dataC active') d3.select('#tooltip') .attr('class', 'active') .html([ '

', d.name, '

', '

', varString1 + ":", d.valueString1, '

', '

', varString2 + ":", d.valueString2, '

', '

', varNum1 + ":", d.valueNum1, '

', '

', varNum2 + ":", d.valueNum2, '

' ].join('')); }); dataCircles.on('mouseleave', function(d){ d3.select(this).attr('class', 'dataC') d3.select('#tooltip').attr('class', 'deactive'); }); } }; this.init.apply( this, arguments ); }; var chart = new Chart; });