diff --git a/src/components/LeafletHeatMap.tsx b/src/components/LeafletHeatMap.tsx index c7a40d5..2a679e5 100644 --- a/src/components/LeafletHeatMap.tsx +++ b/src/components/LeafletHeatMap.tsx @@ -26,8 +26,10 @@ const LeafletHeatMap: React.FC = ({ filters, isDarkMode, on // Initialize the map const map = L.map(mapContainerRef.current, { - center: [0, 0], + center: [20, 0], zoom: 2, + minZoom: 2, + maxZoom: 18, zoomControl: true, scrollWheelZoom: true, doubleClickZoom: true, @@ -35,6 +37,9 @@ const LeafletHeatMap: React.FC = ({ filters, isDarkMode, on keyboard: true, dragging: true, touchZoom: true, + worldCopyJump: true, + maxBounds: [[-85, -Infinity], [85, Infinity]], + maxBoundsViscosity: 1.0, }); mapRef.current = map; @@ -76,10 +81,10 @@ const LeafletHeatMap: React.FC = ({ filters, isDarkMode, on } // Create new heat layer with the data - // Convert [lng, lat] to [lat, lng, intensity] format for leaflet.heat - const heatData: [number, number, number][] = data.map(([lng, lat]: [number, number]) => [ + // Convert [lon, lat] to [lat, lon, intensity] format for leaflet.heat + const heatData: [number, number, number][] = data.map(([lon, lat]: [number, number]) => [ lat, // latitude first for leaflet.heat - lng, // longitude second + lon, // longitude second 1 // intensity (weight) ]); diff --git a/src/pages/api/assets/geo-heatmap.ts b/src/pages/api/assets/geo-heatmap.ts index b48f216..a2193fd 100644 --- a/src/pages/api/assets/geo-heatmap.ts +++ b/src/pages/api/assets/geo-heatmap.ts @@ -15,24 +15,54 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) } - const dbAssets = await db.select({ + // Build query with optional LEFT JOINs based on filters + let query = db.select({ assetId: assets.id, latitude: exif.latitude, longitude: exif.longitude, }).from(assets) .innerJoin(exif, eq(assets.id, exif.assetId)) - .innerJoin(albumsAssetsAssets, eq(assets.id, albumsAssetsAssets.assetId)) - .innerJoin(assetFaces, eq(albumsAssetsAssets.assetId, assetFaces.assetId)) - .innerJoin(person, eq(assetFaces.personId, person.id)) - .where( - and( - eq(assets.ownerId, currentUser.id), - isNotNull(exif.latitude), - isNotNull(exif.longitude), - albumIds?.length > 0 ? inArray(albumsAssetsAssets.albumId, [albumIds]) : undefined, - peopleIds?.length > 0 ? inArray(person.id, [peopleIds]) : undefined - ) - ); + .$dynamic(); + + // Only join albums table if filtering by albumIds + if (albumIds) { + query = query + .innerJoin(albumsAssetsAssets, eq(assets.id, albumsAssetsAssets.assetId)) + .where( + and( + eq(assets.ownerId, currentUser.id), + isNotNull(exif.latitude), + isNotNull(exif.longitude), + inArray(albumsAssetsAssets.albumId, [albumIds]) + ) + ); + } + // Only join people table if filtering by peopleIds + else if (peopleIds) { + query = query + .innerJoin(assetFaces, eq(assets.id, assetFaces.assetId)) + .innerJoin(person, eq(assetFaces.personId, person.id)) + .where( + and( + eq(assets.ownerId, currentUser.id), + isNotNull(exif.latitude), + isNotNull(exif.longitude), + inArray(person.id, [peopleIds]) + ) + ); + } + // No filters - get all assets with location + else { + query = query.where( + and( + eq(assets.ownerId, currentUser.id), + isNotNull(exif.latitude), + isNotNull(exif.longitude) + ) + ); + } + + const dbAssets = await query; const heatmapData = dbAssets.map((asset) => [ asset.longitude, asset.latitude, diff --git a/src/pages/assets/geo-heatmap.tsx b/src/pages/assets/geo-heatmap.tsx index 3c65ee7..4fbbfc1 100644 --- a/src/pages/assets/geo-heatmap.tsx +++ b/src/pages/assets/geo-heatmap.tsx @@ -1,7 +1,7 @@ import Header from '@/components/shared/Header' import React, { useState } from 'react' import PageLayout from '@/components/layouts/PageLayout'; -import { getAssetGeoHeatmap, IHeatMapParams } from '@/handlers/api/asset.handler'; +import { IHeatMapParams } from '@/handlers/api/asset.handler'; import { useTheme } from 'next-themes'; import { X } from 'lucide-react'; import AlbumDropdown from '@/components/shared/AlbumDropdown'; @@ -15,10 +15,6 @@ const LeafletHeatMap = dynamic(() => import('../../components/LeafletHeatMap'), loading: () =>
Loading map...
}); -interface IHeatMapProps { - filters: IHeatMapParams; -} - export default function GeoHeatmap() { const { theme } = useTheme(); const [filters, setFilters] = useState<{