Move to Kaplay

This commit is contained in:
MeowcaTheoRange 2024-06-01 01:31:08 -05:00
parent 5b2aa4dc8b
commit 30ac08e50f
7 changed files with 7184 additions and 127 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,114 +1,160 @@
import "./leaflet.js"; // window.L
const options = {
lang: "en_US",
offs: 0,
viewportPadding: 20,
boundsPadding: 0.1,
}
const defaultPolyStyling = {
color: "#000000",
opacity: 1,
fill: true,
fillOpacity: 0.25,
weight: 3
};
import kaplay from "./modules/kaplay.js";
function moveBounds(polys, xoff = 0, yoff = xoff) {
return polys.map(([x, y]) => [y + yoff, x + xoff]);
}
const map = document.querySelector("map");
// Get tile data
class KaplayMap {
kp;
opts = {
minZoomLevel: 0,
maxZoomLevel: 3,
};
async function getTileData(floor) {
let tileDataReq = await fetch(`/data/${options.lang}/map/${floor}`);
let tileData;
if (tileDataReq.ok)
tileData = await tileDataReq.json();
#zoomLevel = 0;
#scaleTween = null;
return tileData.map((room) =>
L.polygon(moveBounds(room.poly, options.offs), defaultPolyStyling)
);
}
startMousePos = null;
startCamPos = null;
prevCamPos = null;
moveVelocity = null;
moveFriction = 0.25;
moveDead = 1;
#moveTween = null;
// Get floor data
constructor(kp, opts) {
this.kp = kp;
this.opts = {
...this.opts,
...opts,
};
async function getFloorData() {
let floorDataReq = await fetch(`/data/${options.lang}/map/`);
let floorData;
if (floorDataReq.ok)
floorData = await floorDataReq.json();
// Zooming
// Add to Leaflet
this.kp.onScroll((delta) => {
const scrollDist = -delta.y / 120;
this.zoomTo(this.zoomLevel + scrollDist, this.kp.mousePos());
});
const floors = await Promise.all(floorData.map(async (data) => {
const tileData = await getTileData(data.id);
// Dragging
const floorPoly = L.polygon(moveBounds(data.poly, options.offs), defaultPolyStyling)
this.kp.onUpdate(() => {
const curCamPos = this.kp.camPos();
const camScale = 1 / this.kp.camScale().y;
return L.featureGroup([
floorPoly,
...tileData
]);
}));
// ||| Completely unintelligible to the average person |||
// vvv Sorry y'all xwx vvv
return {
layers: floorData,
floors: floors
if (this.kp.isMousePressed()) {
this.startMousePos = this.kp.mousePos();
this.startCamPos = this.kp.camPos();
} else if (this.kp.isMouseReleased() && this.prevCamPos != null) {
this.moveVelocity = this.prevCamPos.sub(curCamPos).scale(1 / camScale);
}
if (this.kp.isMouseDown()) {
this.prevCamPos = this.kp.camPos();
this.kp.camPos(
this.startCamPos.sub(
this.kp.mousePos().sub(this.startMousePos).scale(camScale)
)
);
} else if (this.moveVelocity?.x != 0 && this.moveVelocity?.y != 0)
this.kp.camPos(curCamPos.sub(this.moveVelocity?.scale(camScale) ?? 0));
// ^^^ Completely unintelligible to the average person ^^^
// ||| Sorry y'all xwx |||
if (this.moveVelocity == null) return;
if (
this.moveVelocity.x <= this.moveDead &&
this.moveVelocity.x >= -this.moveDead
)
this.moveVelocity.x = 0;
if (
this.moveVelocity.y <= this.moveDead &&
this.moveVelocity.y >= -this.moveDead
)
this.moveVelocity.y = 0;
this.moveVelocity = this.moveVelocity.scale(1 - this.moveFriction);
});
}
get zoomLevel() {
return this.#zoomLevel;
}
set zoomLevel(newZoom) {
const cameraZoom = this.kp.camScale().y;
let addLinear = newZoom;
if (addLinear < this.opts.minZoomLevel) addLinear = this.opts.minZoomLevel;
if (addLinear > this.opts.maxZoomLevel) addLinear = this.opts.maxZoomLevel;
let linearToLog = Math.pow(2, addLinear);
this.#zoomLevel = addLinear;
if (this.#scaleTween != null) {
this.#scaleTween.finish();
}
this.#scaleTween = this.kp.tween(
cameraZoom,
linearToLog,
0.25,
this.kp.camScale,
this.kp.easings.easeOutQuad
);
this.#scaleTween.then(() => {
this.#scaleTween = null;
});
}
zoomTo(newZoom, position) {
const curCamPos = this.kp.camPos();
const camScale = 1 / this.kp.camScale().y;
const diff = this.kp.center().sub(position).scale(camScale);
this.zoomLevel = newZoom;
let newZoomLog = 1 / Math.pow(2, newZoom);
const newDiff = this.kp.center().sub(position).scale(newZoomLog);
if (newZoom < this.opts.minZoomLevel) return;
if (newZoom > this.opts.maxZoomLevel) return;
if (this.#moveTween != null) {
this.#moveTween.finish();
}
this.#moveTween = this.kp.tween(
curCamPos,
curCamPos.sub(diff).add(newDiff),
0.25,
this.kp.camPos,
this.kp.easings.easeOutQuad
);
this.#moveTween.then(() => {
this.#moveTween = null;
});
}
}
// Create map
const kp = kaplay({
canvas: map,
focus: true,
loadingScreen: false,
crisp: false,
debug: false,
global: false,
maxFPS: 120,
background: "404040",
});
async function createMap() {
const data = await getFloorData();
const kaplaymap = new KaplayMap(kp, {});
let map = L.map('leaflet-map', {
center: [0, 0],
zoom: 2,
crs: L.CRS.Simple
});
const bean = kp.loadBean();
const mainLayer = L.tileLayer('', {
maxZoom: 4,
minZoom: 1,
attribution: 'Test data'
}).addTo(map);
const floor = data.floors[0].addTo(map);
const layerBounds = floor.getBounds();
const blb = layerBounds.pad(options.boundsPadding);
map.setMaxBounds(blb);
map.fitBounds(layerBounds, { padding: [options.viewportPadding, options.viewportPadding] });
const entries = Object.fromEntries(data.floors.map((floor, i) => [
`${data.layers[i].name}`,
floor
]));
let layerControl = L.control.layers(entries).addTo(map);
return {
floors: data.floors,
map,
mainLayer
};
}
async function mainFunction() {
const { floors, map, mainLayer } = await createMap();
map.on('baselayerchange', ({ layer, name }) => {
const layerBounds = layer.getBounds();
const blb = layerBounds.pad(options.boundsPadding);
map.setMaxBounds(blb);
map.fitBounds(layerBounds, { padding: [options.viewportPadding, options.viewportPadding] });
});
}
mainFunction();
kp.add([kp.sprite("bean"), kp.pos(kp.center())]);

7
assets/styles/style.css Normal file
View file

@ -0,0 +1,7 @@
body, html {
margin: 0;
height: 100vh;
width: 100vw;
box-sizing: border-box;
overflow: hidden;
}

View file

@ -1,16 +0,0 @@
body, html {
margin: 0;
height: 100vh;
width: 100vw;
box-sizing: border-box;
overflow: hidden;
}
#leaflet-map {
background-color: #404040;
display: inline-block;
box-sizing: border-box;
height: 100%;
width: 100%;
}

View file

@ -8,17 +8,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
rel="stylesheet"
href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
crossorigin=""
/>
<link
rel="stylesheet"
href="/assets/styles/styles.css"
href="/assets/styles/style.css"
/>
</head>
<body>
<div id="leaflet-map"></div>
<canvas id="map"></canvas>
<script src="/assets/scripts/script.js" type="module"></script>
</body>
</html>

View file

@ -39,6 +39,37 @@ app.get('/data/:lang/events', async (req, res) => {
return res.send(merged);
})
app.get('/data/:lang/events/:layer', async (req, res) => {
// Get events
let eventsReq = await fetch(new URL("events/events.json", config.data_url));
let events;
if (eventsReq.ok)
events = await eventsReq.json();
else
return res.status(400).send("Bad Request");
// Get localization
let l10nReq = await fetch(new URL(`localization/${req.params.lang}.json`, config.data_url));
let l10n;
if (l10nReq.ok)
l10n = await l10nReq.json();
else
return res.status(404).send("Localization not found!");
const clippedEvents = events.filter((event) => event.where.layer == req.params.layer);
// Merge events and localization
const merged = events.map(event => {
const localizationKey = l10n.__events[event.id];
return {
...event,
...localizationKey
};
});
return res.send(merged);
})
app.get('/data/:lang/map', async (req, res) => {
// Get layers
let layersReq = await fetch(new URL("map/layers.json", config.data_url));