d3.js绘制多组heatmap

实现了根据图的总体宽度来采用横向展示和纵向展示,参数中的width,height属性是每个热图的格子的宽度、高度

实现如下效果:

多组heatmap

多组heatmap
一、json数据:
 

{

	"data": [
		[
			[-0.0282, 0.0545, 0.2327, 0.2276, 0.1717, -0.1646, -0.1646, -0.1646],
			[-0.0431, -0.0431, -0.0431, -0.0431, -0.0431, 0.0426, 0.1371, 0.0788],
			[-0.0775, -0.2289, -0.2802, -0.2255, 0.2543, -0.0343, -0.0745, 0.196],
			[-0.0775, -0.2289, -0.2802, -0.2255, 0.2543, -0.0343, -0.0745, 0.196],
			[-0.0775, -0.2289, -0.2802, -0.2255, 0.2543, -0.0343, -0.0745, 0.196],
			[-0.0775, -0.2289, -0.2802, -0.2255, 0.2543, -0.0343, -0.0745, 0.196],
			[-0.0775, -0.2289, -0.2802, -0.2255, 0.2543, -0.0343, -0.0745, 0.196]
		],
		[
			[-0.0282, 0.0545, 0.2327, 0.2276, 0.1717, -0.1646, -0.1646, -0.1646, -0.1646],
			[-0.0431, -0.0431, -0.0431, -0.0431, -0.0431, 0.0426, 0.1371, 0.0788, -0.0431],
			[-0.0775, -0.2289, -0.2802, -0.2255, 0.2543, -0.0343, -0.0745, 0.196, 0.4706],
			[-0.0775, -0.2289, -0.2802, -0.2255, 0.2543, -0.0343, -0.0745, 0.196, 0.4706],
			[-0.0775, -0.2289, -0.2802, -0.2255, 0.2543, -0.0343, -0.0745, 0.196, 0.4706],
			[-0.0775, -0.2289, -0.2802, -0.2255, 0.2543, -0.0343, -0.0745, 0.196, 0.4706],
			[-0.0775, -0.2289, -0.2802, -0.2255, 0.2543, -0.0343, -0.0745, 0.196, 0.4706]
		]
	],
	"params": {
		"title": "这个是热图的标题测试",
		"y_label": "Function",
		"x_label": "Species",
		"start_color": "#1d953f",
		"middle_color": "#130c0e",
		"end_color": "#ed1941",
		"show_gap": true,
		"show_label": true,
		"orient": "v",
		"rows": ["ko0001", "ko0002", "ko0003", "ko0004", "ko0005", "ko0006", "ko0007"],

		"columns": [
			["MJ1", "MJ2", "MJ3", "MJ4", "MJ5", "MJ6", "MJ7", "MJ8"],
			["MJ1", "MJ2", "MJ3", "MJ4", "MJ5", "MJ1e", "MJ7", "MJ8", "MJ9"]
		],
		"legend": [{
			"title": "Proteobacteria",
			"desc": "描述1"
		}, {
			"title": "Actinomycete",
			"desc": "描述1"
		}, {
			"title": "Firmicutes",
			"desc": "描述1"
		}],
		"legend_group_name": "Taxon"
	},
	"size": {
		"width": 50,
		"height": 30,
		"max_graph_width": 800
	}
}

参数说明:

  • 用途:热图(物种与功能贡献度分析Heatmap)(不需要指定的属性可以去掉)
  • *data,三维数组,按照组的方式进行绘制
  • title:标题
  • y_label:y轴标签
  • x_label:x轴标签
  • *start_color[初始颜色],end_color[结束颜色],middle_color[中间过度色,非必填]
  • show_gap:是否显示边框,默认false
  • show_label:是否显示数值标签,默认false
  • *rows:行的标签名称,一维数组
  • *columns:列的标签名称,二维数组
  • *legend:[title:分组的标题, desc:图例的细节描述]
  • legend_group_name:图例分组的title

以下为toolip的样式:

<style>
.heatmap_tooltip{  
    font-family:simsun;  
    font-size:13px;  
    width:120;  
    height:auto;  
    position:absolute;   
    text-align:left;  
    border-style:solid;  
    border-width:1px;  
    background-color:white;  
    border-radius:5px;    
}  
</style>


二、用到的js插件
#jquery插件

<script src="jquery-1.8.3.min.js"></script>
#d3 v3版本插件

<script src="d3-3.min.js"></script>
#图的实现文件
<script src="multi_heatmap.js"></script>

三、图形的调用
var content = $.parseJSON($('textarea').val()); //从textarea里面取出图的json数据并转化为object
graph.heatmap("container", content);   //把生成的图放在#container里面

四、以下为图的代码实现(D3.js实现)

/* globals jQuery: true, d3: true */
var graph = {
    /**渐变图例的比例尺,渐变图例的对象**/
    ingredient_legend_scale:null,
    legend_pointer:null,
    /**每组热图之间的间距**/
    heatmap_gap:10,
    /**分组的高度**/
    group_label_height:30,
    /**定义每一个文字的长度**/
    per_label_word_len : 6.15,
    margin : {
        
    },
    tooltip: null,
	heatmap:function(container, content)
	{
        var margin = {
            top:50,
            left:60,
            right:40,
            bottom:60,
        };

        var _margin = {
            top:50,
            left:60,
            right:40,
            bottom:60,
        };

        this.margin = margin;

        if (this.tooltip == null){
            this.tooltip = d3.select("body").append("div")  
                .attr("class","heatmap_tooltip") 
                .attr("opacity",0.0);
        }
        var column_lengths = new Array();

        for (var i in content.params.columns) {
            column_lengths.push(content.params.columns[i].length);
        }

        var rows_lengths = new Array();
        for (var i in content.params.rows) {
            rows_lengths.push(content.params.rows[i].length);
        }

        this.margin.left += d3.max(rows_lengths) * this.per_label_word_len;

        legend_word_lengths = new Array();
        for (var i in content.params.legend) {
            legend_word_lengths.push((content.params.legend[i].title+':'+content.params.legend[i].desc).length);
        }
        margin.right += d3.max(legend_word_lengths) * this.per_label_word_len;

        var width = margin.left + content.size.width * d3.sum(column_lengths) + (content.params.columns.length -1) * this.heatmap_gap + margin.right;
        var max_graph_width = typeof(content.size.max_graph_width) != 'undefined' ? content.size.max_graph_width : 800;

        console.log(_margin);
        this.margin = _margin;
        console.log(this.margin);
        if (width > max_graph_width) {
            this.hHeatmap(container, content);
        } else {
            this.vHeatmap(container, content);
        }

        return ;
        if (typeof(content.params.orient) == 'undefined' || content.params.orient == 'v') {
            this.vHeatmap(container, content);
        } else {
            this.hHeatmap(container, content);
        }
        
	},
    /**
     * 垂直热图
     *
     **/
    vHeatmap:function(container, content)
	{
        var graph_obj = this;

        /**获取列label的长度**/
        var column_lengths = new Array();
        var group_length = 0;

        /**获取每组热图的列的长度**/
        var column_length = 0;
        var column_group_lengths = new Array();

        for (var i in content.params.columns) {
            for (var j in content.params.columns[i]) {
                column_lengths.push(content.params.columns[i][j].length);
                column_length ++;
            }
            column_group_lengths.push(column_length);
            group_length ++;
        }


        graph_obj.margin.bottom += d3.max(column_lengths) * graph_obj.per_label_word_len;

        /**获取行label的长度**/
        var rows_lengths = new Array();
        for (var i in content.params.rows) {
            rows_lengths.push(content.params.rows[i].length);
        }

        graph_obj.margin.left += d3.max(rows_lengths) * graph_obj.per_label_word_len;


        var per_heatmap_height = content.size.height;
        var per_heatmap_width  = content.size.width;

        /**预留图例宽度**/
        legend_word_lengths = new Array();
        for (var i in content.params.legend) {
            legend_word_lengths.push((content.params.legend[i].title+':'+content.params.legend[i].desc).length);
        }
        graph_obj.margin.right += d3.max(legend_word_lengths) * graph_obj.per_label_word_len;


        var width = graph_obj.margin.left + per_heatmap_width * column_lengths.length + (group_length -1) * graph_obj.heatmap_gap + graph_obj.margin.right;

        /**绘制区域的热图高度**/
        var heatmap_height = per_heatmap_height * content.params.rows.length;

        


        var column_word_len = 0;

        var height = graph_obj.margin.top +graph_obj.group_label_height + heatmap_height + graph_obj.margin.bottom;


        /**获取value的最大值、最小值,颜色比例尺**/
        var min_values = [];
        var max_values = [];

        for (var i in content.data) {
            for (var j in content.data[i]) {
                min_values.push(d3.min(content.data[i][j]));
                max_values.push(d3.max(content.data[i][j]));
            }
            
        }

        var min_value = d3.min(min_values);
        var max_value = d3.max(max_values);

        if (typeof(content.params.middle_color) != 'undefined') {
        
            var color_scale = d3.scale.linear()
                .domain([min_value, (min_value+max_value)/2, max_value])
                .range([content.params.start_color, content.params.middle_color, content.params.end_color]);
        } else {
            var color_scale = d3.scale.linear()
                .domain([min_value, (min_value+max_value)/2, max_value])
                .range([content.params.start_color, content.params.end_color]);

        }

		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 title = typeof(content.params.title) != 'undefined' ? content.params.title : '';

        if (title) {
            var title_obj = svg.append('text').text(title).attr('y', 25).attr('x', function() {
                var text_length = this.getComputedTextLength();

                return (width - text_length)/2
            });
        }

        var y_label = typeof(content.params.y_label) != 'undefined' ? content.params.y_label : '';

        if (y_label) {
            svg.append('text').text(y_label).attr('y', function() {
                return height /2;
            }).attr('transform', function() {
                var text_length = this.getComputedTextLength();

                return "rotate(-90, 20, "+(height/2)+")";
            });
        }

        var x_label = typeof(content.params.x_label) != 'undefined' ? content.params.x_label : '';

        if (x_label) {
            svg.append('text').text(x_label).attr('y', function() {
                return height - 10;
            })
            .attr('x', function() {
                return (width - this.getComputedTextLength())/2;
            })
        }

        var area = svg.append('g').attr('class', 'area').attr('transform', function() {
            return 'translate('+graph_obj.margin.left+ ',' +graph_obj.margin.top+')';
        });

        
        var sub_titles = area.append('g').attr('class', 'sub_titles').attr('font-size', 13);
        sub_titles.selectAll('.sub_groups').data(content.data).enter()
            .append('g').attr('class', function(d, i) {
                return 'sub_groups sub_group'+i;
            })
            .attr('transform', function(d, i) {
                var sub_main_x = i > 0 ? column_group_lengths[i-1] * per_heatmap_width + i * graph_obj.heatmap_gap : 0;
                return "translate("+sub_main_x+")";
            })
            .each(function(d, i) {
                var self = d3.select(this);
                self.append('rect').attr('width', d[0].length * per_heatmap_width).attr('height', graph_obj.group_label_height).attr('fill', '#ccc').attr('stroke', '#555');
                self.append('text').text(content.params.legend[i].title).attr('transform', function() {
                    return "translate("+(d[0].length * per_heatmap_width - this.getComputedTextLength()) /2+", 18)";
                })
            });

        var main = area.append('g').attr('class', 'main').attr('transform',"translate(0, "+graph_obj.group_label_height+")");
        
        main.selectAll('.sub_main').data(content.data).enter()
            .append('g').attr('class', function(d, i) {
                return 'sub_main sub_main_'+i;
            })
            .attr('font-size', 11)
            .attr('transform', function(d, i) {
                var sub_main_x = i > 0 ? column_group_lengths[i-1] * per_heatmap_width + i * graph_obj.heatmap_gap : 0;
                return "translate("+sub_main_x+")";
            }).each(function(d, i) {
                var self = d3.select(this);
                self.append('rect').attr('width', content.params.columns[i].length * per_heatmap_width).attr('height', heatmap_height).attr('stroke', '#ccc').attr('fill', 'none');
                self.selectAll('.heatmap_groups').data(d).enter()
                    .append('g').attr('class', function(dd, ii) {
                        return "heatmap_groups heatmap_groups_"+ii;
                    })
                    .attr('transform', function(dd, ii) {
                        var per_group_y = per_heatmap_height * ii;
                        return "translate(0,"+per_group_y+")";
                    })
                    .each(function(dd, ii) {
                        var self = d3.select(this);
                        var hd   = self.selectAll('.h_d').data(dd).enter()
                            .append('g').attr('class', function(ddd, iii) {
                                return "h_d h_d_"+i+"_"+ii+"_"+iii;
                            })
                            .attr('transform', function(ddd, iii) {
                                var rect_x = per_heatmap_width * iii;
                                
                                return "translate("+rect_x+")";
                            })
                            .each(function(ddd, iii) {
                                var self = d3.select(this);
                                var rect = self.append('rect').attr('width', per_heatmap_width).attr('height', per_heatmap_height).attr('stroke-width', 0).attr('stroke', color_scale(ddd)).attr('fill', color_scale(ddd));
                                

                                if (typeof(content.params.show_gap) != 'undefined' && content.params.show_gap == true){
                                    rect.attr('stroke-width', 1).attr('stroke', '#000');
                                }
                                self.append('text').text(Math.round(ddd*10000)/10000).attr('x', function () {
                                    return per_heatmap_width /2 - this.getComputedTextLength()/2;
                                })
                                .attr('y', function() {
                                    return per_heatmap_height /2+5;
                                })
                            })
                            .attr('opacity', 0.9)
                            .on('mouseover', function(ddd, iii) {
                                var page_x     = d3.event.pageX;
					            var page_y     = d3.event.pageY+20;
                                var self = d3.select(this);
                                self.attr('opacity', 1);
                                var point_x = graph_obj.ingredient_legend_scale(ddd);
                                graph_obj.legend_pointer.attr('transform', "translate("+point_x+")").attr('fill-opacity', 1);
                                graph_obj.tooltip.html('<strong>column:</strong>'+content.params.rows[ii]+'</br> <strong>row:</strong>'+content.params.columns[i][iii]+'<br /><strong>value:</strong>'+ddd)  
                                .style("left",page_x+"px")  
                                .style("top",page_y+"px")  
                                .style("opacity",0.9)
                                .style('padding', '5px');
                            })
                            .on('mouseout', function() {
                                graph_obj.legend_pointer.attr('fill-opacity', 0);
                                var self = d3.select(this);
                                self.attr('opacity', 0.9);
                                graph_obj.tooltip.style('opacity', 0.0);
                            });;
                        
                    })
                /**定一个每一个组的x轴比例尺**/
                var xscale = d3.scale.linear()
                    .domain([0, content.params.columns[i].length-1])
                    .range([0, per_heatmap_width * d[0].length]);
                var xaxis = d3.svg.axis()
                    .scale(xscale)
                    .ticks(content.params.columns[i].length)
                    .tickFormat(function(d) {
                        return content.params.columns[i][d];
                    })
                    .orient('bottom');
                var xaxis_y = heatmap_height+4;
        
                var xaxis_obj = self.append('g').attr('class', 'xaxis_'+i)
                    .attr('font-size', 11)
                    .attr('text-anchor', 'start')
                    .attr('transform', "translate(0,"+xaxis_y+")")
                    .call(xaxis);
                xaxis_obj.selectAll('line').attr('fill', 'none').attr('stroke', '#000');
                xaxis_obj.select('.domain').attr('fill', 'none').attr('stroke', '#000');

                xaxis_obj.selectAll('.tick').each(function(iiii) {
                    var tick_x = (iiii) * per_heatmap_width +  per_heatmap_width /2;
                    d3.select(this).attr('transform',"translate("+tick_x+",0)");
                    d3.select(this).select('text').attr('transform', function() {
                        d3.select(this).attr('text-anchor', 'start');
                        return "rotate(90, 8,5) translate("+(this.getComputedTextLength()/2+16)+")";
                    });
                });

            })
        
        /**定义y比例尺**/
        var yscale = d3.scale.linear()
            .domain([0, content.params.rows.length -1])
            .range([heatmap_height, 0]);

        var yaxis = d3.svg.axis()
            .scale(yscale)
            .ticks(content.params.rows.length -1)
            .tickFormat(function(d) {
                return content.params.rows[d];
            })
            .orient('left');

        var yaxis_obj = main.append('g').attr('class', 'yaxis')
            .attr('font-size', 11)
            .attr('text-anchor', 'bottom')
            .call(yaxis);
 
        yaxis_obj.selectAll('line').attr('fill', 'none').attr('stroke', '#000');
        yaxis_obj.select('.domain').attr('fill', 'none').attr('stroke', '#000');

        yaxis_obj.selectAll('.tick').each(function(i) {
            var tick_y = per_heatmap_height * i + per_heatmap_height /2;
            d3.select(this).attr('transform',"translate(0,"+tick_y+")");
        });



        graph_obj.showLegend(svg, content, {min_value:min_value, max_value:max_value, width:width});
        /**------end---------**/
        
	},
    /**
     * 水平热图
     *
     **/
    hHeatmap:function(container, content)
	{
        var graph_obj = this;
		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"];

        /**获取列label的长度**/
        var column_lengths = new Array();
        var group_length = 0;

        /**获取每组热图的列的长度**/
        var column_length = 0;
        var column_group_lengths = new Array();

        for (var i in content.params.columns) {
            for (var j in content.params.columns[i]) {
                column_lengths.push(content.params.columns[i][j].length);
                column_length ++;
            }
            column_group_lengths.push(column_length);
            group_length ++;
        }

        graph_obj.margin.left += d3.max(column_lengths) * graph_obj.per_label_word_len;

        /**获取行label的长度**/
        var rows_lengths = new Array();
        for (var i in content.params.rows) {
            rows_lengths.push(content.params.rows[i].length);
        }

        graph_obj.margin.bottom += d3.max(rows_lengths) * graph_obj.per_label_word_len;

        var per_heatmap_height = content.size.height;
        var per_heatmap_width  = content.size.width;

        /**预留图例宽度**/

        legend_word_lengths = new Array();
        for (var i in content.params.legend) {
            legend_word_lengths.push((content.params.legend[i].title+':'+content.params.legend[i].desc).length);
        }
        graph_obj.margin.right += d3.max(legend_word_lengths) * graph_obj.per_label_word_len;


        var height = graph_obj.margin.top + per_heatmap_height * column_lengths.length + (group_length -1) * graph_obj.heatmap_gap + graph_obj.margin.bottom;

        /**绘制区域的热图高度**/
        var heatmap_height = per_heatmap_height * content.params.rows.length;

        var width = graph_obj.margin.left +graph_obj.group_label_height + per_heatmap_width * content.params.rows.length + graph_obj.margin.right;

        /**获取value的最大值、最小值,颜色比例尺**/
        var min_values = [];
        var max_values = [];

        for (var i in content.data) {
            for (var j in content.data[i]) {
                min_values.push(d3.min(content.data[i][j]));
                max_values.push(d3.max(content.data[i][j]));
            }
            
        }

        var min_value = d3.min(min_values);
        var max_value = d3.max(max_values);

        if (typeof(content.params.middle_color) != 'undefined') {
            var color_scale = d3.scale.linear()
                .domain([min_value, (min_value+max_value)/2, max_value])
                .range([content.params.start_color, content.params.middle_color, content.params.end_color]);
        } else {
            var color_scale = d3.scale.linear()
                .domain([min_value, (min_value+max_value)/2, max_value])
                .range([content.params.start_color, content.params.end_color]);

        }



		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 title = typeof(content.params.title) != 'undefined' ? content.params.title : '';

        if (title) {
            var title_obj = svg.append('text').text(title).attr('y', 25).attr('x', function() {
                var text_length = this.getComputedTextLength();

                return (width - text_length)/2
            });
        }

        var y_label = typeof(content.params.y_label) != 'undefined' ? content.params.y_label : '';

        if (y_label) {
            svg.append('text').text(y_label).attr('y', function() {
                return height - 10;
            })
            .attr('x', function() {
                return (width - this.getComputedTextLength())/2;
            })
        }

        var x_label = typeof(content.params.x_label) != 'undefined' ? content.params.x_label : '';

        if (x_label) {
            svg.append('text').text(x_label).attr('y', function() {
                return height /2;
            }).attr('transform', function() {
                var text_length = this.getComputedTextLength();

                return "rotate(-90, 20, "+(height/2)+")";
            });
        }

        var area = svg.append('g').attr('class', 'area').attr('transform', function() {
            return 'translate('+graph_obj.margin.left+ ',' +graph_obj.margin.top+')';
        });

        var sub_titles = area.append('g').attr('class', 'sub_titles').attr('font-size', 13);
        sub_titles.selectAll('.sub_groups').data(content.data).enter()
            .append('g').attr('class', function(d, i) {
                return 'sub_groups sub_group'+i;
            })
            .attr('transform', function(d, i) {
                var sub_title_x =  content.params.rows.length * per_heatmap_width;
                var sub_title_y =  i > 0 ? column_group_lengths[i-1] * per_heatmap_height + i * graph_obj.heatmap_gap: 0;
                return "translate("+sub_title_x+", "+sub_title_y+")";
            })
            .each(function(d, i) {
                var self = d3.select(this);
                self.append('rect').attr('width', graph_obj.group_label_height).attr('height', d[0].length * per_heatmap_height).attr('fill', '#ccc').attr('stroke', '#555');
                self.append('text').text(content.params.legend[i].title).attr('transform', function() {
                    return "translate(0,"+(d[0].length * per_heatmap_height - this.getComputedTextLength()) /2+")rotate(90,5,5)";
                })
            });

        var main = area.append('g').attr('class', 'main');

        main.selectAll('.sub_main').data(content.data).enter()
            .append('g').attr('class', function(d, i) {
                return 'sub_main sub_main_'+i;
            })
            .attr('font-size', 11)
            .attr('transform', function(d, i) {
                var sub_main_y = i > 0 ? column_group_lengths[i-1] * per_heatmap_height + i * graph_obj.heatmap_gap : 0;
                return "translate(0,"+sub_main_y+")";
            })
            .each(function(d, i) {
                var self = d3.select(this);
                self.selectAll('.heatmap_groups').data(d).enter()
                    .append('g').attr('class', function(dd, ii) {
                        return "heatmap_groups heatmap_groups_"+ii;
                    })
                    .attr('transform', function(dd, ii) {
                        var per_group_x = per_heatmap_width * ii;
                        return "translate("+per_group_x+")";
                    })
                    .each(function(dd, ii) {
                        var self = d3.select(this);
                        var hd   = self.selectAll('.h_d').data(dd).enter()
                            .append('g').attr('class', function(ddd, iii) {
                                return "h_d h_d_"+i+"_"+ii+"_"+iii;
                            })
                            .attr('transform', function(ddd, iii) {
                                var rect_y = per_heatmap_height * iii;
                                
                                return "translate(0,"+rect_y+")";
                            })
                            .each(function(ddd, iii) {
                                var self = d3.select(this);
                                var rect = self.append('rect').attr('width', per_heatmap_width).attr('height', per_heatmap_height).attr('stroke-width', 0).attr('stroke', color_scale(ddd)).attr('fill', color_scale(ddd));
                                    
                                if (typeof(content.params.show_gap) != 'undefined' && content.params.show_gap == true){
                                    rect.attr('stroke-width', 1).attr('stroke', '#000');
                                }
                                if (typeof(content.params.show_label) != 'undefined' && content.params.show_label == true) {
                                    self.append('text').text(Math.round(ddd*10000)/10000).attr('x', function () {
                                        return per_heatmap_width /2 - this.getComputedTextLength()/2;
                                    })
                                    .attr('y', function() {
                                        return per_heatmap_height /2+5;
                                    });
                                }
                            })
                            .attr('opacity', 0.9)
                            .on('mouseover', function(ddd, iii) {
                                var page_x     = d3.event.pageX;
					            var page_y     = d3.event.pageY+20;
                                
                                var self = d3.select(this);
                                self.attr('opacity', 1);
                                var point_x = graph_obj.ingredient_legend_scale(ddd);
                                graph_obj.legend_pointer.attr('transform', "translate("+point_x+")").attr('fill-opacity', 1);
                                
                                graph_obj.tooltip.html('<strong>column:</strong>'+content.params.rows[ii]+'</br> <strong>row:</strong>'+content.params.columns[i][iii]+'<br /><strong>value:</strong>'+ddd)  
                                .style("left",page_x+"px")  
                                .style("top",page_y+"px")  
                                .style("opacity",0.9)
                                .style('padding', '5px');
                            })
                            .on('mouseout', function() {
                                graph_obj.legend_pointer.attr('fill-opacity', 0);
                                var self = d3.select(this);
                                self.attr('opacity', 0.9);
                                graph_obj.tooltip.style('opacity', 0.0);
                            });
                    });
                var yscale = d3.scale.linear()
                    .domain([0, content.params.columns[i].length -1])
                    .range([per_heatmap_height * content.params.columns[i].length, 0]);
                var yaxis = d3.svg.axis()
                    .scale(yscale)
                    .ticks(content.params.columns[i].length -1)
                    .tickFormat(function(d) {
                        return content.params.columns[i][d];
                    })
                    .orient('left');

                var yaxis_obj = self.append('g').attr('class', 'yaxis')
                    .attr('font-size', 11)
                    .attr('text-anchor', 'bottom')
                    .call(yaxis);
                
                yaxis_obj.selectAll('line').attr('fill', 'none').attr('stroke', '#000');
                yaxis_obj.select('.domain').attr('fill', 'none').attr('stroke', '#000');

                yaxis_obj.selectAll('.tick').each(function(i) {
                    var tick_y = per_heatmap_height * i + per_heatmap_height /2;
                    d3.select(this).attr('transform',"translate(0,"+tick_y+")");
                });
            });

        /**定义x轴比例尺**/
        var xscale = d3.scale.linear()
            .domain([0, content.params.rows.length-1])
            .range([0, per_heatmap_width * content.params.rows.length]);
        var xaxis = d3.svg.axis()
            .scale(xscale)
            .ticks(content.params.rows.length)
            .tickFormat(function(d) {
                return content.params.rows[d];
            })
            .orient('bottom');
        var xaxis_y = height - graph_obj.margin.bottom - graph_obj.margin.top+5;

        var xaxis_obj = main.append('g').attr('class', 'xaxis_'+i)
            .attr('font-size', 11)
            .attr('text-anchor', 'start')
            .attr('transform', "translate(0,"+xaxis_y+")")
            .call(xaxis);

        xaxis_obj.selectAll('line').attr('fill', 'none').attr('stroke', '#000');
        xaxis_obj.select('.domain').attr('fill', 'none').attr('stroke', '#000');

        xaxis_obj.selectAll('.tick').each(function(iiii) {
            var tick_x = (iiii) * per_heatmap_width +  per_heatmap_width /2;
            d3.select(this).attr('transform',"translate("+tick_x+",0)");
            d3.select(this).select('text').attr('transform', function() {
                d3.select(this).attr('text-anchor', 'start');
                return "rotate(90, 8,5) translate("+(this.getComputedTextLength()/2+16)+")";
            });
        });

        this.showLegend(svg, content, {min_value:min_value, max_value:max_value, width:width});


        

        
        /**------end---------**/
        
	},
    showLegend(svg, content, other)
    {
        var graph_obj = this;
        /**图例**/
        var legend_obj = svg.append('g').attr('class', 'legends').attr('transform', 'translate('+(other.width - graph_obj.margin.right + 20)+', '+graph_obj.margin.top+')');

        var group_legend = legend_obj.append('g').attr('class','group_legend_title');
        group_legend.append('text').text(content.params.legend_group_name).attr('font-size', 12);
        group_legend.selectAll('.legend_titles').data(content.params.legend).enter()
            .append('g').attr('class', function(d, i) {
                return "legend_titles legend_title_"+i;
            })
            .attr('font-size', 10)
            .attr('transform', function(d, i) {
                return "translate(0,"+(20 * i + 20)+")";
            })
            .each(function(d, i) {
                var self = d3.select(this);
                self.append('text').text(d.title+': '+d.desc);
            })

        

        /**渐变图例**/

        function sprintf(text, arr) {
            var i = 0;
            return text.replace(/\$S/g, function () {
                return (i < arr.length) ? arr[i++] : "";
            });
        }

        var color_stops = [
          '<stop offset="0%" stop-color="$S"></stop>',
          '<stop offset="50%" stop-color="$S"></stop>',
          '<stop offset="100%" stop-color="$S"></stop>'
          ];
        if(typeof(content.params.middle_color) == 'undefined'){
            color_stops = [color_stops[0], color_stops[2]].join('');
            color_stops = sprintf(color_stops, [content.params.start_color, content.params.end_color]);
        }else{
            color_stops = sprintf(color_stops.join(''), [content.params.start_color, content.params.middle_color, content.params.end_color]);
        };

        var defs = svg.append('defs');

        /** 定义滤镜颜色**/
        defs.append('linearGradient')
          .attr({
            id: 'ingredient_legend',
            x1: "0%",
            y1: "0%",
            x2: "100%",
            y2: "0%"
          })
          .html(color_stops);

        /**定义滤镜上移动的箭头**/
        var nonius_scale = 6;
        var pointer = "M0 0 " +
            "L" + nonius_scale    + " " + -nonius_scale     + " " +
            "L" + nonius_scale    + " " + -2 * nonius_scale + " " +
            "L" + (-nonius_scale) + " " + -2 * nonius_scale + " " +
            "L" + (-nonius_scale) + " " + -nonius_scale     + " Z";

        var ingredient_legend_width = 60;
        var ingredient_legend_height = 17;
        var ingredient_legend_y = content.params.legend.length * 20 + 20;

        var ingredient_legend = legend_obj.append('g').attr('class', 'ingredient_legend').attr('transform', 'translate(0, '+(ingredient_legend_y)+')');

        
        ingredient_legend.append('rect').attr('width', ingredient_legend_width).attr('height', ingredient_legend_height).attr('fill', "url(#ingredient_legend)")
            .attr('shape-rendering','crispEdges');

        this.ingredient_legend_scale = d3.scale.linear()
            .domain([other.min_value, other.max_value])
            .range([0, ingredient_legend_width]);


        var ingredient_legend_axis = d3.svg.axis()
            .scale(this.ingredient_legend_scale)
            .ticks(5)
            .orient('bottom');

        var ingredient_legend_axis_obj = ingredient_legend.append('g').attr('class', 'legend_axis').attr('transform',"translate(0,"+ingredient_legend_height+")")
            .call(ingredient_legend_axis);


        ingredient_legend_axis_obj.selectAll('line').attr('fill', 'none').attr('stroke', '#000');
        ingredient_legend_axis_obj.select('.domain').attr('fill', 'none').attr('stroke', 'none');

        var tick_size = ingredient_legend.select('.legend_axis').selectAll('.tick').size();
        ingredient_legend.select('.legend_axis').selectAll('.tick').each(function(d, i) {
            if (i != 0 && i != tick_size -1) {
                d3.select(this).remove();
            }
            
        });

        this.legend_pointer = ingredient_legend.append("path")
        .attr({
            class: "legend-pointer",
            d: pointer,
            fill: "#33a3dc",
            "fill-opacity": 0
        });
    }
};

以上就是图的全部实现,如果有不清楚的地方可以留言,欢迎交流

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值