<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8" />
    <title>Example - example-example52-production</title>
    <script data-require="lodash.js@*" data-semver="3.8.0" src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.8.0/lodash.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
    <script src="http://cesiumjs.org/Cesium/Build/CesiumUnminified/Cesium.js"></script>
    <script src="http://stepplus.co.il/images/svg2png.js"></script>
    <link rel="stylesheet" href="http://cesiumjs.org/Cesium/Build/CesiumUnminified/Widgets/widgets.css" />
    <link rel="stylesheet" href="style.css" />
  </head>

  <body ng-app="myApp">
    <div ng-controller="mainAppCtrl as mainAppCtrl">
      <div 
        cesium-directive="mainAppCtrl.cesiumConfig" 
        cesium-buttons
        cesium-polygon-drawer
        id="cesium1" class="cesiumContainer">
        <button
          ng-disabled="mainAppCtrl.drawing"
          ng-click="mainAppCtrl.draw()">Start Drawing</button>
        <button
          ng-disabled="!mainAppCtrl.drawing"
          ng-click="mainAppCtrl.stopDrawing()">Stop Drawing</button>
      </div>
    </div>
    <script src="app.js"></script>
  </body>

</html>
"use strict";


angular.module('myApp', ['ngCesium', 'ngCesiumButtons', 'ngCesiumPolygonDrawer'])
    .controller('mainAppCtrl', ['$scope', function($scope){
        function resolve(polygon){
          vm.drawing = false;
        }
        
        function notify(polygon){
          // do something with the polygon
        }
        
        var vm = this;

        // config variable in the main controller context
        vm.cesiumConfig = {
        };
        
        vm.stopDrawing = function(){
          vm.cesiumConfig.cesiumInstance.cesiumPolygonDrawer.stopDrawing();
        }
        
        vm.draw = function(){
          vm.drawing = true;
          
          var promise = vm.cesiumConfig.cesiumInstance.cesiumPolygonDrawer.startDrawing();
          promise.then(resolve, null, notify);
        }
    }]);

// other app stuff can come here - like routing, more directives and services


// define the ngCesium module
angular.module('ngCesium', [])
    //define the cesium directive
    .directive('cesiumDirective', function($interval, cesiumService){
    // return the directive definition object
    return {
      restrict: "EA",
      controllerAs: "cesiumCtrl",
      priority: 500,
      scope: {
        cesiumDirective: "="
      },
      bindToController: true,
      controller: function($scope, $element){
        this.cesiumViewer = new Cesium.Viewer($element[0], {
          baseLayerPicker: false,
          fullscreenButton: false,
          homeButton: false,
          sceneModePicker: false,
          selectionIndicator: false,
          timeline: false,
          animation: false,
          geocoder: false
        });
        
        // this makes sure our parent app gets its cesiumInstance back
        this.cesiumDirective.cesiumInstance = new cesiumService(this.cesiumViewer);
      },
      // define the "link" function
      link: function(scope, element, attr, ctrl){
        
      }
    };
  })
    // define the cesium factory
    .factory('cesiumService', function(){
        // constructor
        function cesiumService(viewer){
            this._viewer = viewer;
        };

        cesiumService.prototype = {
            addEntity: function addEntity(options){
                return this._viewer.entities.add(options);
            },
            removeEntity: function removeEntity(id){
                this._viewer.entities.removeById(id);
            },
            setCallbackProperty: function(property){
                return new Cesium.CallbackProperty(function(){
                    return property;
                }, false);
            },
            getEventHandler: function(){
                return new Cesium.ScreenSpaceEventHandler(this._viewer.scene.canvas);
            }
        };

        return cesiumService;
    })
    .controller('cesiumCtrl', ['$scope', function($scope) {

    }]);

// define the ngCesiumButtons module (dependant on ngCesium)
angular.module('ngCesiumButtons', ['ngCesium'])
    // add templates into cache
    .run(function($templateCache){
        // cache our buttons template
        $templateCache.put('ngCesium/cesiumButtons',
            '<div class="cesiumButtonsWrapper">\
            {{cesiumButtonsCtrl.test}}\
              <button ng-click="cesiumButtonsCtrl.cesiumButtonsInstance.addEntity()">Add Entity</button>\
              <button ng-disabled="!cesiumButtonsCtrl.cesiumButtonsInstance.ngCesiumInstance._viewer.entities.values.length" \
              ng-click="cesiumButtonsCtrl.cesiumButtonsInstance.removeEntity()">Remove Entity</button>\
            </div>')
    })
    .directive('cesiumButtons', function(cesiumButtonsService, $compile){
    return {
      restrict: 'A',
      priority: -500,
      require: 'cesiumDirective',
      link: function(scope, element, attr, ctrl){
        // create an isolate scope for this directive
        var isoScope = scope.$new(true);
        
        // add parent's controller to the scope
        isoScope.cesiumButtonsCtrl = ctrl;
        
        // create a cesiumButtonsInstance and add it to our controller
        isoScope.cesiumButtonsCtrl.cesiumButtonsInstance = new cesiumButtonsService(ctrl.cesiumDirective.cesiumInstance);
        
        // get the template using our API
        var template = isoScope.cesiumButtonsCtrl.cesiumButtonsInstance.getTemplate();
        
        // turn the template into an angular element
        template = angular.element(template);
        
        // compile the template
        template = $compile(template)(isoScope);
        
        // inject into the DOM just below the cesium viewer
        element.append(template);
      }
    }
  })
    .factory('cesiumButtonsService', function($templateCache){
        // constructor
        function cesiumButtonsService(ngCesiumInstance){
            this.ngCesiumInstance = ngCesiumInstance;
            ngCesiumInstance.cesiumButtons = this;
        };

        cesiumButtonsService.prototype = {
            getTemplate: function(){
                return $templateCache.get('ngCesium/cesiumButtons');
            },
            addEntity: function(){
                var options = {
                    id: _.uniqueId('entity_'),
                    point: {
                        pixelSize: 32
                    },
                    position: new Cesium.Cartesian3.fromDegrees((98+Math.random()*5) * 180/Math.PI, (47+Math.random()*5) * 180/Math.PI, 500)
                }
                this.ngCesiumInstance.addEntity(options);
            },
            removeEntity: function(){
                var entityId = this.ngCesiumInstance._viewer.entities.values[_.random(0, this.ngCesiumInstance._viewer.entities.values.length-1)].id;
                this.ngCesiumInstance.removeEntity(entityId);
            }
        }

        return cesiumButtonsService;
    })

// define the ngCesiumPolygonDrawer module (dependant on ngCesium)
angular.module('ngCesiumPolygonDrawer', ['ngCesium'])
    .directive('cesiumPolygonDrawer', function(cesiumPolygonDrawerService){
        return {
            restrict: 'A',
            require: 'cesiumDirective',
            link: function(scope, element, attr, ctrl){
                // create an isolate scope for this directive
                var isoScope = scope.$new(true);
            
                // add parent's controller to the scope
                isoScope.cesiumPolygonDrawerCtrl = ctrl;
                // create a cesiumButtonsInstance and add it to our controller
                isoScope.cesiumPolygonDrawerCtrl.cesiumPolygonDrawerInstance = new cesiumPolygonDrawerService(ctrl.cesiumDirective.cesiumInstance);
            }
        };
    })
    .factory('cesiumPolygonDrawerService', function($q){
        // constructor
        function cesiumPolygonDrawerService(ngCesiumInstance){
          var that = this;
          that.ngCesiumInstance = ngCesiumInstance;
          ngCesiumInstance.cesiumPolygonDrawer = that;

          // initialize the polygon's positions - we will add more points as we draw
          that.positions = [];

          // create the polygon entity
          var options = {
              id: 'cesium drawing polygon',
              polyline: {
                  show: true,
                  positions: ngCesiumInstance.setCallbackProperty(that.positions)
              },
              polygon: {
                  show: false,
                  hierarchy: ngCesiumInstance.setCallbackProperty(that.positions)
              }
          }

          that.polygonEntity = ngCesiumInstance.addEntity(options);

          // setup the events handler
          that.eventsHandler = ngCesiumInstance.getEventHandler();
          
          // setup the drawing flah
          that.currentlyDrawing = false;
        };
        
        cesiumPolygonDrawerService.prototype = {
            // this starts the drawing on the cesium viewer
            startDrawing: function(options){
              function addPolylinePoint(click){
                var cartesian = that.ngCesiumInstance._viewer.camera.pickEllipsoid(click.position, that.ngCesiumInstance._viewer.scene.globe.ellipsoid);
                if (!cartesian) return;
                // reset the positions array if we start a new polygon
                if (that.currentlyDrawing === false){
                  that.positions.length = 0;
                  that.polygonEntity.polyline.show = true;
                  that.polygonEntity.polygon.show = false;
                  that.currentlyDrawing = true;
                }
                that.positions.push(cartesian);
              }
              
              function updatePolyline(position){
                if (that.currentlyDrawing === false) return;
                var cartesian = that.ngCesiumInstance._viewer.camera.pickEllipsoid(position.endPosition, that.ngCesiumInstance._viewer.scene.globe.ellipsoid);
                if (!cartesian) return;
                  
                if (that.positions.length > 1)
                  that.positions.splice(that.positions.length-1, 1, cartesian);
                else
                  that.positions.push(cartesian);
                
              }
              
              function closePolygon(click){
                that.currentlyDrawing = false; // reset the drawing status
                that.positions.splice(that.positions.length-1, 1); // remove the last point
                
                // hide polyline, show polygon
                that.polygonEntity.polyline.show = false;
                that.polygonEntity.polygon.show = true;
                
                // send the polygon to the sending function
                that.deferred.notify(that.polygonEntity.polygon);
              }
              
              var that = this;
              
              if (angular.isDefined(options) && angular.isDefined(options.color)){
                that.polygonEntity.polygon.material = options.color;
              }
              
              // setup event listeners
              that.eventsHandler.setInputAction(addPolylinePoint, Cesium.ScreenSpaceEventType.LEFT_CLICK);
              that.eventsHandler.setInputAction(updatePolyline, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
              that.eventsHandler.setInputAction(closePolygon, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
              
              // setup the promise
              that.deferred = $q.defer();
              return that.deferred.promise;
            },
            stopDrawing: function(){
              var that = this;
              // destroy event listeners
              that.eventsHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
              that.eventsHandler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
              that.eventsHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
              
              // resolve the promise
              that.deferred.resolve(this.polygonEntity.polygon);
            }
        }

        return cesiumPolygonDrawerService;
    });
.cesiumContainer{
  height: 50%;
  width: 100%;
}