$(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 Chart = function() { /* ------------------------- メニューã¨ã—ã¦è¡¨ç¤ºã—ãŸã„å称 ------------------------- */ var varAll = "ã™ã¹ã¦"; //定性的データ var varString1 = "メーカーå"; var varString2 = "特徴"; //定é‡çš„データ var varNum1 = "容é‡(g)"; var varNum2 = "エãƒãƒ«ã‚®ãƒ¼(kcal)"; var varNum3 = "1gã‚ãŸã‚Šã‚¨ãƒãƒ«ã‚®ãƒ¼(kcal)"; //é…列化 var kirikuchiLabel = [ varAll, varString1, varString2, varNum1, varNum2, varNum3 ]; var circleScale = 20; 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} ]; // varNum3 var lengthArray3 = [ {min: 0.0, max: 0.4}, {min: 0.41, max: 0.80}, {min: 0.81, max: 1.00}, {min: 1.01, max: 1.50} ]; /* ------------------------- 変数ã®è¨å®š ------------------------- */ 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 coreContainer = svg.append("svg:g") .attr("id", "coreCircle") .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); 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 '<option>' + d + '</option>'; }).join(''); keyString2 = d3.set( data.map(function(d){ return d.valueString2 }) ).values(), options = keyString2.map(function(d) { return '<option>' + d + '</option>'; }).join(''); //値ã¨è‰²ã‚’関連ã¥ã‘ã‚‹ varForColor = keyString2; 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: 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: labelsArray.length=0; for (var i=0; i<lengthArray1.length; i++) { labelsArray[i] = lengthArray1[i].min + "〜" + lengthArray1[i].max; }; var _l = lengthArray1.length; wScale.domain([0, _l]).range([0, 3]); for (var j=0; j<_l; j++) { if ((o.valueNum1 >= parseInt(lengthArray1[j].min)) && (o.valueNum1 <= parseInt(lengthArray1[j].max))) { centerx = wScale(j); } }; break; case 4: labelsArray.length=0; for (var i=0; i<lengthArray2.length; i++) { labelsArray[i] = lengthArray2[i].min + "〜" + lengthArray2[i].max; }; var _l = lengthArray2.length; wScale.domain([0, _l]).range([0, 3]); for (var j=0; j<_l; j++) { if ((o.valueNum2 >= parseInt(lengthArray2[j].min)) && (o.valueNum2 <= parseInt(lengthArray2[j].max))) { centerx = wScale(j); } }; break; case 5: labelsArray.length=0; var valueNum3 = o.valueNum2/o.valueNum1; for (var i=0; i<lengthArray3.length; i++) { labelsArray[i] = lengthArray3[i].min + "〜" + lengthArray3[i].max; }; var _l = lengthArray3.length; wScale.domain([0, _l]).range([0, 3]); for (var j=0; j<_l; j++) { if ((valueNum3 >= parseFloat(lengthArray3[j].min)) && (valueNum3 <= parseFloat(lengthArray3[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('.coreC').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 coreCircles = coreContainer.selectAll('.coreC') .data(data) coreCircles.enter() .append('circle') .attr('class', 'coreC') .attr('r', 0) .attr('fill', "#FFF") .call( self.force.drag ) coreCircles .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.valueString2]; }) //円ã®å¤§ãã•ã¨å€¤ã‚’関連ã¥ã‘ã‚‹ .attr('r', function(d){ var valueNum3 = d.valueNum2/d.valueNum1; return valueNum3 * circleScale; }); dataCircles.on('mouseenter', function(d){ d3.select(this) .attr('class', 'dataC active') d3.select('#tooltip') .attr('class', 'active') .html([ '<p class="name">', d.name, '</p>', '<p class="valData">', varString1 + ":", d.valueString1, '</p>', '<p class="valData">', varString2 + ":", d.valueString2, '</p>', '<p class="valData">', varNum1 + ":", d.valueNum1, '</p>', '<p class="valData">', varNum2 + ":", d.valueNum2, '</p>', '<p class="valData">', varNum3 + ":", d.valueNum2/d.valueNum1, '</p>' ].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; });