Source: src/js/views/maps/CesiumGeohashes.js

define(["backbone",
        "cesium",
        "nGeohash",
        "models/maps/assets/CesiumGeohash"],
  function(Backbone, Cesium, geohash, CesiumGeohash){

    /**
    * @class CesiumGeohashes
    * @name CesiumGeohashes
    * @classcategory Views/Maps
    * @extends Backbone.View
    * @classdesc Draws geohash boxes and their associated count/density in a Cesium {@link CesiumWidgetView}. Uses the {@link CesiumGeohash} Map Asset for the geohash data.
    * @since 2.22.0
    */
    return Backbone.View.extend(/** @lends CesiumGeohashes.prototype */{

        cesiumViewer: null,

        /**
         * A reference to the CesiumGeohash MapAsset model that is rendered in this view
         * @type {CesiumGeohash}
         * @since 2.22.0
         */
        cesiumGeohash: null,
        
        render: function(){

            //If there is no CesiumGeohash model, exit without rendering
            if(!this.cesiumGeohash){
                return;
            }

           this.entities = this.cesiumGeohash.get("cesiumModel").entities;

            if(this.cesiumGeohash.get('status') == "ready"){
               this.drawGeohashes();
            }

            //When the status changes, re-render this view
            this.listenTo(this.cesiumGeohash, "change:status", this.drawGeohashes);

            this.listenToMovement();

        },

        /**
         * Listens to Cesium Camera movement so the geohash level can change when the camera zooms in
         * @since 2.22.0
         */
        listenToMovement: function(){
            //Listen to camera movement to change the geohash level
            let view = this;
            this.cesiumViewer.scene.camera.moveEnd.addEventListener(function () {
                //Get the position of the Cesium camera
                let c = Cesium.Cartographic.fromCartesian(new Cesium.Cartesian3(view.cesiumViewer.scene.camera.position.x, view.cesiumViewer.scene.camera.position.y, view.cesiumViewer.scene.camera.position.z))
                //Set the geohash level based on the camera position height
                view.cesiumGeohash.setGeohashLevel(c.height);
            });
        },
        
        /**
         * Draws the geohash polygons on the Cesium map (via {@link CesiumGeohash}) associated with this view. Draws a number representing the
         * count/density associated with that polygon (e.g. number of datasets in that area).
         * @since 2.22.0
         */
        drawGeohashes: function(){

            let polygon,
                entities = this.entities,
                dataSource = this.dataSource,
                viewer = this.cesiumViewer,
                hue = this.cesiumGeohash.get("hue");

            //If there is no CesiumGeohash model, exit without rendering
            if(!this.cesiumGeohash){
                return;
            }        

            //Remove all the Entities from the Cesium layer
            entities.removeAll();

            let counts = this.cesiumGeohash.get("geohashCounts");

            for(let i=0; i < counts.length; i+=2){
          
              let hash = counts[i],
                  bbox = geohash.decode_bbox(hash),
                  count = counts[i+1],
                  alpha = count/this.cesiumGeohash.get("totalCount") + 0.5;
          
              let polygon = entities.add({
                  polygon : {
                  hierarchy : Cesium.Cartesian3.fromDegreesArray([ 
                          bbox[1], bbox[0],
                          bbox[3], bbox[0],  
                          bbox[3], bbox[2],
                          bbox[1], bbox[2] ]),
                  height : 1000,
                  material : Cesium.Color.fromHsl(hue/360, 0.5, 0.6, alpha),
                  outline : true,
                  outlineColor : Cesium.Color.WHITE
                },
                show: true
              });
          
              let label = entities.add({
                position : Cesium.Cartesian3.fromDegrees((bbox[3]+bbox[1])/2, (bbox[2]+bbox[0])/2),
                label : {
                    text : count.toString(),
                    font : '14pt monospace',
                    style: Cesium.LabelStyle.FILL,
                    outlineWidth : 0,
                    scaleByDistance : new Cesium.NearFarScalar(1.5e2, 5.0, 8.0e6, 0.7)
                },
                show: true
              });
          
            }

            viewer.dataSourceDisplay.dataSources.add(this.cesiumGeohash.get("cesiumModel"))

        }
          

    });

});