6. Vyskakovací okna

Data, se kterými chceme pracovat máme přidána. Chybí ale podrobnější informace o svatebních místech a přesunech mezi nimi. Mapa postrádá jakoukoli interaktivitu.

Informace o obřadě jako například čas, souřadnice, fotka a pozvání svatebčanů a další informace mohou být součástí vyskakovacích oken. U ikonek obsah vyskakovacích oken definujeme dynamicky, protože budeme chtít v textu uvést číselné hodnoty souřadnic míst v systémech S-JTSK (EPSG:5514) i WGS84 (EPSG:4326). Souřadnice v S-JTSK budeme proto za běhu transformovat do WGS84. Obsah vyskakovacích oken u přesunových tras budeme definovat pouze na základě vlastností v GeoJSON souboru.

Vyskakovací okna u vektorových vrstev

Vyskakovací okno je HTML objektem. Je tedy nutné ho přidat i v rámci index.html souboru. Kvůli transformaci souřadnic ze systému EPSG:5514 do systému EPSG:4326 pro účely zobrazení přetransformovaných hodnot ve vyskakovacím okně je nutné dále připojit do index.html ještě JavaScript knihovnu proj4. To provedeme přidáním následujícího odkazu: https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.5.0/proj4.js.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/x-icon" href="https://openlayers.org/…ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Plánek svatba</title>
  </head>
  <body>
    <div id="map"></div>
    <div id="popup" class="ol-popup">
      <a href="#" id="popup-closer" class="ol-popup-closer"></a>
      <div id="popup-content"></div>
    </div>
    <script type="module" src="./main.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.5.0/proj4.js"></script>
  </body>
</html>

Stylizaci popup okna definujeme v souboru style.css:

@import "node_modules/ol/ol.css";

html, body {
  margin: 0;
  height: 100%;
}
#map {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 100%;
}
.ol-popup {
  position: absolute;
  background-color: white;
  box-shadow: 0 1px 4px rgba(0,0,0,0.4);
  padding: 20px;
  border-radius: 10px;
  border: 1px solid #cccccc;
  bottom: 15px;
  left: -50px;
  min-width: 280px;
}
.ol-popup:after, .ol-popup:before {
  top: 100%;
  border: solid transparent;
  content: " ";
  height: 0;
  width: 0;
  position: absolute;
  pointer-events: none;
}
.ol-popup:after {
  border-top-color: white;
  border-width: 10px;
  left: 48px;
  margin-left: -10px;
}
.ol-popup:before {
  border-top-color: #cccccc;
  border-width: 11px;
  left: 48px;
  margin-left: -11px;
}
.ol-popup-closer {
  text-decoration: none;
  position: absolute;
  top: 2px;
  right: 8px;
}
.ol-popup-closer:after {
  content: "✖";
}

V souboru main.js dále sestavíme obsah zprávy, která se má zobrazit v závislosti na typu vybraného prvku. Vytvoříme si dvě funkce transformGeometryToWGS84 a definePopupContent, které budou sloužit k dynamickému naplnění obsahu popup oken patřících k ikonkám. Poté napíšeme, co se má stát při události singleclick - na základě typu prvku zobraz požadované vyskakovací okno. To bude mít pokaždé podobnou strukturu. Pokud bychom chtěli okno jiné struktury, můžeme obsah HTML definovat rovnou do content.innerHTML vlastnosti.

// Add Krovak CRS as PROJ def in order to have the possibility to transform from SJTSK to WGS84

addProjection(sjtsk_projection);

proj4.defs('EPSG:5514','+proj=krovak +lat_0=49.5 +lon_0=24.8333333333333 +alpha=30.2881397527778 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=589,76,480,0,0,0,0 +units=m +no_defs +type=crs');
register(proj4);

// Function for transforming S-JTSK coordinates to WGS-84
function transformGeometryToWGS84(geometrySJTSK) {
  return toStringHDMS(transform(geometrySJTSK, 'EPSG:5514', 'EPSG:4326'));
}

// Function for preparing content of popup windows for two important places
// Popups have a similar style which include place description, picture, picture title and coordinates in both CRS systems
function definePopupContent(textHtml, pictureHtml, pictureTitleHtml, coordinatesSJTSK){
  return textHtml + pictureHtml + pictureTitleHtml +
        'WGS84: <code>' + transformGeometryToWGS84(coordinatesSJTSK) + '</code><p> S-JTSK: <code>' +
        coordinatesSJTSK + '</code></p>';
}

// Take popup elements
const container = document.getElementById('popup');
const content = document.getElementById('popup-content');
const closer = document.getElementById('popup-closer');

// Create popup overlay layer
var popup = new Overlay({
    element: container,
    autoPan: true,
    autoPanAnimation: {
        duration: 250
    }
});

map.addOverlay(popup);

closer.onclick = function () {
  popup.setPosition(undefined);
  closer.blur();
  return false;
};

// Show popup above Icon and Linestring on single click if feature exists
map.on('singleclick', function(event) {
  if (map.hasFeatureAtPixel(event.pixel) === true) {
    var coordinate = event.coordinate;
    var features = map.getFeaturesAtPixel(event.pixel);
    content.innerHTML = "undefined";

    if (features[0].getGeometry().getType() == "Point" && features[0].getProperties().name != "text") {
      // HTML content of point features
      if (features[0].getProperties().name == "kostel") {
        content.innerHTML = definePopupContent('<p>Zde si řekneme své ano.</p>',
                                              '<img src="data/pictures/kostel.jpg" width="300" height="200">',
                                              '<p>Kostel sv. Václava na Proseku</p>',
                                              features[0].getGeometry().getFlatCoordinates());
      }
      if (features[0].getProperties().name == "restaurant") {
        content.innerHTML = definePopupContent('<p>Zde náš významný den společně oslavíme.</p>',
                                              '<img src="data/pictures/sv_dvur.jpg" width="370" height="227">',
                                              '<p>Restaurace a hotel Svatojánský Dvůr</p>',
                                              features[0].getGeometry().getFlatCoordinates());
      }     
    } else if ((features[0].getGeometry().getType() == "LineString")) {
      // HTML content of linestring features
      content.innerHTML = features[0].getProperties().popupContent;
    }

    // Set position of overlazing popup
    if (content.innerHTML != "undefined") {
      popup.setPosition(coordinate);
    } else {
      popup.setPosition(undefined);
    }
  };
});

Znovu nezapomeneme na začátek souboru přidat importní deklarace:

import {addProjection} from 'ol/proj';
import {transform} from 'ol/proj';
import {register} from 'ol/proj/proj4';
import {toStringHDMS} from 'ol/coordinate';

import Overlay from 'ol/Overlay';
Po kliknutí na ikonku pivečka se nám zobrazí následující popup okno:

Vyskakovací okno na GeoJSON prvku s infem k hostině

Vyskakovací okna u vektorových dlaždic

Podobně můžeme nechat zobrazit vyskakovací okna při kliku na parcelu jakožto prvek vektorové dlaždice (dlaždic). Znovu půjde o událost typu singleclick:

// Show popup above Icon on single click on the parcela if parcela exists
map.on('singleclick', function(event) {
  vectorTiles.getFeatures(event.pixel).then(function (features) {
    const feature = features[0];
    if (!feature) {
      return;
    }
    var coordinate = event.coordinate;

    if (feature.get("ID_2") == 2238913101){
      content.innerHTML = "Případné další info k obřadu:.. ";
      popup.setPosition(coordinate);
    }
    if (feature.get("ID_2") == 2113941101){ 
      content.innerHTML = "Případné další info k hostině:.. ";
      popup.setPosition(coordinate);
    }
  });
});

Po kliknutí na ikonku příslušnou parcelu restaurace se nám zobrazí následující popup okno:

Vyskakovací okno na prvku vektorové dlaždice s infem k hostině