edit marker
This commit is contained in:
parent
4418783441
commit
3a889bd25f
|
@ -255,8 +255,6 @@
|
|||
|
||||
<uc-upload-ctx-provider
|
||||
ctx-name="my-uploader"
|
||||
bind:this={uploaderCtxEl}
|
||||
bind:ctx={uploaderCtx}
|
||||
></uc-upload-ctx-provider>
|
||||
|
||||
{#if showImageError}
|
||||
|
|
|
@ -15,40 +15,46 @@
|
|||
lat: number;
|
||||
lng: number;
|
||||
};
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
}
|
||||
|
||||
async function getPastTripLocations(): Promise<TripLocation[]> {
|
||||
function formatDate(dateStr: string): string {
|
||||
const date = new Date(dateStr);
|
||||
return `${date.getDate().toString().padStart(2, '0')}.${(date.getMonth() + 1)
|
||||
.toString()
|
||||
.padStart(2, '0')}.${date.getFullYear()}`;
|
||||
}
|
||||
|
||||
async function getPastTripLocations(): Promise<Record<string, TripLocation[]>> {
|
||||
try {
|
||||
const tripsRef = ref(db, 'trips');
|
||||
const snapshot = await get(tripsRef);
|
||||
if (!snapshot.exists()) return {};
|
||||
|
||||
if (!snapshot.exists()) return [];
|
||||
|
||||
// Get today's date at midnight for comparison
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
|
||||
// Create a Set to store unique locations
|
||||
const uniqueLocations = new Map<string, TripLocation>();
|
||||
const locationMap: Record<string, TripLocation[]> = {};
|
||||
|
||||
// Filter past trips and extract unique destinations
|
||||
Object.values(snapshot.val()).forEach((trip: any) => {
|
||||
const endDate = new Date(trip.endDate);
|
||||
if (endDate < today && trip.destination?.location) {
|
||||
const locationKey = `${trip.destination.location.lat},${trip.destination.location.lng}`;
|
||||
if (!uniqueLocations.has(locationKey)) {
|
||||
uniqueLocations.set(locationKey, {
|
||||
const key = `${trip.destination.location.lat},${trip.destination.location.lng}`;
|
||||
if (!locationMap[key]) locationMap[key] = [];
|
||||
locationMap[key].push({
|
||||
name: trip.destination.name,
|
||||
location: trip.destination.location
|
||||
location: trip.destination.location,
|
||||
startDate: trip.startDate,
|
||||
endDate: trip.endDate
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return Array.from(uniqueLocations.values());
|
||||
return locationMap;
|
||||
} catch (error) {
|
||||
console.error('Error fetching past trips:', error);
|
||||
return [];
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,7 +69,6 @@
|
|||
const width = mapContainer.clientWidth;
|
||||
const height = mapContainer.clientHeight;
|
||||
|
||||
// Create SVG
|
||||
const svg = d3.select(mapContainer)
|
||||
.append('svg')
|
||||
.attr('width', '100%')
|
||||
|
@ -71,30 +76,24 @@
|
|||
.attr('viewBox', `0 0 ${width} ${height}`)
|
||||
.attr('preserveAspectRatio', 'xMidYMid meet') as d3.Selection<SVGSVGElement, unknown, null, undefined>;
|
||||
|
||||
// Add a group for all map elements that will be transformed
|
||||
const g = svg.append('g');
|
||||
|
||||
// Create projection
|
||||
const projection = d3.geoMercator()
|
||||
.scale(width / (2 * Math.PI))
|
||||
.translate([width / 2, height / 1.6]); // position the map, horizontally centered but is slighty upward
|
||||
.translate([width / 2, height / 1.6]);
|
||||
|
||||
const path = d3.geoPath().projection(projection);
|
||||
|
||||
try {
|
||||
// Get past trip locations
|
||||
const pastLocations = await getPastTripLocations();
|
||||
const locationMap = await getPastTripLocations();
|
||||
if (!mounted) return;
|
||||
|
||||
// Load world map data
|
||||
const response = await fetch('https://unpkg.com/world-atlas@2/countries-110m.json');
|
||||
if (!mounted) return;
|
||||
const world = await response.json();
|
||||
|
||||
// Convert TopoJSON to GeoJSON
|
||||
const countries = feature(world, world.objects.countries) as any;
|
||||
|
||||
// Draw the map
|
||||
g.append('g')
|
||||
.selectAll('path')
|
||||
.data(countries.features)
|
||||
|
@ -106,7 +105,8 @@
|
|||
.attr('stroke', Colors.gray.light50)
|
||||
.attr('stroke-width', '0.5');
|
||||
|
||||
// Add markers for past trip locations
|
||||
const pastLocations = Object.values(locationMap).map(trips => trips[0]);
|
||||
|
||||
g.selectAll('circle')
|
||||
.data(pastLocations)
|
||||
.enter()
|
||||
|
@ -116,8 +116,69 @@
|
|||
.attr('r', 5)
|
||||
.attr('class', 'marker')
|
||||
.attr('fill', Colors.planner.med400)
|
||||
.on('click', function (event, d) {
|
||||
d3.selectAll('.trip-label').remove();
|
||||
d3.selectAll('.trip-marker').remove();
|
||||
d3.selectAll('.trip-line').remove();
|
||||
event.stopPropagation();
|
||||
|
||||
const key = `${d.location.lat},${d.location.lng}`;
|
||||
const trips = locationMap[key];
|
||||
|
||||
if (trips && trips.length > 0) {
|
||||
const baseX = projection([d.location.lng, d.location.lat])![0];
|
||||
const baseY = projection([d.location.lng, d.location.lat])![1];
|
||||
|
||||
trips.sort((a, b) => new Date(a.endDate).getTime() - new Date(b.endDate).getTime());
|
||||
|
||||
if (trips.length > 1) {
|
||||
g.append('line')
|
||||
.attr('x1', baseX)
|
||||
.attr('y1', baseY + 5)
|
||||
.attr('x2', baseX)
|
||||
.attr('y2', baseY - (trips.length - 1) * 24 + 6)
|
||||
.attr('stroke', Colors.planner.med400)
|
||||
.attr('stroke-width', 2)
|
||||
.attr('class', 'trip-line');
|
||||
}
|
||||
|
||||
trips.forEach((trip, idx) => {
|
||||
const offsetY = idx * 24;
|
||||
|
||||
const markerGroup = g.append('g')
|
||||
.attr('class', 'trip-group')
|
||||
.on('mouseover', function () {
|
||||
d3.select(this).select('circle').transition().duration(200).attr('r', 7);
|
||||
d3.select(this).select('text').transition().duration(200).attr('fill', Colors.planner.med400);
|
||||
})
|
||||
.on('mouseout', function () {
|
||||
d3.select(this).select('circle').transition().duration(200).attr('r', 5);
|
||||
d3.select(this).select('text').transition().duration(200).attr('fill', Colors.black);
|
||||
});
|
||||
|
||||
markerGroup.append('circle')
|
||||
.attr('cx', baseX)
|
||||
.attr('cy', baseY - offsetY)
|
||||
.attr('r', 5)
|
||||
.attr('fill', Colors.planner.med400)
|
||||
.attr('class', 'trip-marker');
|
||||
|
||||
markerGroup.append('text')
|
||||
.attr('x', baseX + 10)
|
||||
.attr('y', baseY - offsetY + 4)
|
||||
.attr('font-size', '12px')
|
||||
.attr('class', 'trip-label')
|
||||
.text(`${formatDate(trip.startDate)} - ${formatDate(trip.endDate)}`);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
svg.on('click', () => {
|
||||
d3.selectAll('.trip-label').remove();
|
||||
d3.selectAll('.trip-marker').remove();
|
||||
d3.selectAll('.trip-line').remove();
|
||||
});
|
||||
|
||||
// Add zoom behavior
|
||||
const zoom = d3.zoom<SVGSVGElement, unknown>()
|
||||
.scaleExtent([1, 8])
|
||||
.on('zoom', (event) => {
|
||||
|
@ -168,10 +229,17 @@
|
|||
}
|
||||
|
||||
:global(.marker:hover) {
|
||||
r: 8;
|
||||
r: 7;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
:global(.trip-label),
|
||||
:global(.trip-marker),
|
||||
:global(.trip-line) {
|
||||
transition: all 0.2s ease;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
:global(.dark .map-wrapper) {
|
||||
background-color: var(--black);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user