Merge pull request #5048 from tchak/cart-editor-write

Carte Editor sends FeatureCollection to the server
This commit is contained in:
Paul Chavard 2020-04-16 19:39:50 +02:00 committed by GitHub
commit fcfb3cb835
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 98 additions and 55 deletions

View file

@ -1,16 +1,15 @@
class Champs::CarteController < ApplicationController
before_action :authenticate_logged_user!
EMPTY_GEO_JSON = '[]'
ERROR_GEO_JSON = ''
def show
@selector = ".carte-#{params[:position]}"
if params[:dossier].key?(:champs_attributes)
coordinates = params[:dossier][:champs_attributes][params[:position]][:value]
feature_collection = if params[:dossier].key?(:champs_attributes)
params[:dossier][:champs_attributes][params[:position]][:value]
else
coordinates = params[:dossier][:champs_private_attributes][params[:position]][:value]
params[:dossier][:champs_private_attributes][params[:position]][:value]
end
@champ = if params[:champ_id].present?
@ -21,40 +20,21 @@ class Champs::CarteController < ApplicationController
geo_areas = []
if coordinates == EMPTY_GEO_JSON
@champ.value = nil
@champ.geo_areas = []
elsif coordinates == ERROR_GEO_JSON
if feature_collection == ERROR_GEO_JSON
@error = true
@champ.value = nil
@champ.geo_areas = []
else
coordinates = JSON.parse(coordinates)
feature_collection = JSON.parse(feature_collection, symbolize_names: true)
if @champ.cadastres?
cadastres = ApiCartoService.generate_cadastre(coordinates)
geo_areas += cadastres.map do |cadastre|
cadastre[:source] = GeoArea.sources.fetch(:cadastre)
cadastre
end
populate_cadastres(feature_collection)
end
selections_utilisateur = legacy_selections_utilisateur_to_polygons(coordinates)
geo_areas += selections_utilisateur.map do |selection_utilisateur|
selection_utilisateur.merge(source: GeoArea.sources.fetch(:selection_utilisateur))
end
@champ.geo_areas = geo_areas.map do |geo_area|
GeoArea.new(geo_area)
end
@champ.value = coordinates.to_json
geo_areas = GeoArea.from_feature_collection(feature_collection)
end
if @champ.persisted?
@champ.save
@champ.update(value: nil, geo_areas: geo_areas)
end
rescue ApiCarto::API::ResourceNotFound
flash.alert = 'Les données cartographiques sont temporairement indisponibles. Réessayez dans un instant.'
response.status = 503
@ -62,14 +42,23 @@ class Champs::CarteController < ApplicationController
private
def legacy_selections_utilisateur_to_polygons(coordinates)
coordinates.map do |lat_longs|
{
geometry: {
type: 'Polygon',
coordinates: [lat_longs.map { |lat_long| [lat_long['lng'], lat_long['lat']] }]
def populate_cadastres(feature_collection)
coordinates = feature_collection[:features].filter do |feature|
feature[:geometry][:type] == 'Polygon'
end.map do |feature|
feature[:geometry][:coordinates][0].map { |(lng, lat)| { 'lng' => lng, 'lat' => lat } }
end
if coordinates.present?
cadastres = ApiCartoService.generate_cadastre(coordinates)
feature_collection[:features] += cadastres.map do |cadastre|
{
type: 'Feature',
geometry: cadastre.delete(:geometry),
properties: cadastre.merge(source: GeoArea.sources.fetch(:cadastre))
}
}
end
end
end
end

View file

@ -1,9 +1,10 @@
import L from 'leaflet';
import FreeDraw from 'leaflet-freedraw';
import area from '@turf/area';
import { fire, delegate } from '@utils';
import $ from 'jquery';
import polygonArea from './polygon_area';
import createFeatureCollection from './create-feature-collection';
const MAPS = new WeakMap();
@ -81,13 +82,18 @@ function drawUserSelectionEditor(map, { selection }) {
export function addFreeDrawEvents(map, selector) {
const input = findInput(selector);
map.freeDraw.on('markers', ({ latLngs }) => {
if (latLngs.length === 0) {
input.value = EMPTY_GEO_JSON;
} else if (polygonArea(latLngs) < 300000) {
input.value = JSON.stringify(latLngs);
} else {
input.value = ERROR_GEO_JSON;
const featureCollection = createFeatureCollection(latLngs);
if (area(featureCollection) < 300000) {
input.value = JSON.stringify(featureCollection);
} else {
input.value = ERROR_GEO_JSON;
}
}
fire(input, 'change');
@ -121,7 +127,7 @@ function getCurrentMap(element) {
}
}
const EMPTY_GEO_JSON = '[]';
const EMPTY_GEO_JSON = '{ "type": "FeatureCollection", "features": [] }';
const ERROR_GEO_JSON = '';
function findInput(selector) {

View file

@ -1,16 +1,16 @@
import area from '@turf/area';
export default function polygonArea(latLngs) {
return area({
export default function createFeatureCollection(latLngs) {
return {
type: 'FeatureCollection',
features: latLngs.map(featurePolygonLatLngs)
});
};
}
function featurePolygonLatLngs(latLngs) {
return {
type: 'Feature',
properties: {},
properties: {
source: 'selection_utilisateur'
},
geometry: {
type: 'Polygon',
coordinates: [latLngs.map(({ lng, lat }) => [lng, lat])]

View file

@ -74,6 +74,7 @@ class Champs::CarteChamp < Champ
def to_feature_collection
{
type: 'FeatureCollection',
id: type_de_champ.stable_id,
bbox: bounding_box,
features: (legacy_selections_utilisateur + except_selections_utilisateur).map(&:to_feature)
}

View file

@ -43,4 +43,14 @@ class GeoArea < ApplicationRecord
def rgeo_geometry
RGeo::GeoJSON.decode(geometry.to_json, geo_factory: RGeo::Geographic.simple_mercator_factory)
end
def self.from_feature_collection(feature_collection)
feature_collection[:features].map do |feature|
GeoArea.new(
source: feature[:properties].delete(:source),
properties: feature[:properties],
geometry: feature[:geometry]
)
end
end
end

View file

@ -5,3 +5,4 @@
locals: { champ: @champ, error: @error }) %>
<%= fire_event('carte:update', { selector: @selector, data: @champ.to_render_data }.to_json) %>
<%= fire_event('map:update', { featureCollection: @champ.to_feature_collection }.to_json) %>

View file

@ -36,7 +36,12 @@ describe Champs::CarteController, type: :controller do
end
context 'when coordinates are empty' do
let(:value) { '[]' }
let(:value) do
{
type: 'FeatureCollection',
features: []
}.to_json
end
it {
expect(assigns(:error)).to eq(nil)
@ -47,11 +52,26 @@ describe Champs::CarteController, type: :controller do
end
context 'when coordinates are informed' do
let(:value) { [[{ "lat": 48.87442541960633, "lng": 2.3859214782714844 }, { "lat": 48.87273183590832, "lng": 2.3850631713867183 }, { "lat": 48.87081237174292, "lng": 2.3809432983398438 }, { "lat": 48.8712640169951, "lng": 2.377510070800781 }, { "lat": 48.87510283703279, "lng": 2.3778533935546875 }, { "lat": 48.87544154230615, "lng": 2.382831573486328 }, { "lat": 48.87442541960633, "lng": 2.3859214782714844 }]].to_json }
let(:value) do
{
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {
source: 'selection_utilisateur'
},
geometry: { type: 'Polygon', coordinates: [[[2.3859214782714844, 48.87442541960633], [2.3850631713867183, 48.87273183590832], [2.3809432983398438, 48.87081237174292], [2.377510070800781, 48.8712640169951], [2.3859214782714844, 48.87442541960633]]] }
}
]
}.to_json
end
it { expect(response.body).not_to be_nil }
it { expect(response.body).to include('MultiPolygon') }
it { expect(response.body).to include('[2.38715792094576,48.8723062632126]') }
it {
expect(response.body).not_to be_nil
expect(response.body).to include('MultiPolygon')
expect(response.body).to include('[2.38715792094576,48.8723062632126]')
}
end
context 'when error' do
@ -76,10 +96,25 @@ describe Champs::CarteController, type: :controller do
post :show, params: params, format: 'js'
end
let(:value) { [[{ "lat": 48.87442541960633, "lng": 2.3859214782714844 }, { "lat": 48.87273183590832, "lng": 2.3850631713867183 }, { "lat": 48.87081237174292, "lng": 2.3809432983398438 }, { "lat": 48.8712640169951, "lng": 2.377510070800781 }, { "lat": 48.87510283703279, "lng": 2.3778533935546875 }, { "lat": 48.87544154230615, "lng": 2.382831573486328 }, { "lat": 48.87442541960633, "lng": 2.3859214782714844 }]].to_json }
let(:value) do
{
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {
source: 'selection_utilisateur'
},
geometry: { type: 'Polygon', coordinates: [[[2.3859214782714844, 48.87442541960633], [2.3850631713867183, 48.87273183590832], [2.3809432983398438, 48.87081237174292], [2.377510070800781, 48.8712640169951], [2.3859214782714844, 48.87442541960633]]] }
}
]
}.to_json
end
it { expect(response.status).to eq 503 }
it { expect(response.body).to include('Les données cartographiques sont temporairement indisponibles') }
it {
expect(response.status).to eq 503
expect(response.body).to include('Les données cartographiques sont temporairement indisponibles')
}
end
end
end

View file

@ -1,5 +1,5 @@
describe Champs::CarteChamp do
let(:champ) { Champs::CarteChamp.new(geo_areas: geo_areas) }
let(:champ) { Champs::CarteChamp.new(geo_areas: geo_areas, type_de_champ: create(:type_de_champ_carte)) }
let(:value) { '' }
let(:coordinates) { [[2.3859214782714844, 48.87442541960633], [2.3850631713867183, 48.87273183590832], [2.3809432983398438, 48.87081237174292], [2.3859214782714844, 48.87442541960633]] }
let(:geo_json) do
@ -49,6 +49,7 @@ describe Champs::CarteChamp do
let(:feature_collection) {
{
type: 'FeatureCollection',
id: champ.type_de_champ.stable_id,
bbox: champ.bounding_box,
features: features
}