Class: CckForms::ParameterTypeClass::Map

Inherits:
Object
  • Object
show all
Includes:
Base
Defined in:
lib/cck_forms/parameter_type_class/map.rb

Overview

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

Constant Summary collapse

MAP_TYPE_GOOGLE =
'google'.freeze
MAP_TYPE_YANDEX =
'yandex'.freeze
DEFAULT_MAP_TYPE =
Rails.application.config.cck_forms.maps.default_type || MAP_TYPE_GOOGLE
@@map_providers =
[MAP_TYPE_YANDEX, MAP_TYPE_GOOGLE]

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.demongoize_value(value, _parameter_type_class = nil) ⇒ Object

In MongoDB: [x, y], zoom: z

In application:

latitude: x,
longitude: y,
zoom: z



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 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

Instance Method Details

#a_tag(content, attrs) ⇒ Object

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



110
111
112
113
114
115
116
117
118
# 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) ⇒ Object

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


153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# 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 = {}) ⇒ Object

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.



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# 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

#mongoizeObject

In application:

latitude: x,
longitude: y,
zoom: z

In MongoDB: [x, y], zoom: z



48
49
50
51
52
53
54
55
# 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 = {}) ⇒ Object

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



245
246
247
248
# 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 = {}) ⇒ Object

Call #img_tag if :width & :height



58
59
60
61
62
63
64
65
66
# 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

#urlObject

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



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# 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