<commit_before>angular.module('domegis')

.directive('contentThumbnail', [
  function() {
    return {
      restrict: 'E',
      scope: {
        content: '='
      },
      replace: true,
      template: '',
      link: function(scope, element, attrs) {
        scope.$watch('content', function(content) {
          if(content) {
            scope.src = arcgis.getApiRoot() + '/content/items/' + (content.id || content._id) + '/info/' + (content.data ? content.data.thumbnail : content.thumbnail);
          }
        }, true);
      }
    }
  }
])

.directive('domeMap', [
  '$q',
  '$http',
  '$state',
  '$filter',
  'Server',
  'Lang',
  function($q, $http, $state, $filter, Server, Lang) {
    return {
      restrict: 'A',
      scope: {
        views: '=domeMap',
        base: '=',
        feature: '=',
        preview: '='
      },
      replace: true,
      template: '

',
      link: function(scope, element, attrs) {

        var layerService = Server.service('layers');
        var viewService = Server.service('views');
        var previewService = Server.service('previews');

        var loc = getStateLoc();

        var center = [0,0];
        var zoom = 2;

        if(loc.length) {
          center = [loc[0], loc[1]];
          zoom = loc[2];
        }

        var map = L.map('map', {
          center: center,
          zoom: zoom,
          fullscreenControl: true,
          scrollWheelZoom: self == top
        });

        var downloadControl = L.control.downloadData();
        map.addControl(downloadControl);

        var legendControl = L.control.legend();
        map.addControl(legendControl);

        map.on('move', _.debounce(function() {
          $state.go($state.current.name, {loc: getLocStr()}, {notify: false})
        }, 400));

        var baseLayers = [];

        if(scope.base == 'infoamazonia') {

          baseLayers.push('http://{s}.tiles.mapbox.com/v3/infoamazonia.AndesAguaAmazonia_relevo_12AmzRaisg,infoamazonia.AndesAguaAmazonia_relevo_11AmzRaisg,infoamazonia.AndesAguaAmazonia_relevo1-10/{z}/{x}/{y}.png');

          baseLayers.push('http://{s}.tiles.mapbox.com/v3/infoamazonia.naturalEarth_baltimetria/{z}/{x}/{y}.png');

          baseLayers.push('http://{s}.tiles.mapbox.com/v3/infoamazonia.rivers/{z}/{x}/{y}.png');

          baseLayers.push('http://{s}.tiles.mapbox.com/v3/infoamazonia.AAA_pois,infoamazonia.osm-brasil/{z}/{x}/{y}.png');

        } else {

          baseLayers.push('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png');

        }

        baseLayers.forEach(function(url) {
          map.addLayer(L.tileLayer(url));
        });

        var layers = [];

        scope.$watch('views', updateLayers, true);

        scope.$on('updateLayers', function() {
          updateLayers(scope.views);
        });

        var mapBounds;

        function updateLayers(views) {
          layers.forEach(function(layer) {
            if(layer.grid)
              map.removeLayer(layer.grid);
            map.removeLayer(layer.tile);
            legendControl.removeLegend(layer.legend);
            downloadControl.removeLayer(layer.layerId);
          });
          layers = [];
          if(views && views.length) {
            var promises = [];
            views.forEach(function(id) {
              promises.push(Server.get(previewService, id));
            });
            $q.all(promises).then(function(data) {
              data.forEach(addView);
            });
          }
        }

        function addView(view) {
          var layer = {};
          layer.layerId = view.layerId;
          layer.id = view.id;
          var url = '/tiles/' + view.id + '/{z}/{x}/{y}.png';
          var gridUrl = '/tiles/' + view.id + '/{z}/{x}/{y}.grid.json';
          if(scope.preview) {
            url += '?preview=true&time=' + Date.now();
            gridUrl += '?preview=true&time=' + Date.now();
          }
          layer.tile = L.tileLayer(url);
          map.addLayer(layer.tile);
          if(view.fields && view.fields.length) {
            layer.grid = new L.UtfGrid(gridUrl, {
              useJsonP: false
            });
            layer.grid.on('click', function(e) {
              if(e.data) {
                var popup = L.popup()
                  .setLatLng(e.latlng)
                  .setContent(getTooltipHtml(e.data, e.target._dm_fields))
                  .openOn(map);
              }
            });
            map.addLayer(layer.grid);
          }
          layers.push(layer);

          var featureBounds = false;
          var doneFeature = $q.defer();

          // get feature bounds
          if(scope.feature && scope.feature.length && scope.feature[0] && scope.feature[1]) {
            $http.get('/layers/' + scope.feature[0] + '/feature/' + scope.feature[1]).then(function(res) {
              featureBounds = res.data.extents;
              map.fitBounds(parseBounds(featureBounds));
              doneFeature.resolve();
            }, function(err) {
              doneFeature.resolve()
            });
          } else {
            doneFeature.resolve();
          }

          doneFeature.promise.then(function() {
            Server.get(layerService, view.layerId).then(function(l) {
              if(!featureBounds) {
                if(!getStateLoc().length && l.extents) {
                  var bounds = parseBounds(l.extents);
                  if(mapBounds)
                    mapBounds.extend(bounds);
                  else
                    mapBounds = bounds;
                  map.fitBounds(mapBounds);
                }
              }
              layer.legend = getViewLegend(view, l);
              if(layer.grid) {
                layer.grid._dm_fields = l.fields;
              }
              legendControl.addLegend(layer.legend);
              downloadControl.addLayer({
                layerId: l.id,
                title: $filter('translate')(l.name),
                url: '/downloads/' + l.id + '.shp.zip'
              });
            });
          });
        }

        function getTooltipHtml(data, fields) {
          var html = '
';
          for(var key in data) {
            html += '
' + getLabel(key, fields) + '
';
            html += '
' + data[key] + '
';
          }
          html += '
';
          return html;
        }

        function getLabel(key, fields) {
          var lang = Lang.get();
          var field = _.find(fields, function(f) {
            return f.name == key;
          });
          return field.title[lang];
        }

        function parseBounds(pgBounds) {
          var bounds = pgBounds.replace('BOX(', '').replace(')', '').split(',');
          return L.latLngBounds(bounds[1].split(' ').reverse(), bounds[0].split(' ').reverse());
        }

        function getViewLegend(view, layer) {

          var layerType;

          var name = $filter('translate')(layer.name);

          var style = _.find(view.style, function(style, type) {
            var isStyle = layer.geometryType.toLowerCase().indexOf(type) !== -1;
            if(isStyle) {
              layerType = type;
              return true;
            } else {
              return false;
            }
          });

          var clss = '';
          if(layerType == 'polygon') {
            clss = 'sqr';
          } else if(layerType == 'point') {
            clss = 'pnt';
          } else if(layerType == 'linestring') {
            clss = 'ln';
          }

          var stroke = '0';
          var strokeColor = 'transparent';
          if(style.stroke) {
            stroke = style.stroke.width + 'px';
            strokeColor = style.stroke.color;
          }

          var bgColor = style.fill.color;
          var bgOpacity = style.fill.opacity;

          if(view.style.column) {
            if(view.style.type == 'category') {
              if(view.style.category[view.style.column.name]) {
                var catStyle = view.style.category[view.style.column.name];
                var columnName = _.find(layer.fields, function(field) {
                  return field.name == view.style.column.name;
                }).title[Lang.get()];
              }
            }
            if(view.style.type == 'choropleth') {
              if(view.style.choropleth && view.style.choropleth[view.style.column.name]) {
                var cPlethStyle = view.style.choropleth[view.style.column.name];
                var categories = quantiles(view.style.column.values, cPlethStyle.bucket_size || 3);
                var ramp = chroma.scale(cPlethStyle.scale).colors(categories.length).reverse();
                var columnName = _.find(layer.fields, function(field) {
                  return field.name == view.style.column.name;
                }).title[Lang.get()];
              }
            }
          }

          var html = '
';
          html += '
';
          if(view.style.type == 'simple') {
            html += '';
            html += name;
          } else if(view.style.type == 'category') {
            html += '' + name + '';
            if(columnName)
              html += '' + columnName + '';
            if(catStyle) {
              for(var name in catStyle) {
                html += '';
                html += '';
                html += name;
                html += '';
              }
            }
          } else if(view.style.type == 'choropleth') {
            html += '' + name + '';
            if(columnName)
              html += '' + columnName + '';
            html += '';
            if(categories) {
              categories.forEach(function(cat, i) {
                if(cat % 1 !== 0) {
                  cat = cat.toFixed(2);
                }
                html += '';
                html += '';
                html += '' + cat + '';
                html += '';
              });
            }
            html += '';
          }
          html += '
';
          html += '
';
          return html;
        }

        function getLocStr() {
          var center = map.getCenter();
          var zoom = map.getZoom();
          var loc = [];
          loc.push(center.lat);
          loc.push(center.lng);
          loc.push(zoom);
          return loc.join(',');
        }

        function getStateLoc() {
          if($state.params.loc)
            return $state.params.loc.split(',');
          else
            return [];
        }

      }
    }
  }
])

.directive('fixToBottom', [
  function() {
    return {
      restrict: 'AC',
      link: function(scope, element, attrs) {
        $(window).resize(function() {
          var top = $(element).offset().top;
          var height = $(window).height();
          $(element).height(height-top);
        });
        $(window).resize();
      }
    }
  }
]);
<commit_msg>support separate fill and stroke opacities for legend<commit_after>angular.module('domegis')

.directive('contentThumbnail', [
  function() {
    return {
      restrict: 'E',
      scope: {
        content: '='
      },
      replace: true,
      template: '',
      link: function(scope, element, attrs) {
        scope.$watch('content', function(content) {
          if(content) {
            scope.src = arcgis.getApiRoot() + '/content/items/' + (content.id || content._id) + '/info/' + (content.data ? content.data.thumbnail : content.thumbnail);
          }
        }, true);
      }
    }
  }
])

.directive('domeMap', [
  '$q',
  '$http',
  '$state',
  '$filter',
  'Server',
  'Lang',
  function($q, $http, $state, $filter, Server, Lang) {
    return {
      restrict: 'A',
      scope: {
        views: '=domeMap',
        base: '=',
        feature: '=',
        preview: '='
      },
      replace: true,
      template: '

',
      link: function(scope, element, attrs) {

        var layerService = Server.service('layers');
        var viewService = Server.service('views');
        var previewService = Server.service('previews');

        var loc = getStateLoc();

        var center = [0,0];
        var zoom = 2;

        if(loc.length) {
          center = [loc[0], loc[1]];
          zoom = loc[2];
        }

        var map = L.map('map', {
          center: center,
          zoom: zoom,
          fullscreenControl: true,
          scrollWheelZoom: self == top
        });

        var downloadControl = L.control.downloadData();
        map.addControl(downloadControl);

        var legendControl = L.control.legend();
        map.addControl(legendControl);

        map.on('move', _.debounce(function() {
          $state.go($state.current.name, {loc: getLocStr()}, {notify: false})
        }, 400));

        var baseLayers = [];

        if(scope.base == 'infoamazonia') {

          baseLayers.push('http://{s}.tiles.mapbox.com/v3/infoamazonia.AndesAguaAmazonia_relevo_12AmzRaisg,infoamazonia.AndesAguaAmazonia_relevo_11AmzRaisg,infoamazonia.AndesAguaAmazonia_relevo1-10/{z}/{x}/{y}.png');

          baseLayers.push('http://{s}.tiles.mapbox.com/v3/infoamazonia.naturalEarth_baltimetria/{z}/{x}/{y}.png');

          baseLayers.push('http://{s}.tiles.mapbox.com/v3/infoamazonia.rivers/{z}/{x}/{y}.png');

          baseLayers.push('http://{s}.tiles.mapbox.com/v3/infoamazonia.AAA_pois,infoamazonia.osm-brasil/{z}/{x}/{y}.png');

        } else {

          baseLayers.push('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png');

        }

        baseLayers.forEach(function(url) {
          map.addLayer(L.tileLayer(url));
        });

        var layers = [];

        scope.$watch('views', updateLayers, true);

        scope.$on('updateLayers', function() {
          updateLayers(scope.views);
        });

        var mapBounds;

        function updateLayers(views) {
          layers.forEach(function(layer) {
            if(layer.grid)
              map.removeLayer(layer.grid);
            map.removeLayer(layer.tile);
            legendControl.removeLegend(layer.legend);
            downloadControl.removeLayer(layer.layerId);
          });
          layers = [];
          if(views && views.length) {
            var promises = [];
            views.forEach(function(id) {
              promises.push(Server.get(previewService, id));
            });
            $q.all(promises).then(function(data) {
              data.forEach(addView);
            });
          }
        }

        function addView(view) {
          var layer = {};
          layer.layerId = view.layerId;
          layer.id = view.id;
          var url = '/tiles/' + view.id + '/{z}/{x}/{y}.png';
          var gridUrl = '/tiles/' + view.id + '/{z}/{x}/{y}.grid.json';
          if(scope.preview) {
            url += '?preview=true&time=' + Date.now();
            gridUrl += '?preview=true&time=' + Date.now();
          }
          layer.tile = L.tileLayer(url);
          map.addLayer(layer.tile);
          if(view.fields && view.fields.length) {
            layer.grid = new L.UtfGrid(gridUrl, {
              useJsonP: false
            });
            layer.grid.on('click', function(e) {
              if(e.data) {
                var popup = L.popup()
                  .setLatLng(e.latlng)
                  .setContent(getTooltipHtml(e.data, e.target._dm_fields))
                  .openOn(map);
              }
            });
            map.addLayer(layer.grid);
          }
          layers.push(layer);

          var featureBounds = false;
          var doneFeature = $q.defer();

          // get feature bounds
          if(scope.feature && scope.feature.length && scope.feature[0] && scope.feature[1]) {
            $http.get('/layers/' + scope.feature[0] + '/feature/' + scope.feature[1]).then(function(res) {
              featureBounds = res.data.extents;
              map.fitBounds(parseBounds(featureBounds));
              doneFeature.resolve();
            }, function(err) {
              doneFeature.resolve()
            });
          } else {
            doneFeature.resolve();
          }

          doneFeature.promise.then(function() {
            Server.get(layerService, view.layerId).then(function(l) {
              if(!featureBounds) {
                if(!getStateLoc().length && l.extents) {
                  var bounds = parseBounds(l.extents);
                  if(mapBounds)
                    mapBounds.extend(bounds);
                  else
                    mapBounds = bounds;
                  map.fitBounds(mapBounds);
                }
              }
              layer.legend = getViewLegend(view, l);
              if(layer.grid) {
                layer.grid._dm_fields = l.fields;
              }
              legendControl.addLegend(layer.legend);
              downloadControl.addLayer({
                layerId: l.id,
                title: $filter('translate')(l.name),
                url: '/downloads/' + l.id + '.shp.zip'
              });
            });
          });
        }

        function getTooltipHtml(data, fields) {
          var html = '
';
          for(var key in data) {
            html += '
' + getLabel(key, fields) + '
';
            html += '
' + data[key] + '
';
          }
          html += '
';
          return html;
        }

        function getLabel(key, fields) {
          var lang = Lang.get();
          var field = _.find(fields, function(f) {
            return f.name == key;
          });
          return field.title[lang];
        }

        function parseBounds(pgBounds) {
          var bounds = pgBounds.replace('BOX(', '').replace(')', '').split(',');
          return L.latLngBounds(bounds[1].split(' ').reverse(), bounds[0].split(' ').reverse());
        }

        function getViewLegend(view, layer) {

          var layerType;

          var name = $filter('translate')(layer.name);

          var style = _.find(view.style, function(style, type) {
            var isStyle = layer.geometryType.toLowerCase().indexOf(type) !== -1;
            if(isStyle) {
              layerType = type;
              return true;
            } else {
              return false;
            }
          });

          var clss = '';
          if(layerType == 'polygon') {
            clss = 'sqr';
          } else if(layerType == 'point') {
            clss = 'pnt';
          } else if(layerType == 'linestring') {
            clss = 'ln';
          }

          var stroke = '0';
          var strokeColor = 'transparent';
          if(style.stroke) {
            stroke = style.stroke.width + 'px';
            strokeColor = 'rgba(' + style.stroke.color + ', ' + style.stroke.opacity + ')';
          }

          var bgColor = 'rgba(' + style.fill.color + ', ' + style.fill.opacity + ')';

          if(view.style.column) {
            if(view.style.type == 'category') {
              if(view.style.category[view.style.column.name]) {
                var catStyle = view.style.category[view.style.column.name];
                var columnName = _.find(layer.fields, function(field) {
                  return field.name == view.style.column.name;
                }).title[Lang.get()];
              }
            }
            if(view.style.type == 'choropleth') {
              if(view.style.choropleth && view.style.choropleth[view.style.column.name]) {
                var cPlethStyle = view.style.choropleth[view.style.column.name];
                var categories = quantiles(view.style.column.values, cPlethStyle.bucket_size || 3);
                var ramp = chroma.scale(cPlethStyle.scale).colors(categories.length).reverse();
                var columnName = _.find(layer.fields, function(field) {
                  return field.name == view.style.column.name;
                }).title[Lang.get()];
              }
            }
          }

          var html = '
';
          html += '
';
          if(view.style.type == 'simple') {
            html += '';
            html += name;
          } else if(view.style.type == 'category') {
            html += '' + name + '';
            if(columnName)
              html += '' + columnName + '';
            if(catStyle) {
              for(var name in catStyle) {
                html += '';
                html += '';
                html += name;
                html += '';
              }
            }
          } else if(view.style.type == 'choropleth') {
            html += '' + name + '';
            if(columnName)
              html += '' + columnName + '';
            html += '';
            if(categories) {
              categories.forEach(function(cat, i) {
                if(cat % 1 !== 0) {
                  cat = cat.toFixed(2);
                }
                html += '';
                html += '';
                html += '' + cat + '';
                html += '';
              });
            }
            html += '';
          }
          html += '
';
          html += '
';
          return html;
        }

        function getLocStr() {
          var center = map.getCenter();
          var zoom = map.getZoom();
          var loc = [];
          loc.push(center.lat);
          loc.push(center.lng);
          loc.push(zoom);
          return loc.join(',');
        }

        function getStateLoc() {
          if($state.params.loc)
            return $state.params.loc.split(',');
          else
            return [];
        }

      }
    }
  }
])

.directive('fixToBottom', [
  function() {
    return {
      restrict: 'AC',
      link: function(scope, element, attrs) {
        $(window).resize(function() {
          var top = $(element).offset().top;
          var height = $(window).height();
          $(element).height(height-top);
        });
        $(window).resize();
      }
    }
  }
]);
<|endoftext|>


<commit_before>var formMixin = {

    data: function() {
        return {
            errors: new FormErrors(),
            loading: false,
            actionUrl: ''
        };
    },

    mounted: function() {
        var
            component = this,
            $form = $(this.$el);

        var $loaderLayer = $('<div>', {
            class: 'form-loading-layer',
            style: 'position:absolute; top:0; left:0; right:0; bottom:0; width:100%; height:100%; background:white; opacity:0.4; display:none'
        });

        $form.css('position', 'relative').append($loaderLayer);

        $form.submit(function() {
            component.errors.clear();
            component.send();

            return false;
        });
    },

    watch: {
        loading: function(state) {
            var $form = $(this.$el);

            $form.find('.form-loading-layer').toggle(state);
            $form.find(':input').prop('disabled', state);
        }
    },

    methods: {

        post: function (object, callback) {
            var component = this;

            this.postHandler(this.actionUrl, object, function(response) {
                if( ! response.notified && response.type) {
                    var type = response.type + 'FM';

                    noty( $.extend({}, APP.noti[type]('lg', 'full'), {
                        text: response.message,
                        layout: 'bottomRight'
                    }));
                }
                if(response.url) {
                    window.location.href = response.url;
                }

                if(callback) {
                    callback.apply(component, arguments);
                }
            });
        },

        postHandler: function(url, object, callback) {
            var component = this;

            this.loading = true;

            $.post(url, object)
                .always(function() {
                    component.loading = false
                })
                .done(function(response) {
                    if(callback) {
                        callback.apply(component, arguments);
                    }
                })
                .fail(function(response) {
                    component.errors.record(response.responseJSON);
                });
        }
    }

};
<commit_msg>CHG: properly getting error array for VUE form after upgrade to Laravel 5.5<commit_after>var formMixin = {

    data: function() {
        return {
            errors: new FormErrors(),
            loading: false,
            actionUrl: ''
        };
    },

    mounted: function() {
        var
            component = this,
            $form = $(this.$el);

        var $loaderLayer = $('<div>', {
            class: 'form-loading-layer',
            style: 'position:absolute; top:0; left:0; right:0; bottom:0; width:100%; height:100%; background:white; opacity:0.4; display:none'
        });

        $form.css('position', 'relative').append($loaderLayer);

        $form.submit(function() {
            component.errors.clear();
            component.send();

            return false;
        });
    },

    watch: {
        loading: function(state) {
            var $form = $(this.$el);

            $form.find('.form-loading-layer').toggle(state);
            $form.find(':input').prop('disabled', state);
        }
    },

    methods: {

        post: function (object, callback) {
            var component = this;

            this.postHandler(this.actionUrl, object, function(response) {
                if( ! response.notified && response.type) {
                    var type = response.type + 'FM';

                    noty( $.extend({}, APP.noti[type]('lg', 'full'), {
                        text: response.message,
                        layout: 'bottomRight'
                    }));
                }
                if(response.url) {
                    window.location.href = response.url;
                }

                if(callback) {
                    callback.apply(component, arguments);
                }
            });
        },

        postHandler: function(url, object, callback) {
            var component = this;

            this.loading = true;

            $.post(url, object)
                .always(function() {
                    component.loading = false
                })
                .done(function(response) {
                    if(callback) {
                        callback.apply(component, arguments);
                    }
                })
                .fail(function(response) {
                    component.errors.record(response.responseJSON.errors);
                });
        }
    }

};
<|endoftext|>


<commit_before>
/**
 * mongo-view.js
 **/

var App = Spine.Controller.sub({

  db: null,
  collection: null,
  item: null,

  // initialize app
  init: function(params) {
    var self = this;
    // setup routes
    this.routes({
      '/': function() {
        self.setupConnect()
      },
      '/database/disconnect': function() {
        self.disconnect();
      },
      '/database/disconnect/': function() {
        self.disconnect();
      },
      '/database/:database': function(params) {
        self.retrieveCollections(params.database)
      },
      '/database/:database/': function(params) {
        self.retrieveCollections(params.database)
      },
      '/database/:database/collection/:collection': function(params) {
        self.retrieveCollection(params.database, params.collection);
      },
      '/database/:database/collection/:collection/': function(params) {
        self.retrieveCollection(params.database, params.collection);
      },
      '/database/:database/collection/:collection/:id': function(params) {
        self.retrieveItem(params.database, params.collection, params.id);
      },
      '/database/:database/collection/:collection/:id/': function(params) {
        self.retrieveItem(params.database, params.collection, params.id);
      },
    });
    // setup routes
    Spine.Route.setup();
    // preserve html5 history
    Spine.Route.setup({
      history: true
    });
    // navigate via spine
    $.fn.navTo = function(path) {
      self.navigate(path);
    }
  },

  // clear content
  clear: function() {
    $('#content').html('');
  },

  // disconnect method
  disconnect: function() {
    var self = this;
    self.db = null;
    self.collection = null;
    self.item = null;
    $.get('/api/disconnect/', function(data) {
      if (data['message'] === 'disconnected') {
        self.navigate('/');
      };
    });
  },

  // render connect form partial
  setupConnect: function() {
    var self = this;
    self.clear();
    var json = { MONGO_DB : 'mongodb://localhost/test' };
    $.get('/partials/connect.html', function(template) {
      var html = $.mustache(template, json);
      $('#content').append(html);
      // connection form submit
      $('#connect-btn').click(function(e) {
        self.connect($('#connection-string').val());
      });
    });
  },

  // connect to mongo and initialize session
  connect: function(mongoString) {
    var self = this;
    $('#indicator h1').text('connecting to database...');
    $.get('/api/connect/', $('#connection-form').serialize(), function(data) {
      var db = data['db_name'];
      self.db = db;
      // mongodb breadcrumbs
      mongodbBreadcrumbs(self);
      var nextURL = '/database/' + db + '/';
      self.navigate(nextURL);
    });
  },

  // retrieve collections for db
  retrieveCollections: function(db) {
    var self = this;
    self.clear();
    $('#indicator h1').text('retrieving collections for ' + db);
    $.get('/api/database/' + db, function(data) {
      var howMany = data.length - 1;
      var json = {
        collections : data,
        howMany     : (howMany > 0) ? howMany : 'none',
        linker      : function() {
          if (this.count === undefined) {
            return;
          };
          var HTML = '';
          // link
          var navToLink = '/database/' + db + '/collection/' + this.name + '/';
          // build HTML
          HTML += '';
          HTML += this.name + '(' + this.count + ')';
          return HTML;
        }
      };
      $.get('/partials/collections.html', function(template) {
        var html = $.mustache(template, json);
        $('#content').append(html);
      });
    });
  },

  // retrieve single collection
  retrieveCollection: function(db, collection) {
    var self = this;
    self.collection = collection;
    self.clear();
    // mongodb breadcrumbs
    mongodbBreadcrumbs(self);
    $('#indicator h1').text('retrieving collection: ' + collection);
    $.get('/api/database/' + db + '/collection/' + collection, function(data) {
      var json = {
        howMany        : (data.length > 0) ? data.length : 'none',
        collection     : data,
        collectionName : collection,
        linker      : function() {
          return '/database/' + db + '/collection/' + collection + '/' + this._id;
        }
      };
      $.get('/partials/collection.html', function(template) {
        var html = $.mustache(template, json);
        $('#content').append(html);
      });
    });
  },

  // retrieve single collection
  retrieveItem: function(db, collection, id) {
    var self = this;
    self.item = id;
    // mongodb breadcrumbs
    mongodbBreadcrumbs(self);
    self.clear();
    $('#indicator h1').text('retrieving item: ' + id);
    $.get('/api/database/' + db + '/collection/' + collection + '/' + id, function(data) {
      var json = {
        id       : id,
        item     : data,
        collectionName : collection,
        generateRow : function() {
          var HTML = '';
          var props = this;
          var orderedProps = {};
          // push _id to the top
          orderedProps['_id'] = props['_id'];
          for (key in props) {
            orderedProps[key] = props[key];
          };
          for (key in orderedProps) {
            HTML += '
';
            HTML += '

';
            HTML += key;
            HTML += '

'
            HTML += '

';
            if (typeof(props[key]) === 'number') {
              HTML += '' + props[key] + '';
            } else if (typeof(props[key]) === 'string') {
              if (key === '_id') {
                HTML += '$' + props[key] + '';
              } else {
                HTML += '"' + props[key] + '"';
              };
            };
            //html += (props[key] === '_id') ? '$' + props[key] : props[key];
            HTML += '

';
            HTML += '
';
          };
          return HTML;
        }
      };
      $.get('/partials/item.html', function(template) {
        var html = $.mustache(template, json);
        $('#content').append(html);
      });
    });
  }

});

/**
 * @method mongodbBreadcrumbs
 * @param spineInstance
 * @param db
 * @param collection
 * @param item
 **/

function mongodbBreadcrumbs(self) {
  console.log('mongodbBreadcrumbs!');
  // current db
  if (self.db) {
    var db = self.db;
    $('#current-db a').text(db);
    $('#current-db a').click(function() {
      $('#current-collection').hide(350);
      $('#current-item').hide(350);
      self.navigate('/database/' + db + '/');
    });
    $('#current-db').fadeIn(350);
  };
  // current collection
  if (self.collection) {
    var collection = self.collection;
    $('#current-collection a').text(collection);
    $('#current-collection a').click(function() {
      $('#current-item').hide(350);
      self.navigate('/database/' + db + '/' + collection + '/');
    });
    $('#current-collection').fadeIn(350);
  };
  // current item
  if (self.item) {
    var item = self.item;
    $('#current-item a').text('$' + item);
    $('#current-item a').click(function() {
      self.navigate('/database/' + db + '/' + collection + '/' + item);
    });
    $('#current-item').fadeIn(350);
  };
};

$(document).ready(function() {

  // initialize app
  var app = new App({
    start : new Date().getTime()
  });

  // setup ajax indicator text
  $('body').append($('

'));
  $('#indicator').append('

');

  // setup ajax
  $(document).ajaxStart(function() {
    $('#indicator').fadeIn(750);
  }).ajaxStop(function() {
    $('#indicator').fadeOut(750);
  }).ajaxError(function(e, jqxhr, settings, message) {
    var suppressErrorAlert = true;
    if (jqxhr.status === 599) {
      window.location = '/';
      return suppressErrorAlert;
    } else {
      window.location = '/';
      return suppressErrorAlert;
    };
  });

});

/* EOF */<commit_msg>[minor] fix for breadcrumb track backs<commit_after>
/**
 * mongo-view.js
 **/

var App = Spine.Controller.sub({

  db: null,
  collection: null,
  item: null,

  // initialize app
  init: function(params) {
    var self = this;
    // setup routes
    this.routes({
      '/': function() {
        self.setupConnect()
      },
      '/database/disconnect': function() {
        self.disconnect();
      },
      '/database/disconnect/': function() {
        self.disconnect();
      },
      '/database/:database': function(params) {
        self.retrieveCollections(params.database)
      },
      '/database/:database/': function(params) {
        self.retrieveCollections(params.database)
      },
      '/database/:database/collection/:collection': function(params) {
        self.retrieveCollection(params.database, params.collection);
      },
      '/database/:database/collection/:collection/': function(params) {
        self.retrieveCollection(params.database, params.collection);
      },
      '/database/:database/collection/:collection/:id': function(params) {
        self.retrieveItem(params.database, params.collection, params.id);
      },
      '/database/:database/collection/:collection/:id/': function(params) {
        self.retrieveItem(params.database, params.collection, params.id);
      },
    });
    // setup routes
    Spine.Route.setup();
    // preserve html5 history
    Spine.Route.setup({
      history: true
    });
    // navigate via spine
    $.fn.navTo = function(path) {
      self.navigate(path);
    }
  },

  // clear content
  clear: function() {
    $('#content').html('');
  },

  // disconnect method
  disconnect: function() {
    var self = this;
    self.db = null;
    self.collection = null;
    self.item = null;
    $.get('/api/disconnect/', function(data) {
      if (data['message'] === 'disconnected') {
        self.navigate('/');
      };
    });
  },

  // render connect form partial
  setupConnect: function() {
    var self = this;
    self.clear();
    var json = { MONGO_DB : 'mongodb://localhost/test' };
    $.get('/partials/connect.html', function(template) {
      var html = $.mustache(template, json);
      $('#content').append(html);
      // connection form submit
      $('#connect-btn').click(function(e) {
        self.connect($('#connection-string').val());
      });
    });
  },

  // connect to mongo and initialize session
  connect: function(mongoString) {
    var self = this;
    $('#indicator h1').text('connecting to database...');
    $.get('/api/connect/', $('#connection-form').serialize(), function(data) {
      var db = data['db_name'];
      self.db = db;
      // mongodb breadcrumbs
      mongodbBreadcrumbs(self);
      var nextURL = '/database/' + db + '/';
      self.navigate(nextURL);
    });
  },

  // retrieve collections for db
  retrieveCollections: function(db) {
    var self = this;
    self.clear();
    $('#indicator h1').text('retrieving collections for ' + db);
    $.get('/api/database/' + db, function(data) {
      var howMany = data.length - 1;
      var json = {
        collections : data,
        howMany     : (howMany > 0) ? howMany : 'none',
        linker      : function() {
          if (this.count === undefined) {
            return;
          };
          var HTML = '';
          // link
          var navToLink = '/database/' + db + '/collection/' + this.name + '/';
          // build HTML
          HTML += '';
          HTML += this.name + '(' + this.count + ')';
          return HTML;
        }
      };
      $.get('/partials/collections.html', function(template) {
        var html = $.mustache(template, json);
        $('#content').append(html);
      });
    });
  },

  // retrieve single collection
  retrieveCollection: function(db, collection) {
    var self = this;
    self.collection = collection;
    self.clear();
    // mongodb breadcrumbs
    mongodbBreadcrumbs(self);
    $('#indicator h1').text('retrieving collection: ' + collection);
    $.get('/api/database/' + db + '/collection/' + collection, function(data) {
      var json = {
        howMany        : (data.length > 0) ? data.length : 'none',
        collection     : data,
        collectionName : collection,
        linker      : function() {
          return '/database/' + db + '/collection/' + collection + '/' + this._id;
        }
      };
      $.get('/partials/collection.html', function(template) {
        var html = $.mustache(template, json);
        $('#content').append(html);
      });
    });
  },

  // retrieve single collection
  retrieveItem: function(db, collection, id) {
    var self = this;
    self.item = id;
    // mongodb breadcrumbs
    mongodbBreadcrumbs(self);
    self.clear();
    $('#indicator h1').text('retrieving item: ' + id);
    $.get('/api/database/' + db + '/collection/' + collection + '/' + id, function(data) {
      var json = {
        id       : id,
        item     : data,
        collectionName : collection,
        generateRow : function() {
          var HTML = '';
          var props = this;
          var orderedProps = {};
          // push _id to the top
          orderedProps['_id'] = props['_id'];
          for (key in props) {
            orderedProps[key] = props[key];
          };
          for (key in orderedProps) {
            HTML += '
';
            HTML += '

';
            HTML += key;
            HTML += '

'
            HTML += '

';
            if (typeof(props[key]) === 'number') {
              HTML += '' + props[key] + '';
            } else if (typeof(props[key]) === 'string') {
              if (key === '_id') {
                HTML += '$' + props[key] + '';
              } else {
                HTML += '"' + props[key] + '"';
              };
            };
            //html += (props[key] === '_id') ? '$' + props[key] : props[key];
            HTML += '

';
            HTML += '
';
          };
          return HTML;
        }
      };
      $.get('/partials/item.html', function(template) {
        var html = $.mustache(template, json);
        $('#content').append(html);
      });
    });
  }

});

/**
 * @method mongodbBreadcrumbs
 * @param spineInstance
 * @param db
 * @param collection
 * @param item
 **/

function mongodbBreadcrumbs(self) {
  console.log('mongodbBreadcrumbs!');
  // current db
  if (self.db) {
    var db = self.db;
    $('#current-db a').text(db);
    $('#current-db a').click(function() {
      $('#current-collection').hide(350);
      $('#current-item').hide(350);
      self.collection = null;
      self.item = null;
      self.navigate('/database/' + db + '/');
    });
    $('#current-db').fadeIn(350);
  };
  // current collection
  if (self.collection) {
    var collection = self.collection;
    $('#current-collection a').text(collection);
    $('#current-collection a').click(function() {
      $('#current-item').hide(350);
      self.item = null;
      self.navigate('/database/' + db + '/' + collection + '/');
    });
    $('#current-collection').fadeIn(350);
  };
  // current item
  if (self.item) {
    var item = self.item;
    $('#current-item a').text('$' + item);
    $('#current-item a').click(function() {
      self.navigate('/database/' + db + '/' + collection + '/' + item);
    });
    $('#current-item').fadeIn(350);
  };
};

$(document).ready(function() {

  // initialize app
  var app = new App({
    start : new Date().getTime()
  });

  // setup ajax indicator text
  $('body').append($('

'));
  $('#indicator').append('

');

  // setup ajax
  $(document).ajaxStart(function() {
    $('#indicator').fadeIn(750);
  }).ajaxStop(function() {
    $('#indicator').fadeOut(750);
  }).ajaxError(function(e, jqxhr, settings, message) {
    var suppressErrorAlert = true;
    if (jqxhr.status === 599) {
      window.location = '/';
      return suppressErrorAlert;
    } else {
      window.location = '/';
      return suppressErrorAlert;
    };
  });

});

/* EOF */<|endoftext|>


<commit_before>if( document.referrer ) {
    document.write( '<'+'img src="http://rome.purepistos.net:8016/track?r=' + escape( document.referrer ) + '" style="float:left;" width="1" height="1"/>');
}<commit_msg>Added location tracking, too.<commit_after>if( document.referrer ) {
    document.write(
        '<'+'img src="http://rome.purepistos.net:8016/track?' +
        'r=' + escape( document.referrer ) +
        '&l=' + escape( document.location ) +
        '" style="float:left;" width="1" height="1"/>'
    );
}<|endoftext|>


<commit_before>/* global bundle, $ */

var d3 = require("d3");

var COLOR_TABLE = [
    "#C8D2D9", "#97ABB8", "#FFBEB9", "#FFD1CE"
];

/**
 * updateGraph
 *
 * Update the graph with some new data and remove the old one.
 *
 * @newData: New tuples of data to update the graph with
 */
function updateGraph(newData) {
  var svg;

  /* The individual points of data, not including labels */
  var dataPoints = newData.map(function onEachDataPoint(w) {
    return w.value;
  });

  /* Drop any existing SVG elements */
  Array.prototype.forEach.call(document.getElementsByClassName("chart"),
                               function dropInnerHTMLOf(element) {
                                 /* Drop everything inside this chart */
                                 element.innerHTML = "";  // eslint-disable-line no-param-reassign
                               });

  svg = d3.select("div.chart")
          .append("svg")
          .attr("class", "svgchart")
          .attr("width", function computeWidth() {
            return this.parentNode.clientWidth * 0.80;
          })
          .attr("height", function computeHeight() {
            return this.parentNode.clientHeight * 0.80;
          })
          .attr("style", function computeTransform() {
            var x = this.parentNode.clientWidth * 0.10;
            var y = this.parentNode.clientHeight * 0.10;
            return ["transform: translate(", x, "px,", y, "px", ")"].join("");
          });

  newData.map(function forEachDataPoint(dataPoint, index) {
    var g = svg.append("g")
               .attr("transform", function computeBarY(d) {
                 var chartHeight = this.parentNode.clientHeight;
                 var barSpacing = 10;
                 var barHeight = ((chartHeight - (barSpacing *
                                                  newData.length)) /
                                  newData.length);

                 var y = (index * barSpacing) + (index * barHeight);
                 return "translate(0.0, " + y + ")";
               });
    g.append("rect")
     .attr("width", function computeBarWidth() {
       var parentWidth = this.parentNode.parentNode.clientWidth;
       var x = d3.scaleLinear().domain([0, d3.max(dataPoints)])
                               .range([0, parentWidth]);
       return x(dataPoint.value);
     })
     .attr("height", function computeBarHeight() {
       var chartHeight = this.parentNode.parentNode.clientHeight;
       var barSpacing = 10;
       return ((chartHeight - (barSpacing * newData.length)) /
               newData.length);
     })
     .attr("rx", "15")
     .attr("ry", "15")
     .attr("fill", function() {
       return COLOR_TABLE[index % COLOR_TABLE.length];
     });
   g.append("text")
    .attr("fill", function() {
      return "#ffffff";
    })
    .text(function() {
      return dataPoint.name  ;
    })
    .attr("y", function() {
      var chartHeight = this.parentNode.parentNode.clientHeight;
      var barSpacing = 10;
      var textHeight = 15;
      return ((chartHeight - (barSpacing * newData.length)) /
              newData.length) / 2 + (textHeight / 2);
    })
    .attr("x", function() {
      return 10;
    });
  });
}

/**
 * postGraphUpdateRequest
 *
 * Post a request to the server to get a new graph.
 *
 * @name The chart name to fetch.
 */
function postGraphUpdateRequest(name) {
  $.ajax({
    url: "/get_bar_chart",
    data: {
      name: name
    },
    success: function onXHRSuccess(data) {
      updateGraph(data.data);
    }
  });
}

document.addEventListener("DOMContentLoaded", function onDOMLoaded() {
  $("#chartSelectionDropdown ul li a").click(function onDropdownClick(event) {
    var div = $(this).parent().parent().parent();
    var button = div.find("button");

    button.html(this.text + " ");
    div.removeClass("open");
    event.preventDefault();

    postGraphUpdateRequest($(this).attr("data-selection-id"));
    return false;
  });
});
<commit_msg>retraction: Some animations<commit_after>/* global bundle, $ */

var d3 = require("d3");

var COLOR_TABLE = [
    "#C8D2D9", "#97ABB8", "#FFBEB9", "#FFD1CE"
];

/**
 * updateGraph
 *
 * Update the graph with some new data and remove the old one.
 *
 * @newData: New tuples of data to update the graph with
 */
function updateGraph(newData) {
  var svg;

  /* The individual points of data, not including labels */
  var dataPoints = newData.map(function onEachDataPoint(w) {
    return w.value;
  });

  /* Drop any existing SVG elements */
  Array.prototype.forEach.call(document.getElementsByClassName("chart"),
                               function dropInnerHTMLOf(element) {
                                 /* Drop everything inside this chart */
                                 element.innerHTML = "";  // eslint-disable-line no-param-reassign
                               });

  svg = d3.select("div.chart")
          .append("svg")
          .attr("class", "svgchart")
          .attr("width", function computeWidth() {
            return this.parentNode.clientWidth * 0.80;
          })
          .attr("height", function computeHeight() {
            return this.parentNode.clientHeight * 0.80;
          })
          .attr("style", function computeTransform() {
            var x = this.parentNode.clientWidth * 0.10;
            var y = this.parentNode.clientHeight * 0.10;
            return ["transform: translate(", x, "px,", y, "px", ")"].join("");
          });

  newData.map(function forEachDataPoint(dataPoint, index) {
    var g = svg.append("g")
               .attr("transform", function computeBarY(d) {
                 var chartHeight = this.parentNode.clientHeight;
                 var barSpacing = 10;
                 var barHeight = ((chartHeight - (barSpacing *
                                                  newData.length)) /
                                  newData.length);

                 var y = (index * barSpacing) + (index * barHeight);
                 return "translate(0.0, " + y + ")";
               });
    g.append("rect")
     .attr("height", function computeBarHeight() {
       var chartHeight = this.parentNode.parentNode.clientHeight;
       var barSpacing = 10;
       return ((chartHeight - (barSpacing * newData.length)) /
               newData.length);
     })
     .transition()
     .delay(index * 50)
     .duration(750)
     .ease(d3.easeElastic.period(0.4))
     .attr("width", function computeBarWidth() {
       var parentWidth = this.parentNode.parentNode.clientWidth;
       var x = d3.scaleLinear().domain([0, d3.max(dataPoints)])
                               .range([0, parentWidth]);
       return x(dataPoint.value);
     })
     .attr("rx", "15")
     .attr("ry", "15")
     .attr("fill", function() {
       return COLOR_TABLE[index % COLOR_TABLE.length];
     });
   g.append("text")
    .attr("fill", function() {
      return "#ffffff";
    })
    .text(function() {
      return dataPoint.name  ;
    })
    .attr("y", function() {
      var chartHeight = this.parentNode.parentNode.clientHeight;
      var barSpacing = 10;
      var textHeight = 15;
      return ((chartHeight - (barSpacing * newData.length)) /
              newData.length) / 2 + (textHeight / 2);
    })
    .attr("x", function() {
      return 10;
    });
  });
}

/**
 * postGraphUpdateRequest
 *
 * Post a request to the server to get a new graph.
 *
 * @name The chart name to fetch.
 */
function postGraphUpdateRequest(name) {
  $.ajax({
    url: "/get_bar_chart",
    data: {
      name: name
    },
    success: function onXHRSuccess(data) {
      updateGraph(data.data);
    }
  });
}

document.addEventListener("DOMContentLoaded", function onDOMLoaded() {
  $("#chartSelectionDropdown ul li a").click(function onDropdownClick(event) {
    var div = $(this).parent().parent().parent();
    var button = div.find("button");

    button.html(this.text + " ");
    div.removeClass("open");
    event.preventDefault();

    postGraphUpdateRequest($(this).attr("data-selection-id"));
    return false;
  });
});
<|endoftext|>


<commit_before>/* global window, document, _, $, mapboxgl */
/* eslint no-var: "off", prefer-arrow-callback: "off", no-unused-vars: "off" */

const maps = {};

function formatRoute(route) {
  const html = route.route_url
    ? $('<a>').attr('href', route.route_url)
    : $('<div>');

  html.addClass('route-item text-sm mb-2');

  if (route.route_color) {
    $('<div>')
      .addClass('route-color-swatch mr-2 flex-shrink-0')
      .css('backgroundColor', route.route_color)
      .appendTo(html);
  }

  $('<span>')
    .text(`${route.route_short_name} ${route.route_long_name}`)
    .appendTo(html);

  return html.prop('outerHTML');
}

function formatRoutePopup(features) {
  const html = $('<div>');

  if (features.length > 1) {
    $('<div>').addClass('popup-title').text('Routes').appendTo(html);
  }

  $(html).append(features.map((feature) => formatRoute(feature.properties)));

  return html.prop('outerHTML');
}

function getBounds(geojson) {
  const bounds = new mapboxgl.LngLatBounds();
  for (const feature of geojson.features) {
    if (feature.geometry.type === 'Point') {
      bounds.extend(feature.geometry.coordinates);
    } else if (feature.geometry.type === 'LineString') {
      for (const coordinate of feature.geometry.coordinates) {
        bounds.extend(coordinate);
      }
    }
  }

  return bounds;
}

function createSystemMap(id, geojson) {
  const defaultRouteColor = '#FF4728';
  const routeLayerIds = [];
  const routeBackgroundLayerIds = [];

  if (!geojson || geojson.features.length === 0) {
    $('#' + id).hide();
    return false;
  }

  const bounds = getBounds(geojson);
  const map = new mapboxgl.Map({
    container: id,
    style: 'mapbox://styles/mapbox/light-v10',
    center: bounds.getCenter(),
    zoom: 12,
  });
  const routes = {};

  for (const feature of geojson.features) {
    routes[feature.properties.route_id] = feature.properties;
  }

  map.scrollZoom.disable();
  map.addControl(new mapboxgl.NavigationControl());

  map.on('load', () => {
    map.fitBounds(bounds, {
      padding: 20,
      duration: 0,
    });

    // Find the index of the first symbol layer in the map style
    let firstSymbolId;
    for (const layer of map.getStyle().layers) {
      if (layer.type === 'symbol') {
        firstSymbolId = layer.id;
        break;
      }
    }

    // Add white outlines to routes first
    for (const routeId of Object.keys(routes)) {
      routeBackgroundLayerIds.push(`${routeId}outline`);
      map.addLayer(
        {
          id: `${routeId}outline`,
          type: 'line',
          source: {
            type: 'geojson',
            data: geojson,
          },
          paint: {
            'line-color': '#FFFFFF',
            'line-opacity': 1,
            'line-width': 6,
          },
          layout: {
            'line-join': 'round',
            'line-cap': 'round',
          },
          filter: ['==', 'route_id', routeId],
        },
        firstSymbolId
      );
    }

    // Add route lines next
    for (const routeId of Object.keys(routes)) {
      routeLayerIds.push(routeId);
      const routeColor = routes[routeId].route_color || defaultRouteColor;
      map.addLayer(
        {
          id: routeId,
          type: 'line',
          source: {
            type: 'geojson',
            data: geojson,
          },
          paint: {
            'line-color': routeColor,
            'line-opacity': 1,
            'line-width': 2,
          },
          layout: {
            'line-join': 'round',
            'line-cap': 'round',
          },
          filter: ['==', 'route_id', routeId],
        },
        firstSymbolId
      );
    }

    map.on('mousemove', (event) => {
      const features = map.queryRenderedFeatures(event.point, {
        layers: [...routeLayerIds, ...routeBackgroundLayerIds],
      });
      if (features.length > 0) {
        map.getCanvas().style.cursor = 'pointer';
        highlightRoutes(
          _.uniq(features.map((feature) => feature.properties.route_id))
        );
      } else {
        map.getCanvas().style.cursor = '';
        unHighlightRoutes();
      }
    });

    map.on('click', (event) => {
      // Set bbox as 5px reactangle area around clicked point
      const bbox = [
        [event.point.x - 5, event.point.y - 5],
        [event.point.x + 5, event.point.y + 5],
      ];
      const features = map.queryRenderedFeatures(bbox, {
        layers: routeLayerIds,
      });

      if (!features || features.length === 0) {
        return;
      }

      const routeFeatures = _.orderBy(
        _.uniqBy(features, (feature) => feature.properties.route_short_name),
        (feature) => Number.parseInt(feature.properties.route_short_name, 10)
      );

      new mapboxgl.Popup()
        .setLngLat(event.lngLat)
        .setHTML(formatRoutePopup(routeFeatures))
        .addTo(map);
    });

    function highlightRoutes(routeIds, zoom) {
      for (const layerId of routeBackgroundLayerIds) {
        const color = routeIds.includes(layerId.replace(/outline/, ''))
          ? '#FFFD7E'
          : '#FFFFFF';
        const width = routeIds.includes(layerId.replace(/outline/, ''))
          ? 12
          : 6;
        map.setPaintProperty(layerId, 'line-color', color);
        map.setPaintProperty(layerId, 'line-width', width);
      }

      const highlightedFeatures = geojson.features.filter((feature) =>
        routeIds.includes(feature.properties.route_id)
      );

      if (highlightedFeatures.length === 0) {
        return;
      }

      if (zoom) {
        const zoomBounds = getBounds({
          features: highlightedFeatures,
        });
        map.fitBounds(zoomBounds, {
          padding: 20,
        });
      }
    }

    function unHighlightRoutes(zoom) {
      for (const layerId of routeBackgroundLayerIds) {
        map.setPaintProperty(layerId, 'line-color', '#FFFFFF');
        map.setPaintProperty(layerId, 'line-width', 6);
      }

      if (zoom) {
        map.fitBounds(bounds);
      }
    }

    // On table hover, highlight route on map
    $(() => {
      $('.overview-list a').hover((event) => {
        const routeIdString = $(event.target).parents('a').data('route-ids');
        if (routeIdString) {
          const routeIds = routeIdString.toString().split(',');
          highlightRoutes(routeIds, true);
        }
      });

      $('.overview-list').hover(
        () => {},
        () => unHighlightRoutes(true)
      );
    });
  });

  maps[id] = map;
}
<commit_msg>Add route labels to system map<commit_after>/* global window, document, _, $, mapboxgl */
/* eslint no-var: "off", prefer-arrow-callback: "off", no-unused-vars: "off" */

const maps = {};

function formatRoute(route) {
  const html = route.route_url
    ? $('<a>').attr('href', route.route_url)
    : $('<div>');

  html.addClass('route-item text-sm mb-2');

  if (route.route_color) {
    $('<div>')
      .addClass('route-color-swatch mr-2 flex-shrink-0')
      .css('backgroundColor', route.route_color)
      .appendTo(html);
  }

  $('<span>')
    .text(`${route.route_short_name} ${route.route_long_name}`)
    .appendTo(html);

  return html.prop('outerHTML');
}

function formatRoutePopup(features) {
  const html = $('<div>');

  if (features.length > 1) {
    $('<div>').addClass('popup-title').text('Routes').appendTo(html);
  }

  $(html).append(features.map((feature) => formatRoute(feature.properties)));

  return html.prop('outerHTML');
}

function getBounds(geojson) {
  const bounds = new mapboxgl.LngLatBounds();
  for (const feature of geojson.features) {
    if (feature.geometry.type === 'Point') {
      bounds.extend(feature.geometry.coordinates);
    } else if (feature.geometry.type === 'LineString') {
      for (const coordinate of feature.geometry.coordinates) {
        bounds.extend(coordinate);
      }
    }
  }

  return bounds;
}

function createSystemMap(id, geojson) {
  const defaultRouteColor = '#FF4728';
  const routeLayerIds = [];
  const routeBackgroundLayerIds = [];

  if (!geojson || geojson.features.length === 0) {
    $('#' + id).hide();
    return false;
  }

  const bounds = getBounds(geojson);
  const map = new mapboxgl.Map({
    container: id,
    style: 'mapbox://styles/mapbox/light-v10',
    center: bounds.getCenter(),
    zoom: 12,
  });
  const routes = {};

  for (const feature of geojson.features) {
    routes[feature.properties.route_id] = feature.properties;
  }

  map.scrollZoom.disable();
  map.addControl(new mapboxgl.NavigationControl());

  map.on('load', () => {
    map.fitBounds(bounds, {
      padding: 20,
      duration: 0,
    });

    // Find the index of the first symbol layer in the map style
    let firstSymbolId;
    for (const layer of map.getStyle().layers) {
      if (layer.type === 'symbol') {
        firstSymbolId = layer.id;
        break;
      }
    }

    // Add white outlines to routes first
    for (const routeId of Object.keys(routes)) {
      routeBackgroundLayerIds.push(`${routeId}outline`);
      map.addLayer(
        {
          id: `${routeId}outline`,
          type: 'line',
          source: {
            type: 'geojson',
            data: geojson,
          },
          paint: {
            'line-color': '#FFFFFF',
            'line-opacity': 1,
            'line-width': 6,
          },
          layout: {
            'line-join': 'round',
            'line-cap': 'round',
          },
          filter: ['==', 'route_id', routeId],
        },
        firstSymbolId
      );
    }

    // Add route lines next
    for (const routeId of Object.keys(routes)) {
      routeLayerIds.push(routeId);
      const routeColor = routes[routeId].route_color || defaultRouteColor;
      map.addLayer(
        {
          id: routeId,
          type: 'line',
          source: {
            type: 'geojson',
            data: geojson,
          },
          paint: {
            'line-color': routeColor,
            'line-opacity': 1,
            'line-width': 2,
          },
          layout: {
            'line-join': 'round',
            'line-cap': 'round',
          },
          filter: ['==', 'route_id', routeId],
        },
        firstSymbolId
      );
    }

    // Add labels
    map.addLayer({
      id: 'route-labels',
      type: 'symbol',
      source: {
        type: 'geojson',
        data: geojson,
      },
      layout: {
        'symbol-placement': 'line',
        'text-field': ['get', 'route_short_name'],
        'text-size': 14,
      },
      paint: {
        'text-color': '#000000',
        'text-halo-width': 2,
        'text-halo-color': '#ffffff',
      },
      filter: ['has', 'route_short_name'],
    });

    map.on('mousemove', (event) => {
      const features = map.queryRenderedFeatures(event.point, {
        layers: [...routeLayerIds, ...routeBackgroundLayerIds],
      });
      if (features.length > 0) {
        map.getCanvas().style.cursor = 'pointer';
        highlightRoutes(
          _.uniq(features.map((feature) => feature.properties.route_id))
        );
      } else {
        map.getCanvas().style.cursor = '';
        unHighlightRoutes();
      }
    });

    map.on('click', (event) => {
      // Set bbox as 5px reactangle area around clicked point
      const bbox = [
        [event.point.x - 5, event.point.y - 5],
        [event.point.x + 5, event.point.y + 5],
      ];
      const features = map.queryRenderedFeatures(bbox, {
        layers: routeLayerIds,
      });

      if (!features || features.length === 0) {
        return;
      }

      const routeFeatures = _.orderBy(
        _.uniqBy(features, (feature) => feature.properties.route_short_name),
        (feature) => Number.parseInt(feature.properties.route_short_name, 10)
      );

      new mapboxgl.Popup()
        .setLngLat(event.lngLat)
        .setHTML(formatRoutePopup(routeFeatures))
        .addTo(map);
    });

    function highlightRoutes(routeIds, zoom) {
      for (const layerId of routeBackgroundLayerIds) {
        const color = routeIds.includes(layerId.replace(/outline/, ''))
          ? '#FFFD7E'
          : '#FFFFFF';
        const width = routeIds.includes(layerId.replace(/outline/, ''))
          ? 12
          : 6;
        map.setPaintProperty(layerId, 'line-color', color);
        map.setPaintProperty(layerId, 'line-width', width);
      }

      const highlightedFeatures = geojson.features.filter((feature) =>
        routeIds.includes(feature.properties.route_id)
      );

      if (highlightedFeatures.length === 0) {
        return;
      }

      if (zoom) {
        const zoomBounds = getBounds({
          features: highlightedFeatures,
        });
        map.fitBounds(zoomBounds, {
          padding: 20,
        });
      }
    }

    function unHighlightRoutes(zoom) {
      for (const layerId of routeBackgroundLayerIds) {
        map.setPaintProperty(layerId, 'line-color', '#FFFFFF');
        map.setPaintProperty(layerId, 'line-width', 6);
      }

      if (zoom) {
        map.fitBounds(bounds);
      }
    }

    // On table hover, highlight route on map
    $(() => {
      $('.overview-list a').hover((event) => {
        const routeIdString = $(event.target).parents('a').data('route-ids');
        if (routeIdString) {
          const routeIds = routeIdString.toString().split(',');
          highlightRoutes(routeIds, true);
        }
      });

      $('.overview-list').hover(
        () => {},
        () => unHighlightRoutes(true)
      );
    });
  });

  maps[id] = map;
}
<|endoftext|>


<commit_before>var ResultViewer = React.createClass({

    componentDidMount: function () {
    },

    getInitialState: function () {
        return {
            results: []
        }
    },

    render: function () {
        var style = {
            height: '100%',
            background: 'rgba(240,240,240,0.15)'
        }
        if (Array.isArray(this.state.results) === false) {
            return (

                        {this.state.results}

            )
        }
        var resultNodes = this.state.results.map(function (result, index) {
            return (

                        {result.packageName}

                        {result.version}

            )

        })

        if (resultNodes.length > 0) {
            var total = resultNodes.length
            var n = Math.min(total, 10)
            var summary = Showing {n} of {total} results
        }

        return (

            {summary}
            {resultNodes}

)
    }

})<commit_msg>show app id in result viwer<commit_after>var ResultViewer = React.createClass({

    componentDidMount: function () {
    },

    getInitialState: function () {
        return {
            results: []
        }
    },

    render: function () {
        var style = {
            height: '100%',
            background: 'rgba(240,240,240,0.15)'
        }
        if (Array.isArray(this.state.results) === false) {
            return (

                        {this.state.results}

            )
        }
        var resultNodes = this.state.results.map(function (result, index) {
            return (

                        {result.app.id}

            )
        })

        if (resultNodes.length > 0) {
            var total = resultNodes.length
            var n = Math.min(total, 10)
            var summary = Showing {n} of {total} results
        }

        return (

            {summary}
            {resultNodes}

)
    }

})<|endoftext|>


<commit_before>var colors = {
    0: "lightgray",
    1: "#edc240",
    2: "#afd8f8",
    3: "#cb4b4b",
    4: "#4da74d",
    5: "#9440ed",
    6: "rgb(189, 155, 51)",
    7: "rgb(140,172,198)"
};

var target = $('#target');
$(document)
    .ajaxStart(function () {
        $('html, body').css('cursor', 'wait');
        target.overlay();
    })
    .ajaxStop(function () {
        $('html, body').css('cursor', 'auto');
        target.overlayout();
    });

$(function () {
    initLegend();

    // Load the last 14 days
    getFortnight(function (rawdata) {
        render(rawdata)
    });
});

function initLegend() {
    $('#detail-legend').append('

');
};

function render(rawdata) {

    if (!rawdata) {
        // TODO Show error message
        console.log('Sorry, no data found.');
        return;
    }

    var data = convertDataForFlot(rawdata);

    // Legend -------------------------------------------------------------
    var legendContainer = $('#detail-legend');
    var legendHasNoData = legendContainer.find('.table-row-data').length === 0;
    if (legendHasNoData) {
        $.each(data, function (key, val) {
            var tablerow = '
' +
                '
<input type="checkbox" name="' + key + '" checked="checked" id="id' + key + '"></input>
' +
                '

' +
                '
' + val.label + '
' +
                '

' +
                '
';
            legendContainer.find('.div-table').append(tablerow);
        });
    }
    legendContainer.find("input").click(updatePlot);

    var currentSelection = {
        min: undefined,
        max: undefined
    };

    // Main plotting function ---------------------------------------------
    function updatePlot() {

        var plotdata = [];

        legendContainer.find('input:checked').each(function () {
            var key = $(this).attr('name');
            if (key && data[key]) {
                plotdata.push(data[key])
            }
        });

        var rangeselectionCallback = function (o) {
            console.log('rangeselectionCallback invoked...');
            var xaxis = detailPlot.getAxes().xaxis;

            if (o.start <= xaxis.datamin) {
                loadAnotherFortnight(xaxis.datamin, xaxis.datamax);
            } else {
                xaxis.options.min = o.start;
                xaxis.options.max = o.end;
                detailPlot.setupGrid();
                detailPlot.draw();

                currentSelection.min = o.start;
                currentSelection.max = o.end;
            }
        };

        var detailPlaceholder = $('#detail-placeholder');
        var detailPlot = $.plot(detailPlaceholder, plotdata, {
            xaxis: {
                mode: 'time'
            },
            yaxis: {
                panRange: false
            },
            series: {
                lines: {
                    show: true
                },
                points: {
                    show: false
                }
            },
            legend: {
                show: false // Note: The legend is configured manually (see legendContainer)
            },
            grid: {
                hoverable: true,
                clickable: true,
                autoHighlight: false,
                borderWidth: 0,
                markings: weekendAreas
            },
            crosshair: {
                mode: 'x'
            },
            pan: {
                interactive: true
            }
        });

        var overviewPlaceholder = $('#overview-placeholder');
        var overviewData = $.extend(true, [], plotdata);
        for (var i = 0; i < overviewData.length; i++) {
            overviewData[i].color = '#ccc';
            overviewData[i].label = undefined;
        }

        // EXPERIMENT START -----------------------------
        //        var initialOverview = {
        //            start: {},
        //            end: {}
        //        }
        var rangeselectionEnd = detailPlot.getData()[0].data[detailPlot.getData()[0].data.length - 1][0];
        var endDate = new Date(rangeselectionEnd);
        endDate.setDate(endDate.getDate() - 1); // endDate = endDate - 1day
        var rangeselectionInitialStart = endDate.getTime();
        detailPlot.getAxes().xaxis.options.min = rangeselectionInitialStart;
        detailPlot.setupGrid();
        detailPlot.draw();
        // EXPERIMENT STOP -----------------------------

        var overviewPlot = $.plot(overviewPlaceholder, overviewData, {
            series: {
                lines: {
                    show: true,
                    lineWidth: 1
                },
                shadowSize: 0,
                points: {
                    show: false
                }
            },
            xaxis: {
                mode: "time"
            },
            yaxis: {
                labelWidth: 16,
                reserveSpace: true,
                show: false
            },
            legend: {
                show: false
            },
            grid: {
                hoverable: false,
                borderWidth: {
                    'top': 1,
                    'right': 1,
                    'left': 1,
                    'bottom': 1
                },
                borderColor: 'darkgray',
                markings: weekendAreas
            },
            rangeselection: {
                color: '#999',
                enabled: true,
                start: rangeselectionInitialStart,
                end: rangeselectionEnd,
                callback: rangeselectionCallback
            }
        });

        // Since the canvas is redrawn after every interaction, we have to manually set the selection range (if it exists)
        if (currentSelection.min !== undefined && currentSelection.max !== undefined) {
            var xaxis = detailPlot.getAxes().xaxis;
            xaxis.options.min = currentSelection.min;
            xaxis.options.max = currentSelection.max;
            detailPlot.setupGrid();
            detailPlot.draw();

            overviewPlot.getOptions().rangeselection.start = currentSelection.min;
            overviewPlot.getOptions().rangeselection.end = currentSelection.max;
            overviewPlot.setupGrid();
            overviewPlot.draw();
        }

        // PLOTHOVER: UPDATE VALUE IN LEGEND
        detailPlaceholder.bind('plothover', function (event, pos, item) {
            var updateDetailSelectionTimeout = null;
            var latestPosition = null;

            function updateDetailSelection() {
                updateDetailSelectionTimeout = null;
                var pos = latestPosition;
                var axes = detailPlot.getAxes();
                if (pos.x < axes.xaxis.min || pos.x > axes.xaxis.max ||
                    pos.y < axes.yaxis.min || pos.y > axes.yaxis.max) {
                    //tooltipContainer.hide('slow');
                    return;
                }

                var seriesIndex, dataPointInSeries, dataset = plotdata;

                // Iterate of each time series ('seriesIndex')
                var yMax;
                for (seriesIndex = 0; seriesIndex < dataset.length; ++seriesIndex) {
                    var series = dataset[seriesIndex];

                    // Find the nearest points, x-wise
                    for (dataPointInSeries = 0; series.data.length; ++dataPointInSeries) {
                        if (series.data[dataPointInSeries][0] > pos.x) {
                            break;
                        }
                    }

                    // Now interpolate
                    var y,
                        p1 = series.data[dataPointInSeries - 1],
                        p2 = series.data[dataPointInSeries];

                    if (p1 == null) {
                        y = p2[1];
                    } else if (p2 == null) {
                        y = p1[1];
                    } else {
                        y = p1[1] + (p2[1] - p1[1]) * (pos.x - p1[0]) / (p2[0] - p1[0]);
                    }

                    // Set the correct value for the current sensor
                    if ($.isNumeric(y)) {
                        var temperatureValueContainer = legendContainer.find('#temperature-value' + series.id);
                        if (temperatureValueContainer) {
                            temperatureValueContainer.text(y.toFixed(1));
                        }
                    }

                    if (y > yMax) {
                        yMax = y;
                    }
                }

                // Current time
                var m = moment(pos.x);
                m.add(-2, 'hours'); // fucking time stuff
                $('#detail-selection-header').text(m.format('YYYY-MM-DD HH:mm (ddd)'));
            };

            latestPosition = pos;
            if (!updateDetailSelectionTimeout) {
                updateDetailSelectionTimeout = setTimeout(updateDetailSelection, 400);
            }
        });

        // PLOTPAN: UPDATE OVERVIEW PLOT
        detailPlaceholder.bind('plotpan', function (event, plot) {
            var currentMin = plot.getXAxes()[0].min;
            var dataMin = plot.getXAxes()[0].datamin;
            //            console.log('-------')
            //            console.log(new Date(currentMin));
            //            console.log(new Date(dataMin));
            if (currentMin <= dataMin) {
                loadAnotherFortnight(dataMin, overviewPlot.getAxes().xaxis.datamax);
                return;
            } else {
                function clamp(min, value, max) {
                    return value < min ? min : (value > max ? max : value);
                };

                function clampOverViewPlot(value) {
                    overviewMin = overviewPlot.getAxes().xaxis.min;
                    overviewMax = overviewPlot.getAxes().xaxis.max;
                    return clamp(overviewMin, value, overviewMax);
                };

                currentSelection.min = clampOverViewPlot(detailPlot.getAxes().xaxis.min);
                currentSelection.max = clampOverViewPlot(detailPlot.getAxes().xaxis.max);
                overviewPlot.setSelection(currentSelection.min, currentSelection.max);
            }
        });
    };

    updatePlot();
};

/* From flot demo: http://www.flotcharts.org/flot/examples/visitors/index.html */
function weekendAreas(axes) {
    var markings = [],
        d = new Date(axes.xaxis.min);

    // go to the first Saturday
    d.setUTCDate(d.getUTCDate() - ((d.getUTCDay() + 1) % 7))
    d.setUTCSeconds(0);
    d.setUTCMinutes(0);
    d.setUTCHours(0);

    var i = d.getTime();

    do {
        markings.push({
            xaxis: {
                from: i,
                to: i + 2 * 24 * 60 * 60 * 1000
            },
            color: '#FBF8EF'
        });
        i += 7 * 24 * 60 * 60 * 1000;
    } while (i < axes.xaxis.max);

    return markings;
};

function nightAreas(axes) {
    var markings = [],
        d = new Date(axes.xaxis.min);

    // go to the first sunrise
    var sunShine = rest.getSunData(d, axes.xaxis.max);

    //    var minPlusOneDay = (d.getUTCDay() + 1);
    //    var minPlusOneDayInOrigData = 1; // TODO Find closest data point
    //    var firstDayData = []; // TODO create array [min ... minPlusOneDayInOrigData]
    //    var firstSunsetInData = 1;
    //    var firstSunriseInData = 1;

    d.setUTCDate(d.getUTCDate() - ((d.getUTCDay() + 1) % 7))
    d.setUTCSeconds(0);
    d.setUTCMinutes(0);
    d.setUTCHours(0);

    var i = d.getTime();

    do {
        markings.push({
            xaxis: {
                from: i,
                to: i + 2 * 24 * 60 * 60 * 1000
            },
            color: '#FBF8EF'
        });
        i += 7 * 24 * 60 * 60 * 1000;
    } while (i < axes.xaxis.max);

    return markings;
};

function loadAnotherFortnight(oldMin, max) {
    console.log('Reloading with oldMin value: ' + new Date(oldMin));
    console.log('Reloading with max value: ' + new Date(max));

    getByFilter(oldMin, max, function (rawdata) {
        console.log('call getByFilter is done.');
        render(rawdata);
    });
};

// Prepare data -------------------------------------------------------------------------------------------
var formatDate = function (date) {
    // requires moment.js
    return moment.utc(new Date(date)).format('ddd, YYYY MMM DD HH:mm');
};

var convertDataForFlot = function (data) {
    var flotdata = [];
    flotdata.push(mapTimeSeries(data, 'WA', 'outside', colors[0]));
    flotdata.push(mapTimeSeries(data, 'Z2', '2nd floor', colors[1]));
    flotdata.push(mapTimeSeries(data, 'Z3', '1st floor (work)', colors[2]));
    flotdata.push(mapTimeSeries(data, 'Z4', '1st floor (bathroom)', colors[3]));
    flotdata.push(mapTimeSeries(data, 'Z5', '1st floor (bedroom)', colors[4]));
    flotdata.push(mapTimeSeries(data, 'Z6', 'ground floor', colors[5]));
    return flotdata;
};

var mapTimeSeries = function (data, sensorName, label, col) {
    var series = [];
    for (var i = 0; i < data.length; i++) {
        if (data[i].sensorName === sensorName) {
            var mDate = moment(data[i].timestamp + ' +02:00', 'YYYY-MM-DD HH:mm:ss ZZ');
            mDate.add(2, 'hours'); // still don't understand why this is really necessary.
            var millis = new Date(mDate.unix()) * 1000;
            series.push([millis, data[i].degreeCelsius]);
        }
    }

    // Note: Add an 'id' property (because the label property is a descriptive string)
    return {
        data: series,
        label: label,
        color: col,
        id: sensorName
    };
};
<commit_msg>Moved initialization of overview plot to function.<commit_after>var colors = {
    0: "lightgray",
    1: "#edc240",
    2: "#afd8f8",
    3: "#cb4b4b",
    4: "#4da74d",
    5: "#9440ed",
    6: "rgb(189, 155, 51)",
    7: "rgb(140,172,198)"
};

var target = $('#target');
$(document)
    .ajaxStart(function () {
        $('html, body').css('cursor', 'wait');
        target.overlay();
    })
    .ajaxStop(function () {
        $('html, body').css('cursor', 'auto');
        target.overlayout();
    });

$(function () {
    initLegend();

    // Load the last 14 days
    getFortnight(function (rawdata) {
        render(rawdata)
    });
});

function initLegend() {
    $('#detail-legend').append('

');
};

function render(rawdata) {

    if (!rawdata) {
        // TODO Show error message
        console.log('Sorry, no data found.');
        return;
    }

    var data = convertDataForFlot(rawdata);

    // Legend -------------------------------------------------------------
    var legendContainer = $('#detail-legend');
    var legendHasNoData = legendContainer.find('.table-row-data').length === 0;
    if (legendHasNoData) {
        $.each(data, function (key, val) {
            var tablerow = '
' +
                '
<input type="checkbox" name="' + key + '" checked="checked" id="id' + key + '"></input>
' +
                '

' +
                '
' + val.label + '
' +
                '

' +
                '
';
            legendContainer.find('.div-table').append(tablerow);
        });
    }
    legendContainer.find("input").click(updatePlot);

    var currentSelection = {
        min: undefined,
        max: undefined
    };

    // Main plotting function ---------------------------------------------
    function updatePlot() {

        var plotdata = [];

        legendContainer.find('input:checked').each(function () {
            var key = $(this).attr('name');
            if (key && data[key]) {
                plotdata.push(data[key])
            }
        });

        var rangeselectionCallback = function (o) {
            console.log('rangeselectionCallback invoked...');
            var xaxis = detailPlot.getAxes().xaxis;

            if (o.start <= xaxis.datamin) {
                loadAnotherFortnight(xaxis.datamin, xaxis.datamax);
            } else {
                xaxis.options.min = o.start;
                xaxis.options.max = o.end;
                detailPlot.setupGrid();
                detailPlot.draw();

                currentSelection.min = o.start;
                currentSelection.max = o.end;
            }
        };

        var detailPlaceholder = $('#detail-placeholder');
        var detailPlot = $.plot(detailPlaceholder, plotdata, {
            xaxis: {
                mode: 'time'
            },
            yaxis: {
                panRange: false
            },
            series: {
                lines: {
                    show: true
                },
                points: {
                    show: false
                }
            },
            legend: {
                show: false // Note: The legend is configured manually (see legendContainer)
            },
            grid: {
                hoverable: true,
                clickable: true,
                autoHighlight: false,
                borderWidth: 0,
                markings: weekendAreas
            },
            crosshair: {
                mode: 'x'
            },
            pan: {
                interactive: true
            }
        });

        var overviewPlaceholder = $('#overview-placeholder');
        var overviewData = $.extend(true, [], plotdata);
        for (var i = 0; i < overviewData.length; i++) {
            overviewData[i].color = '#ccc';
            overviewData[i].label = undefined;
        }

        function initializeOverview(plot) {
            var rangeselectionEnd = plot.getData()[0].data[plot.getData()[0].data.length - 1][0];
            var endDate = new Date(rangeselectionEnd);
            endDate.setDate(endDate.getDate() - 1); // endDate = endDate - 1day
            var rangeselectionInitialStart = endDate.getTime();
            plot.getAxes().xaxis.options.min = rangeselectionInitialStart;
            plot.setupGrid();
            plot.draw();

            var initialOverview = {
                start: rangeselectionInitialStart,
                end: rangeselectionEnd
            };
            return initialOverview;
        }
        var overview = initializeOverview(detailPlot);

        var overviewPlot = $.plot(overviewPlaceholder, overviewData, {
            series: {
                lines: {
                    show: true,
                    lineWidth: 1
                },
                shadowSize: 0,
                points: {
                    show: false
                }
            },
            xaxis: {
                mode: "time"
            },
            yaxis: {
                labelWidth: 16,
                reserveSpace: true,
                show: false
            },
            legend: {
                show: false
            },
            grid: {
                hoverable: false,
                borderWidth: {
                    'top': 1,
                    'right': 1,
                    'left': 1,
                    'bottom': 1
                },
                borderColor: 'darkgray',
                markings: weekendAreas
            },
            rangeselection: {
                color: '#999',
                enabled: true,
                start: overview.start,
                end: overview.end,
                callback: rangeselectionCallback
            }
        });

        // Since the canvas is redrawn after every interaction, we have to manually set the selection range (if it exists)
        if (currentSelection.min !== undefined && currentSelection.max !== undefined) {
            var xaxis = detailPlot.getAxes().xaxis;
            xaxis.options.min = currentSelection.min;
            xaxis.options.max = currentSelection.max;
            detailPlot.setupGrid();
            detailPlot.draw();

            overviewPlot.getOptions().rangeselection.start = currentSelection.min;
            overviewPlot.getOptions().rangeselection.end = currentSelection.max;
            overviewPlot.setupGrid();
            overviewPlot.draw();
        }

        // PLOTHOVER: UPDATE VALUE IN LEGEND
        detailPlaceholder.bind('plothover', function (event, pos, item) {
            var updateDetailSelectionTimeout = null;
            var latestPosition = null;

            function updateDetailSelection() {
                updateDetailSelectionTimeout = null;
                var pos = latestPosition;
                var axes = detailPlot.getAxes();
                if (pos.x < axes.xaxis.min || pos.x > axes.xaxis.max ||
                    pos.y < axes.yaxis.min || pos.y > axes.yaxis.max) {
                    //tooltipContainer.hide('slow');
                    return;
                }

                var seriesIndex, dataPointInSeries, dataset = plotdata;

                // Iterate of each time series ('seriesIndex')
                var yMax;
                for (seriesIndex = 0; seriesIndex < dataset.length; ++seriesIndex) {
                    var series = dataset[seriesIndex];

                    // Find the nearest points, x-wise
                    for (dataPointInSeries = 0; series.data.length; ++dataPointInSeries) {
                        if (series.data[dataPointInSeries][0] > pos.x) {
                            break;
                        }
                    }

                    // Now interpolate
                    var y,
                        p1 = series.data[dataPointInSeries - 1],
                        p2 = series.data[dataPointInSeries];

                    if (p1 == null) {
                        y = p2[1];
                    } else if (p2 == null) {
                        y = p1[1];
                    } else {
                        y = p1[1] + (p2[1] - p1[1]) * (pos.x - p1[0]) / (p2[0] - p1[0]);
                    }

                    // Set the correct value for the current sensor
                    if ($.isNumeric(y)) {
                        var temperatureValueContainer = legendContainer.find('#temperature-value' + series.id);
                        if (temperatureValueContainer) {
                            temperatureValueContainer.text(y.toFixed(1));
                        }
                    }

                    if (y > yMax) {
                        yMax = y;
                    }
                }

                // Current time
                var m = moment(pos.x);
                m.add(-2, 'hours'); // fucking time stuff
                $('#detail-selection-header').text(m.format('YYYY-MM-DD HH:mm (ddd)'));
            };

            latestPosition = pos;
            if (!updateDetailSelectionTimeout) {
                updateDetailSelectionTimeout = setTimeout(updateDetailSelection, 400);
            }
        });

        // PLOTPAN: UPDATE OVERVIEW PLOT
        detailPlaceholder.bind('plotpan', function (event, plot) {
            var currentMin = plot.getXAxes()[0].min;
            var dataMin = plot.getXAxes()[0].datamin;
            //            console.log('-------')
            //            console.log(new Date(currentMin));
            //            console.log(new Date(dataMin));
            if (currentMin <= dataMin) {
                loadAnotherFortnight(dataMin, overviewPlot.getAxes().xaxis.datamax);
                return;
            } else {
                function clamp(min, value, max) {
                    return value < min ? min : (value > max ? max : value);
                };

                function clampOverViewPlot(value) {
                    overviewMin = overviewPlot.getAxes().xaxis.min;
                    overviewMax = overviewPlot.getAxes().xaxis.max;
                    return clamp(overviewMin, value, overviewMax);
                };

                currentSelection.min = clampOverViewPlot(detailPlot.getAxes().xaxis.min);
                currentSelection.max = clampOverViewPlot(detailPlot.getAxes().xaxis.max);
                overviewPlot.setSelection(currentSelection.min, currentSelection.max);
            }
        });
    };

    updatePlot();
};

/* From flot demo: http://www.flotcharts.org/flot/examples/visitors/index.html */
function weekendAreas(axes) {
    var markings = [],
        d = new Date(axes.xaxis.min);

    // go to the first Saturday
    d.setUTCDate(d.getUTCDate() - ((d.getUTCDay() + 1) % 7))
    d.setUTCSeconds(0);
    d.setUTCMinutes(0);
    d.setUTCHours(0);

    var i = d.getTime();

    do {
        markings.push({
            xaxis: {
                from: i,
                to: i + 2 * 24 * 60 * 60 * 1000
            },
            color: '#FBF8EF'
        });
        i += 7 * 24 * 60 * 60 * 1000;
    } while (i < axes.xaxis.max);

    return markings;
};

function nightAreas(axes) {
    var markings = [],
        d = new Date(axes.xaxis.min);

    // go to the first sunrise
    var sunShine = rest.getSunData(d, axes.xaxis.max);

    //    var minPlusOneDay = (d.getUTCDay() + 1);
    //    var minPlusOneDayInOrigData = 1; // TODO Find closest data point
    //    var firstDayData = []; // TODO create array [min ... minPlusOneDayInOrigData]
    //    var firstSunsetInData = 1;
    //    var firstSunriseInData = 1;

    d.setUTCDate(d.getUTCDate() - ((d.getUTCDay() + 1) % 7))
    d.setUTCSeconds(0);
    d.setUTCMinutes(0);
    d.setUTCHours(0);

    var i = d.getTime();

    do {
        markings.push({
            xaxis: {
                from: i,
                to: i + 2 * 24 * 60 * 60 * 1000
            },
            color: '#FBF8EF'
        });
        i += 7 * 24 * 60 * 60 * 1000;
    } while (i < axes.xaxis.max);

    return markings;
};

function loadAnotherFortnight(oldMin, max) {
    console.log('Reloading with oldMin value: ' + new Date(oldMin));
    console.log('Reloading with max value: ' + new Date(max));

    getByFilter(oldMin, max, function (rawdata) {
        console.log('call getByFilter is done.');
        render(rawdata);
    });
};

// Prepare data -------------------------------------------------------------------------------------------
var formatDate = function (date) {
    // requires moment.js
    return moment.utc(new Date(date)).format('ddd, YYYY MMM DD HH:mm');
};

var convertDataForFlot = function (data) {
    var flotdata = [];
    flotdata.push(mapTimeSeries(data, 'WA', 'outside', colors[0]));
    flotdata.push(mapTimeSeries(data, 'Z2', '2nd floor', colors[1]));
    flotdata.push(mapTimeSeries(data, 'Z3', '1st floor (work)', colors[2]));
    flotdata.push(mapTimeSeries(data, 'Z4', '1st floor (bathroom)', colors[3]));
    flotdata.push(mapTimeSeries(data, 'Z5', '1st floor (bedroom)', colors[4]));
    flotdata.push(mapTimeSeries(data, 'Z6', 'ground floor', colors[5]));
    return flotdata;
};

var mapTimeSeries = function (data, sensorName, label, col) {
    var series = [];
    for (var i = 0; i < data.length; i++) {
        if (data[i].sensorName === sensorName) {
            var mDate = moment(data[i].timestamp + ' +02:00', 'YYYY-MM-DD HH:mm:ss ZZ');
            mDate.add(2, 'hours'); // still don't understand why this is really necessary.
            var millis = new Date(mDate.unix()) * 1000;
            series.push([millis, data[i].degreeCelsius]);
        }
    }

    // Note: Add an 'id' property (because the label property is a descriptive string)
    return {
        data: series,
        label: label,
        color: col,
        id: sensorName
    };
};
<|endoftext|>