\documentclass{article}
\usepackage{ulem}
\usepackage{graphicx}
\usepackage{hyperref}
\pagestyle{headings}
\begin{document}
\part{<a href="https://wiki.horde.org/HordeMap">HordeMap</a>}
Provides a javascript api for interacting with ajax "slippy" maps.

\section{Bugs}
\section{People}
<a href="https://wiki.horde.org/MichaelRubinsky">Michael Rubinsky</a>

\section{Description}
Abstraction for in-line map support. Horde ships with a driver for <a href="http://openlayers.org">OpenLayers</a> which provides support for Google, Yahoo, Bing, and OpenStreetMaps out of the box. Other mapping providers can be added by either adding support to the existing OpenLayers driver or by writing a new custom map driver.

\subsection{Building OpenLayers for Horde}
Horde come bundled with a custom OpenLayers build. In Horde 4 and Horde 5.0, this is based on OpenLayers 2.11. We perform significant modification to the base OpenLayers code to better fit it into the Horde Framework, and to significantly reduce the size of the resulting file. We build a custom version of the file, and split out other parts of it into our own classes. This takes the size of the file from somewhere around 3MB to slightly less the 1MB uncompressed (around 280k compressed).  This section is meant as an overview of how to build this Horde specific file.

\begin{itemize}
\item Download the full OL distribution


\item While not necessary, I usually edit the \textit{lib/OpenLayers.js} file before I run the build to remove all code to check if we are in a single file build or not. This is not necessary since we know we are always a single file build, and it shaves a good bit of code off.


\item Create a custom build cfg file. The file used to build the current file distributed in Horde is attached.


\item Build the file by executing the \textit{build.py} file in the openlayers build directory. Copy the resulting OpenLayers.js file to the hordemap directory.


\item Next we deal with the commercial mapping layers. Take the *full* contents of the \textit{!OpenLayers/Layer/\{mapprovider\}.js} files that you want to support, and add append it to the \textit{hordemap/\{mapprovider\}.js} file, replacing the existing openlayer code already in that file. For example - take the contents of \textit{!OpenLayers/Layer/Google.js} and append it to the end of \textit{hordemap/google.js} being sure to replace the exising openlayer code. This is all the code outside of the HordeMap.Google and HordeMap.Geocoder.Google classes.


\item Language files. This is probably the section with the most work. Since OpenLayers does not maintain any consistency in the style of locale naming, we have to edit almost every language file. OpenLayers sometimes names locales like EN\_US, and sometimes like EN-US and sometimes just like EN. First, copy all the language files (except the en.js file - that should be built in the openlayers.js file) to the \textit{hordemap/lang} directory. They should *all* be named in the de\_DE.js format.  Next, you have to open each file and rename the key into the Lang array to match the filename.


\item Until OpenLayers 3.0 is released, we need to remove a hack that OpenLayers has in place to allow some of their old example code to function. The following code in Openlayers.js should be removed:


\end{itemize}
<pre><code>
// FIXME: Remove this in 3.0. In 3.0, Event.stop will no longer be provided
// by OpenLayers.
if (window.Event) \{
    OpenLayers.Util.applyDefaults(window.Event, OpenLayers.Event);
\} else \{
    var Event = OpenLayers.Event;
\}
</code></pre>
\subsection{How to use (Horde 4 example).}
<pre><code>
<?php
/**
 * Example script for producing a HordeMap
 *
 * @author Michael J Rubinsky
 */

// Init Horde
define('HORDE\_BASE', '/private/var/www/html/horde');
require\_once HORDE\_BASE . '/lib/core.php';
Horde\_Registry::appInit(
	'horde',
	 array(
		'authentication' => 'none',
	    'session\_control' => 'none'));

// Hordemap parameters.
\$params = array(
    // Always "Horde" for horde's map driver.
	'driver' => 'Horde',
    // Provider layers that we want displayed
	'providers' => array('Yahoo', 'Google', 'Public', 'Mytopo'),
    // Geocoder to use.
	'geocoder' => 'Google'
);
// JSON encode for output in the javascript
\$providerJson = json\_encode(\$params['providers']);

// Setup translations
\$language = str\_replace('\_', '-', \$GLOBALS['language']);
\$language = \$GLOBALS['language'];
if (!file\_exists(\$GLOBALS['registry']->get('jsfs', 'horde') . '/map/' . \$language . '.js')) \{
    \$language = 'en-US';
\}

// Additional configurations.
\$params['conf'] = array(
    // If using a marker image
    //'markerImage' => (string)Horde\_Themes::img('map/marker.png'),
    //'markerBackground' => (string)Horde\_Themes::img('map/marker-shadow.png'),
    //'useMarkerLayer' => true,
    // Use this language for translations if available.
    'language' => \$language,
);

// API keys for those layers that require them.
foreach (\$params['providers'] as \$layer) \{
    switch (\$layer) \{
    case 'Google':
        // No longer required for v3.
        //\$params['conf']['apikeys']['google'] = \$GLOBALS['conf']['api']['googlemaps'];
        break;
    case 'Yahoo':
        \$params['conf']['apikeys']['yahoo'] = \$GLOBALS['conf']['api']['yahoomaps'];
        break;
    case 'Cloudmade':
        \$params['conf']['apikeys']['cloudmade'] = \$GLOBALS['conf']['api']['cloudmade'];
        break;
    case 'Mytopo':
        \$params['conf']['apikeys']['mytopo'] = \$GLOBALS['conf']['api']['mytopo'];
        break;
    \}
\}

// Geocoding
if (!empty(\$params['geocoder'])) \{
    switch (\$params['geocoder']) \{
    case 'Google':
        //\$params['conf']['apikeys']['google'] = \$GLOBALS['conf']['api']['googlemaps'];
        break;
    case 'Yahoo':
        \$params['conf']['apikeys']['yahoo'] = \$GLOBALS['conf']['api']['yahoomaps'];
        break;
    case 'Cloudmade':
        \$params['conf']['apikeys']['cloudmade'] = \$GLOBALS['conf']['api']['cloudmade'];
        break;
    \}
\}

// Include the Hordemap bootstrap file, and initialize the Hordemap.
\$params['jsuri'] = \$GLOBALS['registry']->get('jsuri', 'horde') . '/map/';
Horde::addScriptFile('map/map.js', 'horde');
\$js = 'HordeMap.initialize(' . Horde\_Serialize::serialize(\$params, HORDE\_SERIALIZE::JSON) . ');';
Horde::addinlineScript(\$js);

// Start output
require HORDE\_BASE . '/templates/common-header.inc';
?>
<script type="text/javascript">
// Basic initialization code to run on dom:loaded to init and display the map
document.observe("dom:loaded", function() \{
    // These are the same as configured above
    var providers = <?php echo \$providerJson ?>;//['Google', 'Yahoo', 'Public'];
    layers = [];
    providers.each(function(l) \{
       var p = new HordeMap[l]();
       \$H(p.getLayers()).values().each(function(e) \{layers.push(e);\});
    \});
    map = new HordeMap.Map['Horde'](\{
	elt: \$('mapdiv'),
        // If delayed is set to true, the map will not display until map.display()
        // is called (see below).
        //delayed:true,
        layers: layers,
    	markerDragEnd: function(r) \{alert('markerdragend');\},
	    mapClick: function(r) \{alert('mapclick')\}
    \});
    // Must call map.display() when you want the map to display when the
    // delayed property is set to true.
    //map.display();
\});
</script>
<h2>HordeMap Example</h2>
<div id="mapdiv" style="height:300px;width:700px;"></div>
</code></pre>
\section{Resources}
\section{<a href="http://openlayers.org">http://openlayers.org</a><br />
<a href="http://gis.ibbeck.de/ginfo/apps/OLExamples/Index/index.html">http://gis.ibbeck.de/ginfo/apps/OLExamples/Index/index.html</a>}
Back to the <a href="https://wiki.horde.org/Project">Project List</a>

\end{document}
