Initial commit - Typo3 11.5.41
This commit is contained in:
215
typo3conf/ext/ods_osm/Classes/Provider/BaseProvider.php
Normal file
215
typo3conf/ext/ods_osm/Classes/Provider/BaseProvider.php
Normal file
@@ -0,0 +1,215 @@
|
||||
<?php
|
||||
|
||||
namespace Bobosch\OdsOsm\Provider;
|
||||
|
||||
use Bobosch\OdsOsm\Div;
|
||||
use TYPO3\CMS\Core\Page\PageRenderer;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
|
||||
abstract class BaseProvider
|
||||
{
|
||||
/** @var ContentObjectRenderer */
|
||||
public $cObj; // Must set from instantiating class
|
||||
protected $config;
|
||||
protected $script;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected $pageRenderer;
|
||||
|
||||
/** @var array keeping all JavaScripts to be included */
|
||||
protected $scripts = [];
|
||||
|
||||
protected $layers = [
|
||||
0 => [], // Base
|
||||
1 => [], // Overlay
|
||||
2 => [], // Marker
|
||||
];
|
||||
|
||||
// Implement these functions
|
||||
public function getMapCore($backpath = '')
|
||||
{
|
||||
}
|
||||
|
||||
public function getMapMain()
|
||||
{
|
||||
}
|
||||
|
||||
public function getMapCenter($lat, $lon, $zoom)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getLayer($layer, $i, $backpath = '')
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getMarker($item, $table)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get JavaScript code for fulltext button
|
||||
*
|
||||
* @return string The JavaScript to add the fullscreen button
|
||||
*/
|
||||
protected function getFullScreen()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function init($config): void
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getMap($layers, $markers, $lon, $lat, $zoom)
|
||||
{
|
||||
$this->getMapCore();
|
||||
|
||||
$this->layers = $layers;
|
||||
|
||||
$baselayers = $layers[0] ?? null;
|
||||
$overlays = $layers[1] ?? null;
|
||||
|
||||
$this->script = "
|
||||
" . $this->getMapMain() . "
|
||||
" . $this->getBaseLayers($baselayers) . "
|
||||
" . $this->getOverlayLayers($overlays) . "
|
||||
" . $this->getMapCenter($lat, $lon, $zoom) . "
|
||||
" . $this->getMarkers($markers);
|
||||
|
||||
if (($this->config['show_layerswitcher'] ?? null) && ($this->config['show_layerswitcher'] > 0)) {
|
||||
$this->script .= $this->getLayerSwitcher() . "\n";
|
||||
}
|
||||
|
||||
if ($this->config['show_fullscreen'] ?? null) {
|
||||
$this->script .= $this->getFullScreen() . "\n";
|
||||
}
|
||||
|
||||
Div::addJsFiles($this->scripts, null);
|
||||
|
||||
return $this->getHtml();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getBaseLayers($layers, $backpath = '')
|
||||
{
|
||||
// Main layer
|
||||
$i = 0;
|
||||
$jsBaseLayer = [];
|
||||
if (is_array($layers) && !empty($layers)) {
|
||||
foreach ($layers as $layer) {
|
||||
$jsBaseLayer[] = $this->getLayer($layer, $i, $backpath);
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
return implode("\n", ($jsBaseLayer));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getOverlayLayers($layers, $backpath = '')
|
||||
{
|
||||
// Main layer
|
||||
$i = 0;
|
||||
$jsOverlayLayer = [];
|
||||
if (is_array($layers) && !empty($layers)) {
|
||||
foreach ($layers as $layer) {
|
||||
$jsOverlayLayer[] = $this->getLayer($layer, $i, $backpath);
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
return implode("\n", ($jsOverlayLayer));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getScript()
|
||||
{
|
||||
return $this->script;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getMarkers($markers)
|
||||
{
|
||||
$jsMarker = '';
|
||||
foreach ($markers as $table => $items) {
|
||||
foreach ($items as $item) {
|
||||
$jsMarker .= $this->getMarker($item, $table);
|
||||
}
|
||||
}
|
||||
|
||||
return $jsMarker;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getLayerSwitcher()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getHtml()
|
||||
{
|
||||
$mousePosition = '';
|
||||
$popupcode = '';
|
||||
if ($this->config['library'] == 'openlayers') {
|
||||
if ($this->config['mouse_position']) {
|
||||
$mousePosition = '<div id="mouse-position-' . $this->config['id'] . '">' . LocalizationUtility::translate('mouse_position', 'OdsOsm') . ': </div>';
|
||||
}
|
||||
$popupcode = '
|
||||
<div id="popup" class="ol-popup">
|
||||
<a href="#" id="popup-closer" class="ol-popup-closer"></a>
|
||||
<div id="popup-content"></div>
|
||||
</div>';
|
||||
}
|
||||
return '<div style="width:' . $this->config['width'] . '; height:' . $this->config['height'] . '; " id="' . $this->config['id'] . '"></div>' . $mousePosition . $popupcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getTileUrl($layer)
|
||||
{
|
||||
if (strpos($layer['tile_url'], '://') !== false) {
|
||||
return $layer['tile_url'];
|
||||
}
|
||||
// if protocoll is missing, we add http:// or https://
|
||||
if ($layer['tile_https'] == 1) {
|
||||
return 'https://' . $layer['tile_url'];
|
||||
}
|
||||
return 'http://' . $layer['tile_url'];
|
||||
}
|
||||
|
||||
public function setContentObjectRenderer(ContentObjectRenderer $cObj): void
|
||||
{
|
||||
$this->cObj = $cObj;
|
||||
}
|
||||
}
|
||||
355
typo3conf/ext/ods_osm/Classes/Provider/Leaflet.php
Normal file
355
typo3conf/ext/ods_osm/Classes/Provider/Leaflet.php
Normal file
@@ -0,0 +1,355 @@
|
||||
<?php
|
||||
|
||||
namespace Bobosch\OdsOsm\Provider;
|
||||
|
||||
use Bobosch\OdsOsm\Div;
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Resource\FileRepository;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\PathUtility;
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
|
||||
class Leaflet extends BaseProvider
|
||||
{
|
||||
protected $path_res;
|
||||
protected $path_leaflet;
|
||||
|
||||
public function getMapCore($backpath = ''): void
|
||||
{
|
||||
$this->path_res = ($backpath ? $backpath :
|
||||
PathUtility::getAbsoluteWebPath(
|
||||
GeneralUtility::getFileAbsFileName(Div::RESOURCE_BASE_PATH . 'JavaScript/Leaflet/')
|
||||
)
|
||||
);
|
||||
$this->path_leaflet = ($this->config['local_js'] ? $this->path_res . 'Core/' : 'https://unpkg.com/leaflet@1.9.4/dist/');
|
||||
$this->pageRenderer->addCssFile($this->path_leaflet . 'leaflet.css');
|
||||
$this->scripts['leaflet'] = [
|
||||
'src' => $this->path_leaflet . 'leaflet.js',
|
||||
'sri' => 'sha384-cxOPjt7s7Iz04uaHJceBmS+qpjv2JkIHNVcuOrM+YHwZOmJGBXI00mdUXEq65HTH'
|
||||
];
|
||||
}
|
||||
|
||||
public function getMapMain()
|
||||
{
|
||||
$controls = [];
|
||||
if ($this->config['show_scalebar']) {
|
||||
$controls['scalebar'] = 'new L.control.scale()';
|
||||
}
|
||||
|
||||
$vars = '';
|
||||
foreach ($controls as $var => $obj) {
|
||||
$vars .= "\n\t\t\t" . $this->config['id'] . '.addControl(' . $obj . ");";
|
||||
}
|
||||
|
||||
$jsMain =
|
||||
$this->config['id'] . "=new L.Map('" . $this->config['id'] . "',
|
||||
{scrollWheelZoom: " .((!isset($this->config['enable_scrollwheelzoom']) || $this->config['enable_scrollwheelzoom'] == '1') ? 'true' : 'false'). ",
|
||||
dragging: " .((!isset($this->config['enable_dragging']) || $this->config['enable_dragging'] == '1') ? 'true' : 'false'). "});
|
||||
L.Icon.Default.imagePath='" . $this->path_leaflet . "images/';"
|
||||
. $vars;
|
||||
if ($this->config['cluster']) {
|
||||
$this->pageRenderer->addCssFile($this->path_res . 'leaflet-markercluster/MarkerCluster.css');
|
||||
$this->pageRenderer->addCssFile($this->path_res . 'leaflet-markercluster/MarkerCluster.Default.css');
|
||||
$this->scripts['leaflet-markercluster'] = [
|
||||
'src' => $this->path_res . 'leaflet-markercluster/leaflet.markercluster.js'
|
||||
];
|
||||
}
|
||||
|
||||
return $jsMain;
|
||||
}
|
||||
|
||||
protected function getLayer($layer, $i, $backpath = '')
|
||||
{
|
||||
if ($layer['tile_url']) {
|
||||
$options = [];
|
||||
if ($layer['min_zoom']) {
|
||||
$options['minZoom'] = $layer['min_zoom'];
|
||||
}
|
||||
if ($layer['max_zoom']) {
|
||||
$options['maxZoom'] = $layer['max_zoom'];
|
||||
}
|
||||
if ($layer['subdomains']) {
|
||||
$options['subdomains'] = $layer['subdomains'];
|
||||
}
|
||||
if ($layer['attribution']) {
|
||||
$options['attribution'] = $layer['attribution'];
|
||||
}
|
||||
|
||||
$jsLayer = 'new L.TileLayer(\'' . $this->getTileUrl($layer) . '\',' . json_encode($options) . ');';
|
||||
}
|
||||
|
||||
$jsLayer = "\n\t\t\tvar layer_" . $layer['uid'] . ' = ' . $jsLayer;
|
||||
|
||||
// only show first base layer on the map
|
||||
if (($layer['overlay'] == 1 && $layer['visible']) || ($i == 0 && $layer['overlay'] == 0)) {
|
||||
$jsLayer .= "\n\t\t\t" . $this->config['id'] . '.addLayer(layer_' . $layer['uid'] . ');';
|
||||
}
|
||||
|
||||
return $jsLayer;
|
||||
}
|
||||
|
||||
protected function getLayerSwitcher()
|
||||
{
|
||||
$base = [];
|
||||
if (is_array($this->layers[0] ?? null) && count($this->layers[0]) > 1) {
|
||||
foreach ($this->layers[0] as $layer) {
|
||||
$base[] = '"' . $layer['title'] . '":' . ($layer['table'] ?? 'layer') . '_' . $layer['uid'];
|
||||
}
|
||||
}
|
||||
$overlay = [];
|
||||
if (is_array($this->layers[1] ?? null)) {
|
||||
foreach ($this->layers[1] as $layer) {
|
||||
if (!empty($layer['gid'])) {
|
||||
$overlay[] = '"' . $layer['title'] . '":' . $layer['gid'];
|
||||
} else {
|
||||
$overlay[] = '"' . $layer['title'] . '":' . ($layer['table'] ?? 'layer') . '_' . $layer['uid'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($base) && empty($overlay)) {
|
||||
return '';
|
||||
}
|
||||
return 'var layersControl=new L.Control.Layers({' . implode(',', $base) . '},{' . implode(',', $overlay) . '}' . ($this->config['show_layerswitcher'] == 2 ? ',{collapsed:false}' : '') . ');
|
||||
' . $this->config['id'] . '.addControl(layersControl);';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fullscreen button
|
||||
*
|
||||
* @return string The JavaScript to add the fullscreen button
|
||||
*/
|
||||
public function getFullScreen()
|
||||
{
|
||||
// load leaflet.fullscreen plugin
|
||||
$this->scripts['leaflet-fullscreen'] = [
|
||||
'src' => $this->path_res . 'leaflet-fullscreen/Control.FullScreen.js',
|
||||
'sri' => 'sha384-TqFtkYBnYsrP2JCfIv/oLQxS9L6xpaIV9xnaI2UGMK25cJsTtQXZIU6WGQ7daT0Z'
|
||||
];
|
||||
$this->pageRenderer->addCssFile($this->path_res . 'leaflet-fullscreen/Control.FullScreen.css');
|
||||
|
||||
return "L.control.fullscreen({
|
||||
position: 'topleft',
|
||||
title: 'Full Screen',
|
||||
titleCancel: 'Exit fullscreen mode',
|
||||
forceSeparateButton: true,
|
||||
forcePseudoFullscreen: true, // force use of pseudo full screen even if full screen API is available, default false
|
||||
fullscreenElement: false // Dom element to render in full screen, false by default, fallback to map._container
|
||||
}).addTo(" . $this->config['id'] . ");";
|
||||
}
|
||||
|
||||
public function getMapCenter($lat, $lon, $zoom)
|
||||
{
|
||||
$return = 'var center = new L.LatLng(' . json_encode($lat) . ',' . json_encode($lon) . ');' . $this->config['id'] . '.setView(center,' . $zoom . ');';
|
||||
if ($this->config['position']) {
|
||||
$return .= $this->config['id'] . '.locate();' . $this->config['id'] . '.on("locationfound",function(e){var radius=e.accuracy/2;L.circle(e.latlng,radius).addTo(' . $this->config['id'] . ');});';
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
protected function getMarkers($markers)
|
||||
{
|
||||
$jsMarker = parent::getMarkers($markers);
|
||||
|
||||
foreach ($this->layers[2] as $group_uid => $group) {
|
||||
if ($this->config['cluster']) {
|
||||
$jsMarker .= 'var ' . $group_uid . ' = new L.MarkerClusterGroup({maxClusterRadius:' . (int)$this->config['cluster_radius'] . '});' . "\n";
|
||||
foreach ($group as $jsElementVar) {
|
||||
$jsMarker .= $group_uid . '.addLayer(' . $jsElementVar . ');' . "\n";
|
||||
}
|
||||
} else {
|
||||
$jsMarker .= 'var ' . $group_uid . ' = L.layerGroup([' . implode(',', $group) . ']);' . "\n";
|
||||
}
|
||||
$jsMarker .= $this->config['id'] . '.addLayer(' . $group_uid . ');' . "\n";
|
||||
}
|
||||
|
||||
return $jsMarker;
|
||||
}
|
||||
|
||||
protected function getMarker($item, $table)
|
||||
{
|
||||
$jsMarker = '';
|
||||
$jsElementVar = $table . '_' . $item['uid'];
|
||||
$fileRepository = GeneralUtility::makeInstance(FileRepository::class);
|
||||
$jsElementVarsForPopup = [];
|
||||
|
||||
switch ($table) {
|
||||
case 'tx_odsosm_track':
|
||||
$fileObjects = $fileRepository->findByRelation('tx_odsosm_track', 'file', $item['uid']);
|
||||
if ($fileObjects) {
|
||||
$file = $fileObjects[0];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
// Add tracks to layerswitcher
|
||||
$this->layers[1][] = [
|
||||
'title' => $item['title'],
|
||||
'table' => $table,
|
||||
'uid' => $item['uid']
|
||||
];
|
||||
|
||||
switch (strtolower(pathinfo($file->getName(), PATHINFO_EXTENSION))) {
|
||||
case 'kml':
|
||||
// include javascript file for KML support
|
||||
$this->scripts['leaflet-plugins'] = [
|
||||
'src' => $this->path_res . 'leaflet-plugins/layer/vector/KML.js'
|
||||
];
|
||||
|
||||
$jsMarker .= 'var ' . $jsElementVar . ' = new L.KML(';
|
||||
$jsMarker .= '"' . $file->getPublicUrl() . '"';
|
||||
$jsMarker .= ");\n";
|
||||
$jsMarker .= $this->config['id'] . '.addLayer(' . $jsElementVar . ');' . "\n";
|
||||
break;
|
||||
case 'gpx':
|
||||
// include javascript file for GPX support
|
||||
$this->scripts['leaflet-gpx'] = [
|
||||
'src' => $this->path_res . 'leaflet-gpx/gpx.js'
|
||||
];
|
||||
$options = [
|
||||
'clickable' => 'false',
|
||||
'polyline_options' => [
|
||||
'color' => $item['color'],
|
||||
'weight' => $item['width'] ?: 1,
|
||||
],
|
||||
'marker_options' => [
|
||||
'startIconUrl' => $this->path_res . 'leaflet-gpx/pin-icon-start.png',
|
||||
'endIconUrl' => $this->path_res . 'leaflet-gpx/pin-icon-end.png',
|
||||
'shadowUrl' => $this->path_res . 'leaflet-gpx/pin-shadow.png',
|
||||
],
|
||||
];
|
||||
$jsMarker .= 'var ' . $jsElementVar . ' = new L.GPX("' . $file->getPublicUrl() . '",';
|
||||
|
||||
$jsMarker .= json_encode($options) . ");\n";
|
||||
$jsMarker .= $this->config['id'] . '.addLayer(' . $jsElementVar . ');' . "\n";
|
||||
break;
|
||||
}
|
||||
$jsElementVarsForPopup[] = $jsElementVar;
|
||||
break;
|
||||
case 'tx_odsosm_vector':
|
||||
// add styles from record if both are set - color and width
|
||||
if (!empty($item['color']) && !empty($item['width'])) {
|
||||
$jsMarker .= 'var myStyle = {
|
||||
"color": "'.$item['color'].'",
|
||||
"weight": '.$item['width'].',
|
||||
"opacity": 1
|
||||
};';
|
||||
} else {
|
||||
$jsMarker .= 'var myStyle = {};';
|
||||
}
|
||||
|
||||
$fileObjects = $fileRepository->findByRelation('tx_odsosm_vector', 'file', $item['uid']);
|
||||
if ($fileObjects) {
|
||||
$file = $fileObjects[0];
|
||||
$filename = Environment::getPublicPath() . '/' . $file->getPublicUrl();
|
||||
$jsMarker .= 'var ' . $jsElementVar . '_file = new L.geoJson(' . file_get_contents($filename) . ',
|
||||
{
|
||||
style: myStyle
|
||||
});' . "\n";
|
||||
$jsMarker .= $this->config['id'] . '.addLayer(' . $jsElementVar . '_file);' . "\n";
|
||||
|
||||
// Add vector file to layerswitcher
|
||||
$this->layers[1][] = [
|
||||
'title' => $item['title'] . ' ('. LocalizationUtility::translate('file', 'OdsOsm') .')',
|
||||
'table' => $table,
|
||||
'uid' => $item['uid'] . '_file'
|
||||
];
|
||||
$jsElementVarsForPopup[] = $jsElementVar . '_file';
|
||||
}
|
||||
|
||||
// add geojson from data field as well
|
||||
if ($item['data']) {
|
||||
$jsMarker .= 'var ' . $jsElementVar . '_data = new L.geoJson(' . $item['data'] . ',
|
||||
{
|
||||
style: myStyle
|
||||
});' . "\n";
|
||||
$jsMarker .= $this->config['id'] . '.addLayer(' . $jsElementVar . '_data);' . "\n";
|
||||
|
||||
// Add vector data to layerswitcher
|
||||
$this->layers[1][] = [
|
||||
'title' => $item['title'],
|
||||
'table' => $table,
|
||||
'uid' => $item['uid'] . '_data'
|
||||
];
|
||||
$jsElementVarsForPopup[] = $jsElementVar . '_data';
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
$markerOptions = [];
|
||||
if ($item['tx_odsosm_marker'] ?? false) {
|
||||
$marker = $item['tx_odsosm_marker'];
|
||||
$iconOptions = [
|
||||
'iconSize' => [(int)$marker['size_x'], (int)$marker['size_y']],
|
||||
'iconAnchor' => [-(int)$marker['offset_x'], -(int)$marker['offset_y']],
|
||||
'popupAnchor' => [0, (int)$marker['offset_y']]
|
||||
];
|
||||
if ($marker['type'] == 'html') {
|
||||
$iconOptions['html'] = $marker['icon'];
|
||||
$markerOptions['icon'] = 'icon: new L.divIcon(' . json_encode($iconOptions) . ')';
|
||||
} else {
|
||||
$icon = $marker['icon']->getPublicUrl();
|
||||
$iconOptions['iconUrl'] = $icon;
|
||||
$markerOptions['icon'] = 'icon: new L.Icon(' . json_encode($iconOptions) . ')';
|
||||
}
|
||||
} else {
|
||||
$marker = [ 'type' => 'image' ];
|
||||
$icon = $this->path_leaflet . 'images/marker-icon.png';
|
||||
}
|
||||
$jsMarker .= 'var ' . $jsElementVar . ' = new L.Marker([' . $item['latitude'] . ', ' . $item['longitude'] . '], {' . implode(',', $markerOptions) . "});\n";
|
||||
// Add group to layer switch
|
||||
if ($item['group_title'] ?? false) {
|
||||
$this->layers[1][] = [
|
||||
'title' => ($marker['type'] == 'html' ? $marker['icon'] : "<img class='marker-icon' src='" . $icon . "' />") . ' ' . $item['group_title'],
|
||||
'gid' => $item['group_uid']
|
||||
];
|
||||
$this->layers[2][$item['group_uid']][] = $jsElementVar;
|
||||
} else {
|
||||
$this->layers[2][$this->config['id'] . '_g'][] = $jsElementVar;
|
||||
}
|
||||
|
||||
$jsElementVarsForPopup[] = $jsElementVar;
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($jsElementVarsForPopup as $jsElementVar) {
|
||||
// is there a properties attribute from geoJSON? If so, we will show the given properties
|
||||
$popupJsCode = '';
|
||||
if ($item['properties'] ?? null) {
|
||||
$geojsonProperties = json_encode(explode(', ', $item['properties']));
|
||||
$popupJsCode = "
|
||||
function (layer) {
|
||||
var osm_popup = '" . ($item['popup'] ?? '') . "';
|
||||
|
||||
var feature = layer.feature,
|
||||
props = feature.properties,
|
||||
ll = Object.keys(props),
|
||||
attribute, value = '';
|
||||
|
||||
var osm_filter = " . $geojsonProperties . ";
|
||||
|
||||
osm_filter.forEach((osm_prop) => {
|
||||
if (typeof props[osm_prop] !== 'undefined') {
|
||||
value += '<dt>' + osm_prop + '</dt> <dd>' + props[osm_prop] + '</dd>';
|
||||
}
|
||||
});
|
||||
return osm_popup + '<dl>' + value + '</dl>';
|
||||
}
|
||||
";
|
||||
} elseif ($item['popup'] ?? null) {
|
||||
$popupJsCode = json_encode($item['popup'] ?? '');
|
||||
}
|
||||
if ($this->config['show_popups'] == 1) {
|
||||
$jsMarker .= $jsElementVar . '.bindPopup(' . $popupJsCode . '); ' . "\n";
|
||||
if ($item['initial_popup'] ?? null) {
|
||||
$jsMarker .= $jsElementVar . ".openPopup();\n";
|
||||
}
|
||||
} elseif ($this->config['show_popups'] == 2) {
|
||||
$jsMarker .= $jsElementVar . '.bindTooltip(' . $popupJsCode . ");\n";
|
||||
}
|
||||
}
|
||||
|
||||
return $jsMarker;
|
||||
}
|
||||
}
|
||||
632
typo3conf/ext/ods_osm/Classes/Provider/Openlayers.php
Normal file
632
typo3conf/ext/ods_osm/Classes/Provider/Openlayers.php
Normal file
@@ -0,0 +1,632 @@
|
||||
<?php
|
||||
/***************************************************************
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2022 Alexander Bigga <alexander@bigga.de>
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
namespace Bobosch\OdsOsm\Provider;
|
||||
|
||||
use Bobosch\OdsOsm\Div;
|
||||
use TYPO3\CMS\Core\Page\PageRenderer;
|
||||
use TYPO3\CMS\Core\Resource\FileRepository;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\PathUtility;
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
|
||||
class Openlayers extends BaseProvider
|
||||
{
|
||||
protected $layers = [
|
||||
0 => [], // Base
|
||||
1 => [], // Overlay
|
||||
2 => [], // Marker
|
||||
];
|
||||
|
||||
public function getMapCore($backpath = ''): void
|
||||
{
|
||||
$path = ($backpath ? $backpath :
|
||||
PathUtility::getAbsoluteWebPath(
|
||||
GeneralUtility::getFileAbsFileName(Div::RESOURCE_BASE_PATH . 'OpenLayers/')
|
||||
)
|
||||
);
|
||||
$pathOl = ($this->config['local_js'] ? $path : 'https://cdn.jsdelivr.net/npm/ol@v8.1.0/');
|
||||
$pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
|
||||
$pageRenderer->addCssFile($pathOl . 'ol.css');
|
||||
$this->scripts['OpenLayers'] = [
|
||||
'src' => $pathOl . 'dist/ol.js',
|
||||
'sri' => 'sha512-7BxMviUlJVAJOF4l717SzPknm3Y5nLAm3PPtRdrWlCu4GLaW+RhBxYuOJ1MkVNAcPu+lRWn4gtWx0PAxvTzD0g=='
|
||||
];
|
||||
|
||||
// Do we need the layerswitcher? If so, some extra plugin is required.
|
||||
if ($this->config['show_layerswitcher']) {
|
||||
$pathContrib = ($this->config['local_js'] ? $path . 'Contrib/ol-layerswitcher/' : 'https://unpkg.com/ol-layerswitcher@4.1.1/dist/');
|
||||
$pathCustom = $path . 'Custom/';
|
||||
|
||||
$pageRenderer->addCssFile($pathContrib . 'ol-layerswitcher.css');
|
||||
$pageRenderer->addCssFile($pathCustom . 'ol-layerswitcher.css');
|
||||
|
||||
$this->scripts['OpenLayersSwitch'] = [
|
||||
'src' => $pathContrib . 'ol-layerswitcher.js',
|
||||
'sri' => 'sha512-HhCrrWOoQb5HSpRe1fsk9ugZQEOokbJsLioPuUhfXlr5ccRTZVg3UpnfRsTJzrdKLejmx7uvY62n2fp5qLdYQg=='
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
public function getMapMain()
|
||||
{
|
||||
$controls = [
|
||||
'new ol.control.Attribution()',
|
||||
'new ol.control.Zoom()',
|
||||
'new ol.control.Rotate()'
|
||||
];
|
||||
if ($this->config['mouse_position']) {
|
||||
$controls[] = "new ol.control.MousePosition({
|
||||
coordinateFormat: ol.coordinate.createStringXY(2),
|
||||
projection: 'EPSG:4326',
|
||||
className: 'ods-osm-mouse-position',
|
||||
target: document.getElementById('mouse-position-" . $this->config['id'] . "')
|
||||
})";
|
||||
}
|
||||
if ($this->config['show_scalebar']) {
|
||||
$controls[] = "new ol.control.ScaleLine()";
|
||||
}
|
||||
|
||||
return "
|
||||
view = new ol.View({
|
||||
center: [0, 0],
|
||||
zoom: 1
|
||||
});
|
||||
|
||||
baselayergroup = new ol.layer.Group({
|
||||
name: 'baselayergroup',
|
||||
title: '" . LocalizationUtility::translate('base_layer', 'OdsOsm') . "',
|
||||
layers: [
|
||||
new ol.layer.Tile({
|
||||
type: 'base',
|
||||
source: new ol.source.OSM(),
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
overlaygroup = new ol.layer.Group({
|
||||
name: 'overlaygroup',
|
||||
title: '" . LocalizationUtility::translate('overlays', 'OdsOsm') . "',
|
||||
layers: []
|
||||
});
|
||||
|
||||
const styleCache = {};
|
||||
clusters = new ol.layer.Vector({
|
||||
name: 'clusters',
|
||||
title: '" . LocalizationUtility::translate('openlayers.clusterLayer', 'OdsOsm') . "',
|
||||
source: new ol.source.Cluster({
|
||||
distance: " . (int)$this->config['cluster_radius'] . ",
|
||||
minDistance: 10,
|
||||
source: new ol.source.Vector({
|
||||
name: 'source',
|
||||
features: [],
|
||||
})
|
||||
}),
|
||||
style: function (feature) {
|
||||
const size = feature.get('features').length;
|
||||
if (size > 1) {
|
||||
style = new ol.style.Style({
|
||||
image: new ol.style.Circle({
|
||||
radius: 20,
|
||||
stroke: new ol.style.Stroke({
|
||||
color: '#fff',
|
||||
}),
|
||||
fill: new ol.style.Fill({
|
||||
color: '#3399CC',
|
||||
}),
|
||||
}),
|
||||
text: new ol.style.Text({
|
||||
text: size.toString(),
|
||||
fill: new ol.style.Fill({
|
||||
color: '#fff',
|
||||
}),
|
||||
}),
|
||||
});
|
||||
} else {
|
||||
style = feature.get('features')[0].values_.style;
|
||||
}
|
||||
return style;
|
||||
},
|
||||
});
|
||||
|
||||
layers = [
|
||||
baselayergroup,
|
||||
overlaygroup
|
||||
];
|
||||
|
||||
var " . $this->config['id'] . " = new ol.Map({
|
||||
target: '" . $this->config['id'] . "',
|
||||
controls:[" . implode(',', $controls) . "],
|
||||
layers: layers,
|
||||
view: view
|
||||
});
|
||||
|
||||
// Popup showing the position the user clicked
|
||||
var container = document.getElementById('popup');
|
||||
var closer = document.getElementById('popup-closer');
|
||||
var content = document.getElementById('popup-content');
|
||||
var popup = new ol.Overlay({
|
||||
element: container,
|
||||
autoPan: true,
|
||||
autoPanAnimation: {
|
||||
duration: 100
|
||||
}
|
||||
});
|
||||
" . $this->config['id'] . ".addOverlay(popup);
|
||||
closer.onclick = function () {
|
||||
popup.setPosition(undefined);
|
||||
content.innerHTML = '';
|
||||
closer.blur();
|
||||
return false;
|
||||
};
|
||||
";
|
||||
}
|
||||
|
||||
/**
|
||||
* The center and zoom level of the map
|
||||
*
|
||||
* @param float $lat: latitude
|
||||
* @param float $lon: longitude
|
||||
* @param int $zoom: zoom level
|
||||
*
|
||||
* @return string The JavaScript to set the center and zoom level
|
||||
*/
|
||||
public function getMapCenter($lat, $lon, $zoom)
|
||||
{
|
||||
return '
|
||||
view.setCenter(ol.proj.transform([' . $lon . ', ' . $lat . '], \'EPSG:4326\', \'EPSG:3857\'));
|
||||
view.setZoom(' . $zoom . ');
|
||||
';
|
||||
}
|
||||
|
||||
protected function getLayer($layer, $i, $backpath = '')
|
||||
{
|
||||
if (empty($layer['subdomains'])) {
|
||||
$layer['subdomains'] = 'abc';
|
||||
}
|
||||
$layer['subdomains'] = substr($layer['subdomains'], 0, 1) . '-' . substr($layer['subdomains'], -1, 1);
|
||||
$layer['tile_url'] = strtr($this->getTileUrl($layer), ['{s}' => '{' . $layer['subdomains'] . '}']);
|
||||
|
||||
if ($layer['overlay'] == 1) {
|
||||
return $this->config['id'] . "_" . $i . "_overlayLayer =
|
||||
new ol.layer.Tile({
|
||||
visible: " . ($layer['visible'] == true ? 'true' : 'false') . ",
|
||||
opacity: 0.99,
|
||||
title: '" . $layer['title'] . "',
|
||||
source: new ol.source.OSM({
|
||||
url: '" . $layer['tile_url'] . "',
|
||||
attributions: [
|
||||
'" . $layer['attribution']. "'
|
||||
]
|
||||
})
|
||||
});
|
||||
overlaygroup.getLayers().push(" . $this->config['id'] . "_" . $i . "_overlayLayer);
|
||||
";
|
||||
}
|
||||
|
||||
return $this->config['id'] . "_" . $i . "_baselayergroup =
|
||||
new ol.layer.Tile({
|
||||
type: 'base',
|
||||
combine: 'true',
|
||||
visible: " . ($i == 0 ? 'true' : 'false') . ",
|
||||
title: '" . $layer['title'] . "',
|
||||
source: new ol.source.OSM({
|
||||
url: '" . $layer['tile_url'] . "',
|
||||
attributions: [
|
||||
'" . $layer['attribution']. "'
|
||||
]
|
||||
})
|
||||
});
|
||||
baselayergroup.getLayers().push(" . $this->config['id'] . "_" . $i . "_baselayergroup);
|
||||
";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the layer switcher
|
||||
*
|
||||
* @return string The JavaScript to add the layerswitcher
|
||||
*/
|
||||
protected function getLayerSwitcher()
|
||||
{
|
||||
return '
|
||||
var layerSwitcher = new ol.control.LayerSwitcher({
|
||||
activationMode: \'' . ($this->config['layerswitcher_activationMode'] == '1' ? 'click' : 'mouseover') . '\',
|
||||
startActive: ' . ($this->config['show_layerswitcher'] == '2' ? 'true' : 'false') . ',
|
||||
tipLabel: \'' . LocalizationUtility::translate('openlayers.showLayerList', 'OdsOsm') . '\',
|
||||
collapseTipLabel: \'' . LocalizationUtility::translate('openlayers.hideLayerList', 'OdsOsm') . '\',
|
||||
groupSelectStyle: \'children\',
|
||||
reverse: false
|
||||
});
|
||||
' . $this->config['id'] . '.addControl(layerSwitcher);
|
||||
';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fullscreen button
|
||||
*
|
||||
* @return string The JavaScript to add the fullscreen button
|
||||
*/
|
||||
protected function getFullScreen()
|
||||
{
|
||||
return '
|
||||
var fullScreen = new ol.control.FullScreen();
|
||||
' . $this->config['id'] . '.addControl(fullScreen);
|
||||
';
|
||||
}
|
||||
|
||||
protected function getMarkers($markers)
|
||||
{
|
||||
$jsMarker = parent::getMarkers($markers);
|
||||
|
||||
// open popup? If yes, with click or hover?
|
||||
switch ($this->config['show_popups']) {
|
||||
case 1:
|
||||
$eventMethod = 'singleclick';
|
||||
break;
|
||||
case 2:
|
||||
$eventMethod = 'pointermove';
|
||||
break;
|
||||
default:
|
||||
$eventMethod = false;
|
||||
}
|
||||
|
||||
if ($eventMethod !== false) {
|
||||
$jsMarker .= "
|
||||
" . $this->config['id'] . ".on('" . $eventMethod . "', function (event) {
|
||||
var feature = " . $this->config['id'] . ".forEachFeatureAtPixel(event.pixel, function (feat, layer) {
|
||||
return feat;
|
||||
});
|
||||
var layer = " . $this->config['id'] . ".forEachFeatureAtPixel(event.pixel, function (feat, layer) {
|
||||
return layer;
|
||||
});
|
||||
|
||||
if (feature === undefined) {
|
||||
return;
|
||||
}
|
||||
if (feature.get('features') === undefined) {
|
||||
var coordinate = event.coordinate;
|
||||
if (feature.get('desc') !== undefined) {
|
||||
content.innerHTML = feature.get('desc');
|
||||
} else {
|
||||
// this might be some geoJSON data with properties set
|
||||
|
||||
var osm_popup = layer.get('popup');
|
||||
var props = feature.values_,
|
||||
ll = Object.keys(props),
|
||||
attribute, value = '';
|
||||
|
||||
var osm_filter = layer.get('properties').split(',').map(item=>item.trim());
|
||||
|
||||
osm_filter.forEach((osm_prop) => {
|
||||
if (typeof feature.get(osm_prop) !== 'undefined') {
|
||||
value += '<dt>' + osm_prop + '</dt> <dd>' + feature.get(osm_prop) + '</dd>';
|
||||
}
|
||||
});
|
||||
content.innerHTML = osm_popup + '<dl>' + value + '</dl>';
|
||||
}
|
||||
popup.setPosition(coordinate);
|
||||
} else if (feature.get('features').length === 1) {
|
||||
var singleFeature = feature.get('features')[0];
|
||||
if (feature && singleFeature.get('type') == 'Point') {
|
||||
var coordinate = event.coordinate;
|
||||
|
||||
content.innerHTML = singleFeature.get('desc');
|
||||
popup.setPosition(coordinate);
|
||||
}
|
||||
} else if (feature && feature.get('type') == 'Point') {
|
||||
|
||||
var coordinate = event.coordinate;
|
||||
|
||||
content.innerHTML = feature.get('desc');
|
||||
popup.setPosition(coordinate);
|
||||
} else {
|
||||
if (feature.get('features').length > 0) {
|
||||
const clusterMembers = feature.get('features');
|
||||
if (clusterMembers.length > 1) {
|
||||
// Calculate the extent of the cluster members.
|
||||
const extent = new ol.extent.createEmpty();
|
||||
clusterMembers.forEach((feature) =>
|
||||
ol.extent.extend(extent, feature.getGeometry().getExtent())
|
||||
);
|
||||
const view = " . $this->config['id'] . ".getView();
|
||||
const resolution = " . $this->config['id'] . ".getView().getResolution();
|
||||
if (
|
||||
view.getZoom() === view.getMaxZoom() ||
|
||||
(ol.extent.getWidth(extent) < resolution && ol.extent.getHeight(extent) < resolution)
|
||||
) {
|
||||
// Show an expanded view of the cluster members.
|
||||
clickFeature = features[0];
|
||||
clickResolution = resolution;
|
||||
clusterCircles.setStyle(clusterCircleStyle);
|
||||
} else {
|
||||
// Zoom to the extent of the cluster members.
|
||||
view.fit(extent, {duration: 600, padding: [100, 100, 100, 100]});
|
||||
}
|
||||
}
|
||||
}
|
||||
popup.setPosition(undefined);
|
||||
}
|
||||
});
|
||||
";
|
||||
}
|
||||
|
||||
// grouped marker layer
|
||||
foreach ($this->layers[2] as $group_uid => $group) {
|
||||
|
||||
$jsMarker .= $group['layer'];
|
||||
$jsMarkerFeatureBatch = [];
|
||||
foreach ($group['jsMarkerFeatures'] as $id => $jsMarkerFeature) {
|
||||
$jsMarker .= 'var ' . $group_uid . $id . ' = ' . $jsMarkerFeature;
|
||||
$jsMarkerFeatureBatch[] = $group_uid . $id;
|
||||
}
|
||||
|
||||
if ($this->config['cluster']) {
|
||||
$jsMarker .= 'clusters.getSource().getSource().addFeatures([' . implode(',', $jsMarkerFeatureBatch) . ']);' . "\n";
|
||||
} else {
|
||||
$jsMarker .= $group_uid . '.getSource().addFeatures([' . implode(',', $jsMarkerFeatureBatch) . ']);' . "\n";
|
||||
$jsMarker .= 'overlaygroup.getLayers().push(' . $group_uid . ');' . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->config['cluster']) {
|
||||
// add cluster layer in overlaygroup
|
||||
$jsMarker .= 'overlaygroup.getLayers().push(clusters);' . "\n";
|
||||
}
|
||||
|
||||
return $jsMarker;
|
||||
}
|
||||
|
||||
protected function getMarker($item, $table)
|
||||
{
|
||||
$jsMarker = '';
|
||||
$jsElementVar = $table . '_' . $item['uid'];
|
||||
$fileRepository = GeneralUtility::makeInstance(FileRepository::class);
|
||||
|
||||
// Convert item color hex value to rgba() as Openlayers doesn't have an opacity option.
|
||||
if (empty($item['color'])) {
|
||||
// set default blue, if nothing is given
|
||||
$item['color'] = '#0009ff';
|
||||
}
|
||||
if (strlen($item['color']) == 7) {
|
||||
$hex = [ $item['color'][1] . $item['color'][2], $item['color'][3] . $item['color'][4], $item['color'][5] . $item['color'][6] ];
|
||||
$rgb = array_map('hexdec', $hex);
|
||||
$opacity = '0.2';
|
||||
$item['rgba'] = 'rgba('.implode(",", $rgb).','.$opacity.')';
|
||||
}
|
||||
|
||||
switch ($table) {
|
||||
case 'tx_odsosm_track':
|
||||
$fileObjects = $fileRepository->findByRelation('tx_odsosm_track', 'file', $item['uid']);
|
||||
if ($fileObjects) {
|
||||
$file = $fileObjects[0];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
// Add tracks to layerswitcher
|
||||
$this->layers[1][] = [
|
||||
'title' => $item['title'],
|
||||
'table' => $table,
|
||||
'uid' => $item['uid']
|
||||
];
|
||||
|
||||
// define style from given color and width
|
||||
$jsMarker .= 'var ' . $jsElementVar . '_style = new ol.style.Style({
|
||||
stroke: new ol.style.Stroke({
|
||||
color: \''.$item['color'].'\',
|
||||
width: '.($item['width'] ?: 1).'
|
||||
}),
|
||||
fill: new ol.style.Fill({
|
||||
color: \''.$item['rgba'].'\'
|
||||
}),
|
||||
});';
|
||||
|
||||
switch (strtolower(pathinfo($file->getName(), PATHINFO_EXTENSION))) {
|
||||
case 'kml':
|
||||
$jsMarker .= 'var ' . $jsElementVar . '_gpx = new ol.layer.Vector({
|
||||
title: \'' .$item['title'] . '\',
|
||||
source: new ol.source.Vector({
|
||||
projection: \'EPSG:3857\',
|
||||
url: \'' . $file->getPublicUrl() . '\',
|
||||
format: new ol.format.KML()
|
||||
}),
|
||||
style: ' . $jsElementVar . '_style
|
||||
});' . "\n";
|
||||
|
||||
$jsMarker .= "overlaygroup.getLayers().push(" . $jsElementVar . "_gpx);";
|
||||
break;
|
||||
case 'gpx':
|
||||
$jsMarker .= 'var ' . $jsElementVar . '_gpx = new ol.layer.Vector({
|
||||
title: \'' .$item['title'] . '\',
|
||||
source: new ol.source.Vector({
|
||||
projection: \'EPSG:3857\',
|
||||
url: \'' . $file->getPublicUrl() . '\',
|
||||
format: new ol.format.GPX()
|
||||
}),
|
||||
style: ' . $jsElementVar . '_style
|
||||
});' . "\n";
|
||||
|
||||
$jsMarker .= "overlaygroup.getLayers().push(" . $jsElementVar . "_gpx);";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'tx_odsosm_vector':
|
||||
$fileObjects = $fileRepository->findByRelation('tx_odsosm_vector', 'file', $item['uid']);
|
||||
|
||||
// define style from given color and width
|
||||
$jsMarker .= 'var ' . $jsElementVar . '_style = new ol.style.Style({
|
||||
stroke: new ol.style.Stroke({
|
||||
color: \''.$item['color'].'\',
|
||||
width: '.($item['width'] ?: 1).'
|
||||
}),
|
||||
fill: new ol.style.Fill({
|
||||
color: \''.$item['rgba'].'\'
|
||||
}),
|
||||
});' . "\n";
|
||||
|
||||
if ($fileObjects) {
|
||||
$file = $fileObjects[0];
|
||||
$filename = $file->getPublicUrl();
|
||||
|
||||
$properties = [
|
||||
'popup' => $item['popup'] ?? '',
|
||||
'properties' => $item['properties'],
|
||||
];
|
||||
|
||||
$jsMarker .= 'var ' . $jsElementVar . '_file_properties = ' . json_encode($properties) . ';';
|
||||
$jsMarker .= 'var ' . $jsElementVar . '_file = new ol.layer.Vector({
|
||||
title: \'' .$item['title'] . ' ('. LocalizationUtility::translate('file', 'OdsOsm') .')\',
|
||||
source: new ol.source.Vector({
|
||||
projection: \'EPSG:3857\',
|
||||
url: \'' . $filename . '\',
|
||||
format: new ol.format.GeoJSON()
|
||||
}),
|
||||
style: ' . $jsElementVar . '_style,
|
||||
properties: ' . $jsElementVar . '_file_properties,
|
||||
});' . "\n";
|
||||
|
||||
$jsMarker .= $jsElementVar . "_file.getSource().setProperties(" . $jsElementVar . "_file_properties);";
|
||||
$jsMarker .= "overlaygroup.getLayers().push(" . $jsElementVar . "_file);";
|
||||
}
|
||||
|
||||
// add geojson from data field as well
|
||||
if ($item['data']) {
|
||||
$properties = [
|
||||
'popup' => $item['popup'] ? $item['popup'] . '<br />' : '',
|
||||
'properties' => $item['properties'],
|
||||
];
|
||||
|
||||
$jsMarker .= 'const ' . $jsElementVar . '_geojsonObject = '. $item['data'] . ';';
|
||||
|
||||
$jsMarker .= 'var ' . $jsElementVar . '_data_properties = ' . json_encode($properties) . ';';
|
||||
$jsMarker .= 'var ' . $jsElementVar . '_data = new ol.layer.Vector({
|
||||
title: \'' .$item['title'] . '\',
|
||||
source: new ol.source.Vector({
|
||||
features: new ol.format.GeoJSON({
|
||||
featureProjection:"EPSG:3857"
|
||||
}).readFeatures(' . $jsElementVar . '_geojsonObject)
|
||||
}),
|
||||
style: ' . $jsElementVar . '_style
|
||||
});';
|
||||
|
||||
$jsMarker .= $jsElementVar . "_data.setProperties(" . $jsElementVar . "_data_properties);";
|
||||
$jsMarker .= "overlaygroup.getLayers().push(" . $jsElementVar . "_data);";
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
$markerOptions = [];
|
||||
if ($item['tx_odsosm_marker'] ?? false) {
|
||||
$marker = $item['tx_odsosm_marker'];
|
||||
if ($marker['type'] == 'html') {
|
||||
$markerOptions['icon'] = 'icon: new L.divIcon(' . json_encode($marker['icon']) . ')';
|
||||
} else {
|
||||
$icon = $marker['icon']->getPublicUrl();
|
||||
$markerOptions['icon'] = 'icon: new L.Icon(' . json_encode($icon) . ')';
|
||||
}
|
||||
} else {
|
||||
$icon = '/typo3conf/ext/ods_osm/Resources/Public/Icons/marker-icon.png';
|
||||
$marker['size_x'] = 25;
|
||||
$marker['size_y'] = 41;
|
||||
}
|
||||
|
||||
$markerStyle = "const " . $jsElementVar . "_style = new ol.style.Style({
|
||||
image: new ol.style.Icon({
|
||||
anchor: [0.5, 46],
|
||||
anchorXUnits: 'fraction',
|
||||
anchorYUnits: 'pixels',
|
||||
src: '" . $icon ."',
|
||||
width: " . (int)$marker['size_x'] . ",
|
||||
height: " . (int)$marker['size_y'] . "
|
||||
}),
|
||||
});";
|
||||
|
||||
// It's a group of markers
|
||||
if ($item['group_title'] ?? false) {
|
||||
if (empty($jsMarkerGroup)) {
|
||||
$jsMarker .= $markerStyle;
|
||||
|
||||
$group_title = ($marker['type'] == 'html' ? $icon : "<img class='marker-icon' src='" . $icon . "' />") . ' ' . $item['group_title'];
|
||||
$jsMarkerGroup = "
|
||||
var " . $item['group_uid'] . " = new ol.layer.Vector({
|
||||
title: \"" . $group_title . "\",
|
||||
source: new ol.source.Vector({
|
||||
features: []
|
||||
}),
|
||||
style: " . $jsElementVar . "_style
|
||||
});";
|
||||
|
||||
$this->layers[2][$item['group_uid']]['layer'] = $jsMarkerGroup;
|
||||
}
|
||||
|
||||
$popupJsCode = "
|
||||
function (layer) {
|
||||
var osm_popup = '" . ($item['popup'] ?? '') . "';
|
||||
|
||||
var feature = layer.feature,
|
||||
props = feature.properties,
|
||||
ll = Object.keys(props),
|
||||
attribute, value = '';
|
||||
|
||||
for (attribute in props) {
|
||||
value += '<strong>' + attribute + '</strong>: ' + props[attribute] + '<br />';
|
||||
}
|
||||
return osm_popup + value;
|
||||
}
|
||||
";
|
||||
|
||||
$jsMarkerFeature = "
|
||||
new ol.Feature({
|
||||
geometry: new ol.geom.Point(ol.proj.fromLonLat([" . $item['longitude'] . ", " . $item['latitude'] . "])),
|
||||
type: 'Point',
|
||||
desc: " . json_encode($item['popup']) . ",
|
||||
style: " . $jsElementVar . "_style
|
||||
});";
|
||||
|
||||
$this->layers[2][$item['group_uid']]['jsMarkerFeatures'][] = $jsMarkerFeature;
|
||||
} else {
|
||||
$jsMarker .= $markerStyle;
|
||||
$jsMarker .= "var " . $jsElementVar . " = new ol.layer.Vector({
|
||||
title: '<img src=\"" .$icon . "\" class=\"marker-icon\" /> " . ($item['group_title'] ?? $item['name']) . "',
|
||||
source: new ol.source.Vector({
|
||||
features: [
|
||||
new ol.Feature({
|
||||
geometry: new ol.geom.Point(ol.proj.fromLonLat([" . $item['longitude'] . ", " . $item['latitude'] . "])),
|
||||
type: 'Point',
|
||||
desc: " . json_encode($item['popup']) . "
|
||||
})
|
||||
]
|
||||
}),
|
||||
style: " . $jsElementVar . "_style
|
||||
});";
|
||||
|
||||
$jsMarker .= 'overlaygroup.getLayers().push(' . $jsElementVar . ');' . "\n";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return $jsMarker;
|
||||
}
|
||||
}
|
||||
108
typo3conf/ext/ods_osm/Classes/Provider/Staticmap.php
Normal file
108
typo3conf/ext/ods_osm/Classes/Provider/Staticmap.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace Bobosch\OdsOsm\Provider;
|
||||
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
|
||||
class Staticmap extends BaseProvider
|
||||
{
|
||||
protected $uploadPath = 'fileadmin/tx_odsosm/staticmap';
|
||||
|
||||
public function getMap($layers, $markers, $lon, $lat, $zoom)
|
||||
{
|
||||
$marker = [];
|
||||
|
||||
foreach ($markers as $table => $items) {
|
||||
foreach ($items as $item) {
|
||||
switch ($table) {
|
||||
case 'tx_odsosm_track':
|
||||
case 'tx_odsosm_vector':
|
||||
break;
|
||||
default:
|
||||
$lon = $item['longitude'];
|
||||
$lat = $item['latitude'];
|
||||
if ($item['tx_odsosm_marker'] ?? false) {
|
||||
$marker = $item['tx_odsosm_marker'];
|
||||
$icon = $marker['icon'];
|
||||
} else {
|
||||
$marker = ['size_x' => 21, 'size_y' => 25, 'offset_x' => -11, 'offset_y' => -25];
|
||||
$icon = 'EXT:ods_osm/Resources/Public/Icons/marker-icon.png';
|
||||
}
|
||||
break 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set reasonable defaults for width and height (100% and vh/vw does not work with staticmap)
|
||||
if ((int)$this->config['width'] <= 100) {
|
||||
$this->config['width'] = 640;
|
||||
}
|
||||
if ((int)$this->config['height'] <= 100) {
|
||||
$this->config['height'] = 480;
|
||||
}
|
||||
|
||||
|
||||
$markerUrl = [
|
||||
'###lon###' => $lon,
|
||||
'###lat###' => $lat,
|
||||
'###zoom###' => $zoom,
|
||||
'###width###' => (int)$this->config['width'],
|
||||
'###height###' => (int)$this->config['height'],
|
||||
];
|
||||
|
||||
$layer = array_shift($layers);
|
||||
$url = strtr($layer[0]['static_url'], $markerUrl);
|
||||
|
||||
$this->uploadPath = Environment::getPublicPath() . '/' . $this->uploadPath;
|
||||
if (!is_dir($this->uploadPath)) {
|
||||
GeneralUtility::mkdir_deep($this->uploadPath);
|
||||
}
|
||||
|
||||
$filename = $this->uploadPath . '/' . md5($url) . '.png';
|
||||
|
||||
// Cache image
|
||||
$cache = false;
|
||||
if (file_exists($filename)) {
|
||||
$cache = filectime($filename) > time() - 7 * 24 * 60 * 60;
|
||||
}
|
||||
if (!$cache) {
|
||||
$referer = $_SERVER['HTTP_REFERER'];
|
||||
$opts = [
|
||||
'http'=>[
|
||||
'header'=>["Referer: $referer\r\n"]
|
||||
]
|
||||
];
|
||||
$context = stream_context_create($opts);
|
||||
$image = file_get_contents($url, false, $context);
|
||||
if ($image) {
|
||||
file_put_contents($filename, $image);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate image tag
|
||||
$config = [
|
||||
'file' => 'GIFBUILDER',
|
||||
'file.' => [
|
||||
'format' => 'png',
|
||||
'XY' => '[10.w],[10.h]',
|
||||
'10' => 'IMAGE',
|
||||
'10.' => [
|
||||
'file' => $filename,
|
||||
]
|
||||
],
|
||||
];
|
||||
|
||||
if ($marker['offset_x'] ?? null) {
|
||||
$config['file.']['20'] = 'IMAGE';
|
||||
$config['file.']['20.'] = [
|
||||
'offset' => ((int)$this->config['width'] / 2 + (int)$marker['offset_x']) . ',' . ((int)$this->config['height'] / 2 + (int)$marker['offset_y']),
|
||||
'file' => $icon,
|
||||
];
|
||||
}
|
||||
|
||||
$content = $this->cObj->cObjGetSingle('IMAGE', $config);
|
||||
|
||||
return ($content);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user