<commit_before>var myChart = echarts.init(document.getElementById('main'));

        // Specify configurations and data graphs
myChart.showLoading({text:'iUsed努力加载数据中...'});

$.get('USA_geo.json', function (usaJson) {
    myChart.hideLoading();

    echarts.registerMap('USA', usaJson, {
        Alaska: {              // 把阿拉斯加移到美国主大陆左下方
            left: -131,
            top: 25,
            width: 15
        },
        Hawaii: {
            left: -110,        // 夏威夷
            top: 28,
            width: 5
        },
        'Puerto Rico': {       // 波多黎各
            left: -76,
            top: 26,
            width: 2
        }
    });
    option = {
        title: {
            text: 'Unique Visitors On iUsed.org(Feb.2017)',
            subtext: 'Data from api.iused.org',
            sublink: 'http://api.iused.org',
            left: 'right'
        },
        tooltip: {
            trigger: 'item',
            showDelay: 0,
            transitionDuration: 0.2,
            formatter: function (params) {
                var value = (params.value + '').split('.');
                value = value[0].replace(/(\d{1,3})(?=(?:\d{3})+(?!\d))/g, '$1,');
                return params.seriesName + '
' + params.name + ': ' + value+'人访问';
            }
        },
        visualMap: {
            left: 'right',
            min: 0,
            max: 500,
            inRange: {
                color: ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf', '#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026']
            },
            text:['Opening','Wait to start'],           // 文本，默认为数值文本
            calculable: true
        },
        toolbox: {
            show: true,
            //orient: 'vertical',
            left: 'left',
            top: 'top',
            feature: {
                dataView: {readOnly: true},
                restore: {show:false},
                saveAsImage: {}
            }
        },
        series: [
            {
                name: '初始数据统计中...',
                type: 'map',
                roam: true,
                map: 'USA',
                itemStyle:{
                    emphasis:{label:{show:true}}
                },
                // 文本位置修正
                textFixed: {
                    Alaska: [20, -20]
                },
                data:[
                    {name: 'Alabama', value: 0,provinceurl:"http://al.iused.org"},
                    {name: 'Alaska', value: 0,provinceurl:"http://ak.iused.org"},
                    {name: 'Arizona', value: 400,provinceurl:"http://az.iused.org"},
                    {name: 'Arkansas', value: 0,provinceurl:"http://ar.iused.org"},
                    {name: 'California', value: 0,provinceurl:"http://ca.iused.org"},
                    {name: 'Colorado', value: 0,provinceurl:"http://co.iused.org"},
                    {name: 'Connecticut', value: 0,provinceurl:"http://ct.iused.org"},
                    {name: 'Delaware', value: 0,provinceurl:"http://de.iused.org"},
                    {name: 'District of Columbia', value: 0,provinceurl:"http://dc.iused.org"},
                    {name: 'Florida', value: 400,provinceurl:"http://fl.iused.org"},
                    {name: 'Georgia', value: 0,provinceurl:"http://ga.iused.org"},
                    {name: 'Hawaii', value: 0,provinceurl:"http://hi.iused.org"},
                    {name: 'Idaho', value: 0,provinceurl:"http://id.iused.org"},
                    {name: 'Illinois', value: 0,provinceurl:"http://il.iused.org"},
                    {name: 'Indiana', value: 0,provinceurl:"http://in.iused.org"},
                    {name: 'Iowa', value: 500,provinceurl:"http://ia.iused.org"},
                    {name: 'Kansas', value: 500,provinceurl:"http://ks.iused.org"},
                    {name: 'Kentucky', value: 0,provinceurl:"http://ky.iused.org"},
                    {name: 'Louisiana', value: 0,provinceurl:"http://la.iused.org"},
                    {name: 'Maine', value: 0,provinceurl:"http://me.iused.org"},
                    {name: 'Maryland', value: 0,provinceurl:"http://md.iused.org"},
                    {name: 'Massachusetts', value: 0,provinceurl:"http://ma.iused.org"},
                    {name: 'Michigan', value: 400,provinceurl:"http://mi.iused.org"},
                    {name: 'Minnesota', value: 0,provinceurl:"http://mn.iused.org"},
                    {name: 'Mississippi', value: 0,provinceurl:"http://ms.iused.org"},
                    {name: 'Missouri', value: 500,provinceurl:"http://mo.iused.org"},
                    {name: 'Montana', value: 0,provinceurl:"http://mt.iused.org"},
                    {name: 'Nebraska', value: 0,provinceurl:"http://ne.iused.org"},
                    {name: 'Nevada', value: 0,provinceurl:"http://nv.iused.org"},
                    {name: 'New Hampshire', value: 0,provinceurl:"http://nh.iused.org"},
                    {name: 'New Jersey', value: 0,provinceurl:"http://nj.iused.org"},
                    {name: 'New Mexico', value: 0,provinceurl:"http://nm.iused.org"},
                    {name: 'New York', value: 0,provinceurl:"http://ny.iused.org"},
                    {name: 'North Carolina', value: 0,provinceurl:"http://nc.iused.org"},
                    {name: 'North Dakota', value: 0,provinceurl:"http://nd.iused.org"},
                    {name: 'Ohio', value: 400,provinceurl:"http://oh.iused.org"},
                    {name: 'Oklahoma', value: 500,provinceurl:"http://ok.iused.org"},
                    {name: 'Oregon', value: 400,provinceurl:"http://or.iused.org"},
                    {name: 'Pennsylvania', value: 400,provinceurl:"http://pa.iused.org"},
                    {name: 'Rhode Island', value: 0,provinceurl:"http://ri.iused.org"},
                    {name: 'South Carolina', value: 0,provinceurl:"http://sc.iused.org"},
                    {name: 'South Dakota', value: 0,provinceurl:"http://sd.iused.org"},
                    {name: 'Tennessee', value: 0,provinceurl:"http://tn.iused.org"},
                    {name: 'Texas', value: 0,provinceurl:"http://tx.iused.org"},
                    {name: 'Utah', value: 0,provinceurl:"http://ut.iused.org"},
                    {name: 'Vermont', value: 0,provinceurl:"http://vt.iused.org"},
                    {name: 'Virginia', value: 0,provinceurl:"http://va.iused.org"},
                    {name: 'Washington', value: 0,provinceurl:"http://wa.iused.org"},
                    {name: 'West Virginia', value: 0,provinceurl:"http://wv.iused.org"},
                    {name: 'Wisconsin', value: 0,provinceurl:"http://wi.iused.org"},
                    {name: 'Wyoming', value: 0,provinceurl:"http://wy.iused.org"},
                    {name: 'Puerto Rico', value: 0,provinceurl:"http://pr.iused.org"}
                ]
            }
        ]
    };

    myChart.setOption(option);
});
    myChart.on('click', function (params) {window.open(params.data.provinceurl);
});
<commit_msg>Update index.js<commit_after>var myChart = echarts.init(document.getElementById('main'));

        // Specify configurations and data graphs
myChart.showLoading({text:'iUsed努力加载数据中...'});

$.get('https://s3-us-west-2.amazonaws.com/s.cdpn.io/95368/USA_geo.json', function (usaJson) {
    myChart.hideLoading();

    echarts.registerMap('USA', usaJson, {
        Alaska: {              // 把阿拉斯加移到美国主大陆左下方
            left: -131,
            top: 25,
            width: 15
        },
        Hawaii: {
            left: -110,        // 夏威夷
            top: 28,
            width: 5
        },
        'Puerto Rico': {       // 波多黎各
            left: -76,
            top: 26,
            width: 2
        }
    });
    option = {
        title: {
            text: 'Unique Visitors On iUsed.org(Feb.2017)',
            subtext: 'Data from api.iused.org',
            sublink: 'http://api.iused.org',
            left: 'right'
        },
        tooltip: {
            trigger: 'item',
            showDelay: 0,
            transitionDuration: 0.2,
            formatter: function (params) {
                var value = (params.value + '').split('.');
                value = value[0].replace(/(\d{1,3})(?=(?:\d{3})+(?!\d))/g, '$1,');
                return params.seriesName + '
' + params.name + ': ' + value+'人访问';
            }
        },
        visualMap: {
            left: 'right',
            min: 0,
            max: 500,
            inRange: {
                color: ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf', '#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026']
            },
            text:['Opening','Wait to start'],           // 文本，默认为数值文本
            calculable: true
        },
        toolbox: {
            show: true,
            //orient: 'vertical',
            left: 'left',
            top: 'top',
            feature: {
                dataView: {readOnly: true},
                restore: {show:false},
                saveAsImage: {}
            }
        },
        series: [
            {
                name: '初始数据统计中...',
                type: 'map',
                roam: true,
                map: 'USA',
                itemStyle:{
                    emphasis:{label:{show:true}}
                },
                // 文本位置修正
                textFixed: {
                    Alaska: [20, -20]
                },
                data:[
                    {name: 'Alabama', value: 0,provinceurl:"http://al.iused.org"},
                    {name: 'Alaska', value: 0,provinceurl:"http://ak.iused.org"},
                    {name: 'Arizona', value: 400,provinceurl:"http://az.iused.org"},
                    {name: 'Arkansas', value: 0,provinceurl:"http://ar.iused.org"},
                    {name: 'California', value: 0,provinceurl:"http://ca.iused.org"},
                    {name: 'Colorado', value: 0,provinceurl:"http://co.iused.org"},
                    {name: 'Connecticut', value: 0,provinceurl:"http://ct.iused.org"},
                    {name: 'Delaware', value: 0,provinceurl:"http://de.iused.org"},
                    {name: 'District of Columbia', value: 0,provinceurl:"http://dc.iused.org"},
                    {name: 'Florida', value: 400,provinceurl:"http://fl.iused.org"},
                    {name: 'Georgia', value: 0,provinceurl:"http://ga.iused.org"},
                    {name: 'Hawaii', value: 0,provinceurl:"http://hi.iused.org"},
                    {name: 'Idaho', value: 0,provinceurl:"http://id.iused.org"},
                    {name: 'Illinois', value: 0,provinceurl:"http://il.iused.org"},
                    {name: 'Indiana', value: 0,provinceurl:"http://in.iused.org"},
                    {name: 'Iowa', value: 500,provinceurl:"http://ia.iused.org"},
                    {name: 'Kansas', value: 500,provinceurl:"http://ks.iused.org"},
                    {name: 'Kentucky', value: 0,provinceurl:"http://ky.iused.org"},
                    {name: 'Louisiana', value: 0,provinceurl:"http://la.iused.org"},
                    {name: 'Maine', value: 0,provinceurl:"http://me.iused.org"},
                    {name: 'Maryland', value: 0,provinceurl:"http://md.iused.org"},
                    {name: 'Massachusetts', value: 0,provinceurl:"http://ma.iused.org"},
                    {name: 'Michigan', value: 400,provinceurl:"http://mi.iused.org"},
                    {name: 'Minnesota', value: 0,provinceurl:"http://mn.iused.org"},
                    {name: 'Mississippi', value: 0,provinceurl:"http://ms.iused.org"},
                    {name: 'Missouri', value: 500,provinceurl:"http://mo.iused.org"},
                    {name: 'Montana', value: 0,provinceurl:"http://mt.iused.org"},
                    {name: 'Nebraska', value: 0,provinceurl:"http://ne.iused.org"},
                    {name: 'Nevada', value: 0,provinceurl:"http://nv.iused.org"},
                    {name: 'New Hampshire', value: 0,provinceurl:"http://nh.iused.org"},
                    {name: 'New Jersey', value: 0,provinceurl:"http://nj.iused.org"},
                    {name: 'New Mexico', value: 0,provinceurl:"http://nm.iused.org"},
                    {name: 'New York', value: 0,provinceurl:"http://ny.iused.org"},
                    {name: 'North Carolina', value: 0,provinceurl:"http://nc.iused.org"},
                    {name: 'North Dakota', value: 0,provinceurl:"http://nd.iused.org"},
                    {name: 'Ohio', value: 400,provinceurl:"http://oh.iused.org"},
                    {name: 'Oklahoma', value: 500,provinceurl:"http://ok.iused.org"},
                    {name: 'Oregon', value: 400,provinceurl:"http://or.iused.org"},
                    {name: 'Pennsylvania', value: 400,provinceurl:"http://pa.iused.org"},
                    {name: 'Rhode Island', value: 0,provinceurl:"http://ri.iused.org"},
                    {name: 'South Carolina', value: 0,provinceurl:"http://sc.iused.org"},
                    {name: 'South Dakota', value: 0,provinceurl:"http://sd.iused.org"},
                    {name: 'Tennessee', value: 0,provinceurl:"http://tn.iused.org"},
                    {name: 'Texas', value: 0,provinceurl:"http://tx.iused.org"},
                    {name: 'Utah', value: 0,provinceurl:"http://ut.iused.org"},
                    {name: 'Vermont', value: 0,provinceurl:"http://vt.iused.org"},
                    {name: 'Virginia', value: 0,provinceurl:"http://va.iused.org"},
                    {name: 'Washington', value: 0,provinceurl:"http://wa.iused.org"},
                    {name: 'West Virginia', value: 0,provinceurl:"http://wv.iused.org"},
                    {name: 'Wisconsin', value: 0,provinceurl:"http://wi.iused.org"},
                    {name: 'Wyoming', value: 0,provinceurl:"http://wy.iused.org"},
                    {name: 'Puerto Rico', value: 0,provinceurl:"http://pr.iused.org"}
                ]
            }
        ]
    };

    myChart.setOption(option);
});
    myChart.on('click', function (params) {window.open(params.data.provinceurl);
});
<|endoftext|>


<commit_before>$(function(){

  var appendthis =  ("

");

    $('a[data-modal-id]').click(function(e) {
      e.preventDefault();
      $("body").append(appendthis);
      $(".modal-overlay").fadeTo(250, .75);
      // $(".js-modalbox").fadeIn(500);
      var modalBox = $(this).attr('data-modal-id');
      $('#'+modalBox).fadeIn($(this).data());
    });

  $(".js-modal-close, .modal-overlay").click(function() {
      $(".modal-box, .modal-overlay").fadeOut(250, function() {
          $(".modal-overlay").remove();
      });

  });
  $(".arrow").hide();

  // Check devise/window size for scroll prompt
  $(window).on('load', function() {
    if ($(window).width() <= 800) {
      $(".arrow").show('slow').delay( 3000).hide('slow');
    } else {
      $(".arrow").hide();
    }
  });

  // Resize function with timeout to see if prompt should be shown to scroll of not
  var resizeTimer;

  $(window).on('resize', function(e) {

    clearTimeout(resizeTimer);
    resizeTimer = setTimeout(function() {

      if ($(window).width() <= 800) {
        $(".arrow").show('slow').delay( 3000).hide('slow');
      } else if ($(window).height() > 1050) {
        $(".arrow").hide();
      } else if ($(window).width() < 767) {
        $(".modal-box").addClass('fixed');
        $(".modal-box").removeClass('flex');
      } else {
        $(".modal-box").addClass('flex');
        $(".modal-box").removeClass('fixed');
        $(".arrow").hide();
      }

    }, 250);

  });

  // Image Map Resizer to keep coordinates for clickable items in the right location
  // on an image
  $('map').imageMapResize();
});
<commit_msg>fix spacing<commit_after>$(function(){

  var appendthis =  ("

");

    $('a[data-modal-id]').click(function(e) {
      e.preventDefault();
      $("body").append(appendthis);
      $(".modal-overlay").fadeTo(250, .75);
      // $(".js-modalbox").fadeIn(500);
      var modalBox = $(this).attr('data-modal-id');
      $('#'+modalBox).fadeIn($(this).data());
    });

  $(".js-modal-close, .modal-overlay").click(function() {
      $(".modal-box, .modal-overlay").fadeOut(250, function() {
          $(".modal-overlay").remove();
      });

  });

  $(".arrow").hide();

  // Check devise/window size for scroll prompt
  $(window).on('load', function() {
    if ($(window).width() <= 800) {
      $(".arrow").show('slow').delay( 3000).hide('slow');
    } else {
      $(".arrow").hide();
    }
  });

  // Resize function with timeout to see if prompt should be shown to scroll of not
  var resizeTimer;

  $(window).on('resize', function(e) {

    clearTimeout(resizeTimer);
    resizeTimer = setTimeout(function() {

      if ($(window).width() <= 800) {
        $(".arrow").show('slow').delay( 3000).hide('slow');
      } else if ($(window).height() > 1050) {
        $(".arrow").hide();
      } else if ($(window).width() < 767) {
        $(".modal-box").addClass('fixed');
        $(".modal-box").removeClass('flex');
      } else {
        $(".modal-box").addClass('flex');
        $(".modal-box").removeClass('fixed');
        $(".arrow").hide();
      }

    }, 250);

  });

  // Image Map Resizer to keep coordinates for clickable items in the right location
  // on an image
  $('map').imageMapResize();
});
<|endoftext|>


<commit_before>/**
 * Application logic.
 *
 * @package themakermap
 */

(function($){
    /**
     * Configuration
     */
    var dataProvider = '1tteiG-HYAlsmh3ef5U-XVDEWu5QXqDxqWwDx-pc';

    /**
     * Storage objects
     */
    var map, layer;
    var makersLayer;

    /**
     * Window rendering handler.
     */
    function render () {
        var $map    = $('#map-wrapper');
        var calc    = $(window).height() - $map.position().top;

        $map.css('height', calc + 'px');
    }

    /**
     * Event handler for checkbox controls.
     *
     * @param {Object} Event
     *
     * @return {void}
     */
    function updateAnyCheckbox (e) {
        var $target = $(e.target);
        var $boxen  = $('#filter').find('input[type="checkbox"]').not('[value="any"]');
        var $any    = $('#filter').find('input[value="any"]');

        if ($target.val() == 'any') {
            // Update other checkboxes based on "any" state
            if ($any.is(':checked')) {
                $boxen.prop('checked', 'checked');
            } else {
                $boxen.removeAttr('checked');
            }
        } else {
            // Update "any" checkbox based on others' state
            if ($boxen.not(':checked').length) {
                $any.removeAttr('checked');
            } else {
                $any.prop('checked', 'checked');
            }
        }
    }

    /**
     * Generates a search query.
     *
     * @param {String} Search term
     *
     * @return {String}
     */
    function generateSearchQuery (term) {
        var q = term.replace(/^\s+|\s+$/g, "").replace(/'/g, '\\\'').toLowerCase();
            qp = "'Resource Name' CONTAINS IGNORING CASE '",
            qs = "'";

        if (q === '') return '';
        return qp + q + qs;
    }

    /**
     * Generates a filter query.
     *
     * @return {String}
     */
    function generateFilterQuery () {
        var q  = "",
            qp = "'Business Type' IN (",
            qs = ")",
            $filter = $('#filter');

        if ($filter.find('input[value="any"]:checked').length > 0) {
            return '';
        }

        $filter.find('input[type="checkbox"]:checked').each(function () {
            q += "'" + $(this).attr('value') + "', ";
        });

        q = q.slice(0, q.length - 2);
        if (q === '') return '';

        return qp + q + qs;
    }

    /**
     * Generates query object for the Google Fusion Tables API.
     *
     * @return {Object}
     */
    function generateQuery () {
        var search  = generateSearchQuery($('#search').find('input').val()),
            filter  = generateFilterQuery(),
            and     = (search !== '' && filter !== '') ? ' AND ' : '';

        return {
            select: 'Location',
            from:   dataProvider,
            where:  search + and + filter
        };
    }

    /**
     * Google Maps
     */
    function initMaps () {
        map = new google.maps.Map(document.getElementById('map-canvas'), {
            center: new google.maps.LatLng(-37.8136, 144.9631),
            zoom: 9,
            disableDefaultUI: true,
            zoomControl: true,
    		zoomControlOptions: {
    			style: google.maps.ZoomControlStyle.LARGE,
    			position: google.maps.ControlPosition.TOP_RIGHT
    		},
            streetViewControl: true
        });

        var style = [
            {
                elementType: 'geometry',
                stylers: [
                    { saturation: -100 },
                    { weight: 0.4 }
                ]
            },
            {
                featureType: 'poi',
                stylers: [
                    { visibility: "off" }
                ]
            },
            {
                featureType: 'administrative.land_parcel',
                elementType: 'all',
                stylers: [
                    { visibility: 'off' }
                ]
            }
        ];

        var styledMapType = new google.maps.StyledMapType(style, {
            map: map,
            name: 'Styled Map'
        });

        map.mapTypes.set('map-style', styledMapType);
        map.setMapTypeId('map-style');

        loadData();

        if (navigator && navigator.geolocation) {
           locateMe();
        }
    }

		function locateMe () {
			navigator.geolocation.getCurrentPosition(function(position) {
	      var latlng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
	      map.setCenter(latlng);
	      map.setZoom(12);

				$('.locateMe').fadeIn(1000,function(){
					$(this).tooltip('show');
				}).css("display",'table');

	    });

			$('.locateMe').click(function(){
				locateMe();
			});

		}

    /**
     * UI events
     */
    function initEventListeners () {
        // Selectors
        var $window = $(window);
        var $nav    = $('#topnav a');
        var $search = $('#search');
        var $filter = $('#filter');

        // Resize handler
        $window.resize(render);

        // Top nav
        $.hovertips($nav, {
            delay_hide:     0,
            delay_hover:    0,
            delay_leave:    0,
            render: function($el, data, loading) {
                var $tooltip;
                var self = this;
                $tooltip = $('
');
                $tooltip.addClass('nav-tooltip')
                $tooltip.html($el.find('img').attr('alt'));
                $el.on('click', function() {
                    self.hide(0);
                });
                return $tooltip;
            }
        });

        // Search
        $search.submit(function () {
            return false;
        });

        $search.find('input').keyup(function () {
            layer.setQuery(generateQuery());
        });

        // Filter
        $filter.find('input').click(function (e) {
            updateAnyCheckbox(e);
            layer.setQuery(generateQuery());
        });
    }

		function filterMenu() {
			$('.filterIcon').click(function(){
				$('.filterWrap').slideToggle();
			});
		}

		function mobileMenu() {
			$('.menuToggle').click(function(){
				$('.aboutWrap').slideToggle();
			});
		}

		function aboutModal() {
			var aboutContent = $('.aboutWrap').html();
			$('#aboutModal .modal-body').html(aboutContent);

			$('.about .searchAction').click(function(){
				console.log('click');
				$('#aboutModal').modal('hide')
				$('#searchForm').focus();
			});

		}

    function initSocialite() {
        Socialite.load($('div.footer'));
    }

    function makerToFeature(mkr) {
        var coords = mkr.get("coordinates").toJSON();
        var obj = {
            id: mkr.id,
            geometry: {
                lng: coords.longitude,
                lat: coords.latitude
            },
            properties: {
                title: mkr.get("title"),
                description: mkr.get("description"),
                marker_color: mkr.get("marker_color"),
                marker_size: mkr.get("marker_size"),
                marker_symbol: mkr.get("marker_symbol")
            }
        };
        return new google.maps.Data.Feature(obj);
    }

    function getIcon(symbolName) {
        if (!symbolName || symbolName == "") {
            return null;
        }
        return "/images/" + symbolName + ".png";
    }

    function loadData() {
        // Detach the layer before replacing
        if (makersLayer) {
            makersLayer.setMap(null);
        }
        makersLayer = new google.maps.Data()
        makersLayer.setStyle(function(feature) {
            return {
                fillColor: feature.getProperty("marker_color"),
                clickable: true,
                title: feature.getProperty("title"),
                icon: getIcon(feature.getProperty("marker_symbol"))
            };
        });
        var query = new Parse.Query(MakerMap.Model.Maker);
        query.find({
            success: function(resp) {
                for (var i = 0; i < resp.length; i++) {
                    makersLayer.add(makerToFeature(resp[i]));
                }
                makersLayer.setMap(map);
            },
            failure: function(err) {
                alert("Error loading markers: " + err);
            }
        })
    }

    //Init the parse API
    Parse.initialize("wj2jWY2HA6L4C1qpWuZzsruUHkO8BZjIbtUI0hmr" /* App ID */, "3GNfJdTZKsLlRrqsH1n8vJtrgFCRwuCmfb33Y2JG" /* JS Key */);
    /**
     * On load, init maps & start listening for UI events
     */
    render();
    initMaps();
    initEventListeners();
		filterMenu();
		mobileMenu();
		aboutModal();
    initSocialite();

})(jQuery);
<commit_msg>adds a listener to show a popup for the maker<commit_after>/**
 * Application logic.
 *
 * @package themakermap
 */

(function($){
    /**
     * Configuration
     */
    var dataProvider = '1tteiG-HYAlsmh3ef5U-XVDEWu5QXqDxqWwDx-pc';

    /**
     * Storage objects
     */
    var makersLayer;
    var map, layer, infoWindow;

    /**
     * Window rendering handler.
     */
    function render () {
        var $map    = $('#map-wrapper');
        var calc    = $(window).height() - $map.position().top;

        $map.css('height', calc + 'px');
    }

    /**
     * Event handler for checkbox controls.
     *
     * @param {Object} Event
     *
     * @return {void}
     */
    function updateAnyCheckbox (e) {
        var $target = $(e.target);
        var $boxen  = $('#filter').find('input[type="checkbox"]').not('[value="any"]');
        var $any    = $('#filter').find('input[value="any"]');

        if ($target.val() == 'any') {
            // Update other checkboxes based on "any" state
            if ($any.is(':checked')) {
                $boxen.prop('checked', 'checked');
            } else {
                $boxen.removeAttr('checked');
            }
        } else {
            // Update "any" checkbox based on others' state
            if ($boxen.not(':checked').length) {
                $any.removeAttr('checked');
            } else {
                $any.prop('checked', 'checked');
            }
        }
    }

    /**
     * Generates a search query.
     *
     * @param {String} Search term
     *
     * @return {String}
     */
    function generateSearchQuery (term) {
        var q = term.replace(/^\s+|\s+$/g, "").replace(/'/g, '\\\'').toLowerCase();
            qp = "'Resource Name' CONTAINS IGNORING CASE '",
            qs = "'";

        if (q === '') return '';
        return qp + q + qs;
    }

    /**
     * Generates a filter query.
     *
     * @return {String}
     */
    function generateFilterQuery () {
        var q  = "",
            qp = "'Business Type' IN (",
            qs = ")",
            $filter = $('#filter');

        if ($filter.find('input[value="any"]:checked').length > 0) {
            return '';
        }

        $filter.find('input[type="checkbox"]:checked').each(function () {
            q += "'" + $(this).attr('value') + "', ";
        });

        q = q.slice(0, q.length - 2);
        if (q === '') return '';

        return qp + q + qs;
    }

    /**
     * Generates query object for the Google Fusion Tables API.
     *
     * @return {Object}
     */
    function generateQuery () {
        var search  = generateSearchQuery($('#search').find('input').val()),
            filter  = generateFilterQuery(),
            and     = (search !== '' && filter !== '') ? ' AND ' : '';

        return {
            select: 'Location',
            from:   dataProvider,
            where:  search + and + filter
        };
    }

    /**
     * Google Maps
     */
    function initMaps () {
        map = new google.maps.Map(document.getElementById('map-canvas'), {
            center: new google.maps.LatLng(-37.8136, 144.9631),
            zoom: 9,
            disableDefaultUI: true,
            zoomControl: true,
    		zoomControlOptions: {
    			style: google.maps.ZoomControlStyle.LARGE,
    			position: google.maps.ControlPosition.TOP_RIGHT
    		},
            streetViewControl: true
        });

        var style = [
            {
                elementType: 'geometry',
                stylers: [
                    { saturation: -100 },
                    { weight: 0.4 }
                ]
            },
            {
                featureType: 'poi',
                stylers: [
                    { visibility: "off" }
                ]
            },
            {
                featureType: 'administrative.land_parcel',
                elementType: 'all',
                stylers: [
                    { visibility: 'off' }
                ]
            }
        ];

        var styledMapType = new google.maps.StyledMapType(style, {
            map: map,
            name: 'Styled Map'
        });

        map.mapTypes.set('map-style', styledMapType);
        map.setMapTypeId('map-style');

        infoWindow = new google.maps.InfoWindow({
            content: ""
        });
        loadData();

        if (navigator && navigator.geolocation) {
           locateMe();
        }
    }

		function locateMe () {
			navigator.geolocation.getCurrentPosition(function(position) {
	      var latlng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
	      map.setCenter(latlng);
	      map.setZoom(12);

				$('.locateMe').fadeIn(1000,function(){
					$(this).tooltip('show');
				}).css("display",'table');

	    });

			$('.locateMe').click(function(){
				locateMe();
			});

		}

    /**
     * UI events
     */
    function initEventListeners () {
        // Selectors
        var $window = $(window);
        var $nav    = $('#topnav a');
        var $search = $('#search');
        var $filter = $('#filter');

        // Resize handler
        $window.resize(render);

        // Top nav
        $.hovertips($nav, {
            delay_hide:     0,
            delay_hover:    0,
            delay_leave:    0,
            render: function($el, data, loading) {
                var $tooltip;
                var self = this;
                $tooltip = $('
');
                $tooltip.addClass('nav-tooltip')
                $tooltip.html($el.find('img').attr('alt'));
                $el.on('click', function() {
                    self.hide(0);
                });
                return $tooltip;
            }
        });

        // Search
        $search.submit(function () {
            return false;
        });

        $search.find('input').keyup(function () {
            layer.setQuery(generateQuery());
        });

        // Filter
        $filter.find('input').click(function (e) {
            updateAnyCheckbox(e);
            layer.setQuery(generateQuery());
        });
    }

		function filterMenu() {
			$('.filterIcon').click(function(){
				$('.filterWrap').slideToggle();
			});
		}

		function mobileMenu() {
			$('.menuToggle').click(function(){
				$('.aboutWrap').slideToggle();
			});
		}

		function aboutModal() {
			var aboutContent = $('.aboutWrap').html();
			$('#aboutModal .modal-body').html(aboutContent);

			$('.about .searchAction').click(function(){
				console.log('click');
				$('#aboutModal').modal('hide')
				$('#searchForm').focus();
			});

    		}

    function initSocialite() {
        Socialite.load($('div.footer'));
    }

    function makerToFeature(mkr) {
        var coords = mkr.get("coordinates").toJSON();
        var obj = {
            id: mkr.id,
            geometry: {
                lng: coords.longitude,
                lat: coords.latitude
            },
            properties: {
                title: mkr.get("title"),
                description: mkr.get("description"),
                marker_color: mkr.get("marker_color"),
                marker_size: mkr.get("marker_size"),
                marker_symbol: mkr.get("marker_symbol")
            }
        };
        return new google.maps.Data.Feature(obj);
    }

    function getIcon(symbolName) {
        if (!symbolName || symbolName == "") {
            return null;
        }
        return "/images/" + symbolName + ".png";
    }

    function loadData() {
        // Detach the layer before replacing
        if (makersLayer) {
            makersLayer.setMap(null);
        }
        makersLayer = new google.maps.Data()
        makersLayer.setStyle(function(feature) {
            return {
                fillColor: feature.getProperty("marker_color"),
                clickable: true,
                title: feature.getProperty("title"),
                icon: getIcon(feature.getProperty("marker_symbol"))
            };
        });
        var query = new Parse.Query(MakerMap.Model.Maker);
        query.find({
            success: function(resp) {
                for (var i = 0; i < resp.length; i++) {
                    makersLayer.add(makerToFeature(resp[i]));
                }
                makersLayer.setMap(map);
            },
            failure: function(err) {
                alert("Error loading markers: " + err);
            }
        })
    }

    $(function() {
        map.data.addListener('click', function(event) {
            infoWindow.setContent(
                '
'+event.feature.getProperty('title')+'
'+
                '
'+event.feature.getProperty('description')+'
'
            );
            var anchor = new google.maps.MVCObject();
            anchor.set("position",event.latLng);
            infoWindow.open(map,anchor);
        });
    });

    //Init the parse API
    Parse.initialize("wj2jWY2HA6L4C1qpWuZzsruUHkO8BZjIbtUI0hmr" /* App ID */, "3GNfJdTZKsLlRrqsH1n8vJtrgFCRwuCmfb33Y2JG" /* JS Key */);
    /**
     * On load, init maps & start listening for UI events
     */
    render();
    initMaps();
    initEventListeners();
		filterMenu();
		mobileMenu();
		aboutModal();
    initSocialite();

})(jQuery);
<|endoftext|>


<commit_before>(function () {
    function Person(data) {
        _.extend(this, data);
    }
    _.extend(Person.prototype, {

        age: function (date) {
            var birth = this.birth_date;
            if (typeof birth == 'number' || /^c/.test(birth)) {
                birth += '-07-01';
                birth = birth.replace(/^c\s+/, '');
            }
            return moment(date).diff(moment(birth, 'YYYY-MM-DD'), 'd') / 365.2425;
        },

        experience: function (date, pattern) {
            var ymd = moment(date).format('YYYY-MM-DD'),
                regexp = new RegExp(pattern),
                days = 0;
            this.positions.forEach(function (p) {
                if (p.start <= ymd && regexp.test(p.office)) {
                    var end = p.end <= ymd ? moment(p.end, 'YYYY-MM-DD') : moment(date);
                    days += end.diff(moment(p.start, 'YYYY-MM-DD'), 'd');
                }
            });
            return days / 365.2425;
        },

        councilExperience: function (date) {
            return this.experience(date, 'Council');
        },

        mayoralExperience: function (date) {
            return this.experience(date, 'Mayor');
        }
    });

    function Council() {
        _.extend(this, {
            members: [],
            add: [],
            remove: []
        });
    }
    _.extend(Council.prototype, {

        genderCount: function (gender) {
            return this.members.reduce(function (previousValue, currentPerson) {
                if (currentPerson.gender == gender) {
                    previousValue++;
                }
                return previousValue;
            }, 0);
        },

        women: function () {
            return this.genderCount('F');
        },

        men: function () {
            return this.genderCount('M');
        },

        ages: function (date) {
            return this.members.map(function (person) {
                return person.age(date);
            });
        },

        averageAge: function (date) {
            return this.ages(date).reduce(function (previous, current) {
                    return previous + current;
                }, 0) / this.members.length;
        },

        minAge: function (date) {
            return _.min(this.ages(date));
        },

        maxAge: function (date) {
            return _.max(this.ages(date));
        },

        totalCouncilExperience: function (date) {
            return this.members.reduce(function (previousValue, currentPerson) {
                return previousValue + currentPerson.councilExperience(date);
            }, 0);
        },

        totalMayoralExperience: function (date) {
            return this.members.reduce(function (previousValue, currentPerson) {
                return previousValue + currentPerson.mayoralExperience(date);
            }, 0);
        },

        changes: function () {
            var texts = [],
                lost = _.difference(this.remove, this.add),
                gained = _.difference(this.add, this.remove);
            if (lost.length) {
                texts.push('Lost ' + _.pluck(lost, 'name').join(', ') + '.');
            }
            if (gained.length) {
                texts.push('Gained ' + _.pluck(gained, 'name').join(', ') + '.');
            }
            return texts.join('
');
        }
    });

    fetch('data/person.json')
      .then(function (res) { return res.json(); } )
      .then(process);

    function process(personData) {
        console.log(personData);
        var councils = {},
            members = [];
        _.each(personData, function (data) {
            var person = new Person(data);
            person.positions.forEach(function (p) {
                if (!/Council/.test(p.office)) {
                    return;
                }
                if (p.start) {
                    if (!councils[p.start]) {
                        councils[p.start] = new Council();
                        councils[p.start].date = p.start;
                    }
                    councils[p.start].add.push(person);
                }
                else {
                    throw 'Missing start in ' + person.code;
                }
                if (p.end) {
                    if (!councils[p.end]) {
                        councils[p.end] = new Council();
                        councils[p.end].date = p.end;
                    }
                    councils[p.end].remove.push(person);
                }
            });
        });
        councils = _.pick(councils, _.keys(councils).sort());
        _.each(councils, function (c, date) {
            members = _.union(_.difference(members, c.remove), c.add);
            c.members = members.slice();
        });
        draw(councils);
    }

    function dataRow(council, date) {
        return {
            date: date,
            men: council.men(),
            women: council.women(),
            councilExperience: council.totalCouncilExperience(date),
            mayoralExperience: council.totalMayoralExperience(date),
            averageAge: council.averageAge(date),
            minAge: council.minAge(date),
            maxAge: council.maxAge(date),
            changes: council.changes()
        };
    }

    function millisToYmd(millis) {
        return moment(millis).utc().format('YYYY-MM-DD');
    }

    function draw(councils) {
        var data = [],
            prevCouncil;
        _.each(councils, function (council, ymd) {
            if (prevCouncil) {
                data.push(dataRow(prevCouncil, ymd));
            }
            data.push(dataRow(council, ymd));
            prevCouncil = council;
        });
        /*
        now = new Date();
        date = moment(prevCouncil.date).add(180, 'd').toDate();
        if (now.getTime() > date.getTime()) {
            date = now;
        }
        */
        data.push(dataRow(prevCouncil, moment().format('YYYY-MM-DD')));
        var xConfig = {
                type : 'timeseries',
                tick: {
                    format: '%Y',
                    values: _.range(1975, 2021, 2).map(function (y) { return y + '-01-01'; })
                },
                padding: 0
            },
            tooltipConfig = {
                format: {
                    title: function (x) {
                        return moment(x).format('D MMM YYYY');
                    },
                    value: function (value) {
                        return Array.isArray(value) ? _.uniq(value).map(function (item) { return item % 1 ? item.toFixed(2) : item; }).join(' ⮕ ') : value;
                    }
                },
                contents: function (d, defaultTitleFormat, defaultValueFormat, color) {
                    var newD = [],
                        ymd = moment(d[0].x).format('YYYY-MM-DD'),
                        html;
                    d.forEach(function (item) {
                        var last = newD.length && newD[newD.length - 1];
                        if (last && last.id === item.id) {
                            last.value.push(item.value);
                        }
                        else {
                            newD.push(_.extend({}, item, {value: [item.value]}));
                        }
                    });
                    html = c3.chart.internal.fn.getTooltipContent.call(this, newD, defaultTitleFormat, defaultValueFormat, color);
                    if (councils[ymd]) {
                        html = html.replace('
', '
' + councils[ymd].changes() + '

');
                    }
                    return html;
                }
            },
            zoomConfig = {
                enabled: true,
                type: 'scroll'
            };
        var charts = [
        c3.generate({
            bindto: '#women-graph',
            data: {
                x: 'date',
                type: 'area',
                groups: [['women', 'men']],
                colors: {
                    women: '#018571',
                    men: '#80cdc1'
                },
                names: {
                    women: 'Women',
                    men: 'Men'
                },
                columns: [
                    ['date'].concat(_.pluck(data, 'date')),
                    ['women'].concat(_.pluck(data, 'women')),
                    ['men'].concat(_.pluck(data, 'men'))
                ]
            },
            axis: {
                x: xConfig,
                y: {
                    max: 13,
                    tick: {
                        values: _.range(0, 14, 2),
                        outer: false
                    },
                    padding: 0
                }
            },
            point: {
                show: false,
                sensitivity: 100
            },
            padding: {right: 10},
            tooltip: tooltipConfig,
            zoom: zoomConfig
        }),
        c3.generate({
            bindto: '#experience-graph',
            data: {
                x: 'date',
                type: 'area',
                groups: [['councilExperience', 'mayoralExperience']],
                order: null,
                colors: {
                    councilExperience: '#a6611a',
                    mayoralExperience: '#dfc27d'
                },
                names: {
                    councilExperience: 'Years on Council',
                    mayoralExperience: 'Years as Mayor'
                },
                columns: [
                    ['date'].concat(_.pluck(data, 'date')),
                    ['councilExperience'].concat(_.pluck(data, 'councilExperience')),
                    ['mayoralExperience'].concat(_.pluck(data, 'mayoralExperience'))
                ]
            },
            axis: {
                x: xConfig,
                y: {
                    max: 155,
                    tick: {
                        values: _.range(0, 160, 20),
                        outer: false
                    },
                    padding: 0
                }
            },
            point: {
                show: false,
                sensitivity: 100
            },
            padding: {right: 10},
            tooltip: tooltipConfig,
            zoom: zoomConfig
        }),
        c3.generate({
            bindto: '#age-graph',
            data: {
                x: 'date',
                type: 'line',
                names: {
                    averageAge: 'Average',
                    minAge: 'Youngest',
                    maxAge: 'Oldest'
                },
                columns: [
                    ['date'].concat(_.pluck(data, 'date')),
                    ['averageAge'].concat(_.pluck(data, 'averageAge')),
                    ['minAge'].concat(_.pluck(data, 'minAge')),
                    ['maxAge'].concat(_.pluck(data, 'maxAge'))
                ]
            },
            axis: {
                x: xConfig,
                y: {
                    min: 25,
                    max: 85,
                    padding: 0,
                    outer: false
                }
            },
            point: {
                show: false,
                sensitivity: 100
            },
            padding: {right: 10},
            tooltip: tooltipConfig,
            zoom: zoomConfig
        })
        ];
        // Flush (redraw) is needed for some reason to get widths right
        charts.forEach(function (chart) { chart.flush(); });
    }
})();
<commit_msg>remove unnecessary code from index.js<commit_after>(function () {
    function Person(data) {
        _.extend(this, data);
    }
    _.extend(Person.prototype, {

        age: function (date) {
            var birth = this.birth_date;
            if (typeof birth == 'number' || /^c/.test(birth)) {
                birth += '-07-01';
                birth = birth.replace(/^c\s+/, '');
            }
            return moment(date).diff(moment(birth), 'd') / 365.2425;
        },

        experience: function (date, pattern) {
            var ymd = moment(date).format('YYYY-MM-DD'),
                regexp = new RegExp(pattern),
                days = 0;
            this.positions.forEach(function (p) {
                if (p.start <= ymd && regexp.test(p.office)) {
                    var end = p.end <= ymd ? moment(p.end) : moment(date);
                    days += end.diff(moment(p.start), 'd');
                }
            });
            return days / 365.2425;
        },

        councilExperience: function (date) {
            return this.experience(date, 'Council');
        },

        mayoralExperience: function (date) {
            return this.experience(date, 'Mayor');
        }
    });

    function Council() {
        _.extend(this, {
            members: [],
            add: [],
            remove: []
        });
    }
    _.extend(Council.prototype, {

        genderCount: function (gender) {
            return this.members.reduce(function (previousValue, currentPerson) {
                if (currentPerson.gender == gender) {
                    previousValue++;
                }
                return previousValue;
            }, 0);
        },

        women: function () {
            return this.genderCount('F');
        },

        men: function () {
            return this.genderCount('M');
        },

        ages: function (date) {
            return this.members.map(function (person) {
                return person.age(date);
            });
        },

        averageAge: function (date) {
            return this.ages(date).reduce(function (previous, current) {
                    return previous + current;
                }, 0) / this.members.length;
        },

        minAge: function (date) {
            return _.min(this.ages(date));
        },

        maxAge: function (date) {
            return _.max(this.ages(date));
        },

        totalCouncilExperience: function (date) {
            return this.members.reduce(function (previousValue, currentPerson) {
                return previousValue + currentPerson.councilExperience(date);
            }, 0);
        },

        totalMayoralExperience: function (date) {
            return this.members.reduce(function (previousValue, currentPerson) {
                return previousValue + currentPerson.mayoralExperience(date);
            }, 0);
        },

        changes: function () {
            var texts = [],
                lost = _.difference(this.remove, this.add),
                gained = _.difference(this.add, this.remove);
            if (lost.length) {
                texts.push('Lost ' + _.pluck(lost, 'name').join(', ') + '.');
            }
            if (gained.length) {
                texts.push('Gained ' + _.pluck(gained, 'name').join(', ') + '.');
            }
            return texts.join('
');
        }
    });

    fetch('data/person.json')
      .then(function (res) { return res.json(); } )
      .then(process);

    function process(personData) {
        var councils = {},
            members = [];
        _.each(personData, function (data) {
            var person = new Person(data);
            person.positions.forEach(function (p) {
                if (!/Council/.test(p.office)) {
                    return;
                }
                if (p.start) {
                    if (!councils[p.start]) {
                        councils[p.start] = new Council();
                        councils[p.start].date = p.start;
                    }
                    councils[p.start].add.push(person);
                }
                else {
                    throw 'Missing start in ' + person.code;
                }
                if (p.end) {
                    if (!councils[p.end]) {
                        councils[p.end] = new Council();
                        councils[p.end].date = p.end;
                    }
                    councils[p.end].remove.push(person);
                }
            });
        });
        councils = _.pick(councils, _.keys(councils).sort());
        _.each(councils, function (c, date) {
            members = _.union(_.difference(members, c.remove), c.add);
            c.members = members.slice();
        });
        draw(councils);
    }

    function dataRow(council, date) {
        return {
            date: date,
            men: council.men(),
            women: council.women(),
            councilExperience: council.totalCouncilExperience(date),
            mayoralExperience: council.totalMayoralExperience(date),
            averageAge: council.averageAge(date),
            minAge: council.minAge(date),
            maxAge: council.maxAge(date),
            changes: council.changes()
        };
    }

    function draw(councils) {
        var data = [],
            prevCouncil;
        _.each(councils, function (council, ymd) {
            if (prevCouncil) {
                data.push(dataRow(prevCouncil, ymd));
            }
            data.push(dataRow(council, ymd));
            prevCouncil = council;
        });
        /*
        now = new Date();
        date = moment(prevCouncil.date).add(180, 'd').toDate();
        if (now.getTime() > date.getTime()) {
            date = now;
        }
        */
        data.push(dataRow(prevCouncil, moment().format('YYYY-MM-DD')));
        var xConfig = {
                type : 'timeseries',
                tick: {
                    format: '%Y',
                    values: _.range(1975, 2021, 2).map(function (y) { return y + '-01-01'; })
                },
                padding: 0
            },
            tooltipConfig = {
                format: {
                    title: function (x) {
                        return moment(x).format('D MMM YYYY');
                    },
                    value: function (value) {
                        return Array.isArray(value) ? _.uniq(value).map(function (item) { return item % 1 ? item.toFixed(2) : item; }).join(' ⮕ ') : value;
                    }
                },
                contents: function (d, defaultTitleFormat, defaultValueFormat, color) {
                    var newD = [],
                        ymd = moment(d[0].x).format('YYYY-MM-DD'),
                        html;
                    d.forEach(function (item) {
                        var last = newD.length && newD[newD.length - 1];
                        if (last && last.id === item.id) {
                            last.value.push(item.value);
                        }
                        else {
                            newD.push(_.extend({}, item, {value: [item.value]}));
                        }
                    });
                    html = c3.chart.internal.fn.getTooltipContent.call(this, newD, defaultTitleFormat, defaultValueFormat, color);
                    if (councils[ymd]) {
                        html = html.replace('
', '
' + councils[ymd].changes() + '

');
                    }
                    return html;
                }
            },
            zoomConfig = {
                enabled: true,
                type: 'scroll'
            };
        var charts = [
        c3.generate({
            bindto: '#women-graph',
            data: {
                x: 'date',
                type: 'area',
                groups: [['women', 'men']],
                colors: {
                    women: '#018571',
                    men: '#80cdc1'
                },
                names: {
                    women: 'Women',
                    men: 'Men'
                },
                columns: [
                    ['date'].concat(_.pluck(data, 'date')),
                    ['women'].concat(_.pluck(data, 'women')),
                    ['men'].concat(_.pluck(data, 'men'))
                ]
            },
            axis: {
                x: xConfig,
                y: {
                    max: 13,
                    tick: {
                        values: _.range(0, 14, 2),
                        outer: false
                    },
                    padding: 0
                }
            },
            point: {
                show: false,
                sensitivity: 100
            },
            padding: {right: 10},
            tooltip: tooltipConfig,
            zoom: zoomConfig
        }),
        c3.generate({
            bindto: '#experience-graph',
            data: {
                x: 'date',
                type: 'area',
                groups: [['councilExperience', 'mayoralExperience']],
                order: null,
                colors: {
                    councilExperience: '#a6611a',
                    mayoralExperience: '#dfc27d'
                },
                names: {
                    councilExperience: 'Years on Council',
                    mayoralExperience: 'Years as Mayor'
                },
                columns: [
                    ['date'].concat(_.pluck(data, 'date')),
                    ['councilExperience'].concat(_.pluck(data, 'councilExperience')),
                    ['mayoralExperience'].concat(_.pluck(data, 'mayoralExperience'))
                ]
            },
            axis: {
                x: xConfig,
                y: {
                    max: 155,
                    tick: {
                        values: _.range(0, 160, 20),
                        outer: false
                    },
                    padding: 0
                }
            },
            point: {
                show: false,
                sensitivity: 100
            },
            padding: {right: 10},
            tooltip: tooltipConfig,
            zoom: zoomConfig
        }),
        c3.generate({
            bindto: '#age-graph',
            data: {
                x: 'date',
                type: 'line',
                names: {
                    averageAge: 'Average',
                    minAge: 'Youngest',
                    maxAge: 'Oldest'
                },
                columns: [
                    ['date'].concat(_.pluck(data, 'date')),
                    ['averageAge'].concat(_.pluck(data, 'averageAge')),
                    ['minAge'].concat(_.pluck(data, 'minAge')),
                    ['maxAge'].concat(_.pluck(data, 'maxAge'))
                ]
            },
            axis: {
                x: xConfig,
                y: {
                    min: 25,
                    max: 85,
                    padding: 0,
                    outer: false
                }
            },
            point: {
                show: false,
                sensitivity: 100
            },
            padding: {right: 10},
            tooltip: tooltipConfig,
            zoom: zoomConfig
        })
        ];
        // Flush (redraw) is needed for some reason to get widths right
        charts.forEach(function (chart) { chart.flush(); });
    }
})();
<|endoftext|>


<commit_before>//Clock
$(document).ready(function () {
    var setClock = function () {
        var now = new Date();
        var hours = now.getHours();
        var minutes = now.getMinutes();

        if (hours < 10) {
            hours = "0" + hours;
        }
        if (minutes < 10) {
            minutes = "0" + minutes;
        }

        if (hours > 12) {
            var hours = hours - 12;
            var ap = "p";
        } else if (hours == 12) {
            var ap = "p";
        } else if (hours == 24) {
            var hours = hours - 12;
            var ap = "a";
        } else {
            var ap = "a";
        }

        document.getElementById('clock').innerHTML = hours + ":" + minutes + ap;
    };

    setInterval(setClock, 1000);
    setClock();
});

$(".cont").ready(function () {
    setInterval(function () {
        var height = $(".foreground").height();
        var top = $(".foreground").height();
        var div = $(window).width();
        $(".cont").css("height", height + 30);
        $(".foreground").css("top", -top + 15);
        $(".text").css("margin-top", top - 60);
    }, 0.01);
});

//Color settings
$(document).ready(function () {
    setInterval(function () {
        var dawn = '#78d';
        var day = '#1bf';
        var dusk = '#036';

        var mood = new Date();
        var hour = mood.getSeconds() % 24; //mood.getHours();
        if ((hour > 5 && hour < 8) || (hour > 17 && hour < 19)) {
            $('body').css('background', dawn);
            $('.trees').css('fill', dawn);
            $('.sky-dawn').css('opacity', '1');
            $('.sky-day').css('opacity', '1');
            $('.hills').css('fill', '#c66');
        }
        // Day
        else if (hour > 7 && hour < 18) {
            $('body').css('background', day);
            $('.trees').css('fill', day);
            $('.sky-dawn').css('opacity', '0');
            $('.sky-day').css('opacity', '1');
            $('.hills').css('fill', '#db9');
        }
        // Night
        else {
            $('body').css('background', dusk);
            $('.trees').css('fill', dusk);
            $('.sky-day').css('opacity', '0');
            $('.hills').css('fill', '#0be');
        }
    }, 1000 * 60); // 1 Minute
});<commit_msg>Fix setMood interval<commit_after>//Clock
$(document).ready(function () {
    var setClock = function () {
        var now = new Date();
        var hours = now.getHours();
        var minutes = now.getMinutes();

        if (hours < 10) {
            hours = "0" + hours;
        }
        if (minutes < 10) {
            minutes = "0" + minutes;
        }

        if (hours > 12) {
            var hours = hours - 12;
            var ap = "p";
        } else if (hours == 12) {
            var ap = "p";
        } else if (hours == 24) {
            var hours = hours - 12;
            var ap = "a";
        } else {
            var ap = "a";
        }

        document.getElementById('clock').innerHTML = hours + ":" + minutes + ap;
    };

    setInterval(setClock, 1000);
    setClock();
});

$(".cont").ready(function () {
    setInterval(function () {
        var height = $(".foreground").height();
        var top = $(".foreground").height();
        var div = $(window).width();
        $(".cont").css("height", height + 30);
        $(".foreground").css("top", -top + 15);
        $(".text").css("margin-top", top - 60);
    }, 0.01);
});

//Color settings
$(document).ready(function () {
    var setMood = function () {
        var dawn = '#78d';
        var day = '#1bf';
        var dusk = '#036';

        var mood = new Date();
        var hour = mood.getHours();
        if ((hour > 5 && hour < 8) || (hour > 17 && hour < 19)) {
            $('body').css('background', dawn);
            $('.trees').css('fill', dawn);
            $('.sky-dawn').css('opacity', '1');
            $('.sky-day').css('opacity', '1');
            $('.hills').css('fill', '#c66');
        }
        // Day
        else if (hour > 7 && hour < 18) {
            $('body').css('background', day);
            $('.trees').css('fill', day);
            $('.sky-dawn').css('opacity', '0');
            $('.sky-day').css('opacity', '1');
            $('.hills').css('fill', '#db9');
        }
        // Night
        else {
            $('body').css('background', dusk);
            $('.trees').css('fill', dusk);
            $('.sky-day').css('opacity', '0');
            $('.hills').css('fill', '#0be');
        }
    };

    setInterval(setMood, 1000 * 60); // 1 Minute
    setMood();
});<|endoftext|>


<commit_before>'use strict';

function button_click(button_id){
    // Set button color and value.
    document.getElementById(button_id).classList.remove('color10');
    document.getElementById(button_id).classList.add('color' + button_values[button_id]);

    document.getElementById(button_id).value = [
      'ABCDEFGHIJ'[button_values[button_id]],
      button_values[button_id],
      '~!@#$%^&*('[button_values[button_id]]
    ][document.getElementById('display-select').value];

    var loop_counter = 19;
    // If this is first button of button pair.
    if(selected_button[0] === -1){
        // Reset other buttons that haven't been matched yet.
        do{
            if(button_values[loop_counter] > -1
              && loop_counter !== button_id){
                document.getElementById(loop_counter).classList.remove('color' + button_values[loop_counter]);
                document.getElementById(loop_counter).classList.add('color10');
                document.getElementById(loop_counter).value = '-';
            }
        }while(loop_counter--);

        // Store button information.
        selected_button = [
          button_values[button_id],
          button_id,
        ];

        // Disable this button to prevent reclicks.
        document.getElementById(button_id).disabled = true;

        return;
    }

    document.getElementById('attempted-matches').innerHTML =
      parseInt(document.getElementById('attempted-matches').innerHTML) + 1;

    // If value of this button matches the value of the previously selected button.
    if(selected_button[0] === button_values[button_id]){
        // Set button values to -1 to prevent them from being reset.
        button_values[button_id] = -1;
        button_values[selected_button[1]] = -1;
    }

    // Check if there are any enabled buttons left.
    var buttons_remain = false;
    do{
        document.getElementById(loop_counter).disabled = button_values[loop_counter] < 0;

        if(!document.getElementById(loop_counter).disabled){
            buttons_remain = true;
        }
    }while(loop_counter--);

    selected_button = [
      -1,
      -1,
    ];

    // If not, end game.
    if(!buttons_remain){
        stop();
    }
}

function decisecond(){
    // If max-time is set, decrease time by .1sec, else add .1sec.
    document.getElementById('time').innerHTML = (
      parseFloat(document.getElementById('time').innerHTML)
      + (document.getElementById('max-time').value > 0
        ? -.1
        : .1
      )
    ).toFixed(1);

    // If time can run out, check if game over.
    if(document.getElementById('max-time').value > 0
      && document.getElementById('time').innerHTML <= 0){
        stop();
    }
}

function play_audio(id){
    if(document.getElementById('audio-volume').value <= 0){
        return;
    }

    document.getElementById(id).volume = document.getElementById('audio-volume').value;
    document.getElementById(id).currentTime = 0;
    document.getElementById(id).play();
}

function reset(){
    if(!window.confirm('Reset settings?')){
        return;
    }

    document.getElementById('audio-volume').value = 1;
    document.getElementById('display-select').value = 1;
    document.getElementById('max-time').value = 0;
    document.getElementById('start-key').value = 'H';
    document.getElementById('y-margin').value = 0;

    save();
}

// Save settings into window.localStorage if they differ from default.
function save(){
    var ids = {
      'audio-volume': 1,
      'display-select': 1,
      'max-time': 0,
      'start-key': 'H',
      'y-margin': 0,
    };
    for(var id in ids){
        if(document.getElementById(id).value == ids[id]){
            window.localStorage.removeItem('Match.htm-' + id);

        }else{
            window.localStorage.setItem(
              'Match.htm-' + id,
              document.getElementById(id).value
            );
        }
    }
}

function settings_toggle(state){
    state = state == void 0
      ? document.getElementById('settings-button').value === '+'
      : state;

    if(state){
        document.getElementById('settings-span').style.display = 'inline';
        document.getElementById('settings-button').value = '-';

    }else{
        document.getElementById('settings-span').style.display = 'none';
        document.getElementById('settings-button').value = '+';
    }
}

function start(){
    document.getElementById('attempted-matches').innerHTML = 0;

    // Validate settings.
    var ids = {
      'audio-volume': 1,
      'max-time': 0,
      'y-margin': 0,
    };
    for(var id in ids){
        if(isNaN(document.getElementById(id).value)
          || document.getElementById(id).value < 0){
            document.getElementById(id).value = ids[id];
        }
    }

    // Set margin-top of table based on y-margin.
    document.getElementById('table').style.marginTop = document.getElementById('y-margin').value + 'px';

    // Generate button pairs.
    var loop_counter = 19;
    var tempinfo = [
      -1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,
    ];
    var temp = 0;
    do{
        document.getElementById(loop_counter).disabled = false;

        var pairs_counter = 9;
        do{
            document.getElementById(loop_counter).classList.remove('color' + pairs_counter);
        }while(pairs_counter--);

        document.getElementById(loop_counter).classList.add('color10');
        document.getElementById(loop_counter).value = '-';

        do{
            temp = Math.floor(Math.random() * 20);
        }while(tempinfo[temp] != -1);

        tempinfo[temp] = Math.floor(temp / 2);
        button_values[loop_counter] = Math.floor(temp / 2);
    }while(loop_counter--);

    document.getElementById('start-button').value = 'End [ESC]';
    document.getElementById('start-button').onclick = stop;

    // Display time limit if it is greater than 0.
    if(document.getElementById('max-time').value > 0){
        document.getElementById('time').innerHTML = document.getElementById('max-time').value;
        document.getElementById('time-max').innerHTML = document.getElementById('max-time').value;
        document.getElementById('if-time-limit').style.display = 'inline';

    }else{
        document.getElementById('time').innerHTML = 0;
        document.getElementById('if-time-limit').style.display = 'none';
    }

    interval = window.setInterval(
      'decisecond()',
      100
    );
    save();
}

function stop(){
    window.clearInterval(interval);

    document.getElementById('start-button').value = 'Start [' + document.getElementById('start-key').value + ']';
    document.getElementById('start-button').onclick = start;

    // Disable all game-area buttons.
    var loop_counter = 19;
    do{
        document.getElementById(loop_counter).disabled = true;
    }while(loop_counter--);

    // Blank out button values.
    button_values = [
      -1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,
    ];
    selected_button = [
      -1,
      -1,
    ];
}

var button_values = [
  -1,-1,-1,-1,-1,
  -1,-1,-1,-1,-1,
  -1,-1,-1,-1,-1,
  -1,-1,-1,-1,-1,
];
var interval = 0;
var selected_button = [-1, -1,];

window.onkeydown = function(e){
    var key = e.keyCode || e.which;

    if(String.fromCharCode(key) === document.getElementById('start-key').value){
        stop();
        start();

    // ESC: stop current game.
    }else if(key === 27){
        stop();

    // +: show settings.
    }else if(key === 187){
        settings_toggle(true);

    // -: hide settings.
    }else if(key === 189){
        settings_toggle(false);
    }
};

window.onload = function(){
    // Fetch settings from window.localStorage and update settings inputs.
    document.getElementById('audio-volume').value =
      parseFloat(window.localStorage.getItem('Match.htm-audio-volume')) || 1,
    document.getElementById('display-select').value =
      window.localStorage.getItem('Match.htm-display-select') || 1;
    document.getElementById('max-time').value =
      parseInt(window.localStorage.getItem('Match.htm-max-time')) || 0;
    document.getElementById('y-margin').value =
      parseInt(window.localStorage.getItem('Match.htm-y-margin')) || 0;

    // Set value of start-key if saved into window.localStorage.
    if(window.localStorage.getItem('Match.htm-start-key') === null){
        document.getElementById('start-key').value = 'H';

    }else{
        document.getElementById('start-key').value =
          window.localStorage.getItem('Match.htm-start-key');
        document.getElementById('start-button').value =
          'Start [' + window.localStorage.getItem('Match.htm-start-key') + ']';
    }

    // Set margin-top of table based on y-margin.
    document.getElementById('table').style.marginTop = document.getElementById('y-margin').value + 'px';

    // Setup buttons in game-area.
    var output = '';

    for(var loop_counter = 0; loop_counter < 20; loop_counter++){
        if(loop_counter % 5 === 0
          && loop_counter !== 0){
            output += '
';
        }
        output +=
          '<input class="buttons color10" disabled id=' + loop_counter
          + ' onclick=button_click(' + loop_counter
          + ') type=button value=->';
    }
    document.getElementById('game-area').innerHTML = output;
};
<commit_msg>simplified onload<commit_after>'use strict';

function button_click(button_id){
    // Set button color and value.
    document.getElementById(button_id).classList.remove('color10');
    document.getElementById(button_id).classList.add('color' + button_values[button_id]);

    document.getElementById(button_id).value = [
      'ABCDEFGHIJ'[button_values[button_id]],
      button_values[button_id],
      '~!@#$%^&*('[button_values[button_id]]
    ][document.getElementById('display-select').value];

    var loop_counter = 19;
    // If this is first button of button pair.
    if(selected_button[0] === -1){
        // Reset other buttons that haven't been matched yet.
        do{
            if(button_values[loop_counter] > -1
              && loop_counter !== button_id){
                document.getElementById(loop_counter).classList.remove('color' + button_values[loop_counter]);
                document.getElementById(loop_counter).classList.add('color10');
                document.getElementById(loop_counter).value = '-';
            }
        }while(loop_counter--);

        // Store button information.
        selected_button = [
          button_values[button_id],
          button_id,
        ];

        // Disable this button to prevent reclicks.
        document.getElementById(button_id).disabled = true;

        return;
    }

    document.getElementById('attempted-matches').innerHTML =
      parseInt(document.getElementById('attempted-matches').innerHTML) + 1;

    // If value of this button matches the value of the previously selected button.
    if(selected_button[0] === button_values[button_id]){
        // Set button values to -1 to prevent them from being reset.
        button_values[button_id] = -1;
        button_values[selected_button[1]] = -1;
    }

    // Check if there are any enabled buttons left.
    var buttons_remain = false;
    do{
        document.getElementById(loop_counter).disabled = button_values[loop_counter] < 0;

        if(!document.getElementById(loop_counter).disabled){
            buttons_remain = true;
        }
    }while(loop_counter--);

    selected_button = [
      -1,
      -1,
    ];

    // If not, end game.
    if(!buttons_remain){
        stop();
    }
}

function decisecond(){
    // If max-time is set, decrease time by .1sec, else add .1sec.
    document.getElementById('time').innerHTML = (
      parseFloat(document.getElementById('time').innerHTML)
      + (document.getElementById('max-time').value > 0
        ? -.1
        : .1
      )
    ).toFixed(1);

    // If time can run out, check if game over.
    if(document.getElementById('max-time').value > 0
      && document.getElementById('time').innerHTML <= 0){
        stop();
    }
}

function play_audio(id){
    if(document.getElementById('audio-volume').value <= 0){
        return;
    }

    document.getElementById(id).volume = document.getElementById('audio-volume').value;
    document.getElementById(id).currentTime = 0;
    document.getElementById(id).play();
}

function reset(){
    if(!window.confirm('Reset settings?')){
        return;
    }

    document.getElementById('audio-volume').value = 1;
    document.getElementById('display-select').value = 1;
    document.getElementById('max-time').value = 0;
    document.getElementById('start-key').value = 'H';
    document.getElementById('y-margin').value = 0;

    save();
}

// Save settings into window.localStorage if they differ from default.
function save(){
    var ids = {
      'audio-volume': 1,
      'display-select': 1,
      'max-time': 0,
      'start-key': 'H',
      'y-margin': 0,
    };
    for(var id in ids){
        if(document.getElementById(id).value == ids[id]){
            window.localStorage.removeItem('Match.htm-' + id);

        }else{
            window.localStorage.setItem(
              'Match.htm-' + id,
              document.getElementById(id).value
            );
        }
    }
}

function settings_toggle(state){
    state = state == void 0
      ? document.getElementById('settings-button').value === '+'
      : state;

    if(state){
        document.getElementById('settings-span').style.display = 'inline';
        document.getElementById('settings-button').value = '-';

    }else{
        document.getElementById('settings-span').style.display = 'none';
        document.getElementById('settings-button').value = '+';
    }
}

function start(){
    document.getElementById('attempted-matches').innerHTML = 0;

    // Validate settings.
    var ids = {
      'audio-volume': 1,
      'max-time': 0,
      'y-margin': 0,
    };
    for(var id in ids){
        if(isNaN(document.getElementById(id).value)
          || document.getElementById(id).value < 0){
            document.getElementById(id).value = ids[id];
        }
    }

    // Set margin-top of table based on y-margin.
    document.getElementById('table').style.marginTop = document.getElementById('y-margin').value + 'px';

    // Generate button pairs.
    var loop_counter = 19;
    var tempinfo = [
      -1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,
    ];
    var temp = 0;
    do{
        document.getElementById(loop_counter).disabled = false;

        var pairs_counter = 9;
        do{
            document.getElementById(loop_counter).classList.remove('color' + pairs_counter);
        }while(pairs_counter--);

        document.getElementById(loop_counter).classList.add('color10');
        document.getElementById(loop_counter).value = '-';

        do{
            temp = Math.floor(Math.random() * 20);
        }while(tempinfo[temp] != -1);

        tempinfo[temp] = Math.floor(temp / 2);
        button_values[loop_counter] = Math.floor(temp / 2);
    }while(loop_counter--);

    document.getElementById('start-button').value = 'End [ESC]';
    document.getElementById('start-button').onclick = stop;

    // Display time limit if it is greater than 0.
    if(document.getElementById('max-time').value > 0){
        document.getElementById('time').innerHTML = document.getElementById('max-time').value;
        document.getElementById('time-max').innerHTML = document.getElementById('max-time').value;
        document.getElementById('if-time-limit').style.display = 'inline';

    }else{
        document.getElementById('time').innerHTML = 0;
        document.getElementById('if-time-limit').style.display = 'none';
    }

    interval = window.setInterval(
      'decisecond()',
      100
    );
    save();
}

function stop(){
    window.clearInterval(interval);

    document.getElementById('start-button').value = 'Start [' + document.getElementById('start-key').value + ']';
    document.getElementById('start-button').onclick = start;

    // Disable all game-area buttons.
    var loop_counter = 19;
    do{
        document.getElementById(loop_counter).disabled = true;
    }while(loop_counter--);

    // Blank out button values.
    button_values = [
      -1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,
    ];
    selected_button = [
      -1,
      -1,
    ];
}

var button_values = [
  -1,-1,-1,-1,-1,
  -1,-1,-1,-1,-1,
  -1,-1,-1,-1,-1,
  -1,-1,-1,-1,-1,
];
var interval = 0;
var selected_button = [-1, -1,];

window.onkeydown = function(e){
    var key = e.keyCode || e.which;

    if(String.fromCharCode(key) === document.getElementById('start-key').value){
        stop();
        start();

    // ESC: stop current game.
    }else if(key === 27){
        stop();

    // +: show settings.
    }else if(key === 187){
        settings_toggle(true);

    // -: hide settings.
    }else if(key === 189){
        settings_toggle(false);
    }
};

window.onload = function(){
    // Fetch settings from window.localStorage and update settings inputs.
    document.getElementById('audio-volume').value =
      parseFloat(window.localStorage.getItem('Match.htm-audio-volume')) || 1,
    document.getElementById('display-select').value =
      window.localStorage.getItem('Match.htm-display-select') || 1;
    var ids = {
      'max-time': 0,
      'y-margin': 0,
    };
    for(var id in ids){
        document.getElementById(id).value =
          parseInt(window.localStorage.getItem('Match.htm-' + id)) || ids[id];
    }

    // Set value of start-key if saved into window.localStorage.
    if(window.localStorage.getItem('Match.htm-start-key') === null){
        document.getElementById('start-key').value = 'H';

    }else{
        document.getElementById('start-key').value =
          window.localStorage.getItem('Match.htm-start-key');
        document.getElementById('start-button').value =
          'Start [' + window.localStorage.getItem('Match.htm-start-key') + ']';
    }

    // Set margin-top of table based on y-margin.
    document.getElementById('table').style.marginTop = document.getElementById('y-margin').value + 'px';

    // Setup buttons in game-area.
    var output = '';

    for(var loop_counter = 0; loop_counter < 20; loop_counter++){
        if(loop_counter % 5 === 0
          && loop_counter !== 0){
            output += '
';
        }
        output +=
          '<input class="buttons color10" disabled id=' + loop_counter
          + ' onclick=button_click(' + loop_counter
          + ') type=button value=->';
    }
    document.getElementById('game-area').innerHTML = output;
};
<|endoftext|>


<commit_before>/* Emulate the native <audio> element with Web Audio API */
import { BANDS } from "./constants";
import MyFile from "./myFile";

export default {
  _context: new (window.AudioContext || window.webkitAudioContext)(),
  _source: null,
  _buffer: null,
  _callbacks: {
    waiting: function() {},
    stopWaiting: function() {},
    playing: function() {},
    timeupdate: function() {},
    visualizerupdate: function() {},
    ended: function() {},
    fileLoaded: function() {}
  },
  _startTime: 0,
  _position: 0,
  _balance: 0,
  _playing: false,
  _loop: false,
  autoPlay: false,
  name: null,

  init: function(fileInput) {
    this.fileInput = fileInput;

    // The _source node has to be recreated each time it's stopped or
    // paused, so we don't create it here.

    // Create the preamp node
    this._preamp = this._context.createGain();

    // Create the spliter node
    this._chanSplit = this._context.createChannelSplitter(2);

    // Create the gains for left and right
    this._leftGain = this._context.createGain();
    this._rightGain = this._context.createGain();

    // Create channel merge
    this._chanMerge = this._context.createChannelMerger(2);

    // Create the gain node for the volume control
    this._gainNode = this._context.createGain();

    // Create the analyser node for the visualizer
    this._analyser = this._context.createAnalyser();
    this._analyser.fftSize = 2048;

    // Connect all the nodes in the correct way
    // (Note, source is created and connected later)
    //
    //                 <source>
    //                    |\
    //                    | <analyser>
    //                    |
    //    (split using createChannelSplitter)
    //                    |
    //                   / \
    //                  /   \
    //             leftGain rightGain
    //                  \   /
    //                   \ /
    //                    |
    //     (merge using createChannelMerger)
    //                    |
    //                chanMerge
    //                    |
    //                   gain
    //                    |
    //               destination

    this._preamp.connect(this._chanSplit);

    // Connect split channels to left / right gains
    this._chanSplit.connect(this._leftGain, 0);
    this._chanSplit.connect(this._rightGain, 1);

    // Reconnect the left / right gains to the merge node
    this._leftGain.connect(this._chanMerge, 0, 0);
    this._rightGain.connect(this._chanMerge, 0, 1);

    const output = this._chanMerge;
    this.bands = {};

    BANDS.forEach((band, i) => {
      const filter = this._context.createBiquadFilter();

      this.bands[band] = filter;

      if (i === 0) {
        // The first filter, includes all lower frequencies
        filter.type = "lowshelf";
      } else if (i === band.length - 1) {
        // The last filter, includes all higher frequencies
        filter.type = "highshelf";
      } else {
        filter.type = "peaking";
      }
      filter.frequency.value = band;
      filter.gain.value = 0;
      /*
      Disable this while we wait for Safari to fix its bug.
      output.connect(filter);
      output = filter;
      */
    });

    output.connect(this._gainNode);
    this._gainNode.connect(this._context.destination);

    // Kick off the animation loop
    this._draw(0);
    return this;
  },

  // Load from bufferArray
  loadBuffer: function(buffer, loadedCallback) {
    this.stop();
    this._callbacks.waiting();

    const loadAudioBuffer = function(audioBuffer) {
      this._buffer = audioBuffer;
      loadedCallback();
      this._callbacks.stopWaiting();
      if (this.autoPlay) {
        this.play(0);
      }
    };

    const error = function(errorMessage) {
      console.error("failed to decode:", errorMessage);
    };
    // Decode the target file into an arrayBuffer and pass it to loadBuffer
    this._context.decodeAudioData(buffer, loadAudioBuffer.bind(this), error);
  },

  /* Properties */
  duration: function() {
    return this._buffer.duration;
  },
  timeElapsed: function() {
    return this._position;
  },
  timeRemaining: function() {
    return this.duration() - this.timeElapsed();
  },
  percentComplete: function() {
    return this.timeElapsed() / this.duration() * 100;
  },
  channels: function() {
    if (!this._buffer) {
      return 0;
    }
    return this._buffer.numberOfChannels;
  },
  sampleRate: function() {
    return this._buffer.sampleRate;
  },

  /* Actions */
  previous: function() {
    // Implement this when we support playlists
  },
  play: function(position) {
    if (this._playing) {
      // So we don't get a race condition with _position getting overwritten
      this.pause();
    }
    if (this._buffer) {
      this._source = this._context.createBufferSource();
      this._source.buffer = this._buffer;
      this._source.connect(this._analyser);
      this._source.connect(this._preamp);

      this._position = typeof position !== "undefined"
        ? position
        : this._position;
      this._startTime = this._context.currentTime - this._position;
      this._source.start(0, this._position);
      this._playing = true;
      this._callbacks.playing();
    }
  },
  pause: function() {
    if (!this._playing) {
      return;
    }
    this._silence();
    this._updatePosition();
  },

  stop: function() {
    this._silence();
    this._position = 0;
  },

  _silence: function() {
    if (this._source) {
      this._source.stop(0);
      this._source = null;
    }
    this._playing = false;
  },

  /* Actions with arguments */
  seekToPercentComplete: function(percent) {
    const seekTime = this.duration() * (percent / 100);
    this.seekToTime(seekTime);
  },

  // From 0-1
  setVolume: function(volume) {
    this._gainNode.gain.value = volume / 100;
  },

  // From 0-1
  setPreamp: function(value) {
    this._preamp.gain.value = value / 100;
  },

  // From -100 to 100
  setBalance: function(balance) {
    let changeVal = Math.abs(balance) / 100;

    // Hack for Firefox. Having either channel set to 0 seems to revert us
    // to equal balance.
    changeVal = changeVal - 0.00000001;

    if (balance > 0) {
      // Right
      this._leftGain.gain.value = 1 - changeVal;
      this._rightGain.gain.value = 1;
    } else if (balance < 0) {
      // Left
      this._leftGain.gain.value = 1;
      this._rightGain.gain.value = 1 - changeVal;
    } else {
      // Center
      this._leftGain.gain.value = 1;
      this._rightGain.gain.value = 1;
    }
    this._balance = balance;
  },

  setEqBand: function(band, value) {
    const db = value / 100 * 24 - 12;
    this.bands[band].gain.value = db;
  },

  toggleRepeat: function() {
    this._loop = !this._loop;
  },

  toggleShuffle: function() {
    // Implement this when we support playlists
  },

  /* Listeners */
  addEventListener: function(event, callback) {
    this._callbacks[event] = callback;
  },

  seekToTime: function(time) {
    // Make sure we are within range
    // TODO: Use clamp
    time = Math.min(time, this.duration());
    time = Math.max(time, 0);
    this.play(time);
  },

  loadFromFileReference: function(fileReference) {
    const file = new MyFile();
    file.setFileReference(fileReference);
    this.autoPlay = true;
    this.name = file.name;
    file.processBuffer(this._loadBuffer.bind(this));
  },

  // Used only for the initial load, since it must have a CORS header
  loadFromUrl: function(url, fileName) {
    const file = new MyFile();
    this.name = fileName;
    file.setUrl(url, fileName);
    file.processBuffer(this._loadBuffer.bind(this));
  },

  /* Listeners */
  _loadBuffer: function(buffer) {
    // Note, this will not happen right away
    this.loadBuffer(buffer, this._callbacks.fileLoaded);
  },

  // There is probably a more reasonable way to do this, rather than having
  // it always running.
  _draw: function() {
    if (this._playing) {
      this._updatePosition();
      this._callbacks.timeupdate();
    }
    window.requestAnimationFrame(this._draw.bind(this));
  },

  _updatePosition: function() {
    this._position = this._context.currentTime - this._startTime;
    if (this._position >= this._buffer.duration && this._playing) {
      // Idealy we could use _source.loop, but it makes updating the position tricky
      if (this._loop) {
        this.play(0);
      } else {
        this.stop();
        this._callbacks.ended();
      }
    }
  }
};
<commit_msg>Work around Safari biquad filter bug!<commit_after>/* Emulate the native <audio> element with Web Audio API */
import { BANDS } from "./constants";
import MyFile from "./myFile";

export default {
  _context: new (window.AudioContext || window.webkitAudioContext)(),
  _source: null,
  _buffer: null,
  _callbacks: {
    waiting: function() {},
    stopWaiting: function() {},
    playing: function() {},
    timeupdate: function() {},
    visualizerupdate: function() {},
    ended: function() {},
    fileLoaded: function() {}
  },
  _startTime: 0,
  _position: 0,
  _balance: 0,
  _playing: false,
  _loop: false,
  autoPlay: false,
  name: null,

  init: function(fileInput) {
    this.fileInput = fileInput;

    // The _source node has to be recreated each time it's stopped or
    // paused, so we don't create it here.

    // Create the preamp node
    this._preamp = this._context.createGain();

    // Create the spliter node
    this._chanSplit = this._context.createChannelSplitter(2);

    // Create the gains for left and right
    this._leftGain = this._context.createGain();
    this._rightGain = this._context.createGain();

    // Create channel merge
    this._chanMerge = this._context.createChannelMerger(2);

    // Create the gain node for the volume control
    this._gainNode = this._context.createGain();

    // Create the analyser node for the visualizer
    this._analyser = this._context.createAnalyser();
    this._analyser.fftSize = 2048;

    // Connect all the nodes in the correct way
    // (Note, source is created and connected later)
    //
    //                 <source>
    //                    |\
    //                    | <analyser>
    //                    |
    //    (split using createChannelSplitter)
    //                    |
    //                   / \
    //                  /   \
    //             leftGain rightGain
    //                  \   /
    //                   \ /
    //                    |
    //     (merge using createChannelMerger)
    //                    |
    //                chanMerge
    //                    |
    //                   gain
    //                    |
    //               destination

    this._preamp.connect(this._chanSplit);

    // Connect split channels to left / right gains
    this._chanSplit.connect(this._leftGain, 0);
    this._chanSplit.connect(this._rightGain, 1);

    // Reconnect the left / right gains to the merge node
    this._leftGain.connect(this._chanMerge, 0, 0);
    this._rightGain.connect(this._chanMerge, 0, 1);

    // Safari, both mobile and desktop, has a bug where
    // connecting a merger node to biquad filter node
    // will cause it to crash. Adding this dummy node
    // works around this bug.
    const dummyNode = this._context.createAnalyser();
    this._chanMerge.connect(dummyNode);

    let output = dummyNode;
    this.bands = {};

    BANDS.forEach((band, i) => {
      const filter = this._context.createBiquadFilter();

      this.bands[band] = filter;

      if (i === 0) {
        // The first filter, includes all lower frequencies
        filter.type = "lowshelf";
      } else if (i === band.length - 1) {
        // The last filter, includes all higher frequencies
        filter.type = "highshelf";
      } else {
        filter.type = "peaking";
      }
      filter.frequency.value = band;
      filter.gain.value = 0;

      output.connect(filter);
      output = filter;
    });

    output.connect(this._gainNode);
    this._gainNode.connect(this._context.destination);

    // Kick off the animation loop
    this._draw(0);
    return this;
  },

  // Load from bufferArray
  loadBuffer: function(buffer, loadedCallback) {
    this.stop();
    this._callbacks.waiting();

    const loadAudioBuffer = function(audioBuffer) {
      this._buffer = audioBuffer;
      loadedCallback();
      this._callbacks.stopWaiting();
      if (this.autoPlay) {
        this.play(0);
      }
    };

    const error = function(errorMessage) {
      console.error("failed to decode:", errorMessage);
    };
    // Decode the target file into an arrayBuffer and pass it to loadBuffer
    this._context.decodeAudioData(buffer, loadAudioBuffer.bind(this), error);
  },

  /* Properties */
  duration: function() {
    return this._buffer.duration;
  },
  timeElapsed: function() {
    return this._position;
  },
  timeRemaining: function() {
    return this.duration() - this.timeElapsed();
  },
  percentComplete: function() {
    return this.timeElapsed() / this.duration() * 100;
  },
  channels: function() {
    if (!this._buffer) {
      return 0;
    }
    return this._buffer.numberOfChannels;
  },
  sampleRate: function() {
    return this._buffer.sampleRate;
  },

  /* Actions */
  previous: function() {
    // Implement this when we support playlists
  },
  play: function(position) {
    if (this._playing) {
      // So we don't get a race condition with _position getting overwritten
      this.pause();
    }
    if (this._buffer) {
      this._source = this._context.createBufferSource();
      this._source.buffer = this._buffer;
      this._source.connect(this._analyser);
      this._source.connect(this._preamp);

      this._position = typeof position !== "undefined"
        ? position
        : this._position;
      this._startTime = this._context.currentTime - this._position;
      this._source.start(0, this._position);
      this._playing = true;
      this._callbacks.playing();
    }
  },
  pause: function() {
    if (!this._playing) {
      return;
    }
    this._silence();
    this._updatePosition();
  },

  stop: function() {
    this._silence();
    this._position = 0;
  },

  _silence: function() {
    if (this._source) {
      this._source.stop(0);
      this._source = null;
    }
    this._playing = false;
  },

  /* Actions with arguments */
  seekToPercentComplete: function(percent) {
    const seekTime = this.duration() * (percent / 100);
    this.seekToTime(seekTime);
  },

  // From 0-1
  setVolume: function(volume) {
    this._gainNode.gain.value = volume / 100;
  },

  // From 0-1
  setPreamp: function(value) {
    this._preamp.gain.value = value / 100;
  },

  // From -100 to 100
  setBalance: function(balance) {
    let changeVal = Math.abs(balance) / 100;

    // Hack for Firefox. Having either channel set to 0 seems to revert us
    // to equal balance.
    changeVal = changeVal - 0.00000001;

    if (balance > 0) {
      // Right
      this._leftGain.gain.value = 1 - changeVal;
      this._rightGain.gain.value = 1;
    } else if (balance < 0) {
      // Left
      this._leftGain.gain.value = 1;
      this._rightGain.gain.value = 1 - changeVal;
    } else {
      // Center
      this._leftGain.gain.value = 1;
      this._rightGain.gain.value = 1;
    }
    this._balance = balance;
  },

  setEqBand: function(band, value) {
    const db = value / 100 * 24 - 12;
    this.bands[band].gain.value = db;
  },

  toggleRepeat: function() {
    this._loop = !this._loop;
  },

  toggleShuffle: function() {
    // Implement this when we support playlists
  },

  /* Listeners */
  addEventListener: function(event, callback) {
    this._callbacks[event] = callback;
  },

  seekToTime: function(time) {
    // Make sure we are within range
    // TODO: Use clamp
    time = Math.min(time, this.duration());
    time = Math.max(time, 0);
    this.play(time);
  },

  loadFromFileReference: function(fileReference) {
    const file = new MyFile();
    file.setFileReference(fileReference);
    this.autoPlay = true;
    this.name = file.name;
    file.processBuffer(this._loadBuffer.bind(this));
  },

  // Used only for the initial load, since it must have a CORS header
  loadFromUrl: function(url, fileName) {
    const file = new MyFile();
    this.name = fileName;
    file.setUrl(url, fileName);
    file.processBuffer(this._loadBuffer.bind(this));
  },

  /* Listeners */
  _loadBuffer: function(buffer) {
    // Note, this will not happen right away
    this.loadBuffer(buffer, this._callbacks.fileLoaded);
  },

  // There is probably a more reasonable way to do this, rather than having
  // it always running.
  _draw: function() {
    if (this._playing) {
      this._updatePosition();
      this._callbacks.timeupdate();
    }
    window.requestAnimationFrame(this._draw.bind(this));
  },

  _updatePosition: function() {
    this._position = this._context.currentTime - this._startTime;
    if (this._position >= this._buffer.duration && this._playing) {
      // Idealy we could use _source.loop, but it makes updating the position tricky
      if (this._loop) {
        this.play(0);
      } else {
        this.stop();
        this._callbacks.ended();
      }
    }
  }
};
<|endoftext|>