xref: /plugin/openlayersmap/syntax/olmap.php (revision f204b8ca21a3ff1a5b655b65aceab085168cc9d8)
138a47c60SMark Prins<?php
2a760825cSgithub-actions[bot]
338a47c60SMark Prins/*
4*f204b8caSMark Prins * Copyright (c) 2008-2023 Mark C. Prins <mprins@users.sf.net>
538a47c60SMark Prins *
638a47c60SMark Prins * Permission to use, copy, modify, and distribute this software for any
738a47c60SMark Prins * purpose with or without fee is hereby granted, provided that the above
838a47c60SMark Prins * copyright notice and this permission notice appear in all copies.
938a47c60SMark Prins *
1038a47c60SMark Prins * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1138a47c60SMark Prins * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1238a47c60SMark Prins * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1338a47c60SMark Prins * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1438a47c60SMark Prins * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1538a47c60SMark Prins * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1638a47c60SMark Prins * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1757f8d5bbSMark Prins *
1857f8d5bbSMark Prins * @phpcs:disable Squiz.Classes.ValidClassName.NotCamelCaps
1938a47c60SMark Prins */
20a760825cSgithub-actions[bot]use dokuwiki\Extension\SyntaxPlugin;
213ebe658bSMark Prinsuse geoPHP\Geometry\Point;
22*f204b8caSMark Prinsuse dokuwiki\Logger;
233ebe658bSMark Prins
2438a47c60SMark Prins/**
25cc74a83cSMark Prins * DokuWiki Plugin openlayersmap (Syntax Component).
26cc74a83cSMark Prins * Provides for display of an OpenLayers based map in a wiki page.
27cc74a83cSMark Prins *
28cc74a83cSMark Prins * @author Mark Prins
2938a47c60SMark Prins */
30a760825cSgithub-actions[bot]class syntax_plugin_openlayersmap_olmap extends SyntaxPlugin
31a760825cSgithub-actions[bot]{
321c640875SMark Prins    /**
331c640875SMark Prins     * defaults of the known attributes of the olmap tag.
341c640875SMark Prins     */
35a760825cSgithub-actions[bot]    private $dflt = ['id'            => 'olmap', 'width'         => '550px', 'height'        => '450px', 'lat'           => 50.0, 'lon'           => 5.1, 'zoom'          => 12, 'autozoom'      => 1, 'controls'      => true, 'baselyr'       => 'OpenStreetMap', 'gpxfile'       => '', 'kmlfile'       => '', 'geojsonfile'   => '', 'summary'       => ''];
3638a47c60SMark Prins
3738a47c60SMark Prins    /**
381c640875SMark Prins     *
39cc74a83cSMark Prins     * @see DokuWiki_Syntax_Plugin::getType()
4038a47c60SMark Prins     */
41a760825cSgithub-actions[bot]    public function getType(): string
42a760825cSgithub-actions[bot]    {
4375c98788SMark Prins        return 'substition';
4475c98788SMark Prins    }
4538a47c60SMark Prins
4638a47c60SMark Prins    /**
471c640875SMark Prins     *
48cc74a83cSMark Prins     * @see DokuWiki_Syntax_Plugin::getPType()
4938a47c60SMark Prins     */
50a760825cSgithub-actions[bot]    public function getPType(): string
51a760825cSgithub-actions[bot]    {
5275c98788SMark Prins        return 'block';
5375c98788SMark Prins    }
5438a47c60SMark Prins
5538a47c60SMark Prins    /**
561c640875SMark Prins     *
57cc74a83cSMark Prins     * @see Doku_Parser_Mode::getSort()
5838a47c60SMark Prins     */
59a760825cSgithub-actions[bot]    public function getSort(): int
60a760825cSgithub-actions[bot]    {
6175c98788SMark Prins        return 901;
6275c98788SMark Prins    }
63fc16f3cdSMark Prins
6438a47c60SMark Prins    /**
651c640875SMark Prins     *
66cc74a83cSMark Prins     * @see Doku_Parser_Mode::connectTo()
6738a47c60SMark Prins     */
68a760825cSgithub-actions[bot]    public function connectTo($mode)
69a760825cSgithub-actions[bot]    {
7057f8d5bbSMark Prins        $this->Lexer->addSpecialPattern(
71a760825cSgithub-actions[bot]            '<olmap ?[^>\n]*>.*?</olmap>',
72a760825cSgithub-actions[bot]            $mode,
7357f8d5bbSMark Prins            'plugin_openlayersmap_olmap'
7457f8d5bbSMark Prins        );
7538a47c60SMark Prins    }
76fc16f3cdSMark Prins
7738a47c60SMark Prins    /**
781c640875SMark Prins     *
79cc74a83cSMark Prins     * @see DokuWiki_Syntax_Plugin::handle()
8038a47c60SMark Prins     */
81a760825cSgithub-actions[bot]    public function handle($match, $state, $pos, Doku_Handler $handler): array
82a760825cSgithub-actions[bot]    {
833f760703SMark Prins        // break matched data into its components
843f760703SMark Prins        $_tag       = explode('>', substr($match, 7, -9), 2);
853f760703SMark Prins        $str_params = $_tag[0];
863f760703SMark Prins        if (array_key_exists(1, $_tag)) {
873f760703SMark Prins            $str_points = $_tag[1];
883f760703SMark Prins        } else {
893f760703SMark Prins            $str_points = '';
903f760703SMark Prins        }
91554f43b5SMark Prins        // get the lat/lon for adding them to the metadata (used by geotag)
92d2f4772aSMark Prins        preg_match('(lat[:|=]\"-?\d*\.?\d*\")', $match, $mainLat);
93d2f4772aSMark Prins        preg_match('(lon[:|=]\"-?\d*\.?\d*\")', $match, $mainLon);
94554f43b5SMark Prins        $mainLat = substr($mainLat [0], 5, -1);
95554f43b5SMark Prins        $mainLon = substr($mainLon [0], 5, -1);
96d2f4772aSMark Prins        if (!is_numeric($mainLat)) {
97d2f4772aSMark Prins            $mainLat = $this->dflt ['lat'];
98d2f4772aSMark Prins        }
99d2f4772aSMark Prins        if (!is_numeric($mainLon)) {
100d2f4772aSMark Prins            $mainLon = $this->dflt ['lon'];
101d2f4772aSMark Prins        }
10238a47c60SMark Prins
10357f8d5bbSMark Prins        $gmap          = $this->extractParams($str_params);
10457f8d5bbSMark Prins        $overlay = $this->extractPoints($str_points);
105fc16f3cdSMark Prins        $_firstimageID = '';
10638a47c60SMark Prins
1078e7c4263SMark Prins        $_nocache = false;
108807d36baSMark Prins        // choose maptype based on the specified tag
109628e43ccSMark Prins        $imgUrl = "{{";
110585afb49SMark Prins        if (stripos($gmap ['baselyr'], 'google') !== false) {
1118e7c4263SMark Prins            // Google
11257f8d5bbSMark Prins            $imgUrl .= $this->getGoogle($gmap, $overlay);
1138e7c4263SMark Prins            $imgUrl .= "&.png";
114585afb49SMark Prins        } elseif (stripos($gmap ['baselyr'], 'bing') !== false) {
1158e7c4263SMark Prins            // Bing
116d974ea02SMark Prins            if (!$this->getConf('bingAPIKey')) {
117d974ea02SMark Prins                // in case there is no Bing api key we'll use OSM
11857f8d5bbSMark Prins                $_firstimageID = $this->getStaticOSM($gmap, $overlay);
119d974ea02SMark Prins                $imgUrl        .= $_firstimageID;
120628e43ccSMark Prins                if ($this->getConf('optionStaticMapGenerator') == 'remote') {
121628e43ccSMark Prins                    $imgUrl .= "&.png";
122d974ea02SMark Prins                }
123d974ea02SMark Prins            } else {
1248e7c4263SMark Prins                // seems that Bing doesn't like the DW client, turn off caching
1258e7c4263SMark Prins                $_nocache = true;
12657f8d5bbSMark Prins                $imgUrl   .= $this->getBing($gmap, $overlay) . "&.png";
127d974ea02SMark Prins            }
128*f204b8caSMark Prins         /* elseif (stripos ( $gmap ['baselyr'], 'mapquest' ) !== false) {
1298e7c4263SMark Prins            // MapQuest
1308e7c4263SMark Prins            if (! $this->getConf ( 'mapquestAPIKey' )) {
1318e7c4263SMark Prins                // no API key for MapQuest, use OSM
13257f8d5bbSMark Prins                $_firstimageID = $this->getStaticOSM ( $gmap, $overlay );
133fc16f3cdSMark Prins                $imgUrl .= $_firstimageID;
1348e7c4263SMark Prins                if ($this->getConf ( 'optionStaticMapGenerator' ) == 'remote') {
1358e7c4263SMark Prins                    $imgUrl .= "&.png";
136628e43ccSMark Prins                }
13763037f21SMark Prins            } else {
1388e7c4263SMark Prins                $imgUrl .= $this->_getMapQuest ( $gmap, $overlay );
1398e7c4263SMark Prins                $imgUrl .= "&.png";
1408e7c4263SMark Prins            }
141*f204b8caSMark Prins        } */
142*f204b8caSMark Prins        } else {
1438e7c4263SMark Prins            // default OSM
14457f8d5bbSMark Prins            $_firstimageID = $this->getStaticOSM($gmap, $overlay);
145fc16f3cdSMark Prins            $imgUrl        .= $_firstimageID;
14653bfe4a3SMark Prins            if ($this->getConf('optionStaticMapGenerator') == 'remote') {
14753bfe4a3SMark Prins                $imgUrl .= "&.png";
14853bfe4a3SMark Prins            }
14987d958d4SMark Prins        }
15087d958d4SMark Prins
151628e43ccSMark Prins        // append dw p_render specific params and render
15257f8d5bbSMark Prins        $imgUrl .= "?" . str_replace("px", "", $gmap ['width']) . "x"
15357f8d5bbSMark Prins            . str_replace("px", "", $gmap ['height']);
1546ba8d085SMark Prins        $imgUrl .= "&nolink";
1558e7c4263SMark Prins
1568e7c4263SMark Prins        // add nocache option for selected services
1578e7c4263SMark Prins        if ($_nocache) {
1588e7c4263SMark Prins            $imgUrl .= "&nocache";
1598e7c4263SMark Prins        }
1608e7c4263SMark Prins
161fcd79b50SMark Prins        $imgUrl .= " |" . $gmap ['summary'] . " }}";
162fcd79b50SMark Prins
16338a47c60SMark Prins        $mapid = $gmap ['id'];
16438a47c60SMark Prins        // create a javascript parameter string for the map
16538a47c60SMark Prins        $param = '';
16638a47c60SMark Prins        foreach ($gmap as $key => $val) {
16738a47c60SMark Prins            $param .= is_numeric($val) ? "$key: $val, " : "$key: '" . hsc($val) . "', ";
16838a47c60SMark Prins        }
16938a47c60SMark Prins        if (!empty($param)) {
17045c50327SMark Prins            $param = substr($param, 0, -2);
17138a47c60SMark Prins        }
17238a47c60SMark Prins        unset($gmap ['id']);
17338a47c60SMark Prins
17438a47c60SMark Prins        // create a javascript serialisation of the point data
17538a47c60SMark Prins        $poi      = '';
17645c50327SMark Prins        $poitable = '';
17745c50327SMark Prins        $rowId    = 0;
178a760825cSgithub-actions[bot]        if ($overlay !== []) {
17938a47c60SMark Prins            foreach ($overlay as $data) {
180a760825cSgithub-actions[bot]                [$lat, $lon, $text, $angle, $opacity, $img] = $data;
18145c50327SMark Prins                $rowId++;
18245c50327SMark Prins                $poi .= ", {lat:$lat,lon:$lon,txt:'$text',angle:$angle,opacity:$opacity,img:'$img',rowId: $rowId}";
1838c4eb2fdSMark Prins
1848c4eb2fdSMark Prins                if ($this->getConf('displayformat') === 'DMS') {
1858c4eb2fdSMark Prins                    $lat = $this->convertLat($lat);
1868c4eb2fdSMark Prins                    $lon = $this->convertLon($lon);
1878c4eb2fdSMark Prins                } else {
1888c4eb2fdSMark Prins                    $lat .= 'º';
1898c4eb2fdSMark Prins                    $lon .= 'º';
1908c4eb2fdSMark Prins                }
1918c4eb2fdSMark Prins
192a757236dSMark Prins                $poitable .= '
193a757236dSMark Prins                    <tr>
194a757236dSMark Prins                    <td class="rowId">' . $rowId . '</td>
19557f8d5bbSMark Prins                    <td class="icon"><img src="' . DOKU_BASE . 'lib/plugins/openlayersmap/icons/' . $img . '" alt="'
19657f8d5bbSMark Prins                    . substr($img, 0, -4) . $this->getlang('alt_legend_poi') . '" /></td>
197a57aaf07SMark Prins                    <td class="lat" title="' . $this->getLang('olmapPOIlatTitle') . '">' . $lat . '</td>
198a57aaf07SMark Prins                    <td class="lon" title="' . $this->getLang('olmapPOIlonTitle') . '">' . $lon . '</td>
199a757236dSMark Prins                    <td class="txt">' . $text . '</td>
200a757236dSMark Prins                    </tr>';
20138a47c60SMark Prins            }
20245c50327SMark Prins            $poi = substr($poi, 2);
20338a47c60SMark Prins        }
204e61425c7SMark Prins        if (!empty($gmap ['kmlfile'])) {
205e61425c7SMark Prins            $poitable .= '
206e61425c7SMark Prins                    <tr>
20757f8d5bbSMark Prins                    <td class="rowId"><img src="' . DOKU_BASE
20857f8d5bbSMark Prins                . 'lib/plugins/openlayersmap/toolbar/kml_file.png" alt="KML file" /></td>
20957f8d5bbSMark Prins                    <td class="icon"><img src="' . DOKU_BASE . 'lib/plugins/openlayersmap/toolbar/kml_line.png" alt="'
21057f8d5bbSMark Prins                . $this->getlang('alt_legend_kml') . '" /></td>
211cc74a83cSMark Prins                    <td class="txt" colspan="3">KML track: ' . $this->getFileName($gmap ['kmlfile']) . '</td>
212e61425c7SMark Prins                    </tr>';
213e61425c7SMark Prins        }
214e61425c7SMark Prins        if (!empty($gmap ['gpxfile'])) {
215e61425c7SMark Prins            $poitable .= '
216e61425c7SMark Prins                    <tr>
21757f8d5bbSMark Prins                    <td class="rowId"><img src="' . DOKU_BASE
21857f8d5bbSMark Prins                . 'lib/plugins/openlayersmap/toolbar/gpx_file.png" alt="GPX file" /></td>
21957f8d5bbSMark Prins                    <td class="icon"><img src="' . DOKU_BASE
22057f8d5bbSMark Prins                . 'lib/plugins/openlayersmap/toolbar/gpx_line.png" alt="'
22157f8d5bbSMark Prins                . $this->getlang('alt_legend_gpx') . '" /></td>
222cc74a83cSMark Prins                    <td class="txt" colspan="3">GPX track: ' . $this->getFileName($gmap ['gpxfile']) . '</td>
223e61425c7SMark Prins                    </tr>';
224e61425c7SMark Prins        }
2256914b920SMark Prins        if (!empty($gmap ['geojsonfile'])) {
2266914b920SMark Prins            $poitable .= '
2276914b920SMark Prins                    <tr>
22857f8d5bbSMark Prins                    <td class="rowId"><img src="' . DOKU_BASE
22957f8d5bbSMark Prins                . 'lib/plugins/openlayersmap/toolbar/geojson_file.png" alt="GeoJSON file" /></td>
23057f8d5bbSMark Prins                    <td class="icon"><img src="' . DOKU_BASE
23157f8d5bbSMark Prins                . 'lib/plugins/openlayersmap/toolbar/geojson_line.png" alt="'
23257f8d5bbSMark Prins                . $this->getlang('alt_legend_geojson') . '" /></td>
2336914b920SMark Prins                    <td class="txt" colspan="3">GeoJSON track: ' . $this->getFileName($gmap ['geojsonfile']) . '</td>
2346914b920SMark Prins                    </tr>';
2356914b920SMark Prins        }
236e61425c7SMark Prins
237c8eb1362SMark Prins        $autozoom = empty($gmap ['autozoom']) ? $this->getConf('autoZoomMap') : $gmap ['autozoom'];
23857f8d5bbSMark Prins        $js       = "{mapOpts: {" . $param . ", displayformat: '" . $this->getConf('displayformat')
23957f8d5bbSMark Prins            . "', autozoom: " . $autozoom . "}, poi: [$poi]};";
240a757236dSMark Prins        // unescape the json
241a757236dSMark Prins        $poitable = stripslashes($poitable);
24238a47c60SMark Prins
243a760825cSgithub-actions[bot]        return [$mapid, $js, $mainLat, $mainLon, $poitable, $gmap ['summary'], $imgUrl, $_firstimageID];
24438a47c60SMark Prins    }
24538a47c60SMark Prins
24638a47c60SMark Prins    /**
24738a47c60SMark Prins     * extract parameters for the map from the parameter string
24838a47c60SMark Prins     *
2491c640875SMark Prins     * @param string $str_params
2501c640875SMark Prins     *            string of key="value" pairs
25138a47c60SMark Prins     * @return array associative array of parameters key=>value
25238a47c60SMark Prins     */
253a760825cSgithub-actions[bot]    private function extractParams(string $str_params): array
254a760825cSgithub-actions[bot]    {
255a760825cSgithub-actions[bot]        $param = [];
25638a47c60SMark Prins        preg_match_all('/(\w*)="(.*?)"/us', $str_params, $param, PREG_SET_ORDER);
25738a47c60SMark Prins        // parse match for instructions, break into key value pairs
25838a47c60SMark Prins        $gmap = $this->dflt;
259c8eb1362SMark Prins        foreach ($gmap as $key => &$value) {
260c8eb1362SMark Prins            $defval = $this->getConf('default_' . $key);
261c8eb1362SMark Prins            if ($defval !== '') {
262c8eb1362SMark Prins                $value = $defval;
263c8eb1362SMark Prins            }
264c8eb1362SMark Prins        }
265c8eb1362SMark Prins        unset($value);
26638a47c60SMark Prins        foreach ($param as $kvpair) {
267a760825cSgithub-actions[bot]            [$match, $key, $val] = $kvpair;
26838a47c60SMark Prins            $key = strtolower($key);
26938a47c60SMark Prins            if (isset($gmap [$key])) {
27045c50327SMark Prins                if ($key == 'summary') {
27145c50327SMark Prins                    // preserve case for summary field
27245c50327SMark Prins                    $gmap [$key] = $val;
2731c640875SMark Prins                } elseif ($key == 'id') {
2741c640875SMark Prins                    // preserve case for id field
2751c640875SMark Prins                    $gmap [$key] = $val;
27645c50327SMark Prins                } else {
27738a47c60SMark Prins                    $gmap [$key] = strtolower($val);
27838a47c60SMark Prins                }
27938a47c60SMark Prins            }
28045c50327SMark Prins        }
28138a47c60SMark Prins        return $gmap;
28238a47c60SMark Prins    }
28338a47c60SMark Prins
28438a47c60SMark Prins    /**
28538a47c60SMark Prins     * extract overlay points for the map from the wiki syntax data
28638a47c60SMark Prins     *
2871c640875SMark Prins     * @param string $str_points
2881c640875SMark Prins     *            multi-line string of lat,lon,text triplets
28938a47c60SMark Prins     * @return array multi-dimensional array of lat,lon,text triplets
29038a47c60SMark Prins     */
291a760825cSgithub-actions[bot]    private function extractPoints(string $str_points): array
292a760825cSgithub-actions[bot]    {
293a760825cSgithub-actions[bot]        $point = [];
29457f8d5bbSMark Prins        // preg_match_all('/^([+-]?[0-9].*?),\s*([+-]?[0-9].*?),(.*?),(.*?),(.*?),(.*)$/um',
29557f8d5bbSMark Prins        //      $str_points, $point, PREG_SET_ORDER);
2967a3f422cSMark Prins        /*
29757f8d5bbSMark Prins         * group 1: ([+-]?[0-9]+(?:\.[0-9]*)?)
29857f8d5bbSMark Prins         * group 2: ([+-]?[0-9]+(?:\.[0-9]*)?)
29957f8d5bbSMark Prins         * group 3: (.*?)
30057f8d5bbSMark Prins         * group 4: (.*?)
30157f8d5bbSMark Prins         * group 5: (.*?)
30257f8d5bbSMark Prins         * group 6: (.*)
3037a3f422cSMark Prins         */
30457f8d5bbSMark Prins        preg_match_all(
30557f8d5bbSMark Prins            '/^([+-]?[0-9]+(?:\.[0-9]*)?),\s*([+-]?[0-9]+(?:\.[0-9]*)?),(.*?),(.*?),(.*?),(.*)$/um',
306a760825cSgithub-actions[bot]            $str_points,
307a760825cSgithub-actions[bot]            $point,
308a760825cSgithub-actions[bot]            PREG_SET_ORDER
30957f8d5bbSMark Prins        );
310554f43b5SMark Prins        // create poi array
311a760825cSgithub-actions[bot]        $overlay = [];
31238a47c60SMark Prins        foreach ($point as $pt) {
313a760825cSgithub-actions[bot]            [$match, $lat, $lon, $angle, $opacity, $img, $text] = $pt;
31438a47c60SMark Prins            $lat     = is_numeric($lat) ? $lat : 0;
31538a47c60SMark Prins            $lon     = is_numeric($lon) ? $lon : 0;
31638a47c60SMark Prins            $angle   = is_numeric($angle) ? $angle : 0;
31738a47c60SMark Prins            $opacity = is_numeric($opacity) ? $opacity : 0.8;
31887d958d4SMark Prins            // TODO validate using exist & set up default img?
3191c640875SMark Prins            $img  = trim($img);
3201c640875SMark Prins            $text = p_get_instructions($text);
3211c640875SMark Prins            // dbg ( $text );
3221c640875SMark Prins            $text = p_render("xhtml", $text, $info);
3231c640875SMark Prins            // dbg ( $text );
3241c640875SMark Prins            $text       = addslashes(str_replace("\n", "", $text));
325a760825cSgithub-actions[bot]            $overlay [] = [$lat, $lon, $text, $angle, $opacity, $img];
32638a47c60SMark Prins        }
32738a47c60SMark Prins        return $overlay;
32838a47c60SMark Prins    }
329fcd79b50SMark Prins
330fcd79b50SMark Prins    /**
33157f8d5bbSMark Prins     * Create a Google maps static image url w/ the poi.
33257f8d5bbSMark Prins     *
33357f8d5bbSMark Prins     * @param array $gmap
33457f8d5bbSMark Prins     * @param array $overlay
33557f8d5bbSMark Prins     */
336a760825cSgithub-actions[bot]    private function getGoogle(array $gmap, array $overlay): string
337a760825cSgithub-actions[bot]    {
33857f8d5bbSMark Prins        $sUrl = $this->getConf('iconUrlOverload');
33957f8d5bbSMark Prins        if (!$sUrl) {
34057f8d5bbSMark Prins            $sUrl = DOKU_URL;
34157f8d5bbSMark Prins        }
34257f8d5bbSMark Prins        switch ($gmap ['baselyr']) {
34357f8d5bbSMark Prins            case 'google hybrid':
34457f8d5bbSMark Prins                $maptype = 'hybrid';
34557f8d5bbSMark Prins                break;
34657f8d5bbSMark Prins            case 'google sat':
34757f8d5bbSMark Prins                $maptype = 'satellite';
34857f8d5bbSMark Prins                break;
34957f8d5bbSMark Prins            case 'terrain':
35057f8d5bbSMark Prins            case 'google relief':
35157f8d5bbSMark Prins                $maptype = 'terrain';
35257f8d5bbSMark Prins                break;
35357f8d5bbSMark Prins            case 'google road':
35457f8d5bbSMark Prins            default:
35557f8d5bbSMark Prins                $maptype = 'roadmap';
35657f8d5bbSMark Prins                break;
35757f8d5bbSMark Prins        }
35857f8d5bbSMark Prins        // TODO maybe use viewport / visible instead of center/zoom,
35957f8d5bbSMark Prins        // see: https://developers.google.com/maps/documentation/staticmaps/index#Viewports
36057f8d5bbSMark 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
36157f8d5bbSMark Prins        $imgUrl = "https://maps.googleapis.com/maps/api/staticmap?";
36257f8d5bbSMark Prins        $imgUrl .= "&size=" . str_replace("px", "", $gmap ['width']) . "x"
36357f8d5bbSMark Prins            . str_replace("px", "", $gmap ['height']);
36457f8d5bbSMark Prins        //if (!$this->getConf( 'autoZoomMap')) { // no need for center & zoom params }
36557f8d5bbSMark Prins        $imgUrl .= "&center=" . $gmap ['lat'] . "," . $gmap ['lon'];
36657f8d5bbSMark Prins        // max is 21 (== building scale), but that's overkill..
36757f8d5bbSMark Prins        if ($gmap ['zoom'] > 17) {
36857f8d5bbSMark Prins            $imgUrl .= "&zoom=17";
36957f8d5bbSMark Prins        } else {
37057f8d5bbSMark Prins            $imgUrl .= "&zoom=" . $gmap ['zoom'];
37157f8d5bbSMark Prins        }
372a760825cSgithub-actions[bot]        if ($overlay !== []) {
37357f8d5bbSMark Prins            $rowId = 0;
37457f8d5bbSMark Prins            foreach ($overlay as $data) {
375a760825cSgithub-actions[bot]                [$lat, $lon, $text, $angle, $opacity, $img] = $data;
37657f8d5bbSMark Prins                $imgUrl .= "&markers=icon%3a" . $sUrl . "lib/plugins/openlayersmap/icons/" . $img . "%7c"
37757f8d5bbSMark Prins                    . $lat . "," . $lon . "%7clabel%3a" . ++$rowId;
37857f8d5bbSMark Prins            }
37957f8d5bbSMark Prins        }
38057f8d5bbSMark Prins        $imgUrl .= "&format=png&maptype=" . $maptype;
38157f8d5bbSMark Prins        global $conf;
38257f8d5bbSMark Prins        $imgUrl .= "&language=" . $conf ['lang'];
38357f8d5bbSMark Prins        if ($this->getConf('googleAPIkey')) {
38457f8d5bbSMark Prins            $imgUrl .= "&key=" . $this->getConf('googleAPIkey');
38557f8d5bbSMark Prins        }
38657f8d5bbSMark Prins        return $imgUrl;
38757f8d5bbSMark Prins    }
38857f8d5bbSMark Prins
38957f8d5bbSMark Prins    /**
390fcd79b50SMark Prins     * Create a MapQuest static map API image url.
3911c640875SMark Prins     *
392fcd79b50SMark Prins     * @param array $gmap
393fcd79b50SMark Prins     * @param array $overlay
394fcd79b50SMark Prins     */
395e72390dbSMark Prins    /*
396fcd79b50SMark Prins   private function _getMapQuest($gmap, $overlay) {
397787a5195SMark Prins       $sUrl = $this->getConf ( 'iconUrlOverload' );
398787a5195SMark Prins       if (! $sUrl) {
399787a5195SMark Prins           $sUrl = DOKU_URL;
400787a5195SMark Prins       }
40187d958d4SMark Prins       switch ($gmap ['baselyr']) {
40294c2e868SMark Prins           case 'mapquest hybrid' :
403837eba2fSMark Prins               $maptype = 'hyb';
40487d958d4SMark Prins               break;
40518edeaa5SMark Prins           case 'mapquest sat' :
40644aba0bcSMark Prins               // because sat coverage is very limited use 'hyb' instead of 'sat' so we don't get a blank map
40744aba0bcSMark Prins               $maptype = 'hyb';
40887d958d4SMark Prins               break;
40994c2e868SMark Prins           case 'mapquest road' :
41087d958d4SMark Prins           default :
41187d958d4SMark Prins               $maptype = 'map';
41287d958d4SMark Prins               break;
41387d958d4SMark Prins       }
414004ad4e2SMark Prins       $imgUrl = "http://open.mapquestapi.com/staticmap/v4/getmap?declutter=true&";
41544aba0bcSMark Prins       if (count ( $overlay ) < 1) {
416787a5195SMark Prins           $imgUrl .= "?center=" . $gmap ['lat'] . "," . $gmap ['lon'];
417787a5195SMark Prins           // max level for mapquest is 16
418fcd79b50SMark Prins           if ($gmap ['zoom'] > 16) {
419fcd79b50SMark Prins               $imgUrl .= "&zoom=16";
420fcd79b50SMark Prins           } else {
421fcd79b50SMark Prins               $imgUrl .= "&zoom=" . $gmap ['zoom'];
422fcd79b50SMark Prins           }
42344aba0bcSMark Prins       }
42444aba0bcSMark Prins       // use bestfit instead of center/zoom, needs upperleft/lowerright corners
42557f8d5bbSMark Prins       // $bbox=$this->calcBBOX($overlay, $gmap['lat'], $gmap['lon']);
42644aba0bcSMark Prins       // $imgUrl .= "bestfit=".$bbox['minlat'].",".$bbox['maxlon'].",".$bbox['maxlat'].",".$bbox['minlon'];
42744aba0bcSMark Prins
42857f8d5bbSMark Prins       // TODO declutter option works well for square maps but not for rectangular, maybe compensate for that
42957f8d5bbSMark Prins       //       or compensate the mbr..
43057f8d5bbSMark Prins
43144aba0bcSMark Prins       $imgUrl .= "&size=" . str_replace ( "px", "", $gmap ['width'] ) . "," . str_replace ("px","",$gmap['height']);
43244aba0bcSMark Prins
433fcd79b50SMark Prins       // TODO mapquest allows using one image url with a multiplier $NUMBER eg:
434fcd79b50SMark Prins       // $NUMBER = 2
43557f8d5bbSMark Prins       // $imgUrl .= DOKU_URL."/".DOKU_PLUGIN."/".getPluginName()."/icons/".$img.",$NUMBER,C,"
43657f8d5bbSMark Prins        //  .$lat1.",".$lon1.",0,0,0,0,C,".$lat2.",".$lon2.",0,0,0,0";
437fcd79b50SMark Prins       if (! empty ( $overlay )) {
438fcd79b50SMark Prins           $imgUrl .= "&xis=";
439fcd79b50SMark Prins           foreach ( $overlay as $data ) {
440fcd79b50SMark Prins               list ( $lat, $lon, $text, $angle, $opacity, $img ) = $data;
44144aba0bcSMark Prins               // $imgUrl .= $sUrl."lib/plugins/openlayersmap/icons/".$img.",1,C,".$lat.",".$lon.",0,0,0,0,";
44244aba0bcSMark Prins               $imgUrl .= $sUrl . "lib/plugins/openlayersmap/icons/" . $img . ",1,C," . $lat . "," . $lon . ",";
443fcd79b50SMark Prins           }
444fcd79b50SMark Prins           $imgUrl = substr ( $imgUrl, 0, - 1 );
445fcd79b50SMark Prins       }
44687d958d4SMark Prins       $imgUrl .= "&imageType=png&type=" . $maptype;
447d974ea02SMark Prins       $imgUrl .= "&key=".$this->getConf ( 'mapquestAPIKey' );
448787a5195SMark Prins       return $imgUrl;
449787a5195SMark Prins   }
450e72390dbSMark Prins   */
451cc74a83cSMark Prins
4526e633dd6SMark Prins    /**
45387d958d4SMark Prins     * Create a static OSM map image url w/ the poi from http://staticmap.openstreetmap.de (staticMapLite)
454fcf646d2SMark Prins     * use http://staticmap.openstreetmap.de "staticMapLite" or a local version
4551c640875SMark Prins     *
45687d958d4SMark Prins     * @param array $gmap
45787d958d4SMark Prins     * @param array $overlay
458fcf646d2SMark Prins     *
45957f8d5bbSMark Prins     * @return false|string
460fcf646d2SMark Prins     * @todo implementation for http://ojw.dev.openstreetmap.org/StaticMapDev/
46187d958d4SMark Prins     */
462a760825cSgithub-actions[bot]    private function getStaticOSM(array $gmap, array $overlay)
463a760825cSgithub-actions[bot]    {
464fcf646d2SMark Prins        global $conf;
465372f1508SMark Prins
466751c8ef2SMark Prins        if ($this->getConf('optionStaticMapGenerator') === 'local') {
467d974ea02SMark Prins            // using local basemap composer
468a760825cSgithub-actions[bot]            if (($myMap = plugin_load('helper', 'openlayersmap_staticmap')) === null) {
469*f204b8caSMark Prins                Logger::error(
470*f204b8caSMark Prins                    'openlayersmap_staticmap plugin is not available for use.',
471*f204b8caSMark Prins                    $myMap
47257f8d5bbSMark Prins                );
47353bfe4a3SMark Prins            }
474a760825cSgithub-actions[bot]            if (($geophp = plugin_load('helper', 'geophp')) === null) {
475*f204b8caSMark Prins                Logger::debug('geophp plugin is not available for use.', $geophp);
47653bfe4a3SMark Prins            }
47757f8d5bbSMark Prins            $size = str_replace("px", "", $gmap ['width']) . "x"
47857f8d5bbSMark Prins                . str_replace("px", "", $gmap ['height']);
47953bfe4a3SMark Prins
480a760825cSgithub-actions[bot]            $markers = [];
481a760825cSgithub-actions[bot]            if ($overlay !== []) {
48253bfe4a3SMark Prins                foreach ($overlay as $data) {
483a760825cSgithub-actions[bot]                    [$lat, $lon, $text, $angle, $opacity, $img] = $data;
484751c8ef2SMark Prins                    $iconStyle  = substr($img, 0, -4);
485a760825cSgithub-actions[bot]                    $markers [] = ['lat'  => $lat, 'lon'  => $lon, 'type' => $iconStyle];
48653bfe4a3SMark Prins                }
487372f1508SMark Prins            }
488372f1508SMark Prins
489d2f4772aSMark Prins            $apikey = '';
49018edeaa5SMark Prins            switch ($gmap ['baselyr']) {
49118edeaa5SMark Prins                case 'mapnik':
492fcf646d2SMark Prins                case 'openstreetmap':
493fcf646d2SMark Prins                    $maptype = 'openstreetmap';
49418edeaa5SMark Prins                    break;
495fcf646d2SMark Prins                case 'transport':
496fcf646d2SMark Prins                    $maptype = 'transport';
497b63742deSMark Prins                    $apikey  = '?apikey=' . $this->getConf('tfApiKey');
498fcf646d2SMark Prins                    break;
499fcf646d2SMark Prins                case 'landscape':
500fcf646d2SMark Prins                    $maptype = 'landscape';
501b63742deSMark Prins                    $apikey  = '?apikey=' . $this->getConf('tfApiKey');
502d2f4772aSMark Prins                    break;
503d2f4772aSMark Prins                case 'outdoors':
504d2f4772aSMark Prins                    $maptype = 'outdoors';
505b63742deSMark Prins                    $apikey  = '?apikey=' . $this->getConf('tfApiKey');
50618edeaa5SMark Prins                    break;
50718edeaa5SMark Prins                case 'cycle map':
50818edeaa5SMark Prins                    $maptype = 'cycle';
509b63742deSMark Prins                    $apikey  = '?apikey=' . $this->getConf('tfApiKey');
510372f1508SMark Prins                    break;
511fcf646d2SMark Prins                case 'hike and bike map':
512fcf646d2SMark Prins                    $maptype = 'hikeandbike';
513fcf646d2SMark Prins                    break;
514fcf646d2SMark Prins                case 'mapquest hybrid':
515fcf646d2SMark Prins                case 'mapquest road':
516fcf646d2SMark Prins                case 'mapquest sat':
517fcf646d2SMark Prins                    $maptype = 'mapquest';
518fcf646d2SMark Prins                    break;
51918edeaa5SMark Prins                default:
52018edeaa5SMark Prins                    $maptype = '';
52118edeaa5SMark Prins                    break;
52218edeaa5SMark Prins            }
523d974ea02SMark Prins
52457f8d5bbSMark Prins            $result = $myMap->getMap(
525a760825cSgithub-actions[bot]                $gmap ['lat'],
526a760825cSgithub-actions[bot]                $gmap ['lon'],
527a760825cSgithub-actions[bot]                $gmap ['zoom'],
528a760825cSgithub-actions[bot]                $size,
529a760825cSgithub-actions[bot]                $maptype,
530a760825cSgithub-actions[bot]                $markers,
531a760825cSgithub-actions[bot]                $gmap ['gpxfile'],
532a760825cSgithub-actions[bot]                $gmap ['kmlfile'],
533a760825cSgithub-actions[bot]                $gmap ['geojsonfile'],
534a760825cSgithub-actions[bot]                $apikey
53557f8d5bbSMark Prins            );
536d974ea02SMark Prins        } else {
537d974ea02SMark Prins            // using external basemap composer
538d974ea02SMark Prins
53957f8d5bbSMark Prins            // https://staticmap.openstreetmap.de/staticmap.php?center=47.000622235634,10
54057f8d5bbSMark Prins            //.117187497601&zoom=5&size=500x350
54157f8d5bbSMark Prins            // &markers=48.999812532766,8.3593749976708,lightblue1|43.154850037315,17.499999997306,
54257f8d5bbSMark Prins            //  lightblue1|49.487527053077,10.820312497573,ltblu-pushpin|47.951071133739,15.917968747369,
54357f8d5bbSMark Prins            //  ol-marker|47.921629720114,18.027343747285,ol-marker-gold|47.951071133739,19.257812497236,
54457f8d5bbSMark Prins            //  ol-marker-blue|47.180141361692,19.257812497236,ol-marker-green
54557f8d5bbSMark Prins            $imgUrl = "https://staticmap.openstreetmap.de/staticmap.php";
546d974ea02SMark Prins            $imgUrl .= "?center=" . $gmap ['lat'] . "," . $gmap ['lon'];
54757f8d5bbSMark Prins            $imgUrl .= "&size=" . str_replace("px", "", $gmap ['width']) . "x"
54857f8d5bbSMark Prins                . str_replace("px", "", $gmap ['height']);
549d974ea02SMark Prins
550d974ea02SMark Prins            if ($gmap ['zoom'] > 16) {
551d974ea02SMark Prins                // actually this could even be 18, but that seems overkill
552d974ea02SMark Prins                $imgUrl .= "&zoom=16";
553d974ea02SMark Prins            } else {
554d974ea02SMark Prins                $imgUrl .= "&zoom=" . $gmap ['zoom'];
555d974ea02SMark Prins            }
55618edeaa5SMark Prins
557a760825cSgithub-actions[bot]            if ($overlay !== []) {
55887d958d4SMark Prins                $rowId  = 0;
55987d958d4SMark Prins                $imgUrl .= "&markers=";
56087d958d4SMark Prins                foreach ($overlay as $data) {
561a760825cSgithub-actions[bot]                    [$lat, $lon, $text, $angle, $opacity, $img] = $data;
56287d958d4SMark Prins                    $rowId++;
56353bfe4a3SMark Prins                    $iconStyle = "lightblue$rowId";
56487d958d4SMark Prins                    $imgUrl    .= "$lat,$lon,$iconStyle%7c";
56587d958d4SMark Prins                }
56687d958d4SMark Prins                $imgUrl = substr($imgUrl, 0, -3);
56787d958d4SMark Prins            }
56887d958d4SMark Prins
569f4b9bdacSMark Prins            $result = $imgUrl;
570628e43ccSMark Prins        }
571628e43ccSMark Prins        return $result;
572628e43ccSMark Prins    }
573628e43ccSMark Prins
57444aba0bcSMark Prins    /**
57557f8d5bbSMark Prins     * Create a Bing maps static image url w/ the poi.
57657f8d5bbSMark Prins     *
57757f8d5bbSMark Prins     * @param array $gmap
57857f8d5bbSMark Prins     * @param array $overlay
57957f8d5bbSMark Prins     */
580a760825cSgithub-actions[bot]    private function getBing(array $gmap, array $overlay): string
581a760825cSgithub-actions[bot]    {
58257f8d5bbSMark Prins        switch ($gmap ['baselyr']) {
58357f8d5bbSMark Prins            case 've hybrid':
58457f8d5bbSMark Prins            case 'bing hybrid':
58557f8d5bbSMark Prins                $maptype = 'AerialWithLabels';
58657f8d5bbSMark Prins                break;
58757f8d5bbSMark Prins            case 've sat':
58857f8d5bbSMark Prins            case 'bing sat':
58957f8d5bbSMark Prins                $maptype = 'Aerial';
59057f8d5bbSMark Prins                break;
59157f8d5bbSMark Prins            case 've normal':
59257f8d5bbSMark Prins            case 've road':
59357f8d5bbSMark Prins            case 've':
59457f8d5bbSMark Prins            case 'bing road':
59557f8d5bbSMark Prins            default:
59657f8d5bbSMark Prins                $maptype = 'Road';
59757f8d5bbSMark Prins                break;
59857f8d5bbSMark Prins        }
59957f8d5bbSMark Prins        $imgUrl = "https://dev.virtualearth.net/REST/v1/Imagery/Map/" . $maptype;// . "/";
60057f8d5bbSMark Prins        if ($this->getConf('autoZoomMap')) {
60157f8d5bbSMark Prins            $bbox = $this->calcBBOX($overlay, $gmap ['lat'], $gmap ['lon']);
60257f8d5bbSMark Prins            //$imgUrl .= "?ma=" . $bbox ['minlat'] . "," . $bbox ['minlon'] . ","
60357f8d5bbSMark Prins            //          . $bbox ['maxlat'] . "," . $bbox ['maxlon'];
60457f8d5bbSMark Prins            $imgUrl .= "?ma=" . $bbox ['minlat'] . "%2C" . $bbox ['minlon'] . "%2C" . $bbox ['maxlat']
60557f8d5bbSMark Prins                . "%2C" . $bbox ['maxlon'];
60657f8d5bbSMark Prins            $imgUrl .= "&dcl=1";
60757f8d5bbSMark Prins        }
60857f8d5bbSMark Prins        if (strpos($imgUrl, "?") === false)
60957f8d5bbSMark Prins            $imgUrl .= "?";
61057f8d5bbSMark Prins
61157f8d5bbSMark Prins        //$imgUrl .= "&ms=" . str_replace ( "px", "", $gmap ['width'] ) . ","
61257f8d5bbSMark Prins        //          . str_replace ( "px", "", $gmap ['height'] );
61357f8d5bbSMark Prins        $imgUrl .= "&ms=" . str_replace("px", "", $gmap ['width']) . "%2C"
61457f8d5bbSMark Prins            . str_replace("px", "", $gmap ['height']);
61557f8d5bbSMark Prins        $imgUrl .= "&key=" . $this->getConf('bingAPIKey');
616a760825cSgithub-actions[bot]        if ($overlay !== []) {
61757f8d5bbSMark Prins            $rowId = 0;
61857f8d5bbSMark Prins            foreach ($overlay as $data) {
619a760825cSgithub-actions[bot]                [$lat, $lon, $text, $angle, $opacity, $img] = $data;
62057f8d5bbSMark Prins                // TODO icon style lookup, see: http://msdn.microsoft.com/en-us/library/ff701719.aspx for iconStyle
62157f8d5bbSMark Prins                $iconStyle = 32;
62257f8d5bbSMark Prins                $rowId++;
62357f8d5bbSMark Prins                // NOTE: the max number of pushpins is 18! or we have to use POST
62457f8d5bbSMark Prins                //  (http://msdn.microsoft.com/en-us/library/ff701724.aspx)
62557f8d5bbSMark Prins                if ($rowId == 18) {
62657f8d5bbSMark Prins                    break;
62757f8d5bbSMark Prins                }
62857f8d5bbSMark Prins                //$imgUrl .= "&pp=$lat,$lon;$iconStyle;$rowId";
62957f8d5bbSMark Prins                $imgUrl .= "&pp=$lat%2C$lon%3B$iconStyle%3B$rowId";
63057f8d5bbSMark Prins            }
63157f8d5bbSMark Prins        }
63257f8d5bbSMark Prins        global $conf;
63357f8d5bbSMark Prins        $imgUrl .= "&fmt=png";
63457f8d5bbSMark Prins        $imgUrl .= "&c=" . $conf ['lang'];
63557f8d5bbSMark Prins        return $imgUrl;
63657f8d5bbSMark Prins    }
63757f8d5bbSMark Prins
63857f8d5bbSMark Prins    /**
63944aba0bcSMark Prins     * Calculate the minimum bbox for a start location + poi.
64044aba0bcSMark Prins     *
6411c640875SMark Prins     * @param array $overlay
6421c640875SMark Prins     *            multi-dimensional array of array($lat, $lon, $text, $angle, $opacity, $img)
6431c640875SMark Prins     * @param float $lat
6441c640875SMark Prins     *            latitude for map center
6451c640875SMark Prins     * @param float $lon
6461c640875SMark Prins     *            longitude for map center
64757f8d5bbSMark Prins     * @return array :float array describing the mbr and center point
64844aba0bcSMark Prins     */
649a760825cSgithub-actions[bot]    private function calcBBOX(array $overlay, float $lat, float $lon): array
650a760825cSgithub-actions[bot]    {
651a760825cSgithub-actions[bot]        $lats = [$lat];
652a760825cSgithub-actions[bot]        $lons = [$lon];
653837eba2fSMark Prins        foreach ($overlay as $data) {
654a760825cSgithub-actions[bot]            [$lat, $lon, $text, $angle, $opacity, $img] = $data;
655837eba2fSMark Prins            $lats [] = $lat;
656837eba2fSMark Prins            $lons [] = $lon;
657837eba2fSMark Prins        }
658837eba2fSMark Prins        sort($lats);
659837eba2fSMark Prins        sort($lons);
66044aba0bcSMark Prins        // TODO: make edge/wrap around cases work
66144aba0bcSMark Prins        $centerlat = $lats [0] + ($lats [count($lats) - 1] - $lats [0]);
66244aba0bcSMark Prins        $centerlon = $lons [0] + ($lons [count($lats) - 1] - $lons [0]);
663a760825cSgithub-actions[bot]        return ['minlat'    => $lats [0], 'minlon'    => $lons [0], 'maxlat'    => $lats [count($lats) - 1], 'maxlon'    => $lons [count($lats) - 1], 'centerlat' => $centerlat, 'centerlon' => $centerlon];
66487d958d4SMark Prins    }
665cc74a83cSMark Prins
666cc74a83cSMark Prins    /**
66757f8d5bbSMark Prins     * convert latitude in decimal degrees to DMS+hemisphere.
6681c640875SMark Prins     *
66957f8d5bbSMark Prins     * @param float $decimaldegrees
67057f8d5bbSMark Prins     * @todo move this into a shared library
671cc74a83cSMark Prins     */
672a760825cSgithub-actions[bot]    private function convertLat(float $decimaldegrees): string
673a760825cSgithub-actions[bot]    {
67457f8d5bbSMark Prins        if (strpos($decimaldegrees, '-') !== false) {
67557f8d5bbSMark Prins            $latPos = "S";
67657f8d5bbSMark Prins        } else {
67757f8d5bbSMark Prins            $latPos = "N";
67857f8d5bbSMark Prins        }
67957f8d5bbSMark Prins        $dms = $this->convertDDtoDMS(abs($decimaldegrees));
68057f8d5bbSMark Prins        return hsc($dms . $latPos);
681cc74a83cSMark Prins    }
6828c4eb2fdSMark Prins
6838c4eb2fdSMark Prins    /**
6848c4eb2fdSMark Prins     * Convert decimal degrees to degrees, minutes, seconds format
6858c4eb2fdSMark Prins     *
6868c4eb2fdSMark Prins     * @param float $decimaldegrees
6878c4eb2fdSMark Prins     * @return string dms
68857f8d5bbSMark Prins     * @todo move this into a shared library
6898c4eb2fdSMark Prins     */
690a760825cSgithub-actions[bot]    private function convertDDtoDMS(float $decimaldegrees): string
691a760825cSgithub-actions[bot]    {
6928c4eb2fdSMark Prins        $dms  = floor($decimaldegrees);
6938c4eb2fdSMark Prins        $secs = ($decimaldegrees - $dms) * 3600;
6948c4eb2fdSMark Prins        $min  = floor($secs / 60);
6958c4eb2fdSMark Prins        $sec  = round($secs - ($min * 60), 3);
6968c4eb2fdSMark Prins        $dms  .= 'º' . $min . '\'' . $sec . '"';
6978c4eb2fdSMark Prins        return $dms;
6988c4eb2fdSMark Prins    }
6998c4eb2fdSMark Prins
7008c4eb2fdSMark Prins    /**
7018c4eb2fdSMark Prins     * convert longitude in decimal degrees to DMS+hemisphere.
7028c4eb2fdSMark Prins     *
7038c4eb2fdSMark Prins     * @param float $decimaldegrees
70457f8d5bbSMark Prins     * @todo move this into a shared library
7058c4eb2fdSMark Prins     */
706a760825cSgithub-actions[bot]    private function convertLon(float $decimaldegrees): string
707a760825cSgithub-actions[bot]    {
7088c4eb2fdSMark Prins        if (strpos($decimaldegrees, '-') !== false) {
7098c4eb2fdSMark Prins            $lonPos = "W";
7108c4eb2fdSMark Prins        } else {
7118c4eb2fdSMark Prins            $lonPos = "E";
7128c4eb2fdSMark Prins        }
71357f8d5bbSMark Prins        $dms = $this->convertDDtoDMS(abs($decimaldegrees));
7148c4eb2fdSMark Prins        return hsc($dms . $lonPos);
7158c4eb2fdSMark Prins    }
71657f8d5bbSMark Prins
71757f8d5bbSMark Prins    /**
71857f8d5bbSMark Prins     * Figures out the base filename of a media path.
71957f8d5bbSMark Prins     *
72057f8d5bbSMark Prins     * @param string $mediaLink
72157f8d5bbSMark Prins     */
722a760825cSgithub-actions[bot]    private function getFileName(string $mediaLink): string
723a760825cSgithub-actions[bot]    {
72457f8d5bbSMark Prins        $mediaLink = str_replace('[[', '', $mediaLink);
72557f8d5bbSMark Prins        $mediaLink = str_replace(']]', '', $mediaLink);
72657f8d5bbSMark Prins        $mediaLink = substr($mediaLink, 0, -4);
727a760825cSgithub-actions[bot]
72857f8d5bbSMark Prins        $parts     = explode(':', $mediaLink);
72957f8d5bbSMark Prins        $mediaLink = end($parts);
73057f8d5bbSMark Prins        return str_replace('_', ' ', $mediaLink);
73157f8d5bbSMark Prins    }
73257f8d5bbSMark Prins
73357f8d5bbSMark Prins    /**
73457f8d5bbSMark Prins     *
73557f8d5bbSMark Prins     * @see DokuWiki_Syntax_Plugin::render()
73657f8d5bbSMark Prins     */
737a760825cSgithub-actions[bot]    public function render($format, Doku_Renderer $renderer, $data): bool
738a760825cSgithub-actions[bot]    {
73957f8d5bbSMark Prins        // set to true after external scripts tags are written
74057f8d5bbSMark Prins        static $initialised = false;
74157f8d5bbSMark Prins        // incremented for each map tag in the page source so we can keep track of each map in this page
74257f8d5bbSMark Prins        static $mapnumber = 0;
74357f8d5bbSMark Prins
744a760825cSgithub-actions[bot]        [$mapid, $param, $mainLat, $mainLon, $poitable, $poitabledesc, $staticImgUrl, $_firstimage] = $data;
74557f8d5bbSMark Prins
746751c8ef2SMark Prins        if ($format === 'xhtml') {
74757f8d5bbSMark Prins            $olscript     = '';
748751c8ef2SMark Prins            $stadiaEnable = $this->getConf('enableStadia');
74957f8d5bbSMark Prins            $osmEnable    = $this->getConf('enableOSM');
75057f8d5bbSMark Prins            $enableBing   = $this->getConf('enableBing');
75157f8d5bbSMark Prins
75257f8d5bbSMark Prins            $scriptEnable = '';
75357f8d5bbSMark Prins            if (!$initialised) {
75457f8d5bbSMark Prins                $initialised = true;
7557390889dSMark Prins                // render necessary script tags only once
756660554e1SMark Prins                $olscript = '<script defer="defer" src="' . DOKU_BASE . 'lib/plugins/openlayersmap/ol/ol.js"></script>
757660554e1SMark Prins<script defer="defer" src="' . DOKU_BASE . 'lib/plugins/openlayersmap/ol/ol-layerswitcher.js"></script>';
75857f8d5bbSMark Prins
75957f8d5bbSMark Prins                $scriptEnable = '<script defer="defer" src="data:text/javascript;base64,';
7607390889dSMark Prins                $scriptSrc    = $olscript ? 'const olEnable=true;' : 'const olEnable=false;';
7617390889dSMark Prins                $scriptSrc    .= 'const osmEnable=' . ($osmEnable ? 'true' : 'false') . ';';
762751c8ef2SMark Prins                $scriptSrc    .= 'const stadiaEnable=' . ($stadiaEnable ? 'true' : 'false') . ';';
7637390889dSMark Prins                $scriptSrc    .= 'const bEnable=' . ($enableBing ? 'true' : 'false') . ';';
7647390889dSMark Prins                $scriptSrc    .= 'const bApiKey="' . $this->getConf('bingAPIKey') . '";';
7657390889dSMark Prins                $scriptSrc    .= 'const tfApiKey="' . $this->getConf('tfApiKey') . '";';
7667390889dSMark Prins                $scriptSrc    .= 'const gApiKey="' . $this->getConf('googleAPIkey') . '";';
7677390889dSMark Prins                $scriptSrc    .= 'olMapData = []; let olMaps = {}; let olMapOverlays = {};';
76857f8d5bbSMark Prins                $scriptEnable .= base64_encode($scriptSrc);
76957f8d5bbSMark Prins                $scriptEnable .= '"></script>';
77057f8d5bbSMark Prins            }
7717390889dSMark Prins            $renderer->doc .= "$olscript\n$scriptEnable";
77257f8d5bbSMark Prins            $renderer->doc .= '<div class="olMapHelp">' . $this->locale_xhtml("help") . '</div>';
77357f8d5bbSMark Prins            if ($this->getConf('enableA11y')) {
77457f8d5bbSMark Prins                $renderer->doc .= '<div id="' . $mapid . '-static" class="olStaticMap">'
77557f8d5bbSMark Prins                    . p_render($format, p_get_instructions($staticImgUrl), $info) . '</div>';
77657f8d5bbSMark Prins            }
77757f8d5bbSMark Prins            $renderer->doc .= '<div id="' . $mapid . '-clearer" class="clearer"><p>&nbsp;</p></div>';
77857f8d5bbSMark Prins            if ($this->getConf('enableA11y')) {
77957f8d5bbSMark Prins                // render a table of the POI for the print and a11y presentation, it is hidden using javascript
7807390889dSMark Prins                $renderer->doc .= '
7813f760703SMark Prins                <div id="' . $mapid . '-table-span" class="olPOItableSpan">
7823f760703SMark Prins                    <table id="' . $mapid . '-table" class="olPOItable">
78357f8d5bbSMark Prins                    <caption class="olPOITblCaption">' . $this->getLang('olmapPOItitle') . '</caption>
78457f8d5bbSMark Prins                    <thead class="olPOITblHeader">
78557f8d5bbSMark Prins                    <tr>
78657f8d5bbSMark Prins                    <th class="rowId" scope="col">id</th>
78757f8d5bbSMark Prins                    <th class="icon" scope="col">' . $this->getLang('olmapPOIicon') . '</th>
78857f8d5bbSMark Prins                    <th class="lat" scope="col" title="' . $this->getLang('olmapPOIlatTitle') . '">'
78957f8d5bbSMark Prins                    . $this->getLang('olmapPOIlat') . '</th>
79057f8d5bbSMark Prins                    <th class="lon" scope="col" title="' . $this->getLang('olmapPOIlonTitle') . '">'
79157f8d5bbSMark Prins                    . $this->getLang('olmapPOIlon') . '</th>
79257f8d5bbSMark Prins                    <th class="txt" scope="col">' . $this->getLang('olmapPOItxt') . '</th>
79357f8d5bbSMark Prins                    </tr>
79457f8d5bbSMark Prins                    </thead>';
79557f8d5bbSMark Prins                if ($poitabledesc != '') {
79657f8d5bbSMark Prins                    $renderer->doc .= '<tfoot class="olPOITblFooter"><tr><td colspan="5">' . $poitabledesc
79757f8d5bbSMark Prins                        . '</td></tr></tfoot>';
79857f8d5bbSMark Prins                }
79957f8d5bbSMark Prins                $renderer->doc .= '<tbody class="olPOITblBody">' . $poitable . '</tbody>
8007390889dSMark Prins                    </table>
8017390889dSMark Prins                </div>';
8027390889dSMark Prins                $renderer->doc .= "\n";
80357f8d5bbSMark Prins            }
80457f8d5bbSMark Prins            // render inline mapscript parts
80557f8d5bbSMark Prins            $renderer->doc .= '<script defer="defer" src="data:text/javascript;base64,';
80657f8d5bbSMark Prins            $renderer->doc .= base64_encode("olMapData[$mapnumber] = $param");
80757f8d5bbSMark Prins            $renderer->doc .= '"></script>';
80857f8d5bbSMark Prins            $mapnumber++;
80957f8d5bbSMark Prins            return true;
810751c8ef2SMark Prins        } elseif ($format === 'metadata') {
81157f8d5bbSMark Prins            if (!(($this->dflt ['lat'] == $mainLat) && ($this->dflt ['lon'] == $mainLon))) {
81257f8d5bbSMark Prins                // render geo metadata, unless they are the default
81357f8d5bbSMark Prins                $renderer->meta ['geo'] ['lat'] = $mainLat;
81457f8d5bbSMark Prins                $renderer->meta ['geo'] ['lon'] = $mainLon;
815a760825cSgithub-actions[bot]                if (($geophp = plugin_load('helper', 'geophp')) !== null) {
81657f8d5bbSMark Prins                    // if we have the geoPHP helper, add the geohash
817*f204b8caSMark Prins                    try {
818*f204b8caSMark Prins                        $renderer->meta['geo']['geohash'] = (new Point($mainLon, $mainLat))->out('geohash');
819*f204b8caSMark Prins                    } catch (Exception $e) {
820*f204b8caSMark Prins                        Logger::error("Failed to create geohash for: $mainLat, $mainLon");
821*f204b8caSMark Prins                    }
82257f8d5bbSMark Prins                }
82357f8d5bbSMark Prins            }
82457f8d5bbSMark Prins
82557f8d5bbSMark Prins            if (($this->getConf('enableA11y')) && (!empty($_firstimage))) {
82657f8d5bbSMark Prins                // add map local image into relation/firstimage if not already filled and when it is a local image
82757f8d5bbSMark Prins
82857f8d5bbSMark Prins                global $ID;
82957f8d5bbSMark Prins                $rel = p_get_metadata($ID, 'relation', METADATA_RENDER_USING_CACHE);
83068188742SMark Prins                // $img = $rel ['firstimage'];
83168188742SMark Prins                if (empty($rel ['firstimage']) /* || $img == $_firstimage*/) {
832*f204b8caSMark Prins                    //Logger::debug(
833*f204b8caSMark Prins                    // 'olmap::render#rendering image relation metadata for _firstimage as $img was empty or same.',
834*f204b8caSMark Prins                    // $_firstimage);
835*f204b8caSMark Prins
83657f8d5bbSMark Prins                    // This seems to never work; the firstimage entry in the .meta file is empty
83757f8d5bbSMark Prins                    // $renderer->meta['relation']['firstimage'] = $_firstimage;
83857f8d5bbSMark Prins                    // ... and neither does this; the firstimage entry in the .meta file is empty
83957f8d5bbSMark Prins                    // $relation = array('relation'=>array('firstimage'=>$_firstimage));
84057f8d5bbSMark Prins                    // p_set_metadata($ID, $relation, false, false);
84157f8d5bbSMark Prins                    // ... this works
84257f8d5bbSMark Prins                    $renderer->internalmedia($_firstimage, $poitabledesc);
84357f8d5bbSMark Prins                }
84457f8d5bbSMark Prins            }
84557f8d5bbSMark Prins            return true;
84657f8d5bbSMark Prins        }
84757f8d5bbSMark Prins        return false;
84857f8d5bbSMark Prins    }
84938a47c60SMark Prins}
850