import { ThreeJSOverlayView } from '@googlemaps/three'; import * as THREE from 'three'; import { SVGLoader } from 'three/examples/jsm/loaders/SVGLoader.js'; export class SharedThreeJSOverlayView extends ThreeJSOverlayView { meshes: any = []; geometries: any = []; materials: any = []; positions: any = []; loader = new SVGLoader(); svgString = ` <svg class="base-svg" width="32" height="39" viewBox="0 0 32 39" fill="none" xmlns="http://www.w3.org/2000/svg"> <g class="border"> <path d="M4.68629 27.9907C-1.5621 21.7771 -1.5621 11.703 4.68629 5.4895C10.9347 -0.724038 21.0653 -0.724038 27.3137 5.4895C33.5621 11.703 33.5621 21.7771 27.3137 27.9907L16.7071 38.5381C16.3166 38.9264 15.6834 38.9264 15.2929 38.5381L4.68629 27.9907Z" fill="white"/> </g> <g class="background" filter="url(#filter1_i_6001_29070)"> <path fill-rule="evenodd" clip-rule="evenodd" d="M6.09654 6.90766C0.634484 12.3393 0.634486 21.1409 6.09654 26.5725L16 36.4207L25.9035 26.5725C31.3655 21.1409 31.3655 12.3393 25.9035 6.90766C20.4352 1.46991 11.5648 1.4699 6.09654 6.90766Z" fill="#009AFF"/> </g> <defs> <filter id="filter1_i_6001_29070" x="2" y="2.82935" width="28" height="35.5914" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset dy="2"/> <feGaussianBlur stdDeviation="2"/> <feComposite in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0"/> <feBlend mode="normal" in2="shape" result="effect1_innerShadow_6001_29070"/> </filter> </defs> </svg> `; constructor() { super(); } createMeshFromSVG() { const result = this.loader.parse(this.svgString); const group = new THREE.Group(); result.paths.forEach((path) => { const material = new THREE.MeshBasicMaterial({ color: path.color, side: THREE.DoubleSide, depthWrite: false }); const shapes = path.toShapes(true); shapes.forEach((shape) => { const geometry = new THREE.ShapeGeometry(shape); const bufferGeometry = geometry.toNonIndexed(); bufferGeometry.center(); const mesh = new THREE.Mesh(bufferGeometry, material); group.add(mesh); }); }); this.meshes.push(group); // Add to meshes array return group; } onAdd() { this.positions.forEach((position: any) => { const mesh = this.createMeshFromSVG(); const group = new THREE.Group(); // group.scale.set(80000, -80000, 0); group.add(mesh); this.updateMeshPosition(group, position); this.scene.add(group); }); } // eslint-disable-next-line @typescript-eslint/no-unused-vars onDraw({gl, transformer}: google.maps.WebGLDrawOptions) { const mapZoom = this.getMap().getZoom(); const baseScale = 80000; // Define your base scale at zoom level 0. const zoomScaleFactor = Math.pow(2, mapZoom - 1); // Adjust scale based on zoom. const scale = (baseScale / zoomScaleFactor); this.meshes.forEach((mesh: any) => { const bbox = new THREE.Box3().setFromObject(mesh); // Adjust the scale based on zoom level mesh.scale.set(scale, -scale, 0); // Optionally update position or other transformations if necessary mesh.position.set(0, (bbox.max.y - bbox.min.y) / 2, 0); }); // Original render logic this.camera.projectionMatrix.fromArray( transformer.fromLatLngAltitude(this.anchor, this.rotationArray) ); gl.disable(gl.SCISSOR_TEST); this.onBeforeDraw(); this.renderer.render(this.scene, this.camera); this.renderer.resetState(); if (this.animationMode === "always") this.requestRedraw(); } updateMeshPosition(mesh: any, latLng: any) { // Convert the new LatLng to world coordinates (Three.js space) const worldPosition = this.latLngAltitudeToVector3(latLng); // Update the mesh's position with the new world coordinates mesh.position.set(worldPosition.x, worldPosition.y, 0); // Notify Three.js that the position has been updated mesh.updateMatrixWorld(); } }