You are here

public function ip_geoloc_plugin_style_leaflet::render in IP Geolocation Views & Maps 7

Transform the View result in a list of marker locations and render on map.

@todo refactor

Overrides views_plugin_style::render

File

views/ip_geoloc_plugin_style_leaflet.inc, line 1054

Class

ip_geoloc_plugin_style_leaflet

Code

public function render() {
  if (empty($this->options['map']) || !($map = ip_geoloc_plugin_style_leaflet_map_get_info($this->options['map']))) {
    return t('No Leaflet map was selected or map configuration was not found.');
  }
  if (!empty($this->view->live_preview)) {
    return t('The preview function is incompatible with Leaflet maps so cannot be used. Please visit the page path or the block to view your map.');
  }
  $render_start = microtime(TRUE);
  ip_geoloc_plugin_style_render_fields($this);
  $goto_content_on_click = !empty($this->options['on_click_options']['goto_content_on_click']);
  $open_balloons_on_click = !empty($this->options['on_click_options']['open_balloons_on_click']);
  $open_balloons_on_hover = !empty($this->options['on_hover_options']['open_balloons_on_hover']);
  $polygon_add_shadow_on_hover = $this->options['on_hover_options']['polygon_add_shadow_on_hover'];
  $shadow_on_hover_effect = $this->options['on_hover_options']['shadow_on_hover_effect'];
  $use_tweenmax_for_shadow_on_hover = trim($this->options['on_hover_options']['use_tweenmax_for_shadow_on_hover']);
  $polygon_fill_opacity_on_hover = trim($this->options['on_hover_options']['polygon_fill_opacity_on_hover']);
  $polygon_line_weight_on_hover = trim($this->options['on_hover_options']['polygon_line_weight_on_hover']);
  $enable_balloons = $open_balloons_on_click || $open_balloons_on_hover;
  $locations = ip_geoloc_plugin_style_extract_locations($this, $enable_balloons);
  $this
    ->fill_out_location_regions($locations);
  $marker_color = $this->options['default_marker']['default_marker_color'];
  $visitor_marker_color = $this->options['visitor_marker']['visitor_marker_color'];
  $center_option = !isset($this->options['center_option']) ? 0 : $this->options['center_option'];
  $sync_flags = 0;
  if (!empty($this->options['sync'][LEAFLET_SYNC_CONTENT_TO_MARKER])) {
    $sync_flags |= LEAFLET_SYNC_CONTENT_TO_MARKER;
  }
  if (!empty($this->options['sync'][LEAFLET_SYNC_MARKER_TO_CONTENT])) {
    $sync_flags |= LEAFLET_SYNC_MARKER_TO_CONTENT;
    if (!empty($this->options['sync'][LEAFLET_SYNC_MARKER_TO_CONTENT_WITH_POPUP])) {
      $sync_flags |= LEAFLET_SYNC_MARKER_TO_CONTENT_WITH_POPUP;
    }
    if (!empty($this->options['sync'][LEAFLET_SYNC_REVERT_LAST_MARKER_ON_MAP_OUT])) {
      $sync_flags |= LEAFLET_SYNC_REVERT_LAST_MARKER_ON_MAP_OUT;
    }
  }
  $has_full_screen = !empty($this->options['full_screen']);
  $has_mini_map = !empty($this->options['mini_map']['on']);
  $zoom_indicator = empty($this->options['zoom_indicator']) ? FALSE : TRUE;

  /*array('position' => 'topleft')*/
  $scale_control = FALSE;
  if (!empty($this->options['scale_metric']) || !empty($this->options['scale_imperial'])) {
    $scale_control = array(
      'metric' => !empty($this->options['scale_metric']),
      'imperial' => !empty($this->options['scale_imperial']),
    );
  }
  $reset_control = FALSE;
  if (!empty($this->options['map_reset'])) {
    $label = filter_xss_admin($this->options['map_reset_css_class']);
    $reset_control = array(
      'label' => empty($label) ? ' ' : $label,
    );
  }
  $cluster_control = FALSE;
  if (module_exists('leaflet_markercluster') && !empty($this->options['map_cluster_toggle'])) {
    $cluster_control = array(
      'label' => 'C',
    );
  }
  $cluster_radius = (int) _ip_geoloc_get_session_value('markercluster-radius');
  if ($cluster_radius < 2) {
    $cluster_radius = (int) $this->options['cluster_radius'];
  }
  $disable_clustering_at_zoom = $this->options['disable_clustering_at_zoom'];
  $hull_hug_factor = empty($this->options['cluster_differentiator']['cluster_outline']) ? -1 : 'auto';
  $cluster_tooltips = !empty($this->options['cluster_differentiator']['cluster_tooltips']);
  $cluster_touch_mode = empty($this->options['cluster_differentiator']['cluster_touch_mode']) ? 0 : 'auto';
  $cluster_aggregation_field = $this->options['cluster_aggregation']['aggregation_field'];
  $cluster_aggregation_function = $this->options['cluster_aggregation']['aggregation_function'];
  $cluster_aggregate_ranges = $this->options['cluster_aggregation']['ranges'];
  $cluster_aggregate_precision = $this->options['cluster_aggregation']['precision'];
  $allow_clusters_of_one = !empty($this->options['allow_clusters_of_one']);
  $tag_css_classes = $this->options['tags']['tag_css_class'];
  $marker_css_classes = $this->options['class_names']['marker_class_names'];
  $module_path = drupal_get_path('module', 'ip_geoloc');
  $marker_path = file_create_url(ip_geoloc_marker_directory());
  $max_zoom = (int) $this->options['map_options']['maxzoom'];
  $zoom = max(1, (int) $this->options['map_options']['zoom']);
  $zoom_on_click = (int) $this->options['map_options']['zoom_on_click'];
  $scroll_wheel_zoom = (bool) $this->options['map_options']['scrollwheelzoom'];
  $dragging = (bool) $this->options['map_options']['dragging'];
  $visitor_location = ip_geoloc_get_visitor_location();
  if (!isset($visitor_location['latitude'])) {
    $visitor_location = db_query('SELECT * FROM {ip_geoloc} WHERE ip_address = :ip_address', array(
      ':ip_address' => ip_address(),
    ))
      ->fetchAssoc();
  }
  if (empty($visitor_location['popup'])) {
    $visitor_location['popup'] = $this->options['visitor_marker']['visitor_marker_balloon_text'];
  }
  if (strpos($visitor_location['popup'], '[visitor-location:surrounding-polygon]')) {
    drupal_add_js(drupal_get_path('module', 'ip_geoloc') . '/js/ip_geoloc_pip.js');
  }
  $use_specified_center = !empty($this->options['map_options']['center_lat']) && !empty($this->options['map_options']['center_lon']) && empty($visitor_location['is_updated']);
  if ($use_specified_center) {
    $map['center'] = array(
      'lat' => $this->options['map_options']['center_lat'],
      'lon' => $this->options['map_options']['center_lon'],
    );
  }
  elseif (!empty($locations) && ($center_option == IP_GEOLOC_MAP_CENTER_ON_FIRST_LOCATION || $visitor_marker_color == 'none' && count($locations) == 1)) {
    $map['center'] = _ip_geoloc_get_center(reset($locations));
  }
  elseif (($center_option == IP_GEOLOC_MAP_CENTER_OF_LOCATIONS || $center_option == IP_GEOLOC_MAP_CENTER_OF_LOCATIONS_WEIGHTED) && !empty($locations)) {
    list($center_lat, $center_lon) = ip_geoloc_center_of_locations($locations, $center_option == IP_GEOLOC_MAP_CENTER_OF_LOCATIONS_WEIGHTED);
    $map['center'] = array(
      'lat' => $center_lat,
      'lon' => $center_lon,
    );
  }
  if (!$use_specified_center && (empty($locations) || $center_option == IP_GEOLOC_MAP_CENTER_ON_VISITOR) && isset($visitor_location['latitude'])) {
    $map['center'] = array(
      'lat' => $visitor_location['latitude'],
      'lon' => $visitor_location['longitude'],
    );
  }
  if (empty($locations)) {
    $ll = trim($this->options['empty_map_center']);
    if (empty($ll)) {

      // No map whatsoever.
      return;
    }
    if ($ll != t('visitor')) {

      // Empty map centered on coordinates provided.
      list($map['center']['lat'], $map['center']['lon']) = preg_split("/[\\s,]+/", $ll);
    }

    // else: empty map centered on visitor location, as set above.
  }
  else {
    uasort($locations, '_ip_geoloc_plugin_style_leaflet_compare');
  }
  $marker_dimensions = explode('x', ip_geoloc_marker_dimensions());
  $marker_width = (int) $marker_dimensions[0];
  $marker_height = (int) $marker_dimensions[1];
  switch (variable_get('ip_geoloc_marker_anchor_pos', 'bottom')) {
    case 'top':
      $marker_anchor = 0;
      break;
    case 'middle':
      $marker_anchor = (int) (($marker_height + 1) / 2);
      break;
    default:
      $marker_anchor = $marker_height;
  }
  $features = array();

  // $has_special_markers is used to flag we have to include our own special
  // version of the Drupal.leaflet.create_point() JavaScript code.
  $has_special_markers = $tag_css_classes || $marker_css_classes;
  foreach ($locations as $location) {
    $feature = array(
      'type' => empty($location->type) ? 'point' : $location->type,
    );
    if (isset($location->title)) {
      $feature['title'] = $location->title;
    }

    // Add Vector Display options for polygons, circles etc.
    // Tokens may be used to generate different colours etc.for individual
    // features.
    if ($feature['type'] != 'point' && !empty($this->options['vector_display']['stroke_override'])) {
      $feature_options = $this->options['vector_display'];
      if (module_exists('token')) {
        $entity_type = empty($location->entity_type) ? 'node' : $location->entity_type;
        $entity = isset($location->id) ? entity_load_single($entity_type, $location->id) : FALSE;
        if ($entity) {
          foreach ($feature_options as &$option) {
            $option = token_replace($option, array(
              $entity_type => $entity,
            ), array(
              'clear' => TRUE,
            ));
          }
        }
      }

      // To avoid overwriting options with empty values, removes all NULL
      // FALSE and empty strings, but leave zero values.
      $feature_options = array_filter($feature_options, 'strlen');
      unset($feature_options['stroke_override']);
      $feature['options'] = $feature_options;
    }
    if (isset($location->latitude) || isset($location->lat)) {

      // GeoJSON does not support circles, but Leaflet does
      $feature['lat'] = isset($location->latitude) ? $location->latitude : $location->lat;
      $feature['lon'] = isset($location->longitude) ? $location->longitude : $location->lon;
      if (!empty($location->random_displacement)) {
        ip_geoloc_add_random_displacement($feature, $location->random_displacement);
        $circle = array(
          'type' => 'circle',
          'lat' => $feature['lat'],
          'lon' => $feature['lon'],
          'radius' => $location->random_displacement,
        );
        $features[] = $circle;
      }
    }
    elseif (isset($location->component)) {

      // Possibly parsed by leaflet_process_geofield()
      // see _ip_geoloc_plugin_style_extract_lat_lng().
      $feature['component'] = $location->component;
    }
    elseif (isset($location->points)) {
      $feature['points'] = $location->points;
    }

    // At this point $feature['type'] should be set.
    if ($feature['type'] != 'point') {

      // Linestring, polygon ...
      $feature['flags'] = LEAFLET_MARKERCLUSTER_EXCLUDE_FROM_CLUSTER;
    }
    elseif (!isset($feature['lat'])) {

      // Points must have coords.
      continue;
    }
    if (isset($location->id)) {

      // Allow marker events to identify the corresponding node.
      $feature['feature_id'] = $location->id;
    }
    if (!empty($sync_flags)) {
      $feature['flags'] = isset($feature['flags']) ? $feature['flags'] | $sync_flags : $sync_flags;
    }
    if ($enable_balloons && isset($location->balloon_text)) {
      $feature['popup'] = $location->balloon_text;
    }
    if (!empty($location->marker_special_char) || !empty($location->marker_special_char_class)) {
      $has_special_markers = TRUE;
      if (!empty($location->marker_special_char)) {
        $feature['specialChar'] = filter_xss_admin($location->marker_special_char);
      }
      if (!empty($location->marker_special_char_class)) {
        $feature['specialCharClass'] = filter_xss_admin($location->marker_special_char_class);
      }
    }
    elseif (!empty($this->options['default_marker']['default_marker_special_char']) || !empty($this->options['default_marker']['default_marker_special_char_class'])) {
      $has_special_markers = TRUE;
      $feature['specialChar'] = $this->options['default_marker']['default_marker_special_char'];
      $feature['specialCharClass'] = $this->options['default_marker']['default_marker_special_char_class'];
    }
    if (!empty($location->marker_tooltip)) {
      if (module_exists('leaflet_label')) {
        $feature['label'] = $location->marker_tooltip;
      }
      else {
        $has_special_markers = TRUE;
        $feature['tooltip'] = $location->marker_tooltip;
      }
    }
    if (!empty($location->regions)) {
      $has_special_markers = TRUE;

      // Make sure we start with 0 or regions will come across as Object
      // rather than array.
      $feature['regions'] = array(
        0 => '',
      ) + $location->regions;
      if (isset($location->aggregation_value)) {
        $feature['aggregationValue'] = (double) $location->aggregation_value;
      }

      // Note: cannot use <br/>  or HTML in tooltip as separator. Use \n.
      $feature['tooltip'] = empty($feature['tooltip']) ? '' : $feature['tooltip'] . "\n";
      $second_last = count($feature['regions']) - 2;
      if ($second_last > 0) {
        $feature['tooltip'] .= $feature['regions'][$second_last] . ' - ';
      }
      $feature['tooltip'] .= end($feature['regions']);
    }
    if (!empty($location->marker_tag)) {
      $feature['tag'] = $location->marker_tag;
    }
    if ($tag_css_classes || !empty($location->marker_classes)) {
      if (empty($location->marker_classes)) {
        $feature['cssClass'] = $tag_css_classes;
      }
      else {
        $feature['cssClass'] = implode(' ', array_merge(array(
          $tag_css_classes,
        ), $location->marker_classes));
      }
    }
    if (isset($location->marker_color) && _ip_geoloc_is_no_marker($location->marker_color) || !isset($location->marker_color) && _ip_geoloc_is_no_marker($marker_color)) {

      // "No marker" as opposed to "default" marker.
      $has_special_markers = TRUE;
      $feature['icon'] = FALSE;
    }
    elseif (!empty($location->marker_color) || !empty($marker_color)) {

      // Switch from default icon to specified color.
      $color = empty($location->marker_color) ? $marker_color : $location->marker_color;
      $feature['icon'] = array(
        'iconUrl' => $marker_path . "/{$color}.png",
        'iconSize' => array(
          'x' => $marker_width,
          'y' => $marker_height,
        ),
        'iconAnchor' => array(
          'x' => (int) (($marker_width + 1) / 2),
          'y' => $marker_anchor,
        ),
        // Just above topline, center.
        'popupAnchor' => array(
          'x' => 0,
          'y' => -$marker_height - 1,
        ),
      );
    }
    $features[] = $feature;
  }
  if (isset($visitor_location['latitude'])) {
    if ($visitor_marker_color != 'none') {

      // See leaflet/README.txt for examples of Leaflet "features"
      $visitor_feature = array(
        'type' => 'point',
        'isVisitor' => true,
        'lat' => $visitor_location['latitude'],
        'lon' => $visitor_location['longitude'],
        'specialChar' => filter_xss_admin($this->options['visitor_marker']['visitor_marker_special_char']),
        'specialCharClass' => filter_xss_admin($this->options['visitor_marker']['visitor_marker_special_char_class']),
        'popup' => t('Your approximate location'),
        'tooltip' => !empty($visitor_location['tooltip']) ? $visitor_location['tooltip'] : t('Your approximate location'),
        'zIndex' => 9999,
        // See leaflet_markercluster.drupal.js.
        'flags' => LEAFLET_MARKERCLUSTER_EXCLUDE_FROM_CLUSTER,
      );
      if (!empty($visitor_location['popup']) && module_exists('token')) {
        $visitor_feature['popup'] = token_replace($visitor_location['popup'], $visitor_location, array());
      }
      if ($visitor_marker_color != '') {
        if (!empty($visitor_feature['specialChar']) || !empty($visitor_feature['specialCharClass'])) {
          $has_special_markers = TRUE;
        }
        $visitor_feature['icon'] = array(
          'iconUrl' => $marker_path . "/{$visitor_marker_color}.png",
          'iconSize' => array(
            'x' => $marker_width,
            'y' => $marker_height,
          ),
          'iconAnchor' => array(
            'x' => (int) (($marker_width + 1) / 2),
            'y' => $marker_anchor,
          ),
          // Just above topline, center.
          'popupAnchor' => array(
            'x' => 0,
            'y' => -$marker_height - 1,
          ),
        );
      }
      $features[] = $visitor_feature;
    }
    if (!empty($this->options['visitor_marker']['visitor_marker_accuracy_circle']) && !empty($visitor_location['accuracy'])) {
      $visitor_accuracy_circle = array(
        'type' => 'circle',
        'lat' => $visitor_location['latitude'],
        'lon' => $visitor_location['longitude'],
        'radius' => (double) $visitor_location['accuracy'],
        'popup' => !empty($visitor_location['popup']) ? $visitor_location['popup'] : t("You are within @m meters of the centre of this circle.", array(
          '@m' => $visitor_location['accuracy'],
        )),
        'label' => !empty($visitor_location['tooltip']) ? $visitor_location['tooltip'] : t('You are within this circle'),
        // requires Leaflet Label
        'zIndex' => 9998,
        'flags' => LEAFLET_MARKERCLUSTER_EXCLUDE_FROM_CLUSTER,
      );
      $features[] = $visitor_accuracy_circle;
    }
  }

  // If auto-box is chosen ($center_option==0), zoom only when there are
  // 0 or 1 markers [#1863374]
  if (!$use_specified_center && empty($center_option) && count($features) > 1) {
    unset($map['center']);
  }
  else {
    $map['settings']['zoom'] = $zoom;
    if (!empty($map['center'])) {

      // A leaflet.drupal.js quirk? Have to specify AND force a center...
      $map['center']['force'] = TRUE;
    }
  }
  $map['settings']['maxZoom'] = $max_zoom;
  $map['settings']['scrollWheelZoom'] = $scroll_wheel_zoom;
  $map['settings']['dragging'] = $dragging;
  $map['settings']['revertLastMarkerOnMapOut'] = (bool) ($sync_flags & LEAFLET_SYNC_REVERT_LAST_MARKER_ON_MAP_OUT);
  $map['settings']['maxClusterRadius'] = 0;
  if ($cluster_radius > 0) {
    if (module_exists('leaflet_markercluster')) {
      $map['settings']['maxClusterRadius'] = $cluster_radius;
      $map['settings']['disableClusteringAtZoom'] = $disable_clustering_at_zoom;
      $map['settings']['addRegionToolTips'] = $cluster_tooltips;
      $map['settings']['hullHugFactor'] = $hull_hug_factor;
      $map['settings']['touchMode'] = $cluster_touch_mode;
      $map['settings']['animateAddingMarkers'] = TRUE;
      if (!empty($cluster_aggregation_field)) {
        $map['settings']['clusterAggregationFunction'] = $cluster_aggregation_function;
        $map['settings']['clusterAggregateRanges'] = $cluster_aggregate_ranges;
        $map['settings']['clusterAggregatePrecision'] = $cluster_aggregate_precision;
        drupal_add_css(leaflet_markercluster_get_library_path() . '/MarkerCluster.Aggregations.css');
      }
      if ($allow_clusters_of_one) {
        $map['settings']['allowClustersOfOne'] = TRUE;
        $map['settings']['spiderfyDistanceMultiplier'] = 4.0;
      }
    }
    else {
      $display_name = $this->view
        ->get_human_name() . ' (' . $this->display->display_title . ')';
      drupal_set_message(t('Cannot cluster markers in View %display_name, as the module Leaflet MarkerCluster is not enabled.', array(
        '%display_name' => $display_name,
      )), 'warning');
    }
  }
  $zoom_ranges = array_filter($this->options['cluster_differentiator']['zoom_ranges']);
  if (!empty($zoom_ranges)) {

    // Make sure we start array with 0 and no missing elements. Otherwise this
    // array will arrive as an Object on the JS side.
    $region_levels = array_fill(0, $max_zoom + 1, 0);
    foreach ($zoom_ranges as $level => $zoom_range) {
      for ($zoom = 1; $zoom <= $max_zoom; $zoom++) {
        if (ip_geoloc_is_in_range($zoom, $zoom_range)) {
          $region_levels[$zoom] = $level;
        }
      }
    }

    // Remove any gaps and zeroes.
    for ($z = 1; $z <= $max_zoom; $z++) {
      if (empty($region_levels[$z])) {
        $region_levels[$z] = $region_levels[$z - 1];
      }
    }
    $map['settings']['regionLevels'] = $region_levels;
  }

  // See [#1802732].
  $map_id = 'ip-geoloc-map-of-view-' . $this->view->name . '-' . $this->display->id . '-' . md5(serialize($features));
  drupal_add_js(drupal_get_path('module', 'leaflet') . '/leaflet.drupal.js');

  // Don't load sync JS and CSS when option is not requested.
  if ($sync_flags !== 0) {
    drupal_add_js($module_path . '/js/ip_geoloc_leaflet_sync_content.js', array(
      'weight' => 2,
    ));
    drupal_add_css($module_path . '/css/ip_geoloc_leaflet_sync_content.css');
  }
  if ($has_full_screen) {

    // Load the 'leaflet-fullscreen' library, containing JS and CSS.
    if (drupal_add_library('ip_geoloc', 'leaflet-fullscreen')) {
      $map['settings']['fullscreenControl'] = array(
        'position' => 'topright',
      );
    }
  }
  if ($has_mini_map) {

    // Load the 'leaflet-minimap' library, containing JS and CSS.
    // See https://github.com/Norkart/Leaflet-MiniMap for more settings.
    if (drupal_add_library('ip_geoloc', 'leaflet-minimap')) {
      $map['settings']['miniMap'] = array(
        'autoToggleDisplay' => TRUE,
        'height' => $this->options['mini_map']['height'],
        'width' => $this->options['mini_map']['width'],
        'position' => 'bottomright',
        // 'bottomright'
        'toggleDisplay' => !empty($this->options['mini_map']['toggle']),
        'zoomAnimation' => FALSE,
        'zoomLevelOffset' => (int) $this->options['mini_map']['zoom_delta'],
        // Superimposed rectangle showing extent of main map on the inset.
        'aimingRectOptions' => array(
          'color' => $this->options['mini_map']['scope_color'],
          'weight' => 3,
          'fillOpacity' => 0.1,
        ),
        // The "shadow" rectangle that shows the new map outline.
        'shadowRectOptions' => array(
          'color' => '#888',
          'weight' => 1,
        ),
      );
    }
  }
  $map['settings']['zoomIndicator'] = $zoom_indicator;
  $map['settings']['zoomOnClick'] = $zoom_on_click;
  $map['settings']['resetControl'] = $reset_control;
  $map['settings']['clusterControl'] = $cluster_control;
  $map['settings']['scaleControl'] = $scale_control;
  if ($has_mini_map || $zoom_indicator || $reset_control || $cluster_control || $scale_control) {
    drupal_add_js($module_path . '/js/ip_geoloc_leaflet_controls.js', array(
      'weight' => 1,
    ));
    drupal_add_css($module_path . '/css/ip_geoloc_leaflet_controls.css');
  }
  $map['settings']['gotoContentOnClick'] = $goto_content_on_click;
  $map['settings']['openBalloonsOnHover'] = $open_balloons_on_hover;
  $map['settings']['polygonAddShadowOnHover'] = $polygon_add_shadow_on_hover;
  $map['settings']['shadowOnHoverEffect'] = $shadow_on_hover_effect;
  $map['settings']['useTweenMaxForShadowOnHover'] = $use_tweenmax_for_shadow_on_hover;
  $map['settings']['polygonFillOpacityOnHover'] = $polygon_fill_opacity_on_hover;
  $map['settings']['polygonLineWeightOnHover'] = $polygon_line_weight_on_hover;
  if ($goto_content_on_click) {
    drupal_add_js($module_path . '/js/ip_geoloc_leaflet_goto_content_on_click.js', array(
      'scope' => 'footer',
    ));
  }
  if ($open_balloons_on_hover || $polygon_add_shadow_on_hover || is_numeric($polygon_fill_opacity_on_hover) || is_numeric($polygon_line_weight_on_hover)) {
    if ($polygon_add_shadow_on_hover && $use_tweenmax_for_shadow_on_hover) {
      $version = $use_tweenmax_for_shadow_on_hover;
      drupal_add_js("https://cdnjs.cloudflare.com/ajax/libs/gsap/{$version}/TweenMax.min.js", array(
        'scope' => 'footer',
      ));
    }
    drupal_add_js($module_path . '/js/ip_geoloc_leaflet_hover.js', array(
      'scope' => 'footer',
    ));
  }
  $settings = array(
    'mapId' => $map_id,
    'map' => $map,
    'features' => $features,
  );
  $options = array(
    'type' => 'setting',
    // 'footer' only works for type 'inline'.
    'scope' => 'footer',
  );
  drupal_add_js(array(
    'leaflet' => array(
      $settings,
    ),
  ), $options);
  libraries_load('leaflet');

  // Little hacky this, but can't see another way to load libraries for
  // Leaflet More Maps, Leaflet MarkerCluster, Leaflet Hash...
  drupal_alter('leaflet_map_prebuild', $settings);
  if ($reset_control || $cluster_control || !empty($has_special_markers)) {

    // Load the CSS that comes with the font icon library which in return
    // tells the browser to fetch either the WOFF, TTF or SVG files that
    // define the font faces.
    drupal_add_library('ip_geoloc', 'ip_geoloc_font_icon_libs');
    drupal_add_css($module_path . '/css/ip_geoloc_leaflet_markers.css');
    drupal_add_js($module_path . '/js/ip_geoloc_leaflet_tagged_marker.js', array(
      'weight' => 1,
    ));
  }
  if ($zoom_on_click) {
    drupal_add_js($module_path . '/js/ip_geoloc_leaflet_zoom_on_click.js', array(
      'scope' => 'footer',
    ));
  }

  // drupal_alter('leaflet_build_map', $build); // @todo [#2567391]
  $output = theme('ip_geoloc_leaflet', array(
    'map_id' => $map_id,
    'height' => trim($this->options['map_height']),
    'view' => $this->view,
  ));
  ip_geoloc_debug(t('-- Leaflet map preparation time: %sec s', array(
    '%sec' => number_format(microtime(TRUE) - $render_start, 2),
  )));
  return $output;
}