diff --git a/js/draw.js b/js/draw.js index 1a817ad..9249b8a 100644 --- a/js/draw.js +++ b/js/draw.js @@ -1,244 +1,290 @@ (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('
GEOJSON
'); - $('#' + id + '-input').before('
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); - } + // Keeps map from updating when fired from other event. + if (typeof id == 'undefined') + return false; - //Show select geographic areas if is enable. - if (options.geographic_areas) { - $('.geographic_areas_desc').show(); - } - } - }); + var map = L.map(id, options.map); - } - if (options.geographic_areas) { - var json_data = {}; - var selectList = "


Select a state to add into the map:


"; - $('#' + 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]); - } - } + L.tileLayer(options.map.base_url).addTo(map); + + // 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); + + // Update the field input. + leafletWidgetFormWrite(Items._layers, id) + }); + + map.on('draw:deleted', function (e) { + $('#' + id + '-input').val(''); + }); + + Drupal.leaflet_widget[id] = map; + + if (options.toggle) { + $('#' + id).before(''); + + $('#' + id).after('
' + + '' + + '' + + '
'); + + // 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('
' + + '' + + '' + + '
'); + + // 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('Current data cannot be converted to a single point!'); + } + 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 = "


Select a region to add into the map:


"; + $('#' + id + '-input').before(selectList); - 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); - }); + $('#geographic_areas').change(function() { + var area = $(this).val(); - $(item).parents('form').submit(function(event){ - if ($('#' + id + '-toggle').hasClass('map')) { - leafletWidgetFormWrite(map._layers, id) - } - }); + 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) { + 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); - Drupal.leaflet_widget[id] = 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) { + var feature = '{ "type": "Feature","geometry":' + layerToGeometry(layers[key]) + '}'; + write.push(feature); } - $('#' + 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..623be6a 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']) { @@ -334,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', ); }