首页 > 解决方案 > 谷歌图表时间线 - 个别颜色显示不准确

问题描述

我正在使用 javascript 生成一个 Google 时间线图表,该图表会随着截止日期的临近动态更改条形颜色。某些条形颜色显示的颜色与我插入选项的颜色数组不准确。

控制台日志和视觉输出在这里

我从输入数据中更改了条形条标签,使它们具有唯一的名称,它解决了这个问题。但我想知道是否有办法解决这个问题,而不使用唯一的条形标签。

另外,有没有办法改变行标签的文本颜色?

这是我的代码:

var navcom_api = 'https://script.google.com/macros/s/AKfycbxLlDg0_UrcUhHT9c_3KdlYWqsIr8c5v93qOXKW7jro-q2nCSg/exec';



// Using Google Charts API to Draw Timeline Chart
google.charts.load("current", {packages:["timeline"]});
google.charts.setOnLoadCallback(drawChart(navcom_api));

// For Mobile Responsiveness
/*
$(window).resize(function(){
    drawChart();
});
*/
function searchData() {
    event.preventDefault();


    var keyword = document.forms["searchbar"]["search"].value;

    search_url = `${navcom_api}?q=` + keyword.toLowerCase().replace(/['"]+/g, '').replace(' ', '+');

    google.charts.load("current", {packages:["timeline"]});
    google.charts.setOnLoadCallback(drawChart(search_url));
}


function filterData() {
    event.preventDefault();

    var group = document.getElementById("filter").value;

    if (group == 'All') {
        search_url = navcom_api;
    }

    else {
        search_url = `${navcom_api}?q=` + group.toLowerCase().replace(' ', '+');
    }
    

    google.charts.load("current", {packages:["timeline"]});
    google.charts.setOnLoadCallback(drawChart(search_url));
}

// Function for Drawing Chart using Google Charts API
function drawChart(url) {

    
    var dataList = [];

    
    $.get(url, function(data) {
    
    
    if (data){
        for (var i in data.data) {
            
            if (data.data[i][3] && data.data[i][3]>=data.data[i][2]) {
                dataList.push([data.data[i][0], data.data[i][1], new Date(data.data[i][2]), new Date(data.data[i][3])]);
            }
        }
        
        
        // Today's Date
        var tdate = Date.now();   //Today's Date
        
        
        var fdate = tdate;     //First Date
        var ldate = tdate;     //Last Date



        // Setting Date Range for filter of 40 days
        var mindate = tdate - 20*(60*60*24*1000);           //Converting to miliseconds
        var maxdate = tdate + 20*(60*60*24*1000);           //Converting to miliseconds


        var i;
        var n = dataList.length;

        var colorList=[];


        for (i=0; i < n; i++) {

            // Start Date
            var sdate = dataList[i][2];

            // End Date
            var edate = dataList[i][3];

            if (edate <= mindate || sdate >= maxdate) {
                dataList[i] = null;
                colorList[i] = null;
            } 
            
            else {
                // Calculating Time Left Before Deadline
                // And Color Coding Accordingly
                var time_left = (edate - tdate) / (60*60*24*1000);     //Converting to days

                
                if (time_left < 0) {
                    colorList[i]=('#059DC0');
                    
                }

                else if (time_left < 4 && time_left >= 0) {
                    colorList[i]=('red');
                }
                else if (time_left < 6 && time_left >= 4) {
                    colorList[i]=('orange');
                }
                else if (time_left >= 6) {
                    colorList[i]=('green');
                }



                // Filtering according to Date Range
                
                if (sdate <= mindate) {
                    dataList[i][2] = new Date(mindate);
                }

                if (edate >= maxdate) {
                    dataList[i][3] = new Date(maxdate);
                }


                // Calculating first and last date to calculate dynamic width
                if (dataList[i][2] < fdate) {
                    fdate = dataList[i][2];
                    
                }
                
                if (dataList[i][3] > ldate) {
                    ldate = dataList[i][3];
                    
                }

                console.log(dataList[i][0] + ', ' + dataList[i][1] + ' - ' + colorList[i]);
            }

        }



        var filtered = dataList.filter(function (el) {
            return el != null;
          });

          var filteredColorList = colorList.filter(function (el) {
            return el != null;
          });

        //var filteredColorList = colorList.filter(function (el) {
         //   return el != null;
         // });
          


        // Adding Today's Date as Reference
        filtered.unshift(['CONCERN', 'Today', new Date(tdate), new Date(tdate)]);
        filteredColorList.unshift('black');

        console.log(filteredColorList);


        // Drawing Timeline Chart
        var container = document.getElementById('timeline');
        var chart = new google.visualization.Timeline(container);
        var dataTable = new google.visualization.DataTable();

        dataTable.addColumn({ type: 'string', id: 'Concern' });
        dataTable.addColumn({ type: 'string', id: 'Project' });
        dataTable.addColumn({ type: 'date', id: 'Start' });
        dataTable.addColumn({ type: 'date', id: 'End' });
        // A column for custom tooltip content
        //dataTable.addColumn({type: 'string', role: 'tooltip'});
        dataTable.addRows(filtered);

        // Dynamically Changing Height
        //var height = 500;
        if (n<13) {
            var height = (n + 1) * 40 + 70;
        }

        else {
            var height = screen.height/1.5;
        }
        
        
        //var width = 1600;

        // Dynamically Changing Width
        function responsive(x) {
            if (x.matches) { // If media query matches
                var dateRange = (ldate - fdate) / (60*60*24*1000);     //Converting to days

                width = dateRange * 40;
            } else {
                width = 1600;
            }
        }
          
        var x = window.matchMedia("(max-width: 1000px)");
        responsive(x); // Call listener function at run time
        x.addListener(responsive); // Attach listener function on state changes





        // Chart Properties
        var options = {
            height: height,
            width: width,
            colors: filteredColorList,
            timeline: { showRowLabels: true, groupByRowLabel: false, colorByRowLabel: false, 
            rowLabelStyle: {fontName: 'Montserrat', fontSize: 14},barLabelStyle: { fontName: 'Montserrat', fontSize: 12}},
            avoidOverlappingGridLine:true,
            cssClassNames : {
                headerRow :'headerRow'
            }
        };




        // Calling Function to draw chart
        chart.draw(dataTable, options);


        // Calling Function to draw vertical line reference
        todayLine('timeline');

        google.visualization.events.addListener(chart, 'onmouseover', function(obj){
        if(obj.row == 0){
            $('.google-visualization-tooltip').css('display', 'none');
            }
            todayLine('timeline');
        })
        google.visualization.events.addListener(chart, 'onmouseout', function(obj){
            todayLine('timeline');
        })
        
    }
    });




}

// Function to make Vertical Reference Line for Today's Date
function todayLine(div){
    var height;
    $('#' + div + ' rect').each(function(index){
        var x = parseFloat($(this).attr('x'));
        var y = parseFloat($(this).attr('y'));
        if(x == 0 && y == 0) {height = parseFloat($(this).attr('height'))}
    })
        var todayWord = $('#' + div + ' text:contains("Today")');
        todayWord.prev().first().attr('height', height + 'px').attr('width', '1px').attr('y', '0');

        var navanaGroup = $('#' + div + ' text:contains("Navana Group")');
        navanaGroup.prev().first().attr('color', '#ff0000');

}

  
body {
    width: auto;
    padding: 0;
    font-family: 'Montserrat', serif;
    display: flex;
    flex-direction: column;
    align-items: center;
  }

h1 {
  margin: 20px 0 20px 0;
  font-size: 32px;
  text-align: center;
}

h2 {
  font-size: 22px;
}

.headerRow {
  background-color: #2A94D6;
  font-weight: 500;
}


#filter {
  padding: 4px;
  margin-right: 40px;
  font-family: 'Montserrat', serif;
  font-size: 14px;
}

.group {
  font-family: 'Montserrat', serif;
  font-size: 14px;
}



#searchbar {
  display: flex;
  flex-direction: row;
  align-items: center;
}

#searchbar input[type=text] {
  padding: 4px;
  font-family: 'Montserrat', serif;
  font-size: 14px;
}

#searchbar button {
  float: right;
  padding: 2px;
  background: #eee;
  cursor: pointer;
}





#timeline {
  width: 90vw;
  height: auto;
  overflow-x: auto;
  padding: 0;
  margin: 0;
}






.grid {     
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr;
  align-items: center;
  justify-content: center;
}

.legend {
  margin: 0;
  display: flex;
  flex-direction: row;
  padding: 0;
  margin: 0;
}

.tooltip {
  margin-left: 15px;
  margin-right: 15px;
  display: flex;
  flex-direction: row;
  position: relative;
}

.tooltiptext {
  visibility: hidden;
  background-color: black;
  color: #fff;
  text-align: center;
  border-radius: 6px;
  padding: 5px 10px;

  /* Position the tooltip */
  position: absolute;
  margin-top: 10px;
  z-index: 1;
}

.tooltip:hover .tooltiptext {
  visibility: visible;
}

@media screen and (max-width: 1200px) {
  
  body {
    width: auto;
    padding: 20px 5px 20px 10px;
    font-family: 'Montserrat', serif;
  }

  h1 {
    font-size: 20px;
    margin: 5px 0 5px 0;
  }

  h2 {
    font-size: 16px;
  }

  #filter {
    padding: 2px;
    margin-right: 6px;
    font-size: 12px;
  }

  
  
  #searchbar input[type=text] {
    padding: 2px;
    width: 150px;
    font-size: 12px;
  }
  
  #searchbar button {
    float: right;
    padding: 1px;
    background: #eee;
    cursor: pointer;
  }

}
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Navana CMD - Projects Timeline</title>
  <link rel="stylesheet"  href="https://fonts.googleapis.com/css2?family=Montserrat:wght@100;300;400;500;600;700;900&family=Open+Sans&display=swap">
  <link rel="stylesheet" href="style.css">

  <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.3.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
  <script type="text/javascript" src="app.js"></script>

</head>
<body>
  <h1>CMD Projects Timeline</h1>

  <form id="searchbar" onsubmit="return searchData()" method="post">

    <select id="filter" name="filter" onchange="filterData()">
      <option value="All" class="group">All</option>
      <option value="Navana Group" class="group">Navana Group</option>
      <option value="Navana Interlink" class="group">Navana Interlink</option>
      <option value="Navana Logistics" class="group">Navana Logistics</option>
      <option value="CMD" class="group">CMD</option>
      <option value="Toyota" class="group">Toyota</option>
      <option value="LPG" class="group">LPG</option>
      <option value="Electronics" class="group">Electronics</option>
      <option value="Navana Foods" class="group">Navana Foods</option>
      <option value="Gloria Jeans Coffees" class="group">Gloria Jean's Coffees</option>
      <option value="La Tarte" class="group">La Tarte</option>
      <option value="Navana Real Estate" class="group">Navana Real Estate</option>
      <option value="Navana Construction" class="group">Navana Construction</option>
      <option value="Navana CNG" class="group">Navana CNG</option>
      <option value="Aftab Automobiles" class="group">Aftab Automobiles</option>
      <option value="Navana Furniture" class="group">Navana Furniture</option>
      <option value="Navana Petroleum" class="group">Navana Petroleum</option>
      <option value="Navana Engineering" class="group">Navana Engineering</option>
      <option value="Navana Welding" class="group">Navana Welding</option>
      <option value="Digital Equipment" class="group">Digital Equipment</option>
      <option value="Building Product" class="group">Building Product</option>
      <option value="Navana Batteries" class="group">Navana Batteries</option>
    </select>


    <input type="text" placeholder="Search.." name="search">
    <button type="submit">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="black" width="18px" height="18px"><path d="M0 0h24v24H0z" fill="none"/><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></svg>
    </button>
  </form>
  
  <div id="timeline"></div>

  <div class="legend">
    <h2>Legend:</h2>
    <div class="grid">
      <div class="tooltip" style="background-color: green; height: 20px; width: 20px;">
        <span class="tooltiptext">&gt;5d</span>
      </div>
        <div class="tooltip" style="background-color: orange; height: 20px; width: 20px;">
          <span class="tooltiptext">&lt;5d</span>
        </div>
        <div class="tooltip" style="background-color: red; height: 20px; width: 20px;">
          <span class="tooltiptext">&lt;3d</span>
        </div>
        <div class="tooltip" style="background-color: #059DC0; height: 20px; width: 20px;">
          <span class="tooltiptext">C</span>
        </div>
    </div>
  </div>

</body>
</html>
<script>

</script>

标签: javascriptchartsgoogle-visualization

解决方案


设置timeline.colorByRowLabel为根据数组中的位置为每一行分配颜色。

用于rowLabelStyle设置行标签的样式。

timeline: {
  colorByRowLabel: true,
  rowLabelStyle: {color: 'red'}
}

推荐阅读