An error occurred while loading the file. Please try again.
  • Traboulsi's avatar
    Update public/blog.html, public/blog-details.html,... · 8aecd2e3
    Traboulsi authored
    Update public/blog.html, public/blog-details.html, public/portfolio-details.html, public/Readme.txt, public/service-details.html, public/starter-page.html, public/assets/css/main.css, public/assets/img/blog/blog-1.jpg, public/assets/img/blog/blog-2.jpg, public/assets/img/blog/blog-3.jpg, public/assets/img/blog/blog-4.jpg, public/assets/img/blog/blog-author.jpg, public/assets/img/blog/blog-inside-post.jpg, public/assets/img/blog/blog-recent-1.jpg, public/assets/img/blog/blog-recent-2.jpg, public/assets/img/blog/blog-recent-3.jpg, public/assets/img/blog/blog-recent-4.jpg, public/assets/img/blog/blog-recent-5.jpg, public/assets/img/blog/comments-1.jpg, public/assets/img/blog/comments-2.jpg, public/assets/img/blog/comments-3.jpg, public/assets/img/blog/comments-4.jpg, public/assets/img/blog/comments-5.jpg, public/assets/img/blog/comments-6.jpg, public/assets/img/clients/client-1.png, public/assets/img/clients/client-2.png, public/assets/img/clients/client-3.png, public/assets/img/clients/client-4.png, public/assets/img/clients/client-5.png, public/assets/img/clients/client-6.png, public/assets/img/clients/client-7.png, public/assets/img/clients/client-8.png, public/assets/img/portfolio/app-1.jpg, public/assets/img/portfolio/app-2.jpg, public/assets/img/portfolio/app-3.jpg, public/assets/img/portfolio/books-2.jpg, public/assets/img/portfolio/books-1.jpg, public/assets/img/portfolio/books-3.jpg, public/assets/img/portfolio/branding-1.jpg, public/assets/img/portfolio/branding-2.jpg, public/assets/img/portfolio/product-3.jpg, public/assets/img/portfolio/product-1.jpg, public/assets/img/portfolio/branding-3.jpg, public/assets/img/portfolio/product-2.jpg, public/assets/img/testimonials/testimonials-1.jpg, public/assets/img/testimonials/testimonials-2.jpg, public/assets/img/testimonials/testimonials-3.jpg, public/assets/img/testimonials/testimonials-4.jpg, public/assets/img/testimonials/testimonials-5.jpg, public/assets/img/about.jpg, public/assets/img/alt-features.png, public/assets/img/apple-touch-icon.png, public/assets/img/favicon.png, public/assets/img/features.png, public/assets/img/hero-img.png, public/assets/img/hero-bg.png, public/assets/img/team-shape.svg, public/assets/img/values-2.png, public/assets/img/values-3.png, public/assets/img/values-1.png, public/assets/img/services.jpg, public/assets/img/logo.png, public/assets/js/main.js, public/assets/scss/main.js, public/assets/vendor/aos/aos.cjs.js, public/assets/vendor/aos/aos.css, public/assets/vendor/aos/aos.esm.js, public/assets/vendor/aos/aos.js, public/assets/vendor/aos/aos.js.map, public/assets/vendor/bootstrap/css/bootstrap.css, public/assets/vendor/bootstrap/css/bootstrap.css.map, public/assets/vendor/bootstrap/css/bootstrap.min.css, public/assets/vendor/bootstrap/css/bootstrap.min.css.map, public/assets/vendor/bootstrap/css/bootstrap.rtl.css, public/assets/vendor/bootstrap/css/bootstrap.rtl.css.map, public/assets/vendor/bootstrap/css/bootstrap.rtl.min.css, public/assets/vendor/bootstrap/css/bootstrap.rtl.min.css.map, public/assets/vendor/bootstrap/css/bootstrap-grid.css, public/assets/vendor/bootstrap/css/bootstrap-grid.css.map, public/assets/vendor/bootstrap/css/bootstrap-grid.min.css, public/assets/vendor/bootstrap/css/bootstrap-grid.min.css.map, public/assets/vendor/bootstrap/css/bootstrap-grid.rtl.css, public/assets/vendor/bootstrap/css/bootstrap-grid.rtl.css.map, public/assets/vendor/bootstrap/css/bootstrap-grid.rtl.min.css, public/assets/vendor/bootstrap/css/bootstrap-grid.rtl.min.css.map, public/assets/vendor/bootstrap/css/bootstrap-reboot.css, public/assets/vendor/bootstrap/css/bootstrap-reboot.css.map, public/assets/vendor/bootstrap/css/bootstrap-reboot.min.css, public/assets/vendor/bootstrap/css/bootstrap-reboot.min.css.map, public/assets/vendor/bootstrap/css/bootstrap-reboot.rtl.min.css, public/assets/vendor/bootstrap/css/bootstrap-utilities.css, public/assets/vendor/bootstrap/css/bootstrap-utilities.rtl.css.map, public/assets/vendor/bootstrap/css/bootstrap-reboot.rtl.css.map, public/assets/vendor/bootstrap/css/bootstrap-reboot.rtl.css, public/assets/vendor/bootstrap/css/bootstrap-utilities.min.css, public/assets/vendor/bootstrap/css/bootstrap-utilities.rtl.css, public/assets/vendor/bootstrap/css/bootstrap-utilities.rtl.min.css.map, public/assets/vendor/bootstrap/css/bootstrap-utilities.rtl.min.css, public/assets/vendor/bootstrap/css/bootstrap-utilities.min.css.map, public/assets/vendor/bootstrap/css/bootstrap-reboot.rtl.min.css.map, public/assets/vendor/bootstrap/css/bootstrap-utilities.css.map, public/assets/vendor/bootstrap/js/bootstrap.bundle.js, public/assets/vendor/bootstrap/js/bootstrap.bundle.js.map, public/assets/vendor/bootstrap/js/bootstrap.bundle.min.js, public/assets/vendor/bootstrap/js/bootstrap.bundle.min.js.map, public/assets/vendor/bootstrap/js/bootstrap.esm.js, public/assets/vendor/bootstrap/js/bootstrap.esm.js.map, public/assets/vendor/bootstrap/js/bootstrap.esm.min.js, public/assets/vendor/bootstrap/js/bootstrap.esm.min.js.map, public/assets/vendor/bootstrap/js/bootstrap.js, public/assets/vendor/bootstrap/js/bootstrap.min.js, public/assets/vendor/bootstrap/js/bootstrap.min.js.map, public/assets/vendor/bootstrap/js/bootstrap.js.map, public/assets/vendor/bootstrap-icons/fonts/bootstrap-icons.woff2, public/assets/vendor/bootstrap-icons/fonts/bootstrap-icons.woff, public/assets/vendor/bootstrap-icons/bootstrap-icons.json, public/assets/vendor/bootstrap-icons/bootstrap-icons.css, public/assets/vendor/bootstrap-icons/bootstrap-icons.scss, public/assets/vendor/bootstrap-icons/bootstrap-icons.min.css, public/assets/vendor/glightbox/css/glightbox.css, public/assets/vendor/glightbox/css/glightbox.min.css, public/assets/vendor/glightbox/js/glightbox.js, public/assets/vendor/glightbox/js/glightbox.min.js, public/assets/vendor/imagesloaded/imagesloaded.pkgd.min.js, public/assets/vendor/isotope-layout/isotope.pkgd.js, public/assets/vendor/isotope-layout/isotope.pkgd.min.js, public/assets/vendor/php-email-form/validate.js, public/assets/vendor/purecounter/purecounter_vanilla.js, public/assets/vendor/purecounter/purecounter_vanilla.js.map, public/assets/vendor/swiper/swiper-bundle.min.css, public/assets/vendor/swiper/swiper-bundle.min.js, public/assets/vendor/swiper/swiper-bundle.min.js.map, public/index.html
    8aecd2e3
ar_main.js 17.91 KiB
    // Variablen
    let selectedModel = 'robot';
    let selectedPlacedModel = null;
    let currentSession = null;
    let reticle = null;
    let scene, camera;
    let geoLocation;
    let models = {
      bench: {
        name: "Bench",
        image: "previewImages/bench.PNG",
        file: "/assets/models/bench_model/scene.gltf",
        scale: { x: 0.1, y: 0.1, z: 0.1 },
        minScale: 0.05, // 50% der aktuellen Größe
        maxScale: 0.5   // 500% der aktuellen Größe
      trashbin: {
        name: "Trash bin",
        image: "previewImages/trash_can.PNG",
        file: "/assets/models/trash_model/scene.gltf",
        scale: { x: 0.03, y: 0.03, z: 0.03 },
        minScale: 0.01, // 50% der aktuellen Größe
        maxScale: 0.1   // 500% der aktuellen Größe
      telephone_box: {
        name: "Telephone Box",
        image: "previewImages/telephone_box.PNG",
        file: "/assets/models/telephone_box_model/scene.gltf",
        scale: { x: 0.5, y: 0.5, z: 0.5 },
        minScale: 0.05,
        maxScale: 1
      fire_hydrant_model: {
        name: "Fire Hydrant",
        image: "previewImages/hydrant.PNG",
        file: "/assets/models/fire_hydrant_model/scene.gltf",
        scale: { x: 0.3, y: 0.3, z: 0.3 },
        minScale: 0.1,
        maxScale: 1
      statue: {
        name: "Statue",
        image: "previewImages/statue.PNG",
        file: "/assets/models/statue_model/scene.gltf",
        scale: { x: 0.5, y: 0.5, z: 0.5 },
        minScale: 0.05,
        maxScale: 2
      fountain: {
        name: "Fountain",
        image: "previewImages/fountain.PNG",
        file: "/assets/models/fountain_model/scene.gltf",
        scale: { x: 0.001, y: 0.001, z: 0.001 },
        minScale: 0.0005,
        maxScale: 0.005
      lantern: {
        name: "Lantern",
        image: "previewImages/lantern.jpg",
        file: "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/refs/heads/main/Models/Lantern/glTF/Lantern.gltf",
        scale: { x: 0.15, y: 0.15, z: 0.15 },
        minScale: 0.05,
        maxScale: 0.3
    const menus = ['menu-bar', 'add-menu', 'edit-menu', 'options-menu', 'map-window'];
    window.onload = () => {
initializeAddMenu(); // Fügt Sound zu allen Buttons hinzu const buttons = document.querySelectorAll("button, .menu-item"); buttons.forEach(button => { button.addEventListener("click", playButtonSound); }); }; function initializeAddMenu() { const addMenu = document.getElementById('add-menu'); addMenu.innerHTML = Object.entries(models) .map( ([key, model]) => ` <div class="menu-item" id="${key}-item" onclick="selectModel('${key}')"> <img src="${model.image}" alt="${model.name}" /> </div> ` ) .join('') + ` <div class="menu-item" onclick="showMenu('menu-bar')"> <img src="previewImages/back-icon.png" alt="Zurück" /> </div> `; } function showMenu(menuId) { const isMapWindow = menuId === 'map-window'; if (isMapWindow && !geoLocation) { console.log("Standort nicht geladen"); showInfoDialog("Ihr Standort wurde noch nicht geladen"); return; } menus.forEach(id => { document.getElementById(id).style.display = id === menuId ? 'flex' : 'none'; }); closeDynamicMenu(); if (menuId === 'menu-bar') clearSelectedModel(); else if (isMapWindow) init_map(); } function clearSelectedModel() { if (selectedPlacedModel) { selectedPlacedModel.traverse((child) => { if (child.isMesh) { child.material.emissive.setHex(0x000000); // Markierung entfernen } }); selectedPlacedModel = null; // Kein Modell mehr ausgewählt } } function selectModel(modelId) { const model = models[modelId]; if (model && model.file) { loadModel(model.file); showMenu('menu-bar'); } } function loadModel(filePath) { placeModel(filePath, reticle.position, (model) => { selectedPlacedModel = model; highlightSelectedModel(); showMenu('edit-menu'); }); }
function placeModel(filePath, position, onPlace = null) { const modelConfig = Object.values(models).find(model => model.file === filePath); const loader = new THREE.GLTFLoader(); loader.load( filePath, (gltf) => { const model = gltf.scene; if (modelConfig && modelConfig.scale) { model.scale.set(modelConfig.scale.x, modelConfig.scale.y, modelConfig.scale.z); } model.position.copy(position); model.isPlacedModel = true; model.modelConfig = modelConfig; scene.add(model); if (onPlace) { onPlace(model); } }, undefined, (error) => { console.error("Fehler beim Laden des Modells:", error); } ); } function highlightSelectedModel() { if (selectedPlacedModel) { removeHighlightFromAllModels(); selectedPlacedModel.traverse((child) => { if (child.isMesh) { child.material.emissive.setHex(0xff0000); // Rote Hervorhebung } }); } } function removeHighlightFromAllModels() { scene.traverse((child) => { if (child.isMesh && child.material && child.material.emissive) { child.material.emissive.setHex(0x000000); // Markierung entfernen } }); } function removeHighlightFromSelectedModel() { if (selectedPlacedModel) { selectedPlacedModel.traverse((child) => { if (child.isMesh) child.material.emissive.setHex(0x000000); // Markierung entfernen }); } } function selectModelFromScene(event) { const mouse = new THREE.Vector2( (event.clientX / window.innerWidth) * 2 - 1, -(event.clientY / window.innerHeight) * 2 + 1 ); const raycaster = new THREE.Raycaster(); raycaster.setFromCamera(mouse, camera); // Prüfe Kollisionen mit Objekten in der Szene const intersects = raycaster.intersectObjects(scene.children, true); if (intersects.length > 0) { // Finde das Hauptobjekt (Root-Parent), falls Mesh ausgewählt wurde let selectedObject = intersects[0].object; while (selectedObject.parent && selectedObject.parent !== scene) { selectedObject = selectedObject.parent;
} // Markiere das gesamte Modell als ausgewählt selectedPlacedModel = selectedObject; highlightSelectedModel(); showMenu("edit-menu"); } } function completeEditing() { removeHighlightFromSelectedModel(); closeDynamicMenu(); selectedPlacedModel = null; document.getElementById('edit-menu').style.display = 'none'; document.getElementById('menu-bar').style.display = 'flex'; } function openRotationMenu() { if (!selectedPlacedModel) { showInfoDialog("Kein Modell ausgewählt. Bitte wählen Sie ein Modell aus, bevor Sie es bearbeiten."); return; } // Holen Sie die aktuelle Y-Rotation des Modells (in Grad) const currentRotation = Math.round(THREE.MathUtils.radToDeg(selectedPlacedModel.rotation.y)); const dynamicMenu = document.getElementById("dynamic-menu"); dynamicMenu.style.display = "flex"; dynamicMenu.innerHTML = ` <h3>Rotation anpassen</h3> <label>Y-Achse: <span id="current-rotation">${currentRotation}</span>°<input type="range" min="0" max="360" step="10" onchange="updateRotation('y', this.value)"></label> <button onclick="closeDynamicMenu()">Zurück</button> `; } function updateRotation(axis, value) { if (selectedPlacedModel) { const radians = (value / 180) * Math.PI; selectedPlacedModel.rotation[axis] = radians; // Update der aktuellen Rotation im Menü const currentRotationDisplay = document.getElementById("current-rotation"); if (currentRotationDisplay) { currentRotationDisplay.textContent = value; // Zeige den aktuellen Wert in Grad an } } } function calculateBoundingBox(object) { const box = new THREE.Box3().setFromObject(object); const size = new THREE.Vector3(); box.getSize(size); return size; } function calculateMaxScale(object) { const boundingBox = calculateBoundingBox(object); const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; // Berechne die maximal mögliche Skalierung, um im Viewport zu bleiben const scaleWidth = viewportWidth / boundingBox.x; const scaleHeight = viewportHeight / boundingBox.y; // Wähle den kleineren Wert und reduziere ihn leicht, um sicherzugehen, dass das Objekt nicht über den Rand hinausgeht const safeScaleFactor = 0.95; // Puffer, um sicherzustellen, dass es nicht zu groß wird return Math.min(scaleWidth, scaleHeight) * safeScaleFactor; }
/** function openScaleMenu() { if (!selectedPlacedModel) { showInfoDialog("Kein Modell ausgewählt. Bitte wählen Sie ein Modell aus, bevor Sie es bearbeiten."); return; } // Berechne die maximale Skalierung für das spezifische Objekt const maxScale = calculateMaxScale(selectedPlacedModel); // Aktuelle Skalierung des Modells bestimmen const currentScale = selectedPlacedModel.scale.x; const dynamicMenu = document.getElementById("dynamic-menu"); dynamicMenu.style.display = "flex"; dynamicMenu.innerHTML = ` <h3>Skalierung anpassen</h3> <label>Größe: <span id="scale-value">${currentScale.toFixed(2)}</span><input type="range" min="0.01" max="${maxScale.toFixed(2)}" step="0.0001" value="${currentScale}" onchange="updateScale(this.value)"></label> <button onclick="closeDynamicMenu()">Zurück</button> `; } * */ function openScaleMenu() { if (!selectedPlacedModel) { showInfoDialog("Kein Modell ausgewählt. Bitte wählen Sie ein Modell aus, bevor Sie es bearbeiten."); return; } // Berechne die maximale Skalierung für das spezifische Objekt // const maxScale = calculateMaxScale(selectedPlacedModel); // Aktuelle Skalierung des Modells bestimmen const currentScale = selectedPlacedModel.scale.x; const minScale = selectedPlacedModel.modelConfig.minScale; const maxScale = selectedPlacedModel.modelConfig.maxScale; const step = (maxScale - minScale) / 100; // Dynamische Schrittgröße basierend auf Grenzen console.log("Slider-Werte:", { minScale, maxScale, currentScale }); const dynamicMenu = document.getElementById("dynamic-menu"); dynamicMenu.style.display = "flex"; dynamicMenu.innerHTML = ` <h3>Skalierung anpassen</h3> <label>Größe: <span id="scale-value">${currentScale.toFixed(2)}</span> <input type="range" min="${minScale}" max="${maxScale}" step="${step}" value="${currentScale}" onchange="updateScale(this.value)"></label> <button onclick="closeDynamicMenu()">Zurück</button> `; } function updateScale(value) { if (selectedPlacedModel) { const scale = parseFloat(value); selectedPlacedModel.scale.set(scale, scale, scale); // Anzeige des aktuellen Wertes aktualisieren const scaleValueDisplay = document.getElementById("scale-value"); if (scaleValueDisplay) { scaleValueDisplay.textContent = `${scale.toFixed(2)}`; } } } function deleteModel() { if (!selectedPlacedModel) {
showInfoDialog("Kein Modell ausgewählt. Bitte wählen Sie ein Modell aus, bevor Sie es löschen."); return; } // Dialog anzeigen const deleteDialog = document.getElementById('delete-confirmation-dialog'); deleteDialog.style.display = 'flex'; } function confirmDelete(shouldDelete) { const deleteDialog = document.getElementById('delete-confirmation-dialog'); deleteDialog.style.display = 'none'; if (shouldDelete && selectedPlacedModel) { scene.remove(selectedPlacedModel); selectedPlacedModel = null; showMenu('menu-bar'); } } function closeDynamicMenu() { const dynamicMenu = document.getElementById("dynamic-menu"); dynamicMenu.style.display = "none"; } function getAllPlacedModels() { return scene.children.filter(child => child.isPlacedModel === true); } function refreshMapDialog() { const mapDialog = document.getElementById('map-dialog'); mapDialog.style.display = 'flex'; } function closeMapDialog() { const mapDialog = document.getElementById('map-dialog'); mapDialog.style.display = 'none'; } async function activateXR(sceneData = null) { const canvas = document.createElement('canvas'); document.body.appendChild(canvas); const gl = canvas.getContext('webgl', { xrCompatible: true }); const renderer = new THREE.WebGLRenderer({ alpha: true, canvas, context: gl }); renderer.autoClear = false; scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(); camera.matrixAutoUpdate = false; const light = new THREE.DirectionalLight(0xffffff, 1); light.position.set(10, 10, 10); scene.add(light); const loader = new THREE.GLTFLoader(); loader.load("https://immersive-web.github.io/webxr-samples/media/gltf/reticle/reticle.gltf", (gltf) => { reticle = gltf.scene; reticle.visible = false; scene.add(reticle); }); currentSession = await navigator.xr.requestSession('immersive-ar', { optionalFeatures: ["dom-overlay"], domOverlay: { root: document.body }, requiredFeatures: ['hit-test'] }); currentSession.updateRenderState({ baseLayer: new XRWebGLLayer(currentSession, gl) }); const referenceSpace = await currentSession.requestReferenceSpace('local'); const viewerSpace = await currentSession.requestReferenceSpace('viewer');
const hitTestSource = await currentSession.requestHitTestSource({ space: viewerSpace }); document.getElementById('menu-bar').style.display = 'flex'; currentSession.addEventListener("end", () => { currentSession = null; menus.forEach(id => { document.getElementById(id).style.display = 'none'; }); }); canvas.addEventListener("pointerdown", selectModelFromScene); if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(position => { geoLocation = { latitude: roundTo(position.coords.latitude, 5), longitude: roundTo(position.coords.longitude, 5), }; console.log("GeoLocation: " + JSON.stringify(geoLocation)); if (sceneData) { sceneData.models.forEach((model) => { const offSet = leafletToThree(sceneData.lat, sceneData.lng) if (model.name) { const filePath = Object.values(models).find(m => model.name === m.name).file; const { x, z } = leafletToThree(model.lat, model.lng); const positionVector = new THREE.Vector3(x, model.position.y, z); placeModel(filePath, positionVector, (placed) => { if (model.rotation) { placed.rotation._x = model.rotation._x; placed.rotation._y = model.rotation._y; placed.rotation._z = model.rotation._z; } if (model.scale) { placed.scale.x = model.scale.x; placed.scale.y = model.scale.y; placed.scale.z = model.scale.z; } }); } }); } }, function(error) { console.error("Fehler bei der Geolokalisierung:", JSON.stringify(error)); }, {enableHighAccuracy: true, maximumAge: 2000, timeout: 5000}); } currentSession.requestAnimationFrame(function onXRFrame(time, frame) { currentSession.requestAnimationFrame(onXRFrame); gl.bindFramebuffer(gl.FRAMEBUFFER, currentSession.renderState.baseLayer.framebuffer); const pose = frame.getViewerPose(referenceSpace); if (pose) { const view = pose.views[0]; const viewport = currentSession.renderState.baseLayer.getViewport(view); renderer.setSize(viewport.width, viewport.height); camera.matrix.fromArray(view.transform.matrix); camera.projectionMatrix.fromArray(view.projectionMatrix); camera.updateMatrixWorld(true); const hitTestResults = frame.getHitTestResults(hitTestSource); if (hitTestResults.length > 0) { const hitPose = hitTestResults[0].getPose(referenceSpace); reticle.visible = true; reticle.position.set(hitPose.transform.position.x, hitPose.transform.position.y, hitPose.transform.position.z); reticle.updateMatrixWorld(true); }
renderer.render(scene, camera); } }); } function exitAR() { document.getElementById('confirmation-dialog').style.display = 'flex'; } function confirmExit(shouldExit) { if (shouldExit && currentSession) { currentSession.end(); } document.getElementById('confirmation-dialog').style.display = 'none'; } let soundTimeout = false; function playButtonSound() { if (!soundTimeout) { const sound = document.getElementById("button-sound"); sound.currentTime = 0; sound.play(); soundTimeout = true; setTimeout(() => { soundTimeout = false; }, 200); // Verzögerung von 200ms } }