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;
constructor(kp, opts) {
this.kp = kp;
this.opts = {
...this.opts,
...opts,
};
// Zooming
this.kp.onScroll((delta) => {
const scrollDist = -delta.y / 120;
this.zoomTo(this.zoomLevel + scrollDist, this.kp.mousePos());
});
// Dragging
this.kp.onUpdate(() => {
const curCamPos = this.kp.camPos();
const camScale = 1 / this.kp.camScale().y;
// ||| Completely unintelligible to the average person |||
// vvv Sorry y'all xwx vvv
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));
// Get floor data
// ^^^ Completely unintelligible to the average person ^^^
// ||| Sorry y'all xwx |||
async function getFloorData() {
let floorDataReq = await fetch(`/data/${options.lang}/map/`);
let floorData;
if (floorDataReq.ok)
floorData = await floorDataReq.json();
if (this.moveVelocity == null) return;
// Add to Leaflet
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;
const floors = await Promise.all(floorData.map(async (data) => {
const tileData = await getTileData(data.id);
this.moveVelocity = this.moveVelocity.scale(1 - this.moveFriction);
});
}
const floorPoly = L.polygon(moveBounds(data.poly, options.offs), defaultPolyStyling)
get zoomLevel() {
return this.#zoomLevel;
}
return L.featureGroup([
floorPoly,
...tileData
]);
}));
set zoomLevel(newZoom) {
const cameraZoom = this.kp.camScale().y;
return {
layers: floorData,
floors: floors
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));