diff --git a/calefaction/eve/universe.py b/calefaction/eve/universe.py index 0ccb179..3f38bcb 100644 --- a/calefaction/eve/universe.py +++ b/calefaction/eve/universe.py @@ -45,6 +45,11 @@ class _SolarSystem(_UniqueObject): return self._data["security"] @property + def coords(self): + """The solar system's coordinates, as a 3-tuple of floats (x, y, z).""" + return tuple(self._data["coords"]) + + @property def faction(self): """The solar system's faction, as a _Faction object, or None.""" if "faction" in self._data: @@ -66,6 +71,11 @@ class _SolarSystem(_UniqueObject): """Whether the solar system is in nullsec.""" return self.security >= 0.45 + @property + def is_whspace(self): + """Whether the solar system is in wormhole space.""" + return self.region.is_whspace + class _Constellation(_UniqueObject): """Represents a constellation.""" @@ -87,6 +97,11 @@ class _Constellation(_UniqueObject): return self._universe.faction(self._data["faction"]) return self.region.faction + @property + def is_whspace(self): + """Whether the constellation is in wormhole space.""" + return self.region.is_whspace + class _Region(_UniqueObject): """Represents a region.""" @@ -103,6 +118,11 @@ class _Region(_UniqueObject): return self._universe.faction(self._data["faction"]) return None + @property + def is_whspace(self): + """Whether the region is in wormhole space.""" + return self._id >= 11000000 + class _Faction(_UniqueObject): """Represents a faction.""" @@ -173,7 +193,8 @@ class _DummySolarSystem(_SolarSystem): "name": "Unknown", "constellation": -1, "region": -1, - "security": 0.0 + "security": 0.0, + "coords": (0, 0, 0) }) @@ -288,6 +309,12 @@ class Universe: return _DummySolarSystem(self) return _SolarSystem(self, sid, self._systems[sid]) + def systems(self): + """Return an iterator over all _SolarSystems.""" + self._load() + for sid in self._systems: + yield self.system(sid) + def constellation(self, cid): """Return a _Constellation with the given ID. diff --git a/calefaction/modules/map.py b/calefaction/modules/map.py index 4fd4f11..dc20547 100644 --- a/calefaction/modules/map.py +++ b/calefaction/modules/map.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- +from flask import g, json from flask_mako import render_template -from ._provided import blueprint +from ._provided import app, blueprint def home(): """Render and return the main map page.""" @@ -16,3 +17,22 @@ def navitem(): def map(): """Render and return the main map page.""" return home() + +@blueprint.rroute("/map/data.json") +def mapdata(): + """Render and return the map data as a JSON object.""" + payload = { + "galaxy": { + system.id: { + "name": system.name, + "coords": system.coords, + "security": system.security + } + for system in g.eve.universe.systems() if not system.is_whspace + } + } + resp = app.response_class(response=json.dumps(payload), status=200, + mimetype="application/json") + resp.cache_control.private = True + resp.cache_control.max_age = 24 * 60 * 60 + return resp diff --git a/scripts/import_sde.py b/scripts/import_sde.py index 96485b1..8253004 100755 --- a/scripts/import_sde.py +++ b/scripts/import_sde.py @@ -150,7 +150,9 @@ def _build_galaxy_skeleton(ids, names): assert isinstance(sid, int) d[sid] = { "name": names[sid], - "constellation": -1, "region": -1, "security": 0.0 + "constellation": -1, + "region": -1, + "security": 0.0 } print("done.") @@ -160,15 +162,18 @@ def _load_assoc_for_system(galaxy, system, rid, cid): data = _load_yaml(system / "solarsystem.staticdata") sid = data["solarSystemID"] sec = data["security"] + coords = data["center"] assert isinstance(sid, int) assert isinstance(sec, float) assert sid >= 0 assert sec >= -1.0 and sec <= 1.0 + assert len(coords) == 3 and all(isinstance(val, float) for val in coords) galaxy["systems"][sid]["constellation"] = cid galaxy["systems"][sid]["region"] = rid galaxy["systems"][sid]["security"] = sec + galaxy["systems"][sid]["coords"] = coords if "factionID" in data: facid = data["factionID"] diff --git a/static/map.css b/static/map.css new file mode 100644 index 0000000..409674b --- /dev/null +++ b/static/map.css @@ -0,0 +1,3 @@ +#map .system { + fill: currentColor; +} diff --git a/static/map.js b/static/map.js new file mode 100644 index 0000000..ef53530 --- /dev/null +++ b/static/map.js @@ -0,0 +1,47 @@ +$(function() { + $("#map").html("

Loading map data...

"); + $.getJSON( "map/data.json", function(data) { + $("#map").empty(); + var svg = d3.select("#map").append("svg") + .attr("width", 1000) + .attr("height", 1000); // TODO: dynamic + + var xmin = Infinity, xmax = -Infinity, + ymin = Infinity, ymax = -Infinity; + for (var sid in data["galaxy"]) { + var system = data["galaxy"][sid]; + var x = system["coords"][0]; + var y = system["coords"][2]; + if (x < xmin) xmin = x; + if (x > xmax) xmax = x; + if (y < ymin) ymin = y; + if (y > ymax) ymax = y; + } + + var width = xmax - xmin; + var height = ymax - ymin; + var scale = 1000; + + svg.attr("viewBox", "0 0 " + scale + " " + scale); + + svg.selectAll("circle") + .data(Object.values(data["galaxy"])) + .enter() + .append("circle") + .attr("cx", (d) => { + var x = d["coords"][0]; + return (x - xmin) / width * scale; + }) + .attr("cy", (d) => { + var y = d["coords"][2]; + return (y - ymin) / height * scale; + }) + .attr("r", 1) + .attr("class", (d) => { + var sec = d["security"]; + var klass = sec < 0.05 ? "null" : + Number(sec).toFixed(1).replace(".", "_"); + return "system sec-" + klass; + }); + }); +}); diff --git a/templates/map/map.mako b/templates/map/map.mako index 4dadc8b..66a7af7 100644 --- a/templates/map/map.mako +++ b/templates/map/map.mako @@ -2,6 +2,16 @@ <%block name="title"> ${self.support.maketitle("Map")} +<%block name="extracss"> + ${self.support.makecss("map.css")} + +<%block name="extrajs"> + + ${self.support.makejs("map.js")} +

Map

-## TODO -

No map available yet!

+
+ +