David Pomerenke
commited on
Commit
·
b4a0c57
1
Parent(s):
91e29ba
D3 map with countries (without data display)
Browse files- frontend/public/countries.json +0 -0
- frontend/src/App.js +29 -1
- frontend/src/components/WorldMap.js +58 -0
- frontend/src/index.css +9 -0
frontend/public/countries.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
frontend/src/App.js
CHANGED
@@ -4,6 +4,7 @@ import 'primereact/resources/themes/lara-light-cyan/theme.css'
|
|
4 |
import ModelTable from './components/ModelTable'
|
5 |
import LanguageTable from './components/LanguageTable'
|
6 |
import DatasetTable from './components/DatasetTable'
|
|
|
7 |
import AutoComplete from './components/AutoComplete'
|
8 |
|
9 |
function App () {
|
@@ -12,7 +13,7 @@ function App () {
|
|
12 |
const [error, setError] = useState(null)
|
13 |
const [allSuggestions, setAllSuggestions] = useState([])
|
14 |
const [filters, setFilters] = useState([])
|
15 |
-
|
16 |
useEffect(() => {
|
17 |
fetch('/results.json')
|
18 |
.then(response => {
|
@@ -31,6 +32,22 @@ function App () {
|
|
31 |
})
|
32 |
}, [])
|
33 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
useEffect(() => {
|
35 |
if (data) {
|
36 |
const models = data.model_table.map(item => ({ type: 'Model', value: item.model, detail: item.provider, searchText: item.provider.toLowerCase() + ' ' + item.model.toLowerCase() }))
|
@@ -87,6 +104,17 @@ function App () {
|
|
87 |
{error && <p>Error: {error}</p>}
|
88 |
{data && (
|
89 |
<>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
<div
|
91 |
style={{
|
92 |
flex: '60vw 100vw 40vw',
|
|
|
4 |
import ModelTable from './components/ModelTable'
|
5 |
import LanguageTable from './components/LanguageTable'
|
6 |
import DatasetTable from './components/DatasetTable'
|
7 |
+
import WorldMap from './components/WorldMap'
|
8 |
import AutoComplete from './components/AutoComplete'
|
9 |
|
10 |
function App () {
|
|
|
13 |
const [error, setError] = useState(null)
|
14 |
const [allSuggestions, setAllSuggestions] = useState([])
|
15 |
const [filters, setFilters] = useState([])
|
16 |
+
const [topology, setTopology] = useState(null)
|
17 |
useEffect(() => {
|
18 |
fetch('/results.json')
|
19 |
.then(response => {
|
|
|
32 |
})
|
33 |
}, [])
|
34 |
|
35 |
+
useEffect(() => {
|
36 |
+
fetch('/countries.json')
|
37 |
+
.then(response => {
|
38 |
+
if (!response.ok) {
|
39 |
+
throw new Error('Network response was not ok')
|
40 |
+
}
|
41 |
+
return response.json()
|
42 |
+
})
|
43 |
+
.then(jsonData => {
|
44 |
+
setTopology(jsonData)
|
45 |
+
})
|
46 |
+
.catch(err => {
|
47 |
+
setError(err.message)
|
48 |
+
setLoading(false)
|
49 |
+
})
|
50 |
+
}, [])
|
51 |
useEffect(() => {
|
52 |
if (data) {
|
53 |
const models = data.model_table.map(item => ({ type: 'Model', value: item.model, detail: item.provider, searchText: item.provider.toLowerCase() + ' ' + item.model.toLowerCase() }))
|
|
|
104 |
{error && <p>Error: {error}</p>}
|
105 |
{data && (
|
106 |
<>
|
107 |
+
<div
|
108 |
+
style={{
|
109 |
+
flex: '100vw 100vw 100vw',
|
110 |
+
maxWidth: 'min(100vw, 900px)',
|
111 |
+
marginBottom: '2rem'
|
112 |
+
}}
|
113 |
+
>
|
114 |
+
<div id='figure'>
|
115 |
+
<WorldMap data={data} topology={topology} />
|
116 |
+
</div>
|
117 |
+
</div>
|
118 |
<div
|
119 |
style={{
|
120 |
flex: '60vw 100vw 40vw',
|
frontend/src/components/WorldMap.js
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { useRef, useEffect } from 'react';
|
2 |
+
import * as d3 from 'd3';
|
3 |
+
import { feature } from 'topojson-client';
|
4 |
+
|
5 |
+
const WorldMap = ({ data, topology }) => {
|
6 |
+
const svgRef = useRef(null);
|
7 |
+
|
8 |
+
useEffect(() => {
|
9 |
+
const createMap = async () => {
|
10 |
+
// Clear any existing SVG content
|
11 |
+
d3.select(svgRef.current).selectAll("*").remove();
|
12 |
+
|
13 |
+
// Set dimensions
|
14 |
+
const width = 800;
|
15 |
+
const height = 450;
|
16 |
+
|
17 |
+
// Create SVG
|
18 |
+
const svg = d3.select(svgRef.current)
|
19 |
+
.attr("width", width)
|
20 |
+
.attr("height", height)
|
21 |
+
.attr("viewBox", [0, 0, width, height])
|
22 |
+
.attr("style", "max-width: 100%; height: auto;");
|
23 |
+
|
24 |
+
// Create a projection
|
25 |
+
const projection = d3.geoNaturalEarth1()
|
26 |
+
.scale(width / 2 / Math.PI)
|
27 |
+
.translate([width / 2, height / 2]);
|
28 |
+
|
29 |
+
// Create a path generator
|
30 |
+
const path = d3.geoPath()
|
31 |
+
.projection(projection);
|
32 |
+
|
33 |
+
// Convert TopoJSON to GeoJSON
|
34 |
+
const countries = feature(topology, topology.objects.countries);
|
35 |
+
|
36 |
+
// Draw the map
|
37 |
+
svg.append("g")
|
38 |
+
.selectAll("path")
|
39 |
+
.data(countries.features)
|
40 |
+
.join("path")
|
41 |
+
.attr("fill", "#ccc") // Grey background
|
42 |
+
.attr("d", path)
|
43 |
+
.attr("stroke", "#fff")
|
44 |
+
.attr("stroke-width", 0.5);
|
45 |
+
};
|
46 |
+
|
47 |
+
createMap();
|
48 |
+
}, [data, topology]);
|
49 |
+
|
50 |
+
return (
|
51 |
+
<div className="world-map-container">
|
52 |
+
<h2>World Language Distribution</h2>
|
53 |
+
<svg ref={svgRef}></svg>
|
54 |
+
</div>
|
55 |
+
);
|
56 |
+
};
|
57 |
+
|
58 |
+
export default WorldMap;
|
frontend/src/index.css
CHANGED
@@ -58,6 +58,15 @@ html, body, #root {
|
|
58 |
color: white;
|
59 |
}
|
60 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
.p-autocomplete-input {
|
62 |
width: max(100%, 40vw);
|
63 |
margin-top: 2vh;
|
|
|
58 |
color: white;
|
59 |
}
|
60 |
|
61 |
+
#figure {
|
62 |
+
width: 100%;
|
63 |
+
min-width: 600px;
|
64 |
+
height: 600px;
|
65 |
+
border: 1px solid #bdbdbd;
|
66 |
+
border-radius: 10px;
|
67 |
+
padding: 10px;
|
68 |
+
}
|
69 |
+
|
70 |
.p-autocomplete-input {
|
71 |
width: max(100%, 40vw);
|
72 |
margin-top: 2vh;
|