This example shows a production unit and how
many items it has produced.
If you point with the mouse and drag to right, you can
count number of units in an interval.
aa
The Java script calls a program
get-device-counter.php
This file generates a datastream an encode it as JSON
2016-01-20 00:00:56 2096868 2016-01-20 00:01:56 2096868 2016-01-20 00:02:56 2096885 2016-01-20 00:03:56 2096934 2016-01-20 00:04:56 2096983 2016-01-20 00:05:56 2097002 2016-01-20 00:06:56 2097048 2016-01-20 00:07:56 2097096 2016-01-20 00:08:56 2097145 2016-01-20 00:09:56 2097170 2016-01-20 00:10:56 2097187 2016-01-20 00:11:57 2097224 2016-01-20 00:12:57 2097224 2016-01-20 00:13:57 2097224 2016-01-20 00:14:57 2097227 2016-01-20 00:15:57 2097243 2016-01-20 00:16:57 2097259 2016-01-20 00:17:57 2097273 2016-01-20 00:18:57 2097285 2016-01-20 00:19:57 2097314 ...
Source for the page
001: <?php 002: //---------------------------------------------------------------------- 003: // 004: // http://wesbos.com/html5-canvas-websockets-nodejs/ 005: // http://www.chartjs.org/ 006: // http://weblogs.asp.net/dwahlin/creating-a-line-chart-using-the-html-5-canvas 007: // https://www.dashingd3js.com/using-data-bound-to-dom-elements 008: // 009: //---------------------------------------------------------------------- 010: 011: 012: include_once('framework-config.php'); // configuration data 013: include_once('raditex-library.php'); // main library 014: include_once('framework-lists.php'); // lists - like menues an other 015: include_once('libs/rbis-library-widgets.php'); 016: include_once('libs/rbis-library-database.php'); 017: include_once('libs/rbis-library-html.php'); 018: 019: page_start(); 020: 021: page_header($header_image,"User: gorhas@demo.se"); 022: page_drop_down_menu($site_menu); 023: 024: page_menu($framework_menu); 025: 026: page_row_start(); 027: page_column_start_left(); 028: 029: 030: html_title("Machine work", 1); 031: 032: html_p(" 033: This example shows a production unit and how 034: many items it has produced. 035: <br /> 036: If you point with the mouse and drag to right, you can 037: count number of units in an interval. 038: "); 039: 040: // A div where the graph will go 041: echo "<div id='chartContainer'></div>"; 042: 043: 044: html_title("Data looks like"); 045: 046: html_paragraph(" 047: The Java script calls a program 048: <br /> 049: get-device-counter.php 050: <br /> 051: This file generates a datastream an encode it as JSON 052: "); 053: 054: ?> 055: <pre> 056: 2016-01-20 00:00:56 2096868 057: 2016-01-20 00:01:56 2096868 058: 2016-01-20 00:02:56 2096885 059: 2016-01-20 00:03:56 2096934 060: 2016-01-20 00:04:56 2096983 061: 2016-01-20 00:05:56 2097002 062: 2016-01-20 00:06:56 2097048 063: 2016-01-20 00:07:56 2097096 064: 2016-01-20 00:08:56 2097145 065: 2016-01-20 00:09:56 2097170 066: 2016-01-20 00:10:56 2097187 067: 2016-01-20 00:11:57 2097224 068: 2016-01-20 00:12:57 2097224 069: 2016-01-20 00:13:57 2097224 070: 2016-01-20 00:14:57 2097227 071: 2016-01-20 00:15:57 2097243 072: 2016-01-20 00:16:57 2097259 073: 2016-01-20 00:17:57 2097273 074: 2016-01-20 00:18:57 2097285 075: 2016-01-20 00:19:57 2097314 076: ... 077: </pre> 078: 079: <?php 080: 081: html_h("Sourcecode", 2); 082: 083: html_p("Source for the page"); 084: 085: // html-version of this file 086: include_once("src/plott-advanced.php.html"); 087: 088: html_p("Source for the java-script"); 089: 090: include_once("src/production-library-prod-stat.js.html"); 091: 092: page_column_end(); 093: page_row_end(); 094: 095: page_footer("http://www.raditex.nu","Raditex Konsult","http://www.rscada.se","rScada"); 096: page_end(); 097: 098: print("<script src='libs/rbis-library-utils.js'></script>\n"); 099: print("<script src='http://d3js.org/d3.v3.js'></script>\n"); 100: print("<script src='./production-library-prod-stat.js'></script>\n"); 101: 102: //---------------------------------------------------------------------- 103: // EOF 104: //--------------------------------------------------------------------- 105: ?> 106:
Source for the java-script
001: //---------------------------------------------------------------------- 002: // 003: // Ideas from 004: // http://canvasjs.com/html5-javascript-line-chart 005: // http://square.github.io/cubism/ 006: // http://www.d3noob.org/2013/01/adding-grid-lines-to-d3js-graph.html 007: // http://jsfiddle.net/555Cv/2/ 008: // http://www.stator-afm.com/tutorial/d3-js-mouse-events/ 009: // http://christopheviau.com/d3list/ !! 010: //---------------------------------------------------------------------- 011: 012: 013: var margin = {top: 20, right: 20, bottom: 50, left: 50}, 014: width = 1400 - margin.left - margin.right, 015: height = 350 - margin.top - margin.bottom; 016: 017: var parseDate0 = d3.time.format("%Y-%m-%d %H:%M:%S").parse; 018: 019: var x = d3.time.scale() 020: .range([0, width]); 021: 022: var y0 = d3.scale.linear() 023: .range([height, 0]); 024: 025: 026: var xAxis = d3.svg.axis() 027: .scale(x) 028: .ticks(d3.time.hour, 1) 029: .tickFormat(d3.time.format('%H:%M')) 030: .orient("bottom"); 031: 032: var yAxisLeft = d3.svg.axis() 033: .scale(y0) 034: .tickSize(-width, 0, 0) 035: .orient("left"); 036: 037: 038: 039: var line0 = d3.svg.line() 040: .x(function(d) { return x(d.time); }) 041: .y(function(d) { return y(d.bags); }); 042: 043: 044: var svg = d3.select("#chartContainer").append("svg") 045: .attr("width", width + margin.left + margin.right) 046: .attr("height", height + margin.top + margin.bottom) 047: .attr("width", 1450) 048: .attr("height", 350) 049: .style("border", "1px solid blue") 050: .on("mousedown", mouseDown) 051: .on("mouseup", mouseUp) 052: .on("click", mouseClick) 053: .on("mousemove", mouseMove) 054: .append("g") 055: .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 056: 057: var dup_data; 058: 059: d3.json("./get-device-counter.php",function(error, json) { 060: if(error) return console.warn(error); 061: data = json; 062: 063: dup_data = data.slice(); 064: 065: data.forEach(function(d) { 066: d.time = parseDate0(d.log_time); 067: d.bags = +d.bags_produced; 068: // console.log("time " + d.log_time ); 069: }); 070: 071: 072: var area = d3.svg.area() 073: .interpolate("step-after") 074: .x(function(d) { return x(d.time); }) 075: .y0(height) 076: .y1(function(d) { return y0(d.bags); }); 077: 078: 079: x.domain(d3.extent(data, function(d) { return d.time; })); 080: y0.domain([0, d3.max(data, function(d) { return d.bags; })+5]); 081: 082: 083: svg.append("g") 084: .attr("class", "x axis grid") 085: //.attr("ckass", "grid") 086: .attr("transform", "translate(0," + height + ")") 087: .call(xAxis) 088: .selectAll("text") 089: .attr("y", 0) 090: .attr("x", 9) 091: .attr("dy", ".35em") 092: .attr("transform", "rotate(50)") 093: .style("text-anchor", "start"); 094: 095: svg.append("g") 096: .attr("class", "y axis grid") 097: //.attr("class", "grid" 098: .call(yAxisLeft) 099: .append("text") 100: .attr("transform", "rotate(-90)") 101: .attr("y", 6) 102: .attr("dy", "-3em") 103: .style("text-anchor", "end") 104: .text("items/min"); 105: 106: svg.append("path") 107: .datum(data) 108: .attr("class", "area") 109: .attr("d", area); 110: 111: }); 112: 113: 114: var x_start = 0; 115: var x_end = 0; 116: var sel_area; 117: var text_area; 118: 119: var selection_in_progress = 0; 120: 121: function mouseDown() { 122: 123: //console.log("mouseDown"); 124: //alert("Down"); 125: 126: selection_in_progress = 1; 127: 128: d3.select("#the_area").remove(); 129: 130: // d3.select("#the_area").remove(); 131: 132: x_start = d3.mouse(this)[0]; 133: 134: d3.select("#the_area_text").remove(); 135: 136: sel_area = svg.append("rect") 137: .attr("height", height - 175) 138: .attr("id", "the_area_text") 139: .attr("width", 250) 140: .attr("x", x_start - 52 ) 141: .attr("y", 0) 142: .attr("opacity", 0.7) 143: .style("stroke", "#FFFFFF") 144: .style("fill", "#FFFFFF"); 145: 146: } 147: 148: 149: function mouseMove() { 150: 151: x_mouse = d3.mouse(this)[0]; 152: 153: x_end = x_mouse; 154: 155: var no_bags = 0; 156: 157: //console.log("Xpos: " + x_mouse); 158: //console.log("Selection in progress: " + selection_in_progress ); 159: 160: // console.log( "xxx" + x ); 161: 162: if(selection_in_progress) 163: { 164: 165: d3.select("#the_area").remove(); 166: d3.select("#the_text").remove(); 167: d3.select("#timespan_start").remove(); 168: d3.select("#timespan_end").remove(); 169: d3.select("#timespan").remove(); 170: d3.select("#bags_min").remove(); 171: 172: 173: var timespan; 174: var i_min = 0; 175: var i_max = 0; 176: 177: for( var i = 0; i < dup_data.length; i++) 178: { 179: //console.log("X value " + x(parseDate0(dup_data[i].log_time)) ); 180: 181: //console.log("X value " + x(function(d) { return x(dup_data[i].log_time); }); 182: //console.log("Time : " + parseDate0(dup_data[i].log_time)); 183: //console.log("Value : " + dup_data[i].bags_produced ); 184: 185: if( (x_start -54) <= x(parseDate0(dup_data[i].log_time)) && x(parseDate0(dup_data[i].log_time)) <= (x_end -54) ) 186: { 187: 188: 189: // find out i_min, i_max 190: if(i_min == 0) 191: { 192: i_min = i; 193: } 194: 195: i_max = i; 196: 197: // sum bags in interval 198: no_bags = no_bags + +dup_data[i].bags_produced; 199: } 200: 201: // calculate timespan 202: 203: } 204: 205: timespan = (((parseDate0(dup_data[i_max].log_time) - parseDate0(dup_data[i_min].log_time))/1000)/60); 206: 207: sel_area = svg.append("rect") 208: .attr("height", height - 100 ) 209: .attr("id", "the_area") 210: .attr("width", x_end - x_start) 211: .attr("x", x_start - 52 ) 212: .attr("y", 100) 213: .attr("opacity", .35) 214: .style("stroke", "#CCFFFF") 215: .style("fill", "green"); 216: 217: // Display timespan 218: sel_area = svg.append("text") 219: .attr("id", "timespan_start") 220: .attr("x", x_start - 50 ) 221: .attr("y", 10) 222: .attr("opacity", "1") 223: .style("fill", "black") 224: .attr("font-family", "sans-serif") 225: .text("Start: " + dup_data[i_min].log_time); 226: 227: sel_area = svg.append("text") 228: .attr("id", "timespan_end") 229: .attr("x", x_start - 50 ) 230: .attr("y", 30) 231: .style("fill", "black") 232: .attr("font-family", "sans-serif") 233: .attr("opacity", "1") 234: .text("End: " + dup_data[i_max].log_time); 235: 236: 237: sel_area = svg.append("text") 238: .attr("id", "timespan") 239: .attr("x", x_start - 50 ) 240: .attr("y", 50) 241: .style("fill", "black") 242: .attr("font-family", "sans-serif") 243: .attr("opacity", "1") 244: .text("Minutes: " + timespan.toFixed(0)); 245: 246: sel_area = svg.append("text") 247: .attr("id", "the_text") 248: .attr("x", x_start - 50 ) 249: .attr("y", + 70) 250: .style("fill", "black") 251: .attr("font-family", "sans-serif") 252: .attr("opacity", "1") 253: .text("No units: " + no_bags); 254: 255: sel_area = svg.append("text") 256: .attr("id", "bags_min") 257: .attr("x", x_start - 50 ) 258: .attr("y", + 90) 259: .style("fill", "black") 260: .attr("font-family", "sans-serif") 261: .attr("opacity", "1") 262: .text("Units/min: " + (no_bags/timespan).toFixed(1) ); 263: 264: 265: } 266: 267: } 268: 269: function mouseUp() { 270: // console.log("mouseUp"); 271: 272: selection_in_progress = 0; 273: 274: x_end = d3.mouse(this)[0]; 275: 276: 277: } 278: 279: function mouseClick() { 280: //console.log("mouseClick"); 281: //alert("Click"); 282: } 283: 284: 285: 286: 287: //---------------------------------------------------------------------- 288: // 289: //---------------------------------------------------------------------- 290: function draw_prod_stat() 291: { 292: 293: 294: //return; 295: 296: var prod_stat_canvas = document.getElementById("#chartContainer"); 297: var prod_stat_context = prod_stat_canvas.getContext("2d"); 298: 299: var my_gradient = prod_stat_context.createLinearGradient(1500/2, 0, 1500/2, 350); 300: 301: my_gradient.addColorStop(0, '#FFFFFF' ); 302: my_gradient.addColorStop(1, '#99CCFF' ); 303: 304: prod_stat_context.fillStyle = my_gradient; 305: prod_stat_context.fillRect(0, 0, 1500, 350); 306: 307: //prod_stat_context.fillRect(0, 0, 1500, 200); 308: 309: } 310: 311: 312: 313: 314: //---------------------------------------------------------------------- 315: // Draw nice data 316: //---------------------------------------------------------------------- 317: function draw_nice() 318: { 319: 320: //return; 321: 322: var chart = new CanvasJS.Chart("chartContainer", 323: { 324: zoomEnabled: true, 325: panEnabled: true, 326: title: 327: { 328: text: "Production statistics" 329: }, 330: legend: 331: { 332: horizontalAlign: "left", 333: verticalAlign: "center" 334: }, 335: axisY: 336: { 337: includeZero: false 338: }, 339: data: data, // random generator below 340: }); 341: 342: 343: chart.render(); 344: } 345: 346: 347: //---------------------------------------------------------------------- 348: // 349: //---------------------------------------------------------------------- 350: $().ready(function() 351: { 352: 353: // ?? 354: 355: }); 356:
The script that generates data
01: <?php 02: //---------------------------------------------------------------------- 03: // get-device-counter.php 04: // 05: // A server script that generates data for the graph 06: //---------------------------------------------------------------------- 07: 08: // $txt_file = file_get_contents("/home/gorhas/public_html/d3/stoved.log"); 09: 10: error_reporting(0); 11: 12: // Here I have the data in a file. In real life it should be 13: // collected from a database 14: $file = fopen("/home/gorhas/public_html/framework/counter-device-1.log", "r"); 15: 16: $counter_data = array(); 17: 18: // We take the data in the file and create data for the diagram 19: // First read in first line 20: // 21: $first_line = fgets($file); 22: $row_data = explode(' ', $first_line); 23: $old_counter_data = $row_data[2]; 24: 25: while(!feof($file)) 26: { 27: 28: $line = fgets($file); 29: 30: //get row data 31: $row_data = explode(' ', $line); 32: 33: $new_counter_data = $row_data[2] - $old_counter_data; 34: 35: 36: $values = array("log_time" => $row_data[0] . " " . $row_data[1], 37: "bags_produced"=> $new_counter_data); 38: 39: array_push($counter_data, $values); 40: 41: $old_counter_data = $row_data[2]; 42: 43: } 44: 45: // Now send the data to the webb-page 46: echo json_encode($counter_data); 47: //---------------------------------------------------------------------- 48: // END 49: //---------------------------------------------------------------------- 50: ?> 51: 52:
A slight variant of this is a temperature graph.