xref: /plugin/openlayersmap/syntax/olmap.php (revision 3ebe658b2ec361f0150282b5943779d8d088a5e6)
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
20*3ebe658bSMark Prinsuse geoPHP\Geometry\Point;
21*3ebe658bSMark 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 {
8938a47c60SMark Prins        // break matched cdata into its components
9038a47c60SMark Prins        list ($str_params, $str_points) = explode('>', substr($match, 7, -9), 2);
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            }
128e72390dbSMark 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            }
141e72390dbSMark Prins        } */ else {
1428e7c4263SMark Prins            // default OSM
14357f8d5bbSMark Prins            $_firstimageID = $this->getStaticOSM($gmap, $overlay);
144fc16f3cdSMark Prins            $imgUrl        .= $_firstimageID;
14553bfe4a3SMark Prins            if($this->getConf('optionStaticMapGenerator') == 'remote') {
14653bfe4a3SMark Prins                $imgUrl .= "&.png";
14753bfe4a3SMark Prins            }
14887d958d4SMark Prins        }
14987d958d4SMark Prins
150628e43ccSMark Prins        // append dw p_render specific params and render
15157f8d5bbSMark Prins        $imgUrl .= "?" . str_replace("px", "", $gmap ['width']) . "x"
15257f8d5bbSMark Prins            . str_replace("px", "", $gmap ['height']);
1536ba8d085SMark Prins        $imgUrl .= "&nolink";
1548e7c4263SMark Prins
1558e7c4263SMark Prins        // add nocache option for selected services
1568e7c4263SMark Prins        if($_nocache) {
1578e7c4263SMark Prins            $imgUrl .= "&nocache";
1588e7c4263SMark Prins        }
1598e7c4263SMark Prins
160fcd79b50SMark Prins        $imgUrl .= " |" . $gmap ['summary'] . " }}";
161fcd79b50SMark Prins
1628e7c4263SMark Prins        // dbglog($imgUrl,"complete image tags is:");
1638e7c4263SMark Prins
16438a47c60SMark Prins        $mapid = $gmap ['id'];
16538a47c60SMark Prins        // create a javascript parameter string for the map
16638a47c60SMark Prins        $param = '';
16738a47c60SMark Prins        foreach($gmap as $key => $val) {
16838a47c60SMark Prins            $param .= is_numeric($val) ? "$key: $val, " : "$key: '" . hsc($val) . "', ";
16938a47c60SMark Prins        }
17038a47c60SMark Prins        if(!empty ($param)) {
17145c50327SMark Prins            $param = substr($param, 0, -2);
17238a47c60SMark Prins        }
17338a47c60SMark Prins        unset ($gmap ['id']);
17438a47c60SMark Prins
17538a47c60SMark Prins        // create a javascript serialisation of the point data
17638a47c60SMark Prins        $poi      = '';
17745c50327SMark Prins        $poitable = '';
17845c50327SMark Prins        $rowId    = 0;
17938a47c60SMark Prins        if(!empty ($overlay)) {
18038a47c60SMark Prins            foreach($overlay as $data) {
18138a47c60SMark Prins                list ($lat, $lon, $text, $angle, $opacity, $img) = $data;
18245c50327SMark Prins                $rowId++;
18345c50327SMark Prins                $poi .= ", {lat:$lat,lon:$lon,txt:'$text',angle:$angle,opacity:$opacity,img:'$img',rowId: $rowId}";
1848c4eb2fdSMark Prins
1858c4eb2fdSMark Prins                if($this->getConf('displayformat') === 'DMS') {
1868c4eb2fdSMark Prins                    $lat = $this->convertLat($lat);
1878c4eb2fdSMark Prins                    $lon = $this->convertLon($lon);
1888c4eb2fdSMark Prins                } else {
1898c4eb2fdSMark Prins                    $lat .= 'º';
1908c4eb2fdSMark Prins                    $lon .= 'º';
1918c4eb2fdSMark Prins                }
1928c4eb2fdSMark Prins
193a757236dSMark Prins                $poitable .= '
194a757236dSMark Prins                    <tr>
195a757236dSMark Prins                    <td class="rowId">' . $rowId . '</td>
19657f8d5bbSMark Prins                    <td class="icon"><img src="' . DOKU_BASE . 'lib/plugins/openlayersmap/icons/' . $img . '" alt="'
19757f8d5bbSMark Prins                    . substr($img, 0, -4) . $this->getlang('alt_legend_poi') . '" /></td>
198a57aaf07SMark Prins                    <td class="lat" title="' . $this->getLang('olmapPOIlatTitle') . '">' . $lat . '</td>
199a57aaf07SMark Prins                    <td class="lon" title="' . $this->getLang('olmapPOIlonTitle') . '">' . $lon . '</td>
200a757236dSMark Prins                    <td class="txt">' . $text . '</td>
201a757236dSMark Prins                    </tr>';
20238a47c60SMark Prins            }
20345c50327SMark Prins            $poi = substr($poi, 2);
20438a47c60SMark Prins        }
205e61425c7SMark Prins        if(!empty ($gmap ['kmlfile'])) {
206e61425c7SMark Prins            $poitable .= '
207e61425c7SMark Prins                    <tr>
20857f8d5bbSMark Prins                    <td class="rowId"><img src="' . DOKU_BASE
20957f8d5bbSMark Prins                . 'lib/plugins/openlayersmap/toolbar/kml_file.png" alt="KML file" /></td>
21057f8d5bbSMark Prins                    <td class="icon"><img src="' . DOKU_BASE . 'lib/plugins/openlayersmap/toolbar/kml_line.png" alt="'
21157f8d5bbSMark Prins                . $this->getlang('alt_legend_kml') . '" /></td>
212cc74a83cSMark Prins                    <td class="txt" colspan="3">KML track: ' . $this->getFileName($gmap ['kmlfile']) . '</td>
213e61425c7SMark Prins                    </tr>';
214e61425c7SMark Prins        }
215e61425c7SMark Prins        if(!empty ($gmap ['gpxfile'])) {
216e61425c7SMark Prins            $poitable .= '
217e61425c7SMark Prins                    <tr>
21857f8d5bbSMark Prins                    <td class="rowId"><img src="' . DOKU_BASE
21957f8d5bbSMark Prins                . 'lib/plugins/openlayersmap/toolbar/gpx_file.png" alt="GPX file" /></td>
22057f8d5bbSMark Prins                    <td class="icon"><img src="' . DOKU_BASE
22157f8d5bbSMark Prins                . 'lib/plugins/openlayersmap/toolbar/gpx_line.png" alt="'
22257f8d5bbSMark Prins                . $this->getlang('alt_legend_gpx') . '" /></td>
223cc74a83cSMark Prins                    <td class="txt" colspan="3">GPX track: ' . $this->getFileName($gmap ['gpxfile']) . '</td>
224e61425c7SMark Prins                    </tr>';
225e61425c7SMark Prins        }
2266914b920SMark Prins        if(!empty ($gmap ['geojsonfile'])) {
2276914b920SMark Prins            $poitable .= '
2286914b920SMark Prins                    <tr>
22957f8d5bbSMark Prins                    <td class="rowId"><img src="' . DOKU_BASE
23057f8d5bbSMark Prins                . 'lib/plugins/openlayersmap/toolbar/geojson_file.png" alt="GeoJSON file" /></td>
23157f8d5bbSMark Prins                    <td class="icon"><img src="' . DOKU_BASE
23257f8d5bbSMark Prins                . 'lib/plugins/openlayersmap/toolbar/geojson_line.png" alt="'
23357f8d5bbSMark Prins                . $this->getlang('alt_legend_geojson') . '" /></td>
2346914b920SMark Prins                    <td class="txt" colspan="3">GeoJSON track: ' . $this->getFileName($gmap ['geojsonfile']) . '</td>
2356914b920SMark Prins                    </tr>';
2366914b920SMark Prins        }
237e61425c7SMark Prins
238c8eb1362SMark Prins        $autozoom = empty ($gmap ['autozoom']) ? $this->getConf('autoZoomMap') : $gmap ['autozoom'];
23957f8d5bbSMark Prins        $js       = "{mapOpts: {" . $param . ", displayformat: '" . $this->getConf('displayformat')
24057f8d5bbSMark Prins            . "', autozoom: " . $autozoom . "}, poi: [$poi]};";
241a757236dSMark Prins        // unescape the json
242a757236dSMark Prins        $poitable = stripslashes($poitable);
24338a47c60SMark Prins
2441c640875SMark Prins        return array(
2451c640875SMark Prins            $mapid,
2461c640875SMark Prins            $js,
2471c640875SMark Prins            $mainLat,
2481c640875SMark Prins            $mainLon,
2491c640875SMark Prins            $poitable,
2501c640875SMark Prins            $gmap ['summary'],
2511c640875SMark Prins            $imgUrl,
2521c640875SMark Prins            $_firstimageID
2531c640875SMark Prins        );
25438a47c60SMark Prins    }
25538a47c60SMark Prins
25638a47c60SMark Prins    /**
25738a47c60SMark Prins     * extract parameters for the map from the parameter string
25838a47c60SMark Prins     *
2591c640875SMark Prins     * @param string $str_params
2601c640875SMark Prins     *            string of key="value" pairs
26138a47c60SMark Prins     * @return array associative array of parameters key=>value
26238a47c60SMark Prins     */
26357f8d5bbSMark Prins    private function extractParams(string $str_params): array {
26438a47c60SMark Prins        $param = array();
26538a47c60SMark Prins        preg_match_all('/(\w*)="(.*?)"/us', $str_params, $param, PREG_SET_ORDER);
26638a47c60SMark Prins        // parse match for instructions, break into key value pairs
26738a47c60SMark Prins        $gmap = $this->dflt;
268c8eb1362SMark Prins        foreach($gmap as $key => &$value) {
269c8eb1362SMark Prins            $defval = $this->getConf('default_' . $key);
270c8eb1362SMark Prins            if($defval !== '') {
271c8eb1362SMark Prins                $value = $defval;
272c8eb1362SMark Prins            }
273c8eb1362SMark Prins        }
274c8eb1362SMark Prins        unset ($value);
27538a47c60SMark Prins        foreach($param as $kvpair) {
27638a47c60SMark Prins            list ($match, $key, $val) = $kvpair;
27738a47c60SMark Prins            $key = strtolower($key);
27838a47c60SMark Prins            if(isset ($gmap [$key])) {
27945c50327SMark Prins                if($key == 'summary') {
28045c50327SMark Prins                    // preserve case for summary field
28145c50327SMark Prins                    $gmap [$key] = $val;
2821c640875SMark Prins                } elseif($key == 'id') {
2831c640875SMark Prins                    // preserve case for id field
2841c640875SMark Prins                    $gmap [$key] = $val;
28545c50327SMark Prins                } else {
28638a47c60SMark Prins                    $gmap [$key] = strtolower($val);
28738a47c60SMark Prins                }
28838a47c60SMark Prins            }
28945c50327SMark Prins        }
29038a47c60SMark Prins        return $gmap;
29138a47c60SMark Prins    }
29238a47c60SMark Prins
29338a47c60SMark Prins    /**
29438a47c60SMark Prins     * extract overlay points for the map from the wiki syntax data
29538a47c60SMark Prins     *
2961c640875SMark Prins     * @param string $str_points
2971c640875SMark Prins     *            multi-line string of lat,lon,text triplets
29838a47c60SMark Prins     * @return array multi-dimensional array of lat,lon,text triplets
29938a47c60SMark Prins     */
30057f8d5bbSMark Prins    private function extractPoints(string $str_points): array {
30138a47c60SMark Prins        $point = array();
30257f8d5bbSMark Prins        // preg_match_all('/^([+-]?[0-9].*?),\s*([+-]?[0-9].*?),(.*?),(.*?),(.*?),(.*)$/um',
30357f8d5bbSMark Prins        //      $str_points, $point, PREG_SET_ORDER);
3047a3f422cSMark Prins        /*
30557f8d5bbSMark Prins         * group 1: ([+-]?[0-9]+(?:\.[0-9]*)?)
30657f8d5bbSMark Prins         * group 2: ([+-]?[0-9]+(?:\.[0-9]*)?)
30757f8d5bbSMark Prins         * group 3: (.*?)
30857f8d5bbSMark Prins         * group 4: (.*?)
30957f8d5bbSMark Prins         * group 5: (.*?)
31057f8d5bbSMark Prins         * group 6: (.*)
3117a3f422cSMark Prins         */
31257f8d5bbSMark Prins        preg_match_all(
31357f8d5bbSMark Prins            '/^([+-]?[0-9]+(?:\.[0-9]*)?),\s*([+-]?[0-9]+(?:\.[0-9]*)?),(.*?),(.*?),(.*?),(.*)$/um',
31457f8d5bbSMark Prins            $str_points, $point, PREG_SET_ORDER
31557f8d5bbSMark Prins        );
316554f43b5SMark Prins        // create poi array
31738a47c60SMark Prins        $overlay = array();
31838a47c60SMark Prins        foreach($point as $pt) {
31938a47c60SMark Prins            list ($match, $lat, $lon, $angle, $opacity, $img, $text) = $pt;
32038a47c60SMark Prins            $lat     = is_numeric($lat) ? $lat : 0;
32138a47c60SMark Prins            $lon     = is_numeric($lon) ? $lon : 0;
32238a47c60SMark Prins            $angle   = is_numeric($angle) ? $angle : 0;
32338a47c60SMark Prins            $opacity = is_numeric($opacity) ? $opacity : 0.8;
32487d958d4SMark Prins            // TODO validate using exist & set up default img?
3251c640875SMark Prins            $img  = trim($img);
3261c640875SMark Prins            $text = p_get_instructions($text);
3271c640875SMark Prins            // dbg ( $text );
3281c640875SMark Prins            $text = p_render("xhtml", $text, $info);
3291c640875SMark Prins            // dbg ( $text );
3301c640875SMark Prins            $text       = addslashes(str_replace("\n", "", $text));
3311c640875SMark Prins            $overlay [] = array(
3321c640875SMark Prins                $lat,
3331c640875SMark Prins                $lon,
3341c640875SMark Prins                $text,
3351c640875SMark Prins                $angle,
3361c640875SMark Prins                $opacity,
3371c640875SMark Prins                $img
3381c640875SMark Prins            );
33938a47c60SMark Prins        }
34038a47c60SMark Prins        return $overlay;
34138a47c60SMark Prins    }
342fcd79b50SMark Prins
343fcd79b50SMark Prins    /**
34457f8d5bbSMark Prins     * Create a Google maps static image url w/ the poi.
34557f8d5bbSMark Prins     *
34657f8d5bbSMark Prins     * @param array $gmap
34757f8d5bbSMark Prins     * @param array $overlay
34857f8d5bbSMark Prins     * @return string
34957f8d5bbSMark Prins     */
35057f8d5bbSMark Prins    private function getGoogle(array $gmap, array $overlay): string {
35157f8d5bbSMark Prins        $sUrl = $this->getConf('iconUrlOverload');
35257f8d5bbSMark Prins        if(!$sUrl) {
35357f8d5bbSMark Prins            $sUrl = DOKU_URL;
35457f8d5bbSMark Prins        }
35557f8d5bbSMark Prins        switch($gmap ['baselyr']) {
35657f8d5bbSMark Prins            case 'google hybrid' :
35757f8d5bbSMark Prins                $maptype = 'hybrid';
35857f8d5bbSMark Prins                break;
35957f8d5bbSMark Prins            case 'google sat' :
36057f8d5bbSMark Prins                $maptype = 'satellite';
36157f8d5bbSMark Prins                break;
36257f8d5bbSMark Prins            case 'terrain' :
36357f8d5bbSMark Prins            case 'google relief' :
36457f8d5bbSMark Prins                $maptype = 'terrain';
36557f8d5bbSMark Prins                break;
36657f8d5bbSMark Prins            case 'google road' :
36757f8d5bbSMark Prins            default :
36857f8d5bbSMark Prins                $maptype = 'roadmap';
36957f8d5bbSMark Prins                break;
37057f8d5bbSMark Prins        }
37157f8d5bbSMark Prins        // TODO maybe use viewport / visible instead of center/zoom,
37257f8d5bbSMark Prins        // see: https://developers.google.com/maps/documentation/staticmaps/index#Viewports
37357f8d5bbSMark 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
37457f8d5bbSMark Prins        $imgUrl = "https://maps.googleapis.com/maps/api/staticmap?";
37557f8d5bbSMark Prins        $imgUrl .= "&size=" . str_replace("px", "", $gmap ['width']) . "x"
37657f8d5bbSMark Prins            . str_replace("px", "", $gmap ['height']);
37757f8d5bbSMark Prins        //if (!$this->getConf( 'autoZoomMap')) { // no need for center & zoom params }
37857f8d5bbSMark Prins        $imgUrl .= "&center=" . $gmap ['lat'] . "," . $gmap ['lon'];
37957f8d5bbSMark Prins        // max is 21 (== building scale), but that's overkill..
38057f8d5bbSMark Prins        if($gmap ['zoom'] > 17) {
38157f8d5bbSMark Prins            $imgUrl .= "&zoom=17";
38257f8d5bbSMark Prins        } else {
38357f8d5bbSMark Prins            $imgUrl .= "&zoom=" . $gmap ['zoom'];
38457f8d5bbSMark Prins        }
38557f8d5bbSMark Prins        if(!empty ($overlay)) {
38657f8d5bbSMark Prins            $rowId = 0;
38757f8d5bbSMark Prins            foreach($overlay as $data) {
38857f8d5bbSMark Prins                list ($lat, $lon, $text, $angle, $opacity, $img) = $data;
38957f8d5bbSMark Prins                $imgUrl .= "&markers=icon%3a" . $sUrl . "lib/plugins/openlayersmap/icons/" . $img . "%7c"
39057f8d5bbSMark Prins                    . $lat . "," . $lon . "%7clabel%3a" . ++$rowId;
39157f8d5bbSMark Prins            }
39257f8d5bbSMark Prins        }
39357f8d5bbSMark Prins        $imgUrl .= "&format=png&maptype=" . $maptype;
39457f8d5bbSMark Prins        global $conf;
39557f8d5bbSMark Prins        $imgUrl .= "&language=" . $conf ['lang'];
39657f8d5bbSMark Prins        if($this->getConf('googleAPIkey')) {
39757f8d5bbSMark Prins            $imgUrl .= "&key=" . $this->getConf('googleAPIkey');
39857f8d5bbSMark Prins        }
39957f8d5bbSMark Prins        // dbglog($imgUrl,'syntax_plugin_openlayersmap_olmap::getGoogle: Google image url is:');
40057f8d5bbSMark Prins        return $imgUrl;
40157f8d5bbSMark Prins    }
40257f8d5bbSMark Prins
40357f8d5bbSMark Prins    /**
404fcd79b50SMark Prins     * Create a MapQuest static map API image url.
4051c640875SMark Prins     *
406fcd79b50SMark Prins     * @param array $gmap
407fcd79b50SMark Prins     * @param array $overlay
408fcd79b50SMark Prins     */
409e72390dbSMark Prins    /*
410fcd79b50SMark Prins   private function _getMapQuest($gmap, $overlay) {
411787a5195SMark Prins       $sUrl = $this->getConf ( 'iconUrlOverload' );
412787a5195SMark Prins       if (! $sUrl) {
413787a5195SMark Prins           $sUrl = DOKU_URL;
414787a5195SMark Prins       }
41587d958d4SMark Prins       switch ($gmap ['baselyr']) {
41694c2e868SMark Prins           case 'mapquest hybrid' :
417837eba2fSMark Prins               $maptype = 'hyb';
41887d958d4SMark Prins               break;
41918edeaa5SMark Prins           case 'mapquest sat' :
42044aba0bcSMark Prins               // because sat coverage is very limited use 'hyb' instead of 'sat' so we don't get a blank map
42144aba0bcSMark Prins               $maptype = 'hyb';
42287d958d4SMark Prins               break;
42394c2e868SMark Prins           case 'mapquest road' :
42487d958d4SMark Prins           default :
42587d958d4SMark Prins               $maptype = 'map';
42687d958d4SMark Prins               break;
42787d958d4SMark Prins       }
428004ad4e2SMark Prins       $imgUrl = "http://open.mapquestapi.com/staticmap/v4/getmap?declutter=true&";
42944aba0bcSMark Prins       if (count ( $overlay ) < 1) {
430787a5195SMark Prins           $imgUrl .= "?center=" . $gmap ['lat'] . "," . $gmap ['lon'];
431787a5195SMark Prins           // max level for mapquest is 16
432fcd79b50SMark Prins           if ($gmap ['zoom'] > 16) {
433fcd79b50SMark Prins               $imgUrl .= "&zoom=16";
434fcd79b50SMark Prins           } else {
435fcd79b50SMark Prins               $imgUrl .= "&zoom=" . $gmap ['zoom'];
436fcd79b50SMark Prins           }
43744aba0bcSMark Prins       }
43844aba0bcSMark Prins       // use bestfit instead of center/zoom, needs upperleft/lowerright corners
43957f8d5bbSMark Prins       // $bbox=$this->calcBBOX($overlay, $gmap['lat'], $gmap['lon']);
44044aba0bcSMark Prins       // $imgUrl .= "bestfit=".$bbox['minlat'].",".$bbox['maxlon'].",".$bbox['maxlat'].",".$bbox['minlon'];
44144aba0bcSMark Prins
44257f8d5bbSMark Prins       // TODO declutter option works well for square maps but not for rectangular, maybe compensate for that
44357f8d5bbSMark Prins       //       or compensate the mbr..
44457f8d5bbSMark Prins
44544aba0bcSMark Prins       $imgUrl .= "&size=" . str_replace ( "px", "", $gmap ['width'] ) . "," . str_replace ("px","",$gmap['height']);
44644aba0bcSMark Prins
447fcd79b50SMark Prins       // TODO mapquest allows using one image url with a multiplier $NUMBER eg:
448fcd79b50SMark Prins       // $NUMBER = 2
44957f8d5bbSMark Prins       // $imgUrl .= DOKU_URL."/".DOKU_PLUGIN."/".getPluginName()."/icons/".$img.",$NUMBER,C,"
45057f8d5bbSMark Prins        //  .$lat1.",".$lon1.",0,0,0,0,C,".$lat2.",".$lon2.",0,0,0,0";
451fcd79b50SMark Prins       if (! empty ( $overlay )) {
452fcd79b50SMark Prins           $imgUrl .= "&xis=";
453fcd79b50SMark Prins           foreach ( $overlay as $data ) {
454fcd79b50SMark Prins               list ( $lat, $lon, $text, $angle, $opacity, $img ) = $data;
45544aba0bcSMark Prins               // $imgUrl .= $sUrl."lib/plugins/openlayersmap/icons/".$img.",1,C,".$lat.",".$lon.",0,0,0,0,";
45644aba0bcSMark Prins               $imgUrl .= $sUrl . "lib/plugins/openlayersmap/icons/" . $img . ",1,C," . $lat . "," . $lon . ",";
457fcd79b50SMark Prins           }
458fcd79b50SMark Prins           $imgUrl = substr ( $imgUrl, 0, - 1 );
459fcd79b50SMark Prins       }
46087d958d4SMark Prins       $imgUrl .= "&imageType=png&type=" . $maptype;
461d974ea02SMark Prins       $imgUrl .= "&key=".$this->getConf ( 'mapquestAPIKey' );
4628e7c4263SMark Prins       // dbglog($imgUrl,'syntax_plugin_openlayersmap_olmap::_getMapQuest: MapQuest image url is:');
463787a5195SMark Prins       return $imgUrl;
464787a5195SMark Prins   }
465e72390dbSMark Prins   */
466cc74a83cSMark Prins
4676e633dd6SMark Prins    /**
46887d958d4SMark Prins     * Create a static OSM map image url w/ the poi from http://staticmap.openstreetmap.de (staticMapLite)
469fcf646d2SMark Prins     * use http://staticmap.openstreetmap.de "staticMapLite" or a local version
4701c640875SMark Prins     *
47187d958d4SMark Prins     * @param array $gmap
47287d958d4SMark Prins     * @param array $overlay
473fcf646d2SMark Prins     *
47457f8d5bbSMark Prins     * @return false|string
475fcf646d2SMark Prins     * @todo implementation for http://ojw.dev.openstreetmap.org/StaticMapDev/
47687d958d4SMark Prins     */
47757f8d5bbSMark Prins    private function getStaticOSM(array $gmap, array $overlay) {
478fcf646d2SMark Prins        global $conf;
479372f1508SMark Prins
48053bfe4a3SMark Prins        if($this->getConf('optionStaticMapGenerator') == 'local') {
481d974ea02SMark Prins            // using local basemap composer
48257f8d5bbSMark Prins            if(!$myMap = plugin_load('helper', 'openlayersmap_staticmap')) {
48357f8d5bbSMark Prins                dbglog(
48457f8d5bbSMark Prins                    $myMap,
48557f8d5bbSMark Prins                    'openlayersmap_staticmap plugin is not available for use.'
48657f8d5bbSMark Prins                );
48753bfe4a3SMark Prins            }
48857f8d5bbSMark Prins            if(!$geophp = plugin_load('helper', 'geophp')) {
48957f8d5bbSMark Prins                dbglog($geophp, 'geophp plugin is not available for use.');
49053bfe4a3SMark Prins            }
49157f8d5bbSMark Prins            $size = str_replace("px", "", $gmap ['width']) . "x"
49257f8d5bbSMark Prins                . str_replace("px", "", $gmap ['height']);
49353bfe4a3SMark Prins
4944c9f9dfcSMark Prins            $markers = array();
49553bfe4a3SMark Prins            if(!empty ($overlay)) {
49653bfe4a3SMark Prins                foreach($overlay as $data) {
49753bfe4a3SMark Prins                    list ($lat, $lon, $text, $angle, $opacity, $img) = $data;
49853bfe4a3SMark Prins                    $iconStyle  = substr($img, 0, strlen($img) - 4);
49953bfe4a3SMark Prins                    $markers [] = array(
50053bfe4a3SMark Prins                        'lat'  => $lat,
50153bfe4a3SMark Prins                        'lon'  => $lon,
5021c640875SMark Prins                        'type' => $iconStyle
5031c640875SMark Prins                    );
50453bfe4a3SMark Prins                }
505372f1508SMark Prins            }
506372f1508SMark Prins
507d2f4772aSMark Prins            $apikey = '';
50818edeaa5SMark Prins            switch($gmap ['baselyr']) {
50918edeaa5SMark Prins                case 'mapnik' :
510fcf646d2SMark Prins                case 'openstreetmap' :
511fcf646d2SMark Prins                    $maptype = 'openstreetmap';
51218edeaa5SMark Prins                    break;
513fcf646d2SMark Prins                case 'transport' :
514fcf646d2SMark Prins                    $maptype = 'transport';
515b63742deSMark Prins                    $apikey  = '?apikey=' . $this->getConf('tfApiKey');
516fcf646d2SMark Prins                    break;
517fcf646d2SMark Prins                case 'landscape' :
518fcf646d2SMark Prins                    $maptype = 'landscape';
519b63742deSMark Prins                    $apikey  = '?apikey=' . $this->getConf('tfApiKey');
520d2f4772aSMark Prins                    break;
521d2f4772aSMark Prins                case 'outdoors' :
522d2f4772aSMark Prins                    $maptype = 'outdoors';
523b63742deSMark Prins                    $apikey  = '?apikey=' . $this->getConf('tfApiKey');
52418edeaa5SMark Prins                    break;
52518edeaa5SMark Prins                case 'cycle map' :
52618edeaa5SMark Prins                    $maptype = 'cycle';
527b63742deSMark Prins                    $apikey  = '?apikey=' . $this->getConf('tfApiKey');
528372f1508SMark Prins                    break;
529fcf646d2SMark Prins                case 'hike and bike map' :
530fcf646d2SMark Prins                    $maptype = 'hikeandbike';
531fcf646d2SMark Prins                    break;
532fcf646d2SMark Prins                case 'mapquest hybrid' :
533fcf646d2SMark Prins                case 'mapquest road' :
534fcf646d2SMark Prins                case 'mapquest sat' :
535fcf646d2SMark Prins                    $maptype = 'mapquest';
536fcf646d2SMark Prins                    break;
53718edeaa5SMark Prins                default :
53818edeaa5SMark Prins                    $maptype = '';
53918edeaa5SMark Prins                    break;
54018edeaa5SMark Prins            }
541d974ea02SMark Prins
54257f8d5bbSMark Prins            $result = $myMap->getMap(
54357f8d5bbSMark Prins                $gmap ['lat'], $gmap ['lon'], $gmap ['zoom'], $size, $maptype, $markers,
544b63742deSMark Prins                $gmap ['gpxfile'], $gmap ['kmlfile'], $gmap ['geojsonfile'], $apikey
54557f8d5bbSMark Prins            );
546d974ea02SMark Prins        } else {
547d974ea02SMark Prins            // using external basemap composer
548d974ea02SMark Prins
54957f8d5bbSMark Prins            // https://staticmap.openstreetmap.de/staticmap.php?center=47.000622235634,10
55057f8d5bbSMark Prins            //.117187497601&zoom=5&size=500x350
55157f8d5bbSMark Prins            // &markers=48.999812532766,8.3593749976708,lightblue1|43.154850037315,17.499999997306,
55257f8d5bbSMark Prins            //  lightblue1|49.487527053077,10.820312497573,ltblu-pushpin|47.951071133739,15.917968747369,
55357f8d5bbSMark Prins            //  ol-marker|47.921629720114,18.027343747285,ol-marker-gold|47.951071133739,19.257812497236,
55457f8d5bbSMark Prins            //  ol-marker-blue|47.180141361692,19.257812497236,ol-marker-green
55557f8d5bbSMark Prins            $imgUrl = "https://staticmap.openstreetmap.de/staticmap.php";
556d974ea02SMark Prins            $imgUrl .= "?center=" . $gmap ['lat'] . "," . $gmap ['lon'];
55757f8d5bbSMark Prins            $imgUrl .= "&size=" . str_replace("px", "", $gmap ['width']) . "x"
55857f8d5bbSMark Prins                . str_replace("px", "", $gmap ['height']);
559d974ea02SMark Prins
560d974ea02SMark Prins            if($gmap ['zoom'] > 16) {
561d974ea02SMark Prins                // actually this could even be 18, but that seems overkill
562d974ea02SMark Prins                $imgUrl .= "&zoom=16";
563d974ea02SMark Prins            } else {
564d974ea02SMark Prins                $imgUrl .= "&zoom=" . $gmap ['zoom'];
565d974ea02SMark Prins            }
56618edeaa5SMark Prins
56787d958d4SMark Prins            if(!empty ($overlay)) {
56887d958d4SMark Prins                $rowId  = 0;
56987d958d4SMark Prins                $imgUrl .= "&markers=";
57087d958d4SMark Prins                foreach($overlay as $data) {
57187d958d4SMark Prins                    list ($lat, $lon, $text, $angle, $opacity, $img) = $data;
57287d958d4SMark Prins                    $rowId++;
57353bfe4a3SMark Prins                    $iconStyle = "lightblue$rowId";
57487d958d4SMark Prins                    $imgUrl    .= "$lat,$lon,$iconStyle%7c";
57587d958d4SMark Prins                }
57687d958d4SMark Prins                $imgUrl = substr($imgUrl, 0, -3);
57787d958d4SMark Prins            }
57887d958d4SMark Prins
579f4b9bdacSMark Prins            $result = $imgUrl;
580628e43ccSMark Prins        }
58157f8d5bbSMark Prins        // dbglog ( $result, 'syntax_plugin_openlayersmap_olmap::getStaticOSM: osm image url is:' );
582628e43ccSMark Prins        return $result;
583628e43ccSMark Prins    }
584628e43ccSMark Prins
58544aba0bcSMark Prins    /**
58657f8d5bbSMark Prins     * Create a Bing maps static image url w/ the poi.
58757f8d5bbSMark Prins     *
58857f8d5bbSMark Prins     * @param array $gmap
58957f8d5bbSMark Prins     * @param array $overlay
59057f8d5bbSMark Prins     * @return string
59157f8d5bbSMark Prins     */
59257f8d5bbSMark Prins    private function getBing(array $gmap, array $overlay): string {
59357f8d5bbSMark Prins        switch($gmap ['baselyr']) {
59457f8d5bbSMark Prins            case 've hybrid' :
59557f8d5bbSMark Prins            case 'bing hybrid' :
59657f8d5bbSMark Prins                $maptype = 'AerialWithLabels';
59757f8d5bbSMark Prins                break;
59857f8d5bbSMark Prins            case 've sat' :
59957f8d5bbSMark Prins            case 'bing sat' :
60057f8d5bbSMark Prins                $maptype = 'Aerial';
60157f8d5bbSMark Prins                break;
60257f8d5bbSMark Prins            case 've normal' :
60357f8d5bbSMark Prins            case 've road' :
60457f8d5bbSMark Prins            case 've' :
60557f8d5bbSMark Prins            case 'bing road' :
60657f8d5bbSMark Prins            default :
60757f8d5bbSMark Prins                $maptype = 'Road';
60857f8d5bbSMark Prins                break;
60957f8d5bbSMark Prins        }
61057f8d5bbSMark Prins        $imgUrl = "https://dev.virtualearth.net/REST/v1/Imagery/Map/" . $maptype;// . "/";
61157f8d5bbSMark Prins        if($this->getConf('autoZoomMap')) {
61257f8d5bbSMark Prins            $bbox = $this->calcBBOX($overlay, $gmap ['lat'], $gmap ['lon']);
61357f8d5bbSMark Prins            //$imgUrl .= "?ma=" . $bbox ['minlat'] . "," . $bbox ['minlon'] . ","
61457f8d5bbSMark Prins            //          . $bbox ['maxlat'] . "," . $bbox ['maxlon'];
61557f8d5bbSMark Prins            $imgUrl .= "?ma=" . $bbox ['minlat'] . "%2C" . $bbox ['minlon'] . "%2C" . $bbox ['maxlat']
61657f8d5bbSMark Prins                . "%2C" . $bbox ['maxlon'];
61757f8d5bbSMark Prins            $imgUrl .= "&dcl=1";
61857f8d5bbSMark Prins        }
61957f8d5bbSMark Prins        if(strpos($imgUrl, "?") === false)
62057f8d5bbSMark Prins            $imgUrl .= "?";
62157f8d5bbSMark Prins
62257f8d5bbSMark Prins        //$imgUrl .= "&ms=" . str_replace ( "px", "", $gmap ['width'] ) . ","
62357f8d5bbSMark Prins        //          . str_replace ( "px", "", $gmap ['height'] );
62457f8d5bbSMark Prins        $imgUrl .= "&ms=" . str_replace("px", "", $gmap ['width']) . "%2C"
62557f8d5bbSMark Prins            . str_replace("px", "", $gmap ['height']);
62657f8d5bbSMark Prins        $imgUrl .= "&key=" . $this->getConf('bingAPIKey');
62757f8d5bbSMark Prins        if(!empty ($overlay)) {
62857f8d5bbSMark Prins            $rowId = 0;
62957f8d5bbSMark Prins            foreach($overlay as $data) {
63057f8d5bbSMark Prins                list ($lat, $lon, $text, $angle, $opacity, $img) = $data;
63157f8d5bbSMark Prins                // TODO icon style lookup, see: http://msdn.microsoft.com/en-us/library/ff701719.aspx for iconStyle
63257f8d5bbSMark Prins                $iconStyle = 32;
63357f8d5bbSMark Prins                $rowId++;
63457f8d5bbSMark Prins                // NOTE: the max number of pushpins is 18! or we have to use POST
63557f8d5bbSMark Prins                //  (http://msdn.microsoft.com/en-us/library/ff701724.aspx)
63657f8d5bbSMark Prins                if($rowId == 18) {
63757f8d5bbSMark Prins                    break;
63857f8d5bbSMark Prins                }
63957f8d5bbSMark Prins                //$imgUrl .= "&pp=$lat,$lon;$iconStyle;$rowId";
64057f8d5bbSMark Prins                $imgUrl .= "&pp=$lat%2C$lon%3B$iconStyle%3B$rowId";
64157f8d5bbSMark Prins
64257f8d5bbSMark Prins            }
64357f8d5bbSMark Prins        }
64457f8d5bbSMark Prins        global $conf;
64557f8d5bbSMark Prins        $imgUrl .= "&fmt=png";
64657f8d5bbSMark Prins        $imgUrl .= "&c=" . $conf ['lang'];
64757f8d5bbSMark Prins        // dbglog($imgUrl,'syntax_plugin_openlayersmap_olmap::getBing: bing image url is:');
64857f8d5bbSMark Prins        return $imgUrl;
64957f8d5bbSMark Prins    }
65057f8d5bbSMark Prins
65157f8d5bbSMark Prins    /**
65244aba0bcSMark Prins     * Calculate the minimum bbox for a start location + poi.
65344aba0bcSMark Prins     *
6541c640875SMark Prins     * @param array $overlay
6551c640875SMark Prins     *            multi-dimensional array of array($lat, $lon, $text, $angle, $opacity, $img)
6561c640875SMark Prins     * @param float $lat
6571c640875SMark Prins     *            latitude for map center
6581c640875SMark Prins     * @param float $lon
6591c640875SMark Prins     *            longitude for map center
66057f8d5bbSMark Prins     * @return array :float array describing the mbr and center point
66144aba0bcSMark Prins     */
66257f8d5bbSMark Prins    private function calcBBOX(array $overlay, float $lat, float $lon): array {
6634c9f9dfcSMark Prins        $lats = array($lat);
6644c9f9dfcSMark Prins        $lons = array($lon);
665837eba2fSMark Prins        foreach($overlay as $data) {
666837eba2fSMark Prins            list ($lat, $lon, $text, $angle, $opacity, $img) = $data;
667837eba2fSMark Prins            $lats [] = $lat;
668837eba2fSMark Prins            $lons [] = $lon;
669837eba2fSMark Prins        }
670837eba2fSMark Prins        sort($lats);
671837eba2fSMark Prins        sort($lons);
67244aba0bcSMark Prins        // TODO: make edge/wrap around cases work
67344aba0bcSMark Prins        $centerlat = $lats [0] + ($lats [count($lats) - 1] - $lats [0]);
67444aba0bcSMark Prins        $centerlon = $lons [0] + ($lons [count($lats) - 1] - $lons [0]);
6751c640875SMark Prins        return array(
6761c640875SMark Prins            'minlat'    => $lats [0],
6771c640875SMark Prins            'minlon'    => $lons [0],
6781c640875SMark Prins            'maxlat'    => $lats [count($lats) - 1],
6791c640875SMark Prins            'maxlon'    => $lons [count($lats) - 1],
6801c640875SMark Prins            'centerlat' => $centerlat,
6811c640875SMark Prins            'centerlon' => $centerlon
6821c640875SMark Prins        );
68387d958d4SMark Prins    }
684cc74a83cSMark Prins
685cc74a83cSMark Prins    /**
68657f8d5bbSMark Prins     * convert latitude in decimal degrees to DMS+hemisphere.
6871c640875SMark Prins     *
68857f8d5bbSMark Prins     * @param float $decimaldegrees
68957f8d5bbSMark Prins     * @return string
69057f8d5bbSMark Prins     * @todo move this into a shared library
691cc74a83cSMark Prins     */
69257f8d5bbSMark Prins    private function convertLat(float $decimaldegrees): string {
69357f8d5bbSMark Prins        if(strpos($decimaldegrees, '-') !== false) {
69457f8d5bbSMark Prins            $latPos = "S";
69557f8d5bbSMark Prins        } else {
69657f8d5bbSMark Prins            $latPos = "N";
69757f8d5bbSMark Prins        }
69857f8d5bbSMark Prins        $dms = $this->convertDDtoDMS(abs($decimaldegrees));
69957f8d5bbSMark Prins        return hsc($dms . $latPos);
700cc74a83cSMark Prins    }
7018c4eb2fdSMark Prins
7028c4eb2fdSMark Prins    /**
7038c4eb2fdSMark Prins     * Convert decimal degrees to degrees, minutes, seconds format
7048c4eb2fdSMark Prins     *
7058c4eb2fdSMark Prins     * @param float $decimaldegrees
7068c4eb2fdSMark Prins     * @return string dms
70757f8d5bbSMark Prins     * @todo move this into a shared library
7088c4eb2fdSMark Prins     */
70957f8d5bbSMark Prins    private function convertDDtoDMS(float $decimaldegrees): string {
7108c4eb2fdSMark Prins        $dms  = floor($decimaldegrees);
7118c4eb2fdSMark Prins        $secs = ($decimaldegrees - $dms) * 3600;
7128c4eb2fdSMark Prins        $min  = floor($secs / 60);
7138c4eb2fdSMark Prins        $sec  = round($secs - ($min * 60), 3);
7148c4eb2fdSMark Prins        $dms  .= 'º' . $min . '\'' . $sec . '"';
7158c4eb2fdSMark Prins        return $dms;
7168c4eb2fdSMark Prins    }
7178c4eb2fdSMark Prins
7188c4eb2fdSMark Prins    /**
7198c4eb2fdSMark Prins     * convert longitude in decimal degrees to DMS+hemisphere.
7208c4eb2fdSMark Prins     *
7218c4eb2fdSMark Prins     * @param float $decimaldegrees
7228c4eb2fdSMark Prins     * @return string
72357f8d5bbSMark Prins     * @todo move this into a shared library
7248c4eb2fdSMark Prins     */
72557f8d5bbSMark Prins    private function convertLon(float $decimaldegrees): string {
7268c4eb2fdSMark Prins        if(strpos($decimaldegrees, '-') !== false) {
7278c4eb2fdSMark Prins            $lonPos = "W";
7288c4eb2fdSMark Prins        } else {
7298c4eb2fdSMark Prins            $lonPos = "E";
7308c4eb2fdSMark Prins        }
73157f8d5bbSMark Prins        $dms = $this->convertDDtoDMS(abs($decimaldegrees));
7328c4eb2fdSMark Prins        return hsc($dms . $lonPos);
7338c4eb2fdSMark Prins    }
73457f8d5bbSMark Prins
73557f8d5bbSMark Prins    /**
73657f8d5bbSMark Prins     * Figures out the base filename of a media path.
73757f8d5bbSMark Prins     *
73857f8d5bbSMark Prins     * @param string $mediaLink
73957f8d5bbSMark Prins     * @return string
74057f8d5bbSMark Prins     */
74157f8d5bbSMark Prins    private function getFileName(string $mediaLink): string {
74257f8d5bbSMark Prins        $mediaLink = str_replace('[[', '', $mediaLink);
74357f8d5bbSMark Prins        $mediaLink = str_replace(']]', '', $mediaLink);
74457f8d5bbSMark Prins        $mediaLink = substr($mediaLink, 0, -4);
74557f8d5bbSMark Prins        $parts     = explode(':', $mediaLink);
74657f8d5bbSMark Prins        $mediaLink = end($parts);
74757f8d5bbSMark Prins        return str_replace('_', ' ', $mediaLink);
74857f8d5bbSMark Prins    }
74957f8d5bbSMark Prins
75057f8d5bbSMark Prins    /**
75157f8d5bbSMark Prins     *
75257f8d5bbSMark Prins     * @see DokuWiki_Syntax_Plugin::render()
75357f8d5bbSMark Prins     */
75457f8d5bbSMark Prins    public function render($format, Doku_Renderer $renderer, $data): bool {
75557f8d5bbSMark Prins        // set to true after external scripts tags are written
75657f8d5bbSMark Prins        static $initialised = false;
75757f8d5bbSMark Prins        // incremented for each map tag in the page source so we can keep track of each map in this page
75857f8d5bbSMark Prins        static $mapnumber = 0;
75957f8d5bbSMark Prins
76057f8d5bbSMark Prins        // dbglog($data, 'olmap::render() data.');
76157f8d5bbSMark Prins        list ($mapid, $param, $mainLat, $mainLon, $poitable, $poitabledesc, $staticImgUrl, $_firstimage) = $data;
76257f8d5bbSMark Prins
76357f8d5bbSMark Prins        if($format == 'xhtml') {
76457f8d5bbSMark Prins            $olscript     = '';
76557f8d5bbSMark Prins            $stamenEnable = $this->getConf('enableStamen');
76657f8d5bbSMark Prins            $osmEnable    = $this->getConf('enableOSM');
76757f8d5bbSMark Prins            $enableBing   = $this->getConf('enableBing');
76857f8d5bbSMark Prins
76957f8d5bbSMark Prins            $scriptEnable = '';
77057f8d5bbSMark Prins            if(!$initialised) {
77157f8d5bbSMark Prins                $initialised = true;
7727390889dSMark Prins                // render necessary script tags only once
7737390889dSMark Prins                $olscript = '<script defer="defer" src="' . DOKU_BASE . 'lib/plugins/openlayersmap/ol6/ol.js"></script>
7747390889dSMark Prins<script defer="defer" src="' . DOKU_BASE . 'lib/plugins/openlayersmap/ol6/ol-layerswitcher.js"></script>';
77557f8d5bbSMark Prins
77657f8d5bbSMark Prins                $scriptEnable = '<script defer="defer" src="data:text/javascript;base64,';
7777390889dSMark Prins                $scriptSrc    = $olscript ? 'const olEnable=true;' : 'const olEnable=false;';
7787390889dSMark Prins                $scriptSrc    .= 'const osmEnable=' . ($osmEnable ? 'true' : 'false') . ';';
7797390889dSMark Prins                $scriptSrc    .= 'const stamenEnable=' . ($stamenEnable ? 'true' : 'false') . ';';
7807390889dSMark Prins                $scriptSrc    .= 'const bEnable=' . ($enableBing ? 'true' : 'false') . ';';
7817390889dSMark Prins                $scriptSrc    .= 'const bApiKey="' . $this->getConf('bingAPIKey') . '";';
7827390889dSMark Prins                $scriptSrc    .= 'const tfApiKey="' . $this->getConf('tfApiKey') . '";';
7837390889dSMark Prins                $scriptSrc    .= 'const gApiKey="' . $this->getConf('googleAPIkey') . '";';
7847390889dSMark Prins                $scriptSrc    .= 'olMapData = []; let olMaps = {}; let olMapOverlays = {};';
78557f8d5bbSMark Prins                $scriptEnable .= base64_encode($scriptSrc);
78657f8d5bbSMark Prins                $scriptEnable .= '"></script>';
78757f8d5bbSMark Prins            }
7887390889dSMark Prins            $renderer->doc .= "$olscript\n$scriptEnable";
78957f8d5bbSMark Prins            $renderer->doc .= '<div class="olMapHelp">' . $this->locale_xhtml("help") . '</div>';
79057f8d5bbSMark Prins            if($this->getConf('enableA11y')) {
79157f8d5bbSMark Prins                $renderer->doc .= '<div id="' . $mapid . '-static" class="olStaticMap">'
79257f8d5bbSMark Prins                    . p_render($format, p_get_instructions($staticImgUrl), $info) . '</div>';
79357f8d5bbSMark Prins            }
79457f8d5bbSMark Prins            $renderer->doc .= '<div id="' . $mapid . '-clearer" class="clearer"><p>&nbsp;</p></div>';
79557f8d5bbSMark Prins            if($this->getConf('enableA11y')) {
79657f8d5bbSMark Prins                // render a table of the POI for the print and a11y presentation, it is hidden using javascript
7977390889dSMark Prins                $renderer->doc .= '
7987390889dSMark Prins                <div class="olPOItableSpan" id="' . $mapid . '-table-span">
79957f8d5bbSMark Prins                    <table class="olPOItable" id="' . $mapid . '-table">
80057f8d5bbSMark Prins                    <caption class="olPOITblCaption">' . $this->getLang('olmapPOItitle') . '</caption>
80157f8d5bbSMark Prins                    <thead class="olPOITblHeader">
80257f8d5bbSMark Prins                    <tr>
80357f8d5bbSMark Prins                    <th class="rowId" scope="col">id</th>
80457f8d5bbSMark Prins                    <th class="icon" scope="col">' . $this->getLang('olmapPOIicon') . '</th>
80557f8d5bbSMark Prins                    <th class="lat" scope="col" title="' . $this->getLang('olmapPOIlatTitle') . '">'
80657f8d5bbSMark Prins                    . $this->getLang('olmapPOIlat') . '</th>
80757f8d5bbSMark Prins                    <th class="lon" scope="col" title="' . $this->getLang('olmapPOIlonTitle') . '">'
80857f8d5bbSMark Prins                    . $this->getLang('olmapPOIlon') . '</th>
80957f8d5bbSMark Prins                    <th class="txt" scope="col">' . $this->getLang('olmapPOItxt') . '</th>
81057f8d5bbSMark Prins                    </tr>
81157f8d5bbSMark Prins                    </thead>';
81257f8d5bbSMark Prins                if($poitabledesc != '') {
81357f8d5bbSMark Prins                    $renderer->doc .= '<tfoot class="olPOITblFooter"><tr><td colspan="5">' . $poitabledesc
81457f8d5bbSMark Prins                        . '</td></tr></tfoot>';
81557f8d5bbSMark Prins                }
81657f8d5bbSMark Prins                $renderer->doc .= '<tbody class="olPOITblBody">' . $poitable . '</tbody>
8177390889dSMark Prins                    </table>
8187390889dSMark Prins                </div>';
8197390889dSMark Prins                $renderer->doc .= "\n";
82057f8d5bbSMark Prins            }
82157f8d5bbSMark Prins            // render inline mapscript parts
82257f8d5bbSMark Prins            $renderer->doc .= '<script defer="defer" src="data:text/javascript;base64,';
82357f8d5bbSMark Prins            $renderer->doc .= base64_encode("olMapData[$mapnumber] = $param");
82457f8d5bbSMark Prins            $renderer->doc .= '"></script>';
82557f8d5bbSMark Prins            $mapnumber++;
82657f8d5bbSMark Prins            return true;
82757f8d5bbSMark Prins        } elseif($format == 'metadata') {
82857f8d5bbSMark Prins            if(!(($this->dflt ['lat'] == $mainLat) && ($this->dflt ['lon'] == $mainLon))) {
82957f8d5bbSMark Prins                // render geo metadata, unless they are the default
83057f8d5bbSMark Prins                $renderer->meta ['geo'] ['lat'] = $mainLat;
83157f8d5bbSMark Prins                $renderer->meta ['geo'] ['lon'] = $mainLon;
83257f8d5bbSMark Prins                if($geophp = plugin_load('helper', 'geophp')) {
83357f8d5bbSMark Prins                    // if we have the geoPHP helper, add the geohash
83457f8d5bbSMark Prins
83557f8d5bbSMark Prins                    // fails with older php versions..
83657f8d5bbSMark Prins                    // $renderer->meta['geo']['geohash'] = (new Point($mainLon,$mainLat))->out('geohash');
83757f8d5bbSMark Prins                    $p                                  = new Point ($mainLon, $mainLat);
83857f8d5bbSMark Prins                    $renderer->meta ['geo'] ['geohash'] = $p->out('geohash');
83957f8d5bbSMark Prins                }
84057f8d5bbSMark Prins            }
84157f8d5bbSMark Prins
84257f8d5bbSMark Prins            if(($this->getConf('enableA11y')) && (!empty ($_firstimage))) {
84357f8d5bbSMark Prins                // add map local image into relation/firstimage if not already filled and when it is a local image
84457f8d5bbSMark Prins
84557f8d5bbSMark Prins                global $ID;
84657f8d5bbSMark Prins                $rel = p_get_metadata($ID, 'relation', METADATA_RENDER_USING_CACHE);
84757f8d5bbSMark Prins                $img = $rel ['firstimage'];
84857f8d5bbSMark Prins                if(empty ($img) /* || $img == $_firstimage*/) {
84957f8d5bbSMark Prins                    //dbglog ( $_firstimage,
85057f8d5bbSMark Prins                    // 'olmap::render#rendering image relation metadata for _firstimage as $img was empty or same.' );
85157f8d5bbSMark Prins                    // This seems to never work; the firstimage entry in the .meta file is empty
85257f8d5bbSMark Prins                    // $renderer->meta['relation']['firstimage'] = $_firstimage;
85357f8d5bbSMark Prins
85457f8d5bbSMark Prins                    // ... and neither does this; the firstimage entry in the .meta file is empty
85557f8d5bbSMark Prins                    // $relation = array('relation'=>array('firstimage'=>$_firstimage));
85657f8d5bbSMark Prins                    // p_set_metadata($ID, $relation, false, false);
85757f8d5bbSMark Prins
85857f8d5bbSMark Prins                    // ... this works
85957f8d5bbSMark Prins                    $renderer->internalmedia($_firstimage, $poitabledesc);
86057f8d5bbSMark Prins                }
86157f8d5bbSMark Prins            }
86257f8d5bbSMark Prins            return true;
86357f8d5bbSMark Prins        }
86457f8d5bbSMark Prins        return false;
86557f8d5bbSMark Prins    }
86638a47c60SMark Prins}
867