ngx-gaia-gis
Version:
GaiaGisService is an Angular library that simplifies the integration of interactive maps using OpenLayers. It allows for visualizing raster maps, adding custom points, and adjusting views easily, making it ideal for developers who need to implement geospa
803 lines (796 loc) • 32.6 kB
JavaScript
import * as i0 from '@angular/core';
import { inject, PLATFORM_ID, signal, computed, linkedSignal, Injectable, output, Input, Component } from '@angular/core';
import { isPlatformServer, isPlatformBrowser } from '@angular/common';
import TileLayer from 'ol/layer/Tile';
import { XYZ } from 'ol/source';
import { fromLonLat, toLonLat, transformExtent } from 'ol/proj';
import { Map, View, Feature } from 'ol';
import { Style, Fill, Stroke, Circle, Icon } from 'ol/style';
import { Point, Polygon } from 'ol/geom';
import VectorLayer from 'ol/layer/Vector';
import 'ol/ol.css';
import VectorSource from 'ol/source/Vector';
import OSM from 'ol/source/OSM';
import { jsPDF } from 'jspdf';
import Overlay from 'ol/Overlay';
import Draw from 'ol/interaction/Draw';
var MapsDesign;
(function (MapsDesign) {
MapsDesign["CARTOCDN"] = "https://{1-4}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png";
MapsDesign["GNOSIS_EARTH"] = "https://maps.gnosis.earth/ogcapi/collections/NaturalEarth:raster:HYP_HR_SR_OB_DR/map/tiles/WebMercatorQuad";
MapsDesign["OSM"] = "OSM";
})(MapsDesign || (MapsDesign = {}));
class GaiaGisService {
platform = inject(PLATFORM_ID);
map;
labels = new TileLayer({
source: new XYZ({
attributions: 'Gaia-GIS by © <a href="https://carto.com/attribution">Olympus Analytics</a>',
}),
});
rasterLayers = [];
pointLayer;
popup;
// Polygon drawing properties
polygonLayer;
drawInteraction = null;
keyListener = null;
// Highlight layer for the starting point
highlightLayer;
startPointFeature = null;
// 🔥 Angular 20 Signals for reactive state management
/**
* Signal to track if polygon drawing is active
*/
isDrawingPolygon = signal(false, ...(ngDevMode ? [{ debugName: "isDrawingPolygon" }] : []));
/**
* Signal to store the current polygon being drawn
*/
currentPolygon = signal(null, ...(ngDevMode ? [{ debugName: "currentPolygon" }] : []));
/**
* Signal to store all completed polygons
*/
completedPolygons = signal([], ...(ngDevMode ? [{ debugName: "completedPolygons" }] : []));
/**
* Signal to track drawing mode state
*/
drawingState = signal('idle', ...(ngDevMode ? [{ debugName: "drawingState" }] : []));
/**
* Computed signal for drawing status message
*/
drawingStatus = computed(() => {
const state = this.drawingState();
const isDrawing = this.isDrawingPolygon();
switch (state) {
case 'idle':
return 'Ready to draw';
case 'drawing':
return 'Click to add vertices. Press Enter or click start point to complete.';
case 'completing':
return 'Polygon completed!';
case 'cancelled':
return 'Drawing cancelled';
default:
return 'Ready to draw';
}
}, ...(ngDevMode ? [{ debugName: "drawingStatus" }] : []));
/**
* Computed signal for polygon count
*/
polygonCount = computed(() => this.completedPolygons().length, ...(ngDevMode ? [{ debugName: "polygonCount" }] : []));
// 🔥 Linked signal to handle auto-reset of drawing state
autoResetState = linkedSignal(() => {
const state = this.drawingState();
if (state === 'completing' || state === 'cancelled') {
console.log(`Drawing state changed: ${state}, auto-resetting in 2s`);
setTimeout(() => {
this.drawingState.set('idle');
}, 2000);
}
return state;
});
// 🔥 Linked signal to track polygon count changes
polygonLogger = linkedSignal(() => {
const polygons = this.completedPolygons();
const count = polygons.length;
if (count > 0) {
console.log(`Total polygons: ${count}`);
console.log('Latest polygon:', polygons[count - 1]);
}
return count;
});
// 🔥 Public computed signals that activate the linkedSignals by consuming them
stateStatus = computed(() => {
// This computed consumes the autoResetState linkedSignal, keeping it active
const state = this.autoResetState();
return `Current state: ${state}`;
}, ...(ngDevMode ? [{ debugName: "stateStatus" }] : []));
polygonLogger$ = computed(() => {
// This computed consumes the polygonLogger linkedSignal, keeping it active
return this.polygonLogger();
}, ...(ngDevMode ? [{ debugName: "polygonLogger$" }] : []));
constructor() {
if (isPlatformServer(this.platform))
return; // Skip initialization on server side
this.pointLayer = new VectorLayer({
source: new VectorSource(),
});
// 🔥 LinkedSignals will be activated when accessed by computeds
this.polygonLayer = new VectorLayer({
source: new VectorSource(),
style: new Style({
stroke: new Stroke({
color: '#ff0000',
width: 2,
}),
fill: new Fill({
color: 'rgba(255, 0, 0, 0.1)',
}),
}),
});
// Layer for highlighting the starting point
this.highlightLayer = new VectorLayer({
source: new VectorSource(),
style: new Style({
image: new Circle({
radius: 8,
fill: new Fill({
color: 'rgba(0, 255, 0, 0.8)', // Bright green
}),
stroke: new Stroke({
color: '#00ff00',
width: 3,
}),
}),
}),
zIndex: 1000, // Ensure it's on top
});
}
/**
* Initializes the map with the specified target, center, zoom level, and design.
* @param {string} target - The target element ID for the map.
* @param {Object} options - Options for configuring the map.
* @param {[number, number]} [options.center=[0, 0]] - The initial center of the map.
* @param {number} [options.zoom=2] - The initial zoom level of the map.
* @param {string} [options.design=MapsDesign.CARTOCDN] - The design of the map.
*/
initializeMap(target, options = {}) {
if (isPlatformServer(this.platform))
return; // Skip initialization on server side
const { center = [0, 0], zoom = 2, design = MapsDesign.CARTOCDN } = options;
let baseLayer;
if (design.includes('{z}') &&
design.includes('{x}') &&
design.includes('{y}')) {
baseLayer = new TileLayer({
source: new XYZ({
url: design,
crossOrigin: 'anonymous',
}),
});
}
else {
baseLayer = new TileLayer({
source: new OSM(),
});
}
this.labels = new TileLayer({
source: new XYZ({
url: 'https://{1-4}.basemaps.cartocdn.com/dark_only_labels/{z}/{x}/{y}.png',
attributions: 'Gaia-GIS by © <a href="https://carto.com/attribution">Olympus Analytics</a>',
crossOrigin: 'anonymous',
}),
});
this.map = new Map({
target: target,
layers: [
baseLayer,
this.pointLayer,
this.polygonLayer,
this.highlightLayer, // Add highlight layer on top
],
view: new View({
center: fromLonLat(center),
zoom: zoom,
}),
});
this.initializePopup();
}
/**
* Initializes the popup overlay for the map.
*/
initializePopup() {
if (isPlatformServer(this.platform))
return; // Skip initialization on server side
const container = document.getElementById('popup');
const content = document.getElementById('popup-content');
this.popup = new Overlay({
element: container,
autoPan: true,
});
this.map.addOverlay(this.popup);
let isPopupVisible = false;
this.map.on('click', (event) => {
const feature = this.map.forEachFeatureAtPixel(event.pixel, (feat) => feat);
if (feature && feature.get('info')) {
const coordinates = feature.getGeometry().getCoordinates();
content.innerHTML = feature.get('info');
this.popup.setPosition(coordinates);
if (!isPopupVisible) {
container.classList.remove('hide');
container.classList.add('show');
isPopupVisible = true;
}
}
else {
if (isPopupVisible) {
container.classList.remove('show');
container.classList.add('hide');
isPopupVisible = false;
}
setTimeout(() => {
this.popup.setPosition(undefined);
}, 300);
}
});
this.map.on('pointermove', (event) => {
this.map.getTargetElement().style.cursor = this.map.hasFeatureAtPixel(event.pixel)
? 'pointer'
: '';
});
}
/**
* Highlights the starting point of the polygon being drawn
* @param {[number, number]} coordinate - The coordinate to highlight
*/
highlightStartPoint(coordinate) {
if (isPlatformServer(this.platform))
return; // Skip on server side
this.clearStartPointHighlight();
this.startPointFeature = new Feature({
geometry: new Point(coordinate),
});
// Add pulsing animation effect
const style = new Style({
image: new Circle({
radius: 8,
fill: new Fill({
color: 'rgba(0, 255, 0, 0.8)',
}),
stroke: new Stroke({
color: '#00ff00',
width: 3,
}),
}),
});
this.startPointFeature.setStyle(style);
this.highlightLayer.getSource().addFeature(this.startPointFeature);
// Add pulsing effect with CSS-like animation
this.animateStartPoint();
}
/**
* Animates the starting point with a pulsing effect
*/
animateStartPoint() {
if (isPlatformServer(this.platform))
return; // Skip on server side
if (!this.startPointFeature || !this.isDrawingPolygon()) {
return;
}
let radius = 8;
let growing = true;
const animate = () => {
if (!this.startPointFeature || !this.isDrawingPolygon()) {
return;
}
if (growing) {
radius += 0.5;
if (radius >= 12)
growing = false;
}
else {
radius -= 0.5;
if (radius <= 8)
growing = true;
}
const style = new Style({
image: new Circle({
radius: radius,
fill: new Fill({
color: 'rgba(0, 255, 0, 0.6)',
}),
stroke: new Stroke({
color: '#00ff00',
width: 3,
}),
}),
});
this.startPointFeature.setStyle(style);
if (this.isDrawingPolygon()) {
setTimeout(animate, 100);
}
};
animate();
}
/**
* Clears the starting point highlight
*/
clearStartPointHighlight() {
if (isPlatformServer(this.platform))
return; // Skip on server side
const source = this.highlightLayer.getSource();
if (source) {
source.clear();
}
this.startPointFeature = null;
}
/**
* 🔥 Starts polygon drawing mode using signals for state management.
* Users can click to add vertices and complete the polygon by clicking the first point again or pressing Enter.
*/
startPolygonDraw() {
if (isPlatformServer(this.platform))
return; // Skip on server side
if (this.isDrawingPolygon()) {
this.cancelPolygonDraw();
}
// 🔥 Update signals
this.isDrawingPolygon.set(true);
this.drawingState.set('drawing');
this.currentPolygon.set(null);
this.map.getTargetElement().style.cursor = 'crosshair';
// Create draw interaction for polygons
this.drawInteraction = new Draw({
source: this.polygonLayer.getSource(),
type: 'Polygon',
style: new Style({
stroke: new Stroke({
color: '#ff0000',
width: 2,
}),
fill: new Fill({
color: 'rgba(255, 0, 0, 0.1)',
}),
}),
});
// Handle drawing start to highlight the first point
this.drawInteraction.on('drawstart', (event) => {
// Listen for the first coordinate
const geometry = event.feature.getGeometry();
// Use a small delay to ensure the coordinate is set
setTimeout(() => {
const coordinates = geometry.getCoordinates()[0];
if (coordinates && coordinates.length > 0) {
const firstCoord = coordinates[0];
this.highlightStartPoint(firstCoord);
}
}, 50);
});
// Handle polygon completion
this.drawInteraction.on('drawend', (event) => {
const feature = event.feature;
const geometry = feature.getGeometry();
const coordinates = geometry.getCoordinates()[0]; // Get outer ring coordinates
// Convert coordinates from EPSG:3857 to EPSG:4326 (lat/lng)
const latLngCoordinates = coordinates.map((coord) => toLonLat(coord));
// Create polygon data with unique ID
const polygonId = Date.now();
const polygonData = {
coordinates: latLngCoordinates,
properties: {
id: polygonId,
createdAt: new Date().toISOString(),
},
};
// 🔥 Associate the feature with the polygon ID for later removal
feature.set('polygonId', polygonId);
feature.set('polygonData', polygonData);
// 🔥 Update signals
this.currentPolygon.set(polygonData);
this.completedPolygons.update((polygons) => [...polygons, polygonData]);
this.drawingState.set('completing');
// Clean up
this.stopPolygonDraw();
});
// Add the draw interaction to the map
this.map.addInteraction(this.drawInteraction);
// Add keyboard listener for Enter key to complete polygon
this.keyListener = (event) => {
if (event.key === 'Enter' && this.isDrawingPolygon()) {
this.drawInteraction?.finishDrawing();
}
else if (event.key === 'Escape' && this.isDrawingPolygon()) {
this.cancelPolygonDraw();
}
};
document.addEventListener('keydown', this.keyListener);
}
/**
* 🔥 Cancels the current polygon drawing operation using signals.
*/
cancelPolygonDraw() {
if (isPlatformServer(this.platform))
return; // Skip on server side
if (!this.isDrawingPolygon()) {
return;
}
// 🔥 Update signals
this.drawingState.set('cancelled');
this.currentPolygon.set(null);
this.stopPolygonDraw();
// Clear any incomplete drawing
const source = this.polygonLayer.getSource();
if (source) {
source.clear();
}
}
/**
* Stops polygon drawing mode and cleans up resources.
*/
stopPolygonDraw() {
if (isPlatformServer(this.platform))
return; // Skip on server side
// 🔥 Update signal
this.isDrawingPolygon.set(false);
this.map.getTargetElement().style.cursor = '';
if (this.drawInteraction) {
this.map.removeInteraction(this.drawInteraction);
this.drawInteraction = null;
}
if (this.keyListener) {
document.removeEventListener('keydown', this.keyListener);
this.keyListener = null;
}
// Clear the starting point highlight
this.clearStartPointHighlight();
}
/**
* 🔥 Clears all drawn polygons from the map using signals.
*/
clearPolygons() {
if (isPlatformServer(this.platform))
return; // Skip on server side
console.log(`🗑️ Clearing all polygons...`);
const source = this.polygonLayer.getSource();
if (source) {
const featureCount = source.getFeatures().length;
source.clear();
console.log(`🗑️ Cleared ${featureCount} features from map`);
}
// 🔥 Reset signals
const polygonCount = this.completedPolygons().length;
this.completedPolygons.set([]);
this.currentPolygon.set(null);
console.log(`📊 Cleared ${polygonCount} polygons from signals`);
// Also clear any highlights
this.clearStartPointHighlight();
}
/**
* 🔥 Get the latest completed polygon using signals
*/
getLatestPolygon() {
const polygons = this.completedPolygons();
return polygons.length > 0 ? polygons[polygons.length - 1] : null;
}
/**
* 🔥 Remove a specific polygon by ID using signals
*/
removePolygonById(id) {
console.log(`🗑️ Removing polygon with ID: ${id}`);
// First remove from the map layer
const source = this.polygonLayer.getSource();
if (source) {
const features = source.getFeatures();
console.log(`📋 Total features on map: ${features.length}`);
const featureToRemove = features.find((feature) => {
const featureId = feature.get('polygonId');
console.log(`🔍 Checking feature with ID: ${featureId}`);
return featureId === id;
});
if (featureToRemove) {
console.log(`✅ Found feature to remove with ID: ${id}`);
source.removeFeature(featureToRemove);
console.log(`🗑️ Feature removed from map`);
}
else {
console.warn(`❌ Feature with ID ${id} not found on map`);
// If we can't find by polygonId, try alternative approach
const polygonToRemove = this.completedPolygons().find((p) => p.properties?.['id'] === id);
if (polygonToRemove) {
// Remove all features and re-add the remaining ones
console.log(`🔄 Rebuilding map features...`);
source.clear();
const remainingPolygons = this.completedPolygons().filter((p) => p.properties?.['id'] !== id);
this.rebuildMapFeatures(remainingPolygons);
}
}
}
// Then update the signals
this.completedPolygons.update((polygons) => {
const filtered = polygons.filter((polygon) => polygon.properties?.['id'] !== id);
console.log(`📊 Polygons after removal: ${filtered.length}`);
return filtered;
});
}
/**
* 🔥 Rebuilds map features from polygon data
*/
rebuildMapFeatures(polygons) {
const source = this.polygonLayer.getSource();
if (!source)
return;
polygons.forEach((polygonData) => {
// Convert lat/lng coordinates back to map coordinates
const mapCoordinates = polygonData.coordinates.map((coord) => fromLonLat(coord));
// Close the polygon if not already closed
const lastCoord = mapCoordinates[mapCoordinates.length - 1];
const firstCoord = mapCoordinates[0];
if (lastCoord[0] !== firstCoord[0] || lastCoord[1] !== firstCoord[1]) {
mapCoordinates.push(firstCoord);
}
// Create the feature
const feature = new Feature({
geometry: new Polygon([mapCoordinates]),
});
// Set the polygon ID and data for future removal
feature.set('polygonId', polygonData.properties?.['id']);
feature.set('polygonData', polygonData);
// Add to the map
source.addFeature(feature);
});
console.log(`✅ Rebuilt ${polygons.length} features on map`);
}
/**
* Adds a raster layer to the map using a given URL.
* @param {string} url - The URL of the GeoTIFF file.
* @returns {Promise<void>}
*/
async addRasterLayer(url) {
try {
const encodedUrl = encodeURIComponent(url);
const boundsUrl = `https://tiles.rdnt.io/bounds?url=${encodedUrl}`;
const response = await fetch(boundsUrl);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const result = await response.json();
const extent = transformExtent(result.bounds, 'EPSG:4326', 'EPSG:3857');
this.map.getView().fit(extent, this.map.getSize());
const tilesUrl = this.createTilesUrl(encodedUrl);
const cogLayer = new TileLayer({
source: new XYZ({
url: tilesUrl,
}),
});
const layers = this.map.getLayers();
if (layers.getLength() > 2) {
layers.removeAt(2);
}
this.map.addLayer(cogLayer);
this.rasterLayers.push(cogLayer);
}
catch (error) {
console.error('Error al cargar el archivo GeoTIFF:', error);
alert(`Request failed. Are you sure '${url}' is a valid COG?`);
}
}
/**
* Creates a tiles URL for the given encoded URL.
* @param {string} url - The encoded URL of the GeoTIFF file.
* @returns {string} - The tiles URL.
*/
createTilesUrl(url) {
return `https://tiles.rdnt.io/tiles/{z}/{x}/{y}?url=${url}`;
}
/**
* Removes a raster layer from the map by its index.
* @param {number} index - The index of the raster layer to remove.
*/
removeRasterLayer(index) {
const layer = this.rasterLayers[index];
if (layer) {
this.map.removeLayer(layer);
this.rasterLayers.splice(index, 1);
}
}
/**
* Sets the view of the map to a given center and zoom level.
* @param {[number, number]} center - The new center of the map.
* @param {number} zoom - The new zoom level of the map.
*/
setView(center, zoom) {
this.map.getView().setCenter(fromLonLat(center));
this.map.getView().setZoom(zoom);
}
/**
* Zooms the map to fit a given extent.
* @param {[number, number, number, number]} extent - The extent to fit the map to.
*/
zoomToExtent(extent) {
this.map.getView().fit(extent);
}
/**
* Adds a list of points to the map with an optional icon.
* @param {Array<{ coords: [number, number], info?: string }>} points - The list of points to add to the map.
* @param {string} [iconUrl] - The URL of the icon to use for the points.
*/
addPoints(points, iconUrl) {
console.log('Adding points to the map...');
const features = points.map((point) => {
const feature = new Feature({
geometry: new Point(fromLonLat(point.coords)),
});
if (point.info) {
feature.set('info', point.info);
}
if (iconUrl) {
feature.setStyle(new Style({
image: new Icon({
src: iconUrl,
scale: 0.1,
}),
}));
}
else {
feature.setStyle(new Style({
image: new Circle({
radius: 5,
fill: new Fill({ color: 'red' }),
stroke: new Stroke({ color: 'black', width: 1 }),
}),
}));
}
return feature;
});
const source = this.pointLayer.getSource();
if (source) {
source.addFeatures(features);
}
else {
console.error('La fuente de pointLayer no está disponible.');
}
}
/**
* Exports the current map view to a PDF file.
*/
exportGaiaMapToPdf() {
this.map.once('rendercomplete', () => {
const mapCanvas = document.createElement('canvas');
const size = this.map.getSize();
mapCanvas.width = size[0];
mapCanvas.height = size[1];
const mapContext = mapCanvas.getContext('2d');
const canvases = document.querySelectorAll('.ol-layer canvas');
canvases.forEach((canvas) => {
if (canvas.width > 0) {
const opacity = canvas.parentElement?.style.opacity || '1';
mapContext.globalAlpha = parseFloat(opacity);
const transform = canvas.style.transform;
const matrix = transform
.match(/^matrix\(([^)]+)\)$/)?.[1]
.split(',')
.map(Number);
if (matrix) {
const domMatrix = new DOMMatrix(matrix);
mapContext.setTransform(domMatrix);
}
else {
mapContext.setTransform(1, 0, 0, 1, 0, 0);
}
mapContext.drawImage(canvas, 0, 0);
}
});
const dataUrl = mapCanvas.toDataURL('image/png');
const pdf = new jsPDF('landscape', undefined, 'a4');
pdf.addImage(dataUrl, 'PNG', 0, 0, 297, 210);
pdf.save('map.pdf');
});
this.map.renderSync();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: GaiaGisService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: GaiaGisService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: GaiaGisService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root',
}]
}], ctorParameters: () => [] });
class GaiaGisComponent {
options;
// 🔥 Output event for polygon drawing (for backward compatibility)
polygonDrawn = output();
// 🔥 Inject the service with signals
gaiaGisService = inject(GaiaGisService);
platformId = inject(PLATFORM_ID);
// 🔥 Expose service signals for template usage
isDrawingPolygon = this.gaiaGisService.isDrawingPolygon;
drawingStatus = this.gaiaGisService.drawingStatus;
polygonCount = this.gaiaGisService.polygonCount;
completedPolygons = this.gaiaGisService.completedPolygons;
currentPolygon = this.gaiaGisService.currentPolygon;
drawingState = this.gaiaGisService.drawingState;
// 🔥 Computed signal for UI state
canStartDrawing = computed(() => !this.isDrawingPolygon() && this.drawingState() !== 'completing', ...(ngDevMode ? [{ debugName: "canStartDrawing" }] : []));
showCancelButton = computed(() => this.isDrawingPolygon() && this.drawingState() === 'drawing', ...(ngDevMode ? [{ debugName: "showCancelButton" }] : []));
// 🔥 Linked signal to emit events for backward compatibility
polygonEmitter = linkedSignal(() => {
const currentPolygon = this.currentPolygon();
const state = this.drawingState();
if (currentPolygon && state === 'completing') {
this.polygonDrawn.emit(currentPolygon);
}
return currentPolygon;
});
ngOnInit() {
if (isPlatformBrowser(this.platformId)) {
this.initializeMap();
}
}
initializeMap() {
if (isPlatformBrowser(this.platformId)) {
if (this.options) {
this.gaiaGisService.initializeMap('map', this.options);
}
else {
this.gaiaGisService.initializeMap('map');
}
}
}
/**
* 🔥 Starts polygon drawing mode using the service signals.
*/
startPolygonDraw() {
if (isPlatformBrowser(this.platformId)) {
this.gaiaGisService.startPolygonDraw();
}
}
/**
* 🔥 Cancels polygon drawing using the service signals.
*/
cancelPolygonDraw() {
if (isPlatformBrowser(this.platformId)) {
this.gaiaGisService.cancelPolygonDraw();
}
}
/**
* 🔥 Clears all drawn polygons using the service signals.
*/
clearPolygons() {
if (isPlatformBrowser(this.platformId)) {
this.gaiaGisService.clearPolygons();
}
}
/**
* 🔥 Gets the latest polygon using signals
*/
getLatestPolygon() {
return isPlatformBrowser(this.platformId)
? this.gaiaGisService.getLatestPolygon()
: null;
}
/**
* 🔥 Removes a polygon by ID using signals
*/
removePolygonById(id) {
if (isPlatformBrowser(this.platformId)) {
this.gaiaGisService.removePolygonById(id);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: GaiaGisComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.0", type: GaiaGisComponent, isStandalone: true, selector: "gaia-gis", inputs: { options: "options" }, outputs: { polygonDrawn: "polygonDrawn" }, ngImport: i0, template: "<div id=\"map\" style=\"width: 100%; height: 100%\"></div>\n<div id=\"popup\" class=\"ol-popup\">\n <div id=\"popup-content\"></div>\n</div>\n", styles: [".ol-popup{position:absolute;background-color:#fff;padding:15px;border-radius:10px;border:1px solid #ccc;bottom:12px;left:-50px;min-width:200px;opacity:0;transition:opacity .3s ease-in-out}.ol-popup:after,.ol-popup:before{top:100%;border:solid transparent;content:\"\";height:0;width:0;position:absolute;pointer-events:none}.ol-popup:after{border-top-color:#fff;border-width:10px;left:48px;margin-left:-10px}.ol-popup:before{border-top-color:#ccc;border-width:11px;left:48px;margin-left:-11px}.ol-popup.show{opacity:1}.ol-popup.hide{opacity:0}\n"] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: GaiaGisComponent, decorators: [{
type: Component,
args: [{ selector: 'gaia-gis', standalone: true, imports: [], template: "<div id=\"map\" style=\"width: 100%; height: 100%\"></div>\n<div id=\"popup\" class=\"ol-popup\">\n <div id=\"popup-content\"></div>\n</div>\n", styles: [".ol-popup{position:absolute;background-color:#fff;padding:15px;border-radius:10px;border:1px solid #ccc;bottom:12px;left:-50px;min-width:200px;opacity:0;transition:opacity .3s ease-in-out}.ol-popup:after,.ol-popup:before{top:100%;border:solid transparent;content:\"\";height:0;width:0;position:absolute;pointer-events:none}.ol-popup:after{border-top-color:#fff;border-width:10px;left:48px;margin-left:-10px}.ol-popup:before{border-top-color:#ccc;border-width:11px;left:48px;margin-left:-11px}.ol-popup.show{opacity:1}.ol-popup.hide{opacity:0}\n"] }]
}], propDecorators: { options: [{
type: Input
}] } });
/*
* Public API Surface of gaia-gis
*/
/**
* Generated bundle index. Do not edit.
*/
export { GaiaGisComponent, GaiaGisService, MapsDesign };
//# sourceMappingURL=ngx-gaia-gis.mjs.map