array(
'#input' => TRUE,
'#columns' => array('lat', 'lon', 'wkt'),
'#delta' => 0,
'#process' => array('gmap_geo_picker_process'),
),
);
}
/**
* Implementation of hook_widget_info().
*/
function gmap_geo_widget_info() {
return array(
'gmap_geo_picker' => array(
'label' => t('GMap picker'),
'field types' => array('geo'),
),
);
}
/**
* Implementation of hook_widget().
*/
function gmap_geo_widget(&$form, &$form_state, $field, $items, $delta = 0) {
return array(
'#type' => $field['widget']['type'],
'#default_value' => isset($items[$delta]) ? $items[$delta] : '',
);
}
/**
* Implementation of hook_widget_settings().
* Adds a place to set a GMap macro for the initial location picker map.
*/
function gmap_geo_widget_settings($op, $widget) {
switch ($op) {
case 'form':
$form = array();
$form['gmap_geo_picker_macro'] = array(
'#type' => 'textfield',
'#title' => 'GMap macro',
'#default_value' => $widget['gmap_geo_picker_macro'] ? $widget['gmap_geo_picker_macro'] : '[gmap]',
'#description' => t("A GMap macro describing the initial location picker map. [gmap] displays a map with the settings from !gmap-admin.", array('!gmap-admin' => l('admin/settings/gmap', 'admin/settings/gmap'))),
);
return $form;
case 'save':
return array('gmap_geo_picker_macro');
}
}
/**
* See the gmap_set_location() function in gmap.module and its' companion location_latlon_form() in location.inc
*/
function gmap_geo_picker_process($element, $edit, $form_state, $form) {
$field = $form['#field_info'][$element['#field_name']];
$element['#title'] = $field['widget']['label'];
$element['#type'] = 'fieldset';
$element['map'] = array(); // reserve spot at top of form for map
$element['lat'] = array(
'#type' => 'textfield',
'#title' => t('Latitude'),
'#default_value' => isset($element['#value']['lat']) ? $element['#value']['lat'] : NULL,
'#required' => $field['required'],
'#size' => 15,
'#prefix' => '
',
);
$element['lon'] = array(
'#type' => 'textfield',
'#title' => t('Longitude'),
'#default_value' => isset($element['#value']['lon']) ? $element['#value']['lon'] : NULL,
'#required' => $field['required'],
'#size' => 15,
'#suffix' => '
',
);
$element['wkt'] = array(
'#type' => 'value',
'#value' => isset($element['#value']['wkt']) ? $element['#value']['wkt'] : NULL,
);
$element['map']['gmap']['#value'] = gmap_set_location($field['widget']['gmap_geo_picker_macro'], $element, array('latitude' => 'lat', 'longitude' => 'lon'));
$element['map_instructions'] = array(
'#type' => 'markup',
'#weight' => 2,
'#prefix' => '',
'#value' => t('You may set the location by clicking on the map, or dragging the location marker. To clear the location, click on the marker.'),
'#suffix' => '
',
);
return $element;
}
/**
* Implementation of hook_theme().
*/
function gmap_geo_theme() {
return array(
'gmap_geo_picker' => array(
'arguments' => array('element' => NULL),
),
'gmap_geo_formatter_gmap_geo' => array(
'function' => 'theme_gmap_geo_formatter',
'arguments' => array('element' => NULL),
),
'gmap_geo_formatter_gmap_geo_simplify' => array(
'function' => 'theme_gmap_geo_formatter',
'arguments' => array('element' => NULL),
),
);
}
/**
* Theme the gmap_picker widget.
*/
function theme_gmap_geo_picker($element) {
return $element['#children'];
}
/**
* Implementation of hook_field_formatter_info().
* Note that the formatters don't actually work for geo_data fields yet, because
* that field type doesn't (yet) provide its data in WKT.
*/
function gmap_geo_field_formatter_info() {
return array(
'gmap_geo' => array(
'label' => t('GMap'),
'field types' => array('geo', 'geo_data'),
'multiple values' => CONTENT_HANDLE_MODULE,
),
'gmap_geo_simplify' => array(
'label' => t('Simplified Polygon on a GMap'),
'field types' => array('geo', 'geo_data'),
'multiple values' => CONTENT_HANDLE_MODULE,
),
);
}
/**
* Themes a geo field as a gmap.
*
* Wasn't sure what to use as the base map settings. GMap default settings? GMap
* picker macro settings? Bdragon and I (Bec) have talked about a "gmap profile"
* setup, in which case we could provide a field formatter for each gmap profile
* ("GMap: profile_name"). This would be ideal.
*
* - Right now this map's settings are based on the gmap_picker widget settings,
* if present.
*
* - Should this be checking to make sure that the WKT is well-formed?
* Possibly with geo_wkt_validate()?
*
* - This field formatter is not useful with geodata from most shapefiles,
* because these shapes often have more points than JavaScript-based can handle
* (generally 1,000 points/vertices is a reasonable maximum).
*
* - Autozoom doesn't yet zoom for polygons and lines; this field formatter
* doesn't provide any autozoom stuff either.
*
* - Polygons don't get drawn at all by gmap unless at least one of their
* vertices is within the visible area. If not all of a polygon's vertices are
* within the visible area, they may be rendered incorrectly.
*/
function theme_gmap_geo_formatter($element) {
$i = 0;
$total_points = 0;
while (isset($element[$i])) {
$item = $element[$i]['#item'];
$i++;
if ($total_points > 1000) {
$i = -1;
drupal_set_message(t('Some data is not displayed on the map because there are too many items.'), 'warning');
break;
}
// get the feature's coordinates
$geodata = _gmap_geo_from_wkt($item['wkt']);
switch ($geodata['type']) {
case 'POINT':
foreach($geodata['data'] as $point) {
$coords = explode(' ', $point);
$map['markers'][] = array('longitude' => $coords[0], 'latitude' => $coords[1]);
$total_points++;
}
break;
case 'POLYGON':
case 'LINESTRING':
if (isset($item['centroid'])) {
$centroid_raw = _gmap_geo_from_wkt($item['centroid']);
$centroid = explode(' ', reset($centroid_raw['data']));
// autozoom for polygons is coming in GMap 1.1 (2008-12-30)
$map['latitude'] = $centroid[0];
$map['longitude'] = $centroid[1];
}
// get feature coordinates
$shape_coords = array();
foreach($geodata['data'] as $point) {
$shape_coords[] = explode(' ', $point);
}
// polygon simplification is resource intensive.
// I am not sure how well this handles line data -- quite possibly it
// would be fine, if you provide a centroid.
if ($element['#formatter'] == 'gmap_geo_simplify' && isset($centroid)) {
module_load_include('inc', 'gmap_geo', 'simplify');
$shape_coords = gmap_geo_simplify($shape_coords, $centroid);
}
// if the poly/line is too complex, let's not crash the browser...
if (count($shape_coords) < 200) {
$map['shapes'][] = array(
'type' => ($geodata['type'] == 'POLYGON' ? 'polygon' : 'line'),
'points' => $shape_coords,
);
$total_points += count($shape_coords);
}
else {
$map['markers'][] = array(
'longitude' => $centroid[0],
'latitude' => $centroid[1],
'text' => t('This shape has too many points to display on a Google Map')
);
$total_points++;
}
break;
}
}
if ($map) {
// Load field instance info. If the field uses the gmap_picker widget, use
// the widget's gmap macro to build the map array.
module_load_include('inc', 'content', 'includes/content.crud');
$field = content_field_instance_read(array('type_name' => $element['#type_name'], 'field_name' => $element['#field_name']));
if ($field[0]['widget']['type'] == 'gmap_picker') {
$field_map = gmap_parse_macro($field[0]['widget']['gmap_picker_macro']);
$map = array_merge($field_map, $map);
}
$map['behavior'] = array('autozoom');
if (isset($field_map['zoom'])) {
$map['maxzoom'] = $field_map['zoom'];
}
return theme('gmap', $map);
}
}
/**
* Split WKT into an array.
*/
function _gmap_geo_from_wkt($wkt) {
$geodata = preg_split('/ *\(|,|\)/', $wkt, -1, PREG_SPLIT_NO_EMPTY);
$geodata_type = array_shift($geodata);
return array('type' => $geodata_type, 'data' => $geodata);
}