@trackunit/react-map-adapter-google 0.0.25 → 0.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.cjs.js CHANGED
@@ -190,6 +190,13 @@ class GoogleMapsLayerPort {
190
190
  * the marker the user visibly clicked wins.
191
191
  */
192
192
  this.pointEntityClickedInTick = false;
193
+ /**
194
+ * True for one tick after a point (marker/cluster) hover-start is emitted.
195
+ * Mirrors {@link pointEntityClickedInTick} for hover: a symbol marker
196
+ * overlapping a site polygon can receive both the canvas hover and the
197
+ * polygon's geometric mouseover; the trailing shape hover is suppressed.
198
+ */
199
+ this.pointEntityHoveredInTick = false;
193
200
  this.mapClickListener = null;
194
201
  // Tracked sources, keyed by source ID
195
202
  this.markerSources = new Map();
@@ -1730,13 +1737,21 @@ class GoogleMapsLayerPort {
1730
1737
  }
1731
1738
  drawnMarkers = [];
1732
1739
  }
1740
+ /** Exposed for shape-hover suppression when a symbol overlaps a site polygon. */
1741
+ hitTestAtClient(clientX, clientY) {
1742
+ const hit = this.findHitAtClient(clientX, clientY);
1743
+ return hit !== null ? hit.featureId : null;
1744
+ }
1733
1745
  findHit(event) {
1746
+ return this.findHitAtClient(event.clientX, event.clientY);
1747
+ }
1748
+ findHitAtClient(clientX, clientY) {
1734
1749
  const canvas = this.canvas;
1735
1750
  if (canvas === null)
1736
1751
  return null;
1737
1752
  const rect = canvas.getBoundingClientRect();
1738
- const mouseX = event.clientX - rect.left;
1739
- const mouseY = event.clientY - rect.top;
1753
+ const mouseX = clientX - rect.left;
1754
+ const mouseY = clientY - rect.top;
1740
1755
  let closestEntry = null;
1741
1756
  let closestDist = Infinity;
1742
1757
  for (const drawn of drawnMarkers) {
@@ -1754,6 +1769,7 @@ class GoogleMapsLayerPort {
1754
1769
  const overlay = new CanvasSymbolOverlay();
1755
1770
  overlay.setMap(map);
1756
1771
  tracked.canvasOverlay = overlay;
1772
+ tracked.symbolHitTestAtClient = (clientX, clientY) => overlay.hitTestAtClient(clientX, clientY);
1757
1773
  }
1758
1774
  // ============================================================================
1759
1775
  // Private: Client-side clustering
@@ -2252,7 +2268,11 @@ class GoogleMapsLayerPort {
2252
2268
  this.lastShapeClickEntity = entity;
2253
2269
  this.emitEntityInteraction("click", entity);
2254
2270
  }),
2255
- shape.addListener("mouseover", () => {
2271
+ shape.addListener("mouseover", (e) => {
2272
+ const domEvent = e.domEvent;
2273
+ if (domEvent instanceof MouseEvent && this.isSymbolMarkerAtClientPosition(domEvent.clientX, domEvent.clientY)) {
2274
+ return;
2275
+ }
2256
2276
  this.emitEntityInteraction("hover-start", entity);
2257
2277
  }),
2258
2278
  shape.addListener("mousemove", (e) => {
@@ -2382,6 +2402,17 @@ class GoogleMapsLayerPort {
2382
2402
  m.set("disableDoubleClickZoom", false);
2383
2403
  }, 0);
2384
2404
  }
2405
+ /** True when a symbol canvas marker is under the given viewport client position. */
2406
+ isSymbolMarkerAtClientPosition(clientX, clientY) {
2407
+ for (const tracked of this.markerSources.values()) {
2408
+ const hitTest = tracked.symbolHitTestAtClient;
2409
+ if (hitTest === undefined)
2410
+ continue;
2411
+ if (hitTest(clientX, clientY) !== null)
2412
+ return true;
2413
+ }
2414
+ return false;
2415
+ }
2385
2416
  /** Emit entity interaction event to all subscribed handlers */
2386
2417
  emitEntityInteraction(type, entity) {
2387
2418
  if (type === "click") {
@@ -2427,6 +2458,16 @@ class GoogleMapsLayerPort {
2427
2458
  }, 0);
2428
2459
  }
2429
2460
  }
2461
+ if (type === "hover-start") {
2462
+ if (entity.type === "shape" && this.pointEntityHoveredInTick)
2463
+ return;
2464
+ if (entity.type === "marker" || entity.type === "cluster") {
2465
+ this.pointEntityHoveredInTick = true;
2466
+ setTimeout(() => {
2467
+ this.pointEntityHoveredInTick = false;
2468
+ }, 0);
2469
+ }
2470
+ }
2430
2471
  const event = { type, entity };
2431
2472
  this.interactionHandlers.forEach(handler => handler(event));
2432
2473
  }
package/index.esm.js CHANGED
@@ -188,6 +188,13 @@ class GoogleMapsLayerPort {
188
188
  * the marker the user visibly clicked wins.
189
189
  */
190
190
  this.pointEntityClickedInTick = false;
191
+ /**
192
+ * True for one tick after a point (marker/cluster) hover-start is emitted.
193
+ * Mirrors {@link pointEntityClickedInTick} for hover: a symbol marker
194
+ * overlapping a site polygon can receive both the canvas hover and the
195
+ * polygon's geometric mouseover; the trailing shape hover is suppressed.
196
+ */
197
+ this.pointEntityHoveredInTick = false;
191
198
  this.mapClickListener = null;
192
199
  // Tracked sources, keyed by source ID
193
200
  this.markerSources = new Map();
@@ -1728,13 +1735,21 @@ class GoogleMapsLayerPort {
1728
1735
  }
1729
1736
  drawnMarkers = [];
1730
1737
  }
1738
+ /** Exposed for shape-hover suppression when a symbol overlaps a site polygon. */
1739
+ hitTestAtClient(clientX, clientY) {
1740
+ const hit = this.findHitAtClient(clientX, clientY);
1741
+ return hit !== null ? hit.featureId : null;
1742
+ }
1731
1743
  findHit(event) {
1744
+ return this.findHitAtClient(event.clientX, event.clientY);
1745
+ }
1746
+ findHitAtClient(clientX, clientY) {
1732
1747
  const canvas = this.canvas;
1733
1748
  if (canvas === null)
1734
1749
  return null;
1735
1750
  const rect = canvas.getBoundingClientRect();
1736
- const mouseX = event.clientX - rect.left;
1737
- const mouseY = event.clientY - rect.top;
1751
+ const mouseX = clientX - rect.left;
1752
+ const mouseY = clientY - rect.top;
1738
1753
  let closestEntry = null;
1739
1754
  let closestDist = Infinity;
1740
1755
  for (const drawn of drawnMarkers) {
@@ -1752,6 +1767,7 @@ class GoogleMapsLayerPort {
1752
1767
  const overlay = new CanvasSymbolOverlay();
1753
1768
  overlay.setMap(map);
1754
1769
  tracked.canvasOverlay = overlay;
1770
+ tracked.symbolHitTestAtClient = (clientX, clientY) => overlay.hitTestAtClient(clientX, clientY);
1755
1771
  }
1756
1772
  // ============================================================================
1757
1773
  // Private: Client-side clustering
@@ -2250,7 +2266,11 @@ class GoogleMapsLayerPort {
2250
2266
  this.lastShapeClickEntity = entity;
2251
2267
  this.emitEntityInteraction("click", entity);
2252
2268
  }),
2253
- shape.addListener("mouseover", () => {
2269
+ shape.addListener("mouseover", (e) => {
2270
+ const domEvent = e.domEvent;
2271
+ if (domEvent instanceof MouseEvent && this.isSymbolMarkerAtClientPosition(domEvent.clientX, domEvent.clientY)) {
2272
+ return;
2273
+ }
2254
2274
  this.emitEntityInteraction("hover-start", entity);
2255
2275
  }),
2256
2276
  shape.addListener("mousemove", (e) => {
@@ -2380,6 +2400,17 @@ class GoogleMapsLayerPort {
2380
2400
  m.set("disableDoubleClickZoom", false);
2381
2401
  }, 0);
2382
2402
  }
2403
+ /** True when a symbol canvas marker is under the given viewport client position. */
2404
+ isSymbolMarkerAtClientPosition(clientX, clientY) {
2405
+ for (const tracked of this.markerSources.values()) {
2406
+ const hitTest = tracked.symbolHitTestAtClient;
2407
+ if (hitTest === undefined)
2408
+ continue;
2409
+ if (hitTest(clientX, clientY) !== null)
2410
+ return true;
2411
+ }
2412
+ return false;
2413
+ }
2383
2414
  /** Emit entity interaction event to all subscribed handlers */
2384
2415
  emitEntityInteraction(type, entity) {
2385
2416
  if (type === "click") {
@@ -2425,6 +2456,16 @@ class GoogleMapsLayerPort {
2425
2456
  }, 0);
2426
2457
  }
2427
2458
  }
2459
+ if (type === "hover-start") {
2460
+ if (entity.type === "shape" && this.pointEntityHoveredInTick)
2461
+ return;
2462
+ if (entity.type === "marker" || entity.type === "cluster") {
2463
+ this.pointEntityHoveredInTick = true;
2464
+ setTimeout(() => {
2465
+ this.pointEntityHoveredInTick = false;
2466
+ }, 0);
2467
+ }
2468
+ }
2428
2469
  const event = { type, entity };
2429
2470
  this.interactionHandlers.forEach(handler => handler(event));
2430
2471
  }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry.js","sourceRoot":"","sources":["../../../../../libs/react/map-adapter-google/migrations/entry.ts"],"names":[],"mappings":"","sourcesContent":["export {};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trackunit/react-map-adapter-google",
3
- "version": "0.0.25",
3
+ "version": "0.0.26",
4
4
  "repository": "https://github.com/Trackunit/manager",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "engines": {
@@ -41,6 +41,13 @@ export declare class GoogleMapsLayerPort implements LayerPort {
41
41
  * the marker the user visibly clicked wins.
42
42
  */
43
43
  private pointEntityClickedInTick;
44
+ /**
45
+ * True for one tick after a point (marker/cluster) hover-start is emitted.
46
+ * Mirrors {@link pointEntityClickedInTick} for hover: a symbol marker
47
+ * overlapping a site polygon can receive both the canvas hover and the
48
+ * polygon's geometric mouseover; the trailing shape hover is suppressed.
49
+ */
50
+ private pointEntityHoveredInTick;
44
51
  private mapClickListener;
45
52
  private readonly markerSources;
46
53
  /** featureId → element, keyed by sourceId. Cleared when a source is removed. */
@@ -251,6 +258,8 @@ export declare class GoogleMapsLayerPort implements LayerPort {
251
258
  * overriding it. Re-enables on the next tick.
252
259
  */
253
260
  private suppressNativeZoom;
261
+ /** True when a symbol canvas marker is under the given viewport client position. */
262
+ private isSymbolMarkerAtClientPosition;
254
263
  /** Emit entity interaction event to all subscribed handlers */
255
264
  private emitEntityInteraction;
256
265
  /**