frog shit
All checks were successful
ClarkeIS Build / Build-Docker-Image (push) Successful in 25s

This commit is contained in:
2025-03-23 23:53:59 -04:00
parent 5e194a532b
commit fd82bf82b6
6 changed files with 319 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="64mm"
height="64mm"
viewBox="0 0 64.000002 64"
version="1.1"
id="svg1"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
sodipodi:docname="icon.svg"
inkscape:export-filename="icon.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="0.71268238"
inkscape:cx="291.85512"
inkscape:cy="94.011024"
inkscape:window-width="1920"
inkscape:window-height="1011"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"
inkscape:export-bgcolor="#ffffffff" />
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-32.216804,-67.856489)">
<path
id="path1"
style="fill:#00ffff;stroke:#000000;stroke-width:0.164;stroke-linecap:round"
d="M 64.216803,71.650989 A 14.47875,14.47875 0 0 0 49.7381,86.130208 14.47875,14.47875 0 0 0 52.866591,95.067131 L 64.216803,127.48737 75.567014,95.067131 A 14.47875,14.47875 0 0 0 78.695505,86.130208 14.47875,14.47875 0 0 0 64.216803,71.650989 Z" />
<circle
style="fill:#ff0000;stroke:#000000;stroke-width:0.164;stroke-linecap:round"
id="path2"
cx="64.216805"
cy="85.879189"
r="5.1190114" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html>
<head>
<title>Real Estate Picture Taker Thingy</title>
<link rel="stylesheet" href="main.css" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="manifest" href="manifest.json" />
</head>
<body>
<video id="magic_video" class="offscreen">video stream unavailable</video>
<div id="home" style="display: none;">
<button onclick="setdetails()" style="display: none;" id="endcamera">Next</button>
<canvas id="precanvas" class="offscreen"></canvas>
<div id="camview">
<div id="video-container">
<video id="preview">video stream unavailable</video>
</div>
<button onclick="takepicture()">Take Picture!</button>
</div>
</div>
<div id="details" style="display: none;">
<span>Longitude: <input type="number" id="long"/></span>
<span>Latitude: <input type="number" id="lat"/></span>
<button onclick="populateLocation()" id="here">Current Location</button>
<span>Title: <input type="text" id="title" placeholder="123 A Place"/></span>
<span>Notes: <input type="text" id="notes" placeholder="Location Notes" /></span>
<button onclick="render()">Finish</button>
</div>
<div id="finalresult" style="display: none;">
<canvas id="final" width="720" height="480"></canvas>
<button onclick="download()">Download!</button>
</div>
<script src="main.js"></script>
</body>
</html>

View File

@@ -0,0 +1,83 @@
body {
margin: 0px;
padding: 0px;
}
body > div {
position: absolute;
top: 0px;
left: 0px;
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
body > div > * {
margin: 20px;
}
#camview {
max-width: 100vw;
box-shadow: 0px 0px 50px 0px black;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 30px;
box-sizing: border-box;
}
#camview.took {
position: fixed;
right: 0px;
bottom: 0px;
width: 150px;
z-index: 100;
display: inline-flex;
background-color: white;
padding: 10px;
}
#camview.took > button {
font-size: 1em;
}
#video-container {
max-width: 100%;
}
#camview > button {
font-size: 2em;
}
#precanvas {
height: 100%;
max-height: 4in;
flex-shrink: 0;
}
#preview {
width: 100%;
display: inline-block;
}
.offscreen {
position: absolute;
top: -10000px;
left: -10000px;
}
video.unbounded {
position: absolute;
height: 100vw !important;
width: auto;
}
#final {
max-width: 100vw;
border: 1px solid black;
}

132
frog-realestate-pwa/main.js Normal file
View File

@@ -0,0 +1,132 @@
function frame(e) {
for (let el of document.querySelectorAll("body > div")) {
if (el.style.display != "none") {
el.style.display = "none";
window.app[el.id].exit();
}
}
document.getElementById(e).style.display = "";
window.app[e].enter();
}
let canvas = document.getElementById("precanvas");
let ctx = canvas.getContext("2d");
let video = document.getElementById("magic_video");
function takepicture() {
let box = video.getBoundingClientRect();
canvas.width = box.width;
canvas.height = box.height;
video.classList.add("unbounded");
document.getElementById("endcamera").style.display = "";
ctx.canvas.classList.remove("offscreen");
document.getElementById("camview").classList.add("took")
requestAnimationFrame(() => {
ctx.drawImage(video, 0, 0, box.width, box.height);
video.classList.remove("unbounded");
})
}
function setdetails() {
frame("details");
}
if ("geolocation" in navigator) {
document.getElementById("here").style.display = "";
}
function populateLocation() {
navigator.geolocation.getCurrentPosition(pos => {
document.getElementById("long").value = pos.coords.longitude;
document.getElementById("lat").value = pos.coords.latitude;
});
}
function render() {
frame("finalresult");
}
window.app = {
"home": {
enter() {
let preview = document.getElementById("preview");
navigator.mediaDevices.getUserMedia({ video: {
facingMode: { ideal: "environment" }
}, audio : false }).then((stream) => {
video.srcObject = stream;
video.play();
preview.srcObject = stream;
preview.play();
window.app.stream = stream;
});
},
exit() {
window.app.stream.getTracks().forEach(track => {
track.stop();
});
}
},
"details": {
enter() {
},
exit() {
}
},
"finalresult": {
enter() {
let canvas = document.getElementById("final");
let ctx = canvas.getContext("2d");
ctx.font = "bold 48px sans-serif";
ctx.filLStyle = "black";
ctx.fillText(document.getElementById("title").value, 0, 48);
ctx.font = "bold 24px sans-serif";
ctx.fillText(new Date().toLocaleString(), 0, 76);
let lat = document.getElementById("lat").value;
let long = document.getElementById("long").value;
/*reverse_geocode(lat, long).then(res => {
ctx.fillText(res, 0, 104);
});*/
ctx.fillText("https://maps.google.com/maps?q=" + lat + "," + long, 0, 128);
ctx.fillText("Notes: " + document.getElementById("notes").value, 0, 154);
let image = document.getElementById("precanvas");
ctx.drawImage(image, 0, 160, 720 * 1/2, image.height / image.width * 720 * 1/2);
maps_static(lat, long, img => {
ctx.drawImage(img, 365, 160);
});
},
exit() {
}
}
}
frame("home");
async function reverse_geocode(lat, long) {
let res = await fetch("https://maps.googleapis.com/maps/api/geocode/json?zoom=6&latlng=" + lat + "," + long + "&key=AIzaSyD_zbdxwN7_aOMNH69eAL9bSS814Ix-UM8");
let json = await res.json();
return json.results[0].formatted_address;
}
function maps_static(lat, long, cbk) {
let img = document.createElement("img");
document.body.appendChild(img);
img.classList.add("offscreen");
img.src = "https://maps.googleapis.com/maps/api/staticmap?size=355x300&key=AIzaSyD_zbdxwN7_aOMNH69eAL9bSS814Ix-UM8&markers=label:S%7C" + lat + "," + long;
img.onload = () => {
cbk(img);
};
}
function download() {
let canvas = document.getElementById("final");
let anchor = document.createElement("a");
anchor.href = canvas.toDataURL();
anchor.download = "file.png";
anchor.click();
}

View File

@@ -0,0 +1,12 @@
{
"name": "Real Estate Pictures Tool",
"start_url": ".",
"icons": [
{
"src": "icon.png",
"type": "image/png",
"sizes": "64x64"
}
],
"display": "standalone"
}