add zone, add popup address, add popup zone, add remove marker, add close popup
This commit is contained in:
parent
849a6f07a0
commit
943c4fc4ae
99
CLAUDE.md
99
CLAUDE.md
@ -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
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import {Map, NavigationControl, Marker, Popup} from 'maplibre-gl';
|
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 * as i0 from '@angular/core';
|
||||||
import { inject, PLATFORM_ID, output, Directive, Injector, input, runInInjectionContext, effect, ViewChild, Component } from '@angular/core';
|
import { inject, PLATFORM_ID, output, Directive, Injector, input, runInInjectionContext, effect, ViewChild, Component } from '@angular/core';
|
||||||
import { isPlatformBrowser } from '@angular/common';
|
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(`
|
|
||||||
<div class="delivery-address">
|
|
||||||
<p>${address.line1}</p>
|
|
||||||
${address.line2 ? `<p>${address.line2}</p>` : ''}
|
|
||||||
<p>${address.city}, ${address.postalCode}</p>
|
|
||||||
<p>${address.subdivision}, ${address.country}</p>
|
|
||||||
${address.shippingFee ? `<p>Shipping ${address.shippingFee}</p>` : ''}
|
|
||||||
${address.deliverySchedule ? `<p>Delivery time estimate ${address.deliverySchedule}</p>` : ''}
|
|
||||||
</div>`)
|
|
||||||
.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)
|
openZonePopup(zone)
|
||||||
{
|
{
|
||||||
let sumLng = 0;
|
let sumLng = 0;
|
||||||
@ -263,47 +234,10 @@ class LeafletAdapter {
|
|||||||
if (zone.opacity)
|
if (zone.opacity)
|
||||||
opacity = zone.opacity;
|
opacity = zone.opacity;
|
||||||
|
|
||||||
const polygon = L.polygon(latlngs, { color, fillOpacity: opacity })
|
polygon(latlngs, { color, fillOpacity: opacity })
|
||||||
.addTo(this.map);
|
.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(`
|
|
||||||
<div class="delivery-address">
|
|
||||||
<p>${address.line1}</p>
|
|
||||||
${address.line2 ? `<p>${address.line2}</p>` : ''}
|
|
||||||
<p>${address.city}, ${address.postalCode}</p>
|
|
||||||
<p>${address.subdivision}, ${address.country}</p>
|
|
||||||
${address.shippingFee ? `<p>Shipping ${address.shippingFee}</p>` : ''}
|
|
||||||
${address.deliverySchedule ? `<p>Delivery time estimate ${address.deliverySchedule}</p>` : ''}
|
|
||||||
</div>`,
|
|
||||||
{
|
|
||||||
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)
|
openZonePopup(zone)
|
||||||
{
|
{
|
||||||
let sumLat = 0;
|
let sumLat = 0;
|
||||||
@ -323,17 +257,13 @@ class LeafletAdapter {
|
|||||||
opacity: 0
|
opacity: 0
|
||||||
})
|
})
|
||||||
.addTo(this.map)
|
.addTo(this.map)
|
||||||
.bindTooltip(`
|
.bindPopup(`
|
||||||
<div class="delivery-zone">
|
<div >
|
||||||
${zone.name ? `<p><strong>${zone.name}</strong></p>` : ''}
|
${zone.name ? `<p><strong>${zone.name}</strong></p>` : ''}
|
||||||
${zone.shippingFee ? `<p>Shipping: ${zone.shippingFee}</p>` : ''}
|
${zone.shippingFee ? `<p>Shipping: ${zone.shippingFee}</p>` : ''}
|
||||||
${zone.deliverySchedule ? `<p>Delivery: ${zone.deliverySchedule}</p>` : ''}
|
${zone.deliverySchedule ? `<p>Delivery: ${zone.deliverySchedule}</p>` : ''}
|
||||||
</div>`,
|
</div>`)
|
||||||
{
|
.openPopup();
|
||||||
permanent: true,
|
|
||||||
offset: [0, 0]
|
|
||||||
})
|
|
||||||
.openTooltip();
|
|
||||||
}
|
}
|
||||||
closePopup()
|
closePopup()
|
||||||
{
|
{
|
||||||
@ -386,9 +316,6 @@ class MapFacade {
|
|||||||
updateZone(zones) {
|
updateZone(zones) {
|
||||||
this.adapter.updateZone(zones);
|
this.adapter.updateZone(zones);
|
||||||
}
|
}
|
||||||
openAddressPopup(deliveryAddress) {
|
|
||||||
this.adapter.openAddressPopup(deliveryAddress);
|
|
||||||
}
|
|
||||||
openZonePopup(zone) {
|
openZonePopup(zone) {
|
||||||
this.adapter.openZonePopup(zone);
|
this.adapter.openZonePopup(zone);
|
||||||
}
|
}
|
||||||
|
|||||||
3
lib/adapters/leaflet-adapter.d.ts
vendored
3
lib/adapters/leaflet-adapter.d.ts
vendored
@ -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 {
|
export declare class LeafletAdapter implements IMapAdapter {
|
||||||
private map;
|
private map;
|
||||||
private deliveryCheckMarker?;
|
private deliveryCheckMarker?;
|
||||||
@ -13,7 +13,6 @@ export declare class LeafletAdapter implements IMapAdapter {
|
|||||||
addZone(zone: Zone[]): void;
|
addZone(zone: Zone[]): void;
|
||||||
updateZone(zone: Zone[]): void;
|
updateZone(zone: Zone[]): void;
|
||||||
openZonePopup(zone: Zone) : void
|
openZonePopup(zone: Zone) : void
|
||||||
openAddressPopup(address: Address): void;
|
|
||||||
closePopup(): void;
|
closePopup(): void;
|
||||||
on(type: string, event: (e: any) => void): void;
|
on(type: string, event: (e: any) => void): void;
|
||||||
}
|
}
|
||||||
|
|||||||
3
lib/adapters/libre-adapter.d.ts
vendored
3
lib/adapters/libre-adapter.d.ts
vendored
@ -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 {
|
export declare class LibreAdapter implements IMapAdapter {
|
||||||
private map;
|
private map;
|
||||||
private deliveryCheckMarker?;
|
private deliveryCheckMarker?;
|
||||||
@ -13,7 +13,6 @@ export declare class LibreAdapter implements IMapAdapter {
|
|||||||
addZone(zone: Zone[]): void;
|
addZone(zone: Zone[]): void;
|
||||||
updateZone(zone: Zone[]): void;
|
updateZone(zone: Zone[]): void;
|
||||||
openZonePopup(zone: Zone) : void
|
openZonePopup(zone: Zone) : void
|
||||||
openAddressPopup(address: Address): void;
|
|
||||||
closePopup(): void;
|
closePopup(): void;
|
||||||
on(type: string, event: (e: any) => void): void;
|
on(type: string, event: (e: any) => void): void;
|
||||||
}
|
}
|
||||||
|
|||||||
11
lib/adapters/map-adapter.interface.d.ts
vendored
11
lib/adapters/map-adapter.interface.d.ts
vendored
@ -18,16 +18,6 @@ export interface Zone {
|
|||||||
shippingFee?: number;
|
shippingFee?: number;
|
||||||
deliverySchedule?: string;
|
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 type LatLng = [number, number];
|
||||||
export declare function getLngLat(latLng: LatLng): [number, number];
|
export declare function getLngLat(latLng: LatLng): [number, number];
|
||||||
@ -41,7 +31,6 @@ export interface IMapAdapter {
|
|||||||
addZone(zone: Zone[]): void;
|
addZone(zone: Zone[]): void;
|
||||||
updateZone(zone: Zone[]): void;
|
updateZone(zone: Zone[]): void;
|
||||||
openZonePopup(zone: Zone) : void
|
openZonePopup(zone: Zone) : void
|
||||||
openAddressPopup(address: Address): void;
|
|
||||||
closePopup(): void;
|
closePopup(): void;
|
||||||
on(
|
on(
|
||||||
type: string,
|
type: string,
|
||||||
|
|||||||
3
lib/adapters/map-facade.d.ts
vendored
3
lib/adapters/map-facade.d.ts
vendored
@ -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 {
|
export declare class MapFacade implements IMapAdapter {
|
||||||
private readonly adapter;
|
private readonly adapter;
|
||||||
private readonly leafletZoomOffset;
|
private readonly leafletZoomOffset;
|
||||||
@ -12,7 +12,6 @@ export declare class MapFacade implements IMapAdapter {
|
|||||||
addZone(zone: Zone[]): void;
|
addZone(zone: Zone[]): void;
|
||||||
updateZone(zone: Zone[]): void;
|
updateZone(zone: Zone[]): void;
|
||||||
openZonePopup(zone: Zone) : void
|
openZonePopup(zone: Zone) : void
|
||||||
openAddressPopup(address: Address): void;
|
|
||||||
closePopup(): void;
|
closePopup(): void;
|
||||||
on(type: string, event: (e: any) => void): void;
|
on(type: string, event: (e: any) => void): void;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user