wip: get popup
This commit is contained in:
11
src/data.rs
11
src/data.rs
@ -1,5 +1,6 @@
|
||||
use crate::geo_utils::GeoUtils;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use geojson::{Feature};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
@ -27,11 +28,16 @@ pub struct Game {
|
||||
impl Game {
|
||||
fn build_territories(&mut self, geoutils: &GeoUtils) {
|
||||
let territory_names = geoutils.get_all_territories();
|
||||
for name in territory_names {
|
||||
let territory_json = geoutils.get_feature_collection_copy();
|
||||
for feature in &territory_json.features {
|
||||
let feat: Feature = feature.clone();
|
||||
let name = feature.property("S_HOOD").unwrap_or_default();
|
||||
let name = name.as_str().unwrap_or("unknown");
|
||||
let t: Territory = Territory {
|
||||
territory_name: name,
|
||||
territory_name: String::from(name),
|
||||
claiming_team: None,
|
||||
claiming_score: 0,
|
||||
territory_feature:feat,
|
||||
};
|
||||
self.territories.push(t);
|
||||
}
|
||||
@ -73,6 +79,7 @@ pub struct Territory {
|
||||
pub territory_name: String,
|
||||
pub claiming_team: Option<Team>,
|
||||
pub claiming_score: i32,
|
||||
pub territory_feature: Feature,
|
||||
}
|
||||
|
||||
impl Team {
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
use crate::Team;
|
||||
use geo as geo_types;
|
||||
use geo::algorithm::contains::Contains;
|
||||
use geojson::{FeatureCollection, GeoJson, Geometry, Value};
|
||||
use std::convert::TryFrom;
|
||||
use std::fs;
|
||||
use crate::data::{Game, Territory};
|
||||
|
||||
pub struct GeoUtils {
|
||||
feature_collection: FeatureCollection,
|
||||
@ -42,58 +42,28 @@ impl GeoUtils {
|
||||
self.feature_collection.clone()
|
||||
}
|
||||
|
||||
pub fn get_colored_collection_copy(self, teams: Vec<Team>) -> FeatureCollection {
|
||||
pub fn get_colored_collection_copy(self, game: &Game) -> FeatureCollection {
|
||||
let mut copy = self.feature_collection.clone();
|
||||
for feature in &mut copy.features {
|
||||
let name = feature.property("S_HOOD").unwrap_or_default();
|
||||
let name = name.as_str().unwrap_or("unknown");
|
||||
let mut max_team: (Option<String>, i32) = (None, 0);
|
||||
for team in &teams {
|
||||
let score = team.scores.get(name).unwrap_or(&0);
|
||||
if *score > max_team.1 {
|
||||
max_team = (Some(team.color.clone()), *score);
|
||||
} else if *score > 0 && *score == max_team.1 {
|
||||
// Tie doesn't count
|
||||
max_team = (None, 0);
|
||||
}
|
||||
}
|
||||
match max_team.0 {
|
||||
None => feature.set_property("color", "#888888ff"),
|
||||
Some(c) => {
|
||||
feature.set_property("color", c);
|
||||
// TODO: Make the territories field of Game struct to be a hashmap
|
||||
let this_territory : Territory = game.territories.clone().iter().find(|t| t.territory_name == *name)
|
||||
.expect("somehow the territory wasn't found").clone();
|
||||
match this_territory.claiming_team {
|
||||
Some(team) => {
|
||||
feature.set_property("color", team.color.clone());
|
||||
feature.set_property("claiming_team", team.name.clone());
|
||||
}
|
||||
None => {
|
||||
feature.set_property("color", "#888888ff");
|
||||
}
|
||||
}
|
||||
feature.set_property("claiming_score", this_territory.claiming_score);
|
||||
}
|
||||
copy
|
||||
}
|
||||
|
||||
// pub fn get_number_neighborhoods(self, teams : Vec<Team>) -> HashMap<Team, i32> {
|
||||
// // new dicts of {team_name: number_claimed_neighborhoods}
|
||||
// let team_to_score = HashMap::new();
|
||||
// let mut copy = self.feature_collection.clone();
|
||||
// for feature in &mut copy.features {
|
||||
// let name = feature.property("S_HOOD").unwrap_or_default();
|
||||
// let name = name.as_str().unwrap_or("unknown");
|
||||
// let mut max_team: (Option<Team>, i32) = (None, 0);
|
||||
// for team in &teams {
|
||||
// let score = team.scores.get(name).unwrap_or(&0);
|
||||
// if *score > max_team.1 {
|
||||
// max_team = (Some(team.clone()), *score);
|
||||
// } else if *score > 0 && *score == max_team.1 {
|
||||
// // Tie doesn't count
|
||||
// max_team = (None, 0);
|
||||
// }
|
||||
// }
|
||||
// match max_team.0 {
|
||||
// None => println!("No team has claimed this neighborhood: {name}"),
|
||||
// Some(c) => {
|
||||
// team_to_score.entry(c).and_modify(|val| *val+=1).or_insert(1);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// team_to_score
|
||||
// }
|
||||
|
||||
pub fn get_territory_for(self, point: geo_types::Point) -> String {
|
||||
let feature_collection: FeatureCollection = self.get_feature_collection_copy();
|
||||
for feature in feature_collection {
|
||||
|
||||
@ -139,7 +139,6 @@ async fn get_territories(
|
||||
if let Ok(Responses::GamesResult(games)) = games_actor.send(Messages::GetGames).await
|
||||
&& let Some(game) = games.iter().find(|g| g.code == *game_code)
|
||||
{
|
||||
println!("{0:?}", game);
|
||||
return HttpResponse::Ok()
|
||||
.content_type("application/json")
|
||||
.body(serde_json::to_string(&game.territories).unwrap());
|
||||
@ -183,9 +182,8 @@ async fn geojson_endpoint(
|
||||
if let Ok(Responses::GamesResult(games)) = games_actor.send(Messages::GetGames).await
|
||||
&& let Some(game) = games.iter().find(|g| g.code == *game_code)
|
||||
{
|
||||
let teams = &game.teams;
|
||||
let utils = geo_utils::GeoUtils::new();
|
||||
let feature_collection = utils.get_colored_collection_copy(teams.to_vec());
|
||||
let feature_collection = utils.get_colored_collection_copy(&game);
|
||||
return HttpResponse::Ok()
|
||||
.content_type("application/json")
|
||||
.body(serde_json::to_string(&feature_collection).unwrap());
|
||||
|
||||
@ -36,8 +36,13 @@
|
||||
function onEachFeature(feature, layer) {
|
||||
// bind a popup to each geojson element
|
||||
// does this feature have a property named popupContent?
|
||||
|
||||
if (feature.properties) {
|
||||
layer.bindPopup(feature.properties.S_HOOD);
|
||||
const popup = document.createElement("p");
|
||||
popup.textContent += feature.properties.S_HOOD;
|
||||
popup.textContent += "\nTeam: " + feature.properties.claiming_team;
|
||||
popup.textContent += "\nScore: " + feature.properties.claiming_score;
|
||||
layer.bindPopup(popup);
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,7 +53,9 @@
|
||||
|
||||
fetch('/geojson/{{game_code}}')
|
||||
.then(res => res.json())
|
||||
.then(data => L.geoJSON(data, {style: style, onEachFeature : onEachFeature}).addTo(map));
|
||||
.then(data => {
|
||||
L.geoJSON(data, {style: style, onEachFeature : onEachFeature}).addTo(map)
|
||||
});
|
||||
// </map>
|
||||
// <legend>
|
||||
const endpoint = "/legend-data/{{game_code}}";
|
||||
|
||||
@ -1,79 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{{ game_code }}</title>
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css"/>
|
||||
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
|
||||
<style>
|
||||
#map { height: 90vh; }
|
||||
.legend {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
width: 200px;
|
||||
}
|
||||
.legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.color-box {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 10px;
|
||||
border: 1px solid #000;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
<ul id="legend" class="legend"></ul>
|
||||
<script>
|
||||
// <map>
|
||||
function style(feature) {
|
||||
return { color: feature.properties.color};
|
||||
}
|
||||
var map = L.map('map').setView([47.6062, -122.3321], 12);
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
maxZoom: 18,
|
||||
}).addTo(map);
|
||||
|
||||
fetch('/geojson/{{game_code}}')
|
||||
.then(res => res.json())
|
||||
.then(data => L.geoJSON(data, {style: style}).addTo(map));
|
||||
// </map>
|
||||
// <legend>
|
||||
const endpoint = "/legend-data/{{game_code}}";
|
||||
fetch(endpoint)
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error("Network response was not ok");
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
const legend = document.getElementById("legend");
|
||||
// Clear existing content if any
|
||||
legend.innerHTML = "";
|
||||
|
||||
data.forEach(item => {
|
||||
const li = document.createElement("li");
|
||||
li.className = "legend-item";
|
||||
|
||||
const colorBox = document.createElement("span");
|
||||
colorBox.className = "color-box";
|
||||
colorBox.style.backgroundColor = item.color;
|
||||
|
||||
const label = document.createElement("span");
|
||||
label.textContent = item.name;
|
||||
|
||||
li.appendChild(colorBox);
|
||||
li.appendChild(label);
|
||||
legend.appendChild(li);
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Fetching legend data failed:", error);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user