'use strict'; /* global Backbone, _, $, AmCharts */ /* global mainview */ /* jshint browser: true , devel: true*/ (function($) { var GraphView; var mqttConfig = { orgId: 'qz0da4', userName: 'a-qz0da4-dfwwdkmkzr', appKey: '9txJEf3Cjy7hkSOvkv', prefix: 'iot-2/type/mDot/id/' }; var sendAuthentication = function(xhr) { var user = 'a-qz0da4-dfwwdkmkzr'; // Your actual username var pass = '9txJEf3Cjy7hkSOvkv'; // Your actual password var token = user.concat(':', pass); xhr.setRequestHeader('Authorization', ('Basic '.concat(btoa(token)))); console.log('Auth:', ('Basic '.concat(btoa(token)))); }; var EventsModel = Backbone.Model.extend({ initialize: function() { _.bindAll(this, 'processAdded'); this.on('all', function(d) { console.log('model:all', d); this.temporal = {low: 0, high: 0}; }); this.on('remove', function() { $('#output').empty(); }); this.on('add', function() { this.processAdded(); }); }, processAdded: function() { console.log('Model:ProcessAdded'); var tempCollection = new Backbone.Collection(); _.invoke(DeviceCollection.toArray(), 'destroy'); this.temporal = {low: 0, high: 0}; _(this.get('events')).each(function(i) { if (this.temporal.low === 0 || this.temporal.low > i.timestamp) { this.temporal.low = i.timestamp; } if (this.temporal.high === 0 || this.temporal.high < i.timestamp) { this.temporal.high = i.timestamp; } tempCollection.add({ dt: i.timestamp, lux: i.lux, temp: i.temp, co2: i.co2, humid: i.humidity, noise: i.sound }); }, this); DeviceCollection.temporal = this.temporal; DeviceCollection.models = tempCollection.models; DeviceCollection.trigger('update'); console.log('temporal:', this.temporal); }, decoder: function(data) { var _obj = {}; var _data = window.atob(data).split(''); var bytes = _data.map(i => i.charCodeAt()); _obj.light = parseInt('0x' + ('0' + bytes[0]).substr(-2) + ('0' + bytes[1]).substr( -2)); _obj.co2 = parseInt(_data[2] + _data[3] + _data[4] + _data[5] + _data[6], 10); _obj.temp = (parseInt(_data[7] + _data[8] + _data[9] + _data[10] + _data[11], 10) - 1000) / 10; _obj.humid = (parseInt(_data[12] + _data[13] + _data[14] + _data[15] + _data[16], 10) / 10); _obj.noise = parseInt('0x' + ('0' + bytes[17]).substr(-2) + ('0' + bytes[18]).substr( -2)); _obj.binData = bytes; return _obj; }, dateTime: function($date) { var dateTime = new Date.create($date); var date = dateTime.format('{yyyy}-{MM}-{dd}'); var time = dateTime.format('{HH}:{mm}:{ss}'); return { dateTime: dateTime.format('{yyyy}-{MM}-{dd} {HH}:{mm}:{ss}'), date: date, time: time }; } }); var mDotCollection = Backbone.Collection.extend({ model: EventsModel, url: 'https://qz0da4.internetofthings.ibmcloud.com/api/v0002/historian/types/mDot/devices/', initialize: function() { this.on('update', function() { // Console.log('Collection:update',this); }); } }); var ItemView = Backbone.View.extend({ tagName: 'div', className: 'item mui-container', initialize: function() { this.template = _.template($('#item-template').html()); console.log('ItemView:Init'); // This.render(); }, render: function() { console.log('ItemView:Render'); _(this.model.events).each(function(i) { this.$el.append(this.template({item: i})); }, this); return this; } }); var MDOT = Backbone.View.extend({ model: EventsModel, el: $('#output'), events: { 'click button#refresh': 'refresh' }, initialize: function() { _.bindAll(this, 'render', 'refresh', 'update'); this.collection.bind('change reset add remove', this.render, this); //This.template = _.template($('#list-template').html()); this.template = _.template($('#loaded-template').html()); //This.render(); }, refresh: function() { }, update: function() { console.log('MDOT:update'); this.collection.each(function(model) { // Var events = model.get('events'); // var e = new ItemView({model: model.toJSON()}); }); }, render: function() { console.log('MDOT:render'); $('#output').empty(); var that = this; that.$el.append(this.template); /* Var that = this; this.$el.empty(); this.collection.each(function(model) { var events = model.get('events'); var e = new ItemView({model: model.toJSON()}).render().el; console.log('render:done:'); that.$el.append(e); }); console.log('bah');*/ return this; } }); var MainModel = Backbone.Model.extend({}); var MainView = Backbone.View.extend({ el: $('#main'), template: _.template($('#main-template').html()), events: { 'change select#device': 'changeDevice', 'click button#refresh': 'updateDevice', 'change input#from': 'changeDate', 'change input#to': 'changeDate', submit: function(event) {} }, initialize: function() { _.bindAll(this, 'render', 'changeDevice', 'updateDevice'); this.model.on('change', this.updateDevice); console.log('MainView:', this); this.render(); }, render: function() { $(this.el).html(this.template()); return this; }, changeDate: function(elm) { console.log('ChangeDate', elm); if (elm.currentTarget.valueAsDate === null) { this.model.unset(elm.currentTarget.id); } else { this.model.set(elm.currentTarget.id, elm.currentTarget.valueAsDate); } }, changeDevice: function() { var newDevice; console.log('MainView:ChangeDevice'); newDevice = this.$el.find('#device')[0].value; this.model.set('device', newDevice); }, updateDevice: function() { var fetchObj = {beforeSend: sendAuthentication}; var rangeObj = {start: null, end: null}; console.log('MainView:Updatedevice'); if (this.model.has('from') && this.model.has('to')) { rangeObj.start = this.model.get('from'); rangeObj.end = this.model.get('to'); fetchObj.data = $.param(rangeObj); } if (this.model.has('device')) { // FetchObj.data = $.param({key:'"'+ this.model.get('device') + '"'}); // this.collection.url = 'https://qz0da4.internetofthings.ibmcloud.com/api/v0002/historian/types/mDot/devices/' + this.model.get('device'); // this.collection.url = '/api/mdot/' + this.model.get('device'); this.collection.url = '/apiv2/mdot/' + this.model.get('device'); // this.collection.url = 'http://127.0.0.1:5984/mdot/_design/getDevice/_view/getDevice'; $('#output').empty(); this.collection.fetch(fetchObj); } else { console.error('Nothing to get!'); } } }); GraphView = Backbone.View.extend({ el: $('#graph'), template: _.template($('#AMChart-template').html()), initialize: function() { this.modes = ['', 'lux', 'temp', 'co2', 'humid', 'noise']; this.titles = [ '', 'Light Levels', 'Temperature', 'Co2 Levels', 'Humidity', 'Sound' ]; this.otherTitles = ['Co2 Levels', 'Humidity']; this.mode = 0; // Config AMChart this.chart = new AmCharts.AmStockChart(); this.categoryAxesSettings = new AmCharts.CategoryAxesSettings(); this.dataSet = new AmCharts.DataSet(); console.log('GraphView!'); _.bindAll(this, 'render', 'changeMode', 'updateGraph', 'setupChart'); this.collection.on('update', function(d) { if (this.mode > 0) { this.updateGraph(); } }, this); this.render(); // This.setupChart(); }, events: { 'change select#displaymode': 'changeMode' }, render: function() { $(this.el).html(this.template()); return this; }, setupChart: function() { console.log('chart:SetupChart'); this.categoryAxesSettings.minPeriod = 'mm'; this.chart.categoryAxesSettings = this.categoryAxesSettings; this.dataSet.color = '#b0de09'; this.chart.dataSets = [this.dataSet]; // This.chart.write('chartdiv'); }, changeMode: function() { this.mode = this.$el.find('#displaymode')[0].value; this.updateGraphV2(); console.log('new mode:', this.mode); }, makeAxis: function(params) { let title = params.title || 'Missing title'; let color = params.color || '#ff0000'; let position = params.position || 'left'; var newAxis = new AmCharts.ValueAxis(); newAxis.tickLength = 0; newAxis.axisAlpha = 0; newAxis.showFirstLabel = false; newAxis.showLastLabel = false; newAxis.title = title; newAxis.position = position; newAxis.gridColor = '#FFFFFF'; newAxis.axisColor = '#cccccc'; newAxis.color = color; return newAxis; }, makeGraph: function(params) { if (!params.hasOwnProperty('valueField')) { console.error('MakeGraph - missing required field'); } let lineColor = params.lineColor || 'rgba(46,255,0,1)'; let valueField = params.valueField; let title = params.title || 'Missing title'; let valueAxis = params.valueAxis || null; let labelPosition = params.labelPosition || 'left'; var graph = new AmCharts.AmGraph(); graph.lineColor = lineColor; graph.labelColor = lineColor; graph.valueField = valueField; graph.balloonText = title + ':[[value]]'; graph.title = title; if (valueAxis) { graph.valueAxis = valueAxis; } graph.legendValueText = '[[description]]/[[value]]'; graph.labelPosition = labelPosition; graph.showBalloon = true; return graph; }, doChartV2: function(chartData) { var self = this; self.chart = AmCharts.makeChart('chartdiv', { type: 'serial', theme: 'light', legend: { useGraphSettings: true }, color:'#ffffff', dataProvider: chartData, dataDateFormat: 'YYYY-MM-DDTHH:NN:SS.QQQ', synchronizeGrid: true, valueAxes: [{ id: 'lux', axisColor: '#FF6600', axisThickness: 2, axisAlpha: 1, position: 'left' }, { id: 'co2', axisColor: '#FCD202', axisThickness: 2, axisAlpha: 1, position: 'right' }, { id: 'temp', axisColor: '#B0DE09', axisThickness: 2, gridAlpha: 0, offset: 50, axisAlpha: 1, position: 'left' }, { id: 'humid', axisColor: '#ff0000', axisThickness: 2, axisAlpha: 1, offset: 50, position: 'right' }, { id: 'noise', axisColor: '#0000ff', axisThickness: 2, gridAlpha: 0, offset: 100, axisAlpha: 1, position: 'left' }], graphs: [{ valueAxis: 'lux', lineColor: '#FF6600', title: 'Light Level', valueField: 'lux', fillAlphas: 0 }, { valueAxis: 'co2', lineColor: '#FCD202', title: 'Co2', valueField: 'co2', fillAlphas: 0 }, { valueAxis: 'temp', lineColor: '#B0DE09', title: 'Temperature', valueField: 'temp', fillAlphas: 0 },{ valueAxis: 'humid', lineColor: '#ff0000', title: 'Humidity', valueField: 'humid', fillAlphas: 0 },{ valueAxis: 'noise', lineColor: '#0000ff', title: 'Sound', valueField: 'noise', fillAlphas: 0 }], chartScrollbar: {}, chartCursor: { cursorPosition: 'mouse' }, categoryField: 'date', categoryAxis: { minPeriod:'mm', parseDates: true, axisColor: '#ff0000', minorGridEnabled: true }, export: { enabled: true, position: 'bottom-right' } }); $('#chartdiv').empty(); self.chart.write('chartdiv'); }, doChart: function(mode, chartData) { var chartScrollbar; var chartCursor; var graph; var valueAxis; var categoryAxis; var self = this; var otherAxis; console.log(chartData); console.log('Doing chart now'); //Debugger; // SERIAL CHART self.chart = new AmCharts.AmSerialChart(); //"2016-08-10T23:04:31.000Z" self.chart.dataProvider = chartData; self.chart.dataDateFormat = 'YYYY-MM-DDTHH:NN:SS.QQQ'; self.chart.categoryField = 'date'; self.chart.color = '#ffffff'; self.chart.marginLeft = 0; // AXES // category categoryAxis = self.chart.categoryAxis; categoryAxis.parseDates = true; // As our data is date-based, we set parseDates to true categoryAxis.minPeriod = 'mm'; categoryAxis.gridAlpha = 0.2; categoryAxis.minorGridAlpha = 0; categoryAxis.axisAlpha = 0.5; categoryAxis.minorGridEnabled = true; categoryAxis.gridColor = '#FFFFFF'; categoryAxis.axisColor = '#cccccc'; categoryAxis.inside = true; valueAxis = self.makeAxis({ title: this.titles[this.mode], color: 'rgba(46,255,0,1)' }); self.chart.addValueAxis(valueAxis); if (mode > 5) { otherAxis = self.makeAxis({ title: this.otherTitles[mode - 6], color: 'rgba(0,191,255,1)', position: 'right' }); self.chart.addValueAxis(otherAxis); } graph = self.makeGraph({ valueField: 'value', title: this.titles[this.mode] }); self.chart.addGraph(graph); if (mode > 5) { var otherGraph = self.makeGraph({ lineColor: 'rgba(0,191,255,1)', valueField: 'valueB', title: this.otherTitles[mode - 6], valueAxis: otherAxis, labelPosition: 'right' }); self.chart.addGraph(otherGraph); } // CURSOR chartCursor = new AmCharts.ChartCursor(); chartCursor.valueLineEnabled = true; chartCursor.valueLineBalloonEnabled = true; self.chart.addChartCursor(chartCursor); // SCROLLBAR chartScrollbar = new AmCharts.ChartScrollbar(); chartScrollbar.graph = graph; chartScrollbar.position = 'bottom'; self.chart.addChartScrollbar(chartScrollbar); $('#chartdiv').empty(); self.chart.write('chartdiv'); }, updateGraphV2: function() { var self = this; var chartData = []; _(this.collection.models).each(function(i) { chartData.push({ date: i.get('dt'), co2: i.get('co2'), humid: i.get('humid'), lux: i.get('lux'), noise: i.get('noise'), temp: i.get('temp') }); }); console.log(chartData); self.doChartV2(chartData); }, updateGraph: function() { var self = this; let getMode = this.modes[this.mode]; var chartData = []; var temporal = {high: 0, low: 0}; var HL = {high: 0, low: 0}; var mode = parseInt(this.mode); console.log('mode:', mode, this.mode); _(this.collection.models).each(function(i) { var dt = i.get('dt'); var obj; var value, valueB; if (mode < 6) { value = i.get(getMode); } else { if (mode === 6) { value = i.get(this.modes[1]); valueB = i.get(this.modes[3]); } else { value = i.get(this.modes[2]); valueB = i.get(this.modes[4]); } } if (temporal.low === 0 || dt < temporal.low) { temporal.low = dt; } if (temporal.high === 0 || dt > temporal.high) { temporal.high = dt; } if (HL.low === 0 || value < HL.low) { HL.low = value; } if (HL.high === 0 || value > HL.high) { HL.high = value; } obj = {date: dt, value: value}; if (mode => 6) { obj.valueB = valueB; } chartData.push(obj); }, this); self.doChart(mode, chartData); } }); var DeviceCollection = new Backbone.Collection; var mdotCollection = new mDotCollection(); var mainSettings = new MainModel(); var mainview = new MainView({ collection: mdotCollection, model: mainSettings }); var mdot = new MDOT({collection: mdotCollection}); var grapher = new GraphView({collection: DeviceCollection}); })(jQuery);