1<?php 2/* 3 * Copyright (c) 2008-2016 Mark C. Prins <mprins@users.sf.net> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17if (! defined ( 'DOKU_INC' )) 18 define ( 'DOKU_INC', realpath ( dirname ( __FILE__ ) . '/../../' ) . '/' ); 19if (! defined ( 'DOKU_PLUGIN' )) 20 define ( 'DOKU_PLUGIN', DOKU_INC . 'lib/plugins/' ); 21require_once (DOKU_PLUGIN . 'syntax.php'); 22 23/** 24 * DokuWiki Plugin openlayersmap (Syntax Component). 25 * Provides for display of an OpenLayers based map in a wiki page. 26 * 27 * @author Mark Prins 28 */ 29class syntax_plugin_openlayersmap_olmap extends DokuWiki_Syntax_Plugin { 30 31 /** 32 * defaults of the known attributes of the olmap tag. 33 */ 34 private $dflt = array ( 35 'id' => 'olmap', 36 'width' => '550px', 37 'height' => '450px', 38 'lat' => 50.0, 39 'lon' => 5.1, 40 'zoom' => 12, 41 'statusbar' => true, 42 'controls' => true, 43 'poihoverstyle' => false, 44 'baselyr' => 'OpenStreetMap', 45 'gpxfile' => '', 46 'kmlfile' => '', 47 'geojsonfile' => '', 48 'summary' => '' 49 ); 50 51 /** 52 * 53 * @see DokuWiki_Syntax_Plugin::getType() 54 */ 55 function getType() { 56 return 'substition'; 57 } 58 59 /** 60 * 61 * @see DokuWiki_Syntax_Plugin::getPType() 62 */ 63 function getPType() { 64 return 'block'; 65 } 66 67 /** 68 * 69 * @see Doku_Parser_Mode::getSort() 70 */ 71 function getSort() { 72 return 901; 73 } 74 75 /** 76 * 77 * @see Doku_Parser_Mode::connectTo() 78 */ 79 function connectTo($mode) { 80 $this->Lexer->addSpecialPattern ( '<olmap ?[^>\n]*>.*?</olmap>', $mode, 'plugin_openlayersmap_olmap' ); 81 } 82 83 /** 84 * 85 * @see DokuWiki_Syntax_Plugin::handle() 86 */ 87 function handle($match, $state, $pos, Doku_Handler $handler) { 88 // break matched cdata into its components 89 list ( $str_params, $str_points ) = explode ( '>', substr ( $match, 7, - 9 ), 2 ); 90 // get the lat/lon for adding them to the metadata (used by geotag) 91 preg_match ( '(lat[:|=]\"-?\d*\.?\d*\")', $match, $mainLat ); 92 preg_match ( '(lon[:|=]\"-?\d*\.?\d*\")', $match, $mainLon ); 93 $mainLat = substr ( $mainLat [0], 5, - 1 ); 94 $mainLon = substr ( $mainLon [0], 5, - 1 ); 95 if (!is_numeric($mainLat)) { 96 $mainLat = $this->dflt ['lat']; 97 } 98 if (!is_numeric($mainLon)) { 99 $mainLon = $this->dflt ['lon']; 100 } 101 102 $gmap = $this->_extract_params ( $str_params ); 103 $overlay = $this->_extract_points ( $str_points ); 104 $_firstimageID = ''; 105 106 $_nocache = false; 107 // choose maptype based on the specified tag 108 $imgUrl = "{{"; 109 if (stripos ( $gmap ['baselyr'], 'google' ) !== false) { 110 // Google 111 $imgUrl .= $this->_getGoogle ( $gmap, $overlay ); 112 $imgUrl .= "&.png"; 113 } elseif (stripos ( $gmap ['baselyr'], 'bing' ) !== false) { 114 // Bing 115 if (! $this->getConf ( 'bingAPIKey' )) { 116 // in case there is no Bing api key we'll use OSM 117 $_firstimageID = $this->_getStaticOSM ( $gmap, $overlay ); 118 $imgUrl .= $_firstimageID; 119 if ($this->getConf ( 'optionStaticMapGenerator' ) == 'remote') { 120 $imgUrl .= "&.png"; 121 } 122 } else { 123 // seems that Bing doesn't like the DW client, turn off caching 124 $_nocache = true; 125 $imgUrl .= $this->_getBing ( $gmap, $overlay ) . "&.png"; 126 } 127 } /* elseif (stripos ( $gmap ['baselyr'], 'mapquest' ) !== false) { 128 // MapQuest 129 if (! $this->getConf ( 'mapquestAPIKey' )) { 130 // no API key for MapQuest, use OSM 131 $_firstimageID = $this->_getStaticOSM ( $gmap, $overlay ); 132 $imgUrl .= $_firstimageID; 133 if ($this->getConf ( 'optionStaticMapGenerator' ) == 'remote') { 134 $imgUrl .= "&.png"; 135 } 136 } else { 137 $imgUrl .= $this->_getMapQuest ( $gmap, $overlay ); 138 $imgUrl .= "&.png"; 139 } 140 } */ else { 141 // default OSM 142 $_firstimageID = $this->_getStaticOSM ( $gmap, $overlay ); 143 $imgUrl .= $_firstimageID; 144 if ($this->getConf ( 'optionStaticMapGenerator' ) == 'remote') { 145 $imgUrl .= "&.png"; 146 } 147 } 148 149 // append dw p_render specific params and render 150 $imgUrl .= "?" . str_replace ( "px", "", $gmap ['width'] ) . "x" . str_replace ( "px", "", $gmap ['height'] ); 151 $imgUrl .= "&nolink"; 152 153 // add nocache option for selected services 154 if ($_nocache) { 155 $imgUrl .= "&nocache"; 156 } 157 158 $imgUrl .= " |".$gmap ['summary'] . " }}"; 159 160 // dbglog($imgUrl,"complete image tags is:"); 161 162 $mapid = $gmap ['id']; 163 // create a javascript parameter string for the map 164 $param = ''; 165 foreach ( $gmap as $key => $val ) { 166 $param .= is_numeric ( $val ) ? "$key: $val, " : "$key: '" . hsc ( $val ) . "', "; 167 } 168 if (! empty ( $param )) { 169 $param = substr ( $param, 0, - 2 ); 170 } 171 unset ( $gmap ['id'] ); 172 173 // create a javascript serialisation of the point data 174 $poi = ''; 175 $poitable = ''; 176 $rowId = 0; 177 if (! empty ( $overlay )) { 178 foreach ( $overlay as $data ) { 179 list ( $lat, $lon, $text, $angle, $opacity, $img ) = $data; 180 $rowId ++; 181 $poi .= ", {lat: $lat, lon: $lon, txt: '$text', angle: $angle, opacity: $opacity, img: '$img', rowId: $rowId}"; 182 183 if ($this->getConf ( 'displayformat' ) === 'DMS') { 184 $lat = $this->convertLat ( $lat ); 185 $lon = $this->convertLon ( $lon ); 186 } else { 187 $lat .= 'º'; 188 $lon .= 'º'; 189 } 190 191 $poitable .= ' 192 <tr> 193 <td class="rowId">' . $rowId . '</td> 194 <td class="icon"><img src="' . DOKU_BASE . 'lib/plugins/openlayersmap/icons/' . $img . '" alt="'. substr($img, 0, -4) . $this->getlang('alt_legend_poi').' " /></td> 195 <td class="lat" title="' . $this->getLang ( 'olmapPOIlatTitle' ) . '">' . $lat . '</td> 196 <td class="lon" title="' . $this->getLang ( 'olmapPOIlonTitle' ) . '">' . $lon . '</td> 197 <td class="txt">' . $text . '</td> 198 </tr>'; 199 } 200 $poi = substr ( $poi, 2 ); 201 } 202 if (! empty ( $gmap ['kmlfile'] )) { 203 $poitable .= ' 204 <tr> 205 <td class="rowId"><img src="' . DOKU_BASE . 'lib/plugins/openlayersmap/toolbar/kml_file.png" alt="KML file" /></td> 206 <td class="icon"><img src="' . DOKU_BASE . 'lib/plugins/openlayersmap/toolbar/kml_line.png" alt="' . $this->getlang('alt_legend_kml') .'" /></td> 207 <td class="txt" colspan="3">KML track: ' . $this->getFileName ( $gmap ['kmlfile'] ) . '</td> 208 </tr>'; 209 } 210 if (! empty ( $gmap ['gpxfile'] )) { 211 $poitable .= ' 212 <tr> 213 <td class="rowId"><img src="' . DOKU_BASE . 'lib/plugins/openlayersmap/toolbar/gpx_file.png" alt="GPX file" /></td> 214 <td class="icon"><img src="' . DOKU_BASE . 'lib/plugins/openlayersmap/toolbar/gpx_line.png" alt="' . $this->getlang('alt_legend_gpx') .'" /></td> 215 <td class="txt" colspan="3">GPX track: ' . $this->getFileName ( $gmap ['gpxfile'] ) . '</td> 216 </tr>'; 217 } 218 if (! empty ( $gmap ['geojsonfile'] )) { 219 $poitable .= ' 220 <tr> 221 <td class="rowId"><img src="' . DOKU_BASE . 'lib/plugins/openlayersmap/toolbar/geojson_file.png" alt="GeoJSON file" /></td> 222 <td class="icon"><img src="' . DOKU_BASE . 'lib/plugins/openlayersmap/toolbar/geojson_line.png" alt="' . $this->getlang('alt_legend_geojson') .'" /></td> 223 <td class="txt" colspan="3">GeoJSON track: ' . $this->getFileName ( $gmap ['geojsonfile'] ) . '</td> 224 </tr>'; 225 } 226 227 $js .= "{mapOpts:{" . $param . ",displayformat:'" . $this->getConf ( 'displayformat' ) . "'},poi:[$poi]};"; 228 // unescape the json 229 $poitable = stripslashes ( $poitable ); 230 231 return array ( 232 $mapid, 233 $js, 234 $mainLat, 235 $mainLon, 236 $poitable, 237 $gmap ['summary'], 238 $imgUrl, 239 $_firstimageID 240 ); 241 } 242 243 /** 244 * 245 * @see DokuWiki_Syntax_Plugin::render() 246 */ 247 function render($mode, Doku_Renderer $renderer, $data) { 248 // set to true after external scripts tags are written 249 static $initialised = false; 250 // incremented for each map tag in the page source so we can keep track of each map in this page 251 static $mapnumber = 0; 252 253 // dbglog($data, 'olmap::render() data.'); 254 list ( $mapid, $param, $mainLat, $mainLon, $poitable, $poitabledesc, $staticImgUrl, $_firstimage ) = $data; 255 256 if ($mode == 'xhtml') { 257 $olscript = ''; 258 $olEnable = false; 259 $gscript = ''; 260 $gEnable = $this->getConf ( 'enableGoogle' ); 261 $stamenEnable = $this->getConf ( 'enableStamen' ); 262 $osmEnable = $this->getConf ( 'enableOSM' ); 263 $enableBing = $this->getConf ( 'enableBing' ); 264 265 $scriptEnable = ''; 266 if (! $initialised) { 267 $initialised = true; 268 // render necessary script tags 269 if ($gEnable) { 270 $gscript = '<script type="text/javascript" src="//maps.google.com/maps/api/js?v=3.29&key='.$this->getConf ( 'googleAPIkey' ).'"></script>'; 271 } 272 $olscript = '<script type="text/javascript" src="' . DOKU_BASE . 'lib/plugins/openlayersmap/lib/OpenLayers.js"></script>'; 273 274 $scriptEnable = '<script type="text/javascript">/*<![CDATA[*/'; 275 $scriptEnable .= $olscript ? 'olEnable = true;' : 'olEnable = false;'; 276 $scriptEnable .= 'gEnable = ' . ($gEnable ? 'true' : 'false') . ';'; 277 $scriptEnable .= 'osmEnable = ' . ($osmEnable ? 'true' : 'false') . ';'; 278 $scriptEnable .= 'stamenEnable = ' . ($stamenEnable ? 'true' : 'false') . ';'; 279 $scriptEnable .= 'bEnable = ' . ($enableBing ? 'true' : 'false') . ';'; 280 $scriptEnable .= 'bApiKey="' . $this->getConf ( 'bingAPIKey' ) . '";'; 281 $scriptEnable .= 'tfApiKey="' . $this->getConf ( 'tfApiKey' ) . '";'; 282 $scriptEnable .= 'gApiKey="' . $this->getConf ( 'googleAPIkey' ) . '";'; 283 $scriptEnable .= '/*!]]>*/</script>'; 284 } 285 $renderer->doc .= "$gscript\n$olscript\n$scriptEnable"; 286 $renderer->doc .= '<div class="olMapHelp">' . $this->locale_xhtml ( "help" ) . '</div>'; 287 if ($this->getConf ( 'enableA11y' )) { 288 $renderer->doc .= '<div id="' . $mapid . '-static" class="olStaticMap">' . p_render ( $mode, p_get_instructions ( $staticImgUrl ), $info ) . '</div>'; 289 } 290 $renderer->doc .= '<div id="' . $mapid . '-clearer" class="clearer"><p> </p></div>'; 291 if ($this->getConf ( 'enableA11y' )) { 292 // render a table of the POI for the print and a11y presentation, it is hidden using javascript 293 $renderer->doc .= '<div class="olPOItableSpan" id="' . $mapid . '-table-span"> 294 <table class="olPOItable" id="' . $mapid . '-table"> 295 <caption class="olPOITblCaption">' . $this->getLang ( 'olmapPOItitle' ) . '</caption> 296 <thead class="olPOITblHeader"> 297 <tr> 298 <th class="rowId" scope="col">id</th> 299 <th class="icon" scope="col">' . $this->getLang ( 'olmapPOIicon' ) . '</th> 300 <th class="lat" scope="col" title="' . $this->getLang ( 'olmapPOIlatTitle' ) . '">' . $this->getLang ( 'olmapPOIlat' ) . '</th> 301 <th class="lon" scope="col" title="' . $this->getLang ( 'olmapPOIlonTitle' ) . '">' . $this->getLang ( 'olmapPOIlon' ) . '</th> 302 <th class="txt" scope="col">' . $this->getLang ( 'olmapPOItxt' ) . '</th> 303 </tr> 304 </thead>'; 305 if ($poitabledesc != '') { 306 $renderer->doc .= '<tfoot class="olPOITblFooter"><tr><td colspan="5">' . $poitabledesc . '</td></tr></tfoot>'; 307 } 308 $renderer->doc .= '<tbody class="olPOITblBody">' . $poitable . '</tbody> 309 </table></div>'; 310 } 311 // render inline mapscript parts 312 $renderer->doc .= '<script type="text/javascript">/*<![CDATA[*/'; 313 $renderer->doc .= " olMapData[$mapnumber] = $param /*!]]>*/</script>"; 314 $mapnumber ++; 315 return true; 316 } elseif ($mode == 'metadata') { 317 if (! (($this->dflt ['lat'] == $mainLat) && ($thisdflt ['lon'] == $mainLon))) { 318 // render geo metadata, unless they are the default 319 $renderer->meta ['geo'] ['lat'] = $mainLat; 320 $renderer->meta ['geo'] ['lon'] = $mainLon; 321 if ($geophp = &plugin_load ( 'helper', 'geophp' )) { 322 // if we have the geoPHP helper, add the geohash 323 // fails with older php versions.. $renderer->meta['geo']['geohash'] = (new Point($mainLon,$mainLat))->out('geohash'); 324 $p = new Point ( $mainLon, $mainLat ); 325 $renderer->meta ['geo'] ['geohash'] = $p->out ( 'geohash' ); 326 } 327 } 328 329 if (($this->getConf ( 'enableA11y' )) && (! empty ( $_firstimage ))) { 330 // add map local image into relation/firstimage if not already filled and when it is a local image 331 332 global $ID; 333 $rel = p_get_metadata ( $ID, 'relation', METADATA_RENDER_USING_CACHE ); 334 $img = $rel ['firstimage']; 335 if (empty ( $img ) /* || $img == $_firstimage*/){ 336 //dbglog ( $_firstimage, 'olmap::render#rendering image relation metadata for _firstimage as $img was empty or the same.' ); 337 // This seems to never work; the firstimage entry in the .meta file is empty 338 // $renderer->meta['relation']['firstimage'] = $_firstimage; 339 340 // ... and neither does this; the firstimage entry in the .meta file is empty 341 // $relation = array('relation'=>array('firstimage'=>$_firstimage)); 342 // p_set_metadata($ID, $relation, false, false); 343 344 // ... this works 345 $renderer->internalmedia ( $_firstimage, $poitabledesc ); 346 } 347 } 348 return true; 349 } 350 return false; 351 } 352 353 /** 354 * extract parameters for the map from the parameter string 355 * 356 * @param string $str_params 357 * string of key="value" pairs 358 * @return array associative array of parameters key=>value 359 */ 360 private function _extract_params($str_params) { 361 $param = array (); 362 preg_match_all ( '/(\w*)="(.*?)"/us', $str_params, $param, PREG_SET_ORDER ); 363 // parse match for instructions, break into key value pairs 364 $gmap = $this->dflt; 365 foreach ( $param as $kvpair ) { 366 list ( $match, $key, $val ) = $kvpair; 367 $key = strtolower ( $key ); 368 if (isset ( $gmap [$key] )) { 369 if ($key == 'summary') { 370 // preserve case for summary field 371 $gmap [$key] = $val; 372 } elseif ($key == 'id') { 373 // preserve case for id field 374 $gmap [$key] = $val; 375 } else { 376 $gmap [$key] = strtolower ( $val ); 377 } 378 } 379 } 380 return $gmap; 381 } 382 383 /** 384 * extract overlay points for the map from the wiki syntax data 385 * 386 * @param string $str_points 387 * multi-line string of lat,lon,text triplets 388 * @return array multi-dimensional array of lat,lon,text triplets 389 */ 390 private function _extract_points($str_points) { 391 $point = array (); 392 // preg_match_all('/^([+-]?[0-9].*?),\s*([+-]?[0-9].*?),(.*?),(.*?),(.*?),(.*)$/um', $str_points, $point, PREG_SET_ORDER); 393 /* 394 * group 1: ([+-]?[0-9]+(?:\.[0-9]*)?) group 2: ([+-]?[0-9]+(?:\.[0-9]*)?) group 3: (.*?) group 4: (.*?) group 5: (.*?) group 6: (.*) 395 */ 396 preg_match_all ( '/^([+-]?[0-9]+(?:\.[0-9]*)?),\s*([+-]?[0-9]+(?:\.[0-9]*)?),(.*?),(.*?),(.*?),(.*)$/um', $str_points, $point, PREG_SET_ORDER ); 397 // create poi array 398 $overlay = array (); 399 foreach ( $point as $pt ) { 400 list ( $match, $lat, $lon, $angle, $opacity, $img, $text ) = $pt; 401 $lat = is_numeric ( $lat ) ? $lat : 0; 402 $lon = is_numeric ( $lon ) ? $lon : 0; 403 $angle = is_numeric ( $angle ) ? $angle : 0; 404 $opacity = is_numeric ( $opacity ) ? $opacity : 0.8; 405 // TODO validate using exist & set up default img? 406 $img = trim ( $img ); 407 $text = p_get_instructions ( $text ); 408 // dbg ( $text ); 409 $text = p_render ( "xhtml", $text, $info ); 410 // dbg ( $text ); 411 $text = addslashes ( str_replace ( "\n", "", $text ) ); 412 $overlay [] = array ( 413 $lat, 414 $lon, 415 $text, 416 $angle, 417 $opacity, 418 $img 419 ); 420 } 421 return $overlay; 422 } 423 424 /** 425 * Create a MapQuest static map API image url. 426 * 427 * @param array $gmap 428 * @param array $overlay 429 */ 430 /* 431 private function _getMapQuest($gmap, $overlay) { 432 $sUrl = $this->getConf ( 'iconUrlOverload' ); 433 if (! $sUrl) { 434 $sUrl = DOKU_URL; 435 } 436 switch ($gmap ['baselyr']) { 437 case 'mapquest hybrid' : 438 $maptype = 'hyb'; 439 break; 440 case 'mapquest sat' : 441 // because sat coverage is very limited use 'hyb' instead of 'sat' so we don't get a blank map 442 $maptype = 'hyb'; 443 break; 444 case 'mapquest road' : 445 default : 446 $maptype = 'map'; 447 break; 448 } 449 $imgUrl = "http://open.mapquestapi.com/staticmap/v4/getmap?declutter=true&"; 450 if (count ( $overlay ) < 1) { 451 $imgUrl .= "?center=" . $gmap ['lat'] . "," . $gmap ['lon']; 452 // max level for mapquest is 16 453 if ($gmap ['zoom'] > 16) { 454 $imgUrl .= "&zoom=16"; 455 } else { 456 $imgUrl .= "&zoom=" . $gmap ['zoom']; 457 } 458 } 459 // use bestfit instead of center/zoom, needs upperleft/lowerright corners 460 // $bbox=$this->_calcBBOX($overlay, $gmap['lat'], $gmap['lon']); 461 // $imgUrl .= "bestfit=".$bbox['minlat'].",".$bbox['maxlon'].",".$bbox['maxlat'].",".$bbox['minlon']; 462 463 // TODO declutter option works well for square maps but not for rectangular, maybe compensate for that or compensate the mbr.. 464 $imgUrl .= "&size=" . str_replace ( "px", "", $gmap ['width'] ) . "," . str_replace ( "px", "", $gmap ['height'] ); 465 466 // TODO mapquest allows using one image url with a multiplier $NUMBER eg: 467 // $NUMBER = 2 468 // $imgUrl .= DOKU_URL."/".DOKU_PLUGIN."/".getPluginName()."/icons/".$img.",$NUMBER,C,".$lat1.",".$lon1.",0,0,0,0,C,".$lat2.",".$lon2.",0,0,0,0"; 469 if (! empty ( $overlay )) { 470 $imgUrl .= "&xis="; 471 foreach ( $overlay as $data ) { 472 list ( $lat, $lon, $text, $angle, $opacity, $img ) = $data; 473 // $imgUrl .= $sUrl."lib/plugins/openlayersmap/icons/".$img.",1,C,".$lat.",".$lon.",0,0,0,0,"; 474 $imgUrl .= $sUrl . "lib/plugins/openlayersmap/icons/" . $img . ",1,C," . $lat . "," . $lon . ","; 475 } 476 $imgUrl = substr ( $imgUrl, 0, - 1 ); 477 } 478 $imgUrl .= "&imageType=png&type=" . $maptype; 479 $imgUrl .= "&key=".$this->getConf ( 'mapquestAPIKey' ); 480 // dbglog($imgUrl,'syntax_plugin_openlayersmap_olmap::_getMapQuest: MapQuest image url is:'); 481 return $imgUrl; 482 } 483 */ 484 485 /** 486 * Create a Google maps static image url w/ the poi. 487 * 488 * @param array $gmap 489 * @param array $overlay 490 */ 491 private function _getGoogle($gmap, $overlay) { 492 $sUrl = $this->getConf ( 'iconUrlOverload' ); 493 if (! $sUrl) { 494 $sUrl = DOKU_URL; 495 } 496 switch ($gmap ['baselyr']) { 497 case 'google hybrid' : 498 $maptype = 'hybrid'; 499 break; 500 case 'google sat' : 501 $maptype = 'satellite'; 502 break; 503 case 'terrain' : 504 case 'google relief' : 505 $maptype = 'terrain'; 506 break; 507 case 'google road' : 508 default : 509 $maptype = 'roadmap'; 510 break; 511 } 512 // TODO maybe use viewport / visible instead of center/zoom, 513 // see: https://developers.google.com/maps/documentation/staticmaps/index#Viewports 514 // http://maps.google.com/maps/api/staticmap?center=51.565690,5.456756&zoom=16&size=600x400&markers=icon:http://wild-water.nl/dokuwiki/lib/plugins/openlayersmap/icons/marker.png|label:1|51.565690,5.456756&markers=icon:http://wild-water.nl/dokuwiki/lib/plugins/openlayersmap/icons/marker-blue.png|51.566197,5.458966|label:2&markers=icon:http://wild-water.nl/dokuwiki/lib/plugins/openlayersmap/icons/parking.png|51.567177,5.457909|label:3&markers=icon:http://wild-water.nl/dokuwiki/lib/plugins/openlayersmap/icons/parking.png|51.566283,5.457330|label:4&markers=icon:http://wild-water.nl/dokuwiki/lib/plugins/openlayersmap/icons/parking.png|51.565630,5.457695|label:5&sensor=false&format=png&maptype=roadmap 515 $imgUrl = "http://maps.googleapis.com/maps/api/staticmap?"; 516 $imgUrl .= "&size=" . str_replace ( "px", "", $gmap ['width'] ) . "x" . str_replace ( "px", "", $gmap ['height'] ); 517 //if (!$this->getConf( 'autoZoomMap')) { // no need for center & zoom params } 518 $imgUrl .= "¢er=" . $gmap ['lat'] . "," . $gmap ['lon']; 519 // max is 21 (== building scale), but that's overkill.. 520 if ($gmap ['zoom'] > 17) { 521 $imgUrl .= "&zoom=17"; 522 } else { 523 $imgUrl .= "&zoom=" . $gmap ['zoom']; 524 } 525 if (! empty ( $overlay )) { 526 $rowId = 0; 527 foreach ( $overlay as $data ) { 528 list ( $lat, $lon, $text, $angle, $opacity, $img ) = $data; 529 $imgUrl .= "&markers=icon%3a" . $sUrl . "lib/plugins/openlayersmap/icons/" . $img . "%7c" . $lat . "," . $lon . "%7clabel%3a" . ++ $rowId; 530 } 531 } 532 $imgUrl .= "&format=png&maptype=" . $maptype; 533 global $conf; 534 $imgUrl .= "&language=" . $conf ['lang']; 535 if ($this->getConf( 'googleAPIkey' )) { 536 $imgUrl .= "&key=" . $this->getConf( 'googleAPIkey' ); 537 } 538 // dbglog($imgUrl,'syntax_plugin_openlayersmap_olmap::_getGoogle: Google image url is:'); 539 return $imgUrl; 540 } 541 542 /** 543 * Create a Bing maps static image url w/ the poi. 544 * 545 * @param array $gmap 546 * @param array $overlay 547 */ 548 private function _getBing($gmap, $overlay) { 549 switch ($gmap ['baselyr']) { 550 case 've hybrid' : 551 case 'bing hybrid' : 552 $maptype = 'AerialWithLabels'; 553 break; 554 case 've sat' : 555 case 'bing sat' : 556 $maptype = 'Aerial'; 557 break; 558 case 've normal' : 559 case 've road' : 560 case 've' : 561 case 'bing road' : 562 default : 563 $maptype = 'Road'; 564 break; 565 } 566 $imgUrl = "http://dev.virtualearth.net/REST/v1/Imagery/Map/" . $maptype;// . "/"; 567 if ($this->getConf ( 'autoZoomMap' )) { 568 $bbox = $this->_calcBBOX ( $overlay, $gmap ['lat'], $gmap ['lon'] ); 569 //$imgUrl .= "?ma=" . $bbox ['minlat'] . "," . $bbox ['minlon'] . "," . $bbox ['maxlat'] . "," . $bbox ['maxlon']; 570 $imgUrl .= "?ma=" . $bbox ['minlat'] . "%2C" . $bbox ['minlon'] . "%2C" . $bbox ['maxlat'] . "%2C" . $bbox ['maxlon']; 571 $imgUrl .= "&dcl=1"; 572 } 573 if (strpos ( $imgUrl, "?" ) === false) 574 $imgUrl .= "?"; 575 576 //$imgUrl .= "&ms=" . str_replace ( "px", "", $gmap ['width'] ) . "," . str_replace ( "px", "", $gmap ['height'] ); 577 $imgUrl .= "&ms=" . str_replace ( "px", "", $gmap ['width'] ) . "%2C" . str_replace ( "px", "", $gmap ['height'] ); 578 $imgUrl .= "&key=" . $this->getConf ( 'bingAPIKey' ); 579 if (! empty ( $overlay )) { 580 $rowId = 0; 581 foreach ( $overlay as $data ) { 582 list ( $lat, $lon, $text, $angle, $opacity, $img ) = $data; 583 // TODO icon style lookup, see: http://msdn.microsoft.com/en-us/library/ff701719.aspx for iconStyle 584 $iconStyle = 32; 585 $rowId ++; 586 // NOTE: the max number of pushpins is 18! or we have to use POST (http://msdn.microsoft.com/en-us/library/ff701724.aspx) 587 if ($rowId == 18) { 588 break; 589 } 590 //$imgUrl .= "&pp=$lat,$lon;$iconStyle;$rowId"; 591 $imgUrl .= "&pp=$lat%2C$lon%3B$iconStyle%3B$rowId"; 592 593 } 594 } 595 global $conf; 596 $imgUrl .= "&fmt=png"; 597 $imgUrl .= "&c=" . $conf ['lang']; 598 // dbglog($imgUrl,'syntax_plugin_openlayersmap_olmap::_getBing: bing image url is:'); 599 return $imgUrl; 600 } 601 602 /** 603 * Create a static OSM map image url w/ the poi from http://staticmap.openstreetmap.de (staticMapLite) 604 * use http://staticmap.openstreetmap.de "staticMapLite" or a local version 605 * 606 * @param array $gmap 607 * @param array $overlay 608 * 609 * @todo implementation for http://ojw.dev.openstreetmap.org/StaticMapDev/ 610 */ 611 private function _getStaticOSM($gmap, $overlay) { 612 global $conf; 613 614 if ($this->getConf ( 'optionStaticMapGenerator' ) == 'local') { 615 // using local basemap composer 616 if (! $myMap = &plugin_load ( 'helper', 'openlayersmap_staticmap' )) { 617 dbglog ( $myMap, 'syntax_plugin_openlayersmap_olmap::_getStaticOSM: openlayersmap_staticmap plugin is not available.' ); 618 } 619 if (! $geophp = &plugin_load ( 'helper', 'geophp' )) { 620 dbglog ( $geophp, 'syntax_plugin_openlayersmap_olmap::_getStaticOSM: geophp plugin is not available.' ); 621 } 622 $size = str_replace ( "px", "", $gmap ['width'] ) . "x" . str_replace ( "px", "", $gmap ['height'] ); 623 624 $markers = array(); 625 if (! empty ( $overlay )) { 626 foreach ( $overlay as $data ) { 627 list ( $lat, $lon, $text, $angle, $opacity, $img ) = $data; 628 $iconStyle = substr ( $img, 0, strlen ( $img ) - 4 ); 629 $markers [] = array ( 630 'lat' => $lat, 631 'lon' => $lon, 632 'type' => $iconStyle 633 ); 634 } 635 } 636 637 $apikey = ''; 638 switch ($gmap ['baselyr']) { 639 case 'mapnik' : 640 case 'openstreetmap' : 641 $maptype = 'openstreetmap'; 642 break; 643 case 'transport' : 644 $maptype = 'transport'; 645 $apikey = $this->getConf ( 'tfApiKey' ); 646 break; 647 case 'landscape' : 648 $maptype = 'landscape'; 649 $apikey = $this->getConf ( 'tfApiKey' ); 650 break; 651 case 'outdoors' : 652 $maptype = 'outdoors'; 653 $apikey = $this->getConf ( 'tfApiKey' ); 654 break; 655 case 'cycle map' : 656 $maptype = 'cycle'; 657 $apikey = $this->getConf ( 'tfApiKey' ); 658 break; 659 case 'hike and bike map' : 660 $maptype = 'hikeandbike'; 661 break; 662 case 'mapquest hybrid' : 663 case 'mapquest road' : 664 case 'mapquest sat' : 665 $maptype = 'mapquest'; 666 break; 667 default : 668 $maptype = ''; 669 break; 670 } 671 672 $result = $myMap->getMap ( $gmap ['lat'], $gmap ['lon'], $gmap ['zoom'], $size, $maptype, $markers, $gmap ['gpxfile'], $gmap ['kmlfile'], $gmap ['geojsonfile'] ); 673 } else { 674 // using external basemap composer 675 676 // http://staticmap.openstreetmap.de/staticmap.php?center=47.000622235634,10.117187497601&zoom=5&size=500x350 677 // &markers=48.999812532766,8.3593749976708,lightblue1|43.154850037315,17.499999997306,lightblue1|49.487527053077,10.820312497573,ltblu-pushpin|47.951071133739,15.917968747369,ol-marker|47.921629720114,18.027343747285,ol-marker-gold|47.951071133739,19.257812497236,ol-marker-blue|47.180141361692,19.257812497236,ol-marker-green 678 $imgUrl = "http://staticmap.openstreetmap.de/staticmap.php"; 679 $imgUrl .= "?center=" . $gmap ['lat'] . "," . $gmap ['lon']; 680 $imgUrl .= "&size=" . str_replace ( "px", "", $gmap ['width'] ) . "x" . str_replace ( "px", "", $gmap ['height'] ); 681 682 if ($gmap ['zoom'] > 16) { 683 // actually this could even be 18, but that seems overkill 684 $imgUrl .= "&zoom=16"; 685 } else { 686 $imgUrl .= "&zoom=" . $gmap ['zoom']; 687 } 688 689 if (! empty ( $overlay )) { 690 $rowId = 0; 691 $imgUrl .= "&markers="; 692 foreach ( $overlay as $data ) { 693 list ( $lat, $lon, $text, $angle, $opacity, $img ) = $data; 694 $rowId ++; 695 $iconStyle = "lightblue$rowId"; 696 $imgUrl .= "$lat,$lon,$iconStyle%7c"; 697 } 698 $imgUrl = substr ( $imgUrl, 0, - 3 ); 699 } 700 701 $result = $imgUrl; 702 } 703 // dbglog ( $result, 'syntax_plugin_openlayersmap_olmap::_getStaticOSM: osm image url is:' ); 704 return $result; 705 } 706 707 /** 708 * Calculate the minimum bbox for a start location + poi. 709 * 710 * @param array $overlay 711 * multi-dimensional array of array($lat, $lon, $text, $angle, $opacity, $img) 712 * @param float $lat 713 * latitude for map center 714 * @param float $lon 715 * longitude for map center 716 * @return multitype:float array describing the mbr and center point 717 */ 718 private function _calcBBOX($overlay, $lat, $lon) { 719 $lats = array($lat); 720 $lons = array($lon); 721 foreach ( $overlay as $data ) { 722 list ( $lat, $lon, $text, $angle, $opacity, $img ) = $data; 723 $lats [] = $lat; 724 $lons [] = $lon; 725 } 726 sort ( $lats ); 727 sort ( $lons ); 728 // TODO: make edge/wrap around cases work 729 $centerlat = $lats [0] + ($lats [count ( $lats ) - 1] - $lats [0]); 730 $centerlon = $lons [0] + ($lons [count ( $lats ) - 1] - $lons [0]); 731 return array ( 732 'minlat' => $lats [0], 733 'minlon' => $lons [0], 734 'maxlat' => $lats [count ( $lats ) - 1], 735 'maxlon' => $lons [count ( $lats ) - 1], 736 'centerlat' => $centerlat, 737 'centerlon' => $centerlon 738 ); 739 } 740 741 /** 742 * Figures out the base filename of a media path. 743 * 744 * @param String $mediaLink 745 */ 746 private function getFileName($mediaLink) { 747 $mediaLink = str_replace ( '[[', '', $mediaLink ); 748 $mediaLink = str_replace ( ']]', '', $mediaLink ); 749 $mediaLink = substr ( $mediaLink, 0, - 4 ); 750 $parts = explode ( ':', $mediaLink ); 751 $mediaLink = end ( $parts ); 752 return str_replace ( '_', ' ', $mediaLink ); 753 } 754 755 /** 756 * Convert decimal degrees to degrees, minutes, seconds format 757 * 758 * @todo move this into a shared library 759 * @param float $decimaldegrees 760 * @return string dms 761 */ 762 private function _convertDDtoDMS($decimaldegrees) { 763 $dms = floor ( $decimaldegrees ); 764 $secs = ($decimaldegrees - $dms) * 3600; 765 $min = floor ( $secs / 60 ); 766 $sec = round ( $secs - ($min * 60), 3 ); 767 $dms .= 'º' . $min . '\'' . $sec . '"'; 768 return $dms; 769 } 770 771 /** 772 * convert latitude in decimal degrees to DMS+hemisphere. 773 * 774 * @todo move this into a shared library 775 * @param float $decimaldegrees 776 * @return string 777 */ 778 private function convertLat($decimaldegrees) { 779 if (strpos ( $decimaldegrees, '-' ) !== false) { 780 $latPos = "S"; 781 } else { 782 $latPos = "N"; 783 } 784 $dms = $this->_convertDDtoDMS ( abs ( floatval ( $decimaldegrees ) ) ); 785 return hsc ( $dms . $latPos ); 786 } 787 788 /** 789 * convert longitude in decimal degrees to DMS+hemisphere. 790 * 791 * @todo move this into a shared library 792 * @param float $decimaldegrees 793 * @return string 794 */ 795 private function convertLon($decimaldegrees) { 796 if (strpos ( $decimaldegrees, '-' ) !== false) { 797 $lonPos = "W"; 798 } else { 799 $lonPos = "E"; 800 } 801 $dms = $this->_convertDDtoDMS ( abs ( floatval ( $decimaldegrees ) ) ); 802 return hsc ( $dms . $lonPos ); 803 } 804} 805