Spaces:
Running
Running
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;
|