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 import kaplay from "./modules/kaplay.js";
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
};
function moveBounds(polys, xoff = 0, yoff = xoff) { const map = document.querySelector("map");
return polys.map(([x, y]) => [y + yoff, x + xoff]);
}
// Get tile data class KaplayMap {
kp;
opts = {
minZoomLevel: 0,
maxZoomLevel: 3,
};
async function getTileData(floor) { #zoomLevel = 0;
let tileDataReq = await fetch(`/data/${options.lang}/map/${floor}`); #scaleTween = null;
let tileData;
if (tileDataReq.ok)
tileData = await tileDataReq.json();
return tileData.map((room) => startMousePos = null;
L.polygon(moveBounds(room.poly, options.offs), defaultPolyStyling) 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() { // Zooming
let floorDataReq = await fetch(`/data/${options.lang}/map/`);
let floorData;
if (floorDataReq.ok)
floorData = await floorDataReq.json();
// 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) => { // Dragging
const tileData = await getTileData(data.id);
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([ // ||| Completely unintelligible to the average person |||
floorPoly, // vvv Sorry y'all xwx vvv
...tileData
]);
}));
return { if (this.kp.isMousePressed()) {
layers: floorData, this.startMousePos = this.kp.mousePos();
floors: floors 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 kaplaymap = new KaplayMap(kp, {});
const data = await getFloorData();
let map = L.map('leaflet-map', { const bean = kp.loadBean();
center: [0, 0],
zoom: 2,
crs: L.CRS.Simple
});
const mainLayer = L.tileLayer('', { kp.add([kp.sprite("bean"), kp.pos(kp.center())]);
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();

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

View file

@ -39,6 +39,37 @@ app.get('/data/:lang/events', async (req, res) => {
return res.send(merged); 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) => { app.get('/data/:lang/map', async (req, res) => {
// Get layers // Get layers
let layersReq = await fetch(new URL("map/layers.json", config.data_url)); let layersReq = await fetch(new URL("map/layers.json", config.data_url));