Kopie von https://jsfiddle.net/spy2eh0h/44 als Gist.
Direkt nutzbar unter https://bl.ocks.org/tordans/9495504789d52e503bbe0022e592e451 (Mehr über https://bl.ocks.org/-/about)
Kopie von https://jsfiddle.net/spy2eh0h/44 als Gist.
Direkt nutzbar unter https://bl.ocks.org/tordans/9495504789d52e503bbe0022e592e451 (Mehr über https://bl.ocks.org/-/about)
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta http-equiv="content-type" content="text/html; charset=UTF-8"> | |
<title>Verkehrsordnungswidrigkeitenanzeige bei Halt- und Parkverstößen</title> | |
<meta name="robots" content="noindex, nofollow"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<script type="text/javascript" src="/js/lib/dummy.js"></script> | |
<link rel="stylesheet" type="text/css" href="/css/result-light.css"> | |
<style id="compiled-css" type="text/css"> | |
body { | |
font-family: Helvetica, Arial, sans-serif; | |
/* font-size: 2.2vh; */ | |
zoom: 66.67%; | |
} | |
h3 { | |
color: #b5050e; | |
} | |
input, | |
textarea { | |
width: 32em; | |
} | |
ol>li { | |
padding-bottom: 1em; | |
} | |
</style> | |
<!-- TODO: Missing CoffeeScript 2 --> | |
<script> | |
window.onload=function(){ | |
function resizeImageToDataUri(img, width, height) { | |
// create an off-screen canvas | |
var canvas = document.createElement('canvas'); | |
var ctx = canvas.getContext('2d'); | |
// set its dimension to target size | |
canvas.width = width; | |
canvas.height = height; | |
var size = img.src.length; | |
console.log({size, width, height}); | |
// draw source image into the off-screen canvas: | |
ctx.drawImage(img, 0, 0, width, height); | |
// encode image to data-uri with base64 version of compressed image | |
var quality = 0.5; | |
var result = canvas.toDataURL('image/jpeg', quality); // quality = [0.0, 1.0] | |
console.log(result.length); | |
//document.getElementsByTagName('body')[0].appendChild(canvas); | |
return result; | |
} | |
function selectElementContents(element) { | |
var range = document.createRange(); | |
range.selectNodeContents(element); | |
var selection = window.getSelection(); | |
selection.removeAllRanges(); | |
selection.addRange(range); | |
} | |
function toDecimal(number) { | |
if (typeof(number) != "undefined") { | |
return number[0].numerator + number[1].numerator / | |
(60 * number[1].denominator) + number[2].numerator / (3600 * number[2].denominator); | |
} else { | |
return 0; | |
} | |
} | |
function reverseGeoLocate(latlng, targetElement) { | |
// asynchronous call to Google API | |
geocoder.geocode({ | |
'location': latlng | |
}, function(results, status) { | |
if (status === google.maps.GeocoderStatus.OK && results[0]) { | |
var formatted_address = results[0].formatted_address; | |
targetElement.innerHTML = formatted_address; | |
} else { | |
window.alert('Geocoder failed due to: ' + status); | |
} | |
}); | |
} | |
function reverseGeotagImage(imgfile, container) { | |
EXIF.getData(imgfile, function() { | |
if (!EXIF.getTag(this, 'GPSDateStamp')) { | |
return false; | |
} | |
var lat = toDecimal(EXIF.getTag(this, 'GPSLatitude')); | |
var lon = toDecimal(EXIF.getTag(this, 'GPSLongitude')); | |
//console.log(EXIF.getTag(this, 'GPSTimeStamp')); | |
//console.log(EXIF.getTag(this, 'GPSTimeStamp').join(':').replace(/(^|\b|:)([0-9])\b/g, "$10$2")); | |
var datetime_s = EXIF.getTag(this, 'GPSDateStamp').replace(/:/g, '-') + " " + EXIF.getTag(this, 'GPSTimeStamp').join(':').replace(/(^|\b|:)([0-9])\b/g, "$1" + '0' + "$2").replace(/\.[0-9]+$/, '') + " UTC"; | |
var latlng = { | |
lat: lat, | |
lng: lon | |
}; | |
var datetime_p = document.createElement("p"); | |
//console.log(JSON.stringify(EXIF.getAllTags(this))); | |
//var imageWidth = EXIF.getTag(this, 'PixelXDimension') || 1024; //FIXME | |
//var imageHeight = EXIF.getTag(this, 'PixelYDimension') || 200;//FIXME | |
//var newWidth = Math.min(1024, imageWidth); | |
var reader = new FileReader(); | |
reader.readAsDataURL(imgfile); | |
reader.onload = function(event) { | |
var preview_img = document.createElement('img'); | |
var zoomLevel = window.getComputedStyle(document.getElementsByTagName('body')[0], null).getPropertyValue('zoom'); | |
if (!zoomLevel) { | |
zoomLevel = 1; | |
} | |
preview_img.src = reader.result; | |
preview_img.onload = function() { | |
//console.log(JSON.stringify(preview_img.naturalWidth)); | |
var imageWidth = preview_img.naturalWidth; | |
var imageHeight = preview_img.naturalHeight; | |
var newWidth = Math.min(1024, imageWidth); | |
preview_img.width = Math.min(Math.round(window.innerWidth / 2 / zoomLevel), newWidth); | |
preview_img.maxWidth = 320; //FIXME (device width) | |
var count = 0; | |
var result = resizeImageToDataUri(this, newWidth, newWidth * imageHeight / imageWidth); | |
while (result.length < 16*1024 && count++ < 5) { | |
console.log({count: count, "result.length": result.length}); | |
result = resizeImageToDataUri(this, newWidth, newWidth * imageHeight / imageWidth); | |
} | |
if (result.length && result.length > 64*1024) { // at least 64 kB | |
this.src = result; | |
this.onload = null; | |
//this.style = "border: 1px solid yellow;"; | |
} else { | |
this.style = "border: 1px solid red;"; | |
} | |
} | |
datetime_p.appendChild(preview_img); | |
}; | |
datetime_p.appendChild(document.createTextNode("Aufnahmeort: ")); | |
var loc_elem = document.createElement("span"); | |
loc_elem.className = "location"; | |
datetime_p.appendChild(loc_elem); | |
reverseGeoLocate(latlng, loc_elem); | |
datetime_p.appendChild(document.createElement("br")); | |
datetime_p.appendChild(document.createTextNode("GPS: ")); | |
var a = document.createElement('a'); | |
a.href = 'https://www.google.com/maps/@' + lat + ',' + lon + ',75m/data=!3m1!1e3'; | |
a.target = '_blank'; | |
a.appendChild(document.createTextNode(lat + "," + lon)); | |
datetime_p.appendChild(a); | |
var datetime = new Date(datetime_s.replace(/ /, 'T').replace(/ UTC/, 'Z')); | |
datetime_p.appendChild(document.createElement("br")); | |
datetime_p.appendChild(document.createTextNode("Aufnahmezeitpunkt: " + datetime_s + ' (' + datetime.toLocaleString('de-DE', { | |
weekday: 'short', | |
year: 'numeric', | |
month: 'short', | |
day: 'numeric', | |
hour: 'numeric', | |
minute: 'numeric', | |
second: 'numeric', | |
timeZoneName: 'short' | |
}) + ')')); | |
datetime_p.appendChild(document.createElement("br")); | |
container.appendChild(datetime_p); | |
}); | |
} | |
var geocoder = new google.maps.Geocoder(); | |
$("#imgfiles").change(function() { | |
for (i = 0; i < document.getElementById('imgfiles').files.length; i++) { | |
var container = document.createElement('div'); | |
var imgfile = document.getElementById('imgfiles').files[i]; | |
if (!imgfile.type.match('image')) { | |
continue; | |
} | |
reverseGeotagImage(imgfile, container); | |
this.parentNode.appendChild(container); | |
} | |
}); | |
function sendMail(address) { | |
var docLoc = document.location; | |
mailWin = window.open('mailto:' + address, 'emailWindow'); | |
if (mailWin && mailWin.open && !mailWin.closed) { | |
mailWin.close(); | |
} else { | |
docLoc = 'mailto:' + address; | |
} | |
} | |
function cleanup(nodeList) { | |
for (i = 0; i < nodeList.length; i++) { | |
//alert(nodeList.length); | |
if (nodeList[i].classList.contains("remove") || nodeList[i].value === null || nodeList[i].value === '') { | |
if (nodeList[i].nextSibling && nodeList[i].nextSibling.tagName === "BR") { | |
nodeList[i].nextSibling.remove(); | |
} | |
nodeList[i].remove(); | |
i--; | |
} else if (nodeList[i].type === "text" || nodeList[i].type === "select-one" || nodeList[i].type === "textarea") { | |
var elem; | |
if (nodeList[i].name === "Anschrift") { | |
elem = document.createElement("a"); | |
elem.href = "https://www.google.com/maps/search/" + encodeURI(nodeList[i].value) + ",+" + encodeURI(nodeList[i + 1].value) + ",+Berlin/"; | |
elem.target = "_blank"; | |
} else { | |
elem = document.createElement("span"); | |
} | |
elem.innerHTML = nodeList[i].value; | |
nodeList[i].replaceWith(elem); | |
document.getElementsByTagName('body')[0].style.fontSize = "1em"; | |
document.getElementsByTagName('body')[0].style.zoom = "reset"; | |
i--; | |
} | |
} | |
} | |
function clearLocalStorage() { | |
localStorage.clear(); | |
} | |
function saveLocalStorage(nodeList) { | |
for (i = 0; i < nodeList.length; i++) { | |
localStorage.setItem(nodeList[i].name, nodeList[i].value.trim()); | |
} | |
} | |
function loadLocalStorage(nodeList) { | |
for (i = 0; i < nodeList.length; i++) { | |
var value = localStorage.getItem(nodeList[i].name); | |
if (value && (nodeList[i].type === "text" || nodeList[i].type === "textarea" || nodeList[i].type === "select-one")) { | |
nodeList[i].value = value.trim(); | |
} | |
} | |
} | |
$(document).ready(function() { | |
loadLocalStorage(document.getElementsByTagName('input')); | |
loadLocalStorage(document.getElementsByTagName('textarea')); | |
loadLocalStorage(document.getElementsByTagName('select')); | |
}); | |
$('input').change(function() { | |
saveLocalStorage(document.getElementsByTagName('input')); | |
}); | |
$('textarea').change(function() { | |
saveLocalStorage(document.getElementsByTagName('textarea')); | |
}); | |
$('select').change(function() { | |
saveLocalStorage(document.getElementsByTagName('select')); | |
}); | |
$('#sendMail').click(function() { | |
if (document.getElementById('imgfiles').files.length > 0 && document.getElementsByClassName('location').length > 0) { | |
cleanup(document.getElementsByClassName('remove')); | |
cleanup(document.getElementsByTagName('input')); | |
cleanup(document.getElementsByTagName('textarea')); | |
cleanup(document.getElementsByTagName('select')); | |
selectElementContents(document.getElementsByTagName('body')[0]); | |
if (document.execCommand("copy") && confirm("Anzeigetext wurde kopiert. Bitte in E-Mail einfügen und an anzeige@bowi.berlin.de senden.")) { | |
sendMail('anzeige@bowi.berlin.de?Subject=Verkehrsordnungswidrigkeitenanzeige%20bei%20Halt-%20und%20Parkverst%C3%B6%C3%9Fen&Body=%5BBitte%20hier%20das%20kopierte%20Formular%20einf%C3%BCgen%5D'); | |
return false; | |
} else { | |
return false; | |
} | |
} else { | |
if(confirm("Bitte fügen Sie wenigstens ein Foto mit aktiviertem Ortungsdienst (GPS) bei!")) { $('#imgfiles').click(); }; | |
return false; | |
} | |
}); | |
} | |
//]]> | |
</script> | |
<script src="https://maps.googleapis.com/maps-api-v3/api/js/37/5/intl/de_ALL/common.js"></script> | |
<script src="https://maps.googleapis.com/maps-api-v3/api/js/37/5/intl/de_ALL/util.js"></script> | |
<script src="https://maps.googleapis.com/maps-api-v3/api/js/37/5/intl/de_ALL/geocoder.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/exif-js/2.3.0/exif.min.js"></script> | |
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script> | |
</head> | |
<body> | |
<div id="navElements" class="remove" style="position: fixed; right: 25px; top: 5px; padding: 5px; text-align: center; line-height: 25px; font-size: 20px; border: 0px solid lime; zoom: reset;"> | |
<fieldset style="position: relative; float: left; background-color: rgba(190,190,190,0.4); font-size: small; text-shadow: 2px 2px 4px white; padding: 5px;"> | |
<legend style="background-color: rgba(210,210,210,0.8); font-size: 80%; text-shadow: 2px 2px 4px white; box-shadow: 2px 2px 4px grey;">In 4 Schritten zur Anzeige</legend> | |
<ol> | |
<li><button onclick="document.getElementsByName('Anrede')[0].focus(); return false;">Adresse eingeben</button><br></li> | |
<li><button onclick="document.getElementsByName('Verkehrsverstoß')[0].focus(); return false;">Vorwurf auswählen</button><br></li> | |
<li><button onclick="document.getElementById('imgfiles').click(); return false;">Bilder auswählen</button><br></li> | |
<li><button onclick="document.getElementById('sendMail').click(); return false;">E-Mail erzeugen</button><br></li> | |
</ol> | |
</fieldset> | |
<!-- | |
<div style="position: relative; float: right; border: 0px solid blue;"> | |
<input type="button" value="^^" style="width: 2.5em" onClick="var actionElement = (document.scrollingElement || document.body); actionElement.scrollTop = 0; return false;"><br> | |
<input type="button" value="+" style="width: 2.5em" onClick="var actionElement = document.getElementsByTagName('body')[0]; actionElement.style.zoom = (parseFloat(window.getComputedStyle(actionElement, null).getPropertyValue('zoom')) * 1.2); return false;"><br> | |
<input type="button" value="*" style="width: 2.5em" onClick="var actionElement = document.getElementsByTagName('body')[0]; actionElement.style.zoom = 'reset'; actionElement.style.fontSize = '1em'; return false;"><br> | |
<input type="button" value="-" style="width: 2.5em" onClick="var actionElement = document.getElementsByTagName('body')[0]; actionElement.style.zoom = (parseFloat(window.getComputedStyle(actionElement, null).getPropertyValue('zoom')) * 0.8); return false;"><br> | |
<input type="button" value="v" style="width: 2.5em" onClick="$('body').animate({ scrollTop: $('#sendMail').offset().top }, 500); return false;"><br> | |
<input type="button" value="vv" style="width: 2.5em" onClick="var actionElement = (document.scrollingElement || document.body); actionElement.scrollTop = actionElement.scrollHeight; return false;"><br> | |
</div> | |
--> | |
</div> | |
<h3>(Vereinfachte) Verkehrsordnungswidrigkeitenanzeige bei Halt- und Parkverstößen</h3> | |
<ul class="remove"> | |
<li><a href="https://www.berlin.de/polizei/aufgaben/bussgeldstelle/anzeigenerstattung/">https://www.berlin.de/polizei/aufgaben/bussgeldstelle/anzeigenerstattung/</a></li> | |
</ul> | |
<ol> | |
<li> | |
<strong>Anzeigende/Anzeigender = Zeugin/Zeuge:</strong> | |
<p> | |
<input name="Anrede" placeholder="Anrede" type="text"><br> | |
<input name="Vorname" placeholder="Vorname" type="text"><br> | |
<input name="Familienname" placeholder="Familienname" type="text"><br> | |
<input name="Anschrift" placeholder="Straße, Hausnummer" type="text"><br> | |
<input name="Ort" placeholder="PLZ, Ort" type="text"><br> | |
<input name="Kontakt" placeholder="optional / für Rückfragen: Telefonnummer, E-Mail-Adresse" type="text"><br> | |
</p> | |
<ul> | |
<li>Meine vorstehend angegebenen Personalien sind zutreffend und —soweit erforderlich— vollständig (<a href="https://dejure.org/gesetze/OWiG/111.html">§111 OWiG</a>).</li> | |
<li>Mir ist bewusst, dass ich als Zeugin / Zeuge zur wahrheitsgemäßen Aussage (<a href="https://dejure.org/gesetze/StPO/57.html">§ 57</a> und <a href="https://dejure.org/gesetze/StPO/161a.html">§ 161a StPO</a> i. V. m. <a href="https://dejure.org/gesetze/OWiG/46.html">§ 46 OWiG</a>) | |
und ggf. auch zu einem Erscheinen vor Gericht verpflichtet bin (<a href="https://dejure.org/gesetze/StPO/48.html">§ 48 StPO</a>).</li> | |
<li>Ich weiß, dass vorsätzlich falsche Angaben zu angeblichen Ordnungswidrigkeiten eine Straftat (<a href="https://dejure.org/gesetze/StGB/164.html">§ 164 StGB</a>) darstellen können.</li> | |
<li>Ich weiß, dass die angezeigten Person bei einer Akteneinsicht auch meinen Namen und vollständige Adresse ersehen kann (<a href="https://dejure.org/gesetze/StPO/147.html">§ 147 StPO</a>).</li> | |
</ul> | |
</li> | |
<li> | |
<strong>Angaben zum Verkehrsverstoß:</strong><br> | |
<select name="Verkehrsverstoß"> | |
<option>Fahren</option> | |
<option>Halten</option> | |
<option selected="">Parken</option> | |
</select> auf dem <select name="Verkehrsfläche"> | |
<option>Schutzstreifen</option> | |
<option selected="">Radfahrstreifen</option> | |
<option>Radweg</option> | |
<option>Gehweg</option> | |
<option>Sonderweg</option> | |
<option>(siehe Anmerkung*)</option> | |
</select> <select name="Qualifizierung"> | |
<option selected="">ohne Behinderung</option> | |
<option>mit Behinderung: ich musste anhalten</option> | |
<option>mit Behinderung: ich musste ausweichen</option> | |
<option>mit Behinderung: ich musste absteigen</option> | |
<option>mit Gefährdung: ich musste in den Fliessverkehr ausweichen</option> | |
</select><br> | |
<p><textarea name="weitereAngaben" rows="3" placeholder="optional: weitere Angaben (z. B. Kennzeichen, Typ, Farbe des KFz; vorhandene Verkehrszeichen) oder *) Anmerkung zum Verstoß"></textarea></p> | |
</li> | |
<li> | |
<strong>Fotos mit Orts- & Zeitangaben:</strong><br> | |
<p class="remove">Bitte fügen Sie aussagekräftige Fotos mit aktiviertem Ortungsdienst (GPS) bei. Darauf sollten das Fahrzeug, sein amtliches Kennzeichen und die relevanten Verkehrszeichen ersichtlich sein.<br> Bei zeitabhängigen Verstößen (>3 min; >1 h; >3 | |
h) sollte der zeitliche Abstand zwischen erstem und letztem Foto größer sein.</p> | |
<div><input type="file" id="imgfiles" accept="image/jpeg" multiple="multiple" class="remove"><label for="imgfiles" class="remove">(1–6 Fotos)</label> | |
</div> | |
</li> | |
<li class="remove"> | |
<div id="sendMail" class="remove">Formular umwandeln und an <a href="mailto:anzeige@bowi.berlin.de?Subject=Verkehrsordnungswidrigkeitenanzeige%20bei%20Halt-%20und%20Parkverst%C3%B6%C3%9Fen&Body=%5BBitte%20das%20ausgef%C3%BCllte%20Formular%20kopieren%20und%20hier%20einf%C3%BCgen%5D" title="Link zur E-Mail">anzeige@bowi.berlin.de</a> senden</div> | |
</li> | |
</ol> | |
<script> | |
// tell the embed parent frame the height of the content | |
if (window.parent && window.parent.parent){ | |
window.parent.parent.postMessage(["resultsFrame", { | |
height: document.body.getBoundingClientRect().height, | |
slug: "" | |
}], "*") | |
} | |
// always overwrite window.name, in case users try to set it manually | |
window.name = "result" | |
</script> | |
</body> | |
</html> |