class CckForms::ParameterTypeClass::Map

Represents a map point in Google Maps or Yandex.Maps.

Constants

DEFAULT_MAP_TYPE
MAP_TYPE_GOOGLE
MAP_TYPE_YANDEX

Public Class Methods

demongoize_value(value, _parameter_type_class=nil) click to toggle source

In MongoDB: {latlon: [x, y], zoom: z}

In application: {

latitude: x,
longitude: y,
zoom: z

}

# File lib/cck_forms/parameter_type_class/map.rb, line 23
def self.demongoize_value(value, _parameter_type_class=nil)
  value = value.to_h
  value.stringify_keys!
  latlon = value['latlon'] || []

  latitude = value['latitude'] || latlon[0]
  longitude = value['longitude'] || latlon[1]
  type_of_map = value['type'] || DEFAULT_MAP_TYPE

  {
      'latitude' => latitude,
      'longitude' => longitude,
      'zoom' => value['zoom'].presence,
      'type' => type_of_map
  }
end

Public Instance Methods

a_tag(content, attrs) click to toggle source

<A> tag with a link to the Google/Yandex Maps with marker placed on the current value position

# File lib/cck_forms/parameter_type_class/map.rb, line 110
def a_tag(content, attrs)
  if attrs[:href] = url
    attrs_strings = []
    attrs.each_pair { |name, value| attrs_strings << sprintf('%s="%s"', name, value) }
    sprintf '<a %s>%s</a>', attrs_strings.join, content
  else
    ''
  end
end
build_form(form_builder, options) click to toggle source

3 hidden field: latitude, longitude, zoom. Next we place a DIV nearby on which Google/Yandex Map is hooked.

1 click on a map places a point (writing to hidden fields). 1 click on a point removes it (emptying fields).

options:

value     - current point
width     - map width
height    - map height
latitude  - default map center lat
longitude - default map center lon
zoom      - default map center zoom
# File lib/cck_forms/parameter_type_class/map.rb, line 153
def build_form(form_builder, options)
  set_value_in_hash options

  options = {
      width: 550,
      height: 400,
      latitude: 47.757581,
      longitude: 67.298256,
      zoom: 5,
      value: {},
  }.merge options

  value = (options[:value].is_a? Hash) ? options[:value].stringify_keys : {}

  inputs = []
  id = ''

  form_builder.tap do |value_builder|
    id = form_builder_name_to_id value_builder
    inputs << value_builder.hidden_field(:latitude,  value: value['latitude'])
    inputs << value_builder.hidden_field(:longitude, value: value['longitude'])
    inputs << value_builder.hidden_field(:zoom,      value: value['zoom'])
    inputs << value_builder.hidden_field(:type,      value: value['type'])
  end

  allowed_maps      = @@map_providers
  map_names         = {'google' => 'Google', 'yandex' => 'Yandex'}
  selected_map_type = value['type'].in?(allowed_maps) ? value['type'] : allowed_maps.first
  group_class       = options[:group_class].presence  || 'btn-group'
  switcher_classes  = {
      'yandex' => options[:yandex_button_class],
      'google' => options[:google_button_class]
  }

  switchers = []
  switchers << %Q|<div class="#{group_class} cck-map-switchers #{'hide' if allowed_maps.count < 2}" style="margin-top: 5px;">|
  allowed_maps.map do |map|
    button_class = switcher_classes[map].presence || 'btn btn-default'
    button_class << ' active' if selected_map_type == map
    switchers << %Q|<a class="#{button_class}" href="#" data-map-type="#{map}">#{map_names[map]}</a>|
  end
  switchers << '</div>'

  map_html_containers = []
  allowed_maps.each do |map|
    map_html_containers.push %Q|<div id="#{id}_#{map}" data-id=#{id} class="map_widget" style="display: none; width: #{options[:width]}px; height: #{options[:height]}px"></div>|
  end

  google_api_key = @@google_maps_api_key.present? ? "&key=#{@@google_maps_api_key}" : nil
  yandex_api_key = @@yandex_maps_api_key.present? ? "&apikey=#{@@yandex_maps_api_key}" : nil

  %Q|
  <div class="map-canvas">
    #{inputs.join}

    <script>
    var mapsReady = {google: false, yandex: false, callback: null, on: function(callback) {
      this.callback = callback;
      this.fireIfReady();
    }, fireIfReady: function() {
      if(this.google && this.yandex && this.callback) { this.callback() }
    }}

    function googleMapReady() { mapsReady.google = true; mapsReady.fireIfReady() }
    function yandexMapReady() { mapsReady.yandex = true; mapsReady.fireIfReady() }

    function loadMapScripts() {
      var script;
      script = document.createElement('script');
      script.type = 'text/javascript';
      script.src = 'https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&callback=googleMapReady#{google_api_key}';
      document.body.appendChild(script);

      script = document.createElement('script');
      script.type = 'text/javascript';
      script.src = 'https://api-maps.yandex.ru/2.0/?coordorder=longlat&load=package.full&wizard=constructor&lang=ru-RU&onload=yandexMapReady#{yandex_api_key}';
      document.body.appendChild(script);
    }

    window.onload = loadMapScripts;
    </script>

    <div data-map-data-source data-options='#{options.to_json}' data-id="#{id}" data-allowed-maps='#{allowed_maps.to_json}' style="width: #{options[:width]}px; height: #{options[:height]}px">
      #{map_html_containers.join}
    </div>

    #{switchers.join}
  </div>
  |
end
img_tag(width, height, options = {}) click to toggle source

IMG tag of options X options size with a point on it in the current value position (unless value is empty, of course).

See Google/Yandex Maps Static API.

# File lib/cck_forms/parameter_type_class/map.rb, line 72
def img_tag(width, height, options = {})
  map_type = value['type']

  if value['latitude'].present? and value['longitude'].present?
    if map_type == MAP_TYPE_GOOGLE
      zoom_if_any = value['zoom'].present? ? "&zoom=#{value['zoom']}" : nil
      marker_size_if_any = options[:marker_size] ? "|size:#{options[:marker_size]}" : nil

      url = %Q(
        http://maps.googleapis.com/maps/api/staticmap?
          language=ru&
          size=#{width}x#{height}&
          maptype=roadmap&
          markers=color:red#{marker_size_if_any}|
          #{value['latitude']},#{value['longitude']}&
          sensor=false
          #{zoom_if_any}
      ).gsub(/\s+/, '')

    else # yandex
      zoom_if_any = value['zoom'].present? ? "&z=#{value['zoom']}" : nil
      marker_size = options[:marker_size] == :large ? 'l' : 'm'

      url = %Q(
        http://static-maps.yandex.ru/1.x/?
          l=map&
          size=#{width},#{height}&
          pt=#{value['longitude']},#{value['latitude']},pm2bl#{marker_size}&
          #{zoom_if_any}
      ).gsub(/\s+/, '')
    end
    %Q(<img src="#{url}" width="#{width}" height="#{height}" />).html_safe
  else
    ''
  end
end
mongoize() click to toggle source

In application: {

latitude: x,
longitude: y,
zoom: z

}

In MongoDB: {latlon: [x, y], zoom: z}

# File lib/cck_forms/parameter_type_class/map.rb, line 48
def mongoize
  value = self.value.is_a?(Hash) ? self.value : {}
  return {
      'latlon' => [value['latitude'].presence, value['longitude'].presence],
      'zoom' => value['zoom'].presence,
      'type' => value['type'].presence || DEFAULT_MAP_TYPE
  }
end
to_diff_value(_options = {}) click to toggle source

Returns a 64x64 IMG with a marker (see img_tag)

# File lib/cck_forms/parameter_type_class/map.rb, line 245
def to_diff_value(_options = {})
  demongoize_value!
  img_tag(64, 64, marker_size: :small)
end
to_s(options = {}) click to toggle source

Call img_tag if :width & :height

# File lib/cck_forms/parameter_type_class/map.rb, line 58
def to_s(options = {})
  options ||= {}
  if options[:width].to_i > 0 and options[:height].to_i > 0
    return a_tag(to_s(options.except :link), options[:link]) if options[:link]
    return img_tag options[:width], options[:height]
  end

  ''
end
url() click to toggle source

Returns a URL to Google/Yandex Maps map with marker placed on the current value position

# File lib/cck_forms/parameter_type_class/map.rb, line 121
def url
  if value['latitude'].present? and value['longitude'].present?
    if value['type'] == MAP_TYPE_GOOGLE
      sprintf(
        'http://maps.google.com/maps?%s&t=m&q=%s+%s',
        value['zoom'].present? ? 'z=' + value['zoom'] : '',
        value['latitude'],
        value['longitude']
      )
    else # yandex
      sprintf(
        'http://maps.yandex.ru/?l=map&text=%s&ll=%s%s',
        [value['latitude'], value['longitude']].join(','),
        [value['longitude'], value['latitude']].join(','),
        value['zoom'].present? ? '&z=' + value['zoom'] : nil
      )
    end
  end
end