first import

This commit is contained in:
Bachir Soussi Chiadmi
2015-04-08 11:40:19 +02:00
commit 1bc61b12ad
8435 changed files with 1582817 additions and 0 deletions

View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -0,0 +1,98 @@
__ _ _ _
/ _(_) | | | |
__ _ ___ ___ | |_ _ ___| | __| |
/ _` |/ _ \/ _ \| _| |/ _ \ |/ _` |
| (_| | __/ (_) | | | | __/ | (_| |
\__, |\___|\___/|_| |_|\___|_|\__,_|
__/ |
|___/
CONTENTS OF THIS FILE
---------------------
* About Geofield
* Install
* Configure
* Credits
* API notes
ABOUT GEOFIELD
--------------
Geofield (http://drupal.org/project/geofield) is a Drupal 7 module that
provides a field types for storing geographic data. This data can be attached
to any entity, e.g., nodes, users and taxonomy terms. Geofield provides
different widgets for data input and formatters for data output. The Geofield
module can can store data as Latitude and Longitude, Bounding Box and Well
Known Text (WKT) and it supports all types of geographical data: points,
lines, polygons, multitypes et cetera.
Great documentation on Geofield can be found at http://drupal.org/node/1089574
INSTALL
-------
Install the modules Geofield and geoPHP in the usual way. General information
on installing Drupal modules can be found here: http://drupal.
org/documentation/install/modules-themes/modules-7
Optionally install Open Layers 2: http://drupal.org/project/openlayers
CONFIGURE
---------
To add a geofield to a content type go to /admin/structure/types/ and choose
"Manage fields" for the chosen content type. Add a new field of the field type
"Geofield", and choose the preferred widget, e.g., "OpenLayers Map". Configure
the field according ton the chosen options.
Geofield comes with the basic but easy-to-use submodule Geofield Map that
allows you to display geographical data in a Google map. Enable Geofield Map
at /admin/modules. Read more about Geofield Map at
http://drupal.org/node/1466490
For more advanced and flexible data display you need to configure or create a
map in OpenLayers at /admin/structure/openlayers/maps. You can easily create
your own map by cloning an existing one. An introduction to OpenLayers can be
found here: http://drupal.org/node/1481374.
When you have configured a map in OpenLayers you must define to use the map.
Go to /admin/structure/types and choose "Manage display".
Note: you can also add a geofield to a user, a taxonomy term or a comment.
CREDITS
-------
Original author: Tristan O'Neil
Contributors: Alex Barth, Jeff Miccolis, Young Hahn, Tom MacWright,
Patrick Hayes, Dave Tarc, Nikhil Trivedi, Marek Sotak,
Khalid Jebbari, Brandon Morrison, David Peterson
API NOTES
---------
Geofield fields contain nine columns of information about the geographic data
that is stores. At its heart is the 'wkt' column where it stores the full
geometry in the 'Well Known Text' (WKT) format. All other columns are metadata
derived from the WKT column. Columns are as follows:
'wkt' WKT
'geo_type' Type of geometry (point, linestring, polygon etc.)
'lat' Centroid (Latitude or Y)
'lon' Centroid (Longitude or X)
'top' Bounding Box Top (Latitude or Max Y)
'bottom' Bounding Box Bottom (Latitude or Min Y)
'left' Bounding Box Left (Longitude or Min X)
'right' Bounding Box Right (Longitude or Max X)
When a geofield is saved using the provided widgets, these values are passed
through the geofield_compute_values function in order to compute dependent
values. By default dependent values are computed based on WKT, but this may be
overriden to compute values based on other columns. For example,
geofield_compute_values may be called like so:
geofield_compute_values($values, 'latlon');
This will compute the wkt field (and all other fields) based on the lat/lon
columns, resulting in a point. As a developer this is important to remember if
you modify geofield information using node_load and node_save. Make sure to
run any modified geofield instances through geofield_compute_values in order
to make all columns consistent.

View File

@@ -0,0 +1,165 @@
<?php
/**
* @file
* Create random data to populate geofields.
*/
/**
* Implements hook_devel_generate().
*/
function geofield_devel_generate($object, $field, $instance, $bundle) {
if (field_behaviors_widget('multiple values', $instance) == FIELD_BEHAVIOR_CUSTOM) {
return devel_generate_multiple('_geofield_devel_generate', $object, $field, $instance, $bundle);
}
else {
return _geofield_devel_generate($object, $field, $instance, $bundle);
}
}
function _geofield_devel_generate($object, $field, $instance, $bundle) {
$object_field = array();
$type = str_replace('geofield_', '', $instance['widget']['type']);
$val = array(
'wkt' => NULL,
'lat' => NULL,
'lon' => NULL,
'top' => NULL,
'bottom' => NULL,
'right' => NULL,
'left' => NULL,
);
if ($type == 'latlon' || $type == 'bounds') {
list($val['lon'], $val['lat']) = _random_point();
// don't actually need lat/lon but provide a center for our bounds
if ($type == 'bounds') {
$lat_diff = _dd_generate(2, 10) / 100;
$lon_diff = _dd_generate(2, 10) / 100;
$val['left'] = $val['lon'] - $lon_diff;
$val['right'] = $val['lon'] + $lon_diff;
$val['top'] = $val['lat'] - $lat_diff;
$val['bottom'] = $val['lat'] + $lat_diff;
}
}
else {
$type = 'wkt';
$val['wkt'] = _wkt_generate();
}
$values = geofield_compute_values($val, $type);
return $values;
}
/**
* Helper to generate DD coordinates
*/
function _dd_generate($min, $max, $int = FALSE) {
$func = 'rand';
if (function_exists('mt_rand')) {
$func = 'mt_rand';
}
$number = $func($min, $max);
if ($int || abs($number) === 180) {
return $number;
}
$decimals = $func(1, pow(10, 5)) / pow(10, 5);
return round($number + $decimals, 5);
}
/**
* Helper to generate a random WKT string
*
* Try to keeps values sane, no shape is more than 100km across
*/
function _wkt_generate() {
$types = array(
'point',
'linestring',
'polygon',
'multipoint',
'multilinestring',
'multipolygon',
);
// don't always generate the same type
shuffle($types);
$type = $types[0];
$func = '_wkt_generate_' . $type;
if (function_exists($func)) {
$wkt = $func();
return drupal_strtoupper($type) . ' (' . $wkt . ')';
}
return 'POINT (0 0)';
}
function _random_point() {
$lon = _dd_generate(-180, 180);
$lat = _dd_generate(-84, 84);
return array($lon, $lat);
}
function _wkt_generate_point($point = FALSE) {
$point = $point ? $point : _random_point();
return implode(' ', $point);
}
function _wkt_generate_multipoint() {
$num = _dd_generate(1, 5, TRUE);
$start = _random_point();
$points[] = _wkt_generate_point($start);
for ($i = 0; $i < $num; $i += 1) {
$diff = _random_point();
$start[0] += $diff[0] / 100;
$start[1] += $diff[1] / 100;
$points[] = _wkt_generate_point($start);
}
return implode(', ', $points);
}
// make a line that looks like a line
function _wkt_generate_linestring($start = FALSE, $segments = FALSE) {
$start = $start ? $start : _random_point();
$segments = $segments ? $segments : _dd_generate(1, 5, TRUE);
$points[] = $start[0] . ' ' . $start[1];
// Points are at most 1km away from each other
for ($i = 0; $i < $segments; $i += 1) {
$diff = _random_point();
$start[0] += $diff[0] / 100;
$start[1] += $diff[1] / 100;
$points[] = $start[0] . ' ' . $start[1];
}
return implode(", ", $points);
}
// make a line that looks like a line
function _wkt_generate_multilinestring() {
$start = _random_point();
$num = _dd_generate(1, 3, TRUE);
$lines[] = _wkt_generate_linestring($start);
for ($i = 0; $i < $num; $i += 1) {
$diff = _random_point();
$start[0] += $diff[0] / 100;
$start[1] += $diff[1] / 100;
$lines[] = _wkt_generate_linestring($start);
}
return '(' . implode('), (', $lines) . ')';
}
function _wkt_generate_polygon($start = FALSE, $segments = FALSE) {
$start = $start ? $start : _random_point();
$segments = $segments ? $segments : _dd_generate(2, 4, TRUE);
$poly = _wkt_generate_linestring($start, $segments);
// close the polygon
return '(' . $poly . ' , ' . $start[0] . ' ' . $start[1] . ')';
}
function _wkt_generate_multipolygon() {
$start = _random_point();
$num = _dd_generate(1, 5, TRUE);
$segments = _dd_generate(2, 3, TRUE);
$poly[] = _wkt_generate_polygon($start, $segments);
for ($i = 0; $i < $num; $i += 1) {
$diff = _random_point();
$start[0] += $diff[0] / 100;
$start[1] += $diff[1] / 100;
$poly[] = _wkt_generate_polygon($start, $segments);
}
return '(' . implode(', ', $poly) . ')';
}

View File

@@ -0,0 +1,216 @@
<?php
/**
* @file
* Provides integration with Feeds module (http://drupal.org/project/feeds)
*/
/**
* Implementation of hook_feeds_parser_sources_alter().
*
* @see geofield_feeds_combined_source()
*/
function geofield_feeds_parser_sources_alter(&$sources, $content_type) {
$sources['geofield'] = array(
'name' => t('Geofield (combined)'),
'description' => t('All geographic information from the item.'),
'callback' => 'geofield_feeds_combined_source',
);
}
/**
* Callback; Provides a source combining geo information from items.
*
* Currently handles geo output from:
* - simplepie 1.3
* - common syndication parser (feeds 7.x-2.x)
*
* @param $source
* The FeedsSource object being imported.
* @param $result
* The FeedsParserResult object being mapped from.
* @param $key
* The key specified in the $sources array in
* hook_feeds_parser_sources_alter().
*
* @return
* The value to be extracted from the source.
*
* @see geofield_feeds_parser_sources_alter()
*/
function geofield_feeds_combined_source($source, FeedsParserResult $result, $key) {
$values = array();
$item = $result->currentItem();
// Simplepie 1.3 output
if (isset($item['location_latitude'])) {
// Lon X; lat Y
foreach ($item['location_latitude'] as $key => $lat) {
$point = array('lat' => $lat, 'lon' => $item['location_longitude'][$key]);
$values[] = geofield_compute_values($point, 'latlon');
}
}
// Common Syndication Parser
elseif (isset($item['geolocations'][0]) && is_a($item['geolocations'][0], 'FeedsGeoTermElement')) {
// Presently Common Syndication Parser is just parsing points?
// and is creating FeedsGeoTermElements, which is possibly not so useful.
// Maybe better if we could read access the original item, or add in to the item parsing?
foreach ($item['geolocations'] as $geolocation) {
$point = array('lat' => $geolocation->lat, 'lon' => $geolocation->lon);
$values[] = geofield_compute_values($point, 'latlon');
}
}
return $values;
}
/**
* Implements hook_feeds_node_processor_targets_alter().
*/
function geofield_feeds_processor_targets_alter(&$targets, $entity_type,
$bundle_name) {
foreach (field_info_instances($entity_type, $bundle_name) as
$name => $instance) {
$info = field_info_field($name);
if ($info['type'] == 'geofield') {
$targets[$info['field_name'] . ':wkt'] = array(
'name' => t($instance['label'] . ' WKT'),
'callback' => 'geofield_set_target_wkt',
'real_target' => $info['field_name'],
);
$targets[$info['field_name'] . ':lat'] = array(
'name' => t($instance['label'] . ' Latitude'),
'callback' => 'geofield_set_target_simple',
'real_target' => $info['field_name'],
);
$targets[$info['field_name'] . ':lon'] = array(
'name' => t($instance['label'] . ' Longitude'),
'callback' => 'geofield_set_target_simple',
'real_target' => $info['field_name'],
);
$targets[$info['field_name'] . ':left'] = array(
'name' => t($instance['label'] . ' Left Latitude'),
'callback' => 'geofield_set_target_simple',
'real_target' => $info['field_name'],
);
$targets[$info['field_name'] . ':top'] = array(
'name' => t($instance['label'] . ' Top Longitude'),
'callback' => 'geofield_set_target_simple',
'real_target' => $info['field_name'],
);
$targets[$info['field_name'] . ':right'] = array(
'name' => t($instance['label'] . ' Right Latitude'),
'callback' => 'geofield_set_target_simple',
'real_target' => $info['field_name'],
);
$targets[$info['field_name'] . ':bottom'] = array(
'name' => t($instance['label'] . ' Bottom Longitude'),
'callback' => 'geofield_set_target_simple',
'real_target' => $info['field_name'],
);
$targets[$info['field_name'] . ':combined'] = array(
'name' => t($instance['label'] . ' (combined)'),
'callback' => 'geofield_set_target_combined',
'real_target' => $info['field_name'],
);
}
}
}
/**
* Example callback specified in hook_feeds_processor_targets_alter().
*
* @param $source
* Field mapper source settings.
* @param $entity
* An entity object, for instance a node object.
* @param $target
* A string identifying the target on the node.
* @param $value
* The value to populate the target with.
*
*/
function geofield_set_target_simple($source, $entity, $target, $value) {
list($field_name, $sub_field) = explode(':', $target, 2);
$entity->{$field_name}['und'][0][$sub_field] = $value;
}
/**
* Feeds processor target callback from the already combined source.
*
* @see geofield_feeds_parser_sources_alter()
*
* @param $source
* Field mapper source settings.
* @param $entity
* An entity object, for instance a node object.
* @param $target
* A string identifying the target on the node.
* @param $value
* The value to populate the target with.
*
*/
function geofield_set_target_combined($source, $entity, $target, $value) {
$field_name = substr($target, 0, strpos($target, ':'));
_geofield_set_target($source, $entity, $field_name, $value);
}
/**
* Feeds processor target callback for WKT source.
*/
function geofield_set_target_wkt($source, $entity, $target, $value) {
$field_name = substr($target, 0, strpos($target, ':'));
$geofield_values = array();
if (is_array($value)) {
foreach ($value as $key => $wkt) {
$field = array('wkt' => $wkt);
$geofield_values[] = geofield_compute_values($field, 'wkt');
}
}
else {
$field = array('wkt' => $value);
$geofield_values[] = geofield_compute_values($field, 'wkt');
}
_geofield_set_target($source, $entity, $field_name, $geofield_values);
}
/**
* Helper function to set values and respect ordinality of field.
*
* Based on _field_feeds_set_target(). But type set, more keys than just value.
*
* @param $source
* A FeedsSource object.
* @param $entity
* The entity to map to.
* @param $target
* The target key on $entity to map to.
* @param $value
* The value to map. MUST be an array.
*/
function _geofield_set_target($source, $entity, $target, $value) {
if (empty($value)) {
return;
}
$info = field_info_field($target);
// Iterate over all values.
$i = 0;
$field = isset($entity->$target) ? $entity->$target : array();
foreach ($value as $v) {
// Check if field value is empty.
if(empty($v)){
continue;
}
if (is_array($v) || is_object($v)) {
$field['und'][$i] = $v;
}
if ($info['cardinality'] == 1) {
break;
}
$i++;
}
$entity->{$target} = $field;
}

View File

@@ -0,0 +1,471 @@
<?php
/**
* @file
* Drupal field formatter hooks and helper functions.
*/
/**
* Implements hook_field_formatter_info().
*/
function geofield_field_formatter_info() {
$formatters = array(
'geofield_wkt' => array(
'label' => t('Well Known Text (WKT)'),
'field types' => array('geofield'),
'settings' => array('data' => 'full'),
),
'geofield_geojson' => array(
'label' => t('GeoJSON'),
'field types' => array('geofield'),
'settings' => array('data' => 'full'),
),
'geofield_kml' => array(
'label' => t('KML'),
'field types' => array('geofield'),
'settings' => array('data' => 'full'),
),
'geofield_gpx' => array(
'label' => t('GPX'),
'field types' => array('geofield'),
'settings' => array('data' => 'full'),
),
'geofield_latlon' => array(
'label' => t('Latitude/Longitude'),
'field types' => array('geofield'),
'settings' => array('data' => 'full', 'format' => 'decimal_degrees', 'labels' => 1),
),
'geofield_lat' => array(
'label' => t('Latitude Only'),
'field types' => array('geofield'),
'settings' => array('data' => 'full', 'format' => 'decimal_degrees'),
),
'geofield_lon' => array(
'label' => t('Longitude Only'),
'field types' => array('geofield'),
'settings' => array('data' => 'full', 'format' => 'decimal_degrees'),
),
'geofield_geo_type' => array(
'label' => t('Geometry Type'),
'field types' => array('geofield'),
'settings' => array('data' => 'full'),
),
);
if (module_exists('openlayers')) {
$formatters['geofield_openlayers'] = array(
'label' => t('OpenLayers'),
'field types' => array('geofield'),
'settings' => array('data' => 'full', 'map_preset' => 'geofield_formatter_map'),
);
}
// Accessibility formatters for blind users with screen-readers
$formatters['geofield_def_list'] = array(
'label' => t('Definition List (Accessibility)'),
'field types' => array('geofield'),
'settings' => array('data' => '', 'address' => 0),
);
$formatters['geofield_description'] = array(
'label' => t('Decriptive Text (Accessibility)'),
'field types' => array('geofield'),
'settings' => array('data' => '', 'address' => 0),
);
return $formatters;
}
/**
* Helper function for getting data options
*/
function _geofield_formatter_settings_data_options($formatter) {
return array(
'full' => t('Use full geometry'),
'centroid' => t('Use centroid'),
'bounding' => t('Use bounding box'),
);
}
/**
* Helper function for getting format options
*/
function _geofield_formatter_settings_format_options($formatter) {
return array(
'decimal_degrees' => t('Decimal degrees'),
'degrees_minutes_seconds' => t('Degrees minutes seconds'),
'ccs' => t('Astronomical Celestial Coordinates System (CCS)'),
);
}
/**
* Implements hook_field_formatter_settings_form().
*/
function geofield_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
// Map preset formatter
if ($display['type'] == 'geofield_openlayers' && module_exists('openlayers')) {
// Get preset options, filtered to those which have the GeoField placeholder layer
$presets = openlayers_presets();
$preset_options = array();
foreach ($presets as $preset) {
if (in_array('geofield_formatter', $preset->data['layers'])) {
$preset_options[$preset->name] = $preset->title;
}
}
$element['map_preset'] = array(
'#title' => t('OpenLayers Preset'),
'#type' => 'select',
'#default_value' => $settings['map_preset'] ? $settings['map_preset'] : 'geofield_formatter_map',
'#required' => TRUE,
'#options' => $preset_options,
'#description' => t('Select which OpenLayers map you would like to use. Only maps which have the geofield placeholder layer may be selected. If your preferred map is not here, add the geofield placeholder layer to it first.'),
);
}
$data_options = _geofield_formatter_settings_data_options($display['type']);
$element['data'] = array(
'#title' => t('Data options'),
'#type' => 'select',
'#default_value' => $settings['data'] ? $settings['data'] : 'full',
'#required' => TRUE,
'#options' => $data_options,
);
if ($display['type'] == 'geofield_latlon' || $display['type'] == 'geofield_lat' || $display['type'] == 'geofield_lon') {
$format_options = _geofield_formatter_settings_format_options($display['type']);
$element['format'] = array(
'#title' => t('Format'),
'#type' => 'select',
'#default_value' => $settings['format'] ? $settings['format'] : 'decimal_degrees',
'#required' => TRUE,
'#options' => $format_options,
);
}
if ($display['type'] == 'geofield_latlon') {
$element['labels'] = array(
'#title' => t('Display Labels'),
'#type' => 'checkbox',
'#default_value' => $settings['labels'],
);
}
if ($display['type'] == 'geofield_def_list' || $display['type'] == 'geofield_description') {
$element['address'] = array(
'#title' => t('Include reverse-geocoded address'),
'#type' => 'checkbox',
'#default_value' => $settings['address'],
);
}
return $element;
}
/**
* Implements hook_field_formatter_settings_summary().
*/
function geofield_field_formatter_settings_summary($field, $instance, $view_mode) {
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
$summary = array();
$data_options = _geofield_formatter_settings_data_options($display['type']);
// Styles could be lost because of enabled/disabled modules that defines
// their styles in code.
if (!empty($data_options[$settings['data']])) {
$summary[] = t('Data options: @data', array('@data' => $data_options[$settings['data']]));
}
else {
$summary[] = t('No data options set');
}
if ($display['type'] == 'geofield_openlayers' && !empty($settings['map_preset'])) {
$openlayers_presets = openlayers_preset_options();
$summary[] = t('Openlayers Map: @data', array('@data' => $openlayers_presets[$settings['map_preset']]));
}
if ($display['type'] == 'geofield_latlon') {
$format_options = _geofield_formatter_settings_format_options($display['type']);
// Display this setting only if image is linked.
if (isset($format_options[$settings['format']])) {
$summary[] = $format_options[$settings['format']];
}
}
if (!empty($settings['address']) && $settings['address']) {
$summary[] = t('Including reverse-geocoded address');
}
return implode('<br />', $summary);
}
/**
* Implements hook_field_formatter_view().
*/
function geofield_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
$element = array();
// Transform into centroid or bounding if needed
if ($display['settings']['data'] != 'full') {
geophp_load();
if ($display['settings']['data'] == 'centroid') {
foreach ($items as $delta => $item) {
$centroid_wkt = 'POINT(' . $item['lon'] . ' ' . $item['lat'] . ')';
$centroid = geoPHP::load($centroid_wkt, 'wkt');
$items[$delta] = geofield_get_values_from_geometry($centroid);
}
}
if ($display['settings']['data'] == 'bounding') {
foreach ($items as $delta => $item) {
$envelope_wkt = 'POLYGON ((' . $item['left'] . ' ' . $item['top'] . ', ' . $item['right'] . ' ' . $item['top'] . ', ' . $item['right'] . ' ' . $item['bottom'] . ', ' . $item['left'] . ' ' . $item['bottom'] . ', ' . $item['left'] . ' ' . $item['top'] . '))';
$envelope = geoPHP::load($envelope_wkt, 'wkt');
$items[$delta] = geofield_get_values_from_geometry($envelope);
}
}
}
// If we are a lat, lon, or latlon, and we are using degrees-minutes-seconds (instead of decimal degrees), then do a transformation
if (isset($display['settings']['format'])) {
if ($display['settings']['format'] == 'degrees_minutes_seconds') {
foreach ($items as $delta => $item) {
$items[$delta]['lat'] = geofield_latlon_DECtoDMS($item['lat'], 'lat');
$items[$delta]['lon'] = geofield_latlon_DECtoDMS($item['lon'], 'lon');
}
}
}
// If we are a lat, lon, or latlon, and we are using celestial coordinate system (instead of decimal degrees), then do a transformation
if (isset($display['settings']['format'])) {
if ($display['settings']['format'] == 'ccs') {
foreach ($items as $delta => $item) {
$items[$delta]['lat'] = geofield_latlon_DECtoCCS($item['lat'], 'lat');
$items[$delta]['lon'] = geofield_latlon_DECtoCCS($item['lon'], 'lon');
}
}
}
switch ($display['type']) {
case 'geofield_wkt':
foreach ($items as $delta => $item) {
$element[$delta] = array('#markup' => $item['wkt']);
}
return $element;
case 'geofield_geojson':
geophp_load();
foreach ($items as $delta => $item) {
$geometry = geoPHP::load($item['wkt'], 'wkt');
$json = $geometry->out('json');
$element[$delta] = array('#markup' => $json);
}
return $element;
case 'geofield_kml':
geophp_load();
foreach ($items as $delta => $item) {
$geometry = geoPHP::load($item['wkt'], 'wkt');
$kml = $geometry->out('kml');
$element[$delta] = array('#markup' => $kml);
}
return $element;
case 'geofield_gpx':
geophp_load();
foreach ($items as $delta => $item) {
$geometry = geoPHP::load($item['wkt'], 'wkt');
$kml = $geometry->out('gpx');
$element[$delta] = array('#markup' => $kml);
}
return $element;
case 'geofield_latlon':
foreach ($items as $delta => $item) {
if ($display['settings']['labels']) {
$output = t('Latitude: !latitude <br/>Longitude: !longitude', array('!latitude' => $item['lat'], '!longitude' => $item['lon']));
}
else {
$output = $item['lat'] . ', ' . $item['lon'];
}
$element[$delta] = array('#markup' => $output);
}
return $element;
case 'geofield_lat':
foreach ($items as $delta => $item) {
$element[$delta] = array('#markup' => $item['lat']);
}
return $element;
case 'geofield_lon':
foreach ($items as $delta => $item) {
$element[$delta] = array('#markup' => $item['lon']);
}
return $element;
case 'geofield_geo_type':
foreach ($items as $delta => $item) {
$element[$delta] = array('#markup' => $item['geo_type']);
}
return $element;
case 'geofield_openlayers':
$map_name = $display['settings']['map_preset'] ? $display['settings']['map_preset'] : 'geofield_formatter_map';
$element[0] = array('#markup' => _geofield_openlayers_formatter($map_name, $items));
return $element;
case 'geofield_def_list':
foreach ($items as $delta => $item) {
$element[$delta] = array('#markup' => _geofield_def_list_formatter($item, $display['settings']));
}
return $element;
case 'geofield_description':
foreach ($items as $delta => $item) {
$element[$delta] = array('#markup' => _geofield_description_formatter($item, $display['settings']));
}
return $element;
}
return $element;
}
function _geofield_openlayers_formatter($map_name, $items) {
$features = array();
// Create array of $features
foreach ($items as $delta) {
$features[] = array(
'wkt' => $delta['wkt'],
'projection' => '4326',
);
}
// Get map preset
$preset = openlayers_preset_load($map_name);
$map = openlayers_build_map($preset->data);
if (!isset($map['layers']['geofield_formatter'])) {
drupal_set_message(t('Trying to render a geofield formatter on a map without the placeholder layer'), 'error');
}
// Add the features to the placeholder layer
$map['layers']['geofield_formatter']['features'] = $features;
// Return themed map if no errors found
if (empty($map['errors'])) {
$js = array('openlayers' => array('maps' => array($map['id'] => $map)));
drupal_add_js($js, 'setting');
// Push map through theme function and return
$output = theme('openlayers_map', array(
'map' => $map,
'map_name' => $map_name
));
}
return $output;
}
function _geofield_def_list_formatter($item, $settings) {
geophp_load();
$geometry = geoPHP::load($item['wkt'], 'wkt');
// Single types
$single_types = array('Point', 'LineStrnig', 'Polygon');
if (in_array($geometry->geometryType(), $single_types)) {
$centroid = new Point($item['lon'], $item['lat']);
$info = _geofield_formatter_get_info($geometry, $centroid, $settings['address']);
return _geofield_def_list_formatter_dl($info);
}
else {
$output = '';
foreach ($geometry->getComponents() as $component) {
$centroid = $component->centroid();
$info = _geofield_formatter_get_info($component, $centroid, $settings['address']);
$output .= _geofield_def_list_formatter_dl($info);
}
return $output;
}
}
function _geofield_def_list_formatter_dl($info) {
$output = '<dl>';
foreach ($info as $dt => $dd) {
$output .= '<dt>' . drupal_ucfirst($dt) . '</dt><dd>' . $dd . '</dd>';
}
$output .= '</dl>';
return $output;
}
function _geofield_description_formatter($item, $settings) {
geophp_load();
$geometry = geoPHP::load($item['wkt'], 'wkt');
// Single types
$single_types = array('Point', 'LineString', 'Polygon');
if (in_array($geometry->geometryType(), $single_types)) {
$centroid = new Point($item['lon'], $item['lat']);
$info = _geofield_formatter_get_info($geometry, $centroid, $settings['address']);
return _geofield_description_formatter_text($info);
}
else {
$output = t('A collection of shapes');
$output .= '<ol>';
foreach ($geometry->getComponents() as $component) {
$centroid = $component->centroid();
$info = _geofield_formatter_get_info($component, $centroid, $settings['address']);
$output .= '<li>' . _geofield_description_formatter_text($info) . '</li>';
}
$output .= '</ol>';
return $output;
}
}
function _geofield_description_formatter_text($info) {
$text = t('@shape with a center of latitude @lat and longitude @lon.', array('@shape' => $info['shape'], '@lat' => $info['latitude'], '@lon' => $info['longitude']));
if (isset($info['address'])) {
$text .= ' ' . t('It has an approximate address of @address.', array('@address' => $info['address']));
}
if (isset($info['area'])) {
$text .= ' ' . t('It has an area of @area.', array('@area' => $info['area']));
}
if (isset($info['length'])) {
$text .= ' ' . t('It has a length of @length.', array('@length' => $info['length']));
}
return $text;
}
function _geofield_formatter_get_info($geometry, $centroid, $address = FALSE, $units = 'degrees') {
$info = array(
'latitude' => $centroid->y(),
'longitude' => $centroid->x(),
);
// Get the shape
if ($geometry->geometryType() == 'Point') {
$info['shape'] = 'Point';
}
if ($geometry->geometryType() == 'LineString') {
$info['shape'] = 'Line';
}
if ($geometry->geometryType() == 'Polygon') {
//@@TODO: Get more useful information like 'Triangle', 'Square', 'Rectangle', 'Pentagon'
$info['shape'] = 'Polygon';
}
if ($address) {
$info['address'] = $centroid->out('google_geocode');
}
//@@TODO, convert length and area to proper units
#if ($geometry->geometryType() == 'LineString') {
# $info['length'] = $geometry->length();
#}
#if ($geometry->geometryType() == 'Polygon') {
# $info['area'] = $geometry->area();
#}
return $info;
}

View File

@@ -0,0 +1,19 @@
name = Geofield
description = Stores geographic and location data (points, lines, and polygons).
core = 7.x
dependencies[] = geophp
package = Fields
files[] = geofield.module
files[] = geofield.install
files[] = geofield.widgets.inc
files[] = geofield.formatters.inc
files[] = geofield.openlayers.inc
files[] = geofield.feeds.inc
files[] = geofield.test
; Information added by drupal.org packaging script on 2012-09-03
version = "7.x-1.1+6-dev"
core = "7.x"
project = "geofield"
datestamp = "1346631868"

View File

@@ -0,0 +1,64 @@
<?php
/**
* @file
* Install, update and uninstall functions for the geofield module.
*/
/**
* Implements hook_field_schema().
*/
function geofield_field_schema($field) {
return array(
'columns' => array(
'wkt' => array(
'type' => 'text',
'size' => 'big',
'not null' => FALSE,
),
'geo_type' => array(
'type' => 'text',
'size' => 'normal',
'not null' => FALSE,
),
'lat' => array(
'type' => 'float',
'not null' => FALSE,
),
'lon' => array(
'type' => 'float',
'not null' => FALSE,
),
'left' => array(
'type' => 'float',
'not null' => FALSE,
),
'top' => array(
'type' => 'float',
'not null' => FALSE,
),
'right' => array(
'type' => 'float',
'not null' => FALSE,
),
'bottom' => array(
'type' => 'float',
'not null' => FALSE,
),
'srid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => FALSE,
'default' => 4326,
),
'accuracy' => array(
'type' => 'int',
'not null' => FALSE,
),
'source' => array(
'type' => 'text',
'not null' => FALSE,
),
),
);
}

View File

@@ -0,0 +1,11 @@
; $Id$
api = 2
core = 7.x
projects[] = libraries
libraries[geophp][download][type] = "get"
libraries[geophp][download][url] = "https://github.com/downloads/phayes/geoPHP/geophp.tar.gz"
libraries[geophp][directory_name] = "geoPHP"
libraries[geophp][destination] = "libraries"

View File

@@ -0,0 +1,551 @@
<?php
require_once('geofield.widgets.inc');
require_once('geofield.formatters.inc');
require_once('geofield.openlayers.inc');
require_once('geofield.feeds.inc');
/**
* Implements hook_field_info().
*/
function geofield_field_info() {
return array(
'geofield' => array(
'label' => 'Geofield',
'description' => t('This field stores geo information.'),
'default_widget' => 'geofield_wkt',
'default_formatter' => 'geofield_wkt',
'instance_settings' => array(
'local_solr' => array(
'enabled' => FALSE,
'lat_field' => 'lat',
'lng_field' => 'lng',
),
),
'property_type' => 'geofield',
'property_callbacks' => array('geofield_property_info_callback'),
),
);
}
/**
* Implements hook_field_presave().
* PDO throws an error when attempting to insert an empty string into a float
* field. Go through all values and convert empty strings to NULL.
*/
function geofield_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
if ($field['type'] === 'geofield') {
foreach ($items as $delta => $item) {
if (!empty($item)) {
foreach ($item as $k => $v) {
if ($v === '') {
$item[$k] = NULL;
}
}
$widget = $instance['widget'];
if ($widget['type'] == 'geofield_wkt') {
$master_column = 'wkt';
}
elseif ($widget['type'] == 'geofield_latlon') {
$master_column = 'latlon';
}
elseif ($widget['type'] == 'geofield_bounds') {
$master_column = 'bounds';
}
elseif ($widget['type'] == 'geofield_geolocation') {
$master_column = 'latlon';
}
else {
$master_column = 'wkt';
}
$item += array('master_column' => $master_column);
geofield_compute_values($item, $item['master_column']);
$items[$delta] = $item;
}
}
}
}
/**
* Implements hook_field_is_empty().
*/
function geofield_field_is_empty($item, $field) {
// TODO: This is ugly. Please fix.
if (!empty($item['master_column'])) {
switch ($item['master_column']) {
case 'wkt';
return (empty($item['wkt']));
case 'latlon':
return (empty($item['lat']) && empty($item['lon']));
case 'bounds':
return (empty($item['left']) && empty($item['right']) && empty($item['top']) && empty($item['bottom']));
}
}
else {
return (empty($item['wkt']));
}
}
/**
* Implements hook_view_api().
*/
function geofield_views_api() {
return array(
'api' => '3.0-alpha1',
'path' => drupal_get_path('module', 'geofield') . '/views',
);
}
/**
* Implements hook_ctools_plugin_type().
*/
function geofield_ctools_plugin_type() {
return array(
'behaviors' => array(
'use hooks' => TRUE,
)
);
}
/**
* Implements hook_ctools_plugin_api().
*/
function geofield_ctools_plugin_api($module, $api) {
return array('version' => 1);
}
/**
* Implements hook_field_instance_settings_form().
*/
function geofield_field_instance_settings_form($field, $instance) {
$form = array();
// Add in local solr settings
if (module_exists('apachesolr')) {
if (isset($instance['settings']['solrspatial'])) $setting = $instance['settings']['solrspatial'];
else $setting = array();
$form['solrspatial'] = array(
'#type' => 'fieldset',
'#title' => t('Local Solr Settings'),
'#tree' => TRUE,
);
$form['solrspatial']['enabled'] = array(
'#type' => 'checkbox',
'#title' => t('Index field in Solr for spatial search'),
'#default_value' => isset($setting['enabled']) ? $setting['enabled'] : '',
);
$form['solrspatial']['lat_field'] = array(
'#type' => 'textfield',
'#title' => t('Name of the Solr Latitude Field'),
'#default_value' => isset($setting['lat_field']) ? $setting['lat_field'] : '',
);
$form['solrspatial']['lng_field'] = array(
'#type' => 'textfield',
'#title' => t('Name of the Solr Lonitude Field'),
'#default_value' => isset($setting['lng_field']) ? $setting['lng_field'] : '',
);
$form['solrspatial']['latlng_field'] = array(
'#type' => 'textfield',
'#title' => t('Name of the Solr LatLon Field'),
'#default_value' => isset($setting['latlng_field']) ? $setting['latlng_field'] : '',
);
}
return $form;
}
/**
* Geofield Compute Values
*
* Compute all dependant values. We compute all other values from whichever
* column is specified in the master_column value
*
* Steps:
* 1. Load the geoPHP library
* 2. Load the Geometry object from the master-column
* 3. Get out all the computer values from the Geometry object
* 4. Set all the values
*
* Allowed values for master_column are wkt, latlon, bounds
*/
function geofield_compute_values(&$values, $master_column = 'wkt') {
// If only a wkt string has been passed in, then format it correctly by wrapping it in an array
if ($master_column == 'wkt' && !is_array($values)) {
$values = array('wkt' => $values);
}
// Load up geoPHP to do the conversions
$geophp = geophp_load();
if (!$geophp) {
drupal_set_message(t("Unable to load geoPHP library. Not all values will be calculated correctly"), 'error');
return;
}
// Load up the geometry object from the master-column data
if ($master_column == 'wkt') {
$wkt = $values['wkt'];
if ($wkt) {
$geometry = geoPHP::load($wkt, 'wkt');
}
}
if ($master_column == 'latlon') {
$lat = $values['lat'];
$lon = $values['lon'];
if (is_numeric($lat) && is_numeric($lon)) {
$geometry = new Point(floatval($lon), floatval($lat));
}
}
if ($master_column == 'bounds') {
$top = $values['top'];
$bottom = $values['bottom'];
$right = $values['right'];
$left = $values['left'];
if (is_numeric($top) && is_numeric($bottom) && is_numeric($right) && is_numeric($left)) {
$wkt_bounds_format = 'POLYGON((left bottom,right bottom,right top,left top,left bottom))';
$wkt = strtr($wkt_bounds_format, array('top' => $top, 'bottom' => $bottom, 'right' => $right, 'left' => $left));
$geometry = geoPHP::load($wkt, 'wkt');
}
}
// Get values from geometry
if (isset($geometry)) {
$values = geofield_get_values_from_geometry($geometry);
}
else {
$values = array();
}
return $values;
}
/**
* Given a geometry object from geoPHP, return a values array
*/
function geofield_get_values_from_geometry($geometry) {
$centroid = $geometry->getCentroid();
$bounding = $geometry->getBBox();
$values['wkt'] = $geometry->out('wkt');
$values['geo_type'] = drupal_strtolower($geometry->getGeomType());
$values['lat'] = $centroid->getY();
$values['lon'] = $centroid->getX();
$values['top'] = $bounding['maxy'];
$values['bottom'] = $bounding['miny'];
$values['right'] = $bounding['maxx'];
$values['left'] = $bounding['minx'];
return $values;
}
/**
* Implements hook_apachesolr_field_mappings().
*/
function geofield_apachesolr_field_mappings() {
return array(
'geofield' => array(
'indexing_callback' => 'geofield_apachesolr_index',
'facets' => TRUE,
)
);
}
/**
* Name callback for field name
*/
function geofield_apachesolr_index($node, $field_name, $index_key, $field_info) {
$return = array();
if (isset($node->$field_name)) {
// Load the instance settings for the field
$instance = field_info_instance('node', $field_name, $node->type);
if (!empty($instance['settings']['solrspatial'])) {
if ($values = field_get_items('node', $node, $field_name)) {
$values = reset($values);
$return = array(
array(
'key' => $instance['settings']['solrspatial']['lat_field'],
'value' => $values['lat']
),
array(
'key' => $instance['settings']['solrspatial']['lng_field'],
'value' => $values['lon']
),
array(
'key' => $instance['settings']['solrspatial']['latlng_field'],
'value' => $values['lat'] . ',' . $values['lon']
),
array(
'key' => 'ss_geo_wkt',
'value' => $values['wkt'],
),
);
}
}
}
return $return;
}
/**
* Implements hook_apachesolr_query_alter()
*/
function geofield_apachesolr_query_alter($query) {
// Add the WKT field field
$query->addParam('fl', 'ss_geo_wkt');
}
// Latitude and Longitude string conversion
// ----------------------------------------
/**
* Decimal-Degrees-Seconds to Decimal Degrees
*
* Converts string to decimal degrees. Has some error correction for messy strings
*/
function geofield_latlon_DMStoDEC($dms) {
if (is_numeric($dms)) {
// It's already decimal degrees, just return it
return $dms;
}
// If it contains both an H and M, then it's an angular hours
if (stripos($dms, 'H') !== FALSE && stripos($dms, 'M') !== FALSE) {
$dms = strtr($dms, "'\"HOURSMINTECNDAhoursmintecnda", " ");
$dms = preg_replace('/\s\s+/', ' ', $dms);
$dms = explode(" ", $dms);
$deg = $dms[0];
$min = $dms[1];
$sec = $dms[2];
$dec = floatval(($deg*15) + ($min/4) + ($sec/240));
return $dec;
}
// If it contains an S or a W, then it's a negative
if (stripos($dms, 'S') !== FALSE || stripos($dms, 'W') !== FALSE) {
$direction = -1;
}
else {
$direction = 1;
}
// Strip all characters and replace them with empty space
$dms = strtr($dms, "<22>'\"NORTHSEAWnorthseaw'", " ");
$dms = preg_replace('/\s\s+/', ' ', $dms);
$dms = explode(" ", $dms);
$deg = $dms[0];
$min = $dms[1];
$sec = $dms[2];
// Direction should be checked only for nonnegative coordinates
$dec = floatval($deg+((($min*60)+($sec))/3600));
if ($dec > 0) {
$dec = $direction * $dec;
}
return $dec;
}
/**
* Decimal Degrees to Decimal-Degrees-Seconds
*
* Converts decimal longitude / latitude to DMS ( Degrees / minutes / seconds )
*/
function geofield_latlon_DECtoDMS($dec, $axis) {
if ($axis == 'lat') {
if ($dec < 0) $direction = 'S';
else $direction = 'N';
}
if ($axis == 'lon') {
if ($dec < 0) $direction = 'W';
else $direction = 'E';
}
$vars = explode(".", $dec);
$deg = abs($vars[0]);
if (isset($vars[1])) {
$tempma = "0." . $vars[1];
}
else {
$tempma = "0";
}
$tempma = $tempma * 3600;
$min = floor($tempma / 60);
$sec = $tempma - ($min*60);
return $deg . "&deg; " . $min . "' " . round($sec, 3) . "\" " . $direction;
}
/**
* Decimal Degrees to Celestial coordinate system (CCS) units
*
* Converts decimal latitude to DMS ( Degrees / minutes / seconds ) and decimal longitude to Angular Hours / Minutes / Seconds
*/
function geofield_latlon_DECtoCCS($dec, $axis) {
// Declination (celestial latitude) should be representeted in Degrees / minutes / seconds
if ($axis == 'lat') {
$vars = explode("." , $dec);
$deg = $vars[0];
if (isset($vars[1])) {
$tempma = "0." . $vars[1];
}
else {
$tempma = "0";
}
$tempma = $tempma * 3600;
$min = floor($tempma / 60);
$sec = $tempma - ($min*60);
return $deg . "&deg; " . $min . "' " . round($sec, 3) . "\"";
}
// Right ascension (celestial longitude) should be representeted in Hours / Minutes / Seconds
if ($axis == 'lon') {
$tempma = $dec / 15;
$vars = explode(".", $tempma);
$hrs = $vars[0];
if (isset($vars[1])) {
$tempma = "0." . $vars[1];
}
else {
$tempma = "0";
}
$tempma = $tempma * 60;
$vars = explode(".", $tempma);
$min = $vars[0];
if (isset($vars[1])) {
$tempma = "0." . $vars[1];
}
else {
$tempma = "0";
}
$sec = $tempma * 60;
return $hrs . "h " . $min . "m " . round($sec, 3) . "s";
}
}
/**
* Callback to alter the property info of geofield fields.
*
* @see geofield_field_info().
*/
function geofield_property_info_callback(&$info, $entity_type, $field, $instance, $field_type) {
$name = $field['field_name'];
$property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$name];
$property['type'] = ($field['cardinality'] != 1) ? 'list<geofield>' : 'geofield';
$property['getter callback'] = 'entity_metadata_field_verbatim_get';
$property['setter callback'] = 'entity_metadata_field_verbatim_set';
// $property['auto creation'] = 'geofield_default_values';
$property['property info'] = geofield_data_property_info('Geofield');
unset($property['query callback']);
}
/**
* Defines info for the properties of the geofield field data structure.
*/
function geofield_data_property_info($name = NULL) {
// Build an array of basic property information for the geofield field.
$properties = array(
'wkt' => array(
'label' => 'Well-known text',
'type' => 'text',
),
'geo_type' => array(
'label' => 'Geo Type',
'options list' => '_geofield_geo_types_options_callback',
'required' => TRUE,
),
'lat' => array(
'label' => 'Latitude',
'type' => 'decimal',
'required' => TRUE,
'setter callback' => 'entity_property_verbatim_set',
),
'lon' => array(
'label' => 'Longitude',
'type' => 'decimal',
'required' => TRUE,
'setter callback' => 'entity_property_verbatim_set',
),
'left' => array(
'label' => 'Left Latitude',
'type' => 'decimal',
'setter callback' => 'entity_property_verbatim_set',
),
'top' => array(
'label' => 'Top Longitude',
'type' => 'decimal',
'setter callback' => 'entity_property_verbatim_set',
),
'right' => array(
'label' => 'Right Latitude',
'type' => 'decimal',
'setter callback' => 'entity_property_verbatim_set',
),
'bottom' => array(
'label' => 'Bottom Longitude',
'type' => 'decimal',
'setter callback' => 'entity_property_verbatim_set',
),
'srid' => array(
'label' => 'Projection (SRID)',
'type' => 'integer'
),
'latlon' => array(
'label' => 'LatLong Pair',
'type' => 'string',
'getter callback' => 'geofield_return_latlon',
),
);
// Add the default values for each of the geofield properties.
foreach ($properties as $key => &$value) {
$value += array(
'description' => !empty($name) ? t('!label of field %name', array('!label' => $value['label'], '%name' => $name)) : '',
'getter callback' => 'entity_property_verbatim_get',
);
}
return $properties;
}
function _geofield_geo_types_options_callback() {
$geophp = geophp_load();
if (!$geophp) {
return;
}
return geoPHP::geometryList();
}
/**
* Gets the a latlong property.
*/
function geofield_return_latlon($data, array $options, $name) {
if ((is_array($data) || (is_object($data) && $data instanceof ArrayAccess))) {
return $data['lat'] . ',' . $data['lon'];
}
return NULL;
}

View File

@@ -0,0 +1,201 @@
<?php
/**
* @file
* Provides hooks for integration with OpenLayers (http://drupal.org/project/openlayers)
*/
/**
* Implements hook_openlayers_maps().
*/
function geofield_openlayers_maps() {
// Create full preset array
$widget = new stdClass;
$widget->disabled = FALSE; /* Edit this to true to make a default openlayers_maps disabled initially */
$widget->api_version = 1;
$widget->name = 'geofield_widget_map';
$widget->title = 'Geofield Widget Map';
$widget->description = 'A Map Used for Geofield Input';
$widget->data = array(
'width' => '600px',
'height' => '400px',
'image_path' => drupal_get_path('module', 'openlayers') . '/themes/default_dark/img/',
'css_path' => drupal_get_path('module', 'openlayers') . '/themes/default_dark/style.css',
'proxy_host' => '',
'hide_empty_map' => 0,
'center' => array(
'initial' => array(
'centerpoint' => '0, 0',
'zoom' => '1',
),
'restrict' => array(
'restrictextent' => 0,
'restrictedExtent' => '',
),
),
'behaviors' => array(
'openlayers_behavior_geofield' => array(
'feature_types' => array(
'point' => 'point',
'path' => 'path',
'polygon' => 'polygon',
),
'allow_edit' => 1,
),
'openlayers_behavior_keyboarddefaults' => array(),
'openlayers_behavior_navigation' => array(
'zoomWheelEnabled' => 0,
'zoomBoxEnabled' => 1,
'documentDrag' => 0,
),
'openlayers_behavior_panzoombar' => array(
'zoomWorldIcon' => 0,
'panIcons' => 1,
),
),
'default_layer' => 'mapquest_osm',
'layers' => array(
'mapquest_osm' => 'mapquest_osm',
),
'layer_weight' => array(
'openlayers_geojson_picture_this' => '0',
'geofield_formatter' => '0',
),
'layer_styles' => array(
'geofield_formatter' => '0',
'openlayers_geojson_picture_this' => '0',
),
'layer_styles_select' => array(
'geofield_formatter' => '0',
'openlayers_geojson_picture_this' => '0',
),
'layer_activated' => array(
'geofield_formatter' => 0,
'openlayers_geojson_picture_this' => 0,
),
'layer_switcher' => array(
'geofield_formatter' => 0,
'openlayers_geojson_picture_this' => 0,
),
'projection' => '900913',
'displayProjection' => '4326',
'styles' => array(
'default' => 'default',
'select' => 'default',
'temporary' => 'default',
),
'map_name' => 'geofield_widget_map',
);
$formatter = new stdClass();
$formatter->api_version = 1;
$formatter->name = 'geofield_formatter_map';
$formatter->title = t('Geofield Formatter Map');
$formatter->description = t('A Map Used for Geofield Output');
$formatter->data = array(
'width' => '600px',
'height' => '400px',
'image_path' => drupal_get_path('module', 'openlayers') . '/themes/default_dark/img/',
'css_path' => drupal_get_path('module', 'openlayers') . '/themes/default_dark/style.css',
'proxy_host' => '',
'hide_empty_map' => 0,
'center' => array(
'initial' => array(
'centerpoint' => '0, 0',
'zoom' => '1',
),
'restrict' => array(
'restrictextent' => 0,
'restrictedExtent' => '',
),
),
'behaviors' => array(
'openlayers_behavior_keyboarddefaults' => array(),
'openlayers_behavior_navigation' => array(
'zoomWheelEnabled' => 0,
'zoomBoxEnabled' => 1,
'documentDrag' => 0,
),
'openlayers_behavior_panzoombar' => array(
'zoomWorldIcon' => 0,
'panIcons' => 1,
),
),
'default_layer' => 'mapquest_osm',
'layers' => array(
'mapquest_osm' => 'mapquest_osm',
'geofield_formatter' => 'geofield_formatter',
),
'layer_weight' => array(
'geofield_formatter' => '0',
'openlayers_geojson_picture_this' => '0',
),
'layer_styles' => array(
'openlayers_geojson_picture_this' => '0',
'geofield_formatter' => '0',
),
'layer_styles_select' => array(
'openlayers_geojson_picture_this' => '0',
'geofield_formatter' => '0',
),
'layer_activated' => array(
'geofield_formatter' => 'geofield_formatter',
'openlayers_geojson_picture_this' => 0,
),
'layer_switcher' => array(
'geofield_formatter' => 0,
'openlayers_geojson_picture_this' => 0,
),
'projection' => '900913',
'displayProjection' => '4326',
'styles' => array(
'default' => 'default',
'select' => 'default',
'temporary' => 'default',
),
'map_name' => 'geofield_formatter_map',
);
return array(
'geofield_widget_map' => $widget,
'geofield_formatter_map' => $formatter,
);
}
/**
* Implements hook_openlayers_behaviors().
*/
function geofield_openlayers_behaviors() {
return array(
'openlayers_behavior_geofield' => array(
'title' => t('Geofield'),
'description' => t('Fuels the geofield map-input form.'),
'type' => 'layer',
'behavior' => array(
'path' => drupal_get_path('module', 'geofield') . '/includes/behaviors',
'file' => 'openlayers_behavior_geofield.inc',
'class' => 'openlayers_behavior_geofield',
'parent' => 'openlayers_behavior',
),
),
);
}
/**
* Formatter layers
*/
function geofield_openlayers_layers() {
$layers = array();
$layer = new stdClass();
$layer->api_version = 1;
$layer->name = 'geofield_formatter';
$layer->title = 'Placeholder for Geofield Formatter';
$layer->description = '';
$layer->data = array(
'layer_type' => 'openlayers_layer_type_raw',
'projection' => array('900913'),
'features' => array()
);
$layers[$layer->name] = $layer;
return $layers;
}

View File

@@ -0,0 +1,67 @@
<?php
/**
* @file
* Tests for geofield.module.
*/
class GeoFieldTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'Geofield',
'description' => "Test the creation of geofields.",
'group' => 'Field types'
);
}
function setUp() {
parent::setUp(array('geofield', 'field_test'));
$this->admin_user = $this->drupalCreateUser(array('administer filters'));
$this->web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content', 'administer modules'));
$this->drupalLogin($this->web_user);
}
// Test fields.
/**
* Test widgets.
*/
function testGeofieldWidgets() {
$this->_testGeofieldWidgets('geofield_wkt');
}
/**
* Helper function for testGeofieldWidgets().
*/
function _testGeofieldWidgets($widget_type) {
// Setup a field and instance
$entity_type = 'test_entity';
$this->field_name = drupal_strtolower($this->randomName());
$this->field = array('field_name' => $this->field_name, 'type' => 'geofield');
field_create_field($this->field);
$this->instance = array(
'field_name' => $this->field_name,
'entity_type' => 'test_entity',
'bundle' => 'test_bundle',
'label' => $this->randomName() . '_label',
'settings' => array(
),
'widget' => array(
'type' => $widget_type,
),
'display' => array(
'full' => array(
'type' => 'geofield_wkt',
),
),
);
field_create_instance($this->instance);
$langcode = LANGUAGE_NONE;
// Display creation form.
$this->drupalGet('test-entity/add/test-bundle');
$this->assertFieldByName("{$this->field_name}[$langcode][0][wkt]", '', t('Widget is displayed'));
}
}

View File

@@ -0,0 +1,371 @@
<?php
/**
* @file
* Provides field widget hooks for geofield module.
*/
/**
* Implements hook_field_widget_info().
*/
function geofield_field_widget_info() {
$widgets = array();
// OpenLayers dependant widget
if (module_exists('openlayers')) {
$widgets['geofield_openlayers'] = array(
'label' => t('Openlayers Map'),
'field types' => array('geofield'),
);
}
$widgets['geofield_wkt'] = array(
'label' => t('Well Known Text (WKT)'),
'field types' => array('geofield'),
);
$widgets['geofield_geojson'] = array(
'label' => t('GeoJSON'),
'field types' => array('geofield'),
);
$widgets['geofield_latlon'] = array(
'label' => t('Latitude / Longitude'),
'field types' => array('geofield'),
);
$widgets['geofield_bounds'] = array(
'label' => t('Bounds'),
'field types' => array('geofield'),
);
$widgets['geofield_textfields'] = array(
'label' => t('All Textfields'),
'field types' => array('geofield'),
);
$widgets['geofield_geolocation'] = array(
'label' => 'HTML5 Geolocation',
'field types' => array('geofield'),
);
return $widgets;
}
/**
* Implements hook_field_widget_settings_form().
*/
function geofield_field_widget_settings_form($field, $instance) {
$widget = $instance['widget'];
$settings = $widget['settings'];
$form = array();
//TODO: Allow more fine-grained control
if ($widget['type'] == 'geofield_openlayers') {
// Get preset options, filtered to those which have the GeoField behavior and *don't* have the draw features behavior, which is incompatible
$maps = openlayers_maps();
$map_options = array();
foreach ($maps as $map) {
if (array_key_exists('openlayers_behavior_geofield', $map->data['behaviors']) && !array_key_exists('openlayers_behavior_drawfeatures', $map->data['behaviors'])) {
$map_options[$map->name] = $map->title;
}
}
if (empty($map_options)) {
form_set_error('openlayers_map', "Error: You have no compatible openlayers maps. Make sure that at least one preset has the 'GeoField' behavior enabled and that it does not have the 'Draw Features' behavior enabled (which is incompatible).");
}
$form['openlayers_map'] = array(
'#type' => 'select',
'#title' => t('OpenLayers Map'),
'#default_value' => isset($settings['openlayers_map']) ? $settings['openlayers_map'] : 'geofield_widget_map',
'#options' => $map_options,
'#description' => t('Select which OpenLayers map you would like to use. Only maps which have the GeoField behavior may be selected. If your preferred map is not here, add the GeoField behavior to it first. The "Draw Features" bahavior is incompatible - presets with this behavior are not shown.'),
);
$form['data_storage'] = array(
'#type' => 'radios',
'#title' => t('Storage Options'),
'#description' => t('Should the widget only allow simple features (points, lines, or polygons), or should the widget allow for complex features? Note that changing this setting from complex to simple after data has been entered can lead to data loss.'),
'#options' => array(
'collection' => 'Store as a single collection.',
'single' => 'Store each simple feature as a separate field.',
),
'#default_value' => (isset($settings['data_storage'])) ? $settings['data_storage'] : 'collection',
);
}
return $form;
}
/**
* Implements hook_field_widget_form().
*/
function geofield_field_widget_form(&$form, &$form_state, $field, $instance,
$langcode, $items, $delta, $base) {
$widget = $instance['widget'];
$settings = $widget['settings'];
$element = geofield_get_base_element($base, $items, $delta);
if ($widget['type'] == 'geofield_wkt') {
$element['wkt']['#title'] = 'Well Known Text';
$element['wkt']['#type'] = 'textarea';
$element['master_column']['#value'] = 'wkt';
}
if ($widget['type'] == 'geofield_geojson') {
$element['wkt']['#title'] = 'GeoJSON';
$element['wkt']['#type'] = 'textarea';
// We're actually displaying as GeoJSON, not wkt. This is confusing.
geophp_load();
$default_value = '';
try {
$wkt = isset($items[$delta]['wkt']) ? $items[$delta]['wkt'] : NULL;
$geometry = geoPHP::load($wkt, 'wkt');
if ($geometry) {
$default_value = $geometry->out('json');
}
} catch (Exception $e) {
// @TODO: Not sure if we should do validation here or not...
}
$element['wkt']['#default_value'] = $default_value;
$element['master_column']['#value'] = 'wkt';
$element['input_format']['#value'] = 'geojson';
}
if ($widget['type'] == 'geofield_latlon') {
$element['lat']['#title'] = 'Latitude';
$element['lat']['#type'] = 'textfield';
$element['lon']['#title'] = 'Longitude';
$element['lon']['#type'] = 'textfield';
$element['master_column']['#value'] = 'latlon';
}
if ($widget['type'] == 'geofield_bounds') {
$element['left']['#title'] = 'Left Longitude';
$element['left']['#type'] = 'textfield';
$element['top']['#title'] = 'Top Latitude';
$element['top']['#type'] = 'textfield';
$element['right']['#title'] = 'Right Longitude';
$element['right']['#type'] = 'textfield';
$element['bottom']['#title'] = 'Bottom Latitude';
$element['bottom']['#type'] = 'textfield';
$element['master_column']['#value'] = 'bounds';
}
if ($widget['type'] == 'geofield_textfields') {
$element['wkt']['#title'] = 'Well Known Text';
$element['wkt']['#type'] = 'textarea';
$element['geo_type']['#title'] = 'Geometry Type';
$element['geo_type']['#type'] = 'textfield';
$element['lat']['#title'] = 'Latitude';
$element['lat']['#type'] = 'textfield';
$element['lon']['#title'] = 'Longitude';
$element['lon']['#type'] = 'textfield';
$element['left']['#title'] = 'Left Longitude';
$element['left']['#type'] = 'textfield';
$element['top']['#title'] = 'Top Latitude';
$element['top']['#type'] = 'textfield';
$element['right']['#title'] = 'Right Longitude';
$element['right']['#type'] = 'textfield';
$element['bottom']['#title'] = 'Bottom Latitude';
$element['bottom']['#type'] = 'textfield';
}
if ($widget['type'] == 'geofield_geolocation') {
$element['#attached']['js'][] = drupal_get_path('module', 'geofield') . '/js/geolocation.js';
$element['lat']['#title'] = 'Latitude';
$element['lat']['#type'] = 'textfield';
$element['lon']['#title'] = 'Longitude';
$element['lon']['#type'] = 'textfield';
$element['master_column']['#value'] = 'latlon';
}
if ($widget['type'] == 'geofield_openlayers') {
$openlayers_map_id = !empty($instance['widget']['settings']['openlayers_map']) ? $instance['widget']['settings']['openlayers_map'] : 'geofield_widget_map';
$element['#openlayers_mapname'] = $openlayers_map_id;
$element['#after_build']= array('geofield_widget_openlayers_afterbuild');
}
return $element;
}
/**
* Callback for afterbuild for widget for js addition to
*/
function geofield_widget_openlayers_afterbuild($element, &$form_state) {
drupal_add_js(
array('geofield' => array(
'data_storage' => (!empty($settings['data_storage'])) ? $settings['data_storage'] : 'collection',
),
),
'setting');
$defaults = array();
$element['helpmap'] = array(
'#markup' => '<div class="form-item geotaxonomy-latlon-helpmap" style="display:block">'
. geofield_form_latlon_map(array(), $element['#openlayers_mapname'])
. '</div>');
$element['helpmap_desc'] = array(
'#markup' => t('<div class="description geofield-help">Use the icons to select what type of feature to draw. Each map can contain one simple feature. Pan and zoom with arrows and the zoom bar.</div>')
);
return $element;
}
/**
* Create LatLon Helper Map.
*/
function geofield_form_latlon_map($defaults = array(), $map_name) {
// Pass variables etc. to javascript
// Set up our map to help set lat and lon
// This map will always be projected as 4326 and use just the default map preset
$map_data = openlayers_map_load($map_name);
$map = $map_data->data;
return openlayers_render_map($map);
}
function geofield_get_base_element($base, $items, $delta) {
$element = $base;
// @TODO: Change this to be generic, so that we don't have poor DX to input as WKT.
$element['wkt'] = array(
'#type' => 'hidden',
'#attributes' => array('class' => array('geofield_wkt')),
'#default_value' => isset($items[$delta]['wkt']) ? $items[$delta]['wkt'] : NULL,
);
$element['input_format'] = array(
'#type' => 'value',
'#attributes' => array('class' => array('geofield_input_format')),
'#value' => 'wkt',
);
$element['geo_type'] = array(
'#type' => 'hidden',
'#attributes' => array('class' => array('geofield_geo_type')),
'#default_value' => isset($items[$delta]['geo_type']) ? $items[$delta]['geo_type'] : NULL,
);
$element['lat'] = array(
'#type' => 'hidden',
'#attributes' => array('class' => array('geofield_lat')),
'#default_value' => isset($items[$delta]['lat']) ? $items[$delta]['lat'] : NULL,
);
$element['lon'] = array(
'#type' => 'hidden',
'#attributes' => array('class' => array('geofield_lon')),
'#default_value' => isset($items[$delta]['lon']) ? $items[$delta]['lon'] : NULL,
);
$element['left'] = array(
'#type' => 'hidden',
'#attributes' => array('class' => array('geofield_left')),
'#default_value' => isset($items[$delta]['left']) ? $items[$delta]['left'] : NULL,
);
$element['right'] = array(
'#type' => 'hidden',
'#attributes' => array('class' => array('geofield_right')),
'#default_value' => isset($items[$delta]['right']) ? $items[$delta]['right'] : NULL,
);
$element['bottom'] = array(
'#type' => 'hidden',
'#attributes' => array('class' => array('geofield_bottom')),
'#default_value' => isset($items[$delta]['bottom']) ? $items[$delta]['bottom'] : NULL,
);
$element['top'] = array(
'#type' => 'hidden',
'#attributes' => array('class' => array('geofield_top')),
'#default_value' => isset($items[$delta]['top']) ? $items[$delta]['top'] : NULL,
);
$element['description'] = array(
'#markup' => (!empty($element['#description'])) ? '<div class="description">' . $element['#description'] . '</div>' : '',
);
// Master column is used by element-validate to decide which set of columns it should use to compute all other values.
// By default, wkt is the master-column, all we compute all other values from it. For other widget (such as lat/lon) this will be different
$element['master_column'] = array(
'#type' => 'hidden',
'#value' => 'wkt',
);
// This validate function computes all other columns from the master field
$element['#element_validate'] = array('geofield_element_validate');
return $element;
}
/**
* Geofield Element Validate for GeoJSON widget
*/
function geofield_element_geojson_validate($element, &$form_state) {
}
/**
* Geofield Element Validate
*
*/
function geofield_element_validate($element, &$form_state) {
$master_column = $element['master_column']['#value'];
$values = array(
'wkt' => $element['wkt']['#value'],
'lat' => $element['lat']['#value'] ? geofield_latlon_DMStoDEC($element['lat']['#value']) : '',
'lon' => $element['lon']['#value'] ? geofield_latlon_DMStoDEC($element['lon']['#value']) : '',
'top' => $element['top']['#value'],
'bottom' => $element['bottom']['#value'],
'right' => $element['right']['#value'],
'left' => $element['left']['#value'],
);
// Because we have an odd flow to filter potential GeoJSON, we need a flag to determine whether or not to process.
// @TODO: This could be expanded to cover WKT as well.
$geo_process = "PROCESS";
if ($element['input_format']['#value'] == 'geojson' && $values['wkt']) {
// For geojson input, we've hijacked the wkt value.
geophp_load();
try {
$geometry = geoPHP::load($values['wkt'], 'json');
$values['wkt'] = $geometry->out('wkt');
} catch (Exception $e) {
form_set_error($element['wkt']['#name'], 'Please enter valid GeoJSON');
$geo_process = '';
}
}
if ($geo_process == "PROCESS") {
geofield_compute_values($values, $master_column);
// Set form values from the $values array
if (isset($values['wkt'])) form_set_value($element['wkt'], $values['wkt'], $form_state);
if (isset($values['geo_type'])) form_set_value($element['geo_type'], $values['geo_type'], $form_state);
if (isset($values['lat'])) form_set_value($element['lat'], $values['lat'], $form_state);
if (isset($values['lon'])) form_set_value($element['lon'], $values['lon'], $form_state);
if (isset($values['top'])) form_set_value($element['top'], $values['top'], $form_state);
if (isset($values['bottom'])) form_set_value($element['bottom'], $values['bottom'], $form_state);
if (isset($values['right'])) form_set_value($element['right'], $values['right'], $form_state);
if (isset($values['left'])) form_set_value($element['left'], $values['left'], $form_state);
}
}

View File

@@ -0,0 +1,12 @@
/**
* @file
* CSS for OpenLayers Draw Features Behavior
*/
.olControlEditingToolbar .olControlModifyFeatureItemActive {
background-position: -0px -23px;
}
.olControlEditingToolbar .olControlModifyFeatureItemInactive {
background-position: -0px -0px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 B

View File

@@ -0,0 +1,185 @@
/**
* @file
* JS Implementation of OpenLayers behavior.
*/
/**
* Class: OpenLayers.Control.GeofieldEditingToolbar
* The GeofieldEditingToolbar is a panel controls to modify or draw polygons, lines,
* points, or to navigate the map by panning. You can select which tool to enable
* with options.tools.
*
* Inherits from:
* - <OpenLayers.Control.Panel>
*/
OpenLayers.Control.GeofieldEditingToolbar = OpenLayers.Class(
OpenLayers.Control.Panel, {
/**
* Constructor: OpenLayers.Control.GeofieldEditingToolbar
* Create an editing toolbar for a given layer.
*
* Parameters:
* layer - {<OpenLayers.Layer.Vector>}
* options - {Object}
*/
initialize: function(layer, options) {
OpenLayers.Control.Panel.prototype.initialize.apply(this, [options]);
var controls = [];
var tools = options.tools;
var tool = null;
if (options.allow_edit && options.allow_edit !== 0) {
// add an Edit feature
controls.push(new OpenLayers.Control.ModifyFeature(layer, {
deleteCodes: [46, 68, 100],
handleKeypress: function(evt) {
if (this.feature && OpenLayers.Util.indexOf(this.deleteCodes, evt.keyCode) > -1) {
// We must unselect the feature before we delete it
var feature_to_delete = this.feature;
this.selectControl.unselectAll();
this.layer.removeFeatures([feature_to_delete]);
}
}
}));
} else {
controls = [new OpenLayers.Control.Navigation()];
}
if (tools && tools.length) {
for (var i = 0, il = tools.length; i < il; i += 1) {
// capitalize first letter
tool = tools[i][0].toUpperCase() + tools[i].slice(1);
controls.push(
new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler[tool], {'displayClass': 'olControlDrawFeature' + tool})
);
}
}
this.addControls(controls);
},
/**
* Method: draw
* calls the default draw, and then activates mouse defaults.
*
* Returns:
* {DOMElement}
*/
draw: function() {
OpenLayers.Control.Panel.prototype.draw.apply(this, arguments);
this.div.className += " olControlEditingToolbar";
if (this.defaultControl === null) {
this.defaultControl = this.controls[0];
}
return this.div;
},
CLASS_NAME: "OpenLayers.Control.GeofieldEditingToolbar"
});
(function($) {
/**
* Geofield Behavior
*/
Drupal.behaviors.openlayers_behavior_geofield = {
'attach': function(context, settings) {
var data = $(context).data('openlayers'),
behavior = data && data.map.behaviors['openlayers_behavior_geofield'],
dataProjection = new OpenLayers.Projection('EPSG:4326'),
features, wktFormat;
// helper to create a WKT format object with the right projections
function initWktFormat (inp, outp) {
var WktWriter = new OpenLayers.Format.WKT();
WktWriter.internalProjection = inp;
WktWriter.externalProjection = outp || dataProjection;
return WktWriter;
}
// populate our wkt input field
function updateWKTField (features) {
var WktWriter = initWktFormat(features.object.map.projection);
// limits are to be checked server-side, not here.
// for a single shape avoid GEOMETRYCOLLECTION
var toSerialize = features.object.features;
// don't serialize empty feature
if (toSerialize.length) {
if (toSerialize.length === 1) { toSerialize = toSerialize[0]; }
this.val(WktWriter.write(toSerialize));
}
// but clear the value
else {
this.val('');
}
}
// keep only one features for each map input
function limitFeatures (features) {
// copy a list of features
var copyFeatures = features.object.features.slice();
// only keep the last one
var lastFeature = copyFeatures.pop();
// we remove a lot of features, don't trigger events
features.object.destroyFeatures(copyFeatures, {silient: true});
}
if (behavior && !$(context).hasClass('geofield-processed')) {
// we get the .form-item wrapper which is a slibling of our hidden input
var $wkt = $(context).closest('.form-item').parent().find('input.geofield_wkt');
// if there is no form input this shouldn't be activated
if ($wkt.length) {
var dataLayer = new OpenLayers.Layer.Vector(Drupal.t('Feature Layer'), {
projection: dataProjection,
drupalID: 'openlayers_behavior_geofield'
});
dataLayer.styleMap = Drupal.openlayers.getStyleMap(data.map, 'openlayers_behavior_geofield');
data.openlayers.addLayer(dataLayer);
// only one feature on each map register before adding our data
if (Drupal.settings.geofield.data_storage == 'single') {
dataLayer.events.register('featureadded', $wkt, limitFeatures);
}
if ($wkt.val() != '') {
wktFormat = initWktFormat(data.openlayers.projection);
features = wktFormat.read($wkt.val());
dataLayer.addFeatures(features);
}
// registering events late, because adding data
// would result in a reprojection loop
dataLayer.events.register('featureadded', $wkt, updateWKTField);
dataLayer.events.register('featureremoved', $wkt, updateWKTField);
dataLayer.events.register('afterfeaturemodified', $wkt, updateWKTField);
// transform options object to array
behavior.tools = [];
// add a new 'tools' key which is an array of enabled features
$.each(behavior.feature_types, function (key, value) {
if (value) {
behavior.tools.push(key);
}
});
// create toolbar
var geofieldControl = new OpenLayers.Control.GeofieldEditingToolbar(dataLayer, behavior);
data.openlayers.addControl(geofieldControl);
// on submit recalculate everything to be up to date
var formData = {
'control': geofieldControl,
'dataLayer': dataLayer
};
function handleSubmit (e) {
$.map(e.data.control.controls, function(c) { c.deactivate(); });
dataLayer.events.triggerEvent('featuremodified');
}
$(context).parents('form').bind('submit', formData, handleSubmit);
}
$(context).addClass('geofield-processed');
} // if
}
};
})(jQuery);

View File

@@ -0,0 +1,55 @@
<?php
/**
* @file
* Implementation of OpenLayers behavior.
*/
/**
* Map Form Values Behavior
*/
class openlayers_behavior_geofield extends openlayers_behavior {
/**
* Provide initial values for options.
*/
function options_init() {
return array(
'feature_types' => array(),
'allow_edit' => 1,
);
}
function options_form($defaults = array()) {
$features = array(
'point' => t('Point'),
'path' => t('Path'),
'polygon' => t('Polygon'),
);
return array(
'feature_types' => array(
'#title' => t('Available Features'),
'#type' => 'checkboxes',
'#options' => $features,
'#description' => t('Select what features are available to draw.'),
'#default_value' => isset($defaults['feature_types']) ? $defaults['feature_types'] : array(),
),
'allow_edit' => array(
'#title' => t('Allow shape modification'),
'#type' => 'checkbox',
'#description' => t('Can you edit and delete shapes.'),
'#default_value' => isset($defaults['allow_edit']) ? $defaults['allow_edit'] : 1,
),
);
}
/**
* Render.
*/
function render(&$map) {
$geopath = drupal_get_path('module', 'geofield');
drupal_add_js($geopath . '/includes/behaviors/js/openlayers_behavior_geofield.js');
return $this->options;
}
}

View File

@@ -0,0 +1,61 @@
// geo-location shim
// Source: https://gist.github.com/366184
// currentely only serves lat/long
// depends on jQuery
;(function(geolocation, $){
if (geolocation) return;
var cache;
geolocation = window.navigator.geolocation = {};
geolocation.getCurrentPosition = function(callback){
if (cache) callback(cache);
$.getScript('//www.google.com/jsapi',function(){
cache = {
coords : {
"latitude": google.loader.ClientLocation.latitude,
"longitude": google.loader.ClientLocation.longitude
}
};
callback(cache);
});
};
geolocation.watchPosition = geolocation.getCurrentPosition;
})(navigator.geolocation, jQuery);
;(function ($) {
Drupal.behaviors.geofieldGeolocation = {
attach: function (context, settings) {
// callback for getCurrentPosition
function updateLocation(position) {
// @TODO: calculate bounding box from accuracy value (accuracy is in meters)
$fields.find('.geofield_lat').val(position.coords.latitude);
$fields.find('.geofield_lon').val(position.coords.longitude);
}
// don't do anything if we're on field configuration
if (!$(context).find("#edit-instance").length) {
var $fields = $(context).find('.field-widget-geofield-geolocation');
// check that we have something to fill up
// on muti values check only that the first one is empty
if ($fields.find('.geofield_lat').val() == '' && $fields.find('.geofield_lon').val() == '') {
// very simple geolocation, no fallback support
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(updateLocation);
}
}
}
}
};
})(jQuery);

View File

@@ -0,0 +1,14 @@
name = Geofield Map
description = Provides a basic mapping interface for Geofield.
core = 7.x
dependencies[] = geofield
files[] = includes/geofield_map.views.inc
files[] = includes/geofield_map_plugin_style_map.inc
; Information added by drupal.org packaging script on 2012-09-03
version = "7.x-1.1+6-dev"
core = "7.x"
project = "geofield"
datestamp = "1346631868"

View File

@@ -0,0 +1,343 @@
<?php
/**
* Implements hook_views_api().
*/
function geofield_map_views_api() {
return array(
'api' => '3.0-alpha1',
'path' => drupal_get_path('module', 'geofield_map') . '/includes',
);
}
/**
* Implements hook_field_formatter_info().
*/
function geofield_map_field_formatter_info() {
return array(
'geofield_map_map' => array(
'label' => t('Geofield Map'),
'field types' => array('geofield'),
'settings' => array(
'geofield_map_width' => '100%',
'geofield_map_height' => '300px',
'geofield_map_zoom' => '8',
'geofield_map_controltype' => 'default',
'geofield_map_mtc' => 'standard',
'geofield_map_pancontrol' => 1,
'geofield_map_maptype' => 'map',
'geofield_map_baselayers_map' => 1,
'geofield_map_baselayers_satellite' => 1,
'geofield_map_baselayers_hybrid' => 1,
'geofield_map_baselayers_physical' => 0,
'geofield_map_scale' => 0,
'geofield_map_overview' => 0,
'geofield_map_overview_opened' => 0,
'geofield_map_scrollwheel' => 0,
'geofield_map_draggable' => 0,
'geofield_map_streetview_show' => 0,
),
),
);
}
/**
* Implements hook_field_formatter_view().
*/
function geofield_map_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
$element = array();
list($entity_id) = entity_extract_ids($entity_type, $entity);
$settings = $display['settings'];
$map_settings = geofield_map_settings_do($settings);
geophp_load();
$data = array();
foreach ($items as $item) {
$geometry = geoPHP::load($item['wkt'], 'wkt');
if (!empty($geometry)) {
$datum = json_decode($geometry->out('json'));
$datum->properties = array(
'description' => entity_label($entity_type, $entity),
);
$data[] = $datum;
}
}
if (!empty($data)) {
$map_id = drupal_html_id("geofield_map_entity_{$entity_type}_{$entity_id}_{$field['field_name']}");
$js_settings = array(
$map_id => array(
'map_settings' => $map_settings,
'data' => count($data) == 1 ?
$data[0] :
array( 'type' => 'GeometryCollection', 'geometries' => $data),
),
);
$container_attributes = array(
//No need for defaults here - these are populated from the field defaults.
'style' => "height:{$settings['geofield_map_height']}; width:{$settings['geofield_map_width']}",
'id' => $map_id,
'class' => 'geofieldMap',
);
$element[0] = array(
'#attached' => array(
'js' => array(
'//maps.googleapis.com/maps/api/js?sensor=false' => array('type' => 'external'),
drupal_get_path('module', 'geofield_map') . '/js/GeoJSON.js',
drupal_get_path('module', 'geofield_map') . '/js/geofield_map.js',
array('data' => array('geofieldMap' => $js_settings), 'type' => 'setting'),
)
),
'#markup' => '<div' . drupal_attributes($container_attributes) . '></div>',
);
}
return $element;
}
/**
* Implements hook_field_formatter_settings_form().
*/
function geofield_map_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
$element = geofield_map_settings_form($settings);
return $element;
}
/**
* Implements hook_field_formatter_settings_summary().
*/
function geofield_map_field_formatter_settings_summary($field, $instance, $view_mode) {
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
$summary = array();
if ($settings['geofield_map_width']) {
$summary[] = t('Width: @w', array('@w' => $settings['geofield_map_width']));
}
if ($settings['geofield_map_height']) {
$summary[] = t('Height: @h', array('@h' => $settings['geofield_map_height']));
}
if ($settings['geofield_map_zoom']) {
$summary[] = t('Zoom: @z', array('@z' => $settings['geofield_map_zoom']));
}
if ($settings['geofield_map_controltype']) {
$summary[] = t('Zoom Control Type: @z', array('@z' => $settings['geofield_map_controltype']));
}
if ($settings['geofield_map_mtc']) {
$summary[] = t('Map Control Type: @m', array('@m' => $settings['geofield_map_mtc']));
}
if ($settings['geofield_map_pancontrol']) {
$summary[] = t('Show Pan Control: @yn', array('@yn' => ($settings['geofield_map_pancontrol'] ? 'Yes' : 'No')));
}
if ($settings['geofield_map_maptype']) {
$summary[] = t('Default Map Type: @m', array('@m' => $settings['geofield_map_maptype']));
}
if ($settings['geofield_map_scale']) {
$summary[] = t('Show Scale: @yn', array('@yn' => ($settings['geofield_map_scale'] ? 'Yes' : 'No')));
}
if ($settings['geofield_map_overview']) {
$summary[] = t('Overview Map: @yn', array('@yn' => ($settings['geofield_map_overview'] ? 'Yes' : 'No')));
}
if ($settings['geofield_map_scrollwheel']) {
$summary[] = t('Scrollwheel: @yn', array('@yn' => ($settings['geofield_map_scrollwheel'] ? 'Yes' : 'No')));
}
if ($settings['geofield_map_draggable']) {
$summary[] = t('Draggable: @yn', array('@yn' => ($settings['geofield_map_draggable'] ? 'Yes' : 'No')));
}
if ($settings['geofield_map_streetview_show']) {
$summary[] = t('Show streetview button: @yn', array('@yn' => ($settings['geofield_map_streetview_show'] ? 'Yes' : 'No')));
}
return implode('<br />', $summary);
}
function geofield_map_settings_form($settings, $element = array()) {
$element['geofield_map_width'] = array(
'#type' => 'textfield',
'#title' => t('Map width'),
'#default_value' => $settings['geofield_map_width'],
'#size' => 25,
'#maxlength' => 25,
'#description' => t('The default width of a Google map, as a CSS length or percentage. Examples: <em>50px</em>, <em>5em</em>, <em>2.5in</em>, <em>95%</em>'),
'#required' => TRUE,
);
$element['geofield_map_height'] = array(
'#type' => 'textfield',
'#title' => t('Map height'),
'#default_value' => $settings['geofield_map_height'],
'#size' => 25,
'#maxlength' => 25,
'#description' => t('The default height of a Google map, as a CSS length or percentage. Examples: <em>50px</em>, <em>5em</em>, <em>2.5in</em>, <em>95%</em>'),
'#required' => TRUE,
);
$element['geofield_map_zoom'] = array(
'#type' => 'select',
'#title' => t('Zoom'),
'#default_value' => $settings['geofield_map_zoom'],
'#options' => drupal_map_assoc(range(0, 17)),
'#description' => t('The default zoom level of a Google map.'),
);
$element['geofield_map_controltype'] = array(
'#type' => 'select',
'#title' => t('Zoom Control Type'),
'#options' => array(
'none' => t('None'),
'default' => t('Default'),
'small' => t('Small'),
'large' => t('Large'),
),
'#default_value' => $settings['geofield_map_controltype'],
);
$element['geofield_map_mtc'] = array(
'#type' => 'select',
'#title' => t('Map Control Type'),
'#options' => array(
'none' => t('None'),
'standard' => t('Horizontal bar'),
'menu' => t('Dropdown'),
),
'#default_value' => $settings['geofield_map_mtc'],
);
$element['geofield_map_pancontrol'] = array(
'#type' => 'checkbox',
'#title' => t('Show Pan control'),
'#default_value' => $settings['geofield_map_pancontrol'],
'#return_value' => 1,
);
$mapopts = array('map' => t('Standard street map'));
if ($settings['geofield_map_baselayers_satellite']) {
$mapopts['satellite'] = t('Standard satellite map');
}
if ($settings['geofield_map_baselayers_hybrid']) {
$mapopts['hybrid'] = t('Hybrid satellite map');
}
if ($settings['geofield_map_baselayers_physical']) {
$mapopts['physical'] = t('Terrain map');
}
$element['geofield_map_maptype'] = array(
'#type' => 'select',
'#title' => t('Default Map Type'),
'#default_value' => $settings['geofield_map_maptype'],
'#options' => array(
'map' => t('Standard street map'),
'satellite' => t('Standard satellite map'),
'hybrid' => t('Hybrid satellite map'),
'physical' => t('Terrain map'),
),
);
$element['geofield_map_baselayers_map'] = array(
'#type' => 'checkbox',
'#title' => t('Standard street map'),
'#description' => t('The standard default street map.'),
'#default_value' => $settings['geofield_map_baselayers_map'],
'#return_value' => 1,
'#prefix' => '<fieldset><legend>' . t('Enable map types') . '</legend>',
);
$element['geofield_map_baselayers_satellite'] = array(
'#type' => 'checkbox',
'#title' => t('Standard satellite map'),
'#description' => t('Satellite view without street overlay.'),
'#default_value' => $settings['geofield_map_baselayers_satellite'],
'#return_value' => 1,
);
$element['geofield_map_baselayers_hybrid'] = array(
'#type' => 'checkbox',
'#title' => t('Hybrid satellite map'),
'#description' => t('Satellite view with street overlay.'),
'#default_value' => $settings['geofield_map_baselayers_hybrid'],
'#return_value' => 1,
);
$element['geofield_map_baselayers_physical'] = array(
'#type' => 'checkbox',
'#title' => t('Terrain map'),
'#description' => t('Map with physical data (terrain, vegetation.)'),
'#default_value' => $settings['geofield_map_baselayers_physical'],
'#return_value' => 1,
'#suffix' => '</fieldset>',
);
$element['geofield_map_scale'] = array(
'#type' => 'checkbox',
'#title' => t('Scale'),
'#description' => t('Show scale'),
'#default_value' => $settings['geofield_map_scale'],
'#return_value' => 1,
);
$element['geofield_map_overview'] = array(
'#type' => 'checkbox',
'#title' => t('Overview map'),
'#description' => t('Show overview map'),
'#default_value' => $settings['geofield_map_overview'],
'#return_value' => 1,
);
$element['geofield_map_overview_opened'] = array(
'#type' => 'checkbox',
'#title' => t('Overview map state'),
'#description' => t('Show overview map as open by default'),
'#default_value' => $settings['geofield_map_overview_opened'],
'#return_value' => 1,
);
$element['geofield_map_scrollwheel'] = array(
'#type' => 'checkbox',
'#title' => t('Scrollwheel'),
'#description' => t('Enable scrollwheel zooming'),
'#default_value' => $settings['geofield_map_scrollwheel'],
'#return_value' => 1,
);
$element['geofield_map_draggable'] = array(
'#type' => 'checkbox',
'#title' => t('Draggable'),
'#description' => t('Enable dragging on the map'),
'#default_value' => $settings['geofield_map_draggable'],
'#return_value' => 1,
);
$element['geofield_map_streetview_show'] = array(
'#type' => 'checkbox',
'#title' => t('Show streetview button'),
'#default_value' => $settings['geofield_map_streetview_show'],
'#return_value' => 1,
);
return $element;
}
function geofield_map_settings_do($settings) {
$map_settings = array(
'zoom' => $settings['geofield_map_zoom'],
'controltype' => $settings['geofield_map_controltype'],
'mtc' => $settings['geofield_map_mtc'],
'pancontrol' => $settings['geofield_map_pancontrol'],
'maptype' => $settings['geofield_map_maptype'],
'baselayers_map' => $settings['geofield_map_baselayers_map'],
'baselayers_satellite' => $settings['geofield_map_baselayers_satellite'],
'baselayers_hybrid' => $settings['geofield_map_baselayers_hybrid'],
'baselayers_physical' => $settings['geofield_map_baselayers_physical'],
'scale' => $settings['geofield_map_scale'],
'overview' => $settings['geofield_map_overview'],
'overview_opened' => $settings['geofield_map_overview_opened'],
'scrollwheel' => $settings['geofield_map_scrollwheel'],
'draggable' => $settings['geofield_map_draggable'],
'streetview_show' => $settings['geofield_map_streetview_show'],
);
return $map_settings;
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* @file
* Default views hooks.
*/
/**
* Implements hook_views_plugins().
*/
function geofield_map_views_plugins() {
$plugins = array(
'module' => 'geofield_map',
'style' => array(
'geofield_map_map' => array(
'title' => t('Geofield Map'),
'help' => t('Displays a View as an Geofield map.'),
'handler' => 'geofield_map_plugin_style_map',
'theme' => 'geofield_map_map',
'theme path' => drupal_get_path('module', 'geofield_map') . '/includes',
'path' => drupal_get_path('module', 'geofield_map') . '/includes',
'uses fields' => TRUE,
'uses row plugin' => FALSE,
'uses options' => TRUE,
'uses grouping' => FALSE,
'type' => 'normal',
'even empty' => TRUE,
),
),
);
return $plugins;
}

View File

@@ -0,0 +1,167 @@
<?php
/**
* @file
* This file holds style plugin for Geofield Maps
*
* @ingroup geofield_map
*/
/**
* @class
* Extension of the Views Plugin Syle for Geofield Map
*/
class geofield_map_plugin_style_map extends views_plugin_style {
/**
* Set default options
*/
function option_definition() {
$options = parent::option_definition();
$options['data_source'] = array('default' => '');
$options['popup_source'] = array('default' => '');
$options['alt_text'] = array('default' => '');
$options['geofield_map_width'] = array('default' => '100%');
$options['geofield_map_height'] = array('default' => '300px');
$options['geofield_map_zoom'] = array('default' => '8');
$options['geofield_map_controltype'] = array('default' => 'default');
$options['geofield_map_mtc'] = array('default' => 'standard');
$options['geofield_map_pancontrol'] = array('default' => 1);
$options['geofield_map_maptype'] = array('default' => 'map');
$options['geofield_map_baselayers_map'] = array('default' => 1);
$options['geofield_map_baselayers_satellite'] = array('default' => 1);
$options['geofield_map_baselayers_hybrid'] = array('default' => 1);
$options['geofield_map_baselayers_physical'] = array('default' => 0);
$options['geofield_map_scale'] = array('default' => 0);
$options['geofield_map_overview'] = array('default' => 0);
$options['geofield_map_overview_opened'] = array('default' => 0);
$options['geofield_map_scrollwheel'] = array('default' => 0);
$options['geofield_map_draggable'] = array('default' => 0);
$options['geofield_map_streetview_show'] = array('default' => 0);
$options['icon'] = array('default' => '');
return $options;
}
/**
* Options form
*/
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
$handlers = $this->display->handler->get_handlers('field');
$data_source_options = $popup_source_options = array(
'' => '<none>',
);
foreach ($handlers as $handle) {
$popup_source_options[$handle->options['id']] = (!empty($handle->options['label'])) ? $handle->options['label'] : $handle->options['id'];
if (!empty($handle->field_info['type']) && $handle->field_info['type'] == 'geofield') {
$data_source_options[$handle->options['id']] = (!empty($handle->options['label'])) ? $handle->options['label'] : $handle->options['id'];
}
}
if (count($data_source_options) == 1) {
$form['error'] = array(
'#markup' => 'Please add at least 1 geofield to the view',
);
}
else {
// Map Preset
$form['data_source'] = array(
'#type' => 'select',
'#title' => t('Data Source'),
'#description' => t('Which field contains geodata?'),
'#options' => $data_source_options,
'#default_value' => $this->options['data_source'] ? $this->options['data_source'] : '',
);
$form['popup_source'] = array(
'#type' => 'select',
'#title' => t('Popup Text'),
'#options' => $popup_source_options,
'#default_value' => $this->options['popup_source'] ? $this->options['popup_source'] : '',
);
$form['alt_text'] = array(
'#type' => 'textarea',
'#title' => t('Alternate Text'),
'#description' => t('This text shows up when a user does not have javascript enabled'),
'#default_value' => $this->options['alt_text'] ? $this->options['alt_text'] : '',
);
$form = geofield_map_settings_form($this->options, $form);
}
}
/**
* Renders views (map)
*/
function render() {
geophp_load();
$style_options = $this->view->style_plugin->options;
$geo_data = (!empty($style_options['data_source'])) ? 'field_' . $style_options['data_source']: NULL;
$popup_data = (!empty($style_options['popup_source'])) ? $style_options['popup_source'] : NULL;
if ($geo_data) {
$this->render_fields($this->view->result);
$data = array();
foreach ($this->view->result as $id => $result) {
$geofield = (!empty($result->$geo_data)) ? $result->$geo_data : NULL;
if (!empty($geofield)) {
$description = ($popup_data ? $this->rendered_fields[$id][$popup_data] : '');
$geometry = geoPHP::load($geofield[0]['raw']['wkt'], 'wkt');
$datum = json_decode($geometry->out('json'));
$datum->properties = array(
'description' => $description,
);
$data[] = $datum;
}
}
if (count($data) == 1) {
$data = $data[0];
}
elseif (count($data) > 1) {
$tmp = $data;
$data = array(
'type' => 'GeometryCollection',
'geometries' => $tmp,
);
}
$map_settings = geofield_map_settings_do($style_options);
$map_id = drupal_html_id('geofield_map_' . $this->view->name . '_' . $this->view->current_display);
$js_settings = array(
$map_id => array(
'map_id' => $map_id,
'map_settings' => $map_settings,
'data' => $data,
),
);
drupal_add_js(array('geofieldMap' => $js_settings), 'setting');
}
drupal_add_js('//maps.googleapis.com/maps/api/js?sensor=false', 'external');
drupal_add_js(drupal_get_path('module', 'geofield_map') . '/js/GeoJSON.js');
drupal_add_js(drupal_get_path('module', 'geofield_map') . '/js/geofield_map.js');
// defaults
$width = '100%';
$height = '300px';
if ($style_options['geofield_map_width']) {
$width = $style_options['geofield_map_width'];
}
if ($style_options['geofield_map_height']) {
$height = $style_options['geofield_map_height'];
}
return '<div style="width: ' . $width . '; height: ' . $height . '" id="' . $map_id . '" class="geofieldMap">' . $style_options['alt_text'] . '</div>';
}
}

View File

@@ -0,0 +1,201 @@
// Source: https://github.com/JasonSanford/GeoJSON-to-Google-Maps
var GeoJSON = function( geojson, options ){
var _geometryToGoogleMaps = function( geojsonGeometry, opts, geojsonProperties ){
var googleObj;
switch ( geojsonGeometry.type ){
case "Point":
opts.position = new google.maps.LatLng(geojsonGeometry.coordinates[1], geojsonGeometry.coordinates[0]);
var bounds = new google.maps.LatLngBounds();
bounds.extend(opts.position);
googleObj = new google.maps.Marker(opts);
googleObj.set('bounds', bounds);
if (geojsonProperties) {
googleObj.set("geojsonProperties", geojsonProperties);
}
break;
case "MultiPoint":
googleObj = [];
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < geojsonGeometry.coordinates.length; i++){
opts.position = new google.maps.LatLng(geojsonGeometry.coordinates[i][1], geojsonGeometry.coordinates[i][0]);
bounds.extend(opts.position);
googleObj.push(new google.maps.Marker(opts));
}
if (geojsonProperties) {
for (var k = 0; k < googleObj.length; k++){
googleObj[k].set("geojsonProperties", geojsonProperties);
}
}
for (var k = 0; k < googleObj.length; k++) {
googleObj[k].set('bounds', bounds);
}
break;
case "LineString":
var path = [];
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < geojsonGeometry.coordinates.length; i++){
var coord = geojsonGeometry.coordinates[i];
var ll = new google.maps.LatLng(coord[1], coord[0]);
bounds.extend(ll);
path.push(ll);
}
opts.path = path;
googleObj = new google.maps.Polyline(opts);
googleObj.set('bounds', bounds);
if (geojsonProperties) {
googleObj.set("geojsonProperties", geojsonProperties);
}
break;
case "MultiLineString":
googleObj = [];
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < geojsonGeometry.coordinates.length; i++){
var path = [];
for (var j = 0; j < geojsonGeometry.coordinates[i].length; j++){
var coord = geojsonGeometry.coordinates[i][j];
var ll = new google.maps.LatLng(coord[1], coord[0]);
bounds.extend(ll);
path.push(ll);
}
opts.path = path;
googleObj.push(new google.maps.Polyline(opts));
}
if (geojsonProperties) {
for (var k = 0; k < googleObj.length; k++){
googleObj[k].set("geojsonProperties", geojsonProperties);
}
}
for (var k = 0; k < googleObj.length; k++) {
googleObj[k].set('bounds', bounds);
}
break;
case "Polygon":
var paths = [];
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < geojsonGeometry.coordinates.length; i++){
var path = [];
for (var j = 0; j < geojsonGeometry.coordinates[i].length; j++){
var ll = new google.maps.LatLng(geojsonGeometry.coordinates[i][j][1], geojsonGeometry.coordinates[i][j][0]);
bounds.extend(ll);
path.push(ll)
}
paths.push(path);
}
opts.paths = paths;
googleObj = new google.maps.Polygon(opts);
googleObj.set('bounds', bounds);
if (geojsonProperties) {
googleObj.set("geojsonProperties", geojsonProperties);
}
break;
case "MultiPolygon":
googleObj = [];
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < geojsonGeometry.coordinates.length; i++){
var paths = [];
for (var j = 0; j < geojsonGeometry.coordinates[i].length; j++){
var path = [];
for (var k = 0; k < geojsonGeometry.coordinates[i][j].length; k++){
var ll = new google.maps.LatLng(geojsonGeometry.coordinates[i][j][k][1], geojsonGeometry.coordinates[i][j][k][0]);
bounds.extend(ll);
path.push(ll);
}
paths.push(path);
}
opts.paths = paths;
googleObj.push(new google.maps.Polygon(opts));
}
if (geojsonProperties) {
for (var k = 0; k < googleObj.length; k++){
googleObj[k].set("geojsonProperties", geojsonProperties);
}
}
for (var k = 0; k < googleObj.length; k++) {
googleObj[k].set('bounds', bounds);
}
break;
case "GeometryCollection":
googleObj = [];
if (!geojsonGeometry.geometries){
googleObj = _error("Invalid GeoJSON object: GeometryCollection object missing \"geometries\" member.");
}else{
for (var i = 0; i < geojsonGeometry.geometries.length; i++){
googleObj.push(_geometryToGoogleMaps(geojsonGeometry.geometries[i], opts, geojsonProperties || null));
}
}
break;
default:
googleObj = _error("Invalid GeoJSON object: Geometry object must be one of \"Point\", \"LineString\", \"Polygon\" or \"MultiPolygon\".");
}
return googleObj;
};
var _error = function( message ){
return {
type: "Error",
message: message
};
};
var obj;
var opts = options || {};
switch ( geojson.type ){
case "FeatureCollection":
if (!geojson.features){
obj = _error("Invalid GeoJSON object: FeatureCollection object missing \"features\" member.");
}else{
obj = [];
for (var i = 0; i < geojson.features.length; i++){
obj.push(_geometryToGoogleMaps(geojson.features[i].geometry, opts, geojson.features[i].properties));
}
}
break;
case "GeometryCollection":
if (!geojson.geometries){
obj = _error("Invalid GeoJSON object: GeometryCollection object missing \"geometries\" member.");
}else{
obj = [];
for (var i = 0; i < geojson.geometries.length; i++){
obj.push(_geometryToGoogleMaps(geojson.geometries[i], opts, geojson.geometries[i].properties));
}
}
break;
case "Feature":
if (!( geojson.properties && geojson.geometry )){
obj = _error("Invalid GeoJSON object: Feature object missing \"properties\" or \"geometry\" member.");
}else{
obj = _geometryToGoogleMaps(geojson.geometry, opts, geojson.properties);
}
break;
case "Point": case "MultiPoint": case "LineString": case "MultiLineString": case "Polygon": case "MultiPolygon":
obj = geojson.coordinates
? obj = _geometryToGoogleMaps(geojson, opts, geojson.properties)
: _error("Invalid GeoJSON object: Geometry object missing \"coordinates\" member.");
break;
default:
obj = _error("Invalid GeoJSON object: GeoJSON object must be one of \"Point\", \"LineString\", \"Polygon\", \"MultiPolygon\", \"Feature\", \"FeatureCollection\" or \"GeometryCollection\".");
}
return obj;
};

View File

@@ -0,0 +1,122 @@
(function ($) {
Drupal.behaviors.geofieldMap = {
attach: function(context, settings) {
$('.geofieldMap', context).once('geofield-processed', function(index, element) {
var data = undefined;
var map_settings = [];
var pointCount = 0;
var resetZoom = true;
var elemID = $(element).attr('id');
if(settings.geofieldMap[elemID]) {
data = settings.geofieldMap[elemID].data;
map_settings = settings.geofieldMap[elemID].map_settings;
}
// Checking to see if google variable exists. We need this b/c views breaks this sometimes. Probably
// an AJAX/external javascript bug in core or something.
if (typeof google != 'undefined' && typeof google.maps.ZoomControlStyle != 'undefined' && data != undefined) {
var features = GeoJSON(data);
// controltype
var controltype = map_settings.controltype;
if (controltype == 'default') { controltype = google.maps.ZoomControlStyle.DEFAULT; }
else if (controltype == 'small') { controltype = google.maps.ZoomControlStyle.SMALL; }
else if (controltype == 'large') { controltype = google.maps.ZoomControlStyle.LARGE; }
else { controltype = false }
// map type
var maptype = map_settings.maptype;
if (maptype) {
if (maptype == 'map' && map_settings.baselayers_map) { maptype = google.maps.MapTypeId.ROADMAP; }
if (maptype == 'satellite' && map_settings.baselayers_satellite) { maptype = google.maps.MapTypeId.SATELLITE; }
if (maptype == 'hybrid' && map_settings.baselayers_hybrid) { maptype = google.maps.MapTypeId.HYBRID; }
if (maptype == 'physical' && map_settings.baselayers_physical) { maptype = google.maps.MapTypeId.TERRAIN; }
}
else { maptype = google.maps.MapTypeId.ROADMAP; }
// menu type
var mtc = map_settings.mtc;
if (mtc == 'standard') { mtc = google.maps.MapTypeControlStyle.HORIZONTAL_BAR; }
else if (mtc == 'menu' ) { mtc = google.maps.MapTypeControlStyle.DROPDOWN_MENU; }
else { mtc = false; }
var myOptions = {
zoom: parseInt(map_settings.zoom),
mapTypeId: maptype,
mapTypeControl: (mtc ? true : false),
mapTypeControlOptions: {style: mtc},
zoomControl: ((controltype !== false) ? true : false),
zoomControlOptions: {style: controltype},
panControl: (map_settings.pancontrol ? true : false),
scrollwheel: (map_settings.scrollwheel ? true : false),
draggable: (map_settings.draggable ? true : false),
overviewMapControl: (map_settings.overview ? true : false),
overviewMapControlOptions: {opened: (map_settings.overview_opened ? true : false)},
streetViewControl: (map_settings.streetview_show ? true : false),
scaleControl: (map_settings.scale ? true : false),
scaleControlOptions: {style: google.maps.ScaleControlStyle.DEFAULT}
};
var map = new google.maps.Map($(element).get(0), myOptions);
var range = new google.maps.LatLngBounds();
var infowindow = new google.maps.InfoWindow({
content: ''
});
if (features.setMap) {
placeFeature(features, map, range);
// Don't move the default zoom if we're only displaying one point.
if (features.getPosition) {
resetZoom = false;
}
} else {
for (var i in features) {
if (features[i].setMap) {
placeFeature(features[i], map, range);
} else {
for (var j in features[i]) {
if (features[i][j].setMap) {
placeFeature(features[i][j], map, range);
}
}
}
}
}
if (resetZoom) {
map.fitBounds(range);
} else {
map.setCenter(range.getCenter());
}
}
function placeFeature(feature, map, range) {
var properties = feature.get('geojsonProperties');
if (feature.setTitle && properties && properties.title) {
feature.setTitle(properties.title);
}
feature.setMap(map);
if (feature.getPosition) {
range.extend(feature.getPosition());
} else {
var path = feature.getPath();
path.forEach(function(element) {
range.extend(element);
});
}
if (properties && properties.description) {
var bounds = feature.get('bounds');
google.maps.event.addListener(feature, 'click', function() {
infowindow.setPosition(bounds.getCenter());
infowindow.setContent(properties.description);
infowindow.open(map);
});
}
}
});
}
}
})(jQuery);