<commit_before>function ImageViewer(imageDivName, img) {
  this.divName = imageDivName;
  this.img = img;
  var that = this;
  $('#' + this.divName).html('');

  var imgWidth = this.img.width;
  var imgHeight = this.img.height;
  var imgCenter = [ imgWidth / 2, -imgHeight / 2 ];
  var url = this.img.url;
  var crossOrigin = 'anonymous';
  var gsd = 2.6; // meter/pix
  // TODO the above gsd is just for example; from metadata, get the real gsd
  var fullSizeMaxGsd = 30;
  var cutoffResolution = fullSizeMaxGsd / gsd;
  var imgWidthMeters = gsd * imgWidth;
  var imgHeightMeters = gsd * imgHeight;
  var originalClipSize = 1000 / gsd;
  var bigImageMaxZoom;

  // Create a 'fake' projection for the openlayers map to use
  var proj = new ol.proj.Projection({
    code : 'ZOOMIFY',
    units : 'pixels',
    extent : [ 0, 0, imgWidth, imgHeight ]
  });

  // Zoomify image source
  var bigImageSource = new ol.source.Zoomify({
    url : url,
    size : [ imgWidth, imgHeight ],
    crossOriginKeyword : crossOrigin,
  });
  bigImageSource.tileGrid.maxZoom = 1;
  // TODO calculate the actual max zoom level for this source
  
  var littleImageSource = new ol.source.Zoomify({
    url : url,
    size : [ imgWidth, imgHeight ],
    crossOriginKeyword : crossOrigin,
  });

  // Create the big image layer, visible when zoomed all the way out
  var bigImageLayer = new ol.layer.Tile({
    source : bigImageSource,
  });

  // Layer that restricts the image size at higher resolutions
  // (keepin the contract happy)
  var littleImageLayer = new ol.layer.Tile({
    source: littleImageSource,
  })

  // Vector layer for the planet logo and distribution statement
  var vectorLayer = new ol.layer.Vector({
    source: new ol.source.Vector()
  });

  // Create the map itself
  this.map = new ol.Map({
    interactions : ol.interaction.defaults(),
    layers : [ bigImageLayer, littleImageLayer, vectorLayer ],
    target : this.divName,
    controls : [], // Disable default controls
    view : new ol.View({
      projection : proj,
      center : imgCenter,
      zoom : 1,
      extent: [0, -imgHeight, imgWidth, 0]
    })
  });

  // Check in the db whether it's a planet image, and only set the attribution
  // logo and zoom restrictions if it is.
  $.get("/meta/rest/auto/image/"+img.id, setAttribution, 'json');

  function setAttribution(data) {
    if (data._attributes !== "") {
      var attributes = JSON.parse(data._attributes);
    } else {
      var attributes = {};
    }
    
    if (attributes.planet_rest_response) {
    
      // initialize attribution data variable
      var attributionData = {
          'divName':that.divName,
          'image':loadAttributionImage(attributionMode),
          'mode':attributionMode,
          'location':attributionLocation
      };
      
      vectorLayer.on('precompose', function(event) {
        var ctx = event.context;
        ctx.save();
        displayAttribution(ctx,attributionData);
      });

      vectorLayer.on('postcompose', function(event) {
        var ctx = event.context;
        ctx.restore();
      })

      var x; var y;

      // Restrict the visible window of the image when zoomed to a high res
      littleImageLayer.on('precompose', function(event) {
        var ctx = event.context;
        ctx.save();
        
        // preferred over "that.map.getView().getResolution()", as viewState
        // contains the exact resolution during a zoom animation
        var currentResolution = event.frameState.viewState.resolution;
        var clipSize = originalClipSize / currentResolution;

        if (mousePosition) {
          var size = that.map.getSize();
          var pixelRatio = event.frameState.pixelRatio;
          var maxX = size[0]/pixelRatio - clipSize;
          var maxY = size[1]/pixelRatio - clipSize;
          var maybeX = mousePosition[0] - (clipSize / 2);
          if (maybeX > 0 && maybeX < maxX) {
            x = maybeX;
          }
          var maybeY = mousePosition[1] - (clipSize / 2);
          if (maybeY > 0 && maybeY < maxY) {
            y = maybeY;
          }
        }

        ctx.beginPath();
        ctx.rect(x,y,clipSize,clipSize)
        ctx.clip();      
      });<commit_msg>High-res square snaps back to center when mouse leaves pane on image view for planet images<commit_after>function ImageViewer(imageDivName, img) {
  this.divName = imageDivName;
  this.img = img;
  var that = this;
  $('#' + this.divName).html('');

  var imgWidth = this.img.width;
  var imgHeight = this.img.height;
  var imgCenter = [ imgWidth / 2, -imgHeight / 2 ];
  var url = this.img.url;
  var crossOrigin = 'anonymous';
  var gsd = 2.6; // meter/pix
  // TODO the above gsd is just for example; from metadata, get the real gsd
  var fullSizeMaxGsd = 30;
  var cutoffResolution = fullSizeMaxGsd / gsd;
  var imgWidthMeters = gsd * imgWidth;
  var imgHeightMeters = gsd * imgHeight;
  var originalClipSize = 1000 / gsd;
  var bigImageMaxZoom;

  // Create a 'fake' projection for the openlayers map to use
  var proj = new ol.proj.Projection({
    code : 'ZOOMIFY',
    units : 'pixels',
    extent : [ 0, 0, imgWidth, imgHeight ]
  });

  // Zoomify image source
  var bigImageSource = new ol.source.Zoomify({
    url : url,
    size : [ imgWidth, imgHeight ],
    crossOriginKeyword : crossOrigin,
  });
  bigImageSource.tileGrid.maxZoom = 1;
  // TODO calculate the actual max zoom level for this source
  
  var littleImageSource = new ol.source.Zoomify({
    url : url,
    size : [ imgWidth, imgHeight ],
    crossOriginKeyword : crossOrigin,
  });

  // Create the big image layer, visible when zoomed all the way out
  var bigImageLayer = new ol.layer.Tile({
    source : bigImageSource,
  });

  // Layer that restricts the image size at higher resolutions
  // (keepin the contract happy)
  var littleImageLayer = new ol.layer.Tile({
    source: littleImageSource,
  })

  // Vector layer for the planet logo and distribution statement
  var vectorLayer = new ol.layer.Vector({
    source: new ol.source.Vector()
  });

  // Create the map itself
  this.map = new ol.Map({
    interactions : ol.interaction.defaults(),
    layers : [ bigImageLayer, littleImageLayer, vectorLayer ],
    target : this.divName,
    controls : [], // Disable default controls
    view : new ol.View({
      projection : proj,
      center : imgCenter,
      zoom : 1,
      extent: [0, -imgHeight, imgWidth, 0]
    })
  });

  // Check in the db whether it's a planet image, and only set the attribution
  // logo and zoom restrictions if it is.
  $.get("/meta/rest/auto/image/"+img.id, setAttribution, 'json');

  function setAttribution(data) {
    if (data._attributes !== "") {
      var attributes = JSON.parse(data._attributes);
    } else {
      var attributes = {};
    }
    
    if (attributes.planet_rest_response) {
    
      // initialize attribution data variable
      var attributionData = {
          'divName':that.divName,
          'image':loadAttributionImage(attributionMode),
          'mode':attributionMode,
          'location':attributionLocation
      };
      
      vectorLayer.on('precompose', function(event) {
        var ctx = event.context;
        ctx.save();
        displayAttribution(ctx,attributionData);
      });

      vectorLayer.on('postcompose', function(event) {
        var ctx = event.context;
        ctx.restore();
      })

      var x; var y;

      // Restrict the visible window of the image when zoomed to a high res
      littleImageLayer.on('precompose', function(event) {
        var ctx = event.context;
        ctx.save();
        
        // preferred over "that.map.getView().getResolution()", as viewState
        // contains the exact resolution during a zoom animation
        var currentResolution = event.frameState.viewState.resolution;
        var clipSize = originalClipSize / currentResolution;
        var size = that.map.getSize();
        var pixelRatio = event.frameState.pixelRatio;

        if (mousePosition) {
          x = mousePosition[0] - (clipSize / 2);
          y = mousePosition[1] - (clipSize / 2);
        } else {
          x = ((size[0]/pixelRatio) - clipSize) / 2;
          y = ((size[1]/pixelRatio) - clipSize) / 2;
        }

        ctx.beginPath();
        ctx.rect(x,y,clipSize,clipSize)
        ctx.clip();      
      });
{'fraction_non_alphanumeric': 0.11345899867931324, 'fraction_numerical': 0.005762996758314323, 'mean_word_length': 2.470833333333333, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, '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': '4668697', 'n_tokens_mistral': 2555, 'n_tokens_neox': 2470, 'n_words': 718}