日历热图:未分配颜色

时间:2016-12-27 17:31:35

标签: javascript d3.js

我已经创建了一个日历热图,但问题是刹车的数据超过4500"标记为黑色而不是指示的颜色#3d3768。看起来这个类别找不到颜色。为什么呢?

<!DOCTYPE html>
<meta charset="utf-8">
<head>
<title>Data Calendar</title>
<style>
    .month {
        fill: none;
        stroke: #000;
        stroke-width: 2px;
    }
    .day {
        fill: #fff;
        stroke: #ccc;
    }
    text    {
        font-family:sans-serif;
        font-size:1.5em;
    }
    .dayLabel   {
        fill:#aaa;
        font-size:0.8em;
    }
    .monthLabel {
        text-anchor:middle;
        font-size:0.8em;
        fill:#aaa;
    }
    .yearLabel  {
        fill:#aaa;
        font-size:1.2em;
    }

    .key    {font-size:0.5em;}

</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
<script>

var breaks=[1500,2500,3500,4500,4550];
var colours=["#e2dff1","#b7b1dd","#8b82c8","#584f95","#3d3768"];

    //general layout information
    var cellSize = 17;
    var xOffset=20;
    var yOffset=60;
    var calY=50;//offset of calendar in each group
    var calX=25;
    var width = 960;
    var height = 163;
    var parseDate = d3.time.format("%d/%m/%y").parse;
    format = d3.time.format("%d-%m-%Y");
    toolDate = d3.time.format("%d/%b/%y");

    d3.csv("data.csv", function(error, data) {

        //set up an array of all the dates in the data which we need to work out the range of the data
        var dates = new Array();
        var values = new Array();

        //parse the data
        data.forEach(function(d)    {
                dates.push(parseDate(d.date));
                values.push(d.value);
                d.date=parseDate(d.date);
                d.value=d.value;
                d.year=d.date.getFullYear();//extract the year from the data
        });

        var yearlyData = d3.nest()
            .key(function(d){return d.year;})
            .entries(data);

        var svg = d3.select("body").append("svg")
            .attr("width","90%")
            .attr("viewBox","0 0 "+(xOffset+width)+" 540")

        //title
        svg.append("text")
        .attr("x",xOffset)
        .attr("y",20)
        .text(title);

        //create an SVG group for each year
        var cals = svg.selectAll("g")
            .data(yearlyData)
            .enter()
            .append("g")
            .attr("id",function(d){
                return d.key;
            })
            .attr("transform",function(d,i){
                return "translate(0,"+(yOffset+(i*(height+calY)))+")";  
            })

        var labels = cals.append("text")
            .attr("class","yearLabel")
            .attr("x",xOffset)
            .attr("y",15)
            .text(function(d){return d.key});

        //create a daily rectangle for each year
        var rects = cals.append("g")
            .attr("id","alldays")
            .selectAll(".day")
            .data(function(d) { return d3.time.days(new Date(parseInt(d.key), 0, 1), new Date(parseInt(d.key) + 1, 0, 1)); })
            .enter().append("rect")
            .attr("id",function(d) {
                return "_"+format(d);
                //return toolDate(d.date)+":\n"+d.value+" dead or missing";
            })
            .attr("class", "day")
            .attr("width", cellSize)
            .attr("height", cellSize)
            .attr("x", function(d) {
                return xOffset+calX+(d3.time.weekOfYear(d) * cellSize);
            })
            .attr("y", function(d) { return calY+(d.getDay() * cellSize); })
            .datum(format);

        //create day labels
        var days = ['Su','Mo','Tu','We','Th','Fr','Sa'];
        var dayLabels=cals.append("g").attr("id","dayLabels")
        days.forEach(function(d,i)    {
            dayLabels.append("text")
            .attr("class","dayLabel")
            .attr("x",xOffset)
            .attr("y",function(d) { return calY+(i * cellSize); })
            .attr("dy","0.9em")
            .text(d);
        })

        //let's draw the data on
        var dataRects = cals.append("g")
            .attr("id","dataDays")
            .selectAll(".dataday")
            .data(function(d){
                return d.values;   
            })
            .enter()
            .append("rect")
            .attr("id",function(d) {
                return format(d.date)+":"+d.value;
            })
            .attr("stroke","#ccc")
            .attr("width",cellSize)
            .attr("height",cellSize)
            .attr("x", function(d){return xOffset+calX+(d3.time.weekOfYear(d.date) * cellSize);})
            .attr("y", function(d) { return calY+(d.date.getDay() * cellSize); })
            .attr("fill", function(d) {
                if (d.value<breaks[0]) {
                    return colours[0];
                }
                for (i=0;i<breaks.length+1;i++){
                    if (d.value>=breaks[i]&&d.value<breaks[i+1]){
                        return colours[i];
                    }
                }
                if (d.value>breaks.length-1){
                    return colours[breaks.length]   
                }
            })

        //append a title element to give basic mouseover info
        dataRects.append("title")
            .text(function(d) { return toolDate(d.date)+":\n"+d.value+units; });

        //add montly outlines for calendar
        cals.append("g")
        .attr("id","monthOutlines")
        .selectAll(".month")
        .data(function(d) { 
            return d3.time.months(new Date(parseInt(d.key), 0, 1),
                                  new Date(parseInt(d.key) + 1, 0, 1)); 
        })
        .enter().append("path")
        .attr("class", "month")
        .attr("transform","translate("+(xOffset+calX)+","+calY+")")
        .attr("d", monthPath);

        //retreive the bounding boxes of the outlines
        var BB = new Array();
        var mp = document.getElementById("monthOutlines").childNodes;
        for (var i=0;i<mp.length;i++){
            BB.push(mp[i].getBBox());
        }

        var monthX = new Array();
        BB.forEach(function(d,i){
            boxCentre = d.width/2;
            monthX.push(xOffset+calX+d.x+boxCentre);
        })

        //create centred month labels around the bounding box of each month path
        //create day labels
        var months = ['JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT','NOV','DEC'];
        var monthLabels=cals.append("g").attr("id","monthLabels")
        months.forEach(function(d,i)    {
            monthLabels.append("text")
            .attr("class","monthLabel")
            .attr("x",monthX[i])
            .attr("y",calY/1.2)
            .text(d);
        })

         //create key
        var key = svg.append("g")
            .attr("id","key")
            .attr("class","key")
            .attr("transform",function(d){
                return "translate("+xOffset+","+(yOffset-(cellSize*1.5))+")";
            });

        key.selectAll("rect")
            .data(colours)
            .enter()
            .append("rect")
            .attr("width",cellSize)
            .attr("height",cellSize)
            .attr("x",function(d,i){
                return i*130;
            })
            .attr("fill",function(d){
                return d;
            });

        key.selectAll("text")
            .data(colours)
            .enter()
            .append("text")
            .attr("x",function(d,i){
                return cellSize+5+(i*130);
            })
            .attr("y","1em")
            .text(function(d,i){
                if (i<colours.length-1){
                    return "up to "+breaks[i] + "%";
                }   else    {
                    return "over "+breaks[i-1] + "%";   
                }
            });

    });//end data load

    //pure Bostock - compute and return monthly path data for any year
    function monthPath(t0) {
      var t1 = new Date(t0.getFullYear(), t0.getMonth() + 1, 0),
          d0 = t0.getDay(), w0 = d3.time.weekOfYear(t0),
          d1 = t1.getDay(), w1 = d3.time.weekOfYear(t1);
      return "M" + (w0 + 1) * cellSize + "," + d0 * cellSize
          + "H" + w0 * cellSize + "V" + 7 * cellSize
          + "H" + w1 * cellSize + "V" + (d1 + 1) * cellSize
          + "H" + (w1 + 1) * cellSize + "V" + 0
          + "H" + (w0 + 1) * cellSize + "Z";
    }

</script>
</body>
</html>

1 个答案:

答案 0 :(得分:0)

您的颜色选择代码的大小可能会有所减少,使用d3刻度来选择您的颜色也会使其更加清晰。但是,最终,你的问题在于:

            if (d.value>breaks.length-1){
                return colours[breaks.length]   
            }

仅在尚未返回颜色时调用此部分代码,即对于那些大于4550的值。当我不确定为什么需要此代码块中的if语句时,您的数组{ {1}}和breaks的长度相同。本质上,您将返回colours,由于数组为零索引,因此不会返回值。您可能希望返回array[array.length],因为您想要最后指定的颜色。

编辑:此外,如果为低于最低休息时间(您出现的那些)和高于最低休息时间的那些分配颜色,则需要多一个颜色而不是中断值。例如:一个中断刻度有两种颜色,用于休息时间上方/下方。但是,您可能故意将colours[colours.length-1]同时应用于colours[0]下的值和breaks[0]breaks[0]之间的值:

breaks[1]