Google Visualization Gauge dynamic update with jqu

2019-07-06 13:57发布

I had a REQ from a client that wanted to see a graphical representation of the sysInfo data on a LAMP server. For those of us who prefer a visual there's live demo here.

I found the gauges on google charts and in their demo the graph was moving. That's what I showed the client, so that's what they wanted. It's just that after poking around under the hood, I quickly realized that they were just updating it with random numbers. so I attempted to do it myself. I scoured the internet and I even posted my issues here but no-one replied.

So, here's what I did...

Initially, I was trying to get my google visualization gauge chart to update via ajax. my json feed returned:

[
{"key":"label1","value":"50.25"},
{"key":"label2","value":"99.43"},
{"key":"label3","value":"4.47"},
{"key":"label4","value":"7.06"}
]

I got it to initially render a static image, but it never seemed to update. it took me a while, then I figured out that my values had quotes around them. That was problem #1: the API was looking for numeric data.It was my 1st time with a json service. I wasn't sure if I needed to somehow add the status:"ok" or if I needed to do an eval() like so many other posts told me. Well, I didn't need either...

My script was as follows:

    <script type='text/javascript' src='http://www.google.com/jsapi'></script>
    <script type='text/javascript'>
    // load the visualization api & skin
    google.load('visualization', '1', {packages:['gauge']});
    // draw the initial chart from snapshot data for quick rendering
    google.setOnLoadCallback(drawChart); 
    // set global vars once DOM finishes
    $(document).ready(function() {
      chart = new google.visualization.Gauge(document.getElementById('chart_div'));
      options = {width: 400, height: 120,
          redFrom:  <?=$CODE_RED?>, redTo:100,
          yellowFrom:<?=$CODE_YEL?>, yellowTo:<?=$CODE_RED?>,
          greenFrom:<?=$CODE_GRN?>0, greenTo:<?=$CODE_YEL?>, 
          minorTicks: 5};
      // initialize ajax update of chart every 15 seconds
      setInterval("getStats ('./getJson.sysinfo.php?dash')", 15000); 
     });

then I rendered a static graph with:

function drawChart() {
    var data = new google.visualization.DataTable();
    data.addColumn('string', 'Label');
    data.addColumn('number', 'Value');
    data.addRows(8);
    data.setValue(0, 0, 'label1');
    data.setValue(0, 1, <?=number_format($X1,2) ?>);
    data.setValue(1, 0, 'label2');
    data.setValue(1, 1, <?=number_format($X2,2)?>);
    data.setValue(2, 0, 'label3');
    data.setValue(2, 1, <?=number_format($X3,2)?>);
    data.setValue(3, 0, 'label4');
    data.setValue(3, 1, <?=number_format($X4,3)?>);
    chart.draw(data, options);
 }   

all of that seemed to work fine until that pesky setInterval() method in doc.ready kicked in my sloppy code - 15 seconds later. The ajax source is a php array wrapped with json_encode(). When the script updated, my entire graph disappeared - which kinda sucked! I saw the json coming in via firebug. It just wasn't working. Take a look:

function getStats (source) {
  $.ajax({
    url: source,
    type: 'POST',
    dataType: 'json',
    success: function(data) { refreshChart(data); },
    error: function (request, status, error) {
           alert("REQUEST:\t"+request
              +"\nSTATUS:\t"+status
              +"\nERROR:\t"+error);
     }
   });
 }

and then my refreshChart() is where everything just fell apart:

    function refreshChart(serverData) {
        var chartData = [];
        for(var i = 0; i < serverData.length; i++) {
    //      chartData.push([serverData[i][0], $.serverData[i][1]['value']]);
    //      chartData.push([serverData[i][0], $.serverData[i][1].val()]);
          chartData.push([serverData[i][0], serverData[i][1].value]);
        }
//  note2self[347] = "I tried the above a million different ways and firebug coming back 
//+ with: "missing ] after element list" on the function declaration line..." 
        var data = new google.visualization.DataTable();
        data.addColumn('string', 'Label');
        data.addColumn('number', 'Value');
        data.addRows(chartData);  
        chart.draw(data, options);
     } 

    </script>

I was thinking maybe I needed to create another DataTable object, or if declared it outside the function, maybe I can use setInterval(data.setValue(i,1, serverDatai),1500) to update the element directly. Either way, the 1st step was accessing the json data. I knew I must have been be doing something stupid... At the bottom of my post (on this page, before I re-re-edited it) I added:"any help or even a nudge in the right direction would be greatly appreciated..." I came back every day for a week and re-re-re-edited. I thought I was just being unclear or that it was a stupid question. "I've seen stupid questions get answered", I thought, "maybe mine was really-really stupid?" None-the-less, I still needed an answer. Although I'm not the best programmer - I'm a pretty good googler. I read everything I could get my eyes on. No luck. nada, non, zylch, niet, nothing...

Well, it was driving me nuts, so here's what I figured out:

  1. As I mentioned before, I had quotes around my numeric values. That's what made my chart bomb... and since jQuery doesn't give you any errors I was kind of blind to the fact that I was stuffing character data into my new array until I called the .draw() method and my pretty picture disappeared.
  2. Another problem that I didn't think to check was the version of jQuery I was using. It was old & didn't have json parsing built into it. so, I would have had to eval the server data, parse the data stream & build the data structure from there.
  3. Both #1 & #2 caused the data row updates to fail and my fields WERE all coming back undefined.
  4. I also had some variable declarations out of scope - namely the class that added the .Guage and incidently the .DataTable() - which came along for the ride.
  5. data.setValue(i,1,serverData[i].value) should have been looped in the success callback of the AJAX() call - and this completely eliminated my refreshChart() method.
  6. The last problem I was having was figuring out how to access the json data & stuff it into my existing array. That was a little more tricky than I thought. a more experienced programmer probably would have just known better... but, I was stubborn. You can see where I was trying to do a chartData.push() into the existing array. I was calling possible every combination of arrayName[][] for several nights. It turned out that I COULD just re-use google's .setValue() method. As you will see below, using the success() callback method I was able to loop it once stuff the 1st few elements into the gauge and the rest into the other places it needed to go, using:
for (var i = 0; i < data.length; i++) {
        if (i<4) {
            dashData.setValue(i, 0, jsonData[i].k);
            dashData.setValue(i, 1, jsonData[i].v);
             } ...

I re-wrote the whole thing from scratch. In the next few days, I will probably re-write it again, several times. Eventually this will evolve into full blown drupal & wordpress plug-ins and a how-to article. I will post it on my blog LogicWizards.NET b/c the jQuery documentation is vague and the example demo on google's site isn't very straight forward, either.

To make a long story even longer, here's what I came up with:

<!-- /** Client-Side Scripts **/ --> 
<script type='text/javascript' src='http://www.google.com/jsapi'></script> 
<script type='text/javascript'> 
// load the visualization api & skin
google.load('visualization', '1', {packages:['gauge']});
// draw the initial chart from snapshot data for quick rendering
google.setOnLoadCallback(drawChart); //as soon as the API is loaded
// set global vars once DOM finishes
$(document).ready(function() {
  dash = new google.visualization.Gauge(document.getElementById('chart_div'));
  dashData = new google.visualization.DataTable();
  options = { width: 400, height: 120,
      redFrom:75, redTo:100,
      yellowFrom:50, yellowTo:75,
      greenFrom:00, greenTo:50, 
      minorTicks: 5};
 });

function drawChart() {
 // method to define initial chart
    dashData.addColumn('string', 'Label');
    dashData.addColumn('number', 'Value');
    dashData.addRows(8);
    dashData.setValue(0, 0, 'CPU');
    dashData.setValue(0, 1, 54.40);
    dashData.setValue(1, 0, 'RAM');
    dashData.setValue(1, 1, 99.54);
    dashData.setValue(2, 0, 'SWAP');
    dashData.setValue(2, 1, 4.25);
    dashData.setValue(3, 0, 'NET');
    dashData.setValue(3, 1, 0.402);
    dash.draw(dashData, options);
 }

function updateJSON (source) {
 // method to update all subsequent charts
 var jsonData = null; //there's really no reason for this anymore (see below)
 $.ajax({ url:source, type:'POST', dataType:'json',
    success: function(data) { jsonData=data;
    for (var i = 0; i < data.length; i++) {
      if (i<4) {
          dashData.setValue(i, 0, jsonData[i].k);
          dashData.setValue(i, 1, jsonData[i].v); 
          if (i<3) { dash.draw(dashData, options); }
        }
           $("#"+jsonData[i].k).text(jsonData[i].v); 
      }
     },
    error: function (request, status, error) {
           alert("REQUEST:\t"+request
               +"\nSTATUS:\t"+status
                +"\nERROR:\t"+error);        }
   }); //end-ajax
  return jsonData; //obsolete: updates are now done through the success callback
 }

function isSet (variable) { // mimic the php function 
  return (typeof variable !== "undefined" && variable.length) ? 1 : 0;
 }

function setDelay(delay){ 
 // method to change timer's sleep interval
    clearInterval(timer); //kill the last timer
    timer=setInterval(json,delay*1000); //delay is miliseconds
  }
</script> 

You will see that the bulk of the heavy lifting is done via the updateJSON() function. and now it works pretty nicely. I figured that if I was having this many problems then somebody else might benefit from a quick edit of my original post - with me answering my own questions as I went along. I think that the process of writing my questions out for StackedOverflow helped me to tell the difference between the problems and the symptoms, and also to find the answers. Even though nobody else had an answer.

If anyone would like to see a live demo go to http://LogicWizards.NET If you need this presentation layer stuff, please feel free to steal it from the 'view source'. The guts of the application are all on the back end... Now, it took me the better part of a week to put all the pieces together. Forgive me for rambling. I will edit this when I have more time. I've just taken so much code from THIS site and the rest of the community, over the years, I feel good about giving a little bit back... just remember to vote this article up, if you use it.

I hope it helps someone who needs it.

Happy Hacking,

Joe Negron ~ NYC

1条回答
我欲成王,谁敢阻挡
2楼-- · 2019-07-06 14:38

According to the project issues tracker, upgrade to 1.1 should fix the issue.

instead of

google.load('visualization', '1')

use

google.load('visualization', '1.1')
查看更多
登录 后发表回答