// ==UserScript==
// @name WME Permalink to several Maps DACH
// @description WME PTSM für Deutschland Österreich Schweiz
// @namespace https://greasyfork.org/de/users/863740-horst-wittlich
// @version 2025.06.07
// @match https://*.waze.com/editor*
// @match https://*.waze.com/*/editor*
// @match https://beta.waze.com/editor*
// @match https://beta.waze.com/*/editor*
// @icon https://i.ibb.co/ckSvk59/waze-icon.png
// @grant none
// @license MIT
// ==/UserScript==
/* global OpenLayers, W, proj4 */
var ptsmVersion = '2025.06.07';
var ptsmInitialized = false;
var ptsmUpdateKey = 'wme-ptsm-update-shown-' + ptsmVersion;
function showUpdatePopup() {
try {
// Prüfen ob Update-Info bereits angezeigt wurde
if (localStorage.getItem(ptsmUpdateKey) === 'true') {
return;
}
} catch (e) {
// Falls localStorage nicht verfügbar, trotzdem anzeigen
}
// Popup erstellen
var overlay = document.createElement('div');
overlay.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 999999;
display: flex;
align-items: center;
justify-content: center;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
`;
var popup = document.createElement('div');
popup.style.cssText = `
background: white;
border-radius: 12px;
padding: 24px;
max-width: 400px;
margin: 20px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
text-align: center;
position: relative;
`;
popup.innerHTML = `
<div style="font-size: 24px; margin-bottom: 16px;">🎉 PTSM DACH Update! 🗺️</div>
<div style="font-size: 18px; font-weight: bold; color: #007bff; margin-bottom: 16px;">
Version ${ptsmVersion}
</div>
<div style="text-align: left; margin-bottom: 20px; line-height: 1.6;">
<div style="font-size: 16px; font-weight: bold; margin-bottom: 12px; color: #333;">
✨ Was ist neu:
</div>
<div style="margin-bottom: 8px;">
🔧 <strong>ADAC Zoom level ist nun feiner. Es werden mehr abstufungen vom WME berücksichtigt</strong> - Präzise Zoom-Übertragung
</div>
</div>
<button id="ptsm-close-popup" style="
background: linear-gradient(135deg, #007bff 0%, #0056b3 100%);
color: white;
border: none;
border-radius: 8px;
padding: 12px 24px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
">
🚀 Los geht's!
</button>
`;
overlay.appendChild(popup);
document.body.appendChild(overlay);
// Close button event
var closeBtn = popup.querySelector('#ptsm-close-popup');
closeBtn.addEventListener('click', function() {
overlay.remove();
try {
localStorage.setItem(ptsmUpdateKey, 'true');
} catch (e) {
// localStorage not available
}
});
closeBtn.addEventListener('mouseover', function() {
this.style.transform = 'translateY(-2px)';
this.style.boxShadow = '0 4px 12px rgba(0, 123, 255, 0.3)';
});
closeBtn.addEventListener('mouseout', function() {
this.style.transform = 'translateY(0)';
this.style.boxShadow = 'none';
});
// Schließen bei Klick auf Overlay
overlay.addEventListener('click', function(e) {
if (e.target === overlay) {
overlay.remove();
try {
localStorage.setItem(ptsmUpdateKey, 'true');
} catch (e) {
// localStorage not available
}
}
});
}
function getCenterZoom() {
var map = W.map.getOLMap();
var zoom = map.getZoom();
var center = map.getCenter().transform(new OpenLayers.Projection('EPSG:900913'), new OpenLayers.Projection('EPSG:4326'));
center.zoom = zoom;
return center;
}
function saveDropdownStates() {
const states = {};
document.querySelectorAll('.ptsm-category').forEach(category => {
const className = category.className.match(/ptsm-category-(\w+)/);
if (className) {
states[className[1]] = category.classList.contains('open');
}
});
try {
localStorage.setItem('wme-ptsm-dropdown-states', JSON.stringify(states));
} catch (e) {
console.log('PTSM: localStorage not available');
}
}
function loadDropdownStates() {
try {
const saved = localStorage.getItem('wme-ptsm-dropdown-states');
return saved ? JSON.parse(saved) : {};
} catch (e) {
return {};
}
}
function saveCompactMode(isCompact) {
try {
localStorage.setItem('wme-ptsm-compact-mode', isCompact ? 'true' : 'false');
} catch (e) {
console.log('PTSM: localStorage not available');
}
}
function loadCompactMode() {
try {
const saved = localStorage.getItem('wme-ptsm-compact-mode');
return saved === 'true';
} catch (e) {
return false;
}
}
function createCategory(title, className, defaultOpen = false) {
const savedStates = loadDropdownStates();
const categoryKey = className.replace('ptsm-category-', '');
const isOpen = savedStates.hasOwnProperty(categoryKey) ? savedStates[categoryKey] : defaultOpen;
var category = document.createElement('div');
category.className = 'ptsm-category ' + className + (isOpen ? ' open' : '');
var header = document.createElement('button');
header.className = 'ptsm-category-header';
header.innerHTML = title + '<div class="ptsm-dropdown-arrow"></div>';
var content = document.createElement('div');
content.className = 'ptsm-category-content';
header.addEventListener('click', function() {
category.classList.toggle('open');
setTimeout(saveDropdownStates, 100);
});
category.appendChild(header);
category.appendChild(content);
return { category, content };
}
function createMapButton(text, className, clickHandler) {
var btn = document.createElement('button');
btn.textContent = text;
btn.className = 'ptsm-map-btn ' + className;
btn.addEventListener('click', clickHandler);
return btn;
}
function createCompactButton() {
var btn = document.createElement('button');
btn.className = 'ptsm-compact-btn';
btn.innerHTML = '🔧 Kompakt-Modus';
const isCompact = loadCompactMode();
if (isCompact) {
btn.innerHTML = '🔧 Normal-Modus';
btn.classList.add('active');
}
btn.addEventListener('click', function() {
const container = document.querySelector('.ptsm-container');
const isCurrentlyCompact = container.classList.contains('compact');
if (isCurrentlyCompact) {
container.classList.remove('compact');
btn.innerHTML = '🔧 Kompakt-Modus';
btn.classList.remove('active');
saveCompactMode(false);
} else {
container.classList.add('compact');
btn.innerHTML = '🔧 Normal-Modus';
btn.classList.add('active');
saveCompactMode(true);
}
});
return btn;
}
function addButtons() {
if (ptsmInitialized) {
return;
}
if (!document.getElementById('user-info')) {
setTimeout(addButtons, 500);
return;
}
if (!W.loginManager.user) {
if (!ptsmInitialized) {
W.loginManager.events.register('login', null, function() {
if (!ptsmInitialized) addButtons();
});
W.loginManager.events.register('loginStatus', null, function() {
if (!ptsmInitialized) addButtons();
});
}
if (!W.loginManager.user) {
return;
}
}
ptsmInitialized = true;
if (typeof proj4 === "undefined") {
var script = document.createElement('script');
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.4.4/proj4.js';
document.head.appendChild(script);
}
// Add CSS
var style = document.createElement('style');
style.textContent = `
.ptsm-container {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
padding: 8px;
background: #fff;
font-size: 12px;
}
.ptsm-category {
margin-bottom: 8px;
border-radius: 6px;
overflow: hidden;
background: #fff;
box-shadow: 0 1px 4px rgba(0,0,0,0.08);
border: 1px solid #e1e5e9;
}
.ptsm-category-header {
width: 100%;
padding: 8px 12px;
background: linear-gradient(135deg, #6c757d 0%, #495057 100%);
color: white;
border: none;
cursor: pointer;
font-weight: 600;
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.5px;
display: flex;
justify-content: space-between;
align-items: center;
transition: all 0.2s ease;
}
.ptsm-category-header:hover {
background: linear-gradient(135deg, #5a6268 0%, #343a40 100%);
}
.ptsm-dropdown-arrow {
width: 0;
height: 0;
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 6px solid white;
transition: transform 0.2s ease;
}
.ptsm-category.open .ptsm-dropdown-arrow {
transform: rotate(180deg);
}
.ptsm-category-content {
max-height: 0;
overflow: hidden;
padding: 0 8px;
transition: max-height 0.3s ease, padding 0.2s ease;
}
.ptsm-category.open .ptsm-category-content {
max-height: 500px;
padding: 8px;
}
.ptsm-map-btn {
width: calc(33.333% - 4px);
height: 28px;
margin: 2px;
padding: 4px 6px 4px 24px;
background: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 4px;
font-size: 10px;
font-weight: 500;
color: #495057;
cursor: pointer;
position: relative;
display: inline-flex;
align-items: center;
justify-content: flex-start;
transition: all 0.15s ease;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.ptsm-map-btn::before {
content: '';
position: absolute;
left: 4px;
top: 50%;
transform: translateY(-50%);
width: 12px;
height: 12px;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
flex-shrink: 0;
}
.ptsm-map-btn:hover {
transform: translateY(-1px);
background: linear-gradient(145deg, #ffffff 0%, #f1f3f4 100%);
border-color: #007bff;
color: #0056b3;
box-shadow: 0 2px 8px rgba(0, 123, 255, 0.12);
}
.ptsm-compact-btn {
width: calc(100% - 4px);
height: 32px;
margin: 2px;
padding: 8px 12px;
background: linear-gradient(135deg, #28a745 0%, #1e7e34 100%);
border: none;
border-radius: 4px;
font-size: 11px;
font-weight: 600;
color: white;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.15s ease;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.ptsm-compact-btn:hover {
transform: translateY(-1px);
background: linear-gradient(135deg, #1e7e34 0%, #155724 100%);
box-shadow: 0 2px 8px rgba(40, 167, 69, 0.25);
}
.ptsm-compact-btn.active {
background: linear-gradient(135deg, #dc3545 0%, #c82333 100%);
}
.ptsm-compact-btn.active:hover {
background: linear-gradient(135deg, #c82333 0%, #a02834 100%);
box-shadow: 0 2px 8px rgba(220, 53, 69, 0.25);
}
/* Kompakt-Modus Styles */
.ptsm-container.compact .ptsm-category {
margin-bottom: 4px;
}
.ptsm-container.compact .ptsm-category-header {
padding: 6px 10px;
font-size: 10px;
}
.ptsm-container.compact .ptsm-category.open .ptsm-category-content {
padding: 4px;
}
.ptsm-container.compact .ptsm-map-btn {
width: calc(33.333% - 3px);
height: 24px;
margin: 1.5px;
padding: 3px 5px 3px 20px;
font-size: 9px;
}
.ptsm-container.compact .ptsm-map-btn::before {
width: 10px;
height: 10px;
left: 3px;
}
.ptsm-container.compact .ptsm-compact-btn {
height: 28px;
font-size: 10px;
padding: 6px 10px;
}
/* Category colors */
.ptsm-category-allgem .ptsm-category-header { background: linear-gradient(135deg, #007bff 0%, #0056b3 100%); }
.ptsm-category-allgem .ptsm-category-header:hover { background: linear-gradient(135deg, #0056b3 0%, #004085 100%); }
.ptsm-category-baustell .ptsm-category-header { background: linear-gradient(135deg, #28a745 0%, #1e7e34 100%); }
.ptsm-category-baustell .ptsm-category-header:hover { background: linear-gradient(135deg, #1e7e34 0%, #155724 100%); }
.ptsm-category-blitzer .ptsm-category-header { background: linear-gradient(135deg, #dc3545 0%, #c82333 100%); }
.ptsm-category-blitzer .ptsm-category-header:hover { background: linear-gradient(135deg, #c82333 0%, #a02834 100%); }
.ptsm-category-bilder .ptsm-category-header { background: linear-gradient(135deg, #17a2b8 0%, #138496 100%); }
.ptsm-category-bilder .ptsm-category-header:hover { background: linear-gradient(135deg, #138496 0%, #0f6674 100%); }
.ptsm-category-geoportal .ptsm-category-header { background: linear-gradient(135deg, #6f42c1 0%, #59359a 100%); }
.ptsm-category-geoportal .ptsm-category-header:hover { background: linear-gradient(135deg, #59359a 0%, #4c2c85 100%); }
.ptsm-category-misc .ptsm-category-header { background: linear-gradient(135deg, #fd7e14 0%, #e65100 100%); }
.ptsm-category-misc .ptsm-category-header:hover { background: linear-gradient(135deg, #e65100 0%, #bf360c 100%); }
/* Icons */
.ptsm-google::before { background-image: url(https://i.ibb.co/d0zx6Pdt/google-maps.png); }
.ptsm-f4map::before { background-image: url(https://i.ibb.co/5WxjKkLp/F-Logo.png); }
.ptsm-apple::before { background-image: url(https://i.ibb.co/WsH15zC/Apple-Jetzt.png); }
.ptsm-bing::before { background-image: url(https://i.ibb.co/0LF74p6/bing.png); }
.ptsm-nrw::before { background-image: url(https://i.ibb.co/37q7H37/nrw.png); }
.ptsm-osm::before { background-image: url(https://i.ibb.co/20wtGrsL/osm.png); }
.ptsm-autobahn::before { background-image: url(https://i.ibb.co/2Y3pT8v2/Autobahn-Logo.png); }
.ptsm-poi-karte::before { background-image: url(https://i.ibb.co/nMRSSKKp/POI-Karte.jpg); }
.ptsm-poi-base::before { background-image: url(https://i.ibb.co/xS7vJQr8/POI-Base.jpg); }
.ptsm-viamichelin::before { background-image: url(https://i.ibb.co/RTzJP87C/viamichelin.png); }
.ptsm-here::before { background-image: url(https://i.ibb.co/MC9JF7T/h-logo.png); }
.ptsm-mapillary::before { background-image: url(https://i.ibb.co/JWkZnh0X/mapillary.png); }
.ptsm-osbrowser::before { background-image: url(https://i.ibb.co/RdQSgsY/osb.png); }
.ptsm-mappy::before { background-image: url(https://i.ibb.co/wrhH7H95/mappy.png); }
.ptsm-blitzer::before { background-image: url(https://i.ibb.co/gVKMwKS/blitzer.png); }
.ptsm-bayernatlas::before { background-image: url(https://i.ibb.co/KxnBpv7J/bayernatlas.png); }
.ptsm-tomtom::before { background-image: url(https://i.ibb.co/hDq5bys/tomtom-icon2.png); }
.ptsm-basemap-de::before { background-image: url(https://i.ibb.co/V3jJJrb/de-map.png); }
.ptsm-reporting::before { background-image: url(https://i.ibb.co/rZb76j2/pin.png); }
.ptsm-kartaview::before { background-image: url(https://i.ibb.co/xgnTMFf/kartaview.png); }
.ptsm-bayerninfo::before { background-image: url(https://i.ibb.co/R0K3SSs/bayerninfo.png); }
.ptsm-timonline::before { background-image: url(https://i.ibb.co/bPJ4qRy/das-da2.png); }
.ptsm-geoadmin::before { background-image: url(https://i.ibb.co/Np5chv4/CH-Icon-20.png); }
.ptsm-basemap-at::before { background-image: url(https://i.ibb.co/MCKhDSH/AT-Icon.png); }
.ptsm-adac::before { background-image: url(https://i.ibb.co/6YsGCFy/adac.png); }
.ptsm-here-edit::before { background-image: url(https://i.ibb.co/VghMgy8/here.png); }
.ptsm-umsehen::before { background-image: url(https://i.ibb.co/XYqjkYX/umsehen-icon.png); }
.ptsm-hackintosh::before { background-image: url(https://i.ibb.co/8xP5RyC/Hackintosh.png); }
.ptsm-archive::before { background-image: url(https://i.ibb.co/QHpvd85/Das-Logo.png); }
.ptsm-state-info {
font-size: 9px;
color: #6c757d;
font-style: italic;
text-align: center;
margin-top: 6px;
margin-bottom: 4px;
}
.ptsm-warning {
background: #fff8e1;
border: 1px solid #ffcc02;
border-radius: 4px;
padding: 8px;
margin-top: 8px;
margin-bottom: 8px;
display: flex;
align-items: flex-start;
}
.ptsm-warning .w-icon {
font-size: 14px;
color: #f57c00;
margin-right: 6px;
flex-shrink: 0;
}
.ptsm-warning-text {
font-size: 9px;
color: #e65100;
line-height: 1.3;
}
@media (max-width: 768px) {
.ptsm-map-btn { width: calc(50% - 4px); }
}
@media (max-width: 480px) {
.ptsm-map-btn { width: calc(100% - 4px); }
}
`;
document.head.appendChild(style);
// Create all map buttons
var btn1 = createMapButton('Google', 'ptsm-google', () => {
var cz = getCenterZoom();
// Bessere Google Maps Zoom-Level Umrechnung
var googleZoom;
if (cz.zoom >= 20) googleZoom = 19; // Sehr nah
else if (cz.zoom >= 18) googleZoom = 17; // Nah
else if (cz.zoom >= 16) googleZoom = 15; // Mittel-nah
else if (cz.zoom >= 14) googleZoom = 13; // Mittel
else if (cz.zoom >= 12) googleZoom = 11; // Mittel-weit
else if (cz.zoom >= 10) googleZoom = 9; // Weit
else googleZoom = Math.max(1, cz.zoom - 2); // Sehr weit
window.open('https://www.google.com/maps/@' + cz.lat + ',' + cz.lon + ',' + googleZoom + 'z/data=!5m1!1e1', '_blank');
});
var btn2 = createMapButton('Bing', 'ptsm-bing', () => {
var cz = getCenterZoom();
cz.zoom -= 1;
window.open('https://www.bing.com/maps/traffic?cp=' + cz.lat + '~' + cz.lon + '&lvl=' + cz.zoom, '_blank');
});
var btn3 = createMapButton('Ver. NRW', 'ptsm-nrw', () => {
var cz = getCenterZoom();
window.open('https://www.verkehr.nrw/?center=' + cz.lat + ',' + cz.lon + '&zoom=' + cz.zoom + '&layer=Verkehrslage,Baustellen,Haltestellen,Parken,Webcams,Verkehrsmeldungen,ELadesaeulen,Tankstellen&highlightRoute=false', '_blank');
});
var btn3a = createMapButton('OSM', 'ptsm-osm', () => {
var cz = getCenterZoom();
window.open('https://www.openstreetmap.org/#map=' + cz.zoom + '/' + cz.lat + '/' + cz.lon, '_blank');
});
var btn4 = createMapButton('F4 3D Map', 'ptsm-f4map', () => {
var cz = getCenterZoom();
window.open('https://demo.f4map.com/#lat=' + cz.lat + '&lon=' + cz.lon + '&zoom=' + cz.zoom, '_blank');
});
var btn5 = createMapButton('Apple', 'ptsm-apple', () => {
var cz = getCenterZoom();
window.open('https://maps.apple.com/look-around?coordinate=' + cz.lat + '%2C' + cz.lon, '_blank');
});
var btn6 = createMapButton('Autobahn', 'ptsm-autobahn', () => {
var cz = getCenterZoom();
window.open('https://verkehr.vz-deutschland.de/?layer=raststellen,baustellen,stau,verkehrsmeldungen&zoom=' + cz.zoom + '&lat=' + cz.lat + '&lon=' + cz.lon, '_blank');
});
var btn7 = createMapButton('POI Karte', 'ptsm-poi-karte', () => {
var cz = getCenterZoom();
// Bessere Zoom-Level-Übertragung: Je höher das Waze-Zoom, desto kleiner der Radius
var radius;
if (cz.zoom >= 18) radius = 500; // Sehr nah - 500m Radius
else if (cz.zoom >= 16) radius = 1000; // Nah - 1km Radius
else if (cz.zoom >= 14) radius = 2500; // Mittel - 2.5km Radius
else if (cz.zoom >= 12) radius = 5000; // Weit - 5km Radius
else if (cz.zoom >= 10) radius = 10000; // Sehr weit - 10km Radius
else radius = 25000; // Maximum - 25km Radius
window.open('https://www.flosm.org/de/POI-Karte.html?lat=' + cz.lat + '&lon=' + cz.lon + '&r=' + radius + '&st=0&sw=speedcamera', '_blank');
});
var btn8 = createMapButton('POI Base', 'ptsm-poi-base', () => {
var cz = getCenterZoom();
window.open('https://www.poibase.com/de/karte/#/map/coords-' + cz.lon + ',' + cz.lat + '/zoom-' + cz.zoom, '_blank');
});
var btn9 = createMapButton('ViaM', 'ptsm-viamichelin', () => {
var cz = getCenterZoom();
// ViaMichelin moderne URL-Struktur mit bounds und center
// Zoom-abhängige Bounds-Berechnung für bessere Darstellung
var zoomFactor;
if (cz.zoom >= 18) zoomFactor = 0.001; // Sehr nah
else if (cz.zoom >= 16) zoomFactor = 0.002; // Nah
else if (cz.zoom >= 14) zoomFactor = 0.005; // Mittel-nah
else if (cz.zoom >= 12) zoomFactor = 0.01; // Mittel
else if (cz.zoom >= 10) zoomFactor = 0.02; // Mittel-weit
else if (cz.zoom >= 8) zoomFactor = 0.05; // Weit
else zoomFactor = 0.1; // Sehr weit
// Bounds berechnen (Rechteck um den Mittelpunkt)
var latMin = (cz.lat - zoomFactor).toFixed(6);
var latMax = (cz.lat + zoomFactor).toFixed(6);
var lonMin = (cz.lon - zoomFactor).toFixed(6);
var lonMax = (cz.lon + zoomFactor).toFixed(6);
var viaMichelinUrl = 'https://www.viamichelin.de/karten-stadtplan/verkehr?bounds=' +
lonMin + '%7E' + latMin + '%7E' + lonMax + '%7E' + latMax +
'¢er=' + cz.lon.toFixed(6) + '%7E' + cz.lat.toFixed(6) +
'&page=1&poiCategories=0&showPolandModal=false';
window.open(viaMichelinUrl, '_blank');
});
var btn10 = createMapButton('Here', 'ptsm-here', () => {
var cz = getCenterZoom();
window.open('https://wego.here.com/?map=' + cz.lat + ',' + cz.lon + ',' + cz.zoom + ',normal', '_blank');
});
var btn11 = createMapButton('Mapillary', 'ptsm-mapillary', () => {
var cz = getCenterZoom();
cz.zoom -= 1;
window.open('https://www.mapillary.com/app/?lat=' + cz.lat + '&lng=' + cz.lon + '&z=' + cz.zoom, '_blank');
});
var btn12 = createMapButton('OSBrowser', 'ptsm-osbrowser', () => {
var cz = getCenterZoom();
window.open('https://www.openstreetbrowser.org/#map=' + cz.zoom + '/' + cz.lat + '/' + cz.lon + '&categories=car_maxspeed', '_blank');
});
var btn13 = createMapButton('Mappy', 'ptsm-mappy', () => {
var cz = getCenterZoom();
window.open('https://en.mappy.com/plan#/' + cz.lat + ',' + cz.lon, '_blank');
});
var btn14 = createMapButton('Blitzer.de', 'ptsm-blitzer', () => {
var cz = getCenterZoom();
window.open('https://map.atudo.com/v5/?lat=' + cz.lat + '&lng=' + cz.lon + '&zoom=' + cz.zoom, '_blank');
});
var btn16 = createMapButton('BY Atlas', 'ptsm-bayernatlas', () => {
var cz = getCenterZoom();
cz.zoom -= 5;
if (typeof proj4 === "undefined") {
alert('proj4 library not loaded');
return;
}
var firstProj = '+proj=utm +zone=32 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs';
var utm = proj4(firstProj, [cz.lon, cz.lat]);
window.open('https://geoportal.bayern.de/bayernatlas/index.html?zoom=' + cz.zoom + '&E=' + utm[0] + '&N=' + utm[1], '_blank');
});
var btn18 = createMapButton('TomTom', 'ptsm-tomtom', () => {
var cz = getCenterZoom();
cz.zoom -= 1;
window.open('https://plan.tomtom.com/de?p=' + cz.lat + ',' + cz.lon + ',' + cz.zoom + 'z', '_blank');
});
var btn19 = createMapButton('Basemap.de', 'ptsm-basemap-de', () => {
var cz = getCenterZoom();
cz.zoom = 0.985 * cz.zoom - 1.05;
window.open('https://basemap.de/viewer?config=' + btoa('{"lat":' + cz.lat + ',"lon":' + cz.lon + ',"zoom":' + cz.zoom + ',"styleID":0,"pitch":0,"bearing":0,"saturation":0,"brightness":0,"hiddenControls":[],"hiddenLayers":[],"changedLayers":[],"hiddenSubGroups":[],"changedSubGroups":[],"externalStyleURL":""}'), '_blank');
});
var btn20 = createMapButton('Reporting', 'ptsm-reporting', () => {
var cz = getCenterZoom();
cz.zoom -= 1;
window.open('https://www.waze.com/partnerhub/map-tool?lat=' + cz.lat + '&lon=' + cz.lon + '&zoom=' + cz.zoom, '_blank');
});
var btn21 = createMapButton('KartaView', 'ptsm-kartaview', () => {
var cz = getCenterZoom();
cz.zoom -= 1;
window.open('https://kartaview.org/map/@' + cz.lat + ',' + cz.lon + ',' + cz.zoom + 'z', '_blank');
});
var btn22 = createMapButton('Bayerninfo', 'ptsm-bayerninfo', () => {
var cz = getCenterZoom();
cz.zoom -= 2;
var now = new Date();
var then = new Date();
then.setDate(then.getDate() + 60);
var mapsUrl = 'https://www.bayerninfo.de/de/baustellenkalender?geo=' + cz.lat + ',' + cz.lon + '&zoom=' + cz.zoom;
mapsUrl += '&datetimeFrom=' + now.toISOString() + '&datetimeTo=' + then.toISOString();
window.open(mapsUrl, '_blank');
});
var btn30 = createMapButton('TimOnline', 'ptsm-timonline', () => {
var cz = getCenterZoom();
cz.zoom = 454959671.96858*Math.exp(-0.693*cz.zoom);
window.open('https://www.tim-online.nrw.de/tim-online2/?center=' + cz.lat + ',' + cz.lon + '&scale=' + cz.zoom, '_blank');
});
var btn31 = createMapButton('GeoAdmin', 'ptsm-geoadmin', () => {
var cz = getCenterZoom();
cz.zoom -= 7.2;
var phi1 = ((cz.lat * 3600) - 169028.66) / 10000;
var lmd1 = ((cz.lon * 3600) - 26782.5) / 10000;
var x = 200147.07 + 308807.95 * phi1 + 3745.25 * lmd1 * lmd1 + 76.63 * phi1 * phi1 + 119.79 * phi1 * phi1 * phi1 - 194.56 * lmd1 * lmd1 * phi1;
var y = 600072.37 + 211455.93 * lmd1 - 10938.51 * lmd1 * phi1 - 0.36 * lmd1 * phi1 * phi1 - 44.54 * lmd1 * lmd1 * lmd1;
window.open('https://map.geo.admin.ch/?Y=' + y.toFixed(0) + '&X=' + x.toFixed(0) + '&zoom=' + cz.zoom + '&topic=ech&lang=de&bgLayer=ch.swisstopo.pixelkarte-farbe&layers=ch.bfs.gebaeude_wohnungs_register,ch.kantone.cadastralwebmap-farbe,ch.swisstopo.swissimage-product,ch.bfe.ladestellen-elektromobilitaet&catalogNodes=457,532,687,458,477,485,491,510,527,1743&layers_visibility=false,false,true,true&layers_timestamp=,,current', '_blank');
});
var btn32 = createMapButton('Basemap', 'ptsm-basemap-at', () => {
var cz = getCenterZoom();
var x = cz.lon / 180 * 20037508.34;
var y = Math.log(Math.tan((90 + cz.lat * 1) * Math.PI / 360)) / Math.PI;
y *= 20037508.34;
window.open('https://basemap.at/bmapp/index.html#{"center":[' + x.toFixed(10) + ',' + y.toFixed(10) + '],"zoom":' + cz.zoom + ',"rotation":0,"layers":"1000000000"}', '_blank');
});
var btn34 = createMapButton('ADAC', 'ptsm-adac', () => {
var cz = getCenterZoom();
// ADAC Maps präzise Bounds-Berechnung basierend auf Bildvergleich
// Das Problem: ADAC zeigt zu viel östlich und zu nah gezoomt
var zoomFactor;
if (cz.zoom >= 19) zoomFactor = 0.002; // Extrem nah - größerer Bereich
else if (cz.zoom >= 18) zoomFactor = 0.003; // Sehr nah
else if (cz.zoom >= 17) zoomFactor = 0.004; // Nah+
else if (cz.zoom >= 16) zoomFactor = 0.006; // Nah
else if (cz.zoom >= 15) zoomFactor = 0.008; // Mittel-nah+
else if (cz.zoom >= 14) zoomFactor = 0.012; // Mittel-nah
else if (cz.zoom >= 13) zoomFactor = 0.016; // Mittel+
else if (cz.zoom >= 12) zoomFactor = 0.022; // Mittel
else if (cz.zoom >= 11) zoomFactor = 0.030; // Mittel-weit+
else if (cz.zoom >= 10) zoomFactor = 0.040; // Mittel-weit
else if (cz.zoom >= 9) zoomFactor = 0.060; // Weit+
else if (cz.zoom >= 8) zoomFactor = 0.080; // Weit
else zoomFactor = 0.120; // Sehr weit
// Korrektur der Verschiebung: ADAC zeigt zu weit östlich und leicht nördlich
// Daher verschieben wir den Mittelpunkt leicht nach Westen und Süden
var correctedLat = cz.lat - (zoomFactor * 0.05); // Leichte Südverschiebung
var correctedLon = cz.lon - (zoomFactor * 0.15); // Leichte Westverschiebung
var latMin = (correctedLat - zoomFactor).toFixed(6);
var latMax = (correctedLat + zoomFactor).toFixed(6);
var lonMin = (correctedLon - zoomFactor).toFixed(6);
var lonMax = (correctedLon + zoomFactor).toFixed(6);
var adacUrl = 'https://maps.adac.de/?bounds=' +
latMin + ',' + lonMin + '-' + latMax + ',' + lonMax +
'&traffic=construction,announcements,flow';
window.open(adacUrl, '_blank');
});
var btn36 = createMapButton('Here Edit', 'ptsm-here-edit', () => {
var cz = getCenterZoom();
window.open('https://mapcreator.here.com/?l=' + cz.lat + ',' + cz.lon + ',' + cz.zoom + ',autoselect', '_blank');
});
var btn37 = createMapButton('Umsehen', 'ptsm-umsehen', () => {
var cz = getCenterZoom();
cz.zoom += 1.0;
window.open('https://maps.apple.com/?ll=' + cz.lat + ',' + cz.lon + '&z=' + cz.zoom + '&t=m', '_blank');
});
var btn39 = createMapButton('Hackintosh', 'ptsm-hackintosh', () => {
var cz = getCenterZoom();
window.open('https://lookmap.eu.pythonanywhere.com/#c=' + cz.zoom + '/' + cz.lat + '/' + cz.lon + '/', '_blank');
});
var btn40 = createMapButton('Archive', 'ptsm-archive', () => {
window.open('https://archive.is/', '_blank');
});
// Kompakt-Button erstellen
var compactButton = createCompactButton();
// Create container
var container = document.createElement('div');
container.className = 'ptsm-container';
// Kompakt-Modus beim Laden anwenden falls gespeichert
if (loadCompactMode()) {
container.classList.add('compact');
}
// Create categories
var allgemCategory = createCategory('Allgemeine Karten', 'ptsm-category-allgem', true);
var baustellCategory = createCategory('Baustellen & Verkehr', 'ptsm-category-baustell', false);
var blitzerCategory = createCategory('Blitzer & Geschwindigkeit', 'ptsm-category-blitzer', false);
var bilderCategory = createCategory('Straßenbilder', 'ptsm-category-bilder', false);
var geoportalCategory = createCategory('Geoportale', 'ptsm-category-geoportal', false);
var miscCategory = createCategory('Sonstiges', 'ptsm-category-misc', false);
// Add buttons to categories
// Allgemeine Karten
allgemCategory.content.appendChild(btn1); // Google
allgemCategory.content.appendChild(btn2); // Bing
allgemCategory.content.appendChild(btn3a); // OSM
allgemCategory.content.appendChild(btn4); // F4 3D
allgemCategory.content.appendChild(btn5); // Apple
allgemCategory.content.appendChild(btn10); // Here
allgemCategory.content.appendChild(btn13); // Mappy
allgemCategory.content.appendChild(btn18); // TomTom
allgemCategory.content.appendChild(btn9); // ViaM
// Baustellen & Verkehr
baustellCategory.content.appendChild(btn3); // Ver. NRW
baustellCategory.content.appendChild(btn6); // Autobahn
baustellCategory.content.appendChild(btn34); // ADAC
// Blitzer & Geschwindigkeit
blitzerCategory.content.appendChild(btn14); // Blitzer.de
blitzerCategory.content.appendChild(btn7); // POI Karte
blitzerCategory.content.appendChild(btn8); // POI Base
// Straßenbilder
bilderCategory.content.appendChild(btn11); // Mapillary
bilderCategory.content.appendChild(btn21); // KartaView
bilderCategory.content.appendChild(btn12); // OSBrowser
// Geoportale
geoportalCategory.content.appendChild(btn19); // Basemap DE
geoportalCategory.content.appendChild(btn31); // GeoAdmin
geoportalCategory.content.appendChild(btn32); // Basemap AT
geoportalCategory.content.appendChild(btn30); // TimOnline
geoportalCategory.content.appendChild(btn16); // BY Atlas
geoportalCategory.content.appendChild(btn22); // Bayerninfo
// Sonstiges
miscCategory.content.appendChild(btn20); // Reporting
miscCategory.content.appendChild(btn36); // Here Edit
miscCategory.content.appendChild(btn37); // Umsehen
miscCategory.content.appendChild(btn39); // Hackintosh
miscCategory.content.appendChild(btn40); // Archive
miscCategory.content.appendChild(compactButton); // Kompakt-Button hinzufügen
// Add categories to container
container.appendChild(allgemCategory.category);
container.appendChild(baustellCategory.category);
container.appendChild(blitzerCategory.category);
container.appendChild(bilderCategory.category);
container.appendChild(geoportalCategory.category);
container.appendChild(miscCategory.category);
// Add version info with update link
var versionInfo = document.createElement('div');
versionInfo.className = 'ptsm-state-info';
var updateLink = document.createElement('a');
updateLink.href = 'https://greasyfork.org/de/scripts/448378-wme-permalink-to-several-maps-dach';
updateLink.target = '_blank';
updateLink.textContent = 'Auf Updates überprüfen / V' + ptsmVersion;
updateLink.style.cssText = 'color: #007bff; text-decoration: none; font-size: 9px;';
updateLink.addEventListener('mouseover', function() {
this.style.textDecoration = 'underline';
});
updateLink.addEventListener('mouseout', function() {
this.style.textDecoration = 'none';
});
versionInfo.appendChild(updateLink);
container.appendChild(versionInfo);
// Add warning about external services
var warning = document.createElement('div');
warning.className = 'ptsm-warning';
warning.innerHTML = '<div class="w-icon">⚠</div><div class="ptsm-warning-text">Hinweis: Einige der externen Karten sind als Informationsquelle zur Kartenbearbeitung nicht zulässig!</div>';
container.appendChild(warning);
// Try to use WME Userscript API first, fallback to manual insertion
try {
if (W.userscripts && W.userscripts.registerSidebarTab) {
const result = W.userscripts.registerSidebarTab('wme-ptsm-dach');
var tabLabel = result.tabLabel;
var tabPane = result.tabPane;
tabLabel.textContent = 'PTSM';
tabLabel.title = 'WME Permalink to several Maps DACH';
tabPane.appendChild(container);
} else {
// Fallback: Try to add to existing sidebar
var sidebar = document.querySelector('#sidebar') || document.querySelector('.sidebar');
if (sidebar) {
// Create a collapsible section
var section = document.createElement('div');
section.style.cssText = 'border: 1px solid #ccc; margin: 10px 0; border-radius: 5px;';
var header = document.createElement('div');
header.style.cssText = 'background: #f5f5f5; padding: 10px; cursor: pointer; font-weight: bold; user-select: none;';
header.textContent = 'PTSM DACH';
var content = document.createElement('div');
content.style.display = 'none';
content.appendChild(container);
header.addEventListener('click', function() {
content.style.display = content.style.display === 'none' ? 'block' : 'none';
});
section.appendChild(header);
section.appendChild(content);
sidebar.appendChild(section);
} else {
// Last resort: Create floating panel
var floatingPanel = document.createElement('div');
floatingPanel.style.cssText = `
position: fixed;
top: 100px;
right: 10px;
width: 300px;
max-height: 70vh;
overflow-y: auto;
background: white;
border: 1px solid #ccc;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
z-index: 10000;
resize: both;
`;
var panelHeader = document.createElement('div');
panelHeader.style.cssText = `
background: linear-gradient(135deg, #007bff 0%, #0056b3 100%);
color: white;
padding: 10px;
font-weight: bold;
cursor: move;
user-select: none;
display: flex;
justify-content: space-between;
align-items: center;
`;
panelHeader.innerHTML = 'PTSM DACH <span style="cursor: pointer; font-size: 18px;">×</span>';
var closeBtn = panelHeader.querySelector('span');
closeBtn.addEventListener('click', function() {
floatingPanel.style.display = 'none';
});
// Make panel draggable
var isDragging = false;
var startX, startY, startLeft, startTop;
panelHeader.addEventListener('mousedown', function(e) {
if (e.target === closeBtn) return;
isDragging = true;
startX = e.clientX;
startY = e.clientY;
startLeft = parseInt(window.getComputedStyle(floatingPanel).left, 10);
startTop = parseInt(window.getComputedStyle(floatingPanel).top, 10);
document.addEventListener('mousemove', drag);
document.addEventListener('mouseup', stopDrag);
});
function drag(e) {
if (!isDragging) return;
var newLeft = startLeft + e.clientX - startX;
var newTop = startTop + e.clientY - startY;
floatingPanel.style.left = newLeft + 'px';
floatingPanel.style.top = newTop + 'px';
}
function stopDrag() {
isDragging = false;
document.removeEventListener('mousemove', drag);
document.removeEventListener('mouseup', stopDrag);
}
floatingPanel.appendChild(panelHeader);
floatingPanel.appendChild(container);
document.body.appendChild(floatingPanel);
}
}
} catch (e) {
console.error('PTSM: Error adding to sidebar:', e);
}
console.log('PTSM DACH v' + ptsmVersion + ' loaded successfully');
// Update-Popup anzeigen (einmalig pro Version)
setTimeout(showUpdatePopup, 1000);
}
// Initialize when page loads
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', addButtons);
} else {
setTimeout(addButtons, 1000);
}
// Also try to initialize when Waze editor loads
if (typeof W !== 'undefined') {
if (W.loginManager && W.loginManager.events) {
W.loginManager.events.register('loginStateChanged', null, addButtons);
}
setTimeout(addButtons, 2000);
} else {
// Wait for Waze object to be available
var checkForWaze = setInterval(function() {
if (typeof W !== 'undefined' && W.loginManager) {
clearInterval(checkForWaze);
setTimeout(addButtons, 1000);
}
}, 500);
}