From d08f5f78277eb54c0fa95f393b5409f017347983 Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Thu, 12 Mar 2015 02:13:22 -0700 Subject: [PATCH 01/11] use async.parallel to make multiple mongo queries at once and get rid of the callback-hell; also use env.DISPLAY_UNITS if units aren't set on request --- lib/pebble.js | 177 +++++++++++++++++++++++++++++++++---------------------- lib/websocket.js | 129 +++++++++++++++++++++++----------------- package.json | 1 + 3 files changed, 180 insertions(+), 127 deletions(-) diff --git a/lib/pebble.js b/lib/pebble.js index d918de564..1f1bcb0ea 100644 --- a/lib/pebble.js +++ b/lib/pebble.js @@ -12,6 +12,7 @@ var DIRECTIONS = { }; var iob = require("./iob")(); +var async = require('async'); function directionToTrend (direction) { var trend = 8; @@ -22,97 +23,126 @@ function directionToTrend (direction) { } function pebble (req, res) { - var ONE_DAY = 24 * 60 * 60 * 1000; - var useMetricBg = (req.query.units === "mmol"); - var uploaderBattery; - var treatmentResults; - var profileResult; + var ONE_DAY = 24 * 60 * 60 * 1000 + , uploaderBattery + , treatmentResults + , profileResult + , sgvData = [ ] + , calData = [ ]; function scaleBg(bg) { - if (useMetricBg) { + if (req.mmol) { return (Math.round((bg / 18) * 10) / 10).toFixed(1); - } else + } else { return bg; + } } - function get_latest (err, results) { + function sendData () { var now = Date.now(); - var sgvData = [ ]; - var calData = [ ]; - - results.forEach(function(element, index, array) { - if (element) { - var obj = {}; - if (element.sgv) { - var next = null; - var sgvs = results.filter(function(d) { - return !!d.sgv; - }); - if (index + 1 < sgvs.length) { - next = sgvs[index + 1]; - } - obj.sgv = scaleBg(element.sgv).toString(); - obj.bgdelta = (next ? (scaleBg(element.sgv) - scaleBg(next.sgv) ) : 0); - if (useMetricBg) { - obj.bgdelta = obj.bgdelta.toFixed(1); - } - if ('direction' in element) { - obj.trend = directionToTrend(element.direction); - obj.direction = element.direction; - } - obj.datetime = element.date; - if (req.rawbg) { - obj.filtered = element.filtered; - obj.unfiltered = element.unfiltered; - obj.noise = element.noise; - obj.rssi = element.rssi; - } - // obj.date = element.date.toString( ); - sgvData.push(obj); - } else if (req.rawbg && element.type == 'cal') { - calData.push(element); - } - } - }); - - var count = parseInt(req.query.count) || 1; - var bgs = sgvData.slice(0, count); //for compatibility we're keeping battery and iob here, but they would be better somewhere else - bgs[0].battery = uploaderBattery ? "" + uploaderBattery : undefined; - if (req.iob) { - bgs[0].iob = iob.calcTotal(treatmentResults.slice(0, 20), profileResult, new Date(now)).display; + if (sgvData.length > 0) { + sgvData[0].battery = uploaderBattery ? "" + uploaderBattery : undefined; + if (req.iob) { + sgvData[0].iob = iob.calcTotal(treatmentResults.slice(0, 20), profileResult, new Date(now)).display; + } } - var result = { status: [ {now:now}], bgs: bgs, cals: calData.slice(0, count) }; + var result = { status: [ {now: now} ], bgs: sgvData, cals: calData }; res.setHeader('content-type', 'application/json'); res.write(JSON.stringify(result)); res.end( ); // collection.db.close(); } - req.devicestatus.last(function(err, value) { - if (!err && value) { - uploaderBattery = value.uploaderBattery; - } else { - console.error("req.devicestatus.tail", err); - } - var earliest_data = Date.now() - ONE_DAY; - loadTreatments(req, earliest_data, function (err, trs) { - treatmentResults = trs; - loadProfile(req, function (err, profileResults) { - profileResults.forEach(function(profile) { - if (profile) { - if (profile.dia) { - profileResult = profile; + var earliest_data = Date.now() - ONE_DAY; + + async.parallel({ + devicestatus: function (callback) { + req.devicestatus.last(function (err, value) { + if (!err && value) { + uploaderBattery = value.uploaderBattery; + } else { + console.error("req.devicestatus.tail", err); } - } + callback(); }); - var q = { find: {"date": {"$gte": earliest_data}} }; - req.entries.list(q, get_latest); - }); - }); - }); + } + , treatments: function(callback) { + loadTreatments(req, earliest_data, function (err, trs) { + treatmentResults = trs; + callback() + }); + } + , profile: function(callback) { + loadProfile(req, function (err, profileResults) { + profileResults.forEach(function (profile) { + if (profile) { + if (profile.dia) { + profileResult = profile; + } + } + }); + callback(); + }) + } + , cal: function(callback) { + var cq = { count: req.count, find: {"type": "cal"} }; + req.entries.list(cq, function (err, results) { + results.forEach(function (element) { + if (element) { + calData.push({ + x: element.date + , d: element.dateString + , scale: element.scale + , intercept: element.intercept + , slope: element.slope + }); + } + }); + callback(); + }); + } + , entries: function(callback) { + var q = { count: req.count, find: { "sgv": { $exists: true }} }; + + req.entries.list(q, function(err, results) { + results.forEach(function(element, index) { + if (element) { + var obj = {}; + var next = null; + var sgvs = results.filter(function(d) { + return !!d.sgv; + }); + if (index + 1 < sgvs.length) { + next = sgvs[index + 1]; + } + obj.sgv = scaleBg(element.sgv).toString(); + obj.bgdelta = (next ? (scaleBg(element.sgv) - scaleBg(next.sgv) ) : 0); + if (req.mmol) { + obj.bgdelta = obj.bgdelta.toFixed(1); + } + if ('direction' in element) { + obj.trend = directionToTrend(element.direction); + obj.direction = element.direction; + } + obj.datetime = element.date; + if (req.rawbg) { + obj.filtered = element.filtered; + obj.unfiltered = element.unfiltered; + obj.noise = element.noise; + obj.rssi = element.rssi; + } + // obj.date = element.date.toString( ); + sgvData.push(obj); + } + }); + callback(); + }); + } + }, sendData); + } function loadTreatments(req, earliest_data, fn) { @@ -140,6 +170,9 @@ function configure (entries, treatments, profile, devicestatus, env) { req.devicestatus = devicestatus; req.rawbg = env.enable && env.enable.indexOf('rawbg') > -1; req.iob = env.enable && env.enable.indexOf('iob') > -1; + req.mmol = (req.query.units || env.DISPLAY_UNITS) === 'mmol'; + req.count = parseInt(req.query.count) || 1; + next( ); } return [middle, pebble]; diff --git a/lib/websocket.js b/lib/websocket.js index 6936ef173..0525a7018 100644 --- a/lib/websocket.js +++ b/lib/websocket.js @@ -1,3 +1,4 @@ +var async = require('async'); function websocket (env, server, entries, treatments, profiles) { "use strict"; @@ -149,62 +150,80 @@ function update() { mbgData = []; profileData = []; var earliest_data = now - TWO_DAYS; - var q = { find: {"date": {"$gte": earliest_data}} }; - entries.list(q, function (err, results) { - results.forEach(function(element, index, array) { - if (element) { - if (element.mbg) { - var obj = {}; - obj.y = element.mbg; - obj.x = element.date; - obj.d = element.dateString; - obj.device = element.device; - mbgData.push(obj); - } else if (element.sgv) { - var obj = {}; - obj.y = element.sgv; - obj.x = element.date; - obj.d = element.dateString; - obj.device = element.device; - obj.direction = directionToChar(element.direction); - obj.filtered = element.filtered; - obj.unfiltered = element.unfiltered; - obj.noise = element.noise; - obj.rssi = element.rssi; - cgmData.push(obj); - } else if (element.slope) { - var obj = {}; - obj.x = element.date; - obj.d = element.dateString; - obj.scale = element.scale; - obj.intercept = element.intercept; - obj.slope = element.slope; - calData.push(obj); - } - } - }); - var tq = { find: {"created_at": {"$gte": new Date(earliest_data).toISOString()}} }; - treatments.list(tq, function (err, results) { - treatmentData = results.map(function(treatment) { - var timestamp = new Date(treatment.timestamp || treatment.created_at); - treatment.x = timestamp.getTime(); - return treatment; - }); - - profiles.list(function (err, results) { - // There should be only one document in the profile collection with a DIA. If there are multiple, use the last one. - results.forEach(function(element, index, array) { - if (element) { - if (element.dia) { - profileData[0] = element; + + async.parallel({ + entries: function(callback) { + var q = { find: {"date": {"$gte": earliest_data}} }; + entries.list(q, function (err, results) { + results.forEach(function (element) { + if (element) { + if (element.mbg) { + mbgData.push({ + y: element.mbg + , x: element.date + , d: element.dateString + , device: element.device + }); + } else if (element.sgv) { + cgmData.push({ + y: element.sgv + , x: element.date + , d: element.dateString + , device: element.device + , direction: directionToChar(element.direction) + , filtered: element.filtered + , unfiltered: element.unfiltered + , noise: element.noise + , rssi: element.rssi + }); + } } - } - }); - // all done, do loadData - loadData( ); - }); - }); - }); + }); + callback(); + }) + } + , cal: function(callback) { + var cq = { count: 1, find: {"type": "cal"} }; + entries.list(cq, function (err, results) { + results.forEach(function (element) { + if (element) { + calData.push({ + x: element.date + , d: element.dateString + , scale: element.scale + , intercept: element.intercept + , slope: element.slope + }); + } + }); + callback(); + }); + } + , treatments: function(callback) { + var tq = { find: {"created_at": {"$gte": new Date(earliest_data).toISOString()}} }; + treatments.list(tq, function (err, results) { + treatmentData = results.map(function (treatment) { + var timestamp = new Date(treatment.timestamp || treatment.created_at); + treatment.x = timestamp.getTime(); + return treatment; + }); + callback(); + }); + } + , profile: function(callback) { + profiles.list(function (err, results) { + // There should be only one document in the profile collection with a DIA. If there are multiple, use the last one. + results.forEach(function(element, index, array) { + if (element) { + if (element.dia) { + profileData[0] = element; + } + } + }); + callback(); + }); + } + }, loadData); return update; } diff --git a/package.json b/package.json index ec203d385..929999ff6 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "node": "0.10.x" }, "dependencies": { + "async": "^0.9.0", "body-parser": "^1.4.3", "bower": "^1.3.8", "browserify-express": "^0.1.4", From 2dc75369c07b696b1ba87f8214fc1fd62113710e Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Thu, 12 Mar 2015 03:06:25 -0700 Subject: [PATCH 02/11] fixed mocks used in pebble test and them bugs found by tests --- lib/pebble.js | 28 ++++++++++++++-------------- tests/pebble.test.js | 32 +++++++++++++++++++++----------- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/lib/pebble.js b/lib/pebble.js index 1f1bcb0ea..8464bb1d6 100644 --- a/lib/pebble.js +++ b/lib/pebble.js @@ -88,21 +88,21 @@ function pebble (req, res) { }) } , cal: function(callback) { - var cq = { count: req.count, find: {"type": "cal"} }; - req.entries.list(cq, function (err, results) { - results.forEach(function (element) { - if (element) { - calData.push({ - x: element.date - , d: element.dateString - , scale: element.scale - , intercept: element.intercept - , slope: element.slope - }); - } + if (req.rawbg) { + var cq = { count: req.count, find: {type: 'cal'} }; + req.entries.list(cq, function (err, results) { + results.forEach(function (element) { + if (element) { + calData.push({ + x: element.date, d: element.dateString, scale: element.scale, intercept: element.intercept, slope: element.slope + }); + } + }); + callback(); }); + } else { callback(); - }); + } } , entries: function(callback) { var q = { count: req.count, find: { "sgv": { $exists: true }} }; @@ -170,7 +170,7 @@ function configure (entries, treatments, profile, devicestatus, env) { req.devicestatus = devicestatus; req.rawbg = env.enable && env.enable.indexOf('rawbg') > -1; req.iob = env.enable && env.enable.indexOf('iob') > -1; - req.mmol = (req.query.units || env.DISPLAY_UNITS) === 'mmol'; + req.mmol = false;//(req.query.units || env.DISPLAY_UNITS) === 'mmol'; req.count = parseInt(req.query.count) || 1; next( ); diff --git a/tests/pebble.test.js b/tests/pebble.test.js index d6704ed79..2edba95ee 100644 --- a/tests/pebble.test.js +++ b/tests/pebble.test.js @@ -4,8 +4,8 @@ var should = require('should'); //Mock entries var entries = { - list: function(q, callback) { - var results = [ + list: function(opts, callback) { + var sgvs = [ { device: 'dexcom', date: 1422727301000, dateString: 'Sat Jan 31 10:01:41 PST 2015', @@ -18,14 +18,6 @@ var entries = { noise: 1 }, { device: 'dexcom', - date: 1422647711000, - dateString: 'Fri Jan 30 11:55:11 PST 2015', - slope: 895.8571693029189, - intercept: 34281.06876195567, - scale: 1, - type: 'cal' - }, - { device: 'dexcom', date: 1422727001000, dateString: 'Sat Jan 31 09:56:41 PST 2015', sgv: 84, @@ -70,7 +62,25 @@ var entries = { noise: 1 } ]; - callback(null, results); + + var cals = [ + { device: 'dexcom', + date: 1422647711000, + dateString: 'Fri Jan 30 11:55:11 PST 2015', + slope: 895.8571693029189, + intercept: 34281.06876195567, + scale: 1, + type: 'cal' + } + ]; + + var count = (opts && opts.count) || 1; + + if (opts && opts.find && opts.find.sgv) { + callback(null, sgvs.slice(0, count)); + } else if (opts && opts.find && opts.find.type == 'cal') { + callback(null, cals.slice(0, count)); + } } }; From 6357212222eb0a6080f71c34bd76d6e4262dd83d Mon Sep 17 00:00:00 2001 From: Kate Farnsworth Date: Thu, 12 Mar 2015 18:37:03 -0400 Subject: [PATCH 03/11] Update pebble.js --- lib/pebble.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/pebble.js b/lib/pebble.js index 8464bb1d6..036339957 100644 --- a/lib/pebble.js +++ b/lib/pebble.js @@ -93,9 +93,11 @@ function pebble (req, res) { req.entries.list(cq, function (err, results) { results.forEach(function (element) { if (element) { - calData.push({ - x: element.date, d: element.dateString, scale: element.scale, intercept: element.intercept, slope: element.slope - }); + var calobj = {}; + calobj.slope = Math.round(element.slope).toFixed(0); + calobj.intercept = Math.round(element.intercept).toFixed(0); + calobj.scale = Math.round(element.scale).toFixed(0); + calData.push(calobj); } }); callback(); @@ -132,7 +134,7 @@ function pebble (req, res) { obj.filtered = element.filtered; obj.unfiltered = element.unfiltered; obj.noise = element.noise; - obj.rssi = element.rssi; + //obj.rssi = element.rssi; } // obj.date = element.date.toString( ); sgvData.push(obj); From 051f49bac5f62143dd2f1d4be6f6b72b0fcb584a Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Thu, 12 Mar 2015 15:37:23 -0700 Subject: [PATCH 04/11] uncomment testing hack that shouldn't have been committed --- lib/pebble.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pebble.js b/lib/pebble.js index 8464bb1d6..06b78ca01 100644 --- a/lib/pebble.js +++ b/lib/pebble.js @@ -170,7 +170,7 @@ function configure (entries, treatments, profile, devicestatus, env) { req.devicestatus = devicestatus; req.rawbg = env.enable && env.enable.indexOf('rawbg') > -1; req.iob = env.enable && env.enable.indexOf('iob') > -1; - req.mmol = false;//(req.query.units || env.DISPLAY_UNITS) === 'mmol'; + req.mmol = (req.query.units || env.DISPLAY_UNITS) === 'mmol'; req.count = parseInt(req.query.count) || 1; next( ); From 7b6f054409632b8f8e30884a991b92f8b6517624 Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Thu, 12 Mar 2015 15:44:21 -0700 Subject: [PATCH 05/11] removed .toFixed(0)'s and fixed tests --- lib/pebble.js | 12 +++++------- tests/pebble.test.js | 5 ++--- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/lib/pebble.js b/lib/pebble.js index ab1f22ff7..2627b55b2 100644 --- a/lib/pebble.js +++ b/lib/pebble.js @@ -93,11 +93,11 @@ function pebble (req, res) { req.entries.list(cq, function (err, results) { results.forEach(function (element) { if (element) { - var calobj = {}; - calobj.slope = Math.round(element.slope).toFixed(0); - calobj.intercept = Math.round(element.intercept).toFixed(0); - calobj.scale = Math.round(element.scale).toFixed(0); - calData.push(calobj); + calData.push({ + slope: Math.round(element.slope) + , intercept: Math.round(element.intercept) + , scale: Math.round(element.scale) + }); } }); callback(); @@ -134,9 +134,7 @@ function pebble (req, res) { obj.filtered = element.filtered; obj.unfiltered = element.unfiltered; obj.noise = element.noise; - //obj.rssi = element.rssi; } - // obj.date = element.date.toString( ); sgvData.push(obj); } }); diff --git a/tests/pebble.test.js b/tests/pebble.test.js index 2edba95ee..e9dd57d1e 100644 --- a/tests/pebble.test.js +++ b/tests/pebble.test.js @@ -174,13 +174,12 @@ describe('Pebble Endpoint with Raw', function ( ) { bg.filtered.should.equal(113984); bg.unfiltered.should.equal(111920); bg.noise.should.equal(1); - bg.rssi.should.equal(179); bg.battery.should.equal('100'); res.body.cals.length.should.equal(1); var cal = res.body.cals[0]; - cal.slope.should.equal(895.8571693029189); - cal.intercept.should.equal(34281.06876195567); + cal.slope.should.equal(896); + cal.intercept.should.equal(34281); cal.scale.should.equal(1); done( ); }); From 31624221c9211200d5e81089a890d04eef899490 Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Thu, 12 Mar 2015 18:00:39 -0700 Subject: [PATCH 06/11] a little clean up --- lib/pebble.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/pebble.js b/lib/pebble.js index 2627b55b2..fac7b3cfb 100644 --- a/lib/pebble.js +++ b/lib/pebble.js @@ -1,3 +1,5 @@ +'use strict'; + var DIRECTIONS = { NONE: 0 , DoubleUp: 1 @@ -53,7 +55,6 @@ function pebble (req, res) { res.setHeader('content-type', 'application/json'); res.write(JSON.stringify(result)); res.end( ); - // collection.db.close(); } var earliest_data = Date.now() - ONE_DAY; @@ -72,7 +73,7 @@ function pebble (req, res) { , treatments: function(callback) { loadTreatments(req, earliest_data, function (err, trs) { treatmentResults = trs; - callback() + callback(); }); } , profile: function(callback) { @@ -85,7 +86,7 @@ function pebble (req, res) { } }); callback(); - }) + }); } , cal: function(callback) { if (req.rawbg) { From b7fc6b932bec2eb37f8267fe0440e2a086f97061 Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Fri, 13 Mar 2015 17:29:02 -0700 Subject: [PATCH 07/11] added initial compression of everything so we can start testing and see if there are any issues --- package.json | 1 + server.js | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 9b5b6aed9..92b50a630 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "body-parser": "^1.4.3", "bower": "^1.3.8", "browserify-express": "^0.1.4", + "compression": "^1.4.2", "errorhandler": "^1.1.1", "event-stream": "~3.1.5", "express": "^4.6.1", diff --git a/server.js b/server.js index 2f56c7597..e427926d6 100644 --- a/server.js +++ b/server.js @@ -43,6 +43,7 @@ var store = require('./lib/storage')(env, function() { var express = require('express'); +var compression = require('compression'); /////////////////////////////////////////////////// // api and json object variables @@ -66,9 +67,14 @@ var appInfo = software.name + ' ' + software.version; app.set('title', appInfo); app.enable('trust proxy'); // Allows req.secure test on heroku https connections. -//if (env.api_secret) { -// console.log("API_SECRET", env.api_secret); -//} +app.use(compression({filter: shouldCompress})); + +function shouldCompress(req, res) { + //TODO: return false here if we find a condition where we don't want to compress + // fallback to standard filter function + return compression.filter(req, res); +} + app.use('/api/v1', api); // pebble data From 206a8fd61cd97bcf16eae330e3ae08103fbd2826 Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Fri, 13 Mar 2015 20:03:05 -0700 Subject: [PATCH 08/11] fixed bug that caused BG color not to change on new data --- static/js/client.js | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/static/js/client.js b/static/js/client.js index 4db9acee5..32cabd881 100644 --- a/static/js/client.js +++ b/static/js/client.js @@ -307,7 +307,8 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; var nowDate = new Date(brushExtent[1] - THIRTY_MINS_IN_MS); - var currentBG = $('.bgStatus .currentBG') + var bgButton = $('.bgButton') + , currentBG = $('.bgStatus .currentBG') , currentDirection = $('.bgStatus .currentDirection') , currentDetails = $('.bgStatus .currentDetails') , lastEntry = $('#lastEntry'); @@ -324,6 +325,11 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; currentBG.text(scaleBg(value)); } + bgButton.removeClass('urgent warning inrange'); + if (!inRetroMode()) { + bgButton.addClass(sgvToColoredRange(value)); + } + currentBG.toggleClass('error-code', value < 39); currentBG.toggleClass('bg-limit', value == 39 || value > 400); } @@ -370,12 +376,6 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; } } - if (inRetroMode()) { - $('.bgButton').removeClass('urgent warning inrange'); - } else { - $('.bgButton').addClass(sgvToColoredRange(latestSGV.y)); - } - // predict for retrospective data // by changing lookback from 1 to 2, we modify the AR algorithm to determine its initial slope from 10m // of data instead of 5, which eliminates the incorrect and misleading predictions generated when @@ -1093,6 +1093,11 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; R2 = Math.sqrt(Math.max(carbs, insulin * CR)) / scale, R3 = R2 + 8 / scale; + if (isNaN(R1) || isNaN(R3) || isNaN(R3)) { + console.warn("Found NaN for treatment:", treatment); + return; + } + var arc_data = [ { 'element': '', 'color': 'white', 'start': -1.5708, 'end': 1.5708, 'inner': 0, 'outer': R1 }, { 'element': '', 'color': 'transparent', 'start': -1.5708, 'end': 1.5708, 'inner': R2, 'outer': R3 }, From bcd3fa021dd0ed888201e159ddf53c5f91079292 Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Fri, 13 Mar 2015 23:07:01 -0700 Subject: [PATCH 09/11] make sure the socket.io.js file that is sent to the client gets gzipped, etc --- lib/websocket.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/websocket.js b/lib/websocket.js index 0525a7018..161d239f8 100644 --- a/lib/websocket.js +++ b/lib/websocket.js @@ -34,7 +34,12 @@ var dir2Char = { patientData = []; function start ( ) { - io = require('socket.io').listen(server); + io = require('socket.io').listen(server, { + //these only effect the socket.io.js file that is sent to the client, but better than nothing + 'browser client minification': true, + 'browser client etag': true, + 'browser client gzip': true + }); } // get data from database and setup to update every minute function kickstart (fn) { From a1f963a351f19b1dab427bfa9dce6b119bffccea Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Sat, 14 Mar 2015 01:49:32 -0700 Subject: [PATCH 10/11] make bad data easier to find and prevent errors --- static/js/client.js | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/static/js/client.js b/static/js/client.js index 32cabd881..f4956a9c8 100644 --- a/static/js/client.js +++ b/static/js/client.js @@ -464,7 +464,14 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; function prepareFocusCircles(sel) { sel.attr('cx', function (d) { return xScale(d.date); }) - .attr('cy', function (d) { return yScale(d.sgv); }) + .attr('cy', function (d) { + if (isNaN(d.sgv)) { + console.warn("Bad Data: isNaN(sgv)", d); + return yScale(450); + } else { + return yScale(d.sgv); + } + }) .attr('fill', function (d) { return d.color; }) .attr('opacity', function (d) { return futureOpacity(d.date.getTime() - latestSGV.x); }) .attr('stroke-width', function (d) { if (d.type == 'mbg') return 2; else return 0; }) @@ -919,7 +926,14 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; function prepareContextCircles(sel) { sel.attr('cx', function (d) { return xScale2(d.date); }) - .attr('cy', function (d) { return yScale2(d.sgv); }) + .attr('cy', function (d) { + if (isNaN(d.sgv)) { + console.warn("Bad Data: isNaN(sgv)", d); + return yScale2(450); + } else { + return yScale2(d.sgv); + } + }) .attr('fill', function (d) { return d.color; }) .style('opacity', function (d) { return highlightBrushPoints(d) }) .attr('stroke-width', function (d) {if (d.type == 'mbg') return 2; else return 0; }) @@ -1094,7 +1108,7 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; R3 = R2 + 8 / scale; if (isNaN(R1) || isNaN(R3) || isNaN(R3)) { - console.warn("Found NaN for treatment:", treatment); + console.warn("Bad Data: Found isNaN value in treatment", treatment); return; } From b2782fc8823895c5c11dd4edca8170bae61e9eb7 Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Sat, 14 Mar 2015 02:02:43 -0700 Subject: [PATCH 11/11] group bad data warnings --- static/js/client.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/static/js/client.js b/static/js/client.js index f4956a9c8..2d5e06c5e 100644 --- a/static/js/client.js +++ b/static/js/client.js @@ -463,11 +463,12 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; }; function prepareFocusCircles(sel) { + var badData = []; sel.attr('cx', function (d) { return xScale(d.date); }) .attr('cy', function (d) { if (isNaN(d.sgv)) { - console.warn("Bad Data: isNaN(sgv)", d); - return yScale(450); + badData.push(d); + return yScale(scaleBg(450)); } else { return yScale(d.sgv); } @@ -481,6 +482,10 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; }) .attr('r', function (d) { return dotRadius(d.type); }); + if (badData.length > 0) { + console.warn("Bad Data: isNaN(sgv)", badData); + } + return sel; } @@ -925,11 +930,12 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; .data(data); function prepareContextCircles(sel) { + var badData = []; sel.attr('cx', function (d) { return xScale2(d.date); }) .attr('cy', function (d) { if (isNaN(d.sgv)) { - console.warn("Bad Data: isNaN(sgv)", d); - return yScale2(450); + badData.push(d); + return yScale2(scaleBg(450)); } else { return yScale2(d.sgv); } @@ -940,6 +946,10 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; .attr('stroke', function (d) { return 'white'; }) .attr('r', function(d) { if (d.type == 'mbg') return 4; else return 2;}); + if (badData.length > 0) { + console.warn("Bad Data: isNaN(sgv)", badData); + } + return sel; }