Skip to content
Snippets Groups Projects
Commit 476b8e54 authored by Saket Agrahari's avatar Saket Agrahari
Browse files

Initial Map POCs

parent 45f68921
No related branches found
No related tags found
No related merge requests found
Showing
with 30643 additions and 0 deletions
from flask import Flask, jsonify, send_file
from flask_cors import CORS
import json
import os
app = Flask(__name__)
# Configure CORS to allow all origins
CORS(app, resources={
r"/api/*": {
"origins": ["http://localhost:3000"],
"methods": ["GET", "POST", "OPTIONS"],
"allow_headers": ["Content-Type"]
}
})
# Create data directory if it doesn't exist
DATA_DIR = os.path.join(os.path.dirname(__file__), 'data')
if not os.path.exists(DATA_DIR):
os.makedirs(DATA_DIR)
def convert_map_to_geojson():
input_file_path = os.path.join(DATA_DIR, 'map.json')
output_file_path = os.path.join(DATA_DIR, 'geant_map_geojson.json')
try:
with open(input_file_path, 'r') as f:
network_data = json.load(f)
geojson = {
"type": "FeatureCollection",
"features": []
}
for iptrunk in network_data['iptrunks']:
if 'iptrunk_sides' in iptrunk['iptrunk']:
start_node = iptrunk['iptrunk']['iptrunk_sides'][0]['iptrunk_side_node']['router_site']
end_node = iptrunk['iptrunk']['iptrunk_sides'][1]['iptrunk_side_node']['router_site']
coordinates = [
[float(start_node['site_longitude']), float(start_node['site_latitude'])],
[float(end_node['site_longitude']), float(end_node['site_latitude'])]
]
feature = {
"type": "Feature",
"properties": {
"subscription_id": iptrunk['subscription_id'],
"iptrunk_speed": iptrunk['iptrunk']['iptrunk_speed'],
"iptrunk_type": iptrunk['iptrunk']['iptrunk_type'],
"iptrunk_capacity": iptrunk['iptrunk']['iptrunk_capacity'],
"gs_id": iptrunk['iptrunk']['gs_id'],
"start_node_city": start_node['site_city'],
"end_node_city": end_node['site_city'],
"start_node_country": start_node['site_country'],
"end_node_country": end_node['site_country'],
},
"geometry": {
"type": "LineString",
"coordinates": coordinates
}
}
geojson['features'].append(feature)
with open(output_file_path, 'w') as f:
json.dump(geojson, f, indent=2)
except Exception as e:
print(f"Error converting to GeoJSON: {str(e)}")
def convert_to_geojson(network_data):
geojson = {
"type": "FeatureCollection",
"features": []
}
# Add nodes as Point features
for node in network_data['cities']: # Changed from 'nodes' to 'cities'
feature = {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [float(node['long']), float(node['lat'])] # Changed from longitude/latitude
},
"properties": {
"id": node['id'],
"name": node['name'],
"type": "node",
"region": node.get('region', ''),
"country_code": node.get('country_code', ''),
"info": node.get('info', '')
}
}
geojson['features'].append(feature)
# Add edges as LineString features
for region, links in network_data['links'].items():
for link in links:
start_node = next((n for n in network_data['cities'] if n['id'] == link['endpoint1_id']), None)
end_node = next((n for n in network_data['cities'] if n['id'] == link['endpoint2_id']), None)
if start_node and end_node:
feature = {
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[float(start_node['long']), float(start_node['lat'])],
[float(end_node['long']), float(end_node['lat'])]
]
},
"properties": {
"id": link['id'],
"source": link['endpoint1_id'],
"target": link['endpoint2_id'],
"type": "edge",
"capacity": link.get('capacity', ''),
"region": region,
"info": link.get('info', ''),
"network": link.get('network', '')
}
}
geojson['features'].append(feature)
return geojson
@app.route('/api/network-data')
def get_network_data():
try:
file_path = os.path.join(DATA_DIR, 'nodes_and_edges.json')
if not os.path.exists(file_path):
return jsonify({"error": f"File not found: {file_path}"}), 404
with open(file_path, 'r') as f:
data = json.load(f)
print("Backend data structure:", {
"cities_count": len(data.get('cities', [])),
"links_regions": list(data.get('links', {}).keys())
})
return jsonify(data)
except json.JSONDecodeError as e:
return jsonify({"error": f"Invalid JSON in file: {str(e)}"}), 400
except Exception as e:
return jsonify({"error": f"Server error: {str(e)}"}), 500
@app.route('/api/topology')
def get_topology():
try:
file_path = os.path.join(DATA_DIR, 'topo.json')
if not os.path.exists(file_path):
return jsonify({"error": f"File not found: {file_path}"}), 404
with open(file_path, 'r') as f:
topo_data = json.load(f)
# Ensure the topology data is in GeoJSON format
if 'type' not in topo_data:
# If it's not already GeoJSON, convert it
geojson = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": feature,
"properties": {}
} for feature in topo_data.get('features', [])]
}
return jsonify(geojson)
return jsonify(topo_data)
except json.JSONDecodeError as e:
return jsonify({"error": f"Invalid JSON in file: {str(e)}"}), 400
except Exception as e:
return jsonify({"error": f"Server error: {str(e)}"}), 500
@app.route('/api/geant-map')
def get_geant_map():
try:
file_path = os.path.join(DATA_DIR, 'geant_map_geojson.json')
if not os.path.exists(file_path):
return jsonify({"error": f"File not found: {file_path}"}), 404
with open(file_path, 'r') as f:
data = json.load(f)
return jsonify(data)
except json.JSONDecodeError as e:
return jsonify({"error": f"Invalid JSON in file: {str(e)}"}), 400
except Exception as e:
return jsonify({"error": f"Server error: {str(e)}"}), 500
if __name__ == '__main__':
convert_map_to_geojson()
app.run(debug=True)
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
{
"files": {
"main.css": "/static/css/main.2a39f069.css",
"main.js": "/static/js/main.a0740bde.js",
"static/media/test-map.svg": "/static/media/test-map.857e032dfe90f034955537835725c32e.svg",
"index.html": "/index.html",
"main.2a39f069.css.map": "/static/css/main.2a39f069.css.map",
"main.a0740bde.js.map": "/static/js/main.a0740bde.js.map"
},
"entrypoints": [
"static/css/main.2a39f069.css",
"static/js/main.a0740bde.js"
]
}
\ No newline at end of file
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Network Visualization App"/><title>Network Visualization</title><script defer="defer" src="/static/js/main.a0740bde.js"></script><link href="/static/css/main.2a39f069.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* @preserve
* Leaflet 1.9.4, a JS library for interactive maps. https://leafletjs.com
* (c) 2010-2023 Vladimir Agafonkin, (c) 2010-2011 CloudMade
*/
/**
* @license React
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
This diff is collapsed.
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 850.39 850.39">
<!-- Generator: Adobe Illustrator 29.3.1, SVG Export Plug-In . SVG Version: 2.1.0 Build 151) -->
<defs>
<style>
.st0 {
fill: #e2a8a8;
}
.st1 {
fill: #afd468;
}
.st2, .st3 {
fill: #231f20;
}
.st2, .st3, .st4 {
stroke-miterlimit: 10;
}
.st2, .st4 {
stroke: #231f20;
stroke-width: 3px;
}
.st5 {
fill: #f3ec56;
}
.st3 {
stroke: #fff;
}
.st6 {
fill: #9e8146;
}
.st7 {
fill: #ca6e2d;
}
.st4 {
fill: none;
}
</style>
</defs>
<g id="Map">
<path id="Amsterdam" class="st5" d="M605.05,360.32c-3.85,8.41-8.2,16.59-13.02,24.48-4.26,6.98-8.96,13.82-15.16,19.15-14.87,12.81-35.85,15.12-53.71,23.24,13.17-12.64,26.33-25.27,39.5-37.91-7.77,3.83-16.25,5.96-24.68,7.98-16.62,3.98-33.32,7.61-50.09,10.91-24.28,4.77-49.02,8.83-73.68,6.82-1.75-.14-3.74-.46-4.67-1.95-.66-1.05-.58-2.39-.4-3.62,3.28-22.54,29.86-37.2,30.55-59.97.04-1.35-.04-2.78-.78-3.9-.9-1.36-2.55-1.97-4.12-2.42-11.83-3.39-24.46-2.07-36.68-3.54-.91-.11-1.93-.3-2.46-1.05-.53-.76-.34-1.79-.11-2.69,1.75-6.9,4.53-13.49,7.08-20.14,8.63-22.48,14.72-45.95,18.11-69.79,8.84-3.65,19.11,1.59,27.23-3.46,3.24-2.01,5.51-5.26,8.51-7.63,4.11-3.25,9.55-4.81,12.92-8.82,1.39-1.65,2.34-3.63,3.72-5.29,3.76-4.55,10.01-6.09,15.86-6.88,20.01-2.73,40.75.18,59.25,8.29,1.05.46,2.15.99,2.77,1.95.62.95.65,2.16.67,3.3.08,5.7.14,11.54-1.71,16.94-1.57,4.59-4.45,8.61-6.75,12.88-4.12,7.67-6.42,16.32-6.65,25.02-.12,4.63.39,9.44,2.74,13.43,2.83,4.79,7.89,7.72,12.05,11.41,6.76,5.99,11.28,14.12,17.68,20.5,9.17,9.15,21.7,14.24,31.2,23.05,3.19,2.95,6.63,5.78,4.82,9.73Z"/>
<path id="Brussel" class="st7" d="M260.97,169.32c-1.68-3.22-3.24-6.66-3.24-10.3,0-5.66,3.69-10.58,7.45-14.81,3.83-4.31,7.92-8.42,12.59-11.8,7.99-5.8,17.4-9.31,26.91-11.94,21.1-5.83,43.33-7.59,65.09-5.16,19.39,2.17,38.27,7.61,56.72,13.98,15.9,5.49,31.96,11.94,44.31,23.34,4.71,4.35,8.86,9.45,11.28,15.4,3.94,9.69,2.92,20.73.18,30.83-2.51,9.25-6.45,18.17-12.18,25.86-10.01,13.43-25.5,22.64-42.07,25.01-8.19,1.17-16.52.74-24.77.18-12.73-.88-25.44-2.08-38.15-3.31-8.18-.79-16.45-1.61-24.22-4.29-33.86-11.64-63.59-41.7-79.9-73Z"/>
<path id="Cambridge" class="st6" d="M471.47,154.35c5.17-4.58,11.81-7.13,18.44-9.1,26.07-7.74,53.74-7.78,80.94-7.29,16.75.3,33.54.78,50.11,3.28,8.99,1.36,18.1,3.38,25.82,8.19,8.9,5.54,15.23,14.29,21.17,22.93,3.56,5.17,7.1,10.45,9.14,16.38s2.45,12.67-.22,18.35c-2.25,4.78-6.43,8.35-10.71,11.45-9.73,7.05-20.77,12.51-32.58,14.66-7.89,1.44-15.97,1.39-23.99,1.14-25.38-.8-50.7-3.6-75.64-8.35-13.63-2.6-27.23-5.79-41.08-6.55-7.5-.41-15.23-.07-22.19,2.75"/>
<path id="Paris" class="st1" d="M550.19,229.6c-9.88,18.04-13.16,38.94-14.37,59.47-.48,8.14-.64,16.44,1.6,24.28,2.17,7.61,6.53,14.45,11.68,20.46,7.51,8.77,16.83,15.98,27.2,21.07,24.6,12.06,53.53,11.67,79.17,21.33,14.83,5.59,28.2,14.4,41.42,23.14,9.92-23.43,12.25-50,6.56-74.8-2.01-8.78-5.01-17.4-5.58-26.39-.57-8.99,1.75-18.75,8.61-24.57,5.13-4.35,12.78-6.71,14.81-13.13,1.94-6.12-2.47-12.3-6.86-16.98-8.11-8.66-17.15-16.45-26.9-23.21-5-3.46-10.74-7.57-11.06-13.64"/>
<path id="London" class="st0" d="M280.04,200.14c-11.33.78-21.7,7.43-28.89,16.23s-11.5,19.6-14.58,30.53c-10.57,37.5-7.01,79.64,13.56,112.73,4.08,6.56,8.8,12.76,12.21,19.7,2.06,4.19,3.83,8.87,7.69,11.5,4.37,2.98,10.35,2.44,15.18.28,4.83-2.16,8.87-5.71,13.2-8.75,12.69-8.91,28.02-13.49,43.41-15.28,15.4-1.79,30.97-.92,46.43.24,15.8,1.19,32.76,2.44,46.45-5.55,4.93-2.88,8.7-6,11-11.22,2.3-5.23,3.23-10.93,4.14-16.57,1.25-7.75,2.5-15.67,1.13-23.4-.93-5.24-3.04-10.18-5.13-15.07-6.98-16.32-13.96-32.64-20.94-48.96-.88-2.05-1.82-4.19-3.55-5.6-1.63-1.33-3.76-1.84-5.82-2.28-9.49-2.02-19.14-3.25-28.83-3.67-6.2-.27-12.51-.21-18.47-1.94-5.51-1.59-10.47-4.62-15.36-7.63-17.1-10.51-34.65-21.26-54.34-25.16-5.85-1.16-12.55-.55-18.49-.14Z"/>
</g>
<g id="Node_x5F_n_x5F_Edge">
<line id="LON-BRU" class="st2" x1="262" y1="282" x2="332.09" y2="184.09"/>
<path id="BRU-CAM" class="st2" d="M332.09,181.46c73.33,3.24,146.66,6.48,219.99,9.71"/>
<path id="CAM-PAR" class="st4" d="M552.09,188.75c78.48,37.76,115.69,63.85,111.61,78.26-.89,3.15-3.75,5.74-8.58,7.77"/>
<path id="PAR-AMS" class="st4" d="M648.46,274.3c-49.95-40.44-69.73-46.11-77.04-40.31-11.75,9.33,13.7,44.32.95,75.09-12.33,29.78-54.8,42-98.38,46.92"/>
<path id="AMS-LON" class="st4" d="M471.5,357.62c-23.86-12.09-47.73-24.18-71.59-36.27-27.2,12.96-54.39,25.93-81.59,38.9l-44.84-18.78c-3.83-19.22-7.65-38.44-11.48-57.66"/>
<circle id="AMS" class="st3" cx="474" cy="356" r="7.09"/>
<circle id="PAR" class="st3" cx="651.49" cy="271.99" r="7.09"/>
<circle id="CAM" class="st3" cx="552.09" cy="191.17" r="7.09"/>
<circle id="BRU" class="st3" cx="332.09" cy="184.09" r="7.09"/>
<circle id="LON_x7C_1:5.1" class="st3" cx="262" cy="282" r="7.09"/>
</g>
</svg>
\ No newline at end of file
This diff is collapsed.
{
"name": "network-visualization",
"version": "1.0.0",
"private": true,
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"ol": "^8.2.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="Network Visualization App" />
<title>Network Visualization</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
\ No newline at end of file
import React, { useState, useRef, useEffect } from 'react';
import MapView from './components/MapView';
import SubwayViewGeo from './components/SubwayViewGeo';
import SubwayView from './components/SubwayView';
import SubwayViewV2 from './components/SubwayViewV2';
import SubwayViewLeaflet from './components/SubwayViewLeaflet';
import './styles/Map.css';
import MapComponent from './components/MapComponent';
function App() {
const [viewType, setViewType] = useState('normal');
const popupRef = useRef();
// Clean up popup when switching views
useEffect(() => {
if (popupRef.current) {
popupRef.current.style.display = 'none';
}
}, [viewType]);
const renderView = () => {
const props = { popupRef };
switch(viewType) {
case 'normal':
return <MapView viewType={viewType} />;
case 'subway-w':
return <SubwayView {...props} key="subway" />;
case 'subway-ol':
return <SubwayViewGeo {...props} key="subway" />;
case 'subway-leaflet':
return <SubwayViewLeaflet {...props} key="subway" />;
case 'subwayv2':
return <SubwayViewV2 {...props} key="subwayv2" />;
case 'svg':
return <MapComponent {...props} key="svg" />;
default:
return <MapView viewType={viewType} />;
}
};
return (
<div className="app">
<div className="map-wrapper">
<div className="controls">
<select
value={viewType}
onChange={(e) => setViewType(e.target.value)}
>
<option value="normal">Normal View</option>
<option value="subway-leaflet">Basic Geant Leaflet View</option>
<option value="subway-ol">Basic Geant Open Layer View</option>
<option value="subway-w">Basic World Open Layer View</option>
<option value="subwayv2">Subway View V2 (Snapped)</option>
<option value="svg">SVG View</option>
</select>
</div>
{renderView()}
</div>
<div ref={popupRef} className="line-popup" />
</div>
);
}
export default App;
.svg-container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.hovered {
stroke: red !important;
fill: yellow !important;
}
.enlarged {
transform: scale(1.2) !important;
transition: transform 0.2s;
transform-origin: center;
}
.popup {
position: absolute;
background-color: white;
border: 1px solid #ccc;
z-index: 1000;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
padding: 10px;
border-radius: 15px;
cursor: pointer;
}
.popup-content {
text-align: center;
}
import React, { useEffect, useState } from 'react';
import './MapComponent.css';
import testMap from '../svg/test-map.svg';
const MapComponent = () => {
const [popupContent, setPopupContent] = useState('');
const [popupVisible, setPopupVisible] = useState(false);
const [popupPosition, setPopupPosition] = useState({ top: 0, left: 0 });
useEffect(() => {
const svgObject = document.getElementById('svg-map');
console.log(svgObject);
svgObject.addEventListener('load', () => {
const svgDoc = svgObject.contentDocument;
const elements = svgDoc.querySelectorAll('line, path, circle');
elements.forEach(element => {
element.addEventListener('mouseover', () => {
const id = element.getAttribute('id');
console.log(`Hovered over: ${id}`);
element.classList.add('hovered');
element.classList.add('enlarged');
});
element.addEventListener('mouseout', () => {
element.classList.remove('hovered');
element.classList.remove('enlarged');
});
element.addEventListener('click', (event) => {
const id = element.getAttribute('id');
setPopupContent(`Element id: ${id}`);
const popupWidth = 150; // Adjust this value based on your popup width
const popupHeight = 80; // Adjust this value based on your popup height
setPopupPosition({ top: event.clientY - popupHeight, left: event.clientX - popupWidth / 2 });
setPopupVisible(true);
event.stopPropagation(); // Prevent the click from propagating to the document
});
});
});
const handleClickOutside = () => {
if (popupVisible) {
setPopupVisible(false);
setPopupContent('');
}
};
document.addEventListener('click', handleClickOutside);
return () => {
const svgDoc = svgObject.contentDocument;
const elements = svgDoc.querySelectorAll('line, path, circle');
elements.forEach(element => {
element.removeEventListener('mouseover', () => {});
element.removeEventListener('mouseout', () => {});
element.removeEventListener('click', () => {});
});
document.removeEventListener('click', handleClickOutside);
};
}, [popupVisible]);
return (
<div onClick={(e) => e.stopPropagation()}>
<object id="svg-map" type="image/svg+xml" data={testMap}>
Your browser does not support SVG
</object>
{popupVisible && (
<div className="popup" style={{ top: popupPosition.top, left: popupPosition.left }}>
<div className="popup-content">
<p>{popupContent}</p>
</div>
</div>
)}
</div>
);
};
export default MapComponent;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment