map_layers 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.autotest +7 -0
- data/.gitignore +2 -0
- data/.rspec +2 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +104 -0
- data/MIT-LICENSE +20 -0
- data/README +160 -0
- data/Rakefile +2 -0
- data/autotest/discover.rb +1 -0
- data/init.rb +8 -0
- data/install.rb +13 -0
- data/lib/map_layers.rb +358 -0
- data/lib/map_layers/#geonames.rb# +66 -0
- data/lib/map_layers/geonames.rb +66 -0
- data/lib/map_layers/js_wrapper.rb +178 -0
- data/lib/map_layers/map.rb +89 -0
- data/lib/map_layers/open_layers.rb +11 -0
- data/lib/map_layers/version.rb +3 -0
- data/lib/map_layers/view_helpers.rb +48 -0
- data/map_layers.gemspec +33 -0
- data/rails/init.rb +2 -0
- data/spec/lib/map_layers/js_wrapper_spec.rb +140 -0
- data/spec/lib/map_layers/map_spec.rb +13 -0
- data/spec/lib/map_layers/view_helpers_spec.rb +13 -0
- data/spec/lib/map_layers_spec.rb +63 -0
- data/spec/rcov.opts +2 -0
- data/spec/spec_helper.rb +98 -0
- data/tasks/map_layers_tasks.rake +21 -0
- data/uninstall.rb +1 -0
- metadata +188 -0
data/.autotest
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
map_layers (0.0.3)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: http://rubygems.org/
|
8
|
+
specs:
|
9
|
+
ZenTest (4.6.0)
|
10
|
+
abstract (1.0.0)
|
11
|
+
actionmailer (3.0.9)
|
12
|
+
actionpack (= 3.0.9)
|
13
|
+
mail (~> 2.2.19)
|
14
|
+
actionpack (3.0.9)
|
15
|
+
activemodel (= 3.0.9)
|
16
|
+
activesupport (= 3.0.9)
|
17
|
+
builder (~> 2.1.2)
|
18
|
+
erubis (~> 2.6.6)
|
19
|
+
i18n (~> 0.5.0)
|
20
|
+
rack (~> 1.2.1)
|
21
|
+
rack-mount (~> 0.6.14)
|
22
|
+
rack-test (~> 0.5.7)
|
23
|
+
tzinfo (~> 0.3.23)
|
24
|
+
activemodel (3.0.9)
|
25
|
+
activesupport (= 3.0.9)
|
26
|
+
builder (~> 2.1.2)
|
27
|
+
i18n (~> 0.5.0)
|
28
|
+
activerecord (3.0.9)
|
29
|
+
activemodel (= 3.0.9)
|
30
|
+
activesupport (= 3.0.9)
|
31
|
+
arel (~> 2.0.10)
|
32
|
+
tzinfo (~> 0.3.23)
|
33
|
+
activeresource (3.0.9)
|
34
|
+
activemodel (= 3.0.9)
|
35
|
+
activesupport (= 3.0.9)
|
36
|
+
activesupport (3.0.9)
|
37
|
+
arel (2.0.10)
|
38
|
+
autotest-notification (2.3.3)
|
39
|
+
autotest-standalone (~> 4.5)
|
40
|
+
autotest-rails (4.1.0)
|
41
|
+
ZenTest
|
42
|
+
autotest-standalone (4.5.5)
|
43
|
+
builder (2.1.2)
|
44
|
+
diff-lcs (1.1.2)
|
45
|
+
erubis (2.6.6)
|
46
|
+
abstract (>= 1.0.0)
|
47
|
+
i18n (0.5.0)
|
48
|
+
mail (2.2.19)
|
49
|
+
activesupport (>= 2.3.6)
|
50
|
+
i18n (>= 0.4.0)
|
51
|
+
mime-types (~> 1.16)
|
52
|
+
treetop (~> 1.4.8)
|
53
|
+
mime-types (1.16)
|
54
|
+
polyglot (0.3.2)
|
55
|
+
rack (1.2.3)
|
56
|
+
rack-mount (0.6.14)
|
57
|
+
rack (>= 1.0.0)
|
58
|
+
rack-test (0.5.7)
|
59
|
+
rack (>= 1.0)
|
60
|
+
rails (3.0.9)
|
61
|
+
actionmailer (= 3.0.9)
|
62
|
+
actionpack (= 3.0.9)
|
63
|
+
activerecord (= 3.0.9)
|
64
|
+
activeresource (= 3.0.9)
|
65
|
+
activesupport (= 3.0.9)
|
66
|
+
bundler (~> 1.0)
|
67
|
+
railties (= 3.0.9)
|
68
|
+
railties (3.0.9)
|
69
|
+
actionpack (= 3.0.9)
|
70
|
+
activesupport (= 3.0.9)
|
71
|
+
rake (>= 0.8.7)
|
72
|
+
rdoc (~> 3.4)
|
73
|
+
thor (~> 0.14.4)
|
74
|
+
rake (0.9.2)
|
75
|
+
rdoc (3.9.2)
|
76
|
+
rspec (2.0.1)
|
77
|
+
rspec-core (~> 2.0.1)
|
78
|
+
rspec-expectations (~> 2.0.1)
|
79
|
+
rspec-mocks (~> 2.0.1)
|
80
|
+
rspec-core (2.0.1)
|
81
|
+
rspec-expectations (2.0.1)
|
82
|
+
diff-lcs (>= 1.1.2)
|
83
|
+
rspec-mocks (2.0.1)
|
84
|
+
rspec-core (~> 2.0.1)
|
85
|
+
rspec-expectations (~> 2.0.1)
|
86
|
+
rspec-rails (2.0.1)
|
87
|
+
rspec (~> 2.0.0)
|
88
|
+
thor (0.14.6)
|
89
|
+
treetop (1.4.10)
|
90
|
+
polyglot
|
91
|
+
polyglot (>= 0.3.1)
|
92
|
+
tzinfo (0.3.29)
|
93
|
+
|
94
|
+
PLATFORMS
|
95
|
+
ruby
|
96
|
+
|
97
|
+
DEPENDENCIES
|
98
|
+
autotest-notification
|
99
|
+
autotest-rails
|
100
|
+
map_layers!
|
101
|
+
rails (>= 3.0.0)
|
102
|
+
rake
|
103
|
+
rspec (~> 2.0.0)
|
104
|
+
rspec-rails (~> 2.0.0)
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 [name of plugin creator]
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
=MapLayers plugin for Rails
|
2
|
+
|
3
|
+
MapLayers makes it easy to integrate a dynamic map in a Rails application. It can display map tiles and markers loaded from many different data sources.
|
4
|
+
The included map viewer is OpenLayers[http://www.openlayers.org/].
|
5
|
+
With MapLayers you can display and publish ActiveRecord models with geographic data.
|
6
|
+
|
7
|
+
|
8
|
+
==Getting Started
|
9
|
+
|
10
|
+
Install the latest version of the plugin:
|
11
|
+
./script/plugin install git://github.com/pka/map_layers.git
|
12
|
+
|
13
|
+
Create a controller and a view
|
14
|
+
./script/generate controller Map index
|
15
|
+
|
16
|
+
===Initialization of the map
|
17
|
+
Add the map viewer initialization to the index action in the controller:
|
18
|
+
@map = MapLayers::Map.new("map") do |map, page|
|
19
|
+
page << map.add_layer(MapLayers::GOOGLE)
|
20
|
+
page << map.zoom_to_max_extent()
|
21
|
+
end
|
22
|
+
|
23
|
+
Add this to the head of your view:
|
24
|
+
<%= map_layers_includes :google => "ABQIAAAA3HdfrnxFAPWyY-aiJUxmqRTJQa0g3IQ9GZqIMmInSLzwtGDKaBQ0KYLwBEKSM7F9gCevcsIf6WPuIQ" %>
|
25
|
+
|
26
|
+
Put a map in the body your view:
|
27
|
+
<div id="map" style="width: 512px; height: 256px;"></div>
|
28
|
+
|
29
|
+
<%= @map.to_html %>
|
30
|
+
|
31
|
+
Test your basic map with <tt>http://localhost:3000/map</tt>
|
32
|
+
|
33
|
+
===Multiple layers
|
34
|
+
Add a second layer and some more controls in the controller action:
|
35
|
+
@map = MapLayers::Map.new("map") do |map, page|
|
36
|
+
page << map.add_layer(MapLayers::GOOGLE)
|
37
|
+
page << map.add_layer(MapLayers::YAHOO_HYBRID)
|
38
|
+
|
39
|
+
page << map.add_control(Control::LayerSwitcher.new)
|
40
|
+
page << map.add_control(Control::Permalink.new('permalink'))
|
41
|
+
page << map.add_control(Control::MousePosition.new)
|
42
|
+
|
43
|
+
page << map.zoom_to_max_extent()
|
44
|
+
end
|
45
|
+
|
46
|
+
Add the Yahoo Javascript library to the includes:
|
47
|
+
<%= map_layers_includes :google => "ABQIAAAA3HdfrnxFAPWyY-aiJUxmqRTJQa0g3IQ9GZqIMmInSLzwtGDKaBQ0KYLwBEKSM7F9gCevcsIf6WPuIQ", :yahoo => "euzuro-openlayers" %>
|
48
|
+
|
49
|
+
There are many more predefined layer types available:
|
50
|
+
GOOGLE_SATELLITE, GOOGLE_HYBRID, GOOGLE_PHYSICAL, VE_ROAD, VE_AERIAL, VE_HYBRID, YAHOO, YAHOO_SATELLITE, YAHOO_HYBRID, MULTIMAP, OSM_MAPNIK, OSM_TELASCIENCE, GEOPOLE_OSM, NASA_GLOBAL_MOSAIC, BLUE_MARBLE_NG, WORLDWIND, WORLDWIND_URBAN, WORLDWIND_BATHY
|
51
|
+
|
52
|
+
To include all Javascript APIs, insert your API keys in the following statement:
|
53
|
+
<%= map_layers_includes :google => "ABQIAAAA3HdfrnxFAPWyY-aiJUxmqRTJQa0g3IQ9GZqIMmInSLzwtGDKaBQ0KYLwBEKSM7F9gCevcsIf6WPuIQ", :multimap => "metacarta_04", :virtualearth => true, :yahoo => "euzuro-openlayers" %>
|
54
|
+
|
55
|
+
|
56
|
+
===Updating the map
|
57
|
+
Now we want to add some simple markers in an Ajax action.
|
58
|
+
First we add a link in the view:
|
59
|
+
|
60
|
+
<%= link_to_remote "Add marker", :url => { :action => "add_marker" } %>
|
61
|
+
|
62
|
+
This requires including the prototype library:
|
63
|
+
|
64
|
+
<%= javascript_include_tag 'prototype' %>
|
65
|
+
|
66
|
+
Then we include a marker layer in the map. Put this after the add_layer statements in the controller:
|
67
|
+
|
68
|
+
page.assign("markers", Layer::Markers.new('Markers'))
|
69
|
+
page << map.addLayer(:markers)
|
70
|
+
|
71
|
+
and then we implement the Ajax action:
|
72
|
+
|
73
|
+
def add_marker
|
74
|
+
render :update do |page|
|
75
|
+
@markers = JsVar.new('markers')
|
76
|
+
page << @markers.add_marker(OpenLayers::Marker.new(OpenLayers::LonLat.new(rand*50,rand*50)))
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
For accessing the marker layer in the Ajax action, we declare a Javascript variable with <tt>page.assign</tt> and access the variable later with the +JsVar+ wrapper.
|
81
|
+
|
82
|
+
|
83
|
+
===OpenStreetMap in WGS84
|
84
|
+
|
85
|
+
To overlay data in WGS84 projection you can use a customized Open Street Map:
|
86
|
+
|
87
|
+
@map = MapLayers::Map.new("map") do |map, page|
|
88
|
+
page << map.add_layer(MapLayers::GEOPOLE_OSM)
|
89
|
+
page << map.zoom_to_max_extent()
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
=Publish your own data
|
94
|
+
|
95
|
+
Create a model:
|
96
|
+
./script/generate model --skip-timestamps --skip-fixture Place placeName:string countryCode:string postalCode:string lat:float lng:float
|
97
|
+
rake db:migrate
|
98
|
+
|
99
|
+
Import some places:
|
100
|
+
./script/runner "Geonames::Postalcode.search('Sidney').each { |pc| Place.create(pc.attributes.slice('placeName', 'postalCode', 'countryCode', 'lat', 'lng')) }"
|
101
|
+
|
102
|
+
Add a new controller with a map_layer:
|
103
|
+
|
104
|
+
class PlacesController < ApplicationController
|
105
|
+
|
106
|
+
map_layer :place, :text => :placeName
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
And add a layer to the map:
|
111
|
+
|
112
|
+
page << map.addLayer(Layer::GeoRSS.new("GeoRSS", "/places/georss"))
|
113
|
+
|
114
|
+
|
115
|
+
Other types of served layers:
|
116
|
+
|
117
|
+
page << map.add_layer(Layer::GML.new("Places KML", "/places/kml", {:format=> JsExpr.new("OpenLayers.Format.KML")}))
|
118
|
+
|
119
|
+
page << map.add_layer(Layer::WFS.new("Places WFS", "/places/wfs", {:typename => "places"}, {:featureClass => JsExpr.new("OpenLayers.Feature.WFS")}))
|
120
|
+
|
121
|
+
|
122
|
+
==Spatial database support
|
123
|
+
|
124
|
+
Using a spatial database requires GeoRuby[http://georuby.rubyforge.org/] and the Spatial Adapter for Rails:
|
125
|
+
|
126
|
+
sudo gem install georuby
|
127
|
+
ruby script/plugin install svn://rubyforge.org/var/svn/georuby/SpatialAdapter/trunk/spatial_adapter
|
128
|
+
|
129
|
+
Install spatial functions in your DB (e.g. Postgis 8.1):
|
130
|
+
DB=map_layers_dev
|
131
|
+
createlang plpgsql $DB
|
132
|
+
psql -d $DB -q -f /usr/share/postgresql-8.1-postgis/lwpostgis.sql
|
133
|
+
|
134
|
+
Create a model:
|
135
|
+
./script/generate model --skip-timestamps --skip-fixture WeatherStation name:string geom:point
|
136
|
+
rake db:migrate
|
137
|
+
|
138
|
+
Import some weather stations:
|
139
|
+
./script/runner "Geonames::Weather.weather(:north => 44.1, :south => -9.9, :east => -22.4, :west => 55.2).each { |st| WeatherStation.create(:name => st.stationName, :geom => Point.from_x_y(st.lng, st.lat)) }"
|
140
|
+
|
141
|
+
Add a new controller with a map_layer:
|
142
|
+
|
143
|
+
class WeatherStationsController < ApplicationController
|
144
|
+
|
145
|
+
map_layer :weather_stations, :geometry => :geom
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
And add a WFS layer to the map:
|
150
|
+
|
151
|
+
page << map.add_layer(Layer::WFS.new("Weather Stations", "/weather_stations/wfs", {:typename => "weather_stations"}, {:featureClass => JsExpr.new("OpenLayers.Feature.WFS")}))
|
152
|
+
|
153
|
+
==License
|
154
|
+
The MapLayers plugin for Rails is released under the MIT license.
|
155
|
+
|
156
|
+
==Support
|
157
|
+
For any questions, enhancement proposals, bug notifications or corrections visit http://rubyforge.org/projects/map-layers/ or send a mail to pka[at]sourcepole[dot]ch.
|
158
|
+
|
159
|
+
|
160
|
+
<em>Copyright (c) 2008 Pirmin Kalberer, Sourcepole AG</em>
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Autotest.add_discovery { "rspec2" }
|
data/init.rb
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
require 'map_layers'
|
2
|
+
require 'map_layers/view_helpers'
|
3
|
+
|
4
|
+
ActionController::Base.send(:include, MapLayers)
|
5
|
+
ActionView::Base.send(:include, MapLayers)
|
6
|
+
ActionView::Base.send(:include, MapLayers::ViewHelpers)
|
7
|
+
|
8
|
+
Mime::Type.register "application/vnd.google-earth.kml+xml", :kml
|
data/install.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Workaround a problem with script/plugin and http-based repos.
|
2
|
+
# See http://dev.rubyonrails.org/ticket/8189
|
3
|
+
Dir.chdir(Dir.getwd.sub(/vendor.*/, '')) do
|
4
|
+
|
5
|
+
def copy_files(source_path, destination_path, plugin_root)
|
6
|
+
source, destination = File.join(File.expand_path(plugin_root), source_path), File.join(RAILS_ROOT, destination_path)
|
7
|
+
FileUtils.mkdir(destination) unless File.exist?(destination)
|
8
|
+
FileUtils.cp_r(source, destination)
|
9
|
+
end
|
10
|
+
|
11
|
+
#copy_files("/public/.", "/public", File.dirname(__FILE__))
|
12
|
+
|
13
|
+
end
|
data/lib/map_layers.rb
ADDED
@@ -0,0 +1,358 @@
|
|
1
|
+
require 'active_support/core_ext'
|
2
|
+
|
3
|
+
module MapLayers # :nodoc:
|
4
|
+
|
5
|
+
#Include helpers in the given scope to AC and AV.
|
6
|
+
# def self.include_helpers(scope)
|
7
|
+
# ActiveSupport.on_load(:action_controller) do
|
8
|
+
# include scope::MapLayers
|
9
|
+
# end
|
10
|
+
|
11
|
+
# ActiveSupport.on_load(:action_view) do
|
12
|
+
# include scope::MapLayers
|
13
|
+
# include scope::MapLayers::ViewHelpers
|
14
|
+
# end
|
15
|
+
# end
|
16
|
+
|
17
|
+
# extend the class that include this with the methods in ClassMethods
|
18
|
+
def self.included(base)
|
19
|
+
base.extend(ClassMethods)
|
20
|
+
end
|
21
|
+
|
22
|
+
def map_layers_config
|
23
|
+
self.class.map_layers_config
|
24
|
+
end
|
25
|
+
|
26
|
+
module ClassMethods
|
27
|
+
|
28
|
+
def map_layer(model_id = nil, options = {})
|
29
|
+
options.assert_valid_keys(:id, :lat, :lon, :geometry, :text)
|
30
|
+
|
31
|
+
# converts Foo::BarController to 'bar' and FooBarsController to 'foo_bar' and AddressController to 'address'
|
32
|
+
model_id = self.to_s.split('::').last.sub(/Controller$/, '').pluralize.singularize.underscore unless model_id
|
33
|
+
|
34
|
+
# create the configuration
|
35
|
+
@map_layers_config = MapLayers::Config::new(model_id, options)
|
36
|
+
|
37
|
+
module_eval do
|
38
|
+
include MapLayers::KML
|
39
|
+
include MapLayers::WFS
|
40
|
+
include MapLayers::GeoRSS
|
41
|
+
include MapLayers::Proxy
|
42
|
+
include MapLayers::Rest
|
43
|
+
end
|
44
|
+
|
45
|
+
#session :off, :only => [:kml, :wfs, :georss]
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
def map_layers_config
|
50
|
+
@map_layers_config || self.superclass.instance_variable_get('@map_layers_config')
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
class Config
|
57
|
+
attr_reader :model_id, :id, :lat, :lon, :geometry, :text
|
58
|
+
|
59
|
+
def initialize(model_id, options)
|
60
|
+
@model_id = model_id.to_s.pluralize.singularize
|
61
|
+
@id = options[:id] || :id
|
62
|
+
@lat = options[:lat] || :lat
|
63
|
+
@lon = options[:lon] || :lng
|
64
|
+
@geometry = options[:geometry]
|
65
|
+
@text = options[:text] || :name
|
66
|
+
end
|
67
|
+
|
68
|
+
def model
|
69
|
+
@model ||= @model_id.to_s.camelize.constantize
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
class Feature < Struct.new(:text, :x, :y, :id)
|
75
|
+
attr_accessor :geometry
|
76
|
+
def self.from_geom(text, geom, id = nil)
|
77
|
+
f = new(text, geom.x, geom.y, id)
|
78
|
+
f.geometry = geom
|
79
|
+
f
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# KML Server methods
|
84
|
+
module KML
|
85
|
+
|
86
|
+
# Publish layer in KML format
|
87
|
+
def kml
|
88
|
+
rows = map_layers_config.model.find(:all, :limit => KML_FEATURE_LIMIT)
|
89
|
+
@features = rows.collect do |row|
|
90
|
+
if map_layers_config.geometry
|
91
|
+
Feature.from_geom(row.send(map_layers_config.text), row.send(map_layers_config.geometry))
|
92
|
+
else
|
93
|
+
Feature.new(row.send(map_layers_config.text), row.send(map_layers_config.lon), row.send(map_layers_config.lat))
|
94
|
+
end
|
95
|
+
end
|
96
|
+
@folder_name = map_layers_config.model_id.to_s.pluralize.humanize
|
97
|
+
logger.info "MapLayers::KML: returning #{@features.size} features"
|
98
|
+
render :inline => KML_XML_ERB, :content_type => "text/xml"
|
99
|
+
rescue Exception => e
|
100
|
+
logger.error "MapLayers::KML: returning no features - Caught exception '#{e}'"
|
101
|
+
render :text => KML_EMPTY_RESPONSE, :content_type => "text/xml"
|
102
|
+
end
|
103
|
+
|
104
|
+
protected
|
105
|
+
|
106
|
+
KML_FEATURE_LIMIT = 1000
|
107
|
+
|
108
|
+
KML_XML_ERB = <<EOS # :nodoc:
|
109
|
+
<?xml version="1.0" encoding="UTF-8" ?>
|
110
|
+
<kml xmlns="http://earth.google.com/kml/2.0">
|
111
|
+
<Document>
|
112
|
+
<Folder><name><%= @folder_name %></name>
|
113
|
+
<% for feature in @features -%>
|
114
|
+
<Placemark>
|
115
|
+
<description><%= feature.text %></description>
|
116
|
+
<Point><coordinates><%= feature.x %>,<%= feature.y %></coordinates></Point>
|
117
|
+
</Placemark>
|
118
|
+
<% end -%>
|
119
|
+
</Folder>
|
120
|
+
</Document>
|
121
|
+
</kml>
|
122
|
+
EOS
|
123
|
+
|
124
|
+
KML_EMPTY_RESPONSE = <<EOS # :nodoc:
|
125
|
+
<?xml version="1.0" encoding="UTF-8" ?>
|
126
|
+
<kml xmlns="http://earth.google.com/kml/2.0">
|
127
|
+
<Document>
|
128
|
+
</Document>
|
129
|
+
</kml>
|
130
|
+
EOS
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
# WFS Server methods
|
135
|
+
module WFS
|
136
|
+
|
137
|
+
WGS84 = 4326
|
138
|
+
|
139
|
+
# Publish layer in WFS format
|
140
|
+
def wfs
|
141
|
+
minx, miny, maxx, maxy = extract_params
|
142
|
+
model = map_layers_config.model
|
143
|
+
if map_layers_config.geometry
|
144
|
+
db_srid = model.columns_hash[map_layers_config.geometry.to_s].srid
|
145
|
+
if db_srid != @srid && !db_srid.nil? && db_srid != -1
|
146
|
+
#Transform geometry from db_srid to requested srid (not possible for undefined db_srid)
|
147
|
+
geom = "Transform(#{geom},#{@srid}) AS #{geom}"
|
148
|
+
end
|
149
|
+
|
150
|
+
spatial_cond = if model.respond_to?(:sanitize_sql_hash_for_conditions)
|
151
|
+
model.sanitize_sql_hash_for_conditions(map_layers_config.geometry => [[minx, miny],[maxx, maxy], db_srid])
|
152
|
+
else # Rails < 2
|
153
|
+
model.sanitize_sql_hash(map_layers_config.geometry => [[minx, miny],[maxx, maxy], db_srid])
|
154
|
+
end
|
155
|
+
#spatial_cond = "Transform(#{spatial_cond}, #{db_srid}) )" Not necessary: bbox is always WGS84 !?
|
156
|
+
|
157
|
+
rows = model.find(:all, :conditions => spatial_cond, :limit => @maxfeatures)
|
158
|
+
@features = rows.collect do |row|
|
159
|
+
Feature.from_geom(row.send(map_layers_config.text), row.send(map_layers_config.geometry.to_s))
|
160
|
+
end
|
161
|
+
else
|
162
|
+
rows = model.find(:all, :limit => @maxfeatures)
|
163
|
+
@features = rows.collect do |row|
|
164
|
+
Feature.new(row.send(map_layers_config.text), row.send(map_layers_config.lon), row.send(map_layers_config.lat))
|
165
|
+
end
|
166
|
+
end
|
167
|
+
logger.info "MapLayers::WFS: returning #{@features.size} features"
|
168
|
+
render :inline => WFS_XML_ERB, :content_type => "text/xml"
|
169
|
+
rescue Exception => e
|
170
|
+
logger.error "MapLayers::WFS: returning no features - Caught exception '#{e}'"
|
171
|
+
render :text => WFS_EMPTY_RESPONSE, :content_type => "text/xml"
|
172
|
+
end
|
173
|
+
|
174
|
+
protected
|
175
|
+
|
176
|
+
WFS_FEATURE_LIMIT = 1000
|
177
|
+
|
178
|
+
def extract_params # :nodoc:
|
179
|
+
@maxfeatures = (params[:maxfeatures] || WFS_FEATURE_LIMIT).to_i
|
180
|
+
@srid = params['SRS'].split(/:/)[1].to_i rescue WGS84
|
181
|
+
req_bbox = params['BBOX'].split(/,/).collect {|n| n.to_f } rescue nil
|
182
|
+
@bbox = req_bbox || [-180.0, -90.0, 180.0, 90.0]
|
183
|
+
end
|
184
|
+
|
185
|
+
WFS_XML_ERB = <<EOS # :nodoc:
|
186
|
+
<?xml version='1.0' encoding="UTF-8" ?>
|
187
|
+
<wfs:FeatureCollection
|
188
|
+
xmlns:ms="http://mapserver.gis.umn.edu/mapserver"
|
189
|
+
xmlns:wfs="http://www.opengis.net/wfs"
|
190
|
+
xmlns:gml="http://www.opengis.net/gml"
|
191
|
+
xmlns:ogc="http://www.opengis.net/ogc"
|
192
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
193
|
+
xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengeospatial.net/wfs/1.0.0/WFS-basic.xsd
|
194
|
+
http://mapserver.gis.umn.edu/mapserver http://www.geopole.org/map/wfs?SERVICE=WFS&VERSION=1.0.0&REQUEST=DescribeFeatureType&TYPENAME=geopole&OUTPUTFORMAT=XMLSCHEMA">
|
195
|
+
<gml:boundedBy>
|
196
|
+
<gml:Box srsName="EPSG:<%= @srid %>">
|
197
|
+
<gml:coordinates><%= @bbox[0] %>,<%= @bbox[1] %> <%= @bbox[2] %>,<%= @bbox[3] %></gml:coordinates>
|
198
|
+
</gml:Box>
|
199
|
+
</gml:boundedBy>
|
200
|
+
<% for feature in @features -%>
|
201
|
+
<gml:featureMember>
|
202
|
+
<ms:geopole>
|
203
|
+
<gml:boundedBy>
|
204
|
+
<gml:Box srsName="EPSG:<%= @srid %>">
|
205
|
+
<gml:coordinates><%= feature.x %>,<%= feature.y %> <%= feature.x %>,<%= feature.y %></gml:coordinates>
|
206
|
+
</gml:Box>
|
207
|
+
</gml:boundedBy>
|
208
|
+
<ms:msGeometry>
|
209
|
+
<gml:Point srsName="EPSG:<%= @srid %>">
|
210
|
+
<gml:coordinates><%= feature.x %>,<%= feature.y %></gml:coordinates>
|
211
|
+
</gml:Point>
|
212
|
+
</ms:msGeometry>
|
213
|
+
<ms:text><%= feature.text %></ms:text>
|
214
|
+
</ms:geopole>
|
215
|
+
</gml:featureMember>
|
216
|
+
<% end -%>
|
217
|
+
</wfs:FeatureCollection>
|
218
|
+
EOS
|
219
|
+
|
220
|
+
WFS_EMPTY_RESPONSE = <<EOS # :nodoc:
|
221
|
+
<?xml version='1.0' encoding="UTF-8" ?>
|
222
|
+
<wfs:FeatureCollection
|
223
|
+
xmlns:wfs="http://www.opengis.net/wfs"
|
224
|
+
xmlns:gml="http://www.opengis.net/gml"
|
225
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
226
|
+
xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengeospatial.net/wfs/1.0.0/WFS-basic.xsd">
|
227
|
+
<gml:boundedBy>
|
228
|
+
<gml:null>missing</gml:null>
|
229
|
+
</gml:boundedBy>
|
230
|
+
</wfs:FeatureCollection>
|
231
|
+
EOS
|
232
|
+
|
233
|
+
end
|
234
|
+
|
235
|
+
# GeoRSS Server methods
|
236
|
+
# http://www.georss.org/1
|
237
|
+
|
238
|
+
module GeoRSS
|
239
|
+
|
240
|
+
# Publish layer in GeoRSS format
|
241
|
+
def georss
|
242
|
+
rows = map_layers_config.model.find(:all, :limit => GEORSS_FEATURE_LIMIT)
|
243
|
+
@features = rows.collect do |row|
|
244
|
+
if map_layers_config.geometry
|
245
|
+
Feature.from_geom(row.send(map_layers_config.text), row.send(map_layers_config.geometry), row.send(map_layers_config.id))
|
246
|
+
else
|
247
|
+
Feature.new(row.send(map_layers_config.text), row.send(map_layers_config.lon), row.send(map_layers_config.lat))
|
248
|
+
end
|
249
|
+
end
|
250
|
+
@base_url = "http://#{request.env["HTTP_HOST"]}/"
|
251
|
+
@item_url = "#{@base_url}#{map_layers_config.model_id.to_s.pluralize}"
|
252
|
+
@title = map_layers_config.model_id.to_s.pluralize.humanize
|
253
|
+
logger.info "MapLayers::GEORSS: returning #{@features.size} features"
|
254
|
+
render :inline => GEORSS_XML_ERB, :content_type => "text/xml"
|
255
|
+
rescue Exception => e
|
256
|
+
logger.error "MapLayers::GEORSS: returning no features - Caught exception '#{e}'"
|
257
|
+
render :text => GEORSS_EMPTY_RESPONSE, :content_type => "text/xml"
|
258
|
+
end
|
259
|
+
|
260
|
+
protected
|
261
|
+
|
262
|
+
GEORSS_FEATURE_LIMIT = 1000
|
263
|
+
|
264
|
+
GEORSS_XML_ERB = <<EOS # :nodoc:
|
265
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
266
|
+
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
267
|
+
xmlns="http://purl.org/rss/1.0/"
|
268
|
+
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
269
|
+
xmlns:georss="http://www.georss.org/georss">
|
270
|
+
<docs>This is an RSS file. Copy the URL into your aggregator of choice. If you don't know what this means and want to learn more, please see: <span>http://platial.typepad.com/news/2006/04/really_simple_t.html</span> for more info.</docs>
|
271
|
+
<channel rdf:about="<%= @base_url %>">
|
272
|
+
<link><%= @base_url %></link>
|
273
|
+
<title><%= @title %></title>
|
274
|
+
<description></description>
|
275
|
+
<items>
|
276
|
+
<rdf:Seq>
|
277
|
+
<% for feature in @features -%>
|
278
|
+
<rdf:li resource="<%= @item_url %>/<%= feature.id %>"/>
|
279
|
+
<% end -%>
|
280
|
+
</rdf:Seq>
|
281
|
+
</items>
|
282
|
+
</channel>
|
283
|
+
<% ts=Time.now.rfc2822 -%>
|
284
|
+
<% for feature in @features -%>
|
285
|
+
<item rdf:about="<%= @item_url %>/<%= feature.id %>">
|
286
|
+
<!--<link><%= @item_url %>/<%= feature.id %></link>-->
|
287
|
+
<title><%= @title %></title>
|
288
|
+
<description><![CDATA[<%= feature.text %>]]></description>
|
289
|
+
<georss:point><%= feature.y %> <%= feature.x %></georss:point>
|
290
|
+
<dc:creator>map-layers</dc:creator>
|
291
|
+
<dc:date><%= ts %></dc:date>
|
292
|
+
</item>
|
293
|
+
<% end -%>
|
294
|
+
</rdf:RDF>
|
295
|
+
EOS
|
296
|
+
|
297
|
+
GEORSS_EMPTY_RESPONSE = <<EOS # :nodoc:
|
298
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
299
|
+
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
300
|
+
xmlns="http://purl.org/rss/1.0/">
|
301
|
+
<docs></docs>
|
302
|
+
<channel rdf:about="http://purl.org/rss/1.0/">
|
303
|
+
<link>http://purl.org/rss/1.0/</link>
|
304
|
+
<title>Empty GeoRSS</title>
|
305
|
+
<description></description>
|
306
|
+
<items>
|
307
|
+
<rdf:Seq>
|
308
|
+
</rdf:Seq>
|
309
|
+
</items>
|
310
|
+
</channel>
|
311
|
+
</rdf:RDF>
|
312
|
+
EOS
|
313
|
+
|
314
|
+
end
|
315
|
+
|
316
|
+
# Remote http Proxy
|
317
|
+
module Proxy
|
318
|
+
|
319
|
+
# Register an url, before the proxy is called
|
320
|
+
def register_remote_url(url)
|
321
|
+
session[:proxy_url] ||= []
|
322
|
+
session[:proxy_url] << url
|
323
|
+
end
|
324
|
+
|
325
|
+
# Proxy for accessing remote files like GeoRSS, which is not allowed directly from the browser
|
326
|
+
def proxy
|
327
|
+
if session[:proxy_url].nil? || !session[:proxy_url].include?(params["url"])
|
328
|
+
logger.warn "Proxy request not in session: #{params["url"]}"
|
329
|
+
render :nothing => true
|
330
|
+
return
|
331
|
+
end
|
332
|
+
|
333
|
+
url = URI.parse(URI.encode(params[:url]))
|
334
|
+
logger.debug "Proxy request for #{url.scheme}://#{url.host}#{url.path}"
|
335
|
+
|
336
|
+
result = Net::HTTP.get_response(url)
|
337
|
+
render :text => result.body, :status => result.code, :content_type => "text/xml"
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
# Restful feture Server methods (http://featureserver.org/)
|
342
|
+
module Rest
|
343
|
+
|
344
|
+
def index
|
345
|
+
respond_to do |format|
|
346
|
+
format.xml { wfs }
|
347
|
+
format.kml { kml }
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
end
|
352
|
+
|
353
|
+
end
|
354
|
+
|
355
|
+
require 'map_layers/version'
|
356
|
+
require 'map_layers/js_wrapper'
|
357
|
+
require 'map_layers/open_layers'
|
358
|
+
require 'map_layers/map'
|