如何根据对象字典进行d3.js渲染

时间:2015-09-14 04:54:04

标签: javascript jquery html json d3.js

我有以下工作JavaScript。它的作用是取mydata的成员并将热图制作出来。

样本

 
 mydata={
      // full data can be found here    
      // http://dpaste.com/1TZP3AJ.txt
      "data1":[ {"timestamp": "2014-09-25T00:00:00", "value": {"PM2.5": 330.22}}, 
                {"timestamp": "2014-09-25T01:00:00", "value": {"PM2.5": 41.61}},
                {"timestamp": "2014-09-25T02:00:00", "value": {"PM2.5": 50.71}},
                {"timestamp": "2014-09-25T03:00:00", "value": {"PM2.5": 57.34}},
                {"timestamp": "2014-09-25T04:00:00", "value": {"PM2.5": 79.64}},
                {"timestamp": "2014-09-25T05:00:00", "value": {"PM2.5": 76.93}},
                {"timestamp": "2014-10-16T23:00:00", "value": {"PM2.5": 64.39}}],

      "data2":[ {"timestamp": "2014-09-25T00:00:00", "value": {"PM2.5": 0.22}}, 
                {"timestamp": "2014-09-25T01:00:00", "value": {"PM2.5": 4.1}},
                {"timestamp": "2014-09-25T02:00:00", "value": {"PM2.5": 5.71}},
                {"timestamp": "2014-09-25T03:00:00", "value": {"PM2.5": 257.34}},
                {"timestamp": "2014-09-25T04:00:00", "value": {"PM2.5": 9.64}},
                {"timestamp": "2014-09-25T05:00:00", "value": {"PM2.5": 6.3}},
                {"timestamp": "2014-10-16T23:00:00", "value": {"PM2.5": 64.39}}]
    }

    jQuery(function($){
      //console.log("HERE")
      //UI configuration
      var itemSize = 18,
        cellSize = itemSize-1,
        width = 800,
        height = 800,
        margin = {top:20,right:20,bottom:20,left:25};

      //formats
      var hourFormat = d3.time.format('%H'),
        dayFormat = d3.time.format('%j'),
        timeFormat = d3.time.format('%Y-%m-%dT%X'),
        monthDayFormat = d3.time.format('%m.%d');

      //data vars for rendering
      var dateExtent = null,
        data = null,
        dayOffset = 0,
        colorCalibration = ['#f6faaa','#FEE08B','#FDAE61','#F46D43','#D53E4F','#9E0142'],
        dailyValueExtent = {};

      //axises and scales
      var axisWidth = 0 ,
        axisHeight = itemSize*24,
        xAxisScale = d3.time.scale(),
        xAxis = d3.svg.axis()
          .orient('top')
          .ticks(d3.time.days,3)
          .tickFormat(monthDayFormat),
        yAxisScale = d3.scale.linear()
          .range([0,axisHeight])
          .domain([0,24]),
        yAxis = d3.svg.axis()
          .orient('left')
          .ticks(5)
          .tickFormat(d3.format('02d'))
          .scale(yAxisScale);

      initCalibration();

      var svg = d3.select('[role="heatmap"]');
      var heatmap = svg
        .attr('width',width)
        .attr('height',height)
      .append('g')
        .attr('width',width-margin.left-margin.right)
        .attr('height',height-margin.top-margin.bottom)
        .attr('transform','translate('+margin.left+','+margin.top+')');
      var rect = null;

      data = mydata.data1;
      //data = mydata.data2;
        data.forEach(function(valueObj){
          valueObj['date'] = timeFormat.parse(valueObj['timestamp']);
          var day = valueObj['day'] = monthDayFormat(valueObj['date']);

          var dayData = dailyValueExtent[day] = (dailyValueExtent[day] || [1000,-1]);
          var pmValue = valueObj['value']['PM2.5'];
          dayData[0] = d3.min([dayData[0],pmValue]);
          dayData[1] = d3.max([dayData[1],pmValue]);
        });

        dateExtent = d3.extent(data,function(d){
          //console.log(d.date)
          return d.date;
        });

        axisWidth = itemSize*(dayFormat(dateExtent[1])-dayFormat(dateExtent[0])+1);
        //console.log(axisWidth)
        //console.log(dayFormat(dateExtent[1]))
        //console.log(dayFormat(dateExtent[0]))
        
        //render axises
        xAxis.scale(xAxisScale.range([0,axisWidth]).domain([dateExtent[0],dateExtent[1]]));  
        svg.append('g')
          .attr('transform','translate('+margin.left+','+margin.top+')')
          .attr('class','x axis')
          .call(xAxis)
        .append('text')
          .text('date')
          .attr('transform','translate('+axisWidth+',-10)');

        svg.append('g')
          .attr('transform','translate('+margin.left+','+margin.top+')')
          .attr('class','y axis')
          .call(yAxis)
        .append('text')
          .text('time')
          .attr('transform','translate(-10,'+axisHeight+') rotate(-90)');

        //render heatmap rects
        dayOffset = dayFormat(dateExtent[0]);
        rect = heatmap.selectAll('rect')
          .data(data)
        .enter().append('rect')
          .attr('width',cellSize)
          .attr('height',cellSize)
          .attr('x',function(d){
            return itemSize*(dayFormat(d.date)-dayOffset);
          })
          .attr('y',function(d){            
            return hourFormat(d.date)*itemSize;
          })
          .attr('fill','#ffffff');

        rect.filter(function(d){ return d.value['PM2.5']>0;})
          .append('title')
          .text(function(d){
            return monthDayFormat(d.date)+' '+d.value['PM2.5'];
          });

        renderColor();
     //});

      function initCalibration(){
        d3.select('[role="calibration"] [role="example"]').select('svg')
          .selectAll('rect').data(colorCalibration).enter()
        .append('rect')
          .attr('width',cellSize)
          .attr('height',cellSize)
          .attr('x',function(d,i){
            return i*itemSize;
          })
          .attr('fill',function(d){
            return d;
          });

        //bind click event
        d3.selectAll('[role="calibration"] [name="displayType"]').on('click',function(){
          renderColor();
        });
      }

      function renderColor(){
        var renderByCount = document.getElementsByName('displayType')[0].checked;

        rect
          .filter(function(d){
            return (d.value['PM2.5']>=0);
          })
          .transition()
          .delay(function(d){      
            return (dayFormat(d.date)-dayOffset)*15;
          })
          .duration(500)
          .attrTween('fill',function(d,i,a){
            //choose color dynamicly      
            var colorIndex = d3.scale.quantize()
              .range([0,1,2,3,4,5])
              .domain((renderByCount?[0,500]:dailyValueExtent[d.day]));

            return d3.interpolate(a,colorCalibration[colorIndex(d.value['PM2.5'])]);
          });
      }
      
      //extend frame height in `http://bl.ocks.org/`
      d3.select(self.frameElement).style("height", "600px");  
    });
 body{font-family:arial, 'Hiragino Sans GB',Tahoma, Arial, Helvetica, STHeiti;font-size: 14px;}
    .days-hours-heatmap{padding: 20px 0 20px 0;width: 500px;margin: 0 auto;}
    .days-hours-heatmap .calibration{margin-bottom: 15px;width:400px;}
    .days-hours-heatmap .calibration .group{display: inline-block;}
    .days-hours-heatmap .calibration .description{width:108px;}
    .days-hours-heatmap .calibration .description>label:last-child{float:right;}
    .days-hours-heatmap .calibration>.display-control{float:right;}
    .days-hours-heatmap .calibration>.display-control label{vertical-align: top;}
    .days-hours-heatmap .calibration>.display-control input[type='radio']{cursor: pointer;}

    .days-hours-heatmap .heatmap .axis path{display: none;}
    .days-hours-heatmap .heatmap .axis line{fill: none;stroke: #000;shape-rendering: crispEdges;}
    .days-hours-heatmap .heatmap .axis text{font-size: 12px}
 <!DOCTYPE html>
    <html>
      <head>
        <title>Days Hours Heatmap</title>    
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
        <meta charset="utf-8"/>
      </head>
      <body>
        <div class="days-hours-heatmap">
          <!-- calibration and render type controller -->
          <div class="calibration" role="calibration">
            <div class="group" role="example">
              <svg width="120" height="17">
              </svg>
              <div role="description" class="description">
                <label>Less</label>
                <label>More</label>
              </div>        
            </div>
            <div role="toggleDisplay" class="display-control">
              <div>
                <input type="radio" name="displayType" checked/>
                <label>count</label>
              </div>
              <div>
                <input type="radio" name="displayType"/>
                <label>daily</label> 
              </div>
            </div>
          </div>
          <!-- heatmap -->
          <svg role="heatmap" class="heatmap"></svg>
        </div>
        
       

      </body>
    </html>

目前,daily单选按钮仅根据基于mydata[data1]的{​​{1}}和count按钮呈现数据。

enter image description here

我想要做的是根据renderByCountdata1呈现图片。 因此,稍后在HTML图片中,而不是data2count按钮会显示dailydata1。我怎样才能做到这一点?

请注意,在此示例中,data2对象仅包含两个成员mydata。但实际上它可能不止于此。

1 个答案:

答案 0 :(得分:0)

只需从对象中的键创建面板,就像任何其他d3层次一样:

var radios = d3.select('.display-control')
    .selectAll('.radio')
    .data(d3.keys(mydata))
    .enter()
    .append('div')
    .attr('class','radio');
radios.append('input').attr({
    'type': 'radio',
    'name': 'displayType',
    'checked': function(d, i) {
        // trace the checked radio somewhere outside
        return i===0 ? 'checked' : null;
    }
});
radios.append('label').text(function(d) {return d;});

超快速&amp;肮脏的小提琴:http://jsfiddle.net/5bh4c6p1/