stats.html HTML Source View


<!!DOCTYPE html>>
<html>
<head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
	<link rel="icon" type="image/png" href="favicon196.png" sizes="196x196">
	<link rel="stylesheet" href="styles/jquery.mobile-1.0b2.min.css?2" />
	<link rel="stylesheet" href="styles/eth.css" />
	<script src="styles/jquery-1.6.4.min.js" type="text/javascript"></script> 
	<script src="styles/jquery.mobile-1.0b2.min.js" type="text/javascript"></script> 
	<script src="styles/RGraph.common.core.js" type="text/javascript"></script> 
	<script src="styles/RGraph.common.dynamic.js" type="text/javascript"></script> 
	<script src="styles/RGraph.common.tooltips.js" type="text/javascript"></script> 
	<script src="styles/RGraph.common.key.js" type="text/javascript"></script> 
    <script src="styles/RGraph.line.js" type="text/javascript"></script> 

	<link rel="stylesheet" href="styles/demo_table.css" />
    <script src="styles/jquery.dataTables.js" type="text/javascript"></script> 
	<script type="text/javascript" src="styles/jquery.mobile.simpledialog.min.js"></script> 
	<link rel="stylesheet" type="text/css" href="styles/jquery.mobile.simpledialog.min.css" />
	
</head>
<body>
	<div data-role="page" id="statTopPage" data-title="Door Statistics - Wireless Tag List">

		<div data-role="header" data-theme="b" data-position="inline">
			<a href="javascript:closeGraph();" data-icon="delete" data-iconpos="notext" data-ajax="false">Close</a>
			<h1 id="stat_title"></h1>
			<a class="ui-btn-right" id="top_right_btn" data-icon="share" data-ajax=0 data-theme="b">Share</a>
		</div>
		<div id="statGraphs" >
		</div>

		<center class="loggedInOnly">
			<button data-icon="arrow-d" data-inline=1 data-theme="b" id="downloadEventLogBtn">Download CSV</button>
			<button data-icon="delete" data-inline=1 data-theme="e" id="deleteEventLogBtn">Delete Motion Log</button>
		</center>
		<center class="sharedOnly">
			Captured by <a href="http://wirelesstag.net">Wireless Sensor Tags</a>
		</center>

	<script src="styles/client.js" type="text/javascript"></script> 
	<script type="text/javascript">

		var old_style_query = (window.location.search.length > 0);
		if (window.location.search.length > 0) {
			var queryString = window.location.search.substring(1).split("&");
			for (var i = 0; i < queryString.length; i++) {
				var pair = queryString[i].split('=');
				if (pair.length == 2) {
					localStorage["mytaglist.stats."+decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || '');
					old_style_query= false;
				}
			}
		}

		var params = (old_style_query ? window.location.search.substring(1) : localStorage["mytaglist.stats.slaveid"]).split('&');
		var slaveId = params[0];
		var tagName = params.length > 1 ? decodeURIComponent(params[1]) : localStorage["mytaglist.stats.name"];
		var isUUID = slaveId.length > 4;
		if (!tagName && params.length > 1 && isUUID) tagName = decodeURIComponent(params[1]);

		if (tagName) $("#stat_title").text(tagName);
		else {
			$.ajax({
				url: WSROOT + "ethClient.asmx/GetTagForSlaveId",
				data: "{slaveid: " + slaveId+ "}",
				success: function (retval, textStatus) {
					$("#stat_title").text(retval.d.name);
				},
				error: function (xhr, textStatus, exception) {
					popup_error(xhr, btn);
				}
			});
		}

		var shareInfo;
		if (old_style_query) {
			$(".loggedInOnly").hide();
			$(".sharedOnly").show();

			var btn = $("#top_right_btn");
			btn.data("icon", "arrow-d");
			btn[0].innerHTML = "Download";
			btn.click(function () {
				window.location = WSROOT + "ethDownloadMotionCSV.aspx?uuid=" + params[0] + "&name=" + tagName + "&min=" + chart.xAxis[0].min + "&max=" + chart.xAxis[0].max;
			});
		} else {
			$(".sharedOnly").hide();

			$("#downloadEventLogBtn").click(function () {
				window.location = WSROOT + "ethDownloadMotionCSV.aspx?id=" + slaveId;
			});
			$("#top_right_btn").click(function () {
				var btn2 = $("#top_right_btn").find(".ui-btn-inner");
				var oldhtml2 = show_finding(btn2, "Loading...");
				$.ajax({
					url: WSROOT + "ethLogs.asmx/GetSharePermissions",
					data: JSON.stringify({ "ids": [slaveId], "type": "motion" }),
					complete: function () { restore_finding(btn2, oldhtml2); },
					success: function (retval, textStatus) {
						shareInfo = retval.d;

						var html = "<div style='padding: 15px; width: " + (window.innerWidth - 200) + "px'><b>Share this data</b>"+
						"<div data-role='fieldcontain'><label for='graphURL'>Link to open graph in Web:</label><input type='text' id='graphURL'></div>"+
						"<div data-role='fieldcontain'><label for='downloadURL'>CSV download link:</label><input type='text' id='downloadURL'></div>"+
						"<div data-role='fieldcontain'><label for='iosURL'>Link to open graph in iOS app:</label><input type='text' id='iosURL'></div>"+
						"<form><center><input type='checkbox' id='shareTemp'><label for='shareTemp'>Anyone with link can access temperature data for this tag</label> " +
						"<input type='checkbox' id='shareMotion'><label for='shareMotion'>Anyone with link can access motion log data for this tag</label>"+
						"<a rel='close' data-role='button' data-theme='b' data-inline=1 href='#'>Apply Permissions</a></center></form></div>";

						var holder = $("#statGraphs");
						if (holder.data('simpledialog')) {
							holder.data('simpledialog').options.fullHTML = html;
							holder.simpledialog('refresh').simpledialog('open');
						} else {
							holder.simpledialog({
								'mode': 'blank',
								'left': 80, 'top': '0px',
								'prompt': false,
								'forceInput': false,
								'useModal': true,
								pickPageTheme: 'c',
								'fullHTML': html,
								onClosed: function () {
									if (shareInfo.shareMotion[0] != $("#shareMotion").is(":checked") || shareInfo.shareTemperature[0] != $("#shareTemp").is(":checked")) {
										$.ajax({
											url: WSROOT + "ethLogs.asmx/EditSharePermissions",
											data: JSON.stringify({ "ids": [slaveId], "shareTemperature": [$("#shareTemp").is(":checked")], "shareMotion": [$("#shareMotion").is(":checked")] }),
											error: function (xhr, textStatus, exception) {
												popup_error(xhr, null);
											}
										});
									}
								}
							});
						}

						$("#shareMotion").attr("checked", shareInfo.shareMotion[0]).checkboxradio("refresh");
						$("#shareTemp").attr("checked", shareInfo.shareTemperature[0]).checkboxradio("refresh");
						$("#graphURL").val(shareInfo.graphUrl).click(function () { return selectedURL(this, true);});
						$("#downloadURL").val(shareInfo.downloadUrl).click(function () { return selectedURL(this, true); });
						$("#iosURL").val(shareInfo.iosAppUrl).click(function () { return selectedURL(this, true); });
						$("#embedHTML").val(shareInfo.embedHTML).click(function () { return selectedURL(this, true); });
					},
					error: function (xhr, textStatus, exception) {
						popup_error(xhr, null);
					}
				});
			});
		}
		function TimeOfDayString(sec) {
			var str = '';
			var ampm = Math.floor(sec / 3600 / 12);
			var hours = Math.floor(sec / 3600);
			var min = Math.round((sec-hours*3600) / 60);
			var min_str = "00"+min;
			return "{0}:{1} {2}".format(hours%12, min_str.substr(min_str.length-2), ampm ? "PM" : "AM");
		}
		function DetailedTimeSpanString(sec) {
			if (sec == 0) return "N/A";
			var str='';
			var days = Math.floor(sec / 60 / 60 / 24);
			if (days >= 1) { str = days + " days "; sec -= days * 60 * 60 * 24 }
			var hours = Math.floor(sec / 60 / 60);
			if (hours >= 1) { str = str + hours + " hours "; sec -= hours * 60 * 60 }
			var min = Math.floor(sec / 60);
			if (min >= 1) { str = str + min + " minutes "; sec -= min * 60 }
			str = str + Math.round(sec) + " seconds";
			return str;
		}
		jQuery.fn.dataTableExt.oSort['title-numeric-asc'] = function (a, b) {
			var x = a.match(/title="*(-?[0-9\.]+)/)[1];
			var y = b.match(/title="*(-?[0-9\.]+)/)[1];
			x = parseFloat(x);
			y = parseFloat(y);
			return ((x < y) ? -1 : ((x > y) ? 1 : 0));
		};

		jQuery.fn.dataTableExt.oSort['title-numeric-desc'] = function (a, b) {
			var x = a.match(/title="*(-?[0-9\.]+)/)[1];
			var y = b.match(/title="*(-?[0-9\.]+)/)[1];
			x = parseFloat(x);
			y = parseFloat(y);
			return ((x < y) ? 1 : ((x > y) ? -1 : 0));
		};
		Array.prototype.max = function () {
			return Math.max.apply(Math, this);
		};
		/*Array.prototype.average = function () {
			return this.sum()/this.length;
		}*/
		var isPrinting = false;
		function createOneDayGraph(stat, ymax1, ymax2) {
			var cvsid = "day_" + stat.date.replace(/\//g, '_');

			var targetWidth;
			if (window.innerWidth > 1000) targetWidth = window.innerWidth / 2-15;
			else targetWidth = window.innerWidth;

			$("<canvas></canvas>").data('date', stat.date).attr("id", cvsid).attr("title", "Click to open details for this day.")
						.attr("height", targetWidth / 3)
			.attr("width", targetWidth * (isPrinting ? 1.18 : 0.95))
			.css("text-align", "center").bind('click', function (event) {
				var date = $(event.target).data('date');
				$.ajax({
					url: WSROOT + (isUUID?"ethLogShared.asmx/GetDetailLogByUUID":"ethLogs.asmx/GetDetailLog"),
					/*beforeSend: function (xhr) {
					if(params.length > 1)
					xhr.setRequestHeader("Cookie", params[1]);
					},*/
					data: JSON.stringify({ "id": slaveId, "date": date }),
					success: function (retval, textStatus) {
						/*var dataSource = new Array();
						for (var i = 0; i < retval.d.length; i++) {
						var ee = retval.d[i];
						dataSource.push([ee.datetime, ee.eventType, ee.durationSec]);
						}*/
						//"aaData": dataSource,

						$("#statDetailTitle").text(date);
						var colDefs = [
							{
								"aTargets": [0],
								"asSorting": ["asc", "desc"],
								"fnRender": function (o) {
									return "<span title=" + o.aData[0] + ">" + TimeOfDayString(o.aData[0]) + "</span>";
								},
								"sType": "title-numeric"
							},
								{ "sClass": "center", "aTargets": [1] }
						];
						colDefs.push({
							"aTargets": [2],
							"fnRender": function (oObj) {
								return "<span>" + (oObj.aData[2]==0? (oObj.aData[3]==0?"N/A":oObj.aData[3].toFixed(2)+"°") : DetailedTimeSpanString(oObj.aData[2])) + "</span>";
							},
							"sType": "title-numeric",
							"sDefaultContent": "N/A"
						});
						var oTable = $('#detailTable').dataTable({
							"bFilter": false,
							"bRetrieve": true,
							"bPaginate": false,
							"aoColumnDefs": colDefs
						});
						oTable.fnClearTable();
						for (var i = 0; i < retval.d.length; i++) {
							var ee = retval.d[i];
							oTable.fnAddData([ee.secOfDay, ee.eventType, ee.durationSec, ee.angle]);
						}

						//alert($.mobile.activePage[0].id);
						$.mobile.changePage($("#statDetailPage"), { transition: "none", role: "dialog" });
						//alert($.mobile.activePage[0].id);
					}
				});
			}).appendTo($("#statGraphs"));

			line2 = new RGraph.Line(cvsid, stat.nOpened);
			line2.Set('chart.ymax', ymax2);
			line2.Set('chart.tooltips', $.map(stat.nOpened, function (n, i) { return n + " times"; }));
			line2.Set('chart.background.grid.autofit.numvlines', 23);
			line2.Set('chart.key.position.x', 45);
			line2.Set('chart.background.grid', true);
			line2.Set('chart.key.background', 'rgba(255,255,255,0.5)');

			line2.Set('chart.gutter.left', 40);
			line2.Set('chart.labels', ['12AM', '', '', '3', '', '', '6AM', '', '', '9', '', '', '12PM', '', '', '3', '', '', '6PM', '', '', '9', '', '']);
			line2.Set('chart.tickmarks', 'circle');

			line2.Set('chart.ymax', ymax1);
			line2.Set('chart.noxaxis', true);
			line2.Set('chart.noendxtick', true);
			line2.Set('chart.title', stat.date + " (" + stat.nOpened.sum() + " times total)");
			line2.Set('chart.colors', ['blue']);


			if (stat.avgOpenedDuration.sum() > 0 && stat.avgOpenedDuration.max()<1000) {
				line3 = new RGraph.Line(cvsid, stat.avgOpenedDuration);
				line3.Set('chart.gutter.left', 40);
				line3.Set('chart.gutter.right', 60);
				line2.Set('chart.gutter.right', 60);
				line3.Set('chart.tickmarks', 'square');
				line3.Set('chart.units.post', ' sec');

				line3.Set('chart.tooltips', $.map(stat.avgOpenedDuration, function (sec, i) { return "Average " + DetailedTimeSpanString(sec); }));

				line3.Set('chart.yaxispos', 'right');
				line3.Set('chart.noendxtick', true);
				line3.Set('chart.colors', ['red', 'blue']);
				line3.Set('chart.key', ['Average open duration (sec)', '# of times opened']);
				line3.Set('chart.background.grid', false);

				line3.Draw();
			} else {
				line2.Set('chart.gutter.right', 10);
				line2.Set('chart.key', ['# of times']);
			}

			line2.Draw();

		}

		var $loader = $("<div class='ui-loader ui-body-a ui-corner-all'><span class='ui-icon ui-icon-loading spin'></span><h1>Loading Statistics...</h1></div>");
		$body = $("body");
		$loader.appendTo($body).css({ top: 100 });
		$body.addClass("ui-loading");

		var statData;
		var ymax1 = new Array(), ymax2 = new Array();

		function resizeCanvas() {
			if ($.mobile.activePage[0].id == 'statTopPage') {
				$("canvas").remove();
				for (var i = 0; i < statData.length; i++) {
					createOneDayGraph(statData[i], ymax1[i], ymax2[i]);
				}
			}
		}

		function loadStats() {
			$.ajax({
				url: WSROOT + (isUUID ? "ethLogShared.asmx/GetDoorStatsByUUID" : "ethLogs.asmx/GetDoorStats"),
				/*beforeSend: function (xhr) {
				if (params.length > 1)
				xhr.setRequestHeader("Cookie", params[1]);
				},*/
				data: JSON.stringify({ "id": slaveId }),
				success: function (retval, textStatus) {
					statData = retval.d;
					for (var i = 0; i < statData.length; i++) {
						ymax1[i] = ymax2[i] = 0;
						for (var j = 0; j < statData[i].nOpened.length; j++) {
							ymax1[i] = Math.max(statData[i].nOpened[j], ymax1[i]);
							ymax2[i] = Math.max(statData[i].avgOpenedDuration[j], ymax2[i]);
						}
						//ymax2[i] = Math.min(3600 * 2, ymax2[i]);
						ymax1[i] = Math.ceil(ymax1[i] / 5 + 0.5) * 5;
						ymax2[i] = Math.ceil(ymax2[i] / 10 + 0.5) * 10;
					}

					for (var i = 0; i < statData.length; i++) {
						createOneDayGraph(statData[i], ymax1[i], ymax2[i]);
					}

					window.addEventListener('resize', function () {
						resizeCanvas();
					}, false);
					window.matchMedia('print').addListener(function (mql) {
						if (mql.matches) {
							isPrinting = true;
							resizeCanvas();
						} else {
							isPrinting = false;
						}
					});

					window.addEventListener('resize', function () {
						resizeCanvas();
					}, false);

					//$body.removeClass("ui-loading");
					$loader.remove();
				},
				error: function (xhr, textStatus, exception) {
					if (xhr.responseText.toLowerCase().indexOf("unauthorized") != -1 || exception.toLowerCase().indexOf("unauthorized") != -1 || xhr.responseText.toLowerCase().indexOf("authentication failed") != -1)
						location.replace("signin.html?ReturnUrl=" + encodeURIComponent(window.location.pathname + window.location.search));
					else {
						//$body.removeClass("ui-loading");
						$loader.remove();

						popup_error(xhr, $body);
					}
				}
			});
		}
			loadStats();

		$('#deleteEventLogBtn').click(function (e) {
			$(e.target).simpledialog({ mode: 'bool', prompt: "This operation will permanently delete all motion sensor log data of this tag. Do you want to continue?",
				useModal: true, forceInput: true, cleanOnClose: true,
				'buttons': {
					'Yes': { click: function () {
						$.ajax({ url: WSROOT + "ethLogs.asmx/DeleteEventData",
							data: "{id: " + slaveId + "}",
							success: function (retval) {
								$("#statGraphs").empty();
								$("#statGraphs").html("<center>" + retval.d + " records permanently removed.</center>");
							}
						});
					}, icon: "forward"
					},
					'Cancel': { click: function () {
					}, icon: "back"
					}
				}
			});
		});
	</script> 
	</div>

	<div data-role="page" id="statDetailPage" style="-webkit-user-select: auto; -webkit-touch-callout: default;">
		<div data-role="header" data-theme="d" data-position="inline">
			<h1 id="statDetailTitle"></h1>
		</div>
		<div data-role="content" data-theme="c">
			<table cellpadding="0" cellspacing="0" border="0" class="display" id="detailTable">
				<thead>
					<tr>
						<th>
							Time
						</th>
						<th>
							Type
						</th>
						<th>
							Duration/Angle
						</th>
					</tr>
				</thead>
				<tbody>
				</tbody>
			</table>
		</div>
	</div>
</body>
</html>