Fix violation of unmined license (distribution)
This commit is contained in:
parent
c63eeb83a0
commit
16f60f6075
@ -1,36 +1,41 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Navbar from "../../Navbar.svelte";
|
import Navbar from "../../Navbar.svelte";
|
||||||
|
import { unmined } from "../../stores";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Unmined,
|
ol_proxy,
|
||||||
type UnminedOptions,
|
type UnminedOptions,
|
||||||
type UnminedRegions,
|
type UnminedRegions,
|
||||||
} from "./unmined";
|
} from "./unmined";
|
||||||
|
|
||||||
export let id = "map";
|
export let id = "map";
|
||||||
|
|
||||||
let unmined = new Unmined();
|
|
||||||
|
|
||||||
type Metadata = {
|
type Metadata = {
|
||||||
properties: UnminedOptions;
|
properties: UnminedOptions;
|
||||||
regions: UnminedRegions;
|
regions: UnminedRegions;
|
||||||
};
|
};
|
||||||
|
|
||||||
async function get_metadata() {
|
async function get_unmined() {
|
||||||
|
if ($unmined === null) {
|
||||||
|
let resp = await fetch("map/unmined.js");
|
||||||
|
let code = await resp.text();
|
||||||
|
$unmined = Function("ol", code).call({}, ol_proxy);
|
||||||
|
}
|
||||||
|
|
||||||
let resp = await fetch("map/metadata.js");
|
let resp = await fetch("map/metadata.js");
|
||||||
let code = await resp.text();
|
let code = await resp.text();
|
||||||
let meta = Function(code).call({}); // TODO possibly vulnerable to prototype pollution
|
let meta: Metadata = Function(code).call({}); // TODO possibly vulnerable to prototype pollution
|
||||||
return meta;
|
return meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupMap(node: HTMLDivElement, metadata: Metadata) {
|
function setupMap(node: HTMLDivElement, metadata: Metadata) {
|
||||||
unmined.map(node.id, metadata.properties, metadata.regions);
|
$unmined.map(node.id, metadata.properties, metadata.regions);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
destroy() {
|
destroy() {
|
||||||
if (unmined.openlayersMap) {
|
if ($unmined.openlayersMap) {
|
||||||
unmined.openlayersMap.setTarget(null);
|
$unmined.openlayersMap.setTarget(null);
|
||||||
unmined.openlayersMap = null;
|
$unmined.openlayersMap = null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -39,7 +44,7 @@
|
|||||||
|
|
||||||
<div class="map-outer">
|
<div class="map-outer">
|
||||||
<Navbar />
|
<Navbar />
|
||||||
{#await get_metadata() then metadata}
|
{#await get_unmined() then metadata}
|
||||||
<div class="map-target" {id} use:setupMap={metadata} />
|
<div class="map-target" {id} use:setupMap={metadata} />
|
||||||
{:catch err}
|
{:catch err}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
@ -1,18 +1,15 @@
|
|||||||
|
import type OlMap from "ol/Map";
|
||||||
|
import type VectorLayer from "ol/layer/Vector";
|
||||||
|
import type VectorSource from "ol/source/Vector";
|
||||||
import { boundingExtent } from "ol/extent";
|
import { boundingExtent } from "ol/extent";
|
||||||
import { addCoordinateTransforms, Projection, transform } from "ol/proj";
|
import { addCoordinateTransforms, Projection } from "ol/proj";
|
||||||
import TileGrid from "ol/tilegrid/TileGrid";
|
import TileGrid from "ol/tilegrid/TileGrid";
|
||||||
import { Tile } from "ol/layer";
|
|
||||||
import XYZ from "ol/source/XYZ";
|
import XYZ from "ol/source/XYZ";
|
||||||
import MousePosition from "ol/control/MousePosition";
|
import Tile from "ol/layer/Tile";
|
||||||
import { createStringXY } from "ol/coordinate";
|
import { createStringXY } from "ol/coordinate";
|
||||||
import OlMap from "ol/Map";
|
import MousePosition from "ol/control/MousePosition";
|
||||||
import { defaults as controlDefaults } from "ol/control/defaults";
|
import { defaults } from "ol/control/defaults";
|
||||||
import { Feature, View } from "ol";
|
import { Map, View } from "ol";
|
||||||
import { Point } from "ol/geom";
|
|
||||||
import Style from "ol/style/Style";
|
|
||||||
import Icon from "ol/style/Icon";
|
|
||||||
import Text from "ol/style/Text";
|
|
||||||
import Fill from "ol/style/Fill";
|
|
||||||
import SourceVector from "ol/source/Vector";
|
import SourceVector from "ol/source/Vector";
|
||||||
import LayerVector from "ol/layer/Vector";
|
import LayerVector from "ol/layer/Vector";
|
||||||
|
|
||||||
@ -30,227 +27,45 @@ export type UnminedOptions = {
|
|||||||
markers: Array<any>;
|
markers: Array<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UnminedRegions = {}[];
|
export type UnminedRegions = {
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
m: Uint32Array,
|
||||||
|
}[];
|
||||||
|
|
||||||
export class Unmined {
|
export type Unmined = {
|
||||||
|
openlayersMap: OlMap,
|
||||||
openlayersMap: OlMap;
|
map: (mapId: string, options: UnminedOptions, regions: UnminedRegions) => void,
|
||||||
|
createMarkersLayer: (markers, dataProjection, viewProjection) => VectorLayer<VectorSource>,
|
||||||
|
}
|
||||||
|
|
||||||
map(mapId: string, options: UnminedOptions, regions: any[]) {
|
/** (cursed) proxy variable to provide the fetched unmined script access to `ol.extent.boundingExtent` etc */
|
||||||
const dpiScale = window.devicePixelRatio ?? 1.0;
|
export const ol_proxy = {
|
||||||
|
extent: {
|
||||||
const worldMinX = options.minRegionX * 512;
|
boundingExtent: boundingExtent,
|
||||||
const worldMinY = options.minRegionZ * 512;
|
},
|
||||||
const worldWidth = (options.maxRegionX + 1 - options.minRegionX) * 512;
|
proj: {
|
||||||
const worldHeight = (options.maxRegionZ + 1 - options.minRegionZ) * 512;
|
Projection: Projection,
|
||||||
|
addCoordinateTransforms: addCoordinateTransforms,
|
||||||
const worldTileSize = 256;
|
},
|
||||||
|
tilegrid: {
|
||||||
const worldMaxZoomFactor = Math.pow(2, options.maxZoom);
|
TileGrid: TileGrid,
|
||||||
|
},
|
||||||
// left, bottom, right, top, Y is negated
|
layer: {
|
||||||
var mapExtent = boundingExtent([
|
Tile: Tile,
|
||||||
[worldMinX * worldMaxZoomFactor, -(worldMinY + worldHeight) * worldMaxZoomFactor],
|
Vector: LayerVector,
|
||||||
[(worldMinX + worldWidth) * worldMaxZoomFactor, -worldMinY * worldMaxZoomFactor]]);
|
},
|
||||||
|
source: {
|
||||||
var viewProjection = new Projection({
|
XYZ: XYZ,
|
||||||
code: 'VIEW',
|
Vector: SourceVector,
|
||||||
units: 'pixels',
|
},
|
||||||
});
|
control: {
|
||||||
|
MousePosition: MousePosition,
|
||||||
var dataProjection = new Projection({
|
defaults: defaults,
|
||||||
code: 'DATA',
|
},
|
||||||
units: 'pixels',
|
coordinate: {
|
||||||
});
|
createStringXY: createStringXY,
|
||||||
|
},
|
||||||
// Coordinate transformation between view and data
|
View: View,
|
||||||
// OpenLayers Y is positive up, world Y is positive down
|
Map: Map,
|
||||||
addCoordinateTransforms(viewProjection, dataProjection,
|
};
|
||||||
function (coordinate) {
|
|
||||||
return [coordinate[0], -coordinate[1]];
|
|
||||||
},
|
|
||||||
function (coordinate) {
|
|
||||||
return [coordinate[0], -coordinate[1]];
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapZoomLevels = options.maxZoom - options.minZoom;
|
|
||||||
// Resolution for each OpenLayers zoom level
|
|
||||||
var resolutions = new Array(mapZoomLevels + 1);
|
|
||||||
for (let z = 0; z < mapZoomLevels + 1; ++z) {
|
|
||||||
resolutions[mapZoomLevels - z] = Math.pow(2, z) * dpiScale / worldMaxZoomFactor;
|
|
||||||
}
|
|
||||||
|
|
||||||
var tileGrid = new TileGrid({
|
|
||||||
extent: mapExtent,
|
|
||||||
origin: [0, 0],
|
|
||||||
resolutions: resolutions,
|
|
||||||
tileSize: worldTileSize / dpiScale
|
|
||||||
});
|
|
||||||
|
|
||||||
var unminedLayer =
|
|
||||||
new Tile({
|
|
||||||
source: new XYZ({
|
|
||||||
projection: viewProjection,
|
|
||||||
tileGrid: tileGrid,
|
|
||||||
tilePixelRatio: dpiScale,
|
|
||||||
tileSize: worldTileSize / dpiScale,
|
|
||||||
|
|
||||||
tileUrlFunction: function (coordinate) {
|
|
||||||
const worldZoom = -(mapZoomLevels - coordinate[0]) + options.maxZoom;
|
|
||||||
const worldZoomFactor = Math.pow(2, worldZoom);
|
|
||||||
|
|
||||||
const minTileX = Math.floor(worldMinX * worldZoomFactor / worldTileSize);
|
|
||||||
const minTileY = Math.floor(worldMinY * worldZoomFactor / worldTileSize);
|
|
||||||
const maxTileX = Math.ceil((worldMinX + worldWidth) * worldZoomFactor / worldTileSize) - 1;
|
|
||||||
const maxTileY = Math.ceil((worldMinY + worldHeight) * worldZoomFactor / worldTileSize) - 1;
|
|
||||||
|
|
||||||
const tileX = coordinate[1];
|
|
||||||
const tileY = coordinate[2];
|
|
||||||
|
|
||||||
const tileBlockSize = worldTileSize / worldZoomFactor;
|
|
||||||
const tileBlockPoint = {
|
|
||||||
x: tileX * tileBlockSize,
|
|
||||||
z: tileY * tileBlockSize
|
|
||||||
};
|
|
||||||
|
|
||||||
const hasTile = function () {
|
|
||||||
const tileRegionPoint = {
|
|
||||||
x: Math.floor(tileBlockPoint.x / 512),
|
|
||||||
z: Math.floor(tileBlockPoint.z / 512)
|
|
||||||
};
|
|
||||||
const tileRegionSize = Math.ceil(tileBlockSize / 512);
|
|
||||||
|
|
||||||
for (let x = tileRegionPoint.x; x < tileRegionPoint.x + tileRegionSize; x++) {
|
|
||||||
for (let z = tileRegionPoint.z; z < tileRegionPoint.z + tileRegionSize; z++) {
|
|
||||||
const group = {
|
|
||||||
x: Math.floor(x / 32),
|
|
||||||
z: Math.floor(z / 32)
|
|
||||||
};
|
|
||||||
const regionMap = regions.find(e => e.x == group.x && e.z == group.z);
|
|
||||||
if (regionMap) {
|
|
||||||
const relX = x - group.x * 32;
|
|
||||||
const relZ = z - group.z * 32;
|
|
||||||
const inx = relZ * 32 + relX;
|
|
||||||
var b = regionMap.m[Math.floor(inx / 32)];
|
|
||||||
var bit = inx % 32;
|
|
||||||
var found = (b & (1 << bit)) != 0;
|
|
||||||
if (found) return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (tileX >= minTileX
|
|
||||||
&& tileY >= minTileY
|
|
||||||
&& tileX <= maxTileX
|
|
||||||
&& tileY <= maxTileY
|
|
||||||
&& hasTile()) {
|
|
||||||
const z = worldZoom,
|
|
||||||
yd = Math.floor(tileY / 10),
|
|
||||||
xd = Math.floor(tileX / 10),
|
|
||||||
y = tileY,
|
|
||||||
x = tileX
|
|
||||||
const url = `map/tiles/zoom.${z}/${xd}/${yd}/tile.${x}.${y}.${options.imageFormat}`
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
var mousePositionControl = new MousePosition({
|
|
||||||
coordinateFormat: createStringXY(0),
|
|
||||||
projection: dataProjection
|
|
||||||
});
|
|
||||||
|
|
||||||
var map = new OlMap({
|
|
||||||
target: mapId,
|
|
||||||
controls: controlDefaults().extend([
|
|
||||||
mousePositionControl
|
|
||||||
]),
|
|
||||||
layers: [
|
|
||||||
unminedLayer,
|
|
||||||
/*
|
|
||||||
new ol.layer.Tile({
|
|
||||||
source: new ol.source.TileDebug({
|
|
||||||
tileGrid: unminedTileGrid,
|
|
||||||
projection: viewProjection
|
|
||||||
})
|
|
||||||
})
|
|
||||||
*/
|
|
||||||
|
|
||||||
],
|
|
||||||
view: new View({
|
|
||||||
center: [0, 0],
|
|
||||||
extent: mapExtent,
|
|
||||||
projection: viewProjection,
|
|
||||||
resolutions: tileGrid.getResolutions(),
|
|
||||||
maxZoom: mapZoomLevels,
|
|
||||||
zoom: mapZoomLevels - options.maxZoom,
|
|
||||||
constrainResolution: true,
|
|
||||||
showFullExtent: true,
|
|
||||||
constrainOnlyCenter: true
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
if (options.markers) {
|
|
||||||
var markersLayer = this.createMarkersLayer(options.markers, dataProjection, viewProjection);
|
|
||||||
map.addLayer(markersLayer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.background) {
|
|
||||||
document.getElementById(mapId).style.backgroundColor = options.background;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
this.openlayersMap = map;
|
|
||||||
}
|
|
||||||
|
|
||||||
createMarkersLayer(markers, dataProjection, viewProjection) {
|
|
||||||
var features = [];
|
|
||||||
|
|
||||||
for (var i = 0; i < markers.length; i++) {
|
|
||||||
var item = markers[i];
|
|
||||||
var longitude = item.x;
|
|
||||||
var latitude = item.z;
|
|
||||||
|
|
||||||
var feature = new Feature({
|
|
||||||
geometry: new Point(transform([longitude, latitude], dataProjection, viewProjection))
|
|
||||||
});
|
|
||||||
|
|
||||||
var style = new Style();
|
|
||||||
if (item.image)
|
|
||||||
style.setImage(new Icon({
|
|
||||||
src: item.image,
|
|
||||||
anchor: item.imageAnchor,
|
|
||||||
scale: item.imageScale
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (item.text)
|
|
||||||
style.setText(new Text({
|
|
||||||
text: item.text,
|
|
||||||
font: item.font,
|
|
||||||
offsetX: item.offsetX,
|
|
||||||
offsetY: item.offsetY,
|
|
||||||
fill: new Fill({
|
|
||||||
color: item.textColor
|
|
||||||
})
|
|
||||||
}));
|
|
||||||
|
|
||||||
feature.setStyle(style);
|
|
||||||
|
|
||||||
features.push(feature);
|
|
||||||
}
|
|
||||||
|
|
||||||
var vectorSource = new SourceVector({
|
|
||||||
features: features
|
|
||||||
});
|
|
||||||
|
|
||||||
var vectorLayer = new LayerVector({
|
|
||||||
source: vectorSource
|
|
||||||
});
|
|
||||||
return vectorLayer;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,5 @@
|
|||||||
import { writable, type Writable } from "svelte/store";
|
import { writable, type Writable } from "svelte/store";
|
||||||
|
import type { Unmined } from "./pages/mining/unmined";
|
||||||
|
|
||||||
type User = {
|
type User = {
|
||||||
name: string,
|
name: string,
|
||||||
@ -6,4 +7,5 @@ type User = {
|
|||||||
picture: string,
|
picture: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const user: Writable<User | null> = writable(null);
|
export const user: Writable<User | null> = writable(null);
|
||||||
|
export const unmined: Writable<Unmined | null> = writable(null);
|
@ -4,13 +4,14 @@ from fastapi.responses import HTMLResponse
|
|||||||
|
|
||||||
from .settings import settings
|
from .settings import settings
|
||||||
from .user import user_auth
|
from .user import user_auth
|
||||||
from .map_tiles import map_tiles
|
from .map_tiles import map_tiles, map_meta
|
||||||
from .templates import j2env
|
from .templates import j2env
|
||||||
|
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
|
|
||||||
app.mount("/user/", user_auth)
|
app.mount("/user/", user_auth)
|
||||||
app.mount("/map/", map_tiles)
|
app.mount("/map/", map_meta)
|
||||||
|
app.mount("/tiles/", map_tiles)
|
||||||
|
|
||||||
frontend = FastAPI()
|
frontend = FastAPI()
|
||||||
|
|
||||||
|
@ -4,17 +4,23 @@ from fastapi.staticfiles import StaticFiles
|
|||||||
from .settings import settings
|
from .settings import settings
|
||||||
from .templates import j2env
|
from .templates import j2env
|
||||||
|
|
||||||
map_tiles = FastAPI()
|
map_tiles = StaticFiles(directory=f"{settings.unmined_out_path}/tiles")
|
||||||
|
|
||||||
map_tiles.mount("/tiles/", StaticFiles(directory=f"{settings.unmined_out_path}/tiles"))
|
map_meta = FastAPI()
|
||||||
|
|
||||||
|
|
||||||
class MetadataJsResponse(Response):
|
class JsResponse(Response):
|
||||||
media_type = "text/javascript"
|
media_type = "text/javascript"
|
||||||
|
|
||||||
|
|
||||||
MAP_PROPS_FILE = f"{settings.unmined_out_path}/unmined.map.properties.js"
|
MAP_PROPS_FILE = f"{settings.unmined_out_path}/unmined.map.properties.js"
|
||||||
MAP_REGIONS_FILE = f"{settings.unmined_out_path}/unmined.map.regions.js"
|
MAP_REGIONS_FILE = f"{settings.unmined_out_path}/unmined.map.regions.js"
|
||||||
|
UNMINED_FILE = f"{settings.unmined_out_path}/unmined.openlayers.js"
|
||||||
|
|
||||||
|
with open(UNMINED_FILE, "r") as f:
|
||||||
|
unmined_script = j2env.get_template("unmined.js").render(
|
||||||
|
unmined_file=UNMINED_FILE, unmined_script=f.read()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def parse_metadata():
|
def parse_metadata():
|
||||||
@ -31,7 +37,12 @@ def parse_metadata():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@map_tiles.get("/metadata.js", response_class=MetadataJsResponse)
|
@map_meta.get("/unmined.js", response_class=JsResponse)
|
||||||
|
async def get_unmined():
|
||||||
|
return unmined_script
|
||||||
|
|
||||||
|
|
||||||
|
@map_meta.get("/metadata.js", response_class=JsResponse)
|
||||||
async def get_metadata():
|
async def get_metadata():
|
||||||
# TODO cache
|
# TODO cache
|
||||||
return parse_metadata()
|
return parse_metadata()
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
/* {{props_file}} */
|
/* {{ props_file }} */
|
||||||
{{map_props}}
|
{{ map_props }}
|
||||||
|
/* end of {{ props_file }} */
|
||||||
|
|
||||||
/* {{regions_file}} */
|
/* {{ regions_file }} */
|
||||||
{{map_regions}}
|
{{map_regions}}
|
||||||
|
/* end of {{ regions_file }} */
|
||||||
|
|
||||||
return {
|
return {
|
||||||
properties: UnminedMapProperties,
|
properties: UnminedMapProperties,
|
||||||
|
5
server/templates/unmined.js
Normal file
5
server/templates/unmined.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/* {{ unmined_file }} */
|
||||||
|
{{ unmined_script }}
|
||||||
|
/* end of {{ unmined_file }} */
|
||||||
|
|
||||||
|
return new Unmined();
|
Loading…
Reference in New Issue
Block a user