xref: /plugin/openlayersmap/syntax/olmap.php (revision 3f760703f2119486a3bdb7c64e89d61345f9ad6a)
138a47c60SMark Prins<?php
238a47c60SMark Prins/*
357f8d5bbSMark Prins * Copyright (c) 2008-2021 Mark C. Prins <mprins@users.sf.net>
438a47c60SMark Prins *
538a47c60SMark Prins * Permission to use, copy, modify, and distribute this software for any
638a47c60SMark Prins * purpose with or without fee is hereby granted, provided that the above
738a47c60SMark Prins * copyright notice and this permission notice appear in all copies.
838a47c60SMark Prins *
938a47c60SMark Prins * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1038a47c60SMark Prins * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1138a47c60SMark Prins * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1238a47c60SMark Prins * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1338a47c60SMark Prins * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1438a47c60SMark Prins * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1538a47c60SMark Prins * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1657f8d5bbSMark Prins *
1757f8d5bbSMark Prins * @phpcs:disable Squiz.Classes.ValidClassName.NotCamelCaps
1838a47c60SMark Prins */
1938a47c60SMark Prins
203ebe658bSMark Prinsuse geoPHP\Geometry\Point;
213ebe658bSMark Prins
2238a47c60SMark Prins/**
23cc74a83cSMark Prins * DokuWiki Plugin openlayersmap (Syntax Component).
24cc74a83cSMark Prins * Provides for display of an OpenLayers based map in a wiki page.
25cc74a83cSMark Prins *
26cc74a83cSMark Prins * @author Mark Prins
2738a47c60SMark Prins */
2838a47c60SMark Prinsclass syntax_plugin_openlayersmap_olmap extends DokuWiki_Syntax_Plugin {
29fcf646d2SMark Prins
301c640875SMark Prins    /**
311c640875SMark Prins     * defaults of the known attributes of the olmap tag.
321c640875SMark Prins     */
3338a47c60SMark Prins    private $dflt = array(
3438a47c60SMark Prins        'id'            => 'olmap',
3538a47c60SMark Prins        'width'         => '550px',
3638a47c60SMark Prins        'height'        => '450px',
3738a47c60SMark Prins        'lat'           => 50.0,
3838a47c60SMark Prins        'lon'           => 5.1,
3938a47c60SMark Prins        'zoom'          => 12,
40c8eb1362SMark Prins        'autozoom'      => 1,
4138a47c60SMark Prins        'controls'      => true,
4238a47c60SMark Prins        'baselyr'       => 'OpenStreetMap',
4338a47c60SMark Prins        'gpxfile'       => '',
4445c50327SMark Prins        'kmlfile'       => '',
456914b920SMark Prins        'geojsonfile'   => '',
4645c50327SMark Prins        'summary'       => ''
4738a47c60SMark Prins    );
4838a47c60SMark Prins
4938a47c60SMark Prins    /**
501c640875SMark Prins     *
51cc74a83cSMark Prins     * @see DokuWiki_Syntax_Plugin::getType()
5238a47c60SMark Prins     */
5357f8d5bbSMark Prins    public function getType(): string {
5475c98788SMark Prins        return 'substition';
5575c98788SMark Prins    }
5638a47c60SMark Prins
5738a47c60SMark Prins    /**
581c640875SMark Prins     *
59cc74a83cSMark Prins     * @see DokuWiki_Syntax_Plugin::getPType()
6038a47c60SMark Prins     */
6157f8d5bbSMark Prins    public function getPType(): string {
6275c98788SMark Prins        return 'block';
6375c98788SMark Prins    }
6438a47c60SMark Prins
6538a47c60SMark Prins    /**
661c640875SMark Prins     *
67cc74a83cSMark Prins     * @see Doku_Parser_Mode::getSort()
6838a47c60SMark Prins     */
6957f8d5bbSMark Prins    public function getSort(): int {
7075c98788SMark Prins        return 901;
7175c98788SMark Prins    }
72fc16f3cdSMark Prins
7338a47c60SMark Prins    /**
741c640875SMark Prins     *
75cc74a83cSMark Prins     * @see Doku_Parser_Mode::connectTo()
7638a47c60SMark Prins     */
7757f8d5bbSMark Prins    public function connectTo($mode) {
7857f8d5bbSMark Prins        $this->Lexer->addSpecialPattern(
7957f8d5bbSMark Prins            '<olmap ?[^>\n]*>.*?</olmap>', $mode,
8057f8d5bbSMark Prins            'plugin_openlayersmap_olmap'
8157f8d5bbSMark Prins        );
8238a47c60SMark Prins    }
83fc16f3cdSMark Prins
8438a47c60SMark Prins    /**
851c640875SMark Prins     *
86cc74a83cSMark Prins     * @see DokuWiki_Syntax_Plugin::handle()
8738a47c60SMark Prins     */
8857f8d5bbSMark Prins    public function handle($match, $state, $pos, Doku_Handler $handler): array {
89*3f760703SMark Prins        // break matched data into its components
90*3f760703SMark Prins        $_tag       = explode('>', substr($match, 7, -9), 2);
91*3f760703SMark Prins        $str_params = $_tag[0];
92*3f760703SMark Prins        if(array_key_exists(1, $_tag)) {
93*3f760703SMark Prins            $str_points = $_tag[1];
94*3f760703SMark Prins        } else {
95*3f760703SMark Prins            $str_points = '';
96*3f760703SMark Prins        }
97554f43b5SMark Prins        // get the lat/lon for adding them to the metadata (used by geotag)
98d2f4772aSMark Prins        preg_match('(lat[:|=]\"-?\d*\.?\d*\")', $match, $mainLat);
99d2f4772aSMark Prins        preg_match('(lon[:|=]\"-?\d*\.?\d*\")', $match, $mainLon);
100554f43b5SMark Prins        $mainLat = substr($mainLat [0], 5, -1);
101554f43b5SMark Prins        $mainLon = substr($mainLon [0], 5, -1);
102d2f4772aSMark Prins        if(!is_numeric($mainLat)) {
103d2f4772aSMark Prins            $mainLat = $this->dflt ['lat'];
104d2f4772aSMark Prins        }
105d2f4772aSMark Prins        if(!is_numeric($mainLon)) {
106d2f4772aSMark Prins            $mainLon = $this->dflt ['lon'];
107d2f4772aSMark Prins        }
10838a47c60SMark Prins
10957f8d5bbSMark Prins        $gmap          = $this->extractParams($str_params);
11057f8d5bbSMark Prins        $overlay = $this->extractPoints($str_points);
111fc16f3cdSMark Prins        $_firstimageID = '';
11238a47c60SMark Prins
1138e7c4263SMark Prins        $_nocache = false;
114807d36baSMark Prins        // choose maptype based on the specified tag
115628e43ccSMark Prins        $imgUrl = "{{";
116585afb49SMark Prins        if(stripos($gmap ['baselyr'], 'google') !== false) {
1178e7c4263SMark Prins            // Google
11857f8d5bbSMark Prins            $imgUrl .= $this->getGoogle($gmap, $overlay);
1198e7c4263SMark Prins            $imgUrl .= "&.png";
120585afb49SMark Prins        } elseif(stripos($gmap ['baselyr'], 'bing') !== false) {
1218e7c4263SMark Prins            // Bing
122d974ea02SMark Prins            if(!$this->getConf('bingAPIKey')) {
123d974ea02SMark Prins                // in case there is no Bing api key we'll use OSM
12457f8d5bbSMark Prins                $_firstimageID = $this->getStaticOSM($gmap, $overlay);
125d974ea02SMark Prins                $imgUrl        .= $_firstimageID;
126628e43ccSMark Prins                if($this->getConf('optionStaticMapGenerator') == 'remote') {
127628e43ccSMark Prins                    $imgUrl .= "&.png";
128d974ea02SMark Prins                }
129d974ea02SMark Prins            } else {
1308e7c4263SMark Prins                // seems that Bing doesn't like the DW client, turn off caching
1318e7c4263SMark Prins                $_nocache = true;
13257f8d5bbSMark Prins                $imgUrl   .= $this->getBing($gmap, $overlay) . "&.png";
133d974ea02SMark Prins            }
134e72390dbSMark Prins        } /* elseif (stripos ( $gmap ['baselyr'], 'mapquest' ) !== false) {
1358e7c4263SMark Prins            // MapQuest
1368e7c4263SMark Prins            if (! $this->getConf ( 'mapquestAPIKey' )) {
1378e7c4263SMark Prins                // no API key for MapQuest, use OSM
13857f8d5bbSMark Prins                $_firstimageID = $this->getStaticOSM ( $gmap, $overlay );
139fc16f3cdSMark Prins                $imgUrl .= $_firstimageID;
1408e7c4263SMark Prins                if ($this->getConf ( 'optionStaticMapGenerator' ) == 'remote') {
1418e7c4263SMark Prins                    $imgUrl .= "&.png";
142628e43ccSMark Prins                }
14363037f21SMark Prins            } else {
1448e7c4263SMark Prins                $imgUrl .= $this->_getMapQuest ( $gmap, $overlay );
1458e7c4263SMark Prins                $imgUrl .= "&.png";
1468e7c4263SMark Prins            }
147e72390dbSMark Prins        } */ else {
1488e7c4263SMark Prins            // default OSM
14957f8d5bbSMark Prins            $_firstimageID = $this->getStaticOSM($gmap, $overlay);
150fc16f3cdSMark Prins            $imgUrl        .= $_firstimageID;
15153bfe4a3SMark Prins            if($this->getConf('optionStaticMapGenerator') == 'remote') {
15253bfe4a3SMark Prins                $imgUrl .= "&.png";
15353bfe4a3SMark Prins            }
15487d958d4SMark Prins        }
15587d958d4SMark Prins
156628e43ccSMark Prins        // append dw p_render specific params and render
15757f8d5bbSMark Prins        $imgUrl .= "?" . str_replace("px", "", $gmap ['width']) . "x"
15857f8d5bbSMark Prins            . str_replace("px", "", $gmap ['height']);
1596ba8d085SMark Prins        $imgUrl .= "&nolink";
1608e7c4263SMark Prins
1618e7c4263SMark Prins        // add nocache option for selected services
1628e7c4263SMark Prins        if($_nocache) {
1638e7c4263SMark Prins            $imgUrl .= "&nocache";
1648e7c4263SMark Prins        }
1658e7c4263SMark Prins
166fcd79b50SMark Prins        $imgUrl .= " |" . $gmap ['summary'] . " }}";
167fcd79b50SMark Prins
1688e7c4263SMark Prins        // dbglog($imgUrl,"complete image tags is:");
1698e7c4263SMark Prins
17038a47c60SMark Prins        $mapid = $gmap ['id'];
17138a47c60SMark Prins        // create a javascript parameter string for the map
17238a47c60SMark Prins        $param = '';
17338a47c60SMark Prins        foreach($gmap as $key => $val) {
17438a47c60SMark Prins            $param .= is_numeric($val) ? "$key: $val, " : "$key: '" . hsc($val) . "', ";
17538a47c60SMark Prins        }
17638a47c60SMark Prins        if(!empty ($param)) {
17745c50327SMark Prins            $param = substr($param, 0, -2);
17838a47c60SMark Prins        }
17938a47c60SMark Prins        unset ($gmap ['id']);
18038a47c60SMark Prins
18138a47c60SMark Prins        // create a javascript serialisation of the point data
18238a47c60SMark Prins        $poi      = '';
18345c50327SMark Prins        $poitable = '';
18445c50327SMark Prins        $rowId    = 0;
18538a47c60SMark Prins        if(!empty ($overlay)) {
18638a47c60SMark Prins            foreach($overlay as $data) {
18738a47c60SMark Prins                list ($lat, $lon, $text, $angle, $opacity, $img) = $data;
18845c50327SMark Prins                $rowId++;
18945c50327SMark Prins                $poi .= ", {lat:$lat,lon:$lon,txt:'$text',angle:$angle,opacity:$opacity,img:'$img',rowId: $rowId}";
1908c4eb2fdSMark Prins
1918c4eb2fdSMark Prins                if($this->getConf('displayformat') === 'DMS') {
1928c4eb2fdSMark Prins                    $lat = $this->convertLat($lat);
1938c4eb2fdSMark Prins                    $lon = $this->convertLon($lon);
1948c4eb2fdSMark Prins                } else {
1958c4eb2fdSMark Prins                    $lat .= 'º';
1968c4eb2fdSMark Prins                    $lon .= 'º';
1978c4eb2fdSMark Prins                }
1988c4eb2fdSMark Prins
199a757236dSMark Prins                $poitable .= '
200a757236dSMark Prins                    <tr>
201a757236dSMark Prins                    <td class="rowId">' . $rowId . '</td>
20257f8d5bbSMark Prins                    <td class="icon"><img src="' . DOKU_BASE . 'lib/plugins/openlayersmap/icons/' . $img . '" alt="'
20357f8d5bbSMark Prins                    . substr($img, 0, -4) . $this->getlang('alt_legend_poi') . '" /></td>
204a57aaf07SMark Prins                    <td class="lat" title="' . $this->getLang('olmapPOIlatTitle') . '">' . $lat . '</td>
205a57aaf07SMark Prins                    <td class="lon" title="' . $this->getLang('olmapPOIlonTitle') . '">' . $lon . '</td>
206a757236dSMark Prins                    <td class="txt">' . $text . '</td>
207a757236dSMark Prins                    </tr>';
20838a47c60SMark Prins            }
20945c50327SMark Prins            $poi = substr($poi, 2);
21038a47c60SMark Prins        }
211e61425c7SMark Prins        if(!empty ($gmap ['kmlfile'])) {
212e61425c7SMark Prins            $poitable .= '
213e61425c7SMark Prins                    <tr>
21457f8d5bbSMark Prins                    <td class="rowId"><img src="' . DOKU_BASE
21557f8d5bbSMark Prins                . 'lib/plugins/openlayersmap/toolbar/kml_file.png" alt="KML file" /></td>
21657f8d5bbSMark Prins                    <td class="icon"><img src="' . DOKU_BASE . 'lib/plugins/openlayersmap/toolbar/kml_line.png" alt="'
21757f8d5bbSMark Prins                . $this->getlang('alt_legend_kml') . '" /></td>
218cc74a83cSMark Prins                    <td class="txt" colspan="3">KML track: ' . $this->getFileName($gmap ['kmlfile']) . '</td>
219e61425c7SMark Prins                    </tr>';
220e61425c7SMark Prins        }
221e61425c7SMark Prins        if(!empty ($gmap ['gpxfile'])) {
222e61425c7SMark Prins            $poitable .= '
223e61425c7SMark Prins                    <tr>
22457f8d5bbSMark Prins                    <td class="rowId"><img src="' . DOKU_BASE
22557f8d5bbSMark Prins                . 'lib/plugins/openlayersmap/toolbar/gpx_file.png" alt="GPX file" /></td>
22657f8d5bbSMark Prins                    <td class="icon"><img src="' . DOKU_BASE
22757f8d5bbSMark Prins                . 'lib/plugins/openlayersmap/toolbar/gpx_line.png" alt="'
22857f8d5bbSMark Prins                . $this->getlang('alt_legend_gpx') . '" /></td>
229cc74a83cSMark Prins                    <td class="txt" colspan="3">GPX track: ' . $this->getFileName($gmap ['gpxfile']) . '</td>
230e61425c7SMark Prins                    </tr>';
231e61425c7SMark Prins        }
2326914b920SMark Prins        if(!empty ($gmap ['geojsonfile'])) {
2336914b920SMark Prins            $poitable .= '
2346914b920SMark Prins                    <tr>
23557f8d5bbSMark Prins                    <td class="rowId"><img src="' . DOKU_BASE
23657f8d5bbSMark Prins                . 'lib/plugins/openlayersmap/toolbar/geojson_file.png" alt="GeoJSON file" /></td>
23757f8d5bbSMark Prins                    <td class="icon"><img src="' . DOKU_BASE
23857f8d5bbSMark Prins                . 'lib/plugins/openlayersmap/toolbar/geojson_line.png" alt="'
23957f8d5bbSMark Prins                . $this->getlang('alt_legend_geojson') . '" /></td>
2406914b920SMark Prins                    <td class="txt" colspan="3">GeoJSON track: ' . $this->getFileName($gmap ['geojsonfile']) . '</td>
2416914b920SMark Prins                    </tr>';
2426914b920SMark Prins        }
243e61425c7SMark Prins
244c8eb1362SMark Prins        $autozoom = empty ($gmap ['autozoom']) ? $this->getConf('autoZoomMap') : $gmap ['autozoom'];
24557f8d5bbSMark Prins        $js       = "{mapOpts: {" . $param . ", displayformat: '" . $this->getConf('displayformat')
24657f8d5bbSMark Prins            . "', autozoom: " . $autozoom . "}, poi: [$poi]};";
247a757236dSMark Prins        // unescape the json
248a757236dSMark Prins        $poitable = stripslashes($poitable);
24938a47c60SMark Prins
2501c640875SMark Prins        return array(
2511c640875SMark Prins            $mapid,
2521c640875SMark Prins            $js,
2531c640875SMark Prins            $mainLat,
2541c640875SMark Prins            $mainLon,
2551c640875SMark Prins            $poitable,
2561c640875SMark Prins            $gmap ['summary'],
2571c640875SMark Prins            $imgUrl,
2581c640875SMark Prins            $_firstimageID
2591c640875SMark Prins        );
26038a47c60SMark Prins    }
26138a47c60SMark Prins
26238a47c60SMark Prins    /**
26338a47c60SMark Prins     * extract parameters for the map from the parameter string
26438a47c60SMark Prins     *
2651c640875SMark Prins     * @param string $str_params
2661c640875SMark Prins     *            string of key="value" pairs
26738a47c60SMark Prins     * @return array associative array of parameters key=>value
26838a47c60SMark Prins     */
26957f8d5bbSMark Prins    private function extractParams(string $str_params): array {
27038a47c60SMark Prins        $param = array();
27138a47c60SMark Prins        preg_match_all('/(\w*)="(.*?)"/us', $str_params, $param, PREG_SET_ORDER);
27238a47c60SMark Prins        // parse match for instructions, break into key value pairs
27338a47c60SMark Prins        $gmap = $this->dflt;
274c8eb1362SMark Prins        foreach($gmap as $key => &$value) {
275c8eb1362SMark Prins            $defval = $this->getConf('default_' . $key);
276c8eb1362SMark Prins            if($defval !== '') {
277c8eb1362SMark Prins                $value = $defval;
278c8eb1362SMark Prins            }
279c8eb1362SMark Prins        }
280c8eb1362SMark Prins        unset ($value);
28138a47c60SMark Prins        foreach($param as $kvpair) {
28238a47c60SMark Prins            list ($match, $key, $val) = $kvpair;
28338a47c60SMark Prins            $key = strtolower($key);
28438a47c60SMark Prins            if(isset ($gmap [$key])) {
28545c50327SMark Prins                if($key == 'summary') {
28645c50327SMark Prins                    // preserve case for summary field
28745c50327SMark Prins                    $gmap [$key] = $val;
2881c640875SMark Prins                } elseif($key == 'id') {
2891c640875SMark Prins                    // preserve case for id field
2901c640875SMark Prins                    $gmap [$key] = $val;
29145c50327SMark Prins                } else {
29238a47c60SMark Prins                    $gmap [$key] = strtolower($val);
29338a47c60SMark Prins                }
29438a47c60SMark Prins            }
29545c50327SMark Prins        }
29638a47c60SMark Prins        return $gmap;
29738a47c60SMark Prins    }
29838a47c60SMark Prins
29938a47c60SMark Prins    /**
30038a47c60SMark Prins     * extract overlay points for the map from the wiki syntax data
30138a47c60SMark Prins     *
3021c640875SMark Prins     * @param string $str_points
3031c640875SMark Prins     *            multi-line string of lat,lon,text triplets
30438a47c60SMark Prins     * @return array multi-dimensional array of lat,lon,text triplets
30538a47c60SMark Prins     */
30657f8d5bbSMark Prins    private function extractPoints(string $str_points): array {
30738a47c60SMark Prins        $point = array();
30857f8d5bbSMark Prins        // preg_match_all('/^([+-]?[0-9].*?),\s*([+-]?[0-9].*?),(.*?),(.*?),(.*?),(.*)$/um',
30957f8d5bbSMark Prins        //      $str_points, $point, PREG_SET_ORDER);
3107a3f422cSMark Prins        /*
31157f8d5bbSMark Prins         * group 1: ([+-]?[0-9]+(?:\.[0-9]*)?)
31257f8d5bbSMark Prins         * group 2: ([+-]?[0-9]+(?:\.[0-9]*)?)
31357f8d5bbSMark Prins         * group 3: (.*?)
31457f8d5bbSMark Prins         * group 4: (.*?)
31557f8d5bbSMark Prins         * group 5: (.*?)
31657f8d5bbSMark Prins         * group 6: (.*)
3177a3f422cSMark Prins         */
31857f8d5bbSMark Prins        preg_match_all(
31957f8d5bbSMark Prins            '/^([+-]?[0-9]+(?:\.[0-9]*)?),\s*([+-]?[0-9]+(?:\.[0-9]*)?),(.*?),(.*?),(.*?),(.*)$/um',
32057f8d5bbSMark Prins            $str_points, $point, PREG_SET_ORDER
32157f8d5bbSMark Prins        );
322554f43b5SMark Prins        // create poi array
32338a47c60SMark Prins        $overlay = array();
32438a47c60SMark Prins        foreach($point as $pt) {
32538a47c60SMark Prins            list ($match, $lat, $lon, $angle, $opacity, $img, $text) = $pt;
32638a47c60SMark Prins            $lat     = is_numeric($lat) ? $lat : 0;
32738a47c60SMark Prins            $lon     = is_numeric($lon) ? $lon : 0;
32838a47c60SMark Prins            $angle   = is_numeric($angle) ? $angle : 0;
32938a47c60SMark Prins            $opacity = is_numeric($opacity) ? $opacity : 0.8;
33087d958d4SMark Prins            // TODO validate using exist & set up default img?
3311c640875SMark Prins            $img  = trim($img);
3321c640875SMark Prins            $text = p_get_instructions($text);
3331c640875SMark Prins            // dbg ( $text );
3341c640875SMark Prins            $text = p_render("xhtml", $text, $info);
3351c640875SMark Prins            // dbg ( $text );
3361c640875SMark Prins            $text       = addslashes(str_replace("\n", "", $text));
3371c640875SMark Prins            $overlay [] = array(
3381c640875SMark Prins                $lat,
3391c640875SMark Prins                $lon,
3401c640875SMark Prins                $text,
3411c640875SMark Prins                $angle,
3421c640875SMark Prins                $opacity,
3431c640875SMark Prins                $img
3441c640875SMark Prins            );
34538a47c60SMark Prins        }
34638a47c60SMark Prins        return $overlay;
34738a47c60SMark Prins    }
348fcd79b50SMark Prins
349fcd79b50SMark Prins    /**
35057f8d5bbSMark Prins     * Create a Google maps static image url w/ the poi.
35157f8d5bbSMark Prins     *
35257f8d5bbSMark Prins     * @param array $gmap
35357f8d5bbSMark Prins     * @param array $overlay
35457f8d5bbSMark Prins     * @return string
35557f8d5bbSMark Prins     */
35657f8d5bbSMark Prins    private function getGoogle(array $gmap, array $overlay): string {
35757f8d5bbSMark Prins        $sUrl = $this->getConf('iconUrlOverload');
35857f8d5bbSMark Prins        if(!$sUrl) {
35957f8d5bbSMark Prins            $sUrl = DOKU_URL;
36057f8d5bbSMark Prins        }
36157f8d5bbSMark Prins        switch($gmap ['baselyr']) {
36257f8d5bbSMark Prins            case 'google hybrid' :
36357f8d5bbSMark Prins                $maptype = 'hybrid';
36457f8d5bbSMark Prins                break;
36557f8d5bbSMark Prins            case 'google sat' :
36657f8d5bbSMark Prins                $maptype = 'satellite';
36757f8d5bbSMark Prins                break;
36857f8d5bbSMark Prins            case 'terrain' :
36957f8d5bbSMark Prins            case 'google relief' :
37057f8d5bbSMark Prins                $maptype = 'terrain';
37157f8d5bbSMark Prins                break;
37257f8d5bbSMark Prins            case 'google road' :
37357f8d5bbSMark Prins            default :
37457f8d5bbSMark Prins                $maptype = 'roadmap';
37557f8d5bbSMark Prins                break;
37657f8d5bbSMark Prins        }
37757f8d5bbSMark Prins        // TODO maybe use viewport / visible instead of center/zoom,
37857f8d5bbSMark Prins        // see: https://developers.google.com/maps/documentation/staticmaps/index#Viewports
37957f8d5bbSMark Prins        // 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
38057f8d5bbSMark Prins        $imgUrl = "https://maps.googleapis.com/maps/api/staticmap?";
38157f8d5bbSMark Prins        $imgUrl .= "&size=" . str_replace("px", "", $gmap ['width']) . "x"
38257f8d5bbSMark Prins            . str_replace("px", "", $gmap ['height']);
38357f8d5bbSMark Prins        //if (!$this->getConf( 'autoZoomMap')) { // no need for center & zoom params }
38457f8d5bbSMark Prins        $imgUrl .= "&center=" . $gmap ['lat'] . "," . $gmap ['lon'];
38557f8d5bbSMark Prins        // max is 21 (== building scale), but that's overkill..
38657f8d5bbSMark Prins        if($gmap ['zoom'] > 17) {
38757f8d5bbSMark Prins            $imgUrl .= "&zoom=17";
38857f8d5bbSMark Prins        } else {
38957f8d5bbSMark Prins            $imgUrl .= "&zoom=" . $gmap ['zoom'];
39057f8d5bbSMark Prins        }
39157f8d5bbSMark Prins        if(!empty ($overlay)) {
39257f8d5bbSMark Prins            $rowId = 0;
39357f8d5bbSMark Prins            foreach($overlay as $data) {
39457f8d5bbSMark Prins                list ($lat, $lon, $text, $angle, $opacity, $img) = $data;
39557f8d5bbSMark Prins                $imgUrl .= "&markers=icon%3a" . $sUrl . "lib/plugins/openlayersmap/icons/" . $img . "%7c"
39657f8d5bbSMark Prins                    . $lat . "," . $lon . "%7clabel%3a" . ++$rowId;
39757f8d5bbSMark Prins            }
39857f8d5bbSMark Prins        }
39957f8d5bbSMark Prins        $imgUrl .= "&format=png&maptype=" . $maptype;
40057f8d5bbSMark Prins        global $conf;
40157f8d5bbSMark Prins        $imgUrl .= "&language=" . $conf ['lang'];
40257f8d5bbSMark Prins        if($this->getConf('googleAPIkey')) {
40357f8d5bbSMark Prins            $imgUrl .= "&key=" . $this->getConf('googleAPIkey');
40457f8d5bbSMark Prins        }
40557f8d5bbSMark Prins        // dbglog($imgUrl,'syntax_plugin_openlayersmap_olmap::getGoogle: Google image url is:');
40657f8d5bbSMark Prins        return $imgUrl;
40757f8d5bbSMark Prins    }
40857f8d5bbSMark Prins
40957f8d5bbSMark Prins    /**
410fcd79b50SMark Prins     * Create a MapQuest static map API image url.
4111c640875SMark Prins     *
412fcd79b50SMark Prins     * @param array $gmap
413fcd79b50SMark Prins     * @param array $overlay
414fcd79b50SMark Prins     */
415e72390dbSMark Prins    /*
416fcd79b50SMark Prins   private function _getMapQuest($gmap, $overlay) {
417787a5195SMark Prins       $sUrl = $this->getConf ( 'iconUrlOverload' );
418787a5195SMark Prins       if (! $sUrl) {
419787a5195SMark Prins           $sUrl = DOKU_URL;
420787a5195SMark Prins       }
42187d958d4SMark Prins       switch ($gmap ['baselyr']) {
42294c2e868SMark Prins           case 'mapquest hybrid' :
423837eba2fSMark Prins               $maptype = 'hyb';
42487d958d4SMark Prins               break;
42518edeaa5SMark Prins           case 'mapquest sat' :
42644aba0bcSMark Prins               // because sat coverage is very limited use 'hyb' instead of 'sat' so we don't get a blank map
42744aba0bcSMark Prins               $maptype = 'hyb';
42887d958d4SMark Prins               break;
42994c2e868SMark Prins           case 'mapquest road' :
43087d958d4SMark Prins           default :
43187d958d4SMark Prins               $maptype = 'map';
43287d958d4SMark Prins               break;
43387d958d4SMark Prins       }
434004ad4e2SMark Prins       $imgUrl = "http://open.mapquestapi.com/staticmap/v4/getmap?declutter=true&";
43544aba0bcSMark Prins       if (count ( $overlay ) < 1) {
436787a5195SMark Prins           $imgUrl .= "?center=" . $gmap ['lat'] . "," . $gmap ['lon'];
437787a5195SMark Prins           // max level for mapquest is 16
438fcd79b50SMark Prins           if ($gmap ['zoom'] > 16) {
439fcd79b50SMark Prins               $imgUrl .= "&zoom=16";
440fcd79b50SMark Prins           } else {
441fcd79b50SMark Prins               $imgUrl .= "&zoom=" . $gmap ['zoom'];
442fcd79b50SMark Prins           }
44344aba0bcSMark Prins       }
44444aba0bcSMark Prins       // use bestfit instead of center/zoom, needs upperleft/lowerright corners
44557f8d5bbSMark Prins       // $bbox=$this->calcBBOX($overlay, $gmap['lat'], $gmap['lon']);
44644aba0bcSMark Prins       // $imgUrl .= "bestfit=".$bbox['minlat'].",".$bbox['maxlon'].",".$bbox['maxlat'].",".$bbox['minlon'];
44744aba0bcSMark Prins
44857f8d5bbSMark Prins       // TODO declutter option works well for square maps but not for rectangular, maybe compensate for that
44957f8d5bbSMark Prins       //       or compensate the mbr..
45057f8d5bbSMark Prins
45144aba0bcSMark Prins       $imgUrl .= "&size=" . str_replace ( "px", "", $gmap ['width'] ) . "," . str_replace ("px","",$gmap['height']);
45244aba0bcSMark Prins
453fcd79b50SMark Prins       // TODO mapquest allows using one image url with a multiplier $NUMBER eg:
454fcd79b50SMark Prins       // $NUMBER = 2
45557f8d5bbSMark Prins       // $imgUrl .= DOKU_URL."/".DOKU_PLUGIN."/".getPluginName()."/icons/".$img.",$NUMBER,C,"
45657f8d5bbSMark Prins        //  .$lat1.",".$lon1.",0,0,0,0,C,".$lat2.",".$lon2.",0,0,0,0";
457fcd79b50SMark Prins       if (! empty ( $overlay )) {
458fcd79b50SMark Prins           $imgUrl .= "&xis=";
459fcd79b50SMark Prins           foreach ( $overlay as $data ) {
460fcd79b50SMark Prins               list ( $lat, $lon, $text, $angle, $opacity, $img ) = $data;
46144aba0bcSMark Prins               // $imgUrl .= $sUrl."lib/plugins/openlayersmap/icons/".$img.",1,C,".$lat.",".$lon.",0,0,0,0,";
46244aba0bcSMark Prins               $imgUrl .= $sUrl . "lib/plugins/openlayersmap/icons/" . $img . ",1,C," . $lat . "," . $lon . ",";
463fcd79b50SMark Prins           }
464fcd79b50SMark Prins           $imgUrl = substr ( $imgUrl, 0, - 1 );
465fcd79b50SMark Prins       }
46687d958d4SMark Prins       $imgUrl .= "&imageType=png&type=" . $maptype;
467d974ea02SMark Prins       $imgUrl .= "&key=".$this->getConf ( 'mapquestAPIKey' );
4688e7c4263SMark Prins       // dbglog($imgUrl,'syntax_plugin_openlayersmap_olmap::_getMapQuest: MapQuest image url is:');
469787a5195SMark Prins       return $imgUrl;
470787a5195SMark Prins   }
471e72390dbSMark Prins   */
472cc74a83cSMark Prins
4736e633dd6SMark Prins    /**
47487d958d4SMark Prins     * Create a static OSM map image url w/ the poi from http://staticmap.openstreetmap.de (staticMapLite)
475fcf646d2SMark Prins     * use http://staticmap.openstreetmap.de "staticMapLite" or a local version
4761c640875SMark Prins     *
47787d958d4SMark Prins     * @param array $gmap
47887d958d4SMark Prins     * @param array $overlay
479fcf646d2SMark Prins     *
48057f8d5bbSMark Prins     * @return false|string
481fcf646d2SMark Prins     * @todo implementation for http://ojw.dev.openstreetmap.org/StaticMapDev/
48287d958d4SMark Prins     */
48357f8d5bbSMark Prins    private function getStaticOSM(array $gmap, array $overlay) {
484fcf646d2SMark Prins        global $conf;
485372f1508SMark Prins
48653bfe4a3SMark Prins        if($this->getConf('optionStaticMapGenerator') == 'local') {
487d974ea02SMark Prins            // using local basemap composer
48857f8d5bbSMark Prins            if(!$myMap = plugin_load('helper', 'openlayersmap_staticmap')) {
48957f8d5bbSMark Prins                dbglog(
49057f8d5bbSMark Prins                    $myMap,
49157f8d5bbSMark Prins                    'openlayersmap_staticmap plugin is not available for use.'
49257f8d5bbSMark Prins                );
49353bfe4a3SMark Prins            }
49457f8d5bbSMark Prins            if(!$geophp = plugin_load('helper', 'geophp')) {
49557f8d5bbSMark Prins                dbglog($geophp, 'geophp plugin is not available for use.');
49653bfe4a3SMark Prins            }
49757f8d5bbSMark Prins            $size = str_replace("px", "", $gmap ['width']) . "x"
49857f8d5bbSMark Prins                . str_replace("px", "", $gmap ['height']);
49953bfe4a3SMark Prins
5004c9f9dfcSMark Prins            $markers = array();
50153bfe4a3SMark Prins            if(!empty ($overlay)) {
50253bfe4a3SMark Prins                foreach($overlay as $data) {
50353bfe4a3SMark Prins                    list ($lat, $lon, $text, $angle, $opacity, $img) = $data;
50453bfe4a3SMark Prins                    $iconStyle  = substr($img, 0, strlen($img) - 4);
50553bfe4a3SMark Prins                    $markers [] = array(
50653bfe4a3SMark Prins                        'lat'  => $lat,
50753bfe4a3SMark Prins                        'lon'  => $lon,
5081c640875SMark Prins                        'type' => $iconStyle
5091c640875SMark Prins                    );
51053bfe4a3SMark Prins                }
511372f1508SMark Prins            }
512372f1508SMark Prins
513d2f4772aSMark Prins            $apikey = '';
51418edeaa5SMark Prins            switch($gmap ['baselyr']) {
51518edeaa5SMark Prins                case 'mapnik' :
516fcf646d2SMark Prins                case 'openstreetmap' :
517fcf646d2SMark Prins                    $maptype = 'openstreetmap';
51818edeaa5SMark Prins                    break;
519fcf646d2SMark Prins                case 'transport' :
520fcf646d2SMark Prins                    $maptype = 'transport';
521b63742deSMark Prins                    $apikey  = '?apikey=' . $this->getConf('tfApiKey');
522fcf646d2SMark Prins                    break;
523fcf646d2SMark Prins                case 'landscape' :
524fcf646d2SMark Prins                    $maptype = 'landscape';
525b63742deSMark Prins                    $apikey  = '?apikey=' . $this->getConf('tfApiKey');
526d2f4772aSMark Prins                    break;
527d2f4772aSMark Prins                case 'outdoors' :
528d2f4772aSMark Prins                    $maptype = 'outdoors';
529b63742deSMark Prins                    $apikey  = '?apikey=' . $this->getConf('tfApiKey');
53018edeaa5SMark Prins                    break;
53118edeaa5SMark Prins                case 'cycle map' :
53218edeaa5SMark Prins                    $maptype = 'cycle';
533b63742deSMark Prins                    $apikey  = '?apikey=' . $this->getConf('tfApiKey');
534372f1508SMark Prins                    break;
535fcf646d2SMark Prins                case 'hike and bike map' :
536fcf646d2SMark Prins                    $maptype = 'hikeandbike';
537fcf646d2SMark Prins                    break;
538fcf646d2SMark Prins                case 'mapquest hybrid' :
539fcf646d2SMark Prins                case 'mapquest road' :
540fcf646d2SMark Prins                case 'mapquest sat' :
541fcf646d2SMark Prins                    $maptype = 'mapquest';
542fcf646d2SMark Prins                    break;
54318edeaa5SMark Prins                default :
54418edeaa5SMark Prins                    $maptype = '';
54518edeaa5SMark Prins                    break;
54618edeaa5SMark Prins            }
547d974ea02SMark Prins
54857f8d5bbSMark Prins            $result = $myMap->getMap(
54957f8d5bbSMark Prins                $gmap ['lat'], $gmap ['lon'], $gmap ['zoom'], $size, $maptype, $markers,
550b63742deSMark Prins                $gmap ['gpxfile'], $gmap ['kmlfile'], $gmap ['geojsonfile'], $apikey
55157f8d5bbSMark Prins            );
552d974ea02SMark Prins        } else {
553d974ea02SMark Prins            // using external basemap composer
554d974ea02SMark Prins
55557f8d5bbSMark Prins            // https://staticmap.openstreetmap.de/staticmap.php?center=47.000622235634,10
55657f8d5bbSMark Prins            //.117187497601&zoom=5&size=500x350
55757f8d5bbSMark Prins            // &markers=48.999812532766,8.3593749976708,lightblue1|43.154850037315,17.499999997306,
55857f8d5bbSMark Prins            //  lightblue1|49.487527053077,10.820312497573,ltblu-pushpin|47.951071133739,15.917968747369,
55957f8d5bbSMark Prins            //  ol-marker|47.921629720114,18.027343747285,ol-marker-gold|47.951071133739,19.257812497236,
56057f8d5bbSMark Prins            //  ol-marker-blue|47.180141361692,19.257812497236,ol-marker-green
56157f8d5bbSMark Prins            $imgUrl = "https://staticmap.openstreetmap.de/staticmap.php";
562d974ea02SMark Prins            $imgUrl .= "?center=" . $gmap ['lat'] . "," . $gmap ['lon'];
56357f8d5bbSMark Prins            $imgUrl .= "&size=" . str_replace("px", "", $gmap ['width']) . "x"
56457f8d5bbSMark Prins                . str_replace("px", "", $gmap ['height']);
565d974ea02SMark Prins
566d974ea02SMark Prins            if($gmap ['zoom'] > 16) {
567d974ea02SMark Prins                // actually this could even be 18, but that seems overkill
568d974ea02SMark Prins                $imgUrl .= "&zoom=16";
569d974ea02SMark Prins            } else {
570d974ea02SMark Prins                $imgUrl .= "&zoom=" . $gmap ['zoom'];
571d974ea02SMark Prins            }
57218edeaa5SMark Prins
57387d958d4SMark Prins            if(!empty ($overlay)) {
57487d958d4SMark Prins                $rowId  = 0;
57587d958d4SMark Prins                $imgUrl .= "&markers=";
57687d958d4SMark Prins                foreach($overlay as $data) {
57787d958d4SMark Prins                    list ($lat, $lon, $text, $angle, $opacity, $img) = $data;
57887d958d4SMark Prins                    $rowId++;
57953bfe4a3SMark Prins                    $iconStyle = "lightblue$rowId";
58087d958d4SMark Prins                    $imgUrl    .= "$lat,$lon,$iconStyle%7c";
58187d958d4SMark Prins                }
58287d958d4SMark Prins                $imgUrl = substr($imgUrl, 0, -3);
58387d958d4SMark Prins            }
58487d958d4SMark Prins
585f4b9bdacSMark Prins            $result = $imgUrl;
586628e43ccSMark Prins        }
58757f8d5bbSMark Prins        // dbglog ( $result, 'syntax_plugin_openlayersmap_olmap::getStaticOSM: osm image url is:' );
588628e43ccSMark Prins        return $result;
589628e43ccSMark Prins    }
590628e43ccSMark Prins
59144aba0bcSMark Prins    /**
59257f8d5bbSMark Prins     * Create a Bing maps static image url w/ the poi.
59357f8d5bbSMark Prins     *
59457f8d5bbSMark Prins     * @param array $gmap
59557f8d5bbSMark Prins     * @param array $overlay
59657f8d5bbSMark Prins     * @return string
59757f8d5bbSMark Prins     */
59857f8d5bbSMark Prins    private function getBing(array $gmap, array $overlay): string {
59957f8d5bbSMark Prins        switch($gmap ['baselyr']) {
60057f8d5bbSMark Prins            case 've hybrid' :
60157f8d5bbSMark Prins            case 'bing hybrid' :
60257f8d5bbSMark Prins                $maptype = 'AerialWithLabels';
60357f8d5bbSMark Prins                break;
60457f8d5bbSMark Prins            case 've sat' :
60557f8d5bbSMark Prins            case 'bing sat' :
60657f8d5bbSMark Prins                $maptype = 'Aerial';
60757f8d5bbSMark Prins                break;
60857f8d5bbSMark Prins            case 've normal' :
60957f8d5bbSMark Prins            case 've road' :
61057f8d5bbSMark Prins            case 've' :
61157f8d5bbSMark Prins            case 'bing road' :
61257f8d5bbSMark Prins            default :
61357f8d5bbSMark Prins                $maptype = 'Road';
61457f8d5bbSMark Prins                break;
61557f8d5bbSMark Prins        }
61657f8d5bbSMark Prins        $imgUrl = "https://dev.virtualearth.net/REST/v1/Imagery/Map/" . $maptype;// . "/";
61757f8d5bbSMark Prins        if($this->getConf('autoZoomMap')) {
61857f8d5bbSMark Prins            $bbox = $this->calcBBOX($overlay, $gmap ['lat'], $gmap ['lon']);
61957f8d5bbSMark Prins            //$imgUrl .= "?ma=" . $bbox ['minlat'] . "," . $bbox ['minlon'] . ","
62057f8d5bbSMark Prins            //          . $bbox ['maxlat'] . "," . $bbox ['maxlon'];
62157f8d5bbSMark Prins            $imgUrl .= "?ma=" . $bbox ['minlat'] . "%2C" . $bbox ['minlon'] . "%2C" . $bbox ['maxlat']
62257f8d5bbSMark Prins                . "%2C" . $bbox ['maxlon'];
62357f8d5bbSMark Prins            $imgUrl .= "&dcl=1";
62457f8d5bbSMark Prins        }
62557f8d5bbSMark Prins        if(strpos($imgUrl, "?") === false)
62657f8d5bbSMark Prins            $imgUrl .= "?";
62757f8d5bbSMark Prins
62857f8d5bbSMark Prins        //$imgUrl .= "&ms=" . str_replace ( "px", "", $gmap ['width'] ) . ","
62957f8d5bbSMark Prins        //          . str_replace ( "px", "", $gmap ['height'] );
63057f8d5bbSMark Prins        $imgUrl .= "&ms=" . str_replace("px", "", $gmap ['width']) . "%2C"
63157f8d5bbSMark Prins            . str_replace("px", "", $gmap ['height']);
63257f8d5bbSMark Prins        $imgUrl .= "&key=" . $this->getConf('bingAPIKey');
63357f8d5bbSMark Prins        if(!empty ($overlay)) {
63457f8d5bbSMark Prins            $rowId = 0;
63557f8d5bbSMark Prins            foreach($overlay as $data) {
63657f8d5bbSMark Prins                list ($lat, $lon, $text, $angle, $opacity, $img) = $data;
63757f8d5bbSMark Prins                // TODO icon style lookup, see: http://msdn.microsoft.com/en-us/library/ff701719.aspx for iconStyle
63857f8d5bbSMark Prins                $iconStyle = 32;
63957f8d5bbSMark Prins                $rowId++;
64057f8d5bbSMark Prins                // NOTE: the max number of pushpins is 18! or we have to use POST
64157f8d5bbSMark Prins                //  (http://msdn.microsoft.com/en-us/library/ff701724.aspx)
64257f8d5bbSMark Prins                if($rowId == 18) {
64357f8d5bbSMark Prins                    break;
64457f8d5bbSMark Prins                }
64557f8d5bbSMark Prins                //$imgUrl .= "&pp=$lat,$lon;$iconStyle;$rowId";
64657f8d5bbSMark Prins                $imgUrl .= "&pp=$lat%2C$lon%3B$iconStyle%3B$rowId";
64757f8d5bbSMark Prins
64857f8d5bbSMark Prins            }
64957f8d5bbSMark Prins        }
65057f8d5bbSMark Prins        global $conf;
65157f8d5bbSMark Prins        $imgUrl .= "&fmt=png";
65257f8d5bbSMark Prins        $imgUrl .= "&c=" . $conf ['lang'];
65357f8d5bbSMark Prins        // dbglog($imgUrl,'syntax_plugin_openlayersmap_olmap::getBing: bing image url is:');
65457f8d5bbSMark Prins        return $imgUrl;
65557f8d5bbSMark Prins    }
65657f8d5bbSMark Prins
65757f8d5bbSMark Prins    /**
65844aba0bcSMark Prins     * Calculate the minimum bbox for a start location + poi.
65944aba0bcSMark Prins     *
6601c640875SMark Prins     * @param array $overlay
6611c640875SMark Prins     *            multi-dimensional array of array($lat, $lon, $text, $angle, $opacity, $img)
6621c640875SMark Prins     * @param float $lat
6631c640875SMark Prins     *            latitude for map center
6641c640875SMark Prins     * @param float $lon
6651c640875SMark Prins     *            longitude for map center
66657f8d5bbSMark Prins     * @return array :float array describing the mbr and center point
66744aba0bcSMark Prins     */
66857f8d5bbSMark Prins    private function calcBBOX(array $overlay, float $lat, float $lon): array {
6694c9f9dfcSMark Prins        $lats = array($lat);
6704c9f9dfcSMark Prins        $lons = array($lon);
671837eba2fSMark Prins        foreach($overlay as $data) {
672837eba2fSMark Prins            list ($lat, $lon, $text, $angle, $opacity, $img) = $data;
673837eba2fSMark Prins            $lats [] = $lat;
674837eba2fSMark Prins            $lons [] = $lon;
675837eba2fSMark Prins        }
676837eba2fSMark Prins        sort($lats);
677837eba2fSMark Prins        sort($lons);
67844aba0bcSMark Prins        // TODO: make edge/wrap around cases work
67944aba0bcSMark Prins        $centerlat = $lats [0] + ($lats [count($lats) - 1] - $lats [0]);
68044aba0bcSMark Prins        $centerlon = $lons [0] + ($lons [count($lats) - 1] - $lons [0]);
6811c640875SMark Prins        return array(
6821c640875SMark Prins            'minlat'    => $lats [0],
6831c640875SMark Prins            'minlon'    => $lons [0],
6841c640875SMark Prins            'maxlat'    => $lats [count($lats) - 1],
6851c640875SMark Prins            'maxlon'    => $lons [count($lats) - 1],
6861c640875SMark Prins            'centerlat' => $centerlat,
6871c640875SMark Prins            'centerlon' => $centerlon
6881c640875SMark Prins        );
68987d958d4SMark Prins    }
690cc74a83cSMark Prins
691cc74a83cSMark Prins    /**
69257f8d5bbSMark Prins     * convert latitude in decimal degrees to DMS+hemisphere.
6931c640875SMark Prins     *
69457f8d5bbSMark Prins     * @param float $decimaldegrees
69557f8d5bbSMark Prins     * @return string
69657f8d5bbSMark Prins     * @todo move this into a shared library
697cc74a83cSMark Prins     */
69857f8d5bbSMark Prins    private function convertLat(float $decimaldegrees): string {
69957f8d5bbSMark Prins        if(strpos($decimaldegrees, '-') !== false) {
70057f8d5bbSMark Prins            $latPos = "S";
70157f8d5bbSMark Prins        } else {
70257f8d5bbSMark Prins            $latPos = "N";
70357f8d5bbSMark Prins        }
70457f8d5bbSMark Prins        $dms = $this->convertDDtoDMS(abs($decimaldegrees));
70557f8d5bbSMark Prins        return hsc($dms . $latPos);
706cc74a83cSMark Prins    }
7078c4eb2fdSMark Prins
7088c4eb2fdSMark Prins    /**
7098c4eb2fdSMark Prins     * Convert decimal degrees to degrees, minutes, seconds format
7108c4eb2fdSMark Prins     *
7118c4eb2fdSMark Prins     * @param float $decimaldegrees
7128c4eb2fdSMark Prins     * @return string dms
71357f8d5bbSMark Prins     * @todo move this into a shared library
7148c4eb2fdSMark Prins     */
71557f8d5bbSMark Prins    private function convertDDtoDMS(float $decimaldegrees): string {
7168c4eb2fdSMark Prins        $dms  = floor($decimaldegrees);
7178c4eb2fdSMark Prins        $secs = ($decimaldegrees - $dms) * 3600;
7188c4eb2fdSMark Prins        $min  = floor($secs / 60);
7198c4eb2fdSMark Prins        $sec  = round($secs - ($min * 60), 3);
7208c4eb2fdSMark Prins        $dms  .= 'º' . $min . '\'' . $sec . '"';
7218c4eb2fdSMark Prins        return $dms;
7228c4eb2fdSMark Prins    }
7238c4eb2fdSMark Prins
7248c4eb2fdSMark Prins    /**
7258c4eb2fdSMark Prins     * convert longitude in decimal degrees to DMS+hemisphere.
7268c4eb2fdSMark Prins     *
7278c4eb2fdSMark Prins     * @param float $decimaldegrees
7288c4eb2fdSMark Prins     * @return string
72957f8d5bbSMark Prins     * @todo move this into a shared library
7308c4eb2fdSMark Prins     */
73157f8d5bbSMark Prins    private function convertLon(float $decimaldegrees): string {
7328c4eb2fdSMark Prins        if(strpos($decimaldegrees, '-') !== false) {
7338c4eb2fdSMark Prins            $lonPos = "W";
7348c4eb2fdSMark Prins        } else {
7358c4eb2fdSMark Prins            $lonPos = "E";
7368c4eb2fdSMark Prins        }
73757f8d5bbSMark Prins        $dms = $this->convertDDtoDMS(abs($decimaldegrees));
7388c4eb2fdSMark Prins        return hsc($dms . $lonPos);
7398c4eb2fdSMark Prins    }
74057f8d5bbSMark Prins
74157f8d5bbSMark Prins    /**
74257f8d5bbSMark Prins     * Figures out the base filename of a media path.
74357f8d5bbSMark Prins     *
74457f8d5bbSMark Prins     * @param string $mediaLink
74557f8d5bbSMark Prins     * @return string
74657f8d5bbSMark Prins     */
74757f8d5bbSMark Prins    private function getFileName(string $mediaLink): string {
74857f8d5bbSMark Prins        $mediaLink = str_replace('[[', '', $mediaLink);
74957f8d5bbSMark Prins        $mediaLink = str_replace(']]', '', $mediaLink);
75057f8d5bbSMark Prins        $mediaLink = substr($mediaLink, 0, -4);
75157f8d5bbSMark Prins        $parts     = explode(':', $mediaLink);
75257f8d5bbSMark Prins        $mediaLink = end($parts);
75357f8d5bbSMark Prins        return str_replace('_', ' ', $mediaLink);
75457f8d5bbSMark Prins    }
75557f8d5bbSMark Prins
75657f8d5bbSMark Prins    /**
75757f8d5bbSMark Prins     *
75857f8d5bbSMark Prins     * @see DokuWiki_Syntax_Plugin::render()
75957f8d5bbSMark Prins     */
76057f8d5bbSMark Prins    public function render($format, Doku_Renderer $renderer, $data): bool {
76157f8d5bbSMark Prins        // set to true after external scripts tags are written
76257f8d5bbSMark Prins        static $initialised = false;
76357f8d5bbSMark Prins        // incremented for each map tag in the page source so we can keep track of each map in this page
76457f8d5bbSMark Prins        static $mapnumber = 0;
76557f8d5bbSMark Prins
76657f8d5bbSMark Prins        // dbglog($data, 'olmap::render() data.');
76757f8d5bbSMark Prins        list ($mapid, $param, $mainLat, $mainLon, $poitable, $poitabledesc, $staticImgUrl, $_firstimage) = $data;
76857f8d5bbSMark Prins
76957f8d5bbSMark Prins        if($format == 'xhtml') {
77057f8d5bbSMark Prins            $olscript     = '';
77157f8d5bbSMark Prins            $stamenEnable = $this->getConf('enableStamen');
77257f8d5bbSMark Prins            $osmEnable    = $this->getConf('enableOSM');
77357f8d5bbSMark Prins            $enableBing   = $this->getConf('enableBing');
77457f8d5bbSMark Prins
77557f8d5bbSMark Prins            $scriptEnable = '';
77657f8d5bbSMark Prins            if(!$initialised) {
77757f8d5bbSMark Prins                $initialised = true;
7787390889dSMark Prins                // render necessary script tags only once
7794718d417SMark Prins                $olscript = '<script defer="defer" src="' . DOKU_BASE . 'lib/plugins/openlayersmap/ol7/ol.js"></script>
7804718d417SMark Prins<script defer="defer" src="' . DOKU_BASE . 'lib/plugins/openlayersmap/ol7/ol-layerswitcher.js"></script>';
78157f8d5bbSMark Prins
78257f8d5bbSMark Prins                $scriptEnable = '<script defer="defer" src="data:text/javascript;base64,';
7837390889dSMark Prins                $scriptSrc    = $olscript ? 'const olEnable=true;' : 'const olEnable=false;';
7847390889dSMark Prins                $scriptSrc    .= 'const osmEnable=' . ($osmEnable ? 'true' : 'false') . ';';
7857390889dSMark Prins                $scriptSrc    .= 'const stamenEnable=' . ($stamenEnable ? 'true' : 'false') . ';';
7867390889dSMark Prins                $scriptSrc    .= 'const bEnable=' . ($enableBing ? 'true' : 'false') . ';';
7877390889dSMark Prins                $scriptSrc    .= 'const bApiKey="' . $this->getConf('bingAPIKey') . '";';
7887390889dSMark Prins                $scriptSrc    .= 'const tfApiKey="' . $this->getConf('tfApiKey') . '";';
7897390889dSMark Prins                $scriptSrc    .= 'const gApiKey="' . $this->getConf('googleAPIkey') . '";';
7907390889dSMark Prins                $scriptSrc    .= 'olMapData = []; let olMaps = {}; let olMapOverlays = {};';
79157f8d5bbSMark Prins                $scriptEnable .= base64_encode($scriptSrc);
79257f8d5bbSMark Prins                $scriptEnable .= '"></script>';
79357f8d5bbSMark Prins            }
7947390889dSMark Prins            $renderer->doc .= "$olscript\n$scriptEnable";
79557f8d5bbSMark Prins            $renderer->doc .= '<div class="olMapHelp">' . $this->locale_xhtml("help") . '</div>';
79657f8d5bbSMark Prins            if($this->getConf('enableA11y')) {
79757f8d5bbSMark Prins                $renderer->doc .= '<div id="' . $mapid . '-static" class="olStaticMap">'
79857f8d5bbSMark Prins                    . p_render($format, p_get_instructions($staticImgUrl), $info) . '</div>';
79957f8d5bbSMark Prins            }
80057f8d5bbSMark Prins            $renderer->doc .= '<div id="' . $mapid . '-clearer" class="clearer"><p>&nbsp;</p></div>';
80157f8d5bbSMark Prins            if($this->getConf('enableA11y')) {
80257f8d5bbSMark Prins                // render a table of the POI for the print and a11y presentation, it is hidden using javascript
8037390889dSMark Prins                $renderer->doc .= '
804*3f760703SMark Prins                <div id="' . $mapid . '-table-span" class="olPOItableSpan">
805*3f760703SMark Prins                    <table id="' . $mapid . '-table" class="olPOItable">
80657f8d5bbSMark Prins                    <caption class="olPOITblCaption">' . $this->getLang('olmapPOItitle') . '</caption>
80757f8d5bbSMark Prins                    <thead class="olPOITblHeader">
80857f8d5bbSMark Prins                    <tr>
80957f8d5bbSMark Prins                    <th class="rowId" scope="col">id</th>
81057f8d5bbSMark Prins                    <th class="icon" scope="col">' . $this->getLang('olmapPOIicon') . '</th>
81157f8d5bbSMark Prins                    <th class="lat" scope="col" title="' . $this->getLang('olmapPOIlatTitle') . '">'
81257f8d5bbSMark Prins                    . $this->getLang('olmapPOIlat') . '</th>
81357f8d5bbSMark Prins                    <th class="lon" scope="col" title="' . $this->getLang('olmapPOIlonTitle') . '">'
81457f8d5bbSMark Prins                    . $this->getLang('olmapPOIlon') . '</th>
81557f8d5bbSMark Prins                    <th class="txt" scope="col">' . $this->getLang('olmapPOItxt') . '</th>
81657f8d5bbSMark Prins                    </tr>
81757f8d5bbSMark Prins                    </thead>';
81857f8d5bbSMark Prins                if($poitabledesc != '') {
81957f8d5bbSMark Prins                    $renderer->doc .= '<tfoot class="olPOITblFooter"><tr><td colspan="5">' . $poitabledesc
82057f8d5bbSMark Prins                        . '</td></tr></tfoot>';
82157f8d5bbSMark Prins                }
82257f8d5bbSMark Prins                $renderer->doc .= '<tbody class="olPOITblBody">' . $poitable . '</tbody>
8237390889dSMark Prins                    </table>
8247390889dSMark Prins                </div>';
8257390889dSMark Prins                $renderer->doc .= "\n";
82657f8d5bbSMark Prins            }
82757f8d5bbSMark Prins            // render inline mapscript parts
82857f8d5bbSMark Prins            $renderer->doc .= '<script defer="defer" src="data:text/javascript;base64,';
82957f8d5bbSMark Prins            $renderer->doc .= base64_encode("olMapData[$mapnumber] = $param");
83057f8d5bbSMark Prins            $renderer->doc .= '"></script>';
83157f8d5bbSMark Prins            $mapnumber++;
83257f8d5bbSMark Prins            return true;
83357f8d5bbSMark Prins        } elseif($format == 'metadata') {
83457f8d5bbSMark Prins            if(!(($this->dflt ['lat'] == $mainLat) && ($this->dflt ['lon'] == $mainLon))) {
83557f8d5bbSMark Prins                // render geo metadata, unless they are the default
83657f8d5bbSMark Prins                $renderer->meta ['geo'] ['lat'] = $mainLat;
83757f8d5bbSMark Prins                $renderer->meta ['geo'] ['lon'] = $mainLon;
83857f8d5bbSMark Prins                if($geophp = plugin_load('helper', 'geophp')) {
83957f8d5bbSMark Prins                    // if we have the geoPHP helper, add the geohash
84057f8d5bbSMark Prins
84157f8d5bbSMark Prins                    // fails with older php versions..
84257f8d5bbSMark Prins                    // $renderer->meta['geo']['geohash'] = (new Point($mainLon,$mainLat))->out('geohash');
84357f8d5bbSMark Prins                    $p                                  = new Point ($mainLon, $mainLat);
84457f8d5bbSMark Prins                    $renderer->meta ['geo'] ['geohash'] = $p->out('geohash');
84557f8d5bbSMark Prins                }
84657f8d5bbSMark Prins            }
84757f8d5bbSMark Prins
84857f8d5bbSMark Prins            if(($this->getConf('enableA11y')) && (!empty ($_firstimage))) {
84957f8d5bbSMark Prins                // add map local image into relation/firstimage if not already filled and when it is a local image
85057f8d5bbSMark Prins
85157f8d5bbSMark Prins                global $ID;
85257f8d5bbSMark Prins                $rel = p_get_metadata($ID, 'relation', METADATA_RENDER_USING_CACHE);
85368188742SMark Prins                // $img = $rel ['firstimage'];
85468188742SMark Prins                if(empty ($rel ['firstimage']) /* || $img == $_firstimage*/) {
85557f8d5bbSMark Prins                    //dbglog ( $_firstimage,
85657f8d5bbSMark Prins                    // 'olmap::render#rendering image relation metadata for _firstimage as $img was empty or same.' );
85757f8d5bbSMark Prins                    // This seems to never work; the firstimage entry in the .meta file is empty
85857f8d5bbSMark Prins                    // $renderer->meta['relation']['firstimage'] = $_firstimage;
85957f8d5bbSMark Prins
86057f8d5bbSMark Prins                    // ... and neither does this; the firstimage entry in the .meta file is empty
86157f8d5bbSMark Prins                    // $relation = array('relation'=>array('firstimage'=>$_firstimage));
86257f8d5bbSMark Prins                    // p_set_metadata($ID, $relation, false, false);
86357f8d5bbSMark Prins
86457f8d5bbSMark Prins                    // ... this works
86557f8d5bbSMark Prins                    $renderer->internalmedia($_firstimage, $poitabledesc);
86657f8d5bbSMark Prins                }
86757f8d5bbSMark Prins            }
86857f8d5bbSMark Prins            return true;
86957f8d5bbSMark Prins        }
87057f8d5bbSMark Prins        return false;
87157f8d5bbSMark Prins    }
87238a47c60SMark Prins}
873