<commit_before>'use strict';

/**
 * @ngdoc directive
 * @name midjaApp.directive:cartodbMap
 * @description
 * # cartodbMap
 */
angular.module('midjaApp')
  .directive('regionMap', function(L, $http, $rootScope, $q, dataService,
    formattingService, $uibModal) {

    // tileserver-gl-light URL
    var tileserverBaseUrl = "https://tiles.map.midja.org";
    var tileJsonUrlTmpl = _.template(
      tileserverBaseUrl + "/data/<%=regionType%>.json");
    var defaultStyles = {
      'regions': _.constant({
        weight: 1,
        color: '#000000',
        fillColor: '#ffffff',
        opacity: 1,
        fillOpacity: 0.7,
        fill: true
      }),
      'points': _.constant({
        weight: 0.1,
        color: '#000000',
        opacity: 0
      })
    };
    var regionHeadingTmpl = _.template("<%=name%> (<%=code%>)");

    // Modified VectorGrid which can take a layer order, so our points can be
    // consistently rendered above regions.
    var ModifiedVectorGrid = L.VectorGrid.Protobuf.extend({
      _getVectorTilePromise: function(coords) {
        var layerOrder = this.options.layerOrder || [];
        var overriddenMethod = _.bind(
          L.VectorGrid.Protobuf.prototype._getVectorTilePromise,
          this);
        return overriddenMethod(coords)
          .then(function(data) {
            var sortedKeys = _.sortBy(_.keys(data.layers), function(
              layer) {
              return layerOrder.indexOf(layer);
            });
            data.layers = _.zipObject(
              sortedKeys,
              _.map(sortedKeys, _.propertyOf(data.layers))
            );
            return data;
          });
      }
    })

    // Generate random ID for map
    var mapId = 'map-' + Math.random().toString().slice(2);
    // Create template using ID
    var template = _.template(
      '<div id="<%=id%>" class="region-map"></div>'
    )({
      id: mapId
    });

    var map = null;
    var regionLayers = null;

    var scopeAttributes = {
      'regionType': '=',
      'regions': '=',
      'choroplethTopic': '=',
      'bubblesTopic': '=',
      'choroplethVisible': '=',
      'bubblesVisible': '='
    }

    return {
      template: template,
      restrict: 'E',
      scope: scopeAttributes,
      replace: true,
      link: postLink
    };

    function setupEvents(scope) {
      function changeEmitter(baseEventName) {
        return function(newVal, oldVal) {
          if (!_.isEqual(newVal, oldVal)) {
            console.log(baseEventName + ':change', newVal, oldVal);
            scope.$emit(baseEventName + ':change', newVal, oldVal);
          }
        }
      }
      // Setup attribute watchers
      for (var attr in scopeAttributes) {
        scope.$watch(attr, changeEmitter(_.kebabCase(attr)));
      }
    }

    function getTileJSON(regionType) {
      return $http.get(tileJsonUrlTmpl({
          regionType: regionType
        }))
        .then(function(response) {
          return response.data;
        });
    }

    function featureStyleCreator(scope, layer) {
      return function(properties, zoom) {
        var hideStyle = _.constant({
          opacity: 0,
          fillOpacity: 0
        });
        var regionCode = properties.region_code
        var region = _.find(
          scope.regions,
          _.flow(
            _.property('code'),
            _.partial(_.isEqual, regionCode)));
        if (!region) {
          return hideStyle();
        }
        return (
          scope.styles[layer] || defaultStyles[layer] || hideStyle
        )(region);
      };
    }

    function setupHooks(scope) {
      var redrawVectorGrid = function redrawVectorGrid() {
        if (scope.vectorGrid) {
          scope.vectorGrid.redraw();
        }
      };
      scope.$on('region-type:change', function _regionTypeChange(evt, regionType) {
        // Create new VectorGrid
        getTileJSON(regionType).then(function(metadata) {
          var styles = _.fromPairs(_.map(
            metadata.vector_layers,
            _.flow(
              _.property('id'),
              function(layerId) {
                return [layerId, featureStyleCreator(scope,
                  layerId)];
              }
            )));
          var bounds = L.latLngBounds(_.map(
            _.chunk(metadata.bounds, 2),
            function(p) {
              return L.latLng(p[1], p[0]);
            }));
          var vectorGrid = new ModifiedVectorGrid(metadata.tiles[0], {
            attribution: metadata.attribution,
            bounds: bounds,
            interactive: true,
            layerOrder: ['regions', 'points'],
            rendererFactory: L.canvas.tile,
            vectorTileLayerStyles: styles
          });
          var resolveRegion = function (regionCode) {
            return _.find(<commit_msg>Faster repaint using some internal APIs<commit_after>'use strict';

/**
 * @ngdoc directive
 * @name midjaApp.directive:cartodbMap
 * @description
 * # cartodbMap
 */
angular.module('midjaApp')
  .directive('regionMap', function(L, $http, $rootScope, $q, dataService,
    formattingService, $uibModal) {

    // tileserver-gl-light URL
    var tileserverBaseUrl = "https://tiles.map.midja.org";
    var tileJsonUrlTmpl = _.template(
      tileserverBaseUrl + "/data/<%=regionType%>.json");
    var defaultStyles = {
      'regions': _.constant({
        weight: 1,
        color: '#000000',
        fillColor: '#ffffff',
        opacity: 1,
        fillOpacity: 0.7,
        fill: true
      }),
      'points': _.constant({
        weight: 0.1,
        color: '#000000',
        opacity: 0
      })
    };
    var regionHeadingTmpl = _.template("<%=name%> (<%=code%>)");

    // Modified VectorGrid which can take a layer order, so our points can be
    // consistently rendered above regions.
    var ModifiedVectorGrid = L.VectorGrid.Protobuf.extend({
      _getVectorTilePromise: function(coords) {
        var layerOrder = this.options.layerOrder || [];
        var overriddenMethod = _.bind(
          L.VectorGrid.Protobuf.prototype._getVectorTilePromise,
          this);
        return overriddenMethod(coords)
          .then(function(data) {
            var sortedKeys = _.sortBy(_.keys(data.layers), function(
              layer) {
              return layerOrder.indexOf(layer);
            });
            data.layers = _.zipObject(
              sortedKeys,
              _.map(sortedKeys, _.propertyOf(data.layers))
            );
            return data;
          });
      }
    })

    // Generate random ID for map
    var mapId = 'map-' + Math.random().toString().slice(2);
    // Create template using ID
    var template = _.template(
      '<div id="<%=id%>" class="region-map"></div>'
    )({
      id: mapId
    });

    var map = null;
    var regionLayers = null;

    var scopeAttributes = {
      'regionType': '=',
      'regions': '=',
      'choroplethTopic': '=',
      'bubblesTopic': '=',
      'choroplethVisible': '=',
      'bubblesVisible': '='
    }

    return {
      template: template,
      restrict: 'E',
      scope: scopeAttributes,
      replace: true,
      link: postLink
    };

    function setupEvents(scope) {
      function changeEmitter(baseEventName) {
        return function(newVal, oldVal) {
          if (!_.isEqual(newVal, oldVal)) {
            console.log(baseEventName + ':change', newVal, oldVal);
            scope.$emit(baseEventName + ':change', newVal, oldVal);
          }
        }
      }
      // Setup attribute watchers
      for (var attr in scopeAttributes) {
        scope.$watch(attr, changeEmitter(_.kebabCase(attr)));
      }
    }

    function getTileJSON(regionType) {
      return $http.get(tileJsonUrlTmpl({
          regionType: regionType
        }))
        .then(function(response) {
          return response.data;
        });
    }

    function featureStyleCreator(scope, layer) {
      return function(properties, zoom) {
        var hideStyle = _.constant({
          opacity: 0,
          fillOpacity: 0
        });
        var regionCode = properties.region_code
        var region = _.find(
          scope.regions,
          _.flow(
            _.property('code'),
            _.partial(_.isEqual, regionCode)));
        if (!region) {
          return hideStyle();
        }
        return (
          scope.styles[layer] || defaultStyles[layer] || hideStyle
        )(region);
      };
    }

    function setupHooks(scope) {
      var redrawVectorGrid = function redrawVectorGrid() {
        if (scope.vectorGrid) {
          scope.vectorGrid.smartRedraw();
        }
      };
      scope.$on('region-type:change', function _regionTypeChange(evt, regionType) {
        // Create new VectorGrid
        getTileJSON(regionType).then(function(metadata) {
          var styles = _.fromPairs(_.map(
            metadata.vector_layers,
            _.flow(
              _.property('id'),
              function(layerId) {
                return [layerId, featureStyleCreator(scope,
                  layerId)];
              }
            )));
          var bounds = L.latLngBounds(_.map(
            _.chunk(metadata.bounds, 2),
            function(p) {
              return L.latLng(p[1], p[0]);
            }));
          var vectorGrid = new ModifiedVectorGrid(metadata.tiles[0], {
            attribution: metadata.attribution,
            bounds: bounds,
            interactive: true,
            layerOrder: ['regions', 'points'],
            rendererFactory: L.canvas.tile,
            vectorTileLayerStyles: styles,
            getFeatureId: function(feature) {
              var randomId = 'feature-'+(Math.random()+"").slice(2);
              return randomId;
            }
          });
          // This uses internal APIs in VectorGrid,
          // but is *much* faster than vectorGrid.redraw().
          vectorGrid.smartRedraw = _.debounce(function() {
            _.values(vectorGrid._vectorTiles).forEach(function(tile) {
              _.keys(tile._features).forEach(function(featureId) {
                vectorGrid.resetFeatureStyle(featureId);
              });
              tile._redraw();
            });
          }, 100);
          var resolveRegion = function (regionCode) {
            return _.find(
{'fraction_non_alphanumeric': 0.12797182271793367, 'fraction_numerical': 0.005478915957342726, 'mean_word_length': 1.8753867791842476, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '346971', 'n_tokens_mistral': 2949, 'n_tokens_neox': 2841, 'n_words': 586}