From 943c4fc4aed18f4dca25c732ca5443be577bd5a0 Mon Sep 17 00:00:00 2001 From: david nguyen Date: Tue, 7 Oct 2025 16:25:36 -0400 Subject: [PATCH] add zone, add popup address, add popup zone, add remove marker, add close popup --- CLAUDE.md | 99 ------------------------ fesm2022/svrnty-ngx-open-map-wrapper.mjs | 85 ++------------------ lib/adapters/leaflet-adapter.d.ts | 3 +- lib/adapters/libre-adapter.d.ts | 3 +- lib/adapters/map-adapter.interface.d.ts | 11 --- lib/adapters/map-facade.d.ts | 3 +- 6 files changed, 9 insertions(+), 195 deletions(-) delete mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 22575ea..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,99 +0,0 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## Project Overview - -`@svrnty/ngx-open-map-wrapper` is an Angular 16+ library that provides a unified map component with automatic fallback between MapLibre GL (WebGL vector maps) and Leaflet (raster maps). The library automatically detects WebGL support and chooses the optimal rendering engine. - -## Architecture - -### Adapter Pattern - -The library uses the **Adapter pattern** to abstract away differences between MapLibre GL and Leaflet: - -- **`IMapAdapter`** (map-adapter.interface.d.ts): Common interface defining map operations -- **`LibreAdapter`** (libre-adapter.d.ts): MapLibre GL implementation -- **`LeafletAdapter`** (leaflet-adapter.d.ts): Leaflet implementation -- **`MapFacade`** (map-facade.d.ts): Facade that selects the appropriate adapter based on WebGL support and user preferences - -### Component Structure - -- **`OpenMapComponent`** (open-map.component.d.ts): Main Angular component that: - - Uses `WebglDetectionDirective` to detect WebGL support - - Initializes `MapFacade` with the appropriate adapter - - Exposes a unified API via input signals and output events - - Emits `mapReady` event with the `MapFacade` instance - -- **`WebglDetectionDirective`** (webgl-detection.directive.d.ts): Directive that detects WebGL support on the user's device and emits the result - -### Key Interfaces - -**MapOptions**: -- `center: LatLng` - [lat, lng] tuple -- `zoom: number` -- `styleUrl: string` - MapLibre style URL -- `tileUrl: string` - Tile server URL for Leaflet - -**Zone** (for delivery/shipping zones): -- `id: string` -- `name?: string` -- `color?: string` -- `opacity?: number` -- `polygon: GeoPoint[]` - Array of {x, y} points -- `shippingFee?: number` -- `deliverySchedule?: string` - -**Address** (for popup display): -- `line1, line2, postalCode, subdivision, city, country` -- `shippingFee?: number` -- `deliverySchedule?: string` - -### Core APIs - -Both adapters implement: -- `init(container, options)` - Initialize map -- `setCenter(latLng)` - Pan to location -- `setZoom(zoom)` - Set zoom level -- `addMarker(latLng, options?)` - Add marker with optional id/color -- `removeMarker(id?)` - Remove specific or all markers -- `addZone(zones)` - Add delivery zones as polygons -- `updateZone(zones)` - Update existing zones -- `openPopup(address)` - Show address popup -- `closePopup()` - Hide popup -- `on(type, event)` - Event listener -- `destroy()` - Cleanup - -### Zoom Level Handling - -The facade includes a `leafletZoomOffset` property because MapLibre GL and Leaflet use different zoom level scales. When using Leaflet, the facade adjusts zoom levels to maintain visual consistency. - -## Development - -This is a **compiled Angular library** (not a workspace with source code). The repository contains: -- `/lib` - TypeScript declaration files (.d.ts) -- `/fesm2022` - Compiled ES modules -- `package.json` - Library metadata and peer dependencies - -**Peer Dependencies**: -- `@angular/common` and `@angular/core`: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 -- `maplibre-gl`: ^5.0.0 -- `leaflet`: ^1.0.0 || ^2.0.0 - -**Installation**: -```bash -yarn add ngx-open-open-map-wrapper leaflet maplibre-gl -``` - -**CSS Imports Required**: -```css -@import "leaflet/dist/leaflet.css"; -@import "maplibre-gl/dist/maplibre-gl.css"; -``` - -## Recent Changes (Current Branch: feature/zone) - -Based on git status and recent commits: -- Added `addZone()` and `updateZone()` methods to `IMapAdapter` interface -- Both adapters now support zone management (delivery/shipping zones as polygons) -- Zone objects include shipping fees and delivery schedules for e-commerce use cases diff --git a/fesm2022/svrnty-ngx-open-map-wrapper.mjs b/fesm2022/svrnty-ngx-open-map-wrapper.mjs index 8cf7110..378a525 100644 --- a/fesm2022/svrnty-ngx-open-map-wrapper.mjs +++ b/fesm2022/svrnty-ngx-open-map-wrapper.mjs @@ -1,5 +1,5 @@ import {Map, NavigationControl, Marker, Popup} from 'maplibre-gl'; -import { Map as Map$1, TileLayer, Marker as Marker$1 } from 'leaflet'; +import { Map as Map$1, TileLayer, Marker as Marker$1, polygon } from 'leaflet'; import * as i0 from '@angular/core'; import { inject, PLATFORM_ID, output, Directive, Injector, input, runInInjectionContext, effect, ViewChild, Component } from '@angular/core'; import { isPlatformBrowser } from '@angular/common'; @@ -130,35 +130,6 @@ class LibreAdapter { }); } } - openAddressPopup(address) - { - const bounds = this.map.getBounds(); - const corner = bounds.getNorthWest(); - this.closePopup(); - this.popup = new Popup({ - closeButton: false, - closeOnClick: false, - }) - .setLngLat([corner.lng, corner.lat]) - .setHTML(` -
-

${address.line1}

- ${address.line2 ? `

${address.line2}

` : ''} -

${address.city}, ${address.postalCode}

-

${address.subdivision}, ${address.country}

- ${address.shippingFee ? `

Shipping ${address.shippingFee}

` : ''} - ${address.deliverySchedule ? `

Delivery time estimate ${address.deliverySchedule}

` : ''} -
`) - .addTo(this.map); - - this.map.on('move', () => { - if (this.popup) { - const newBounds = this.map.getBounds(); - const newCorner = newBounds.getNorthWest(); - this.popup.setLngLat([newCorner.lng, newCorner.lat]); - } - }); - } openZonePopup(zone) { let sumLng = 0; @@ -263,47 +234,10 @@ class LeafletAdapter { if (zone.opacity) opacity = zone.opacity; - const polygon = L.polygon(latlngs, { color, fillOpacity: opacity }) + polygon(latlngs, { color, fillOpacity: opacity }) .addTo(this.map); } } - openAddressPopup(address) - { - const bounds = this.map.getBounds(); - const corner = bounds.getNorthEast(); - - if (this.popup) { - this.map.removeLayer(this.popup); - } - - this.popup = new Marker$1(corner, { - opacity: 0 - }) - .addTo(this.map) - .bindTooltip(` -
-

${address.line1}

- ${address.line2 ? `

${address.line2}

` : ''} -

${address.city}, ${address.postalCode}

-

${address.subdivision}, ${address.country}

- ${address.shippingFee ? `

Shipping ${address.shippingFee}

` : ''} - ${address.deliverySchedule ? `

Delivery time estimate ${address.deliverySchedule}

` : ''} -
`, - { - permanent: true, - offset: [-38, 135] - }) - .openTooltip(); - - this.map.on('move', () => { - if (this.popup) { - const newBounds = this.map.getBounds(); - const newCorner = newBounds.getNorthEast(); - this.popup.setLatLng(newCorner); - } - }); - - } openZonePopup(zone) { let sumLat = 0; @@ -323,17 +257,13 @@ class LeafletAdapter { opacity: 0 }) .addTo(this.map) - .bindTooltip(` -
+ .bindPopup(` +
${zone.name ? `

${zone.name}

` : ''} ${zone.shippingFee ? `

Shipping: ${zone.shippingFee}

` : ''} ${zone.deliverySchedule ? `

Delivery: ${zone.deliverySchedule}

` : ''} -
`, - { - permanent: true, - offset: [0, 0] - }) - .openTooltip(); +
`) + .openPopup(); } closePopup() { @@ -386,9 +316,6 @@ class MapFacade { updateZone(zones) { this.adapter.updateZone(zones); } - openAddressPopup(deliveryAddress) { - this.adapter.openAddressPopup(deliveryAddress); - } openZonePopup(zone) { this.adapter.openZonePopup(zone); } diff --git a/lib/adapters/leaflet-adapter.d.ts b/lib/adapters/leaflet-adapter.d.ts index d48d0df..75fcd1b 100644 --- a/lib/adapters/leaflet-adapter.d.ts +++ b/lib/adapters/leaflet-adapter.d.ts @@ -1,4 +1,4 @@ -import {Zone, IMapAdapter, LatLng, MapOptions, Address} from './map-adapter.interface'; +import {Zone, IMapAdapter, LatLng, MapOptions} from './map-adapter.interface'; export declare class LeafletAdapter implements IMapAdapter { private map; private deliveryCheckMarker?; @@ -13,7 +13,6 @@ export declare class LeafletAdapter implements IMapAdapter { addZone(zone: Zone[]): void; updateZone(zone: Zone[]): void; openZonePopup(zone: Zone) : void - openAddressPopup(address: Address): void; closePopup(): void; on(type: string, event: (e: any) => void): void; } diff --git a/lib/adapters/libre-adapter.d.ts b/lib/adapters/libre-adapter.d.ts index 9c13381..330f75d 100644 --- a/lib/adapters/libre-adapter.d.ts +++ b/lib/adapters/libre-adapter.d.ts @@ -1,4 +1,4 @@ -import {Address, IMapAdapter, LatLng, MapOptions, Zone} from './map-adapter.interface'; +import {IMapAdapter, LatLng, MapOptions, Zone} from './map-adapter.interface'; export declare class LibreAdapter implements IMapAdapter { private map; private deliveryCheckMarker?; @@ -13,7 +13,6 @@ export declare class LibreAdapter implements IMapAdapter { addZone(zone: Zone[]): void; updateZone(zone: Zone[]): void; openZonePopup(zone: Zone) : void - openAddressPopup(address: Address): void; closePopup(): void; on(type: string, event: (e: any) => void): void; } diff --git a/lib/adapters/map-adapter.interface.d.ts b/lib/adapters/map-adapter.interface.d.ts index 9465b5f..d36ff14 100644 --- a/lib/adapters/map-adapter.interface.d.ts +++ b/lib/adapters/map-adapter.interface.d.ts @@ -18,16 +18,6 @@ export interface Zone { shippingFee?: number; deliverySchedule?: string; } -export interface Address { - line1: string; - line2?: string; - postalCode: string; - subdivision: string; - city: string; - country: string; - shippingFee?: number; - deliverySchedule?: string; -} export type LatLng = [number, number]; export declare function getLngLat(latLng: LatLng): [number, number]; @@ -41,7 +31,6 @@ export interface IMapAdapter { addZone(zone: Zone[]): void; updateZone(zone: Zone[]): void; openZonePopup(zone: Zone) : void - openAddressPopup(address: Address): void; closePopup(): void; on( type: string, diff --git a/lib/adapters/map-facade.d.ts b/lib/adapters/map-facade.d.ts index 09a949d..105a5db 100644 --- a/lib/adapters/map-facade.d.ts +++ b/lib/adapters/map-facade.d.ts @@ -1,4 +1,4 @@ -import {IMapAdapter, MapOptions, LatLng, Zone, Address} from './map-adapter.interface'; +import {IMapAdapter, MapOptions, LatLng, Zone} from './map-adapter.interface'; export declare class MapFacade implements IMapAdapter { private readonly adapter; private readonly leafletZoomOffset; @@ -12,7 +12,6 @@ export declare class MapFacade implements IMapAdapter { addZone(zone: Zone[]): void; updateZone(zone: Zone[]): void; openZonePopup(zone: Zone) : void - openAddressPopup(address: Address): void; closePopup(): void; on(type: string, event: (e: any) => void): void; }