From c578eb715d1e316a46ddf058319a9b82fd0e8e59 Mon Sep 17 00:00:00 2001
From: ilan-gold <ilanbassgold@gmail.com>
Date: Thu, 25 Aug 2022 15:29:07 +0200
Subject: [PATCH 01/11] try triming.

---
 .../multiscale-image-layer.js                 | 26 ++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)

diff --git a/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js b/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
index cdb0fe124..bdc2ee7e1 100644
--- a/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
+++ b/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
@@ -84,10 +84,29 @@ const MultiscaleImageLayer = class extends CompositeLayer {
       // The image-tile example works without, this but I have a feeling there is something
       // going on with our pyramids and/or rendering that is different.
       const resolution = Math.round(-z);
+      const planarSize = loader[0].shape.slice(-2);
+      const [clippedHeight, clippedWidth] = planarSize.map(size => Math.ceil(size / (2 ** resolution)));
+      const useClippedHeight = clippedHeight < tileSize;
+      const useClippedWidth = clippedWidth < tileSize;
       const getTile = selection => {
         const config = { x, y, selection, signal };
         return loader[resolution].getTile(config);
       };
+      const clip = tile => {
+        if ((useClippedHeight || useClippedWidth) && (clippedHeight * clippedWidth !== tile.length)) {
+          return tile.filter((data, ind) => {
+            if (
+              (ind % tileSize >= clippedWidth && useClippedWidth) ||
+              (useClippedHeight &&
+                Math.floor(ind / clippedWidth) >= clippedHeight)
+            ) {
+              return false;
+            }
+            return true;
+          });
+        }
+        return tile;
+      }
 
       try {
         /*
@@ -101,10 +120,11 @@ const MultiscaleImageLayer = class extends CompositeLayer {
         const tiles = await Promise.all(selections.map(getTile));
 
         const tile = {
-          data: tiles.map(d => d.data),
-          width: tiles[0].width,
-          height: tiles[0].height
+          data: tiles.map(d => clip(d.data)),
+          width: useClippedWidth ? clippedWidth : tiles[0].width,
+          height: useClippedHeight ? clippedHeight : tiles[0].height
         };
+        console.log(tile, clippedHeight, clippedWidth)
 
         if (isInterleaved(loader[resolution].shape)) {
           // eslint-disable-next-line prefer-destructuring

From 3a79102c0beb2f2dc30326af1bf4baba617d583c Mon Sep 17 00:00:00 2001
From: ilan-gold <ilanbassgold@gmail.com>
Date: Thu, 25 Aug 2022 16:46:13 +0200
Subject: [PATCH 02/11] (fix): `getTileData` args changed

---
 .../src/multiscale-image-layer/multiscale-image-layer.js      | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js b/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
index cdb0fe124..b0d453763 100644
--- a/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
+++ b/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
@@ -66,12 +66,11 @@ const MultiscaleImageLayer = class extends CompositeLayer {
     } = this.props;
     // Get properties from highest resolution
     const { tileSize, dtype } = loader[0];
-
     // This is basically to invert:
     // https://github.com/visgl/deck.gl/pull/4616/files#diff-4d6a2e500c0e79e12e562c4f1217dc80R128
     // The z level can be wrong for showing the correct scales because of the calculation deck.gl does
     // so we need to invert it for fetching tiles and minZoom/maxZoom.
-    const getTileData = async ({ x, y, z, signal }) => {
+    const getTileData = async ({ index: { x, y, z }, signal }) => {
       // Early return if no selections
       if (!selections || selections.length === 0) {
         return null;
@@ -84,6 +83,7 @@ const MultiscaleImageLayer = class extends CompositeLayer {
       // The image-tile example works without, this but I have a feeling there is something
       // going on with our pyramids and/or rendering that is different.
       const resolution = Math.round(-z);
+      console.log(resolution, z);
       const getTile = selection => {
         const config = { x, y, selection, signal };
         return loader[resolution].getTile(config);

From f69ef2063688229164537ec0eabf764227b2f977 Mon Sep 17 00:00:00 2001
From: ilan-gold <ilanbassgold@gmail.com>
Date: Thu, 25 Aug 2022 17:04:31 +0200
Subject: [PATCH 03/11] Fix clipping.

---
 .../multiscale-image-layer.js                 | 27 ++++++++++++-------
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js b/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
index 555d10a54..a3584f765 100644
--- a/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
+++ b/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
@@ -83,8 +83,17 @@ const MultiscaleImageLayer = class extends CompositeLayer {
       // The image-tile example works without, this but I have a feeling there is something
       // going on with our pyramids and/or rendering that is different.
       const resolution = Math.round(-z);
+
+      // Here we set up variables for checking whether or not we should cip the black border of incoming tiles
+      // at low resolutions i.e for zarr tiles.  We need to check a few things before trimming:
+      //  1. The height/width of the full image at the current resolution produces an image smaller than the current tileSize
+      //  2. The incoming image is not exactly this size (i.e tiles that are not "padded" as in zarr)
+      // Once these have been confirmed, we trim the tile by going over it in row major order,
+      // keeping only the data that is not out of the clipped bounds.
       const planarSize = loader[0].shape.slice(-2);
-      const [clippedHeight, clippedWidth] = planarSize.map(size => Math.ceil(size / (2 ** resolution)));
+      const [clippedHeight, clippedWidth] = planarSize.map(size =>
+        Math.floor(size / 2 ** resolution)
+      );
       const useClippedHeight = clippedHeight < tileSize;
       const useClippedWidth = clippedWidth < tileSize;
       const getTile = selection => {
@@ -92,20 +101,20 @@ const MultiscaleImageLayer = class extends CompositeLayer {
         return loader[resolution].getTile(config);
       };
       const clip = tile => {
-        if ((useClippedHeight || useClippedWidth) && (clippedHeight * clippedWidth !== tile.length)) {
+        if (
+          (useClippedHeight || useClippedWidth) &&
+          clippedHeight * clippedWidth !== tile.length
+        ) {
           return tile.filter((data, ind) => {
-            if (
+            return !(
               (ind % tileSize >= clippedWidth && useClippedWidth) ||
               (useClippedHeight &&
                 Math.floor(ind / clippedWidth) >= clippedHeight)
-            ) {
-              return false;
-            }
-            return true;
+            );
           });
         }
         return tile;
-      }
+      };
 
       try {
         /*
@@ -117,13 +126,11 @@ const MultiscaleImageLayer = class extends CompositeLayer {
          * return type, and optional throw for performance.
          */
         const tiles = await Promise.all(selections.map(getTile));
-
         const tile = {
           data: tiles.map(d => clip(d.data)),
           width: useClippedWidth ? clippedWidth : tiles[0].width,
           height: useClippedHeight ? clippedHeight : tiles[0].height
         };
-        console.log(tile, clippedHeight, clippedWidth)
 
         if (isInterleaved(loader[resolution].shape)) {
           // eslint-disable-next-line prefer-destructuring

From 2ea8f61be6d82c25b1ed31ed8d793f64c7cb7142 Mon Sep 17 00:00:00 2001
From: ilan-gold <ilanbassgold@gmail.com>
Date: Thu, 25 Aug 2022 17:17:50 +0200
Subject: [PATCH 04/11] [wip] figuring out right condition.

---
 .../multiscale-image-layer.js                 | 44 +++++++++++++++----
 1 file changed, 35 insertions(+), 9 deletions(-)

diff --git a/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js b/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
index a3584f765..8dc788e20 100644
--- a/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
+++ b/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
@@ -100,20 +100,34 @@ const MultiscaleImageLayer = class extends CompositeLayer {
         const config = { x, y, selection, signal };
         return loader[resolution].getTile(config);
       };
-      const clip = tile => {
+      const clip = ({ data, height, width }) => {
+        console.log(
+          tileSize,
+          useClippedHeight,
+          useClippedWidth,
+          clippedHeight,
+          clippedWidth,
+          data.length,
+          resolution,
+          width,
+          height
+        );
         if (
           (useClippedHeight || useClippedWidth) &&
-          clippedHeight * clippedWidth !== tile.length
+          width !== clippedHeight && height !== clippedHeight
         ) {
-          return tile.filter((data, ind) => {
+          return data.filter((d, ind) => {
             return !(
-              (ind % tileSize >= clippedWidth && useClippedWidth) ||
+              (ind % tileSize >= clippedWidth &&
+                useClippedWidth &&
+                ) ||
               (useClippedHeight &&
-                Math.floor(ind / clippedWidth) >= clippedHeight)
+                Math.floor(ind / clippedWidth) >= clippedHeight &&
+                height !== clippedHeight)
             );
           });
         }
-        return tile;
+        return data;
       };
 
       try {
@@ -127,9 +141,21 @@ const MultiscaleImageLayer = class extends CompositeLayer {
          */
         const tiles = await Promise.all(selections.map(getTile));
         const tile = {
-          data: tiles.map(d => clip(d.data)),
-          width: useClippedWidth ? clippedWidth : tiles[0].width,
-          height: useClippedHeight ? clippedHeight : tiles[0].height
+          data: tiles.map(d =>
+            clip({
+              data: d.data,
+              width: tiles[0].width,
+              height: tiles[0].height
+            })
+          ),
+          width:
+            useClippedWidth && tiles[0].height !== tileSize
+              ? clippedWidth
+              : tiles[0].width,
+          height:
+            useClippedHeight && tiles[0].height !== tileSize
+              ? clippedHeight
+              : tiles[0].height
         };
 
         if (isInterleaved(loader[resolution].shape)) {

From 46e3fd380657650140b2d5dad9c0c5243ecc2e69 Mon Sep 17 00:00:00 2001
From: ilan-gold <ilanbassgold@gmail.com>
Date: Thu, 25 Aug 2022 17:31:56 +0200
Subject: [PATCH 05/11] Fix conditions

---
 .../multiscale-image-layer.js                 | 38 +++++++------------
 1 file changed, 13 insertions(+), 25 deletions(-)

diff --git a/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js b/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
index 8dc788e20..e2aee9840 100644
--- a/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
+++ b/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
@@ -86,44 +86,32 @@ const MultiscaleImageLayer = class extends CompositeLayer {
 
       // Here we set up variables for checking whether or not we should cip the black border of incoming tiles
       // at low resolutions i.e for zarr tiles.  We need to check a few things before trimming:
-      //  1. The height/width of the full image at the current resolution produces an image smaller than the current tileSize
-      //  2. The incoming image is not exactly this size (i.e tiles that are not "padded" as in zarr)
+      //  1. The height/width of the full image at the current resolution
+      //  produces an image smaller than the current tileSize
+      //  2. The incoming image is indeed padded out to the tile size
+      //  in some dimension i.e it should be clipped down to the smaller size
       // Once these have been confirmed, we trim the tile by going over it in row major order,
       // keeping only the data that is not out of the clipped bounds.
       const planarSize = loader[0].shape.slice(-2);
       const [clippedHeight, clippedWidth] = planarSize.map(size =>
         Math.floor(size / 2 ** resolution)
       );
-      const useClippedHeight = clippedHeight < tileSize;
-      const useClippedWidth = clippedWidth < tileSize;
+      const isHeightUnderTileSize = clippedHeight < tileSize;
+      const isWidthUnderTileSize = clippedWidth < tileSize;
       const getTile = selection => {
         const config = { x, y, selection, signal };
         return loader[resolution].getTile(config);
       };
       const clip = ({ data, height, width }) => {
-        console.log(
-          tileSize,
-          useClippedHeight,
-          useClippedWidth,
-          clippedHeight,
-          clippedWidth,
-          data.length,
-          resolution,
-          width,
-          height
-        );
         if (
-          (useClippedHeight || useClippedWidth) &&
-          width !== clippedHeight && height !== clippedHeight
+          (isHeightUnderTileSize && height === tileSize) ||
+          (width === tileSize && isWidthUnderTileSize)
         ) {
           return data.filter((d, ind) => {
             return !(
-              (ind % tileSize >= clippedWidth &&
-                useClippedWidth &&
-                ) ||
-              (useClippedHeight &&
-                Math.floor(ind / clippedWidth) >= clippedHeight &&
-                height !== clippedHeight)
+              (ind % tileSize >= clippedWidth && isWidthUnderTileSize) ||
+              (isHeightUnderTileSize &&
+                Math.floor(ind / clippedWidth) >= clippedHeight)
             );
           });
         }
@@ -149,11 +137,11 @@ const MultiscaleImageLayer = class extends CompositeLayer {
             })
           ),
           width:
-            useClippedWidth && tiles[0].height !== tileSize
+            isWidthUnderTileSize && tiles[0].height === tileSize
               ? clippedWidth
               : tiles[0].width,
           height:
-            useClippedHeight && tiles[0].height !== tileSize
+            isHeightUnderTileSize && tiles[0].height === tileSize
               ? clippedHeight
               : tiles[0].height
         };

From 914b4f9de211cdb0242a755aa50c7d68bb3b390b Mon Sep 17 00:00:00 2001
From: ilan-gold <ilanbassgold@gmail.com>
Date: Tue, 30 Aug 2022 18:30:57 +0200
Subject: [PATCH 06/11] tileSize!

---
 .../layers/src/multiscale-image-layer/multiscale-image-layer.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js b/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
index e2aee9840..d119d09e7 100644
--- a/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
+++ b/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
@@ -111,7 +111,7 @@ const MultiscaleImageLayer = class extends CompositeLayer {
             return !(
               (ind % tileSize >= clippedWidth && isWidthUnderTileSize) ||
               (isHeightUnderTileSize &&
-                Math.floor(ind / clippedWidth) >= clippedHeight)
+                Math.floor(ind / tileSize) >= clippedHeight)
             );
           });
         }

From b61e5fb040dfead28f323782e08627a586cd17e0 Mon Sep 17 00:00:00 2001
From: ilan-gold <ilanbassgold@gmail.com>
Date: Wed, 31 Aug 2022 19:01:29 +0200
Subject: [PATCH 07/11] (refactor): use `getImageSize`

---
 .../layers/src/multiscale-image-layer/multiscale-image-layer.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js b/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
index d119d09e7..6e35ebd8f 100644
--- a/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
+++ b/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
@@ -92,7 +92,7 @@ const MultiscaleImageLayer = class extends CompositeLayer {
       //  in some dimension i.e it should be clipped down to the smaller size
       // Once these have been confirmed, we trim the tile by going over it in row major order,
       // keeping only the data that is not out of the clipped bounds.
-      const planarSize = loader[0].shape.slice(-2);
+      const planarSize = getImageSize(loader[0]);
       const [clippedHeight, clippedWidth] = planarSize.map(size =>
         Math.floor(size / 2 ** resolution)
       );

From f1a49e131552808343dbde23a7d563a34395849b Mon Sep 17 00:00:00 2001
From: ilan-gold <ilanbassgold@gmail.com>
Date: Wed, 31 Aug 2022 19:24:11 +0200
Subject: [PATCH 08/11] (refactor): make `createTileClipper` function.

---
 .../multiscale-image-layer.js                 | 86 +++++++++++--------
 1 file changed, 50 insertions(+), 36 deletions(-)

diff --git a/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js b/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
index 6e35ebd8f..34b896a77 100644
--- a/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
+++ b/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
@@ -7,6 +7,50 @@ import ImageLayer from '../image-layer';
 import { getImageSize, isInterleaved, SIGNAL_ABORTED } from '@vivjs/loaders';
 import { ColorPaletteExtension } from '@vivjs/extensions';
 
+/**
+ * Here we create an object for checking clipping the black border of incoming tiles
+ * at low resolutions i.e for zarr tiles which are padded by zarr.
+ * We need to check a few things before trimming:
+ *  1. The height/width of the full image at the current resolution
+ *  produces an image smaller than the current tileSize
+ *  2. The incoming image is padded to the tile size i.e one of its dimensions matches the tile size
+ * Once these have been confirmed, we trim the tile by going over it in row major order,
+ * keeping only the data that is not out of the clipped bounds.
+ * @param {{
+ *   loader: PixelSource[],
+ *   resolution: number,
+ *   tileSize: number,
+ * }}
+ * @return {{ clip: function, height: number, width: number }}
+ */
+const createTileClipper = ({ loader, resolution, tileSize }) => {
+  const planarSize = Object.values(getImageSize(loader[0]));
+  const [clippedHeight, clippedWidth] = planarSize.map(size =>
+    Math.floor(size / 2 ** resolution)
+  );
+  const isHeightUnderTileSize = clippedHeight < tileSize;
+  const isWidthUnderTileSize = clippedWidth < tileSize;
+  return {
+    clip: ({ data, height, width }) => {
+      if (
+        (isHeightUnderTileSize && height === tileSize) ||
+        (width === tileSize && isWidthUnderTileSize)
+      ) {
+        return data.filter((d, ind) => {
+          return !(
+            (ind % tileSize >= clippedWidth && isWidthUnderTileSize) ||
+            (isHeightUnderTileSize &&
+              Math.floor(ind / tileSize) >= clippedHeight)
+          );
+        });
+      }
+      return data;
+    },
+    height: clippedHeight,
+    width: clippedWidth
+  };
+};
+
 const defaultProps = {
   pickable: { type: 'boolean', value: true, compare: true },
   onHover: { type: 'function', value: null, compare: false },
@@ -83,41 +127,11 @@ const MultiscaleImageLayer = class extends CompositeLayer {
       // The image-tile example works without, this but I have a feeling there is something
       // going on with our pyramids and/or rendering that is different.
       const resolution = Math.round(-z);
-
-      // Here we set up variables for checking whether or not we should cip the black border of incoming tiles
-      // at low resolutions i.e for zarr tiles.  We need to check a few things before trimming:
-      //  1. The height/width of the full image at the current resolution
-      //  produces an image smaller than the current tileSize
-      //  2. The incoming image is indeed padded out to the tile size
-      //  in some dimension i.e it should be clipped down to the smaller size
-      // Once these have been confirmed, we trim the tile by going over it in row major order,
-      // keeping only the data that is not out of the clipped bounds.
-      const planarSize = getImageSize(loader[0]);
-      const [clippedHeight, clippedWidth] = planarSize.map(size =>
-        Math.floor(size / 2 ** resolution)
-      );
-      const isHeightUnderTileSize = clippedHeight < tileSize;
-      const isWidthUnderTileSize = clippedWidth < tileSize;
       const getTile = selection => {
         const config = { x, y, selection, signal };
         return loader[resolution].getTile(config);
       };
-      const clip = ({ data, height, width }) => {
-        if (
-          (isHeightUnderTileSize && height === tileSize) ||
-          (width === tileSize && isWidthUnderTileSize)
-        ) {
-          return data.filter((d, ind) => {
-            return !(
-              (ind % tileSize >= clippedWidth && isWidthUnderTileSize) ||
-              (isHeightUnderTileSize &&
-                Math.floor(ind / tileSize) >= clippedHeight)
-            );
-          });
-        }
-        return data;
-      };
-
+      const clipper = createTileClipper({ loader, resolution, tileSize });
       try {
         /*
          * Try to request the tile data. The pixels sources can throw
@@ -130,19 +144,19 @@ const MultiscaleImageLayer = class extends CompositeLayer {
         const tiles = await Promise.all(selections.map(getTile));
         const tile = {
           data: tiles.map(d =>
-            clip({
+            clipper.clip({
               data: d.data,
               width: tiles[0].width,
               height: tiles[0].height
             })
           ),
           width:
-            isWidthUnderTileSize && tiles[0].height === tileSize
-              ? clippedWidth
+            clipper.width < tileSize && tiles[0].width === tileSize
+              ? clipper.width
               : tiles[0].width,
           height:
-            isHeightUnderTileSize && tiles[0].height === tileSize
-              ? clippedHeight
+            clipper.height < tileSize && tiles[0].height === tileSize
+              ? clipper.height
               : tiles[0].height
         };
 

From 2aa66ad8f7dd87b3a91aa8917198cf0d4a85f1bd Mon Sep 17 00:00:00 2001
From: ilan-gold <ilanbassgold@gmail.com>
Date: Wed, 31 Aug 2022 19:25:24 +0200
Subject: [PATCH 09/11] (chore): changelog update

---
 CHANGELOG.md | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3b289df51..36039d714 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,16 +5,20 @@
 ### Added
 
 ### Changed
+
 - Upgrade deck.gl to 8.8
 - Replace `postversion` script with `version` script for CI release.
 - Remove `package-lock.json` from root (since we use pnpm)
+- Clip low resolution tiles that might be padded by a loader.
 
 ## 0.13.1
 
 ### Added
+
 - Added support for loading multiple single channel TIFFs.
 
 ### Changed
+
 - Update doc strings for `loadMultiTiff`
 - Update release notes in `README.md`
 
@@ -23,6 +27,7 @@
 ### Added
 
 ### Changed
+
 - Migrate to pnpm monorepo
 - Fix all image URLs in README
 - Only run CHANGELOG action on pull_requests

From 1b7f4b8d8c89400241152ae1bd317bbb8f2ca083 Mon Sep 17 00:00:00 2001
From: ilan-gold <ilanbassgold@gmail.com>
Date: Thu, 23 Mar 2023 13:16:08 +0100
Subject: [PATCH 10/11] (feat): refactor for clarity (hopefully)

---
 .../multiscale-image-layer.js                 | 54 +++++++++----------
 1 file changed, 27 insertions(+), 27 deletions(-)

diff --git a/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js b/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
index 34b896a77..272302bad 100644
--- a/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
+++ b/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
@@ -23,19 +23,31 @@ import { ColorPaletteExtension } from '@vivjs/extensions';
  * }}
  * @return {{ clip: function, height: number, width: number }}
  */
-const createTileClipper = ({ loader, resolution, tileSize }) => {
-  const planarSize = Object.values(getImageSize(loader[0]));
-  const [clippedHeight, clippedWidth] = planarSize.map(size =>
-    Math.floor(size / 2 ** resolution)
-  );
-  const isHeightUnderTileSize = clippedHeight < tileSize;
-  const isWidthUnderTileSize = clippedWidth < tileSize;
+const createTileClipper = ({ loader, resolution }) => {
+  const { tileSize } = loader[0];
+  const planarSize = getImageSize(loader[0]);
+  const [clippedHeight, clippedWidth] = [
+    planarSize.height,
+    planarSize.width
+  ].map(size => Math.floor(size / 2 ** resolution));
+  const isUnderTileSize = dimSize => dimSize < tileSize;
+  const shouldClip = ({ clippedDimSize, dataDimSize }) =>
+    isUnderTileSize(clippedDimSize) && dataDimSize === tileSize;
+  const dimSizeGetterFactory =
+    ({ clippedDimSize }) =>
+    ({ dataDimSize }) =>
+      shouldClip({ clippedDimSize, dataDimSize })
+        ? clippedDimSize
+        : dataDimSize;
+
   return {
     clip: ({ data, height, width }) => {
       if (
-        (isHeightUnderTileSize && height === tileSize) ||
-        (width === tileSize && isWidthUnderTileSize)
+        shouldClip({ clippedDimSize: clippedHeight, dataDimSize: height }) ||
+        shouldClip({ clippedDimSize: clippedWidth, dataDimSize: width })
       ) {
+        const isHeightUnderTileSize = isUnderTileSize(clippedHeight);
+        const isWidthUnderTileSize = isUnderTileSize(clippedWidth);
         return data.filter((d, ind) => {
           return !(
             (ind % tileSize >= clippedWidth && isWidthUnderTileSize) ||
@@ -46,8 +58,8 @@ const createTileClipper = ({ loader, resolution, tileSize }) => {
       }
       return data;
     },
-    height: clippedHeight,
-    width: clippedWidth
+    getHeight: dimSizeGetterFactory({ clippedDimSize: clippedHeight }),
+    getWidth: dimSizeGetterFactory({ clippedDimSize: clippedWidth })
   };
 };
 
@@ -131,7 +143,7 @@ const MultiscaleImageLayer = class extends CompositeLayer {
         const config = { x, y, selection, signal };
         return loader[resolution].getTile(config);
       };
-      const clipper = createTileClipper({ loader, resolution, tileSize });
+      const clipper = createTileClipper({ loader, resolution });
       try {
         /*
          * Try to request the tile data. The pixels sources can throw
@@ -143,21 +155,9 @@ const MultiscaleImageLayer = class extends CompositeLayer {
          */
         const tiles = await Promise.all(selections.map(getTile));
         const tile = {
-          data: tiles.map(d =>
-            clipper.clip({
-              data: d.data,
-              width: tiles[0].width,
-              height: tiles[0].height
-            })
-          ),
-          width:
-            clipper.width < tileSize && tiles[0].width === tileSize
-              ? clipper.width
-              : tiles[0].width,
-          height:
-            clipper.height < tileSize && tiles[0].height === tileSize
-              ? clipper.height
-              : tiles[0].height
+          data: tiles.map(clipper.clip),
+          width: clipper.getWidth({ dataDimSize: tiles[0].width }),
+          height: clipper.getHeight({ dataDimSize: tiles[0].height })
         };
 
         if (isInterleaved(loader[resolution].shape)) {

From 768d01452871d5b79cb092a5cccbceb8dbd111fd Mon Sep 17 00:00:00 2001
From: ilan-gold <ilanbassgold@gmail.com>
Date: Thu, 23 Mar 2023 13:27:36 +0100
Subject: [PATCH 11/11] (style): refactor for single function

---
 .../multiscale-image-layer.js                 | 69 +++++++++----------
 1 file changed, 34 insertions(+), 35 deletions(-)

diff --git a/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js b/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
index 272302bad..6043ef903 100644
--- a/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
+++ b/packages/layers/src/multiscale-image-layer/multiscale-image-layer.js
@@ -8,7 +8,7 @@ import { getImageSize, isInterleaved, SIGNAL_ABORTED } from '@vivjs/loaders';
 import { ColorPaletteExtension } from '@vivjs/extensions';
 
 /**
- * Here we create an object for checking clipping the black border of incoming tiles
+ * Here we process the clipping of the black border of incoming tiles
  * at low resolutions i.e for zarr tiles which are padded by zarr.
  * We need to check a few things before trimming:
  *  1. The height/width of the full image at the current resolution
@@ -21,9 +21,9 @@ import { ColorPaletteExtension } from '@vivjs/extensions';
  *   resolution: number,
  *   tileSize: number,
  * }}
- * @return {{ clip: function, height: number, width: number }}
+ * @return {{ data: TypedArray, height: number, width: number }}
  */
-const createTileClipper = ({ loader, resolution }) => {
+const clipTiles = ({ loader, resolution, tiles }) => {
   const { tileSize } = loader[0];
   const planarSize = getImageSize(loader[0]);
   const [clippedHeight, clippedWidth] = [
@@ -33,34 +33,33 @@ const createTileClipper = ({ loader, resolution }) => {
   const isUnderTileSize = dimSize => dimSize < tileSize;
   const shouldClip = ({ clippedDimSize, dataDimSize }) =>
     isUnderTileSize(clippedDimSize) && dataDimSize === tileSize;
-  const dimSizeGetterFactory =
-    ({ clippedDimSize }) =>
-    ({ dataDimSize }) =>
-      shouldClip({ clippedDimSize, dataDimSize })
-        ? clippedDimSize
-        : dataDimSize;
+  const getDimSize = ({ clippedDimSize, dataDimSize }) =>
+    shouldClip({ clippedDimSize, dataDimSize }) ? clippedDimSize : dataDimSize;
 
-  return {
-    clip: ({ data, height, width }) => {
-      if (
-        shouldClip({ clippedDimSize: clippedHeight, dataDimSize: height }) ||
-        shouldClip({ clippedDimSize: clippedWidth, dataDimSize: width })
-      ) {
-        const isHeightUnderTileSize = isUnderTileSize(clippedHeight);
-        const isWidthUnderTileSize = isUnderTileSize(clippedWidth);
-        return data.filter((d, ind) => {
-          return !(
-            (ind % tileSize >= clippedWidth && isWidthUnderTileSize) ||
-            (isHeightUnderTileSize &&
-              Math.floor(ind / tileSize) >= clippedHeight)
-          );
-        });
-      }
-      return data;
-    },
-    getHeight: dimSizeGetterFactory({ clippedDimSize: clippedHeight }),
-    getWidth: dimSizeGetterFactory({ clippedDimSize: clippedWidth })
-  };
+  return tiles.map(({ data, height, width }) => {
+    let clippedData = data;
+    if (
+      shouldClip({ clippedDimSize: clippedHeight, dataDimSize: height }) ||
+      shouldClip({ clippedDimSize: clippedWidth, dataDimSize: width })
+    ) {
+      const isHeightUnderTileSize = isUnderTileSize(clippedHeight);
+      const isWidthUnderTileSize = isUnderTileSize(clippedWidth);
+      clippedData = data.filter((d, ind) => {
+        return !(
+          (ind % tileSize >= clippedWidth && isWidthUnderTileSize) ||
+          (isHeightUnderTileSize && Math.floor(ind / tileSize) >= clippedHeight)
+        );
+      });
+    }
+    return {
+      data: clippedData,
+      height: getDimSize({
+        clippedDimSize: clippedHeight,
+        dataDimSize: height
+      }),
+      width: getDimSize({ clippedDimSize: clippedWidth, dataDimSize: width })
+    };
+  });
 };
 
 const defaultProps = {
@@ -143,7 +142,6 @@ const MultiscaleImageLayer = class extends CompositeLayer {
         const config = { x, y, selection, signal };
         return loader[resolution].getTile(config);
       };
-      const clipper = createTileClipper({ loader, resolution });
       try {
         /*
          * Try to request the tile data. The pixels sources can throw
@@ -153,11 +151,12 @@ const MultiscaleImageLayer = class extends CompositeLayer {
          * This means that our pixels sources _always_ have the same
          * return type, and optional throw for performance.
          */
-        const tiles = await Promise.all(selections.map(getTile));
+        let tiles = await Promise.all(selections.map(getTile));
+        tiles = clipTiles({ loader, resolution, tiles });
         const tile = {
-          data: tiles.map(clipper.clip),
-          width: clipper.getWidth({ dataDimSize: tiles[0].width }),
-          height: clipper.getHeight({ dataDimSize: tiles[0].height })
+          data: tiles.map(d => d.data),
+          width: tiles[0].width,
+          height: tiles[0].height
         };
 
         if (isInterleaved(loader[resolution].shape)) {