davestacey
3/13/2015 - 6:25 PM

Entire map implementation js file

Entire map implementation js file

(function($){
  /*******************************************
  Set your namespaced functions as non global variables, 
  keep the global scope clear to reduce naming clashes and keep memory usage down
  jQuery 1.5 or higher.
  *******************************************/
  var nsmap = nsmap || {};

  ///////////////////////////////////
  /* Drupal.behaviors will get called when the DOM has loaded */
  Drupal.behaviors.maps = {
    attach:function (context, settings) {
      // Set name spaced variables
      nsmap.mapSettings = settings.mapSettings;
      nsmap.basePath = settings.mapSettings.fullModulePath; // path to geodata file
      nsmap.serviceRegions = settings.mapSettings.serviceRegions; // regions from form
      nsmap.geoLocations = settings.mapSettings.geoLocations; // All taxonomy locations with parents
      nsmap.officeLocation = settings.mapSettings.officeLoc; // Office Location
      nsmap.bounds = '';
      nsmap.initialPosition = {};
      nsmap.zoomed = false;
      // Collection object
      nsmap.allFeaturesToSearch = {
        type: 'FeatureCollection',
        features: []
      };
      //console.log(JSON.stringify(nsmap.geoLocations))

      // Init Function
      nsmap.mapInit = function() {
        var L = window.L;
        // check that the Leaflet library is available
        if (!L) {
          console.error('Missing the Leaflet library')
          return false;
        } else {
          //check that the dom element exists before attaching to it
          if ( $('#lmapDetail', context) ){
            //console.log('yes----', $('#lmapDetail', context));
            var map = new L.map('lmapDetail', { minZoom: 2 });

            // Initial Position
            map.setView(new L.LatLng(37.500, -100.000), 4);

            // Add Footer
            L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
              attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
              //attribution: 'Test Overlay'
            }).addTo(map);  

            //turn off features
            map.scrollWheelZoom.disable();
            //map.touchZoom.disable();
            //map.doubleClickZoom.disable();
            //map.boxZoom.disable();
            //map.keyboard.disable();
            //$(".leaflet-control-zoom").css("visibility", "hidden");

            // serviceRegions passed via drupal settings
            if(nsmap.serviceRegions) {
              nsmap.getFeatures( map, nsmap.serviceRegions, function(result){
                var featuresForSelectedStatesObj = result;
                nsmap.buildStateLayer(map, featuresForSelectedStatesObj);
                // add office marker
                if(nsmap.officeLocation) {
                  //console.log('add office, officeLocation= ', nsmap.officeLocation);
                  nsmap.addOfficeMarker(map, nsmap.officeLocation);
                }
              });
            } else {
              console.error('serviceRegions not found');
            }; // if nsmap.serviceRegions
          } else {
            console.error('dom element lmapDetail does not exist');
          } // if $('#lmapDetail
        }
      }// end mapInit

      // nsmap.dynamicBasePath = 'http://' + window.location.hostname + '/geoJSON';

      // Get the features to add to the map
      nsmap.getFeatures = function (thisMap, statesSelected, callback){
        var map = thisMap;
        var theStates = statesSelected;
        var featureFilePath = this.basePath + '/data/us-states.js';
        var provinceFilePath = this.basePath + '/data/canada.json';

        // empty feature collection to add geojson
        var colObj = {
          type: 'FeatureCollection',
          features: []
        };

        // Step 1 get the us-state features
        getUSfCollection(featureFilePath, function(errorMessage, usresults) {
          if (errorMessage){
            console.error('getUSfCollection failed: US state file is a dependency for mapping.');
            callback('getUSfCollection failed');
          };          
          nsmap.allFeaturesToSearch.features = nsmap.allFeaturesToSearch.features.concat(usresults.features); // all the state shapes
          // Step 2 get the Canada features
          getCanadafCollection(provinceFilePath, function(canresults) {
            nsmap.allFeaturesToSearch.features = nsmap.allFeaturesToSearch.features.concat(canresults.features);
            // We have all the features, now apply to the selected states
            for (var i = theStates.length - 1; i >= 0; i--) {
              //console.log('getFeatures - theStates[i]', theStates[i]);
              var aStateNameToFind = theStates[i].name.toUpperCase() ;
              var featureArray = nsmap.allFeaturesToSearch.features;
              if ($.type(featureArray) === "array") {
                // Loop Features and find either a canadian province or a US state
                for (var j = featureArray.length - 1; j >= 0; j--) {
                  var featureNameUS = featureArray[j].properties.name ;
                  var featureNameCanada = featureArray[j].properties.NAME ;
                  var featureNameFound = '';
                  if(featureNameUS ){
                    featureNameFound = featureNameUS.toUpperCase();
                  } else if (featureNameCanada) {
                    featureNameFound = featureNameCanada.toUpperCase();
                  };
                  if (featureNameFound ){
                    if (aStateNameToFind == featureNameFound){
                      //console.log('-getFeatures - matched a location, now get the details');

                      // Collect the parent info (for coloring etc)
                      // Note: now we only get one parent per item, no need to loop.
                      findByNameGetParents(featureNameFound, function(parent){
                        var parentArray = parent; // Assuming just one parent
                        //console.log('returned parent TID: ', parentArray);
                        findParentByTID(parentArray, function(parentObject){
                          if (parentObject) {
                            //console.log('Returned Parent Object: ', parentObject);
                            featureArray[j].properties.parent = parentObject.name;
                            //console.log('Added Parent to featureArray[j]', featureArray[j]);
                          }
                        }); //findParentByTIDFromID
                      }); //findByNameGetParents

                      // push it to the collection
                      colObj.features.push(featureArray[j]);
                    };
                  };
                }; // for feature
              } else {
                console.error('featureArray is not available');
              }
            }// for state
            callback(colObj);
          })//getCanadafCollection
        })//getUSfCollection
      }//getFeatures

      // Loop the location taxonomy terms and get the parent
      function findByNameGetParents(featureNameFound, callback){
        // get the locations to look for parents in.
        var locations =  nsmap.geoLocations;
         //console.log('findByNameGetParents', featureNameFound);
         for (var i = locations.length - 1; i >= 0; i--) {
          if (locations[i].name.toUpperCase() == featureNameFound) {
            //console.log(locations[i].parents);
            callback(locations[i].parents);
          }
         };
      } //findByNameGetParents
      
      function findParentByTID(parents, callback){
        var locations =  nsmap.geoLocations;
        var parentsArray = parents;
          // Usually just one parent
          if (!parentsArray.length === 1) {
            // So far there is only one parent object, this is here as a test.
            console.warn('parentsArray.length != 1, unusual, test: get all parents?');
          }
          // Return just the first parent, always just one so far.
          //console.log('findParent-parentsArray', parentsArray[0]);
          var parentTID = parentsArray[0]
          // loop the object and match the TID
          for (var i = locations.length - 1; i >= 0; i--) {
            if (locations[i].tid == parentTID) {
              //console.log('-findParentByTID parentInfo:', locations[i]);
              //console.log(locations[i].name);
              callback(locations[i]);
            }
          };
      } //findParentByTID


      // Get the us-state features array
      function getUSfCollection(featureFilePath, callback){
        var stateFile = featureFilePath;
        // state file is .js so...
        $.getScript( stateFile )
          .done(function( script, textStatus ) {
            callback(null, statesData);
          })
          .fail(function( jqxhr, settings, exception ) {
            console.error(" Error getting stateFile.", exception)
            callback("Cannot reach stateFile " + exception);
            return false;
        });
      } //getUSfCollection

      // Get the us-state features array
      function getCanadafCollection(provinceFilePath, callback){
        var provinceFile = provinceFilePath;
        // state file is json so...
        $.getJSON(provinceFile, function(data) {
          callback(data);
        })//function(data) 
        .fail(function() {
          console.error( "getCanadafCollection getJSON error!" );
        });
      } //getCanadafCollection


      /////////////////////////////
      // Process the state layer
      nsmap.buildStateLayer = function (map, stateData) {
        //console.log('buildStateLayer stateData', stateData);
        var geojsonStates = L.geoJson(stateData, {
          style: function (feature) {
           return nsmap.styleMap(feature);
          },
          onEachFeature: function (feature, layer) {
            //layer.on({
              //mouseover: highlightFeature,
              //mouseout: resetHighlight,
              //click: zoomToFeature,
              //pointToLayer: pointToLayer
            //});
          },
        });//end geojsonStates

        // put all state layers into a group
        var stateOverlay = L.featureGroup([geojsonStates])
          //.bindPopup('Hello world!')
          .on('click', onOverlayClick);
        stateOverlay.addTo(map);

        function onOverlayClick(){
          //console.log('onOverlayClick', this);
          if (nsmap.zoomed === true){
            //console.log('Zooming out');
            map.setView(new L.LatLng(nsmap.initialPosition.groupCenter.lat, nsmap.initialPosition.groupCenter.lng), nsmap.initialPosition.groupZoom);
            nsmap.zoomed = false;
          }
        };
        //var id_stateOverlay = map.getLayerId(stateOverlay);
        //geojsonStates.addTo(map);

        // Option to set maxZoom with
        var zoomOverride = map.getZoom();

        nsmap.bounds = geojsonStates.getBounds()
        map.fitBounds(nsmap.bounds, { maxZoom: 4 });

        nsmap.addLegend(map);
        //addRolloverControl();
      }//END buildStateLayer()
        
      // Color the states
      nsmap.styleMap = function(feature) {
        // Map Colors
        this.colors = {
          grey : "rgba(84,96,101,0.3)", //#546065",

          // colorblind colors
          blue:         "rgba(21, 21, 119, 0.3)", //#151577
          orange:       "rgba(255, 109, 2, 0.3)", //#ff6d02
          green:        "rgba(50, 82, 16, 0.3)", //#325210
          yellowgreen:  "rgba(216, 205, 24, 0.3)", //#d8cd18
          darkorange:   "rgba(144, 16, 243, 0.3)", //#9010f3
          
        };
        var colorVar = '#7AAD42';

          // Old non-colorblind colors - for reference
          // blue : "rgba(108,157,179,0.3)", //"#6c9db3",
          // orange : "rgba(247,148,30,0.3)", //"#f7941e",
          // green : "rgba(122,173,66,0.3)", //#7aad42",
          // yellowgreen : "rgba(234,234,100,0.3)",//"#d1d179",
          // darkorange : "rgba(188,47,80,0.3)", //#bc2f50", // too close to other orange, added red
          // //darkorange : "rgba(182, 109, 16, 0.3)", //#bc2f50",

        if (feature.properties.parent){
          //console.log('feature has a parent= ', feature.properties.parent);
          switch (feature.properties.parent) {
            // Midwest
            case "East North Central":
                var colorVar =  this.colors.orange;
                break; 
            case 'West North Central':
                var colorVar =  this.colors.orange;
                break; 
            // Northeast
            case "New England":
                var colorVar =  this.colors.darkorange;
                break; 
            case 'Mid-Atlantic':
                var colorVar =  this.colors.darkorange;
              break; 
            // South
            case "East South Central":
                var colorVar =  this.colors.green;
                break; 
            case 'South Atlantic':
                var colorVar =  this.colors.green;
              break; 
            case 'West South Central':
                var colorVar =  this.colors.green;
              break; 
            // West
            case "Mountain":
                var colorVar =  this.colors.blue;
                break; 
            case 'Pacific':
                var colorVar =  this.colors.blue;
              break; 
            // Canada
            case "Canada":
                var colorVar =  this.colors.yellowgreen;
                break; 
            // 
              default: 
                  var colorVar =  this.colors.grey;
          }
        }//if (feature.properties.parent

        return {
            fillColor: colorVar,
            weight: 1,
            opacity: 1.0,
            color: "#a0a0a0",
            dashArray: '3',
            fillOpacity: 0.6,
            className: "statePolygon",
        };
      } //end styleMap


      /////////////////////////////
      /// LEGEND
      nsmap.addLegend = function (map) {
        var colors = this.colors;
        var mapLegend = L.control({position:'bottomleft'});
        mapLegend.onAdd = function (map) {
          // create the control container div with classes
          var container = L.DomUtil.create('div', 'info legend');

          var html = '<h5 class="legend" style="margin-bottom: 0.1rem; padding:0px 10px; ">Regions</h5>';
          html += ' <p class="midwest" style="color:#444444; background-color:' + colors.orange + '; padding:0px 10px; margin-bottom: 0px;">Midwest</p> ';
          html += ' <p class="northeast" style="color:#444444; background-color:' + colors.darkorange + '; padding:0px 10px; margin-bottom: 0px;">Northeast</p> ';
          html += ' <p class="south" style="color:#444444; background-color:' + colors.green + '; padding:0px 10px; margin-bottom: 0px;">South</p> ';
          html += ' <p class="west" style="color:#444444; background-color:'+ colors.blue + '; padding:0px 10px; margin-bottom: 0px;">West</p> ';
          html += ' <p class="canada" style="color:#444444; background-color:' + colors.yellowgreen + '; padding:0px 10px; margin-bottom: 0px;">Canada</p> ';
          container.innerHTML = html;
          return container;
        };
        mapLegend.addTo(map);
      }

      /////////////////////////////
      // Add the Office marker
      nsmap.addOfficeMarker = function (map, coordinates) {
        var longitude = coordinates.lon;
        var latitude = coordinates.lat;

         //This uses Leaflet.js's markers:
         var officeMarker = L.divIcon({
          iconSize:     [2, 20],
          iconAnchor:   [20, 30],
          className: 'comment',
          html: '<i class="fi-marker medium"></i>'
         });
         
        var marker = L.marker([latitude, longitude], {icon: officeMarker}).addTo(map);

        // Popup
        //marker.bindPopup("<b>Hello world!</b><br>I am a popup.").openPopup();
        // map.on('click', function(e) {
        //   console.log(this);
        //   //console.log(nsmap.bounds);
        //   //map.fitBounds(nsmap.bounds);
        // }

        marker.on('click', function(e) {
            // TODO - toggle click function for zoom and reset
            //console.log('nsmap.initialPosition', nsmap.initialPosition);
            if (nsmap.zoomed === false){
              //console.log('Zooming in');
              nsmap.initialPosition.groupCenter = map.getCenter();
              nsmap.initialPosition.groupZoom = map.getZoom();
              map.setView(new L.LatLng(e.latlng.lat, e.latlng.lng), 9);
              nsmap.zoomed = true;
            } else {
              //console.log('Zooming out');
              map.setView(new L.LatLng(nsmap.initialPosition.groupCenter.lat, nsmap.initialPosition.groupCenter.lng), nsmap.initialPosition.groupZoom);
              nsmap.zoomed = false;
            }
            //map.panTo(new L.LatLng(40.737, -73.923));
        });

        // capture map click
        map.on('click', onMapClick);
        function onMapClick(){
          //console.log('initialPosition', nsmap.initialPosition);
          if (nsmap.zoomed === true){
            //console.log('Zooming out');
            map.setView(new L.LatLng(nsmap.initialPosition.groupCenter.lat, nsmap.initialPosition.groupCenter.lng), nsmap.initialPosition.groupZoom);
            nsmap.zoomed = false;
          }
        };
        // click action
        // var popup = L.popup();
        // function onMapClick(e) {
        //     popup
        //         .setLatLng(e.latlng)
        //         .setContent("You clicked the map at " + e.latlng.toString())
        //         .openOn(map);
        // }


      }//END addOfficeMarker()

      //call init function
      nsmap.mapInit();

    }//attach:function (context, settings)
  };//Drupal.behaviors.maps
})(jQuery);