I am using topojson file which only contains data for the oceania region, I am using geoNaturalEarth Projection, but the issue is I am not able to bring the oceania region at the center of screen and fit in the available space. The issue seems out to be with the placement of the region is there a way I can fix it, I have been stuck on it from a long time,
Output is coming to be this:
Here is the relevant code:
import { Loading, Separator, Spinner, useMeasure } from 'ideal';
import React, { useEffect, useRef, useState } from 'react';
import * as topojson from 'topojson-client';
import * as d3 from 'd3';
import { TGeoJsonFeature } from './types';
import { Country } from 'country-state-city';
import useCompanyData, { TCorporation } from 'hooks/api-hooks/useCompanyData';
import { useApiDataContext } from 'components/admin/context/api-call-data-context';
import { doesHaveEntitiesInCountry, getEntitiesInCountry } from './utils';
const OceaniaMap = () => {
const { token, loggedInUserCompanyId } = useApiDataContext();
const { corporations, error } = useCompanyData(loggedInUserCompanyId, token);
const svgRef = useRef(null);
const tooltipRef = useRef<HTMLDivElement>(null);
const [containerRef, bounds] = useMeasure();
const [isMapLoading, setIsMapLoading] = useState<boolean>(false);
const [geoData, setGeoData] = useState(null);
const [tooltipCountries, setTooltipCountries] = useState<string>('');
const [tooltipCorporations, setTooltipCorporations] = useState<
TCorporation[]
>([]);
useEffect(() => {
setIsMapLoading(true);
d3.json('geojson/oceania.json')
.then((data) => {
setGeoData(data);
setIsMapLoading(false);
})
.catch((err) => {
console.error(err);
});
}, []);
useEffect(() => {
if (geoData) {
d3.selectAll('circle').remove();
const tooltip = d3.select(tooltipRef.current);
const svg = d3
.select(svgRef.current)
.attr('width', bounds.width)
.attr('height', bounds.height);
const geojson = topojson.feature(geoData, geoData.objects.countries);
const projection = d3
.geoNaturalEarth1()
// .center([0, 0])
.fitSize([bounds.width, bounds.height], geojson)
.translate([bounds.width / 2 - 80, bounds.height / 2 - 20]);
const path = d3.geoPath().projection(projection);
svg
.selectAll('path')
.data(geojson.features)
.enter()
.append('path')
.attr('d', path)
.attr('class', 'country')
.attr('fill', '#F6F6F6')
.attr('stroke', '#DDDDDD')
.attr('stroke-width', 0.3);
svg
.selectAll('.country')
.filter((d: TGeoJsonFeature) =>
doesHaveEntitiesInCountry(d, corporations)
)
.each((d: TGeoJsonFeature) => {
const centroid = path.centroid(d as d3.GeoPermissibleObjects);
const shadow = svg
.append('circle')
.attr('cx', centroid[0])
.attr('cy', centroid[1])
.attr('r', 10)
.attr('fill', '#1F1F1F20')
.attr('visibility', 'hidden');
const circle = svg
.append('circle')
.attr('cx', centroid[0])
.attr('cy', centroid[1])
.attr('r', 6)
.attr('fill', '#1F1F1F')
.attr('cursor', 'pointer')
.on('mouseover', () => shadow.attr('visibility', 'visible'))
.on('click', (event) => {
event.stopPropagation();
const entitiesInCountry = getEntitiesInCountry(d, corporations);
if (entitiesInCountry.length) {
setTooltipCorporations(entitiesInCountry);
setTooltipCountries(d.properties.ISO_CODE);
tooltip.transition().duration(200).style('opacity', 1);
tooltip
.style('left', `${event.pageX + 20}px`)
.style('top', `${event.pageY - 28}px`);
}
})
.on('mouseout', () => {
shadow.attr('visibility', 'hidden');
});
});
}
}, [geoData, bounds.width, bounds.height]);
if (error) {
console.error(error);
return <Loading />;
}
return (
<div className="flex flex-col gap-6 py-6">
<div className="border rounded-2xl mx-6 border-stroke-2 h-[calc(100vh-196px)] bg-neutral-7 flex flex-col overflow-hidden">
<div className="flex items-center w-full border-b border-b-stroke-2">
<span className="p-4">Africa</span>
</div>
<div className="min-h-full flex-1 flex">
<div
className="flex-1 flex justify-center items-center"
ref={containerRef}
>
{isMapLoading ? (
<Spinner size="lg" />
) : (
<div>
<svg
ref={svgRef}
width={bounds.width}
height={bounds.height}
viewBox={`0 0 ${bounds.width} ${bounds.height}`}
/>
<div
ref={tooltipRef}
style={{
opacity: '0',
}}
className="absolute bg-neutral-7 rounded-b-lg pointer-events-none flex flex-col shadow min-w-[200px] shadow-[0px_4px_32px_0px_rgba(31,_31,_31,_0.15)]"
>
<div className="px-3 py-2 bg-violet-1 text-neutral-7 rounded-t-lg">
<h5 className="inline-block">
{Country.getCountryByCode(tooltipCountries)?.name}
</h5>
<h5 className="inline-block font-normal">
[{tooltipCountries}]
</h5>
</div>
<div>
{tooltipCorporations.map((corp) => {
return (
<div className="flex w-full items-start px-3 py-2 last:rounded-b-lg">
<p className="text-stone-900 text-xs font-normal leading-none">
{corp.companyLegalName}
</p>
</div>
);
})}
</div>
</div>
</div>
)}
</div>
<div className="h-full w-[240px] border-l border-l-stroke-2 flex flex-col overflow-y-auto">
B
</div>
</div>
</div>
<Separator className="h-1" />
</div>
);
};
export default OceaniaMap;
```e