Skip to content

Add advanced markers support#48

Open
paodb wants to merge 7 commits into
masterfrom
google-maps-issue-121
Open

Add advanced markers support#48
paodb wants to merge 7 commits into
masterfrom
google-maps-issue-121

Conversation

@paodb

@paodb paodb commented Jul 17, 2026

Copy link
Copy Markdown
Member

Adds a new google-map-advanced-marker element based on AdvancedMarkerElement, Google's replacement for the deprecated google.maps.Marker. Part of FlowingCode/GoogleMapsAddon#121.

The element supports pin customization (background, border color, glyph, scale). The original google-map-marker is kept: advanced markers require a mapId and don't support some classic features (Symbol icons, labels, animation), so replacing it would break existing users. Per Google's deprecations page, google.maps.Marker is "not scheduled to be discontinued" and keeps working. A doc note now points new development to the new element.

Added new demos: demo/advanced-markers.html and demo/advanced-markers-clustering.html.

Summary by CodeRabbit

  • New Features
    • Added google-map-advanced-marker (based on AdvancedMarkerElement) with support for styled/icon/image and custom HTML content, dragging, InfoWindow open/close, and configurable event forwarding (including touch long-press “right-click”).
    • Added new advanced markers demo pages, including an advanced markers clustering example.
    • Included advanced marker support in the main elements bundle.
  • Bug Fixes
    • Improved marker clustering updates and enhanced fit-to-markers to consider only markers with valid latitude/longitude, with correct single-marker centering.
  • Documentation
    • Updated README with advanced marker setup requirements and a usage example (including the required map-id).
  • Chores
    • Bumped package version to 3.10.0 and updated the marker clustering dependency.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c3855bc2-5646-48dc-b240-cbba3820ee46

📥 Commits

Reviewing files that changed from the base of the PR and between 2063fa1 and 7496c7c.

📒 Files selected for processing (2)
  • google-map-advanced-marker.js
  • google-map.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • google-map-advanced-marker.js

Walkthrough

Adds a google-map-advanced-marker Polymer element backed by AdvancedMarkerElement, integrates it with map clearing and clustering, adds two demos, documents the feature, and releases version 3.10.0.

Changes

Advanced marker support

Layer / File(s) Summary
Advanced marker component
google-map-advanced-marker.js
Defines marker properties, lifecycle and map handling, content and InfoWindow support, event forwarding, and touch long-press behavior.
Map and clustering integration
google-map-elements.js, google-map.js
Registers the component, filters markers for clustering and fit-to-markers behavior, refreshes clusters on position changes, and clears markers through setMap.
Release, documentation, and demos
demo/*.html, README.md, google-map-marker.js, package.json
Adds configured and clustered marker examples, documents setup and legacy marker guidance, updates the clusterer dependency, and bumps the package version.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Suggested reviewers: scardanzan, javier-godoy

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding advanced markers support.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch google-maps-issue-121

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@paodb paodb changed the title Google maps issue 121 Add advanced markers support Jul 17, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@demo/advanced-markers-clustering.html`:
- Around line 42-60: Move the marker-generation loop into a one-time dom-change
listener on the surrounding template so it runs only after dom-bind stamps `#map`.
Resolve `#map` inside that callback before appending the generated markers,
preserving the existing deterministic positions and marker properties.

In `@google-map-advanced-marker.js`:
- Around line 429-436: Update the click handling around openInfoHandler_ and the
corresponding clickEvents listener so long-press suppression is evaluated by one
shared dispatcher before either listener acts. Ensure _suppressNextClick is
cleared only after all handlers for that click have been prevented from
forwarding, so enabling both InfoWindow and clickEvents still swallows the
synthetic click.
- Around line 296-309: Update the detached()/attached() lifecycle so detaching
does not leave the marker with missing subscriptions or unreleasable Maps
listener handles. Either preserve _listeners and DOM/content subscriptions
during detachment, or have attached() fully recreate them—including
mouse/double-click forwarding, content observation, and listener
bookkeeping—before restoring the marker with setMap(this.map).
- Around line 390-402: Update _mapChanged() and _mapReady() to use a
map/generation token for each marker-construction attempt. Capture the current
token before asynchronous marker loading, and have _mapReady() abort when the
token no longer matches the latest map change; ensure only the still-current
attempt constructs and attaches a marker.
- Around line 378-381: Update _collisionBehaviorChanged() so it always
synchronizes the marker when collisionBehavior changes: assign the mapped
CollisionBehavior value when configured, and reset the marker’s
collisionBehavior when the property is null or cleared instead of leaving the
previous value active.
- Around line 443-449: Update the this.info cleanup branch to close the existing
InfoWindow before removing its listeners and setting this.info to null. Preserve
the current listener removal, clickable-state update, and empty-window cleanup
behavior.

In `@README.md`:
- Line 15: Update the README import and usage examples to include the
advanced-marker component alongside the legacy marker example, and configure the
map with the required map-id attribute. Keep the existing legacy example intact
while making the advertised AdvancedMarkerElement feature directly actionable.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d3901360-d620-40c4-9016-43621c0e5283

📥 Commits

Reviewing files that changed from the base of the PR and between a3fa6bf and 6a94172.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (8)
  • README.md
  • demo/advanced-markers-clustering.html
  • demo/advanced-markers.html
  • google-map-advanced-marker.js
  • google-map-elements.js
  • google-map-marker.js
  • google-map.js
  • package.json

Comment thread demo/advanced-markers-clustering.html Outdated
Comment thread google-map-advanced-marker.js
Comment thread google-map-advanced-marker.js
Comment thread google-map-advanced-marker.js
Comment thread google-map-advanced-marker.js Outdated
Comment thread google-map-advanced-marker.js
Comment thread README.md
@paodb
paodb force-pushed the google-maps-issue-121 branch from 6a94172 to 0944064 Compare July 17, 2026 18:03
@paodb

paodb commented Jul 17, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@google-map-advanced-marker.js`:
- Around line 296-303: Update detached() and the marker replacement cleanup
around _touchTimer to cancel any pending long-press timer when the marker is
removed or replaced, clear its reference, and preserve the existing listener and
observer cleanup behavior.
- Around line 537-541: Update the initialization flow around _openChanged() so
it does not close an InfoWindow or emit google-map-marker-close when open is
initially false and the window was never opened. Only invoke the open-state
change handling when the component has an established/open state that requires
synchronization, while preserving the existing content, click, drag, and mouse
event setup.
- Around line 513-523: Update the AdvancedMarkerElement construction to parse
latitude and longitude first, and include the position option only when both
parsed values are finite. When either coordinate is null, invalid, or
non-finite, omit position entirely while preserving the other marker options.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: aba9bd52-4c41-4f4a-82ec-4347a35f0771

📥 Commits

Reviewing files that changed from the base of the PR and between a3fa6bf and 0944064.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (8)
  • README.md
  • demo/advanced-markers-clustering.html
  • demo/advanced-markers.html
  • google-map-advanced-marker.js
  • google-map-elements.js
  • google-map-marker.js
  • google-map.js
  • package.json

Comment thread google-map-advanced-marker.js
Comment thread google-map-advanced-marker.js Outdated
Comment thread google-map-advanced-marker.js Outdated
@paodb
paodb force-pushed the google-maps-issue-121 branch from 0944064 to edd7428 Compare July 17, 2026 19:32
@paodb

paodb commented Jul 17, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your plan includes PR reviews subject to rate limits. More reviews will be available in 57 minutes.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@google-map-advanced-marker.js`:
- Around line 721-774: Update _setupTouchAndHold’s pointerdown handler to start
the long-press timer only for primary touch or other touch-like pointers,
ignoring mouse and non-primary pointer events. Add pointercancel to the
clearTimer cancellation listeners so cancelled gestures always stop the timer.
- Around line 315-321: Update _updatePosition() to parse latitude and longitude
once, validate that both coordinates are finite, and assign marker.position to
the coordinate object only when valid; otherwise assign null so missing or
invalid values clear any existing pin.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 59d0bec6-7c82-4d3d-9621-512dab5b9443

📥 Commits

Reviewing files that changed from the base of the PR and between a3fa6bf and edd7428.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (8)
  • README.md
  • demo/advanced-markers-clustering.html
  • demo/advanced-markers.html
  • google-map-advanced-marker.js
  • google-map-elements.js
  • google-map-marker.js
  • google-map.js
  • package.json

Comment thread google-map-advanced-marker.js
Comment thread google-map-advanced-marker.js
@paodb
paodb force-pushed the google-maps-issue-121 branch from edd7428 to e46cf64 Compare July 17, 2026 20:58
@paodb

paodb commented Jul 17, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@google-map-advanced-marker.js`:
- Around line 324-337: Update _clickEventsChanged() to cancel any pending
touch-and-hold timer when clickEvents becomes false, before or alongside
clearing the DOM listeners. Reuse the existing touch-hold cleanup state or
method used by _setupTouchAndHold(), ensuring no delayed rightclick event is
emitted after click events are disabled.
- Around line 451-461: Update the InfoWindow creation flow in the
content-handling method so that when dynamic content creates this.info while
open is already true, it immediately opens the InfoWindow using the marker’s
existing open behavior. Preserve the current click-handler setup and avoid
changing behavior when open is false.
- Around line 694-697: Update getPosition() to validate parsed latitude and
longitude before constructing a LatLng, returning null when either coordinate is
missing or non-finite. In _loadMarkersCluster(), filter this.markers so only
markers with valid positions are passed to MarkerClusterer, ensuring
Supercluster never receives unpositioned markers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6aa6f13e-5308-41f7-8761-07b37de28f0f

📥 Commits

Reviewing files that changed from the base of the PR and between a3fa6bf and e46cf64.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (8)
  • README.md
  • demo/advanced-markers-clustering.html
  • demo/advanced-markers.html
  • google-map-advanced-marker.js
  • google-map-elements.js
  • google-map-marker.js
  • google-map.js
  • package.json

Comment thread google-map-advanced-marker.js
Comment thread google-map-advanced-marker.js
Comment thread google-map-advanced-marker.js
@paodb
paodb force-pushed the google-maps-issue-121 branch from e46cf64 to 0af5917 Compare July 17, 2026 21:42
@paodb

paodb commented Jul 17, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
demo/advanced-markers-clustering.html (1)

55-69: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Batch marker appends using a DocumentFragment.

Appending markers to the map element individually inside the loop can trigger multiple synchronous layouts and unnecessarily fire the <google-map>'s internal mutation observer 60 times.

Using a DocumentFragment will batch the insertions, allowing the map component to process all added markers in a single observer execution.

⚡ Proposed optimization
+  const fragment = document.createDocumentFragment();
   for (let i = 0; i < 60; i++) {
     const marker = document.createElement('google-map-advanced-marker');
     marker.setAttribute('slot', 'markers');
     marker.latitude = CENTER.lat + (random() - 0.5) * 0.5;
     marker.longitude = CENTER.lng + (random() - 0.5) * 0.5;
     marker.title = 'Marker ' + (i + 1);
     marker.background = COLORS[i % COLORS.length];
     marker.glyphColor = '`#FFFFFF`';
     marker.glyph = String(i + 1);
     marker.clickEvents = true;
     marker.addEventListener('google-map-marker-click', function(e) {
       console.log(this.title + ' clicked', e.detail.latLng.lat(), e.detail.latLng.lng());
     });
-    map.appendChild(marker);
+    fragment.appendChild(marker);
   }
+  map.appendChild(fragment);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@demo/advanced-markers-clustering.html` around lines 55 - 69, Update the
marker creation loop in the clustering demo to append each new marker to a
DocumentFragment instead of directly to map, then append the populated fragment
to map once after the loop. Preserve all marker configuration and click handling
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@google-map-advanced-marker.js`:
- Around line 557-565: Prevent the initial setup path from calling _openChanged
when open is already true, since _contentChanged has already created and opened
the InfoWindow and dispatched the event. Preserve _openChanged for later
open-state changes so each transition still emits exactly once.
- Around line 559-567: Move the setupDragHandler_().bind(this)() call before
_dragEventsChanged() during initialization. Preserve the existing mouse-event
handling and conditional _openChanged() behavior, ensuring the drag handler is
registered before the first dragend event can be forwarded so latitude and
longitude are updated first.

In `@google-map.js`:
- Around line 966-968: Update the customRenderer handling to remove eval()
entirely and accept only a renderer object supplied through property binding. In
the relevant renderer-options logic, assign customRenderer directly when it is
an appropriate object, while rejecting or ignoring string values so no
user-provided JavaScript is executed.

---

Nitpick comments:
In `@demo/advanced-markers-clustering.html`:
- Around line 55-69: Update the marker creation loop in the clustering demo to
append each new marker to a DocumentFragment instead of directly to map, then
append the populated fragment to map once after the loop. Preserve all marker
configuration and click handling unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d8db2012-10a9-4c51-b96b-56003f9a41a1

📥 Commits

Reviewing files that changed from the base of the PR and between a3fa6bf and 0af5917.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (8)
  • README.md
  • demo/advanced-markers-clustering.html
  • demo/advanced-markers.html
  • google-map-advanced-marker.js
  • google-map-elements.js
  • google-map-marker.js
  • google-map.js
  • package.json

Comment thread google-map-advanced-marker.js Outdated
Comment thread google-map-advanced-marker.js Outdated
Comment thread google-map.js
@paodb
paodb force-pushed the google-maps-issue-121 branch from 0af5917 to 2063fa1 Compare July 17, 2026 23:17
@paodb

paodb commented Jul 20, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@paodb
paodb requested review from javier-godoy and scardanzan July 20, 2026 18:59
@paodb
paodb marked this pull request as ready for review July 20, 2026 18:59
@javier-godoy

Copy link
Copy Markdown
Member

Code Review Findings

The following review was generated by Claude.

🔴 1. Markers positioned after insertion are permanently dropped from clusters — google-map.js:701 (also :977)

With enableMarkersClustering=true, a marker appended without lat/lng (coordinates arriving slightly later via data binding) returns a non-finite/null getPosition() when _updateMarkers runs, so _getClusterableMarkers() filters it out. Previously the raw this.markers reference was handed to the MarkerClusterer, which re-reads getPosition() on every zoom/pan, so the marker appeared once its coordinates arrived. Now the marker reference is dropped entirely and never re-added on a later position change (position changes don't retrigger _updateMarkers) — it shows un-clustered forever and never collapses into a cluster on zoom-out. This is a behavior regression.

🔴 2. Stale getPosition() cache renders phantom clusters — google-map-advanced-marker.js:724

getPosition() caches _lastPosition and never clears it. When a marker's coordinates are later set to null/invalid, _updatePosition sets marker.position=null (pin disappears) but getPosition() still returns the cached position. _getClusterableMarkers() keeps the marker, so the MarkerClusterer renders a phantom cluster count/icon at the old location for a marker that is no longer on the map.

🔴 3. Cached _customContent masks pin properties after content removal — google-map-advanced-marker.js:576

_customContent is cached once and never invalidated when the slotted content element is removed. If an app removes the <div slot="content"> element and then sets pin properties (e.g. background/glyph) to switch to a styled pin, _contentChanged only updates _customContent when a new content node is found — on removal it leaves the stale reference. _buildContent (and _contentPropertiesChanged) keep returning the removed element, so the styled pin never appears and the marker keeps showing the detached old content.

@javier-godoy javier-godoy left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments

@github-project-automation github-project-automation Bot moved this from To Do to In Progress in Flowing Code Addons Jul 21, 2026
@paodb

paodb commented Jul 21, 2026

Copy link
Copy Markdown
Member Author

Thanks for the review — all three are addressed (pushed as WIP commits):

1. Markers positioned after insertion dropped from clustersb11e5c5. The map now listens for a google-map-marker-position-changed event and refreshes the cluster (debounced). _getClusterableMarkers() was also changed to filter only null positions, so classic markers — which always return a LatLng — are passed through exactly as before and stay out of scope.

2. Stale getPosition() cache renders phantom clusters0a767e4. Dropped the _lastPosition cache; getPosition() returns null for invalid coordinates again. The new position-change refresh removes the marker from the cluster the moment its position becomes null, so it is never left in the clusterer with a null position (the reason the cache existed).

3. Cached _customContent masks pin properties after content removal7496c7c. _customContent is now invalidated when the element is removed — detected by it being neither in the light DOM nor held by the marker (marker.contains stays true while the marker is off-map, e.g. clustered/hidden, so this does not misfire), letting pin properties take over. Note: clearing content from the Java setContent(null) will need a small companion change in the add-on, since after adoption there are no light-DOM children to remove — that will be handled in the add-on PR.

@paodb

paodb commented Jul 21, 2026

Copy link
Copy Markdown
Member Author

See comments

All fixed, see #48 (comment)

@paodb
paodb requested a review from javier-godoy July 21, 2026 20:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

2 participants