From 2acaa3117841c905b84fef9aede31fc9774ba7bd Mon Sep 17 00:00:00 2001 From: Riadh Habbachi <riadh@angrycactus.biz> Date: Tue, 8 Sep 2015 15:55:03 +0100 Subject: [PATCH 1/7] Improve tabs implementation for leaflet widget --- js/draw.js | 448 ++++++++++++++++++++++-------------------- leaflet_widget.module | 1 + 2 files changed, 241 insertions(+), 208 deletions(-) diff --git a/js/draw.js b/js/draw.js index 1a817ad..b95f2c4 100644 --- a/js/draw.js +++ b/js/draw.js @@ -1,244 +1,276 @@ (function ($) { - Drupal.leaflet_widget = Drupal.leaflet_widget || {}; - - Drupal.behaviors.geofield_widget = { - attach: attach - }; - - function attach(context, settings) { - $('.leaflet-widget').once().each(function(i, item) { - var id = $(item).attr('id'), - options = settings.leaflet_widget_widget[id]; - if (options.toggle) { - $('#' + id + '-input').before('<div class="map btn btn-default" style="cursor: pointer;" id="' + id + '-geojson-toggle">GEOJSON</div>'); - $('#' + id + '-input').before('<div class="map btn btn-default" style="cursor: pointer;" id="' + id + '-point-toggle">POINT</div></br><input type="text" id="manual-' + id + '-point-input" name="manual-point">'); - $('#manual-' + id + '-point-input').hide(); - $('#' + id + '-geojson-toggle').click(function () { - $(item).toggle(); - if ($(this).hasClass('map')) { - $(this).text('Use map'); - $(this).removeClass('map'); - $('#' + id + '-input').get(0).type = 'text'; - - //Hide select geographic areas if is enable. - if (options.geographic_areas) { - $('.geographic_areas_desc').hide(); - } - } - else { - $(this).text('GEOJSON'); - $('#' + id + '-input').get(0).type = 'hidden'; - $(this).addClass('map'); - - //Show select geographic areas if is enable. - if (options.geographic_areas) { - $('.geographic_areas_desc').show(); - } - } - }); + Drupal.leaflet_widget = Drupal.leaflet_widget || {}; - $('#' + id + '-point-toggle').click(function () { - $(item).toggle(); - $('#manual-' + id + '-point-input').toggle(); + Drupal.behaviors.geofield_widget = { + attach: attach + }; - if ($(this).hasClass('map')) { - $(this).text('Use map'); - $(this).removeClass('map'); - $('#manual-' + id + '-point-input').get(0).type = 'text'; + function attach(context, settings) { + $('.leaflet-widget').once().each(function(i, item) { + var id = $(item).attr('id'), + options = settings.leaflet_widget_widget[id]; - //Hide select geographic areas if is enable. - if (options.geographic_areas) { - $('.geographic_areas_desc').hide(); - } - } - else { - $(this).text('POINT'); - $('#' + id + '-input').get(0).type = 'hidden'; - $(this).addClass('map'); - var point_string = $('#manual-' + id + '-point-input').val(); - - if (point_string) { - var point_array = point_string.split(','); - var geojsonFeature = { - "type": "Feature", - "properties": {}, - "geometry": { - "type": "Point", - "coordinates": [point_array[0], point_array[1]] - } - }; - L.geoJson(geojsonFeature).addTo(map); - leafletWidgetFormWrite(map._layers, id); - } + var map = L.map(id, options.map); - //Show select geographic areas if is enable. - if (options.geographic_areas) { - $('.geographic_areas_desc').show(); - } - } - }); + L.tileLayer(options.map.base_url).addTo(map); - } - if (options.geographic_areas) { - var json_data = {}; - var selectList = "<div class='geographic_areas_desc'><p></br>Select a state to add into the map:</p><select id='geographic_areas' name='area'>"; - selectList += "<option value='0'>" + Drupal.t('-none-') + "</option>"; - - for (i = 0; i < options.areas.length; i++) { - json_data = jQuery.parseJSON(options.areas[i]); - $.each(json_data.features, function (index, item) { - selectList += "<option value='" + item.id + "'>" + item.properties.name + "</option>"; - }); - } - selectList += "</select></div></br>"; - $('#' + id + '-input').before(selectList); - - $('#geographic_areas').change(function() { - var area = $(this).val(); - - for (i = 0; i < options.areas.length; i++) { - json_data = jQuery.parseJSON(options.areas[i]); - $.each(json_data.features, function (index, item) { - if (item.id == area) { - L.geoJson(item).addTo(map); - leafletWidgetFormWrite(map._layers, id); - } - }); - } - }); - } - var map = L.map(id, options.map); - - L.tileLayer(options.map.base_url).addTo(map); - - var current = $('#' + id + '-input').val(); - current = JSON.parse(current); - var layers = Array(); - if (current.features.length) { - var geojson = L.geoJson(current) - for (var key in geojson._layers) { - layers.push(geojson._layers[key]); - } - } + // Get initial geojson value + var current = $('#' + id + '-input').val(); + current = JSON.parse(current); + var layers = Array(); + if (current.features.length) { + var geojson = L.geoJson(current) + for (var key in geojson._layers) { + layers.push(geojson._layers[key]); + } + } + + var Items = new L.FeatureGroup(layers).addTo(map); + + // Autocenter if that's cool. + if (options.map.auto_center) { + if (current.features.length) { + map.fitBounds(Items.getBounds()); + } + } + + // Add controles to the map + var drawControl = new L.Control.Draw({ + autocenter: true, + draw: { + position: 'topleft', + polygon: options.draw.tools.polygon, + circle: options.draw.tools.circle, + marker: options.draw.tools.marker, + rectangle: options.draw.tools.rectangle, + polyline: options.draw.tools.polyline + }, + edit: { + featureGroup: Items + } + }); + + map.addControl(drawControl); + + map.on('draw:created', function (e) { + var type = e.layerTypee, + layer = e.layer; + // Remove already created layers. We only want to save one + // per field. + leafletWidgetLayerRemove(map._layers, Items); + // Add new layer. + Items.addLayer(layer); + }); + + $(item).parents('form').submit(function(event){ + if ($('#' + id + '-toggle').hasClass('map')) { + leafletWidgetFormWrite(map._layers, id) + } + }); + + Drupal.leaflet_widget[id] = map; + + if (options.toggle) { + $('#' + id).before('<ul class="ui-tabs-nav leaflet-widget">' + + '<li><a href="#' + id + '">Map</a></li>' + + '<li><a href="#' + id + '-geojson' + '">GeoJSON</a></li>' + + '<li><a href="#' + id + '-points' + '">Points</a></li>' + + '</ul>'); + + $('#' + id).after('<div id="' + id + '-geojson">' + + '<label for="' + id + '-geojson-textarea">' + Drupal.t('Enter GeoJSON:') + '</label>' + + '<textarea class="text-full form-control form-textarea" id="' + id + '-geojson-textarea" cols="60" rows="10"></textarea>' + + '</div>'); + + // Set placeholder + $('#' + id + '-geojson-textarea').attr('placeholder', JSON.stringify({"type":"FeatureCollection","features":[]})); + + // Update field's input when geojson input is updated. + // @TODO validate before sync + $('#' + id + '-geojson-textarea').on('input', function(e) { + if(!$('#' + id + '-geojson-textarea').val()) { + $('#' + id + '-input').val(JSON.stringify({"type":"FeatureCollection","features":[]})); + } else { + $('#' + id + '-input').val($('#' + id + '-geojson-textarea').val()); + } + }); - var Items = new L.FeatureGroup(layers).addTo(map); - // Autocenter if that's cool. - if (options.map.auto_center) { + $('#' + id).after('<div id="' + id + '-points" class="">' + + '<label for="' + id + '-points">' + Drupal.t('Point') + '</label>' + + '<input class="text-full form-control form-text" type="text" id="' + id + '-points-input" " placeholder="longitude,latitude" "size="60" maxlength="255">' + + '</div>'); + + // Update field's input when geojson input is updated. + $('#' + id + '-points-input').on('input', function(e) { + var latlng = L.latLng($('#' + id + '-points-input').val().split(',')); + var coordinates = LatLngToCoords(latlng); + var write = JSON.stringify( + {"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":coordinates},"properties":[]}]} + ); + $('#' + id + '-input').val(write); + }); + + // Set parent as JQuery UI element and update on selection + $('#' + id).parent().tabs({ + // Default tab is the map tab. + selected: 0, + select: function(event, ui){ + switch(ui.index) { + case 0: + // Map tab is selected + // Clear previous layers + leafletWidgetLayerRemove(map._layers, Items); + var current = $('#' + id + '-input').val(); + current = JSON.parse(current); if (current.features.length) { + var geojson = L.geoJson(current) + for (var key in geojson._layers) { + // Add new layer. + Items.addLayer(geojson._layers[key]); + } map.fitBounds(Items.getBounds()); } + break; + + case 1: + // GeoJSON tab is selected + // Sync from field's input + $('#' + id + '-geojson-textarea').val($('#' + id + '-input').val()); + break; + + case 2: + // Points tab is selected + // Reset value and error message and classes (if any). + $('#' + id + '-points-input').val(''); + $('#' + id + '-points-input').parent().removeClass('has-error'); + $('#' + id + '-points-input').prop('disabled', false) + .removeClass('error'); + $('#' + id + '-points .help-block').remove(); + + var current = $('#' + id + '-input').val(); + current = JSON.parse(current); + // Make this unavailable if more then single point. + if (current.features.length == 0) { + // Empty. Nothing to do + } else if (current.features.length == 1 + && current.features[0].geometry.type == 'Point') { + $('#' + id + '-points-input').val(current.features[0].geometry.coordinates.toString()); + } else { + $('#' + id + '-points-input').parent().addClass('has-error'); + $('#' + id + '-points-input').prop('disabled', true) + .addClass('error') + .after('<span class="help-block">Current data cannot be converted to a single point!</span>'); + } + break; } + } + }); + } - var drawControl = new L.Control.Draw({ - autocenter: true, - draw: { - position: 'topleft', - polygon: options.draw.tools.polygon, - circle: options.draw.tools.circle, - marker: options.draw.tools.marker, - rectangle: options.draw.tools.rectangle, - polyline: options.draw.tools.polyline - }, - edit: { - featureGroup: Items - } - - }); + if (options.geographic_areas) { + var json_data = {}; + var selectList = "<div class='geographic_areas_desc'><p></br>Select a state to add into the map:</p><select id='geographic_areas' name='area'>"; + selectList += "<option value='0'>" + Drupal.t('-none-') + "</option>"; - map.addControl(drawControl); + for (i = 0; i < options.areas.length; i++) { + json_data = jQuery.parseJSON(options.areas[i]); + $.each(json_data.features, function (index, item) { + selectList += "<option value='" + item.id + "'>" + item.properties.name + "</option>"; + }); + } - map.on('draw:created', function (e) { - var type = e.layerTypee, - layer = e.layer; - // Remove already created layers. We only want to save one - // per field. - leafletWidgetLayerRemove(map._layers, Items); - // Add new layer. - Items.addLayer(layer); - }); + selectList += "</select></div></br>"; + $('#' + id + '-input').before(selectList); - $(item).parents('form').submit(function(event){ - if ($('#' + id + '-toggle').hasClass('map')) { - leafletWidgetFormWrite(map._layers, id) - } - }); + $('#geographic_areas').change(function() { + var area = $(this).val(); - Drupal.leaflet_widget[id] = map; + for (i = 0; i < options.areas.length; i++) { + json_data = jQuery.parseJSON(options.areas[i]); + $.each(json_data.features, function (index, item) { + if (item.id == area) { + L.geoJson(item).addTo(map); + leafletWidgetFormWrite(map._layers, id); + } + }); + } }); - } - - /** - * Writes layer to input field if there is a layer to write. - */ - function leafletWidgetFormWrite(layers, id) { - var write = Array(); - for (var key in layers) { - if (layers[key]._latlngs || layers[key]._latlng) { - write.push(layerToGeometry(layers[key])); - } } - // If no value then provide empty collection. - if (!write.length) { - write = JSON.stringify({"type":"FeatureCollection","features":[]}); + }); + } + + /** + * Writes layer to input field if there is a layer to write. + */ + function leafletWidgetFormWrite(layers, id) { + var write = Array(); + for (var key in layers) { + if (layers[key]._latlngs || layers[key]._latlng) { + write.push(layerToGeometry(layers[key])); } - $('#' + id + '-input').val('{"type":"FeatureCollection", "features":[' + write + ']}'); } - - /** - * Removes layers that are already on the map. - */ - function leafletWidgetLayerRemove(layers, Items) { - for (var key in layers) { - if (layers[key]._latlngs || layers[key]._latlng) { - Items.removeLayer(layers[key]); - } + // If no value then provide empty collection. + if (!write.length) { + write = JSON.stringify({"type":"FeatureCollection","features":[]}); + } + $('#' + id + '-input').val('{"type":"FeatureCollection", "features":[' + write + ']}'); + } + + /** + * Removes layers that are already on the map. + */ + function leafletWidgetLayerRemove(layers, Items) { + for (var key in layers) { + if (layers[key]._latlngs || layers[key]._latlng) { + Items.removeLayer(layers[key]); } } + } - // This will all go away once this gets into leaflet main branch: - // https://github.com/jfirebaugh/Leaflet/commit/4bc36d4c1926d7c68c966264f3cbf179089bd998 - var layerToGeometry = function(layer) { - var json, type, latlng, latlngs = [], i; + // This will all go away once this gets into leaflet main branch: + // https://github.com/jfirebaugh/Leaflet/commit/4bc36d4c1926d7c68c966264f3cbf179089bd998 + var layerToGeometry = function(layer) { + var json, type, latlng, latlngs = [], i; - if (L.Marker && (layer instanceof L.Marker)) { - type = 'Point'; - latlng = LatLngToCoords(layer._latlng); - return JSON.stringify({"type": type, "coordinates": latlng}); + if (L.Marker && (layer instanceof L.Marker)) { + type = 'Point'; + latlng = LatLngToCoords(layer._latlng); + return JSON.stringify({"type": type, "coordinates": latlng}); - } else if (L.Polygon && (layer instanceof L.Polygon)) { - type = 'Polygon'; - latlngs = LatLngsToCoords(layer._latlngs, 1); - return JSON.stringify({"type": type, "coordinates": [latlngs]}); + } else if (L.Polygon && (layer instanceof L.Polygon)) { + type = 'Polygon'; + latlngs = LatLngsToCoords(layer._latlngs, 1); + return JSON.stringify({"type": type, "coordinates": [latlngs]}); - } else if (L.Polyline && (layer instanceof L.Polyline)) { - type = 'LineString'; - latlngs = LatLngsToCoords(layer._latlngs); - return JSON.stringify({"type": type, "coordinates": latlngs}); + } else if (L.Polyline && (layer instanceof L.Polyline)) { + type = 'LineString'; + latlngs = LatLngsToCoords(layer._latlngs); + return JSON.stringify({"type": type, "coordinates": latlngs}); - } } + } - var LatLngToCoords = function (LatLng, reverse) { // (LatLng, Boolean) -> Array - var lat = parseFloat(reverse ? LatLng.lng : LatLng.lat), - lng = parseFloat(reverse ? LatLng.lat : LatLng.lng); - - return [lng,lat]; - } + var LatLngToCoords = function (LatLng, reverse) { // (LatLng, Boolean) -> Array + var lat = parseFloat(reverse ? LatLng.lng : LatLng.lat), + lng = parseFloat(reverse ? LatLng.lat : LatLng.lng); - var LatLngsToCoords = function (LatLngs, levelsDeep, reverse) { // (LatLngs, Number, Boolean) -> Array - var coord, - coords = [], - i, len; + return [lng,lat]; + } - for (i = 0, len = LatLngs.length; i < len; i++) { - coord = levelsDeep ? - LatLngToCoords(LatLngs[i], levelsDeep - 1, reverse) : - LatLngToCoords(LatLngs[i], reverse); - coords.push(coord); - } + var LatLngsToCoords = function (LatLngs, levelsDeep, reverse) { // (LatLngs, Number, Boolean) -> Array + var coord, + coords = [], + i, len; - return coords; + for (i = 0, len = LatLngs.length; i < len; i++) { + coord = levelsDeep ? + LatLngToCoords(LatLngs[i], levelsDeep - 1, reverse) : + LatLngToCoords(LatLngs[i], reverse); + coords.push(coord); } + return coords; + } + }(jQuery)); diff --git a/leaflet_widget.module b/leaflet_widget.module index 127b148..842f589 100644 --- a/leaflet_widget.module +++ b/leaflet_widget.module @@ -172,6 +172,7 @@ function leaflet_widget_field_widget_form(&$form, &$form_state, $field, $instanc // Include javascript. $widget['#attached']['library'][] = array('leaflet_widget', 'draw'); + $widget['#attached']['library'][] = array('system', 'ui.tabs'); //Check if we need to add geographic areas if (isset($settings['geographic_areas']) && $settings['geographic_areas']) { From 5dd2e4eb4f44280d5db0299b22c75ce17bd11d43 Mon Sep 17 00:00:00 2001 From: Riadh Habbachi <riadh@angrycactus.biz> Date: Tue, 8 Sep 2015 19:23:47 +0100 Subject: [PATCH 2/7] Update the field's input when updating the map. * Fix missing geojson propreties. --- js/draw.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/js/draw.js b/js/draw.js index b95f2c4..8c442e9 100644 --- a/js/draw.js +++ b/js/draw.js @@ -61,12 +61,9 @@ leafletWidgetLayerRemove(map._layers, Items); // Add new layer. Items.addLayer(layer); - }); - $(item).parents('form').submit(function(event){ - if ($('#' + id + '-toggle').hasClass('map')) { - leafletWidgetFormWrite(map._layers, id) - } + // Update the field input. + leafletWidgetFormWrite(Items._layers, id) }); Drupal.leaflet_widget[id] = map; @@ -207,7 +204,8 @@ var write = Array(); for (var key in layers) { if (layers[key]._latlngs || layers[key]._latlng) { - write.push(layerToGeometry(layers[key])); + var feature = '{ "type": "Feature","geometry":' + layerToGeometry(layers[key]) + '}'; + write.push(feature); } } // If no value then provide empty collection. From d02020d1276c55e36e2c995d5d4b4711cb02c55f Mon Sep 17 00:00:00 2001 From: Jacinto capote Robles <jacintocapote@gmail.com> Date: Thu, 10 Sep 2015 22:01:38 +0200 Subject: [PATCH 3/7] Fixed problem deleting items after use the new interface with the select regions --- js/draw.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/js/draw.js b/js/draw.js index 8c442e9..62b33dc 100644 --- a/js/draw.js +++ b/js/draw.js @@ -47,7 +47,7 @@ polyline: options.draw.tools.polyline }, edit: { - featureGroup: Items + featureGroup: Items, } }); @@ -60,7 +60,7 @@ // per field. leafletWidgetLayerRemove(map._layers, Items); // Add new layer. - Items.addLayer(layer); + Items.addLayer(layer); // Update the field input. leafletWidgetFormWrite(Items._layers, id) @@ -187,7 +187,12 @@ json_data = jQuery.parseJSON(options.areas[i]); $.each(json_data.features, function (index, item) { if (item.id == area) { - L.geoJson(item).addTo(map); + var geojson = L.geoJson(item, { + onEachFeature: function (feature, layer) { + Items.addLayer(layer); + + } + }); leafletWidgetFormWrite(map._layers, id); } }); From 535f6b155d10a9154f6fa7ff819f6d05411b7464 Mon Sep 17 00:00:00 2001 From: Jacinto capote Robles <jacintocapote@gmail.com> Date: Thu, 10 Sep 2015 22:05:16 +0200 Subject: [PATCH 4/7] Fixed label to use region instead state --- js/draw.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/draw.js b/js/draw.js index 62b33dc..d148ed3 100644 --- a/js/draw.js +++ b/js/draw.js @@ -167,7 +167,7 @@ if (options.geographic_areas) { var json_data = {}; - var selectList = "<div class='geographic_areas_desc'><p></br>Select a state to add into the map:</p><select id='geographic_areas' name='area'>"; + var selectList = "<div class='geographic_areas_desc'><p></br>Select a region to add into the map:</p><select id='geographic_areas' name='area'>"; selectList += "<option value='0'>" + Drupal.t('-none-') + "</option>"; for (i = 0; i < options.areas.length; i++) { From 67c4e01dd6349adae73857edc9ec5f5462edfb23 Mon Sep 17 00:00:00 2001 From: Jacinto capote Robles <jacintocapote@gmail.com> Date: Fri, 11 Sep 2015 22:07:28 +0200 Subject: [PATCH 5/7] Fixed problem deleting and saving a polygon --- js/draw.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/js/draw.js b/js/draw.js index d148ed3..ab29110 100644 --- a/js/draw.js +++ b/js/draw.js @@ -66,6 +66,10 @@ leafletWidgetFormWrite(Items._layers, id) }); + map.on('draw:deleted', function (e) { + $('#' + id + '-input').val(''); + }); + Drupal.leaflet_widget[id] = map; if (options.toggle) { @@ -189,6 +193,9 @@ if (item.id == area) { var geojson = L.geoJson(item, { onEachFeature: function (feature, layer) { + // Remove already created layers. We only want to save one + // per field. + leafletWidgetLayerRemove(map._layers, Items); Items.addLayer(layer); } From 1e785275c816e7f57ed0ff3fc1e60e6be30c980d Mon Sep 17 00:00:00 2001 From: Aaron Couch <acinternets@gmail.com> Date: Mon, 28 Sep 2015 16:42:40 -0500 Subject: [PATCH 6/7] Update leaflet_widget.module Fixes for https --- leaflet_widget.module | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/leaflet_widget.module b/leaflet_widget.module index 842f589..623be6a 100644 --- a/leaflet_widget.module +++ b/leaflet_widget.module @@ -335,7 +335,7 @@ function leaflet_widget_geojson_feature($wkt, $properties = array()) { */ function leaflet_widget_leaflet_widget_base_layers() { return array( - 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png' => 'OSM Mapnik', + '//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png' => 'OSM Mapnik', ); } From d003a04842eabb48330d1979e8aa8e6a63012bba Mon Sep 17 00:00:00 2001 From: acouch <acinternets@gmail.com> Date: Mon, 6 Jun 2016 15:43:36 -0400 Subject: [PATCH 7/7] Fixes NCS-299 dataset reorder --- js/draw.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/js/draw.js b/js/draw.js index ab29110..9249b8a 100644 --- a/js/draw.js +++ b/js/draw.js @@ -11,6 +11,10 @@ var id = $(item).attr('id'), options = settings.leaflet_widget_widget[id]; + // Keeps map from updating when fired from other event. + if (typeof id == 'undefined') + return false; + var map = L.map(id, options.map); L.tileLayer(options.map.base_url).addTo(map);