setup map component to render correctly and visualize all listings in scrollable components

This commit is contained in:
Viktor Barzin 2025-06-15 21:06:10 +00:00
parent a8ee95b9d9
commit 8e41032c6c
No known key found for this signature in database
GPG key ID: 4056458DBDBF8863
23 changed files with 2183 additions and 342 deletions

View file

@ -1,8 +1,13 @@
import crossfilter from "crossfilter2";
import * as d3 from "d3";
import mapboxgl from "mapbox-gl";
// import 'mapbox-gl/dist/mapbox-gl.css';
import 'mapbox-gl/dist/mapbox-gl.css'; // this hides the map for some reason
import { useEffect, useRef } from "react";
import { renderToString } from 'react-dom/server';
import "../assets/Map.css";
import { Button } from "./ui/button";
import { ScrollArea } from "./ui/scroll-area";
import { Separator } from "./ui/separator";
export function Map(
props: {
@ -31,7 +36,7 @@ export function Map(
// filter['countries'] = Array.from(new Set(data.features.map(function (d) { return d['properties']['country'] })));
// rivets.bind(document.getElementById('overlay'), { filter: filter });
const mapRef = useRef(mapboxgl.Map)
const mapContainerRef = useRef('map')
const mapContainerRef = useRef('map-container')
useEffect(() => {
mapboxgl.accessToken = 'pk.eyJ1IjoiZGktdG8iLCJhIjoiY2o0bnBoYXcxMW1mNzJ3bDhmc2xiNWttaiJ9.ZccatVk_4shzoAsEUXXecA';
mapRef.current = new mapboxgl.Map({
@ -72,10 +77,6 @@ export function Map(
}
function update() {
// close overlay
var modal = document.getElementById('modal_overlay');
modal.classList.toggle('modal-open');
// init heatmap
heatmap = new HexgridHeatmap(mapRef.current, "hexgrid-heatmap", "waterway-label");
heatmap.setIntensity(9); // dunno yet
@ -193,77 +194,116 @@ export function Map(
minY: latitude - searchBuffer,
maxY: latitude + searchBuffer
})
const html = getListingDialogHTML(properties);
if (properties.length > 0) {
const listingDialogPopup = getListingDialog(properties);
new mapboxgl.Popup()
.setLngLat([longtitude, latitude])
.setHTML(html)
.setHTML(renderToString(listingDialogPopup))
.setMaxWidth("500px")
.addTo(mapRef.current);
}
}
function getListingDialogHTML(properties) {
let listinHTMLs = [];
function getListingDialog(properties) {
let listingComponents = [];
for (let property of properties) {
listinHTMLs.push(getPropertyHTML(property));
listingComponents.push(getPropertyComponent(property));
}
// separate them with a line
const result = listinHTMLs.join('<hr>');
const styledResult = `
<div class="scrollable-panel">
${result}
</div>
`
console.log(listingComponents.length)
return <ScrollArea className="rounded-md border">
<div className="overflow-y-auto h-[500px] w-[500px] scrollbar-thin scrollbar-thumb-rounded">
return styledResult;
<div className="propertyListingPopupItem" style={{ width: '100%' }}>
Showing <strong>{properties.length}</strong> properties
</div>
{listingComponents.map((item) => {
const scrollDiv = <div key={item.key}>
{item}
<Separator className="my-2" />
</div>;
return scrollDiv
})}
</div>
</ScrollArea>;
}
function getPropertyHTML(property) {
function getPropertyComponent(property) {
const priceHistoryHTMLs = property.properties.price_history.map((d) => {
return `<li>${d.last_seen.split('T')[0]}: £${d.price}</li>`;
return <li key={d.id}>${d.last_seen.split('T')[0]}: £${d.price}</li>;
});
let priceHistoryHTML = '';
let priceHistoryHTML = <></>;
if (priceHistoryHTMLs.length > 1) {
priceHistoryHTML = `
<strong>Price history:</strong>
<ul>
${priceHistoryHTMLs.join('')}
</ul>
<br />
`
priceHistoryHTML =
<div className="propertyListingPopupItem">
<strong>Price history:</strong>
<ul>
${priceHistoryHTMLs.join('')}
</ul>
<br />
</div>
}
const lastSeenStr = property.properties.last_seen.split('T')[0];
const lastSeenDays = Math.round((new Date() - new Date(lastSeenStr)) / (1000 * 60 * 60 * 24));
return <div key={property.properties.url} style={{ display: 'flex', flexWrap: 'wrap' }}>
<div className="propertyListingPopupItem" style={{ width: '100%' }}>
<img src={property.properties.photo_thumbnail} />
</div>
<div className="propertyListingPopupItem">
<strong>Available from:</strong>
</div>
<div className="propertyListingPopupItem">
{property.properties.available_from}
</div>
<div className="propertyListingPopupItem">
<strong>Price:</strong>
</div>
<div className="propertyListingPopupItem">
£{property.properties.total_price}
</div>
{priceHistoryHTML}
<div className="propertyListingPopupItem">
<strong>Rooms:</strong>
</div>
<div className="propertyListingPopupItem">
return `
<div>
<img src="${property.properties.photo_thumbnail}" style="width:100%; height:auto;">
<p>
<strong>Available from:</strong> ${property.properties.available_from}
<br />
<strong>Price:</strong> £${property.properties.total_price}
<br />
${priceHistoryHTML}
<strong>Rooms:</strong> ${property.properties.rooms}
<br />
<strong>Area:</strong> ${property.properties.qm} m²
<br />
<strong>Price per area:</strong> £${property.properties.qmprice}/m²
<br />
<strong>Last seen:</strong> ${lastSeenDays} days ago
<br />
<strong>Agency:</strong> ${property.properties.agency}
<br />
<a href="${property.properties.url}" target="_blank">View Listing</a>
</p>
{property.properties.rooms}
</div>
<div className="propertyListingPopupItem">
<strong>Area:</strong>
</div>
<div className="propertyListingPopupItem">
{property.properties.qm} m²
</div>
<div className="propertyListingPopupItem">
<strong>Price per area:</strong>
</div>
<div className="propertyListingPopupItem">
£{property.properties.qmprice}/m²
</div>
<div className="propertyListingPopupItem">
<strong>Last seen:</strong>
</div>
<div className="propertyListingPopupItem">
{lastSeenDays} days ago
</div>
<div className="propertyListingPopupItem">
<strong>Agency:</strong>
</div>
<div className="propertyListingPopupItem">
{property.properties.agency}
</div>
<div className="propertyListingPopupItem" style={{ width: '100%' }}>
<Button asChild>
<a href={property.properties.url} target="_blank">View Listing</a>
</Button>
</div>
</div>
`;
}
return <>
<div id='map' ref={mapContainerRef}></div>
<div id='map-container' ref={mapContainerRef}></div>
<div id="legend">
<svg id="svg">