Skip to content

Commit 3c0a02b

Browse files
committed
moved the bharat map js files to src, and made it in typescript
1 parent 23aa8ce commit 3c0a02b

File tree

11 files changed

+887
-118
lines changed

11 files changed

+887
-118
lines changed

package-lock.json

Lines changed: 676 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"astro": "5.1.1",
5858
"class-variance-authority": "0.7.0",
5959
"clsx": "2.1.0",
60+
"d3": "7.9.0",
6061
"dotenv": "^16.4.5",
6162
"dotenv-expand": "^11.0.6",
6263
"lucide-react": "0.469.0",
@@ -72,6 +73,7 @@
7273
"devDependencies": {
7374
"@tailwindcss/aspect-ratio": "0.4.2",
7475
"@tailwindcss/typography": "0.5.10",
76+
"@types/d3": "7.4.3",
7577
"@types/node": "22.10.2",
7678
"@types/react": "19.0.0",
7779
"@typescript-eslint/eslint-plugin": "6.13.2",
@@ -87,4 +89,4 @@
8789
"prettier-plugin-tailwindcss": "0.6.8",
8890
"shx": "0.3.4"
8991
}
90-
}
92+
}

public/js/main.js

Lines changed: 0 additions & 7 deletions
This file was deleted.

public/js/modules/StateModal.js

Lines changed: 0 additions & 76 deletions
This file was deleted.

src/assets/styles/bharat-map/components/map.css

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
display: flex;
1010
align-items: center;
1111
position: relative;
12+
width: 100%;
13+
height: calc(100vh - 180px);
1214
}
1315

1416
svg {
@@ -51,7 +53,7 @@ svg {
5153
fill: var(--primary-color);
5254
}
5355

54-
.capital-marker:hover + .capital-label {
56+
.capital-marker:hover+.capital-label {
5557
opacity: 1;
5658
transform: translateY(-8px);
5759
}
@@ -74,4 +76,4 @@ svg {
7476
.capital-label:hover,
7577
.capital-label.active {
7678
opacity: 1;
77-
}
79+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
---
3+
4+
<div id="stateModal" class="modal">
5+
<div class="modal-content">
6+
<span class="close">&times;</span>
7+
<div class="modal-header">
8+
<h2 id="stateName"></h2>
9+
</div>
10+
<div class="modal-body">
11+
<p>Capital: <span id="stateCapital"></span></p>
12+
<p>Area: <span id="stateArea"></span></p>
13+
<p>Languages: <span id="stateLanguages"></span></p>
14+
<p>Dance Forms: <span id="stateDance"></span></p>
15+
<p>Literacy Rate: <span id="stateLiteracy"></span></p>
16+
<p>Description: <span id="stateDescription"></span></p>
17+
</div>
18+
<div class="modal-footer">
19+
<button id="copyButton">
20+
<i class="fas fa-copy"></i> Copy
21+
</button>
22+
</div>
23+
</div>
24+
</div>

src/components/BharatMap/StateModel.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import "@/assets/styles/bharat-map/components/modal.css";
88
<div class="modal-header">
99
<h2 id="stateName" style="margin: 0"></h2>
1010
<button id="copyButton">
11-
<i class="fas fa-copy"></i> Copy Details
11+
<i class="fas fa-copy"></i> Copy
1212
</button>
1313
</div>
1414
<div class="modal-body">

src/layouts/BharatMapLayout.astro

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,20 @@ const {
1111
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" />
1212
<slot />
1313
<script src="https://d3js.org/d3.v7.min.js"></script>
14-
<script type="module" src="/js/main.js"></script>
14+
15+
<script>
16+
import { MAP_CONFIG } from "@/utils/BharatMap/config/mapConfig";
17+
import { BharatMap } from "@/utils/BharatMap/modules/BharatMap";
18+
19+
declare global {
20+
interface Window {
21+
bharatMap: BharatMap;
22+
}
23+
}
24+
25+
document.addEventListener("DOMContentLoaded", () => {
26+
window.bharatMap = new BharatMap(MAP_CONFIG);
27+
window.bharatMap.loadData();
28+
});
29+
</script>
1530
</BaseLayout>
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export const MAP_CONFIG = {
2-
center: [78.9629, 22.5937],
2+
center: [78.9629, 22.5937] as [number, number],
33
scale: 900,
44
width: window.innerWidth - 60,
55
height: window.innerHeight - 180,
Lines changed: 67 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,41 @@
1-
import { StateModal } from "./StateModal.js";
1+
import * as d3 from "d3";
2+
import { StateModal } from "./StateModal";
3+
4+
interface MapConfig {
5+
center: [number, number];
6+
scale: number;
7+
width: number;
8+
height: number;
9+
initialTransform: d3.ZoomTransform | null;
10+
}
11+
12+
interface CapitalData {
13+
name: string;
14+
coordinates: [number, number];
15+
}
16+
17+
interface StateData {
18+
capital: CapitalData;
19+
[key: string]: any; // for other state properties
20+
}
221

322
export class BharatMap {
4-
// Main class handling the map visualization and interaction
5-
constructor(config) {
23+
private config: MapConfig;
24+
private stateData: Record<string, StateData>;
25+
private projection: d3.GeoProjection;
26+
private path: d3.GeoPath;
27+
private zoom: d3.ZoomBehavior<SVGSVGElement, unknown>;
28+
private svg!: d3.Selection<SVGSVGElement, unknown, HTMLElement, any>;
29+
private mapGroup!: d3.Selection<SVGGElement, unknown, HTMLElement, any>;
30+
private initialTransform: d3.ZoomTransform | null;
31+
32+
constructor(config: MapConfig) {
633
this.config = config;
734
this.stateData = {};
835
this.projection = this.createProjection();
936
this.path = d3.geoPath().projection(this.projection);
1037
this.zoom = d3
11-
.zoom()
38+
.zoom<SVGSVGElement, unknown>()
1239
.scaleExtent([1, 8])
1340
.on("zoom", (event) => this.handleZoom(event));
1441
this.initializeSVG();
@@ -21,7 +48,7 @@ export class BharatMap {
2148
window.addEventListener("beforeunload", this.cleanup);
2249
}
2350

24-
cleanup() {
51+
private cleanup(): void {
2552
window.removeEventListener("resize", this.handleResize);
2653
window.removeEventListener("beforeunload", this.cleanup);
2754
// Clear any D3 selections
@@ -31,9 +58,9 @@ export class BharatMap {
3158
}
3259

3360
// Initialize SVG container and set up zoom behavior
34-
initializeSVG() {
61+
private initializeSVG(): void {
3562
this.svg = d3
36-
.select(".map-container")
63+
.select<SVGSVGElement, unknown>(".map-container")
3764
.append("svg")
3865
.attr("viewBox", `0 0 ${this.config.width} ${this.config.height}`)
3966
.attr("preserveAspectRatio", "xMidYMid meet");
@@ -46,7 +73,7 @@ export class BharatMap {
4673
}
4774

4875
// Create Mercator projection for Bharat map
49-
createProjection() {
76+
private createProjection(): d3.GeoProjection {
5077
return d3
5178
.geoMercator()
5279
.center(this.config.center)
@@ -55,9 +82,15 @@ export class BharatMap {
5582
}
5683

5784
// Load GeoJSON and state data from external files
58-
async loadData() {
85+
public async loadData(): Promise<void> {
5986
try {
60-
const [geoData, states] = await Promise.all([d3.json("data/bharat.geojson"), d3.json("data/state_data.json")]);
87+
const [geoData, states] = await Promise.all([
88+
d3.json<GeoJSON.FeatureCollection>("data/bharat.geojson"),
89+
d3.json<Record<string, StateData>>("data/state_data.json")
90+
]);
91+
92+
if (!geoData || !states) throw new Error("Failed to load data");
93+
6194
this.stateData = states;
6295
this.renderMap(geoData);
6396
this.renderCapitals();
@@ -67,22 +100,24 @@ export class BharatMap {
67100
}
68101
}
69102

70-
handleDataLoadError() {
103+
private handleDataLoadError(): void {
71104
// Error UI feedback
72105
const container = document.querySelector(".map-container");
73-
container.innerHTML = `
74-
<div class="error-message">
75-
Failed to load map data. Please try refreshing the page.
76-
</div>
77-
`;
106+
if (container) {
107+
container.innerHTML = `
108+
<div class="error-message">
109+
Failed to load map data. Please try refreshing the page.
110+
</div>
111+
`;
112+
}
78113
}
79114

80115
// Handle zoom and pan events
81-
handleZoom(event) {
82-
this.mapGroup.attr("transform", event.transform);
116+
private handleZoom(event: d3.D3ZoomEvent<SVGSVGElement, unknown>): void {
117+
this.mapGroup.attr("transform", event.transform.toString());
83118
}
84119

85-
renderMap(geoData) {
120+
private renderMap(geoData: GeoJSON.FeatureCollection): void {
86121
if (!this.mapGroup) return;
87122

88123
this.mapGroup
@@ -92,19 +127,22 @@ export class BharatMap {
92127
.append("path")
93128
.attr("d", this.path)
94129
.attr("class", "state")
95-
.on("click", (event, d) => {
96-
this.handleStateClick(d.properties.st_nm);
130+
.on("click", (event: MouseEvent, d: GeoJSON.Feature) => {
131+
const properties = d.properties as { st_nm: string };
132+
this.handleStateClick(properties.st_nm);
97133
});
98134
}
99135

100-
renderCapitals() {
136+
private renderCapitals(): void {
101137
const capitals = this.mapGroup.append("g").attr("class", "capitals");
102138

103139
Object.entries(this.stateData).forEach(([stateName, data]) => {
104140
const coords = data.capital.coordinates;
105141
if (!coords) return;
106142

107-
const [x, y] = this.projection(coords);
143+
const projected = this.projection(coords);
144+
if (!projected) return;
145+
const [x, y] = projected;
108146
if (isNaN(x) || isNaN(y)) return;
109147

110148
const g = capitals.append("g").attr("class", "capital-group").attr("data-state", stateName);
@@ -117,27 +155,27 @@ export class BharatMap {
117155
});
118156
}
119157

120-
handleStateClick(stateName) {
158+
private handleStateClick(stateName: string): void {
121159
this.highlightCapital(stateName);
122160
this.showStateModal(stateName);
123161
}
124162

125-
highlightCapital(stateName) {
163+
private highlightCapital(stateName: string): void {
126164
d3.selectAll(".capital-marker, .capital-label").classed("active", false);
127165

128166
d3.selectAll(`[data-state="${stateName}"]`).classed("active", true);
129167
}
130168

131-
showStateModal(stateName) {
169+
private showStateModal(stateName: string): void {
132170
const modal = new StateModal(this.stateData[stateName], stateName);
133171
modal.show();
134172
}
135173

136-
resetZoom() {
174+
public resetZoom(): void {
137175
this.svg.transition().duration(750).call(this.zoom.transform, d3.zoomIdentity.scale(1));
138176
}
139177

140-
handleResize() {
178+
private handleResize(): void {
141179
this.config.width = window.innerWidth - 60;
142180
this.config.height = window.innerHeight - 180;
143181

@@ -148,7 +186,7 @@ export class BharatMap {
148186
.scale(this.config.scale)
149187
.translate([this.config.width / 2, this.config.height / 2]);
150188

151-
this.mapGroup.selectAll("path").attr("d", this.path);
189+
this.mapGroup.selectAll("path").attr("d", (d) => this.path(d as GeoJSON.Feature | GeoJSON.Geometry));
152190

153191
// Update capital positions
154192
this.mapGroup.selectAll(".capital-group").remove();

0 commit comments

Comments
 (0)