用d3.js+svg绘制房间人数热力图

  • Post author:
  • Post category:其他


根据数据表格绘制热力图是d3.js的拿手好戏。

本文用存放在csv文件中的表格数据,绘制各个房间内人数的热力图

图形效果如下:

在这里插入图片描述

数据文件内容:

personNumber.csv

name,room1,room2,room3,room4,room5,room6,room7,room8,room9,room10,room11,room12,room13,room14,room15,room16,room17,room18,room19,room20
楼层1,9,39,30,11,22,0,8,10,1,1,4,0,1,4,5,8,2,1,3,2
楼层2,81,38,28,10,20,0,7,9,1,2,5,0,1,6,8,7,2,1,3,2
楼层3,2,36,27,10,21,0,6,7,1,1,4,0,1,4,5,5,2,1,3,2
楼层4,1,38,26,10,20,0,6,7,1,1,2,0,1,7,8,2,1,1,2,2
楼层5,6,36,26,9,19,0,6,7,1,3,7,0,1,4,5,3,1,1,3,3
楼层6,74,39,25,9,19,0,6,7,1,1,3,0,1,6,7,3,1,1,3,2

html文件内容

index.html

<!DOCTYPE html>
<meta charset="utf-8">
<html>
  <head>
    <title>房间人数热力图</title>
    <style>
      rect.bordered {
        stroke: #A1A1A1;
        stroke-width:1px;  
      }

      text.mono {
        font-size: 6pt;
        font-family: Consolas, courier;
        fill: #000;
      }

      text.axis-workweek {
        fill: #00FF;
      }

      text.axis-worktime {
        fill: #ff00;
      }
    </style>
    
    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>  

  </head>
  
  
  <body>

    <div id="roomHeatMap"></div>      
   
    <script type="text/javascript">
    
      // 定义Heatmap的位置、宽高、房间格子的边长等等与布局有关的变量
      var margin = { top: 50, right: 0, bottom: 100, left: 150 },
          
          width = 1300 - margin.left - margin.right,        // Heatmap的宽度
          height = 600 - margin.top - margin.bottom,
          
          gridSize = Math.floor(width / 20),    // 房间格子大小,即去掉小数部分,width分成20份
          gridInnerSize=gridSize-10,

          legendElementWidth = gridSize * 2,    // 下部图例格子的长度,是房间格子边长的两倍
          
          buckets = 9,        // 一共9种颜色级别
          colors = ["#ffffd9","#edf8b1","#c7e9b4","#7fcdbb","#41b6c4","#1d91c0","#225ea8","#253494","#081d58"], 
          
          rooms = ["房间1","房间2","房间3","房间4","房间5","房间6","房间7","房间8","房间9","房间10","房间11","房间12","房间13","房间14","房间15","房间16","房间17","房间18","房间19","房间20"];

                
          // 读取 CSV 文件,房间内的人数存放于此文件中
          d3.csv("personNumber.csv",              
            
            function(error, data) {                
              // console.log(data);

              
              // 设置roomHeatMap,svg
              var svg = d3.select("#roomHeatMap").append("svg") // 选择“roomHeatMap”(就是div),加入一个svg,设置属性跟div一样大
                  .attr("width", width + margin.left + margin.right)
                  .attr("height", height + margin.top + margin.bottom)
                  .append("g")    // 在svg内加入一个g(group组),并设置元素g的显示位置
                  .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
                
              // 行标题
              var dayLabels = svg.selectAll(".nameLabel")
                  .data(data)
                  .enter()    // 为data中每一项创建一个".dayLabel"
                  .append("text")    // 为days中每一项创建一的".dayLabel"添加文本,下面全是设置文本的属性
                    .text(function (d, i) { return data[i].name; })
                    .attr("x", 0)
                    .attr("y", function (d, i) { return i * (gridSize+20)-10; })
                    .style("text-anchor", "end")
                    .attr("transform", "translate(-6," + gridSize / 1.5 + ")")
                    .attr("class", function (d, i) 
                            { return ((i >= 0 && i <= 4) ? "nameLabel mono axis axis-workweek" : "nameLabel mono axis"); }
                        );
     
              // 列标题
              var timeLabels = svg.selectAll(".testLabel")
                  .data(rooms)
                  .enter().append("text")
                    .text(function(d) { return d; })
                    .attr("x", function(d, i) { return i * gridSize+10; })
                    .attr("y", 0)
                    .style("text-anchor", "end")
                    .attr("transform", "translate(" + gridSize / 2 + ", -6)")
                    .attr("class", function(d, i) { 
                            return ( "testLabel mono axis"); }
                         );
              
                // 网格数组,这里将二维数据转换为一维数组,一维数组方便于d3.js绑定
                var personCountArray=[];
                for (var i = 0; i < 6; i++){
                    personCountArray[i*20] =   parseInt(data[i].room1);
                    personCountArray[i*20+1] = parseInt(data[i].room2);
                    personCountArray[i*20+2] = parseInt(data[i].room3);
                    personCountArray[i*20+3] = parseInt(data[i].room4);
                    personCountArray[i*20+4] = parseInt(data[i].room5);
                    personCountArray[i*20+5] = parseInt(data[i].room6);
                    personCountArray[i*20+6] = parseInt(data[i].room7);
                    personCountArray[i*20+7] = parseInt(data[i].room8);
                    personCountArray[i*20+8] = parseInt(data[i].room9);
                    personCountArray[i*20+9] = parseInt(data[i].room10);
                    personCountArray[i*20+10] = parseInt(data[i].room11);
                    personCountArray[i*20+11] = parseInt(data[i].room12);
                    personCountArray[i*20+12] = parseInt(data[i].room13);
                    personCountArray[i*20+13] = parseInt(data[i].room14);
                    personCountArray[i*20+14] = parseInt(data[i].room15);
                    personCountArray[i*20+15] = parseInt(data[i].room16);
                    personCountArray[i*20+16] = parseInt(data[i].room17);
                    personCountArray[i*20+17] = parseInt(data[i].room18);
                    personCountArray[i*20+18] = parseInt(data[i].room19);
                    personCountArray[i*20+19] = parseInt(data[i].room20);
              }
              
              //绘制房间格子,一开始全部是白色
              var heatMap = svg.selectAll(".personNumber")
                  .data(personCountArray)
                  .enter()        
                  .append("rect")
                  .attr("x", function(d, i){ return (i % 20)*gridSize;})
                  .attr("y", function(d, i){ return parseInt(i / 20)*(gridSize+20);})
                  .attr("rx", 6)
                  .attr("ry", 6)
                  .attr("class", "bordered")
                  .attr("width", gridInnerSize)
                  .attr("height", gridInnerSize)
                  .style("fill", "#FFFFFF");

              // 颜色比例尺
              var colorScale = d3.scale.quantile()        // 按分位数取值,可使每个区域内元素个数相等
                  .domain([0, buckets - 1, d3.max(personCountArray)])  // 定义域
                  // domain([0, n, 数据的最大值]);
                  .range(colors);    // 值域:是颜色数组,函数的返回值是代表某种颜色的字符串
                
              // duration(n) 在n毫秒内根据房间内人数为房间格子上色
              heatMap.transition().duration(2000)
                  .style("fill", function(d) { return colorScale(d); });
                
              // 鼠标停留在房间格子上时显示人数
              heatMap.append("title").text(function(d) { return "房间内有 "+d+" 人"; });
                  
              
              // 图例
              var legend = svg.selectAll(".legend")
                  //[0].concat(colorScale.quantiles())将数组[0]与含有8个元素的olorScale.quantiles()连接起来得到一个有9个元素的数组
                  .data([0].concat(colorScale.quantiles()), function(d) {
                   return d;
                    })    
                  .enter().append("g")
                  .attr("class", "legend");
    
              legend.append("rect")
                .attr("x", function(d, i) { return legendElementWidth * i; })
                .attr("y", height+gridSize)
                .attr("width", legendElementWidth)
                .attr("height", gridSize/2)
                .style("fill", function(d, i) { return colors[i]; });
    
              legend.append("text")
                .attr("class", "mono")
                .text(function(d) { 
                  return ""+Math.round(d)+"人以上";
                   })
                .attr("x", function(d, i) { return legendElementWidth * i+20; })
                .attr("y", height +gridSize+40);
          });
    </script>
  
  </body>
</html>



版权声明:本文为littlezhuhui原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。