map_layers 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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'
|