实现如下效果:
一、json数据:
{
"data": [
[{
"name": "metabolic process",
"value": 3532
}, {
"name": "cellular process",
"value": 2814
}, {
"name": "single-organism process",
"value": 2082
}, {
"name": "localization",
"value": 963
}, {
"name": "biological regulation",
"value": 910
}, {
"name": "regulation of biological process",
"value": 817
}, {
"name": "cellular component organization or biogenesis",
"value": 704
}, {
"name": "response to stimulus",
"value": 492
}, {
"name": "signaling",
"value": 192
}, {
"name": "negative regulation of biological process",
"value": 190
}, {
"name": "multi-organism process",
"value": 165
}, {
"name": "positive regulation of biological process",
"value": 163
}, {
"name": "reproduction",
"value": 134
}, {
"name": "reproductive process",
"value": 133
}, {
"name": "developmental process",
"value": 103
}, {
"name": "detoxification",
"value": 34
}, {
"name": "growth",
"value": 27
}, {
"name": "multicellular organismal process",
"value": 20
}, {
"name": "biological adhesion",
"value": 6
}, {
"name": "immune system process",
"value": 2
}, {
"name": "locomotion",
"value": 2
}, {
"name": "cell killing",
"value": 1
}, {
"name": "biological phase",
"value": 1
}, {
"name": "cell aggregation",
"value": 1
}],
[{
"name": "cell",
"value": 2606
}, {
"name": "cell part",
"value": 2591
}, {
"name": "membrane",
"value": 2195
}, {
"name": "organelle",
"value": 2056
}, {
"name": "membrane part",
"value": 1934
}, {
"name": "organelle part",
"value": 1054
}, {
"name": "macromolecular complex",
"value": 962
}, {
"name": "membrane-enclosed lumen",
"value": 417
}, {
"name": "extracellular region",
"value": 69
}, {
"name": "supramolecular complex",
"value": 31
}, {
"name": "virion",
"value": 23
}, {
"name": "virion part",
"value": 23
}, {
"name": "nucleoid",
"value": 12
}, {
"name": "extracellular region part",
"value": 2
}],
[{
"name": "catalytic activity",
"value": 3101
}, {
"name": "binding",
"value": 2701
}, {
"name": "transporter activity",
"value": 367
}, {
"name": "nucleic acid binding transcription factor activity",
"value": 193
}, {
"name": "structural molecule activity",
"value": 144
}, {
"name": "molecular function regulator",
"value": 95
}, {
"name": "signal transducer activity",
"value": 37
}, {
"name": "transcription factor activity, protein binding",
"value": 35
}, {
"name": "antioxidant activity",
"value": 32
}, {
"name": "electron carrier activity",
"value": 26
}, {
"name": "molecular transducer activity",
"value": 18
}, {
"name": "metallochaperone activity",
"value": 3
}, {
"name": "nutrient reservoir activity",
"value": 2
}, {
"name": "translation regulator activity",
"value": 2
}, {
"name": "protein tag",
"value": 2
}]
],
"size": {
"width": 960,
"height": 900
},
"params": {
"width": 300,
"title": "GO Classification",
"sub_title": ["BP", "CC", "MF"],
"show_label": false
}
}
二、用到的js插件
#jquery插件
<script src="jquery-1.8.3.min.js"></script>
#d3 v3版本插件
<script src="d3-3.min.js"></script>
#多维饼图的实现文件
<script src="multipie.js"></script>
三、多维饼图的调用
var content = $.parseJSON($('textarea').val()); //从textarea里面取出多维饼图的json数据并转化为object
graph.multiPie("container", content); //把生成的饼图放在#container里面
四、以下为多维饼图的代码实现(D3.js实现)
/* globals jQuery: true, d3: true */
var graph = {
multiPie:function(container, content)
{
//此处也可以用d3自带的颜色生成器
var colors = ["#388E3C", "#F44336", "#0288D1", "#FF9800", "#727272", "#E91E63", "#673AB7", "#8BC34A", "#2196F3", "#D32F2F", "#FFC107", "#BDBDBD", "#F8BBD0", "#3F51B5", "#CDDC39", "#009688", "#C2185B", "#FFEB3B", "#212121", "#FFCCBC", "#BBDEFB", "#0099CC", "#FFcc99"];
var pie_width = content.params.width;
var pie_height = content.params.width;
var margin = {
top:50,
left:30,
right:30,
bottom:20,
};
var lengths = [];
var group_lengths = [];
for (var i in content.data) {
lengths.push(content.data[i].length);
if (lengths.length == 3) {
group_lengths.push(d3.max(lengths));
lengths = [];
}
}
if (lengths.length > 0) {
group_lengths.push(d3.max(lengths));
lengths = [];
}
console.log(group_lengths);
var width = pie_width * content.data.length + margin.left+margin.right;
var height = 0;
var per_group_y = [0];
for (var i in group_lengths) {
var legend_min_height = group_lengths[i] <= 2 ? group_lengths[i] * 7 : 0;
height += pie_height + group_lengths[i] * 22 + legend_min_height;
per_group_y.push(height);
}
height += margin.top;
console.log(per_group_y);
var svg = d3.select('#'+container).append('svg')
.attr('version', '1.1')
.attr('style', 'font-family:arial')
.attr('xmlns', 'http://www.w3.org/2000/svg')
.attr('width', width)
.attr('height', height);
var word_len = 22;
svg.append('text').text(content.params.title).attr('x', (width - word_len * content.params.title.length)/2).attr('y', 20).attr('font-size', '20px');
var main_group = svg.append('g').attr('class', 'main_group').attr('transform', "translate("+margin.left+","+margin.top+")");
var min_size = d3.min([content.params.width, content.params.height]);
// 得到饼图的比例计算
var pie = d3.layout.pie()
.sort(null)
.value(function(d) {
return d.value;
});
// 计算弧形路径
// 根据画布大小算一个合适的半径
var radius = pie_width *0.8/2;
var arc = d3.svg.arc()
.innerRadius(5)
.outerRadius(radius)
var arc_text = d3.svg.arc()
.innerRadius(5)
.outerRadius(radius * 2.2);
var word_len = 11;
for (var key in content.data){
var main_x = parseInt(key) %3 * pie_width;
var main_y = per_group_y[Math.floor(parseInt(key) / 3)];
var main = main_group.append('g').attr('class', 'g'+key).attr('transform', "translate("+main_x+", "+(main_y)+")").attr('class', 'main_'+key);
var sub_obj = main.append('g').attr('class', 'sub_'+key).attr('transform', "translate(0, 20)");
main.append('text').text(content.params.sub_title[key]).attr('x', (pie_width - word_len * content.params.sub_title[key].length)/2).attr('y', 15).attr('style', 'font-size:12px');
var sub_x = (pie_width/2);
var sub_y = min_size/2;
var sub_main = sub_obj.append('g').attr('transform', "translate("+sub_x+", "+sub_y+")").attr('class', 'sub_main_'+key);
var content_data = content.data[key];
var pie_data = pie(content_data);
//添加弧形
var pie_path = sub_main.selectAll('g')
.data(pie_data)
.enter()
.append('path')
.attr('fill', function(d, i) {
return colors[i%colors.length];
})
.attr('d', function(d) {
return arc(d);
})
.attr('path', key)
.attr('class', function(d, i) {
return 'path_'+i;
});
pie_path.on('mouseover', function(d,i) {
var key = d3.select(this).attr('path');
d3.select(this).attr('stroke', '#000');
if (typeof(content.params.show_label) != 'undefined' && content.params.show_label === false) {
d3.select('.main_'+key).select('.sub_main_'+key).select('.sub_text_'+i).attr('opacity', 1.0);
}
d3.select('.main_'+key).select('.sub_legend_'+key).select('.legend_'+i).select('text').attr('fill', colors[i%colors.length]).attr('style', 'font-weight:bold');
})
.on('mouseout', function(d,i) {
var key = d3.select(this).attr('path');
d3.select(this).attr('stroke', '');
if (typeof(content.params.show_label) != 'undefined' && content.params.show_label === false) {
d3.select('.main_'+key).select('.sub_main_'+key).select('.sub_text_'+i).attr('opacity', 0.0);
}
d3.select('.main_'+key).select('.sub_legend_'+key).select('.legend_'+i).select('text').attr('fill', '#000').attr('style', 'font-weight:normal');
});
var text_obj = sub_main.append('g').attr('class', 'sub_label_'+key);
var texts = text_obj.selectAll('.texts'+key)
.data(pie_data)
.enter()
.append('text')
.attr('class', function(d, i) {
return 'texts'+key+' '+ 'sub_text_'+i;
})
.attr('transform', function(d) {
return "translate("+arc_text.centroid(d)+")";
})
.attr('text-anchor', function(d) {
if ((d.startAngle +d.endAngle) / 2 < Math.PI) {
return "beginning";
} else {
return "end";
}
})
.attr('font-size', '10px')
.text(function(d) {
return d.data.value;
});
if (typeof(content.params.show_label) != 'undefined' && content.params.show_label === false) {
texts.attr('opacity', 0);
}
var legend_obj = sub_obj.append('g').attr('transform', 'translate('+(pie_width/5)+','+(pie_width)+')').attr('class', 'sub_legend_'+key);
legend_obj.selectAll('.legend')
.data(pie_data)
.enter()
.append('g')
.attr('class', function(d, i) {
return "legend legend_"+i;
})
.attr('transform', function(d, i) {
return "translate(0, "+(i * 20)+")";
})
.attr('path', key)
.each(function(d, i) {
var self = d3.select(this);
self.append('circle')
.attr('cx', 0)
.attr('cy', 0)
.attr('r', 5)
.attr('fill', colors[i%colors.length]);
self.append('text')
.text(d.data.name)
.attr('font-size', '10')
.attr('text-anchor', 'start')
.attr('transform', "translate(10, 4)")
.attr('cursor', 'pointer')
})
.on('mouseover', function(d, i) {
var self = d3.select(this);
var key = self.attr('path');
d3.select('.main_'+key).select('.sub_main_'+key).select('.path_'+i).attr('stroke', '#000');
self.select('text').attr('fill', colors[i % colors.length])
.attr('style', 'font-weight:bold');
if (typeof(content.params.show_label) != 'undefined' && content.params.show_label === false) {
d3.select('.main_'+key).select('.sub_main_'+key).select('.sub_text_'+i).attr('opacity', 1);
}
})
.on('mouseout', function(d, i) {
var self = d3.select(this);
var key = self.attr('path');
d3.select('.main_'+key).select('.sub_main_'+key).select('.path_'+i).attr('stroke', '');
self.select('text').attr('fill', '#000')
.attr('style', 'font-weight:normal');
if (typeof(content.params.show_label) != 'undefined' && content.params.show_label === false) {
d3.select('.main_'+key).select('.sub_main_'+key).select('.sub_text_'+i).attr('opacity', 0.0);
}
});;
}
}
};
以上就是多维饼图的全部实现,如果有不清楚的地方可以留言,欢迎交流