From a7f5f6f53ded85b69070ea46e3bc91d9c7ecc0b9 Mon Sep 17 00:00:00 2001 From: Fernando Espinosa Date: Mon, 21 May 2012 19:13:02 +0200 Subject: [PATCH] Allows to save polygons into cartodb --- .gitignore | 12 +---- Gemfile | 2 + Gemfile.lock | 18 +++++++ app/assets/javascripts/application.js | 52 ++++++++++++++++++++- app/assets/stylesheets/application.css.scss | 12 +++++ app/controllers/areas_controller.rb | 12 +++++ app/controllers/home_controller.rb | 3 ++ app/models/area.rb | 4 ++ app/views/common/_map.html.erb | 7 +++ config/initializers/cartodb.rb | 1 + config/locales/en.yml | 2 + config/routes.rb | 1 + spec/acceptance/explore_map_spec.rb | 30 ++++++++++-- spec/support/acceptance/capybara_helpers.rb | 25 ++++++++++ 14 files changed, 165 insertions(+), 16 deletions(-) create mode 100644 app/controllers/areas_controller.rb create mode 100644 app/models/area.rb create mode 100644 config/initializers/cartodb.rb diff --git a/.gitignore b/.gitignore index eb3489a986..dfabb089f0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,5 @@ -# See http://help.github.com/ignore-files/ for more about ignoring files. -# -# If you find yourself ignoring temporary files generated by your text editor -# or operating system, you probably want to add a global ignore instead: -# git config --global core.excludesfile ~/.gitignore_global - -# Ignore bundler config /.bundle - -# Ignore the default SQLite database. /db/*.sqlite3 - -# Ignore all logfiles and tempfiles. /log/*.log /tmp +config/cartodb_config.* diff --git a/Gemfile b/Gemfile index 10d023e49a..a2364f9e79 100644 --- a/Gemfile +++ b/Gemfile @@ -2,6 +2,8 @@ source 'https://rubygems.org' gem 'rails', '~> 3.2.3' +gem 'cartodb-rb-client' + group :assets do gem 'sass-rails', '~> 3.2.3' gem 'coffee-rails', '~> 3.2.1' diff --git a/Gemfile.lock b/Gemfile.lock index d9c0073e84..186fc64e7f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -38,6 +38,16 @@ GEM rack-test (>= 0.5.4) selenium-webdriver (~> 2.0) xpath (~> 0.1.4) + cartodb-rb-client (0.3.1) + activesupport (>= 3.0.0) + i18n (>= 0.5.0, <= 0.6.0) + json (>= 1.5.3) + mime-types (>= 1.16) + oauth (= 0.4.5) + pg (= 0.11.0) + rgeo (= 0.3.2) + rgeo-geojson (= 0.2.1) + typhoeus (= 0.3.3) childprocess (0.3.2) ffi (~> 1.0.6) chunky_png (1.2.5) @@ -97,6 +107,8 @@ GEM multi_json (1.3.5) netrc (0.7.1) nokogiri (1.5.2) + oauth (0.4.5) + pg (0.11.0) poltergeist (0.6.0) capybara (~> 1.0) childprocess (~> 0.3) @@ -131,6 +143,9 @@ GEM json (~> 1.4) rest-client (1.6.7) mime-types (>= 1.16) + rgeo (0.3.2) + rgeo-geojson (0.2.1) + rgeo (>= 0.2.8) rspec (2.10.0) rspec-core (~> 2.10.0) rspec-expectations (~> 2.10.0) @@ -167,6 +182,8 @@ GEM treetop (1.4.10) polyglot polyglot (>= 0.3.1) + typhoeus (0.3.3) + mime-types tzinfo (0.3.33) uglifier (1.2.4) execjs (>= 0.3.0) @@ -179,6 +196,7 @@ PLATFORMS DEPENDENCIES capybara + cartodb-rb-client coffee-rails (~> 3.2.1) compass (~> 0.12.1) compass-rails (~> 1.0.1) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 4c462af65b..ce06e6cad9 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -4,7 +4,11 @@ $(function(){ - var map = new google.maps.Map(document.getElementById("map"), config.mapOptions); + var map = new google.maps.Map(document.getElementById("map"), config.mapOptions) + , renderPolygonListener = null + , polygonPath = [] + , polygon = null + ; map.mapTypes.set('GfwStyle', config.gfwStyle); map.setMapTypeId('GfwStyle'); @@ -52,4 +56,50 @@ $(function(){ var zoomOutControl = new ZoomOut(zoomOutControlDiv, map); zoomOutControlDiv.index = 2; + // Enables map editing mode. When activated, each click in the map draws a polyline + $('#map-container').find('.draw-area').click(function(){ + $(this).closest('#map-container').toggleClass('editing-mode'); + + if (renderPolygonListener) return; + + polygonPath = []; + + polygon = new google.maps.Polygon({ + paths: [], + strokeColor: "#FF0000", + strokeOpacity: 0.8, + strokeWeight: 3, + fillColor: "#FF0000", + fillOpacity: 0.35 + }); + + polygon.setMap(map); + + renderPolygonListener = google.maps.event.addListener(map, 'click', function(e){ + polygonPath.push(e.latLng); + polygon.setPath(polygonPath); + }); + }); + + // Disables editing mode. Sends the created polygon to cartodb. + $('#map-container').find('.save-area') + .submit(function(e){ + e.preventDefault(); + $(this).closest('#map-container').toggleClass('editing-mode'); + $(this).find('#area_the_geom').val("ST_GeomFromGeoJSON('" + JSON.stringify({ + "type": "Polygon", + "coordinates": [ + [ + $.map(polygonPath, function(latlong, index){ + return [latlong.lng(), latlong.lat()] + }) + ] + ] + }) + "')"); + + $.post($(this).attr('action'), $(this).serialize(), function(response){ + google.maps.event.removeListener(renderPolygonListener); + renderPolygonListener = null; + }); + }); }); diff --git a/app/assets/stylesheets/application.css.scss b/app/assets/stylesheets/application.css.scss index be8480adb8..0af4461137 100644 --- a/app/assets/stylesheets/application.css.scss +++ b/app/assets/stylesheets/application.css.scss @@ -288,3 +288,15 @@ nav { } } + +#map-container .save-area { + display: none; +} + +#map-container.editing-mode .draw-area { + display: none; +} + +#map-container.editing-mode .save-area { + display: inline; +} diff --git a/app/controllers/areas_controller.rb b/app/controllers/areas_controller.rb new file mode 100644 index 0000000000..15e0a2c73c --- /dev/null +++ b/app/controllers/areas_controller.rb @@ -0,0 +1,12 @@ +class AreasController < ApplicationController + + def create + area = Area.new params[:area] + area.save + + respond_to do |format| + format.json { render :nothing => true } + end + end + +end diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb index fc0b4743ac..9f2db37725 100644 --- a/app/controllers/home_controller.rb +++ b/app/controllers/home_controller.rb @@ -1,2 +1,5 @@ class HomeController < ApplicationController + def index + @area = Area.new + end end diff --git a/app/models/area.rb b/app/models/area.rb new file mode 100644 index 0000000000..8eb7deec15 --- /dev/null +++ b/app/models/area.rb @@ -0,0 +1,4 @@ +class Area < CartoDB::Model::Base + field :email + +end diff --git a/app/views/common/_map.html.erb b/app/views/common/_map.html.erb index 5da391e738..3ca3e914f1 100644 --- a/app/views/common/_map.html.erb +++ b/app/views/common/_map.html.erb @@ -8,6 +8,13 @@ + <%= link_to t('.map.draw_area'), '#', :class => 'draw-area' %> + <%= form_for :area, :url => areas_path, :html => {:method => :post, :class => 'save-area'} do |f| %> + <%= f.hidden_field :the_geom %> + <%= f.email_field :email, :placeholder => 'Email' %> + <%= f.submit t('.map.save_area') %> + <% end -%> +
diff --git a/config/initializers/cartodb.rb b/config/initializers/cartodb.rb new file mode 100644 index 0000000000..0810f349fe --- /dev/null +++ b/config/initializers/cartodb.rb @@ -0,0 +1 @@ +CartoDB::Init.start YAML.load_file(Rails.root.join('config/cartodb_config.yml')) diff --git a/config/locales/en.yml b/config/locales/en.yml index d623575e3b..002e923c46 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -47,6 +47,8 @@ en: fire: 'fire' carbon: 'carbon' biodiversity: 'biodiversity' + draw_area: 'Draw Area' + save_area: 'Save Area' countries: show: detail: diff --git a/config/routes.rb b/config/routes.rb index 1e2e0ae1e6..9b04d5df33 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,7 @@ Gfw::Application.routes.draw do resources :countries resources :demo + resources :areas match 'map' => 'home#index' root :to => 'home#index' end diff --git a/spec/acceptance/explore_map_spec.rb b/spec/acceptance/explore_map_spec.rb index 1f24747539..be81472c1f 100644 --- a/spec/acceptance/explore_map_spec.rb +++ b/spec/acceptance/explore_map_spec.rb @@ -15,15 +15,14 @@ context 'has a big map', :js => true do scenario 'properly loaded' do - within '#map_container #map' do + within '#map-container #map' do sleep 2 page.evaluate_script('config.mapLoaded').should be_true end end scenario 'with zoom controls' do - within '#map_container #map' do - peich + within '#map-container #map' do page.should have_css 'div', :title => 'Zoom in' page.should have_css 'div', :title => 'Click to zoom' page.should have_css 'div', :title => 'Drag to zoom' @@ -34,7 +33,7 @@ scenario 'with a sharing link' scenario 'with a map type selector' do - within '#map_container #map' do + within '#map-container #map' do page.should have_content 'Map' page.should have_content 'Satellite' page.should have_content 'Terrain' @@ -43,6 +42,29 @@ end + scenario 'allows to define an area and to upload it to cartodb', :js => true do + + within '#map-container' do + + click_link 'Draw Area' + + page.should have_link 'Draw Area', :visible => false + + 5.times { map_click } + + within 'form' do + fill_in 'area_email', :with => 'ferdev@vizzuality.com' + + expect do + click_button 'Save Area' + sleep 2 + end.to change{ Area.all.length }.by(1) + end + + end + + end + include_examples 'download section' include_examples 'common footer' diff --git a/spec/support/acceptance/capybara_helpers.rb b/spec/support/acceptance/capybara_helpers.rb index d4ce286b46..9b972cb891 100644 --- a/spec/support/acceptance/capybara_helpers.rb +++ b/spec/support/acceptance/capybara_helpers.rb @@ -2,6 +2,31 @@ module CapybaraHelpers def peich save_and_open_page end + + def map_click + page.execute_script <<-JS + (function(){ + + if (map) { + + var mapBounds = map.getBounds() + , maxLat = mapBounds.getNorthEast().lat() + , maxLong = mapBounds.getNorthEast().lng() + , minLat = mapBounds.getSouthWest().lat() + , minLong = mapBounds.getSouthWest().lng() + , randomLat = Math.random() * (maxLat - minLat) + minLat + , randomLong = Math.random() * (maxLong - minLong) + minLong + ; + + google.maps.event.trigger(map, 'click', { + latLng: new google.maps.LatLng(randomLat, randomLong) + }); + } + return true; + })(); + JS + rescue + end end RSpec.configure {|config| config.include CapybaraHelpers}