Search code examples
javascriptwebgl-globe

WebGL Globe - multiple datapoints from one vertex


I have been able to follow the source code and get my WebGL globe to work like the example. I am trying to customize this Globe. I have more than one metric that I need to show on the globe. e.g. Instead of showing just the whole population on the globe, I want to show female population as well as male population from the same vertex point. I have been reading through every line in Globe.js but am still confused on how I can achieve this. Can someone point me towards the right direction?


Solution

  • Mh, nice expansion of this demo. The approach coming to my mind would be to change the for-loops in addData()...

    function addData(data, opts) {
      var lat, lng, size, color, i, step, colorFnWrapper;
      // NEW:
      var pointsAtPosition = {};
      var offsetAtPosition = {};
      var pointPosition = '';
      var offset = 0;
    
      ...
    

    The construction of this._baseGeometry seems to set the color, so there is some heavy rewriting here. Why do I handle location indexing with an object and stringifying my lat/long? I tried nested objects first and it was a performance disaster! But maybe there is something even smarter?

      if (this._baseGeometry === undefined) {
        this._baseGeometry = new THREE.Geometry();
    
        for (i = 0; i < data.length; i += step) {
          lat = data[i];
          lng = data[i + 1];
          size = 0;
          offset = 0;
    
        pointPosition = '' + lat + '/' + lng;
    
        if (!pointsAtPosition[pointPosition]) {
            pointsAtPosition[pointPosition] = 1;
            color = {r: 255, g: 0, b: 0};
        } else {
            pointsAtPosition[pointPosition] += 1;
            // set color according to point count
            switch (pointsAtPosition[pointPosition]) {
            default:
                color = {r: 0, g: 0, b: 0};
                break;
            case 2:
                color = {r: 0, g: 255, b: 0};
                break;
            case 3:
                color = {r: 0, g: 0, b: 255};
                break;
            }
        }
    
          addPoint(lat, lng, size, offset, color, this._baseGeometry);
        }
      }
    

    ... looping the second time we set the positions... we improve upon the original code by adding an offset that adds up with each entry for the same lat/lng.

    for (i = 0; i < data.length; i += step) {
        lat = data[i];
        lng = data[i + 1];
    
        size = data[i + 2];
        size = size * 200;
    
        color = 0;
    
        pointPosition = '' + lat + '/' + lng;
    
        if (offsetAtPosition[pointPosition] === undefined) {
            offsetAtPosition[pointPosition] = 0;
        }
    
        offset = offsetAtPosition[pointPosition];
        offsetAtPosition[pointPosition] += size;
    
        addPoint(lat, lng, size, offset, color, subgeo);
    }
    

    Now all that's left is to adjust addPoint() so that it takes offset as an argument.

    function addPoint(lat, lng, size, offset, color, subgeo) {
      var phi = (90 - lat) * Math.PI / 180;
      var theta = (180 - lng) * Math.PI / 180;
    
      point.position.x = (200 + offset) * Math.sin(phi) * Math.cos(theta);
      point.position.y = (200 + offset) * Math.cos(phi);
      point.position.z = (200 + offset) * Math.sin(phi) * Math.sin(theta);
    
      ...
    

    Changing the data JSON file we are now able to display multiple entries per location!

    [
     ["1990",[6,9,0.1,6,9,0.2,6,9,0.2]],
     ["1995",[-35,-64,0.001,21,76,0.001,6,9,0.2]],
     ["2000",[6,159,0.001,21,76,0.001,6,9,0.2]]
    ]
    

    enter image description here