FacundoGFlores
FacundoGFlores

Reputation: 8108

Three js - Google map layer picking

I am using the following library: google-maps-api-threejs-layer Now I want to add, a picking feature.

So, this is my modified code:

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Three.js Layer - Google Maps API</title>
    <style>
      html, body, #map-div {
        margin: 0;
        padding: 0;
        height: 100%;
      }
    </style>

    <script src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
    <script src="data.js"></script>
    <script src="styles.js"></script>
    <script src="../lib/detector.js"></script>
    <script src="../lib/dat.gui.js"></script>
    <script src="../lib/three.js"></script>
    <script src="../threejs-layer.js"></script>

    <script>
      var vector = new THREE.Vector2();
      var raycaster = new THREE.Raycaster();
      var myLayer;
      function init() {
        
        var container = document.getElementById('map-div');
        
        var map = new google.maps.Map(container, {
          zoom: 3,
          mapTypeControl: false,
          center: new google.maps.LatLng(10, 0),
          mapTypeId: google.maps.MapTypeId.TERRAIN,
          styles: styles
        });

        // if you add renderertype:'Canvas' to the options for ThreejsLayer, you can force the usage of CanvasRenderer
        myLayer = new ThreejsLayer({ map: map }, function(layer){
          if (layer.renderertype=='Canvas' || !Detector.webgl) {
            texture = new THREE.Texture(generateSprite());
            particles = new THREE.Object3D();
            material = new THREE.SpriteMaterial({
              size: 20,
              opacity: 1,
              depthTest: false,
              transparent: false
            });


            photos.forEach(function (photo) {
              var particle = new THREE.Sprite(material);
              var location = new google.maps.LatLng(photo[0], photo[1]),
                vertex = layer.fromLatLngToVertex(location);

              particle.position.set(vertex.x, vertex.y, 0);
              particle.scale.x = particle.scale.y = 20;
              particles.add(particle);
              material.size = 20;
            });
          } else {
            var geometry = new THREE.Geometry(),
              texture = new THREE.Texture(generateSprite()),
              material, particles;

            photos.forEach(function(photo){
              var location = new google.maps.LatLng(photo[0], photo[1]),
                vertex = layer.fromLatLngToVertex(location);

              geometry.vertices.push( vertex );
            });

            texture.needsUpdate = true;

            material = new THREE.PointCloudMaterial({
              size: 20,
              opacity: 0.3,
              blending: THREE.AdditiveBlending,
              depthTest: false,
              transparent: false
            });

            particles = new THREE.PointCloud( geometry, material );
          }
          layer.add( particles );

          gui = new dat.GUI();

          function update(){
            if (layer.renderertype=='Canvas' || !Detector.webgl)  material.map = new THREE.Texture(generateSprite(material.size));
            layer.render();
          }

          gui.add(material, 'size', 2, 100).onChange(update);
          gui.add(material, 'opacity', 0.1, 1).onChange(update);

        });
      }

      function onClick( event ) {
          vector.x = ( (event.screenX - myLayer.renderer.domElement.offsetLeft) / myLayer.renderer.domElement.clientWidth ) * 2 - 1;
          vector.y = - ( (event.screenY - myLayer.renderer.domElement.offsetTop) / myLayer.renderer.domElement.clientHeight ) * 2 + 1;
          raycaster.setFromCamera(vector, myLayer.camera);

          var intersects = raycaster.intersectObjects(myLayer.scene.children, true);
          if(intersects.length > 0){
              console.log(vector.x, vector.y);
          }
      }document.addEventListener('click', onClick, false);

      function generateSprite(size) {

        var canvas = document.createElement('canvas'),
          context = canvas.getContext('2d'),
          gradient;
        size = size || 20;
        canvas.width = size;
        canvas.height = size;

        gradient = context.createRadialGradient(
          canvas.width / 2, canvas.height / 2, 0,
          canvas.width / 2, canvas.height / 2, canvas.width / 2
        );

        gradient.addColorStop(1.0, 'rgba(255,255,255,0)');
        gradient.addColorStop(0.0, 'rgba(255,255,255,1)');

        context.fillStyle = gradient;
        context.fillRect(0, 0, canvas.width, canvas.height);

        return canvas;
      }

      document.addEventListener('DOMContentLoaded', init, false);
    </script>

  </head>

  <body>
    <div id="map-div"></div>
  </body>
</html>

As you can see, I am using the raycaster. So, maybe you want an updated three js library: link.

OK, so the problem is when I click, near the geometries (outside the boxes) I can intersect elements, so intersects.length is greater than zero. I only want to intersect pixels inside the geometries in the map. How can I fix it?

EDIT:

I created a repo: https://github.com/FacundoGFlores/google-maps-api-threejs-layer

Upvotes: 0

Views: 1540

Answers (1)

Martin Schuhfu&#223;
Martin Schuhfu&#223;

Reputation: 6986

In your example you are using a PointCloud to render the points on the map. As you cannot reasonably expect any raycasting to precisely hit any single point, three.js uses a treshold-value for the raycaster that might need to get adjusted depending on your use-case.

Upvotes: 1

Related Questions