angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.39k stars 6.76k forks source link

bug(google-map): Flaky SVG Marker Rendering #30078

Closed Tristan-Day-FOS closed 3 days ago

Tristan-Day-FOS commented 4 days ago

Is this a regression?

The previous version in which this bug was not present was

No response

Description

When creating markers using the svg marker element, some parts of the SVG fail to render at different zoom levels.

Image Image

Zooming in to make it render and then zooming out will cause it to behave as expected but will break markers that where taken off-screen.

Image

Reproduction

I cannot recreate the issue in stackblitz due to licence key requirements with the advanced marker component.

Here is further detail on the component structure.

<google-map [options]="options()" height="100vh" width="100vw" #map>

  @if (service.route.history | async) {
    <map-polyline [path]="(service.route.history | async)!" [options]="DEFAULT_POLYLINE_OPTIONS" />
  }

  @if (service.route.suggested | async) {
    <map-directions-renderer [directions]="(service.route.suggested | async)!" [options]="DEFAULT_DIRECTIONS_OPTIONS" />
  }

  @for (marker of service.markers | async; track $index) {
    <map-advanced-marker [position]="marker.position" [content]="marker.node" (mapClick)="onMarkerClicked($index)" />
  }
</google-map>

A marker is generated using typescript and DOM parser

        const node = Assets.generateDriverMarker({
          status: { ... }, vehicle: driver.vehicleId?.vehicleModel, callsign: driver.callSign,
        })

For example

function generateUnallocatedMarker(marker: DriverMarker): string {
  let colour = '#F44336';

  if (marker.status.tracked) {
    colour = '#4CAF50';
  }

  let label = marker.callsign.toUpperCase();

  if (marker.vehicle) {
    label += ` - ${marker.vehicle.toUpperCase()}`;
  }

  // prettier-ignore
  return `
    <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="180" viewBox="0 0 327.68 200" id="${marker.callsign}">
      <g id="dp_dp001">
        <rect fill="black" x="${(327.68 - label.length * 20) / 2}" y="20" width="${label.length * 20}" height="40" rx="8" />
      </g>
      <g id="dp_dp002">
        <text x="${327.68 / 2}" y="50" font-size="25" font-family="Martian Mono" text-anchor="middle" fill="white">
          ${label}
        </text>
      </g>
      <defs>
        <filter id="dropShadow" x="-20%" y="-20%" width="140%" height="140%">
          <feDropShadow dx="0" dy="-3" stdDeviation="7" flood-color="black" flood-opacity="0.7" />
        </filter>
      </defs>
      <g id="dp_dp003" transform="matrix(1,0,0,1,-1284.94,-115.667)" filter="url(#dropShadow)">
        ...
      </g>
    </svg>
  `;
}```

### Expected Behavior

I would expect the markers to render as they are defined in the SVG code. 

### Actual Behavior

The markers only partially render despite no code existing to alter them in this way. Changing to a higher zoom level causes those visible in the viewbox to render correctly while those outside will break.

### Environment

I am using Angular version 18.2.10  with @angular/google-maps version 18.2.9.

I am using the zoneless change detection. 

```ts
platformBrowser().bootstrapModule(AppModule, {
  ngZone: 'noop', providers: [{ provide: LOCALE_ID, useValue: 'en-GB' }],
});
crisbeto commented 3 days ago

Closing since this is likely an issue either with Google Maps or your setup specifically. If I had to guess, I'd say that it's because you have id attributes in the SVG icons and IDs need to be unique in the page.

Tristan-Day-FOS commented 2 days ago

Thanks, updating the IDS for the relevant SVG parts resolved the issue.