first import
This commit is contained in:
339
sites/all/modules/geofield/LICENSE.txt
Normal file
339
sites/all/modules/geofield/LICENSE.txt
Normal 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.
|
98
sites/all/modules/geofield/README.txt
Normal file
98
sites/all/modules/geofield/README.txt
Normal 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.
|
165
sites/all/modules/geofield/geofield.devel_generate.inc
Normal file
165
sites/all/modules/geofield/geofield.devel_generate.inc
Normal 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) . ')';
|
||||
}
|
216
sites/all/modules/geofield/geofield.feeds.inc
Normal file
216
sites/all/modules/geofield/geofield.feeds.inc
Normal 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;
|
||||
}
|
471
sites/all/modules/geofield/geofield.formatters.inc
Normal file
471
sites/all/modules/geofield/geofield.formatters.inc
Normal 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;
|
||||
}
|
19
sites/all/modules/geofield/geofield.info
Normal file
19
sites/all/modules/geofield/geofield.info
Normal 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"
|
||||
|
64
sites/all/modules/geofield/geofield.install
Normal file
64
sites/all/modules/geofield/geofield.install
Normal 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,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
11
sites/all/modules/geofield/geofield.make.example
Normal file
11
sites/all/modules/geofield/geofield.make.example
Normal 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"
|
551
sites/all/modules/geofield/geofield.module
Normal file
551
sites/all/modules/geofield/geofield.module
Normal 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 . "° " . $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 . "° " . $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;
|
||||
}
|
201
sites/all/modules/geofield/geofield.openlayers.inc
Normal file
201
sites/all/modules/geofield/geofield.openlayers.inc
Normal 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;
|
||||
}
|
67
sites/all/modules/geofield/geofield.test
Normal file
67
sites/all/modules/geofield/geofield.test
Normal 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'));
|
||||
}
|
||||
}
|
371
sites/all/modules/geofield/geofield.widgets.inc
Normal file
371
sites/all/modules/geofield/geofield.widgets.inc
Normal 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);
|
||||
}
|
||||
}
|
@@ -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 |
@@ -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);
|
@@ -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;
|
||||
}
|
||||
}
|
61
sites/all/modules/geofield/js/geolocation.js
Normal file
61
sites/all/modules/geofield/js/geolocation.js
Normal 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);
|
@@ -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"
|
||||
|
@@ -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;
|
||||
|
||||
}
|
@@ -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;
|
||||
}
|
@@ -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>';
|
||||
}
|
||||
}
|
201
sites/all/modules/geofield/modules/geofield_map/js/GeoJSON.js
Normal file
201
sites/all/modules/geofield/modules/geofield_map/js/GeoJSON.js
Normal 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;
|
||||
};
|
@@ -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);
|
Reference in New Issue
Block a user