会员经纬度获取和输出模块

论坛: 

Geofield

Geolocation Field

Category: 
Code
Tags: 
drupal 7.x
drupalgap
phonegap
jquery mobile
address field
planet drupal
geofield

In this tutorial (for DrupalCamp Ohio 2014)
we'll explore how to build a mobile application and website that can
geo locate places near our current position. The nearby location results
will be displayed on a map, and will allow us to click on a result item
to view its complete details.

The website will be powered by Drupal 7. The mobile application will be built using DrupalGap, which is powered by PhoneGap and jQuery Mobile. Let's get started!

1. Download and Install Drupal 7

  • Download
  • Install

2. Download and Enable the DrupalGap Module

  • Download
  • Install

3. Download and Enable the Address Field Module

  • Download
  • Install

4. Download and Enable the Geofield Module

  • Download
  • Install

4.a Enable the Geofield Map Module

This module comes packaged with the Geofield module, enable it as well.

5. Download and Enable the Geocoder Module

  • Download
  • Install

6. Create a Content Type called "Location"

Let's create a content type called "Location" at admin/structure/types/add.

6a. Add an Existing Image Field to the Content Type

  1. Go to admin/structure/types/manage/location/fields
  2. In the "Add existing field" section, select "Image: field_image (Image)", or select your own existing image field, or create a new one
  3. Click the "Save" button
  4. Keep all the default settings (optional), then click the "Save settings" button

7. Add an Address Field to the Content Type

In Drupal, go to admin/structure/types/manage/location/fields and add a new field with these values:

  • Label: Address
  • Machine Name: field_address
  • Field Type: Postal address
  • Widget: Dynamic address form

Click
the "Save" button, then click the "Save field settings" button, and
finally click the "Save settings" button at the bottom of the form.
We'll just use all the default values provided for this tutorial, but
feel free to adjust them.

8. Add a Geofield to the Content Type

In Drupal, go to admin/structure/types/manage/location/fields and add a new field with these values:

  • Label: Position
  • Machine Name: field_position
  • Field Type: Geofield
  • Widget: Geocode from another field

Click the "Save" button, then...

  1. Set the "Geocode from field" select list to "Address"
  2. Set the "Geocoder" select list to "Google geocoder"
  3. Click the "Save settings" button at the bottom of the form

We'll just use all the default values provided for this tutorial, but feel free to adjust them.

9. Adjust the "Manage Display" Settings for the Content Type for each Display Mode

  1. Go to admin/structure/types/manage/location/display
  2. Change the "Format" for "Position" to "Geofield Map"
  3. Click the "Save" button.
  4. Optional, repeat this for other fields and display modes (i.e. DrupalGap display mode)

10 Create some Locations with Addresses and Images

If you haven't already, go ahead and create some location nodes with addresses and images:

node/add/location

The geocoder will automatically fetch the latitude and longitude
coordinates and store them within field_position. I'd recommend creating
location nodes with addresses nearby your current position.

11. Create a Views JSON Page Display to Retrieve Nearby Results

Now
that we've got some location nodes with address and coordinate data,
we're ready to build a View. For this example our center location will
be:

Nationwide and Ohio Farm Bureau 4-H Center
2201 Fred Taylor Dr.
Columbus, OH 43210

Which
has latitude and longitude coordinates of 40.008078, -83.028636. The
View  will return to us JSON data about the location nodes that are
within a given coordinates' radius.

11.1 Create the View

  1. In Drupal, go to: admin/structure/views/add, then input these values:
  2. View name: Nearby Locations
  3. Machine name: nearby_locations
  4. Show Content of type Location sorted by Unsorted
  5. Check the "Create a page" box
  6. Path: nearby-locations.json
  7. Display format: JSON data document
  8. Items to display: 5
  9. Click "Continue & Edit"

11.2 Create a Contextual Filter for the Geofield's Proximity

  1. In the "Contextual Filters" section, Click the "Add" button
  2. Type the word "Position" into the Search box, to locate your field
  3. In the search results, check the box next to "Content: Position (field_position) - proximity"
  4. Click the "Apply (All Displays)" button
  5. In the "When the Filter Value is not in the URL" section, select the 'Display contents of "No Results Found"' radio button
  6. Expand the "Exceptions" field set, and clear out the "Exception value" text field
  7. Scroll down to the "Unit of Distance" selection list and choose your preferred option (we'll use Miles for this example)
  8. Click the "Apply (All Displays)" button

Why miles? Well you see, here in America we don't like units of 10, and instead prefer to make our lives, and the rest of the world's, difficult.

11.3 Sort by Closest Location (Proximity)

  1. In the "Sort criteria" section, Click the "Add" button
  2. Type the word "Position" into the Search box, to locate your field
  3. In the search results, check the box next to "Content: Position (field_position) - proximity"
  4. Click the "Apply (All Displays)" button
  5. Select the "Sort ascending" radio button
  6. Under the "Source of Origin Point" select list, choose the "Contextual Geofield Proximity Filter" option
  7. Click the "Apply (All Displays)" button

11.4 Change the Label on the Title Field, and Add 3 Fields: nid, proximity/latitude and proximity/longitude

We'll adjust the label on the title field, and add 2 more fields to our View:

  1. In the "Fields" section, click on the "Title" field, and change the label to: title
  2. Click the "Apply (All Displays)" button
  3. Click the "Add" button to add a new field
  4. Type the word "Nid" into the Search box, to locate the "Content: Nid" checkbox
  5. Click the "Apply (All Displays)" button
  6. Change the label to: nid
  7. Click the "Apply (All Displays)" button
  8. Click the "Add" button to add another field
  9. Type the word "Position" into the Search box, to locate your field
  10. In the search results, check the box next to "Content: Position (field_position) - proximity"
  11. Click the "Apply (All Displays)" button
  12. Uncheck the "Create a label" checkbox
  13. Set the "Round" to 2 decimal points
  14. Select the "Miles" option on the "Unit of Measure" select list
  15. Under the "Source of Origin Point" select list, choose the "Contextual Geofield Proximity Filter" option
  16. Click the "Apply (All Displays)" button

11.4a Add a Latitude and Longitude Field to the View

  1. In the "Fields" section, click the "Add" button
  2. Type the word "Position" into the Search box, to locate your field
  3. In the search results, check the box next to "Content: Position"
  4. Click the "Apply (All Displays)" button
  5. Change the label to: latitude
  6. Change the "Formatter" to "Latitude Only"
  7. Click the "Apply (All Displays)" button
  8. Repeat steps 1-7 for Longitude

11.4 b Add an Image Field to the View

  1. In the "Fields" section, click the "Add" button
  2. Type the word "Image" into the Search box, to locate your field
  3. In the search results, check the box next to "Content: Image"
  4. Click the "Apply (All Displays)" button
  5. Uncheck the "Create a label" checkbox
  6. Change the "Image style" to "Thumbnail 100x100"
  7. Click the "Apply (All Displays)" button

11.5 Preview the Results

  1. Scroll down to the "Preview with contextual filters" text field
  2. Enter
    your latitude and longitude separated by comma (with no spaces), then
    add an underscore followed by the radius to search within. For example, 40.008078,-83.028636_4
  3. Click the "Update preview" button
  4. Observe the results

What
this means is, given a latitude and longitude center point, find
content within a 4 mile radius. Adjust the coordinates and radius to
simulate a position near you and your content. Here's what the result
set will look similar to:

{
  "nodes" : [
    {
      "node" : {
        "title" : "Ohio Stadium Football Field",
        "field_geofield_distance" : "0.6",
        "nid" : "1",
        "latitude" : "40.003680400000",
        "latitude" : "-83.019381800000",
        "field_image" : {
          "src": "http://example.com/sites/default/files/...",
          "alt": ""
      }
    },
    {
      "node" : {
        "title" : "The Ohio Statehouse",
        "field_geofield_distance" : "3.6",
        "nid" : "5",
        "latitude" : "39.961333000000",
        "latitude" : "-82.998887300000",
        "field_image" : {
          "src": "http://example.com/sites/default/files/...",
          "alt": ""
        }
      }
    },
    {
      "node" : {
        "title" : "Columbus Museum of Art",
        "field_geofield_distance" : "3.7",
        "nid" : "3",
        "latitude" : "39.964359000000",
        "latitude" : "-82.987958000000",
        "field_image" : {
          "src": "http://example.com/sites/default/files/...",
          "alt": ""
        }
      }
    }
  ]
}

12. Download and Install the DrupalGap Mobile Application Development Kit

  • Download
  • Install

During the installation process, it is recommended to use a mobile device with Option 2 when setting up the PhoneGap environment. If this is your first time building a DrupalGap app, it is recommended to go with Option 1 instead.

Option
2, will allow us to compile the app directly to our mobile device.
Chances are our mobile device has a GPS feature, so we can use it to
locate nearby locations.

Once installed, DrupalGap will look something like the screen shot to the right, when it is running on the mobile device.

13. Enable the Address Field and Geofield Modules in the App

Download the modules and extract them into the app/modules directory:

  • Download Address Field
  • Download Geofield

Then enable them inside the settings.js file:

Drupal.modules.contrib['addressfield'] = {};
Drupal.modules.contrib['geofield'] = {};

14. Create a Page in the App to Display a Map

Next, let's follow the DrupalGap Google Map example documentation, which will create a simple page in the app that displays a map.

15. Set the App's Front Page to the Map

In our app's settings.js file, we'll set the front page of our app to the map:

drupalgap.settings.front = 'map';

Once loaded, the app will try to lookup our current position and display it on a map:

16. Add a Button and an Empty List, to Find and Display Nearby Locations

In my_module_map() (the page_callback function for the map), let's add a button above the map:

content['find_nearby_locations'] = {
  theme: 'button',
  text: 'Find Nearby Locations',
  attributes: {
    onclick: "_my_module_map_button_click()",
    'data-theme': 'b'
  }
};

and an empty list below the map:

content['location_results'] = {
  theme: 'jqm_item_list',
  items: [],
  attributes: {
    id: 'location_results_list'
  }
};

When the button is clicked, it will call the Drupal website (the
Views JSON Page) and pass along our current position to it (as a
contextual filter):

/**
 * The "Find Nearby Locations" click handler.
 */
function _my_module_map_button_click() {
  try {
    // Build the path to the view to retrieve the results.
    var range = 4; // Search within a 4 mile radius, for illustration purposes.
    var path = 'nearby-locations.json/' +
      _my_module_user_latitude + ',' + _my_module_user_longitude + '_' + range;
      
    // Call the server.
    views_datasource_get_view_result(path, {
        success: function(data) {
          
          if (data.nodes.length == 0) {
            drupalgap_alert('Sorry, we did not find any nearby locations!');
            return;
          }

          // Iterate over each spot, add it to the list and place a marker on the map.
          var items = [];
          $.each(data.nodes, function(index, object) {
              
              // Render a nearby location, and add it to the item list.
              var row = object.node;
              var image_html = theme('image', { path: row.field_image.src });
              var distance =
                row.field_geofield_distance + ' ' +
                drupalgap_format_plural(row.field_geofield_distance, 'mile', 'miles');
              var description =
                '<h2>' + distance + '</h2>' +
                '<p>' + row.title + '</p>';
              var link = l(image_html + description, 'node/' + row.nid);
              items.push(link);
              
              // Add a marker on the map for the location.
              var locationLatlng = new google.maps.LatLng(row.latitude, row.longitude);
              var marker = new google.maps.Marker({
                  position: locationLatlng,
                  map: _my_module_map,
                  data: row
              });
              
          });
          drupalgap_item_list_populate("#location_results_list", items);

        }
    });
  }
  catch (error) { console.log('_my_module_map_button_click - ' + error); }
}

The server will respond with some JSON data about the nearby
locations, and we'll display them on the map and inject them into the
empty list:

And if we scroll down we can see the result list:

17. Click on a Result List Item to View a Location Node

Provided we adjusted the DrupalGap Display Mode for our content type, we can now click on a list item result to view the actual node automatically!

This is because DrupalGap has built in support for many common Drupal paths, such as:

node/123
node/123/edit
user/456
user/456/edit
user/login
user/register
etc...

18. Conclusion

Thank you to DrupalCamp Ohio for the opportunity to present this tutorial!

I hope you enjoyed the tutorial. This would not be possible without Drupal, PhoneGap, jQuery Mobile and the countless other open source projects involved. Cheers to open source software!