mirror of
https://github.com/placeAtlas/atlas.git
synced 2024-09-26 12:09:00 +02:00
Remove ending semicolon
This commit is contained in:
parent
935eadd618
commit
cc57d2bc4f
9 changed files with 1282 additions and 1282 deletions
|
@ -14,47 +14,47 @@
|
|||
*/
|
||||
|
||||
window.addEventListener("error", function (e) {
|
||||
console.error(e);
|
||||
let errorMessage = "<h4 class=\"mb-3\">An error has occurred:</h4>";
|
||||
errorMessage += "<p class=\"text-danger\">" + e.message + "</p>";
|
||||
errorMessage += "<p class=\"text-danger\">on line " + e.lineno + "</p>";
|
||||
errorMessage += "<p>If this keeps happening, feel free to tell us on <a href=\"https://discord.gg/pJkm23b2nA\">our Discord server</a>.</p>";
|
||||
document.getElementById("loadingContent").innerHTML = errorMessage;
|
||||
});
|
||||
console.error(e)
|
||||
let errorMessage = "<h4 class=\"mb-3\">An error has occurred:</h4>"
|
||||
errorMessage += "<p class=\"text-danger\">" + e.message + "</p>"
|
||||
errorMessage += "<p class=\"text-danger\">on line " + e.lineno + "</p>"
|
||||
errorMessage += "<p>If this keeps happening, feel free to tell us on <a href=\"https://discord.gg/pJkm23b2nA\">our Discord server</a>.</p>"
|
||||
document.getElementById("loadingContent").innerHTML = errorMessage
|
||||
})
|
||||
|
||||
function getPositionOfEntry(entry) {
|
||||
let startX = 2000, startY = 2000;
|
||||
let startX = 2000, startY = 2000
|
||||
for (const [x, y] of entry.path) {
|
||||
startX = Math.min(x, startX);
|
||||
startX = Math.min(x, startX)
|
||||
startY = Math.min(y, startY)
|
||||
}
|
||||
if (startX === 2000 || startY === 2000) return null;
|
||||
return [parseInt(startX), parseInt(startY)];
|
||||
if (startX === 2000 || startY === 2000) return null
|
||||
return [parseInt(startX), parseInt(startY)]
|
||||
}
|
||||
|
||||
const areaMap = new Map();
|
||||
const areaMap = new Map()
|
||||
|
||||
// Modified from https://stackoverflow.com/a/33670691
|
||||
function calcPolygonArea(vertices) {
|
||||
const hit = areaMap.get(vertices);
|
||||
const hit = areaMap.get(vertices)
|
||||
if (hit != null) {
|
||||
return hit;
|
||||
return hit
|
||||
}
|
||||
|
||||
let total = 0;
|
||||
let total = 0
|
||||
|
||||
for (let i = 0, l = vertices.length; i < l; i++) {
|
||||
const addX = vertices[i][0];
|
||||
const addY = vertices[i == vertices.length - 1 ? 0 : i + 1][1];
|
||||
const subX = vertices[i == vertices.length - 1 ? 0 : i + 1][0];
|
||||
const subY = vertices[i][1];
|
||||
const addX = vertices[i][0]
|
||||
const addY = vertices[i == vertices.length - 1 ? 0 : i + 1][1]
|
||||
const subX = vertices[i == vertices.length - 1 ? 0 : i + 1][0]
|
||||
const subY = vertices[i][1]
|
||||
|
||||
total += (addX * addY * 0.5);
|
||||
total -= (subX * subY * 0.5);
|
||||
total += (addX * addY * 0.5)
|
||||
total -= (subX * subY * 0.5)
|
||||
}
|
||||
|
||||
const area = Math.floor(Math.abs(total));
|
||||
areaMap.set(vertices, area);
|
||||
const area = Math.floor(Math.abs(total))
|
||||
areaMap.set(vertices, area)
|
||||
|
||||
return area;
|
||||
return area
|
||||
}
|
762
web/_js/draw.js
762
web/_js/draw.js
File diff suppressed because it is too large
Load diff
|
@ -4,11 +4,11 @@ function updateFavicon(colorScheme) {
|
|||
const faviconFallback = document.head.querySelector('.js-site-favicon[type="image/png"]')
|
||||
if (favicon && faviconFallback) {
|
||||
if (colorScheme || colorScheme == 'dark') {
|
||||
favicon.href = '_img/favicon-dark.svg';
|
||||
faviconFallback.href = '_img/favicon-dark.png';
|
||||
favicon.href = '_img/favicon-dark.svg'
|
||||
faviconFallback.href = '_img/favicon-dark.png'
|
||||
} else {
|
||||
favicon.href = '_img/favicon.svg';
|
||||
faviconFallback.href = '_img/favicon.png';
|
||||
favicon.href = '_img/favicon.svg'
|
||||
faviconFallback.href = '_img/favicon.png'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,186 +15,186 @@
|
|||
|
||||
function createInfoBlock(entry, isPreview) {
|
||||
function createLabel(name, value, parent) {
|
||||
const nameElement = document.createElement("span");
|
||||
nameElement.className = "fw-bold";
|
||||
nameElement.textContent = name;
|
||||
const valueElement = document.createElement("span");
|
||||
valueElement.textContent = value;
|
||||
parent.appendChild(nameElement);
|
||||
parent.appendChild(valueElement);
|
||||
return parent;
|
||||
const nameElement = document.createElement("span")
|
||||
nameElement.className = "fw-bold"
|
||||
nameElement.textContent = name
|
||||
const valueElement = document.createElement("span")
|
||||
valueElement.textContent = value
|
||||
parent.appendChild(nameElement)
|
||||
parent.appendChild(valueElement)
|
||||
return parent
|
||||
}
|
||||
function createInfoListItem(name, value) {
|
||||
const entryInfoListElement = document.createElement("li");
|
||||
entryInfoListElement.className = "list-group-item";
|
||||
createLabel(name, value, entryInfoListElement);
|
||||
return entryInfoListElement;
|
||||
const entryInfoListElement = document.createElement("li")
|
||||
entryInfoListElement.className = "list-group-item"
|
||||
createLabel(name, value, entryInfoListElement)
|
||||
return entryInfoListElement
|
||||
}
|
||||
|
||||
const element = document.createElement("div");
|
||||
element.className = "card mb-2 overflow-hidden shadow";
|
||||
const element = document.createElement("div")
|
||||
element.className = "card mb-2 overflow-hidden shadow"
|
||||
|
||||
const headerElement = document.createElement("h4");
|
||||
headerElement.className = "card-header";
|
||||
const headerElement = document.createElement("h4")
|
||||
headerElement.className = "card-header"
|
||||
|
||||
const linkElement = document.createElement("a");
|
||||
linkElement.className = "text-decoration-none d-flex justify-content-between text-body";
|
||||
if (isPreview) linkElement.href = "#";
|
||||
const linkElement = document.createElement("a")
|
||||
linkElement.className = "text-decoration-none d-flex justify-content-between text-body"
|
||||
if (isPreview) linkElement.href = "#"
|
||||
else {
|
||||
let targetPeriod = formatPeriod(currentPeriod, currentPeriod, currentVariation)
|
||||
linkElement.href = "#" + entry.id
|
||||
if (targetPeriod && targetPeriod != defaultPeriod) linkElement.href += "/" + targetPeriod
|
||||
};
|
||||
const linkNameElement = document.createElement("span");
|
||||
linkNameElement.className = "flex-grow-1 text-break";
|
||||
linkNameElement.textContent = entry.name;
|
||||
headerElement.appendChild(linkElement);
|
||||
linkElement.appendChild(linkNameElement);
|
||||
linkElement.insertAdjacentHTML("beforeend", '<i class="bi bi-link-45deg align-self-center link-primary" aria-hidden="true"></i>');// '<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" class="bi bi-link-45deg ms-1 align-self-center flex-shrink-0" viewBox="0 0 16 16"><path d="M4.715 6.542 3.343 7.914a3 3 0 1 0 4.243 4.243l1.828-1.829A3 3 0 0 0 8.586 5.5L8 6.086a1.002 1.002 0 0 0-.154.199 2 2 0 0 1 .861 3.337L6.88 11.45a2 2 0 1 1-2.83-2.83l.793-.792a4.018 4.018 0 0 1-.128-1.287z"/><path d="M6.586 4.672A3 3 0 0 0 7.414 9.5l.775-.776a2 2 0 0 1-.896-3.346L9.12 3.55a2 2 0 1 1 2.83 2.83l-.793.792c.112.42.155.855.128 1.287l1.372-1.372a3 3 0 1 0-4.243-4.243L6.586 4.672z"/></svg>');
|
||||
element.appendChild(headerElement);
|
||||
}
|
||||
const linkNameElement = document.createElement("span")
|
||||
linkNameElement.className = "flex-grow-1 text-break"
|
||||
linkNameElement.textContent = entry.name
|
||||
headerElement.appendChild(linkElement)
|
||||
linkElement.appendChild(linkNameElement)
|
||||
linkElement.insertAdjacentHTML("beforeend", '<i class="bi bi-link-45deg align-self-center link-primary" aria-hidden="true"></i>');// '<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" class="bi bi-link-45deg ms-1 align-self-center flex-shrink-0" viewBox="0 0 16 16"><path d="M4.715 6.542 3.343 7.914a3 3 0 1 0 4.243 4.243l1.828-1.829A3 3 0 0 0 8.586 5.5L8 6.086a1.002 1.002 0 0 0-.154.199 2 2 0 0 1 .861 3.337L6.88 11.45a2 2 0 1 1-2.83-2.83l.793-.792a4.018 4.018 0 0 1-.128-1.287z"/><path d="M6.586 4.672A3 3 0 0 0 7.414 9.5l.775-.776a2 2 0 0 1-.896-3.346L9.12 3.55a2 2 0 1 1 2.83 2.83l-.793.792c.112.42.155.855.128 1.287l1.372-1.372a3 3 0 1 0-4.243-4.243L6.586 4.672z"/></svg>')
|
||||
element.appendChild(headerElement)
|
||||
|
||||
const bodyElement = document.createElement("div");
|
||||
bodyElement.className = "card-body d-flex flex-column gap-3";
|
||||
element.appendChild(bodyElement);
|
||||
const bodyElement = document.createElement("div")
|
||||
bodyElement.className = "card-body d-flex flex-column gap-3"
|
||||
element.appendChild(bodyElement)
|
||||
|
||||
if (entry.description) {
|
||||
const descElement = document.createElement("div");
|
||||
descElement.id = "objectDescription";
|
||||
let formattedDesc = entry.description.replace(/\n{2}/g, '</p><p>');
|
||||
formattedDesc = formattedDesc.replace(/\n/g, '<br>');
|
||||
descElement.innerHTML = '<p>' + formattedDesc + '</p>';
|
||||
bodyElement.appendChild(descElement);
|
||||
const descElement = document.createElement("div")
|
||||
descElement.id = "objectDescription"
|
||||
let formattedDesc = entry.description.replace(/\n{2}/g, '</p><p>')
|
||||
formattedDesc = formattedDesc.replace(/\n/g, '<br>')
|
||||
descElement.innerHTML = '<p>' + formattedDesc + '</p>'
|
||||
bodyElement.appendChild(descElement)
|
||||
}
|
||||
|
||||
const linkListElement = document.createElement("div");
|
||||
linkListElement.className = "d-flex flex-column gap-2";
|
||||
bodyElement.appendChild(linkListElement);
|
||||
const linkListElement = document.createElement("div")
|
||||
linkListElement.className = "d-flex flex-column gap-2"
|
||||
bodyElement.appendChild(linkListElement)
|
||||
|
||||
const listElement = document.createElement("ul");
|
||||
listElement.className = "list-group list-group-flush";
|
||||
element.appendChild(listElement);
|
||||
const listElement = document.createElement("ul")
|
||||
listElement.className = "list-group list-group-flush"
|
||||
element.appendChild(listElement)
|
||||
|
||||
if (entry.diff) {
|
||||
let diffElement = createInfoListItem("Diff: ", entry.diff);
|
||||
let diffElement = createInfoListItem("Diff: ", entry.diff)
|
||||
if (entry.diff == "add") {
|
||||
diffElement.className = "list-group-item list-group-item-success";
|
||||
diffElement.className = "list-group-item list-group-item-success"
|
||||
} else if (entry.diff == "edit") {
|
||||
diffElement.className = "list-group-item list-group-item-warning";
|
||||
diffElement.className = "list-group-item list-group-item-warning"
|
||||
} else if (entry.diff == "delete") {
|
||||
diffElement.className = "list-group-item list-group-item-danger";
|
||||
diffElement.className = "list-group-item list-group-item-danger"
|
||||
}
|
||||
listElement.appendChild(diffElement);
|
||||
listElement.appendChild(diffElement)
|
||||
}
|
||||
|
||||
if (!isPreview) {
|
||||
const [x, y] = entry.center;
|
||||
listElement.appendChild(createInfoListItem("Position: ", `${Math.floor(x)}, ${Math.floor(y)}`));
|
||||
const [x, y] = entry.center
|
||||
listElement.appendChild(createInfoListItem("Position: ", `${Math.floor(x)}, ${Math.floor(y)}`))
|
||||
|
||||
if(entry.path){
|
||||
const area = calcPolygonArea(entry.path);
|
||||
listElement.appendChild(createInfoListItem("Area: ", `${area} pixels`));
|
||||
if (entry.path) {
|
||||
const area = calcPolygonArea(entry.path)
|
||||
listElement.appendChild(createInfoListItem("Area: ", `${area} pixels`))
|
||||
}
|
||||
}
|
||||
|
||||
if (!(entry.links.subreddit === undefined || entry.links.subreddit.length == 0)) {
|
||||
const subredditGroupElement = document.createElement("div");
|
||||
subredditGroupElement.className = "btn-group-vertical";
|
||||
linkListElement.appendChild(subredditGroupElement);
|
||||
const subredditGroupElement = document.createElement("div")
|
||||
subredditGroupElement.className = "btn-group-vertical"
|
||||
linkListElement.appendChild(subredditGroupElement)
|
||||
|
||||
entry.links.subreddit.forEach(subreddit => {
|
||||
if (subreddit) {
|
||||
subreddit = "r/" + subreddit;
|
||||
const subredditLinkElement = document.createElement("a");
|
||||
subredditLinkElement.className = "btn btn-primary text-truncate";
|
||||
subredditLinkElement.target = "_blank";
|
||||
subredditLinkElement.rel = "noopener noreferrer";
|
||||
subredditLinkElement.href = "https://reddit.com/" + subreddit;
|
||||
subredditLinkElement.innerHTML = `<i class="bi bi-reddit" aria-hidden="true"></i> ${subreddit}`;
|
||||
subredditGroupElement.appendChild(subredditLinkElement);
|
||||
subreddit = "r/" + subreddit
|
||||
const subredditLinkElement = document.createElement("a")
|
||||
subredditLinkElement.className = "btn btn-primary text-truncate"
|
||||
subredditLinkElement.target = "_blank"
|
||||
subredditLinkElement.rel = "noopener noreferrer"
|
||||
subredditLinkElement.href = "https://reddit.com/" + subreddit
|
||||
subredditLinkElement.innerHTML = `<i class="bi bi-reddit" aria-hidden="true"></i> ${subreddit}`
|
||||
subredditGroupElement.appendChild(subredditLinkElement)
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (!(entry.links.website === undefined || entry.links.website.length == 0)) {
|
||||
const websiteGroupElement = document.createElement("div");
|
||||
websiteGroupElement.className = "btn-group-vertical";
|
||||
linkListElement.appendChild(websiteGroupElement);
|
||||
const websiteGroupElement = document.createElement("div")
|
||||
websiteGroupElement.className = "btn-group-vertical"
|
||||
linkListElement.appendChild(websiteGroupElement)
|
||||
|
||||
entry.links.website.forEach(link => {
|
||||
if (link) {
|
||||
const websiteLinkElement = document.createElement("a");
|
||||
const websiteLinkElement = document.createElement("a")
|
||||
websiteLinkElement.className = "btn btn-primary text-truncate"
|
||||
websiteLinkElement.target = "_blank";
|
||||
websiteLinkElement.rel = "noopener noreferrer";
|
||||
websiteLinkElement.href = link;
|
||||
websiteLinkElement.target = "_blank"
|
||||
websiteLinkElement.rel = "noopener noreferrer"
|
||||
websiteLinkElement.href = link
|
||||
try {
|
||||
const urlObject = new URL(link)
|
||||
websiteLinkElement.innerHTML = `<i class="bi bi-globe" aria-hidden="true"></i> ${urlObject.hostname.replace(/^www./, "")}`;
|
||||
websiteLinkElement.innerHTML = `<i class="bi bi-globe" aria-hidden="true"></i> ${urlObject.hostname.replace(/^www./, "")}`
|
||||
} catch (e) {
|
||||
websiteLinkElement.innerHTML = `<i class="bi bi-globe" aria-hidden="true"></i> Website`;
|
||||
websiteLinkElement.innerHTML = `<i class="bi bi-globe" aria-hidden="true"></i> Website`
|
||||
}
|
||||
websiteGroupElement.appendChild(websiteLinkElement);
|
||||
websiteGroupElement.appendChild(websiteLinkElement)
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
if (!(entry.links.discord === undefined || entry.links.discord.length == 0)) {
|
||||
const discordGroupElement = document.createElement("div");
|
||||
discordGroupElement.className = "btn-group-vertical";
|
||||
linkListElement.appendChild(discordGroupElement);
|
||||
const discordGroupElement = document.createElement("div")
|
||||
discordGroupElement.className = "btn-group-vertical"
|
||||
linkListElement.appendChild(discordGroupElement)
|
||||
|
||||
entry.links.discord.forEach(link => {
|
||||
if (link) {
|
||||
const discordLinkElement = document.createElement("a");
|
||||
const discordLinkElement = document.createElement("a")
|
||||
discordLinkElement.className = "btn btn-primary text-truncate"
|
||||
discordLinkElement.target = "_blank";
|
||||
discordLinkElement.rel = "noopener noreferrer";
|
||||
discordLinkElement.href = "https://discord.gg/" + link;
|
||||
discordLinkElement.innerHTML = `<i class="bi bi-discord" aria-hidden="true"></i> ${link}`;
|
||||
discordGroupElement.appendChild(discordLinkElement);
|
||||
discordLinkElement.target = "_blank"
|
||||
discordLinkElement.rel = "noopener noreferrer"
|
||||
discordLinkElement.href = "https://discord.gg/" + link
|
||||
discordLinkElement.innerHTML = `<i class="bi bi-discord" aria-hidden="true"></i> ${link}`
|
||||
discordGroupElement.appendChild(discordLinkElement)
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
if (!(entry.links.wiki === undefined || entry.links.wiki.length == 0)) {
|
||||
const wikiGroupElement = document.createElement("div");
|
||||
wikiGroupElement.className = "btn-group-vertical";
|
||||
linkListElement.appendChild(wikiGroupElement);
|
||||
const wikiGroupElement = document.createElement("div")
|
||||
wikiGroupElement.className = "btn-group-vertical"
|
||||
linkListElement.appendChild(wikiGroupElement)
|
||||
|
||||
entry.links.wiki.forEach(link => {
|
||||
if (link) {
|
||||
const wikiLinkElement = document.createElement("a");
|
||||
const wikiLinkElement = document.createElement("a")
|
||||
wikiLinkElement.className = "btn btn-primary text-truncate"
|
||||
wikiLinkElement.target = "_blank";
|
||||
wikiLinkElement.rel = "noopener noreferrer";
|
||||
wikiLinkElement.href = "https://place-wiki.stefanocoding.me/wiki/" + link.replace(/ /g, '_');
|
||||
wikiLinkElement.innerHTML = `<i class="bi bi-book" aria-hidden="true"></i> Wiki Article`;
|
||||
wikiGroupElement.appendChild(wikiLinkElement);
|
||||
wikiLinkElement.target = "_blank"
|
||||
wikiLinkElement.rel = "noopener noreferrer"
|
||||
wikiLinkElement.href = "https://place-wiki.stefanocoding.me/wiki/" + link.replace(/ /g, '_')
|
||||
wikiLinkElement.innerHTML = `<i class="bi bi-book" aria-hidden="true"></i> Wiki Article`
|
||||
wikiGroupElement.appendChild(wikiLinkElement)
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
const idElement = document.createElement("div");
|
||||
idElement.className = "py-1";
|
||||
createLabel("ID: ", entry.id, idElement);
|
||||
const idElement = document.createElement("div")
|
||||
idElement.className = "py-1"
|
||||
createLabel("ID: ", entry.id, idElement)
|
||||
|
||||
const idElementContainer = document.createElement("div");
|
||||
idElementContainer.className = "card-footer d-flex justify-content-between align-items-center";
|
||||
idElementContainer.appendChild(idElement);
|
||||
element.appendChild(idElementContainer);
|
||||
const idElementContainer = document.createElement("div")
|
||||
idElementContainer.className = "card-footer d-flex justify-content-between align-items-center"
|
||||
idElementContainer.appendChild(idElement)
|
||||
element.appendChild(idElementContainer)
|
||||
|
||||
if (!isPreview && (!entry.diff || entry.diff !== "delete")) {
|
||||
const editElement = document.createElement("a");
|
||||
editElement.textContent = "Edit";
|
||||
editElement.className = "btn btn-sm btn-outline-primary";
|
||||
const editElement = document.createElement("a")
|
||||
editElement.textContent = "Edit"
|
||||
editElement.className = "btn btn-sm btn-outline-primary"
|
||||
editElement.href = "./?mode=draw&id=" + entry.id
|
||||
editElement.title = "Edit " + entry.name;
|
||||
idElementContainer.appendChild(editElement);
|
||||
editElement.title = "Edit " + entry.name
|
||||
idElementContainer.appendChild(editElement)
|
||||
}
|
||||
|
||||
if (!bodyElement.hasChildNodes()) bodyElement.remove();
|
||||
if (!linkListElement.hasChildNodes()) linkListElement.remove();
|
||||
if (!listElement.hasChildNodes()) listElement.remove();
|
||||
if (!bodyElement.hasChildNodes()) bodyElement.remove()
|
||||
if (!linkListElement.hasChildNodes()) linkListElement.remove()
|
||||
if (!listElement.hasChildNodes()) listElement.remove()
|
||||
|
||||
return element;
|
||||
return element
|
||||
}
|
374
web/_js/main.js
374
web/_js/main.js
|
@ -15,89 +15,89 @@
|
|||
|
||||
const prodDomain = "place-atlas.stefanocoding.me"
|
||||
|
||||
const innerContainer = document.getElementById("innerContainer");
|
||||
const container = document.getElementById("container");
|
||||
const canvas = document.getElementById("highlightCanvas");
|
||||
const context = canvas.getContext("2d");
|
||||
const innerContainer = document.getElementById("innerContainer")
|
||||
const container = document.getElementById("container")
|
||||
const canvas = document.getElementById("highlightCanvas")
|
||||
const context = canvas.getContext("2d")
|
||||
|
||||
let zoom = 1;
|
||||
let zoom = 1
|
||||
|
||||
if (window.devicePixelRatio) {
|
||||
zoom = 1 / window.devicePixelRatio;
|
||||
zoom = 1 / window.devicePixelRatio
|
||||
}
|
||||
|
||||
const maxZoom = 128;
|
||||
const minZoom = 0.1;
|
||||
const maxZoom = 128
|
||||
const minZoom = 0.1
|
||||
|
||||
let zoomOrigin = [0, 0];
|
||||
let scaleZoomOrigin = [0, 0];
|
||||
let zoomOrigin = [0, 0]
|
||||
let scaleZoomOrigin = [0, 0]
|
||||
|
||||
let dragging = false;
|
||||
let lastPosition = [0, 0];
|
||||
let dragging = false
|
||||
let lastPosition = [0, 0]
|
||||
|
||||
const viewportSize = [0, 0];
|
||||
const viewportSize = [0, 0]
|
||||
|
||||
// document.getElementById("entriesListDonate").addEventListener("click", function(e){
|
||||
// document.getElementById("donateOverlay").style.display = "flex";
|
||||
// });
|
||||
// document.getElementById("donateOverlay").style.display = "flex"
|
||||
// })
|
||||
|
||||
// document.getElementById("closeDonateButton").addEventListener("click", function(e){
|
||||
// document.getElementById("donateOverlay").style.display = "none";
|
||||
// });
|
||||
// document.getElementById("donateOverlay").style.display = "none"
|
||||
// })
|
||||
|
||||
function applyView() {
|
||||
|
||||
//console.log(zoomOrigin, scaleZoomOrigin);
|
||||
//console.log(scaleZoomOrigin[0]);
|
||||
//console.log(zoomOrigin, scaleZoomOrigin)
|
||||
//console.log(scaleZoomOrigin[0])
|
||||
|
||||
scaleZoomOrigin[0] = Math.max(-1000, Math.min(1000, scaleZoomOrigin[0]));
|
||||
scaleZoomOrigin[1] = Math.max(-1000, Math.min(1000, scaleZoomOrigin[1]));
|
||||
scaleZoomOrigin[0] = Math.max(-1000, Math.min(1000, scaleZoomOrigin[0]))
|
||||
scaleZoomOrigin[1] = Math.max(-1000, Math.min(1000, scaleZoomOrigin[1]))
|
||||
|
||||
zoomOrigin = [scaleZoomOrigin[0] * zoom, scaleZoomOrigin[1] * zoom];
|
||||
zoomOrigin = [scaleZoomOrigin[0] * zoom, scaleZoomOrigin[1] * zoom]
|
||||
|
||||
innerContainer.style.height = (~~(zoom * 2000)) + "px";
|
||||
innerContainer.style.width = (~~(zoom * 2000)) + "px";
|
||||
innerContainer.style.height = (~~(zoom * 2000)) + "px"
|
||||
innerContainer.style.width = (~~(zoom * 2000)) + "px"
|
||||
|
||||
innerContainer.style.left = ~~(container.clientWidth / 2 - innerContainer.clientWidth / 2 + zoomOrigin[0] + container.offsetLeft) + "px";
|
||||
innerContainer.style.top = ~~(container.clientHeight / 2 - innerContainer.clientHeight / 2 + zoomOrigin[1] + container.offsetTop) + "px";
|
||||
innerContainer.style.left = ~~(container.clientWidth / 2 - innerContainer.clientWidth / 2 + zoomOrigin[0] + container.offsetLeft) + "px"
|
||||
innerContainer.style.top = ~~(container.clientHeight / 2 - innerContainer.clientHeight / 2 + zoomOrigin[1] + container.offsetTop) + "px"
|
||||
|
||||
}
|
||||
|
||||
let atlas = null;
|
||||
let atlas = null
|
||||
window.atlas = atlas
|
||||
let atlasAll = null
|
||||
window.atlasAll = atlasAll
|
||||
|
||||
if (document.location.host !== prodDomain) document.body.dataset.dev = ""
|
||||
|
||||
init();
|
||||
init()
|
||||
|
||||
async function init() {
|
||||
// For Reviewing Reddit Changes
|
||||
//let resp = await fetch("../tools/temp_atlas.json");
|
||||
const resp = await fetch("./atlas.json");
|
||||
atlas = await resp.json();
|
||||
//let resp = await fetch("../tools/temp_atlas.json")
|
||||
const resp = await fetch("./atlas.json")
|
||||
atlas = await resp.json()
|
||||
atlas.sort(function (a, b) {
|
||||
if (a.center[1] < b.center[1]) {
|
||||
return -1;
|
||||
return -1
|
||||
}
|
||||
if (a.center[1] > b.center[1]) {
|
||||
return 1;
|
||||
return 1
|
||||
}
|
||||
// a must be equal to b
|
||||
return 0;
|
||||
});
|
||||
return 0
|
||||
})
|
||||
|
||||
atlasAll = updateAtlasAll(atlas);
|
||||
atlasAll = updateAtlasAll(atlas)
|
||||
|
||||
let mode = "view";
|
||||
let mode = "view"
|
||||
|
||||
const args = window.location.search;
|
||||
const args = window.location.search
|
||||
const params = new URLSearchParams(args)
|
||||
if (args) {
|
||||
mode = params.get("mode")
|
||||
if (!mode) {
|
||||
mode = "view";
|
||||
mode = "view"
|
||||
}
|
||||
|
||||
// Backwards compatibility for old links using "search" id arg
|
||||
|
@ -112,26 +112,26 @@ async function init() {
|
|||
}
|
||||
|
||||
const hash = window.location.hash.substring(1)
|
||||
const [ , period] = hash.split('/')
|
||||
const [, period] = hash.split('/')
|
||||
|
||||
if (period) {
|
||||
const [ , targetPeriod, targetVariation] = parsePeriod(period)
|
||||
const [, targetPeriod, targetVariation] = parsePeriod(period)
|
||||
await updateTime(targetPeriod, targetVariation)
|
||||
} else {
|
||||
await updateTime(currentPeriod, currentVariation)
|
||||
}
|
||||
|
||||
//console.log(document.documentElement.clientWidth, document.documentElement.clientHeight);
|
||||
//console.log(document.documentElement.clientWidth, document.documentElement.clientHeight)
|
||||
|
||||
zoomOrigin = [0, 0];
|
||||
applyView();
|
||||
zoomOrigin = [0, 0]
|
||||
applyView()
|
||||
|
||||
let initialPinchDistance = 0;
|
||||
let initialPinchZoom = 0;
|
||||
let initialPinchZoomOrigin = [0, 0];
|
||||
let initialPinchDistance = 0
|
||||
let initialPinchZoom = 0
|
||||
let initialPinchZoomOrigin = [0, 0]
|
||||
|
||||
let desiredZoom;
|
||||
let zoomAnimationFrame;
|
||||
let desiredZoom
|
||||
let zoomAnimationFrame
|
||||
|
||||
document.body.dataset.mode = mode
|
||||
|
||||
|
@ -139,38 +139,38 @@ async function init() {
|
|||
if (mode !== "draw") initViewGlobal()
|
||||
|
||||
if (mode === "draw") {
|
||||
initDraw();
|
||||
initDraw()
|
||||
} else if (mode === "about") {
|
||||
window.location = "./about.html";
|
||||
window.location = "./about.html"
|
||||
} else if (mode === "overlap") {
|
||||
if (initOverlap) {
|
||||
initOverlap();
|
||||
initOverlap()
|
||||
}
|
||||
} else if (mode.startsWith("diff")) {
|
||||
try {
|
||||
const liveResp = await fetch("https://place-atlas.stefanocoding.me/atlas.json");
|
||||
let liveJson = await liveResp.json();
|
||||
const liveResp = await fetch("https://place-atlas.stefanocoding.me/atlas.json")
|
||||
let liveJson = await liveResp.json()
|
||||
liveJson = updateAtlasAll(liveJson)
|
||||
|
||||
const liveAtlasReduced = liveJson.reduce(function (a, c) {
|
||||
a[c.id] = c;
|
||||
return a;
|
||||
}, {});
|
||||
a[c.id] = c
|
||||
return a
|
||||
}, {})
|
||||
// Mark added/edited entries
|
||||
atlasAll = atlasAll.map(function (entry) {
|
||||
if (liveAtlasReduced[entry.id] === undefined) {
|
||||
entry.diff = "add";
|
||||
entry.diff = "add"
|
||||
} else if (JSON.stringify(entry) !== JSON.stringify(liveAtlasReduced[entry.id])) {
|
||||
entry.diff = "edit";
|
||||
entry.diff = "edit"
|
||||
}
|
||||
return entry;
|
||||
});
|
||||
return entry
|
||||
})
|
||||
|
||||
// Mark removed entries
|
||||
const atlasReduced = atlasAll.reduce(function (a, c) {
|
||||
a[c.id] = c;
|
||||
return a;
|
||||
}, {});
|
||||
a[c.id] = c
|
||||
return a
|
||||
}, {})
|
||||
const removedEntries = liveJson.filter(entry =>
|
||||
atlasReduced[entry.id] === undefined
|
||||
).map(entry => {
|
||||
|
@ -182,132 +182,132 @@ async function init() {
|
|||
if (mode.includes("only")) {
|
||||
atlasAll = atlasAll.filter(function (entry) {
|
||||
return typeof entry.diff == "string"
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.warn("Diff mode failed to load, reverting to normal view.", error);
|
||||
console.warn("Diff mode failed to load, reverting to normal view.", error)
|
||||
} finally {
|
||||
await updateTime()
|
||||
if (initOverlap && mode.includes("overlap")) {
|
||||
initOverlap();
|
||||
initOverlap()
|
||||
} else {
|
||||
initView();
|
||||
initView()
|
||||
}
|
||||
}
|
||||
} else if (mode === "explore") {
|
||||
initExplore();
|
||||
initExplore()
|
||||
} else {
|
||||
initView();
|
||||
initView()
|
||||
}
|
||||
|
||||
document.getElementById("loading").classList.add("d-none");
|
||||
document.getElementById("loading").classList.add("d-none")
|
||||
|
||||
document.getElementById("zoomInButton").addEventListener("click", function (e) {
|
||||
|
||||
/*if(zoomAnimationFrame){
|
||||
window.cancelAnimationFrame(zoomAnimationFrame);
|
||||
window.cancelAnimationFrame(zoomAnimationFrame)
|
||||
}*/
|
||||
|
||||
const x = container.clientWidth / 2;
|
||||
const y = container.clientHeight / 2;
|
||||
const x = container.clientWidth / 2
|
||||
const y = container.clientHeight / 2
|
||||
|
||||
initialPinchZoomOrigin = [
|
||||
scaleZoomOrigin[0],
|
||||
scaleZoomOrigin[1]
|
||||
];
|
||||
]
|
||||
|
||||
initialPinchZoom = zoom;
|
||||
initialPinchZoom = zoom
|
||||
|
||||
lastPosition = [x, y];
|
||||
zoom = zoom * 2;
|
||||
zoom = Math.max(minZoom, Math.min(maxZoom, zoom));
|
||||
lastPosition = [x, y]
|
||||
zoom = zoom * 2
|
||||
zoom = Math.max(minZoom, Math.min(maxZoom, zoom))
|
||||
|
||||
applyZoom(x, y, zoom);
|
||||
applyZoom(x, y, zoom)
|
||||
|
||||
});
|
||||
})
|
||||
|
||||
document.getElementById("zoomOutButton").addEventListener("click", function (e) {
|
||||
|
||||
/*if(zoomAnimationFrame){
|
||||
window.cancelAnimationFrame(zoomAnimationFrame);
|
||||
window.cancelAnimationFrame(zoomAnimationFrame)
|
||||
}*/
|
||||
|
||||
const x = container.clientWidth / 2;
|
||||
const y = container.clientHeight / 2;
|
||||
const x = container.clientWidth / 2
|
||||
const y = container.clientHeight / 2
|
||||
|
||||
initialPinchZoomOrigin = [
|
||||
scaleZoomOrigin[0],
|
||||
scaleZoomOrigin[1]
|
||||
];
|
||||
]
|
||||
|
||||
initialPinchZoom = zoom;
|
||||
initialPinchZoom = zoom
|
||||
|
||||
lastPosition = [x, y];
|
||||
zoom = zoom / 2;
|
||||
zoom = Math.max(minZoom, Math.min(maxZoom, zoom));
|
||||
lastPosition = [x, y]
|
||||
zoom = zoom / 2
|
||||
zoom = Math.max(minZoom, Math.min(maxZoom, zoom))
|
||||
|
||||
applyZoom(x, y, zoom);
|
||||
});
|
||||
applyZoom(x, y, zoom)
|
||||
})
|
||||
|
||||
document.getElementById("zoomResetButton").addEventListener("click", function (e) {
|
||||
zoom = 1;
|
||||
zoomOrigin = [0, 0];
|
||||
scaleZoomOrigin = [0, 0];
|
||||
updateLines();
|
||||
applyView();
|
||||
});
|
||||
zoom = 1
|
||||
zoomOrigin = [0, 0]
|
||||
scaleZoomOrigin = [0, 0]
|
||||
updateLines()
|
||||
applyView()
|
||||
})
|
||||
|
||||
container.addEventListener("dblclick", function (e) {
|
||||
/*if(zoomAnimationFrame){
|
||||
window.cancelAnimationFrame(zoomAnimationFrame);
|
||||
window.cancelAnimationFrame(zoomAnimationFrame)
|
||||
}*/
|
||||
|
||||
const x = e.clientX - container.offsetLeft;
|
||||
const y = e.clientY - container.offsetTop;
|
||||
const x = e.clientX - container.offsetLeft
|
||||
const y = e.clientY - container.offsetTop
|
||||
|
||||
initialPinchZoomOrigin = [
|
||||
scaleZoomOrigin[0],
|
||||
scaleZoomOrigin[1]
|
||||
];
|
||||
]
|
||||
|
||||
initialPinchZoom = zoom;
|
||||
initialPinchZoom = zoom
|
||||
|
||||
lastPosition = [x, y];
|
||||
lastPosition = [x, y]
|
||||
|
||||
if (e.ctrlKey) {
|
||||
|
||||
zoom = zoom / 2;
|
||||
zoom = zoom / 2
|
||||
|
||||
} else {
|
||||
|
||||
zoom = zoom * 2;
|
||||
zoom = zoom * 2
|
||||
}
|
||||
|
||||
zoom = Math.max(minZoom, Math.min(maxZoom, zoom));
|
||||
applyZoom(x, y, zoom);
|
||||
zoom = Math.max(minZoom, Math.min(maxZoom, zoom))
|
||||
applyZoom(x, y, zoom)
|
||||
|
||||
e.preventDefault();
|
||||
});
|
||||
e.preventDefault()
|
||||
})
|
||||
|
||||
|
||||
container.addEventListener("wheel", function (e) {
|
||||
|
||||
/*if(zoomAnimationFrame){
|
||||
window.cancelAnimationFrame(zoomAnimationFrame);
|
||||
window.cancelAnimationFrame(zoomAnimationFrame)
|
||||
}*/
|
||||
|
||||
const x = e.clientX - container.offsetLeft;
|
||||
const y = e.clientY - container.offsetTop;
|
||||
const x = e.clientX - container.offsetLeft
|
||||
const y = e.clientY - container.offsetTop
|
||||
|
||||
initialPinchZoomOrigin = [
|
||||
scaleZoomOrigin[0],
|
||||
scaleZoomOrigin[1]
|
||||
];
|
||||
]
|
||||
|
||||
initialPinchZoom = zoom;
|
||||
initialPinchZoom = zoom
|
||||
|
||||
lastPosition = [x, y];
|
||||
lastPosition = [x, y]
|
||||
|
||||
// Check if we are zooming by pixels
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent/deltaMode
|
||||
|
@ -315,146 +315,146 @@ async function init() {
|
|||
// Scale the pixel delta by the current zoom factor
|
||||
// We want to zoom faster when closer, and slower when further
|
||||
// This creates a smoother experience
|
||||
zoom -= e.deltaY * (0.001 * zoom);
|
||||
zoom -= e.deltaY * (0.001 * zoom)
|
||||
} else {
|
||||
if (e.deltaY > 0) {
|
||||
|
||||
zoom = zoom / 2;
|
||||
zoom = zoom / 2
|
||||
|
||||
} else if (e.deltaY < 0) {
|
||||
|
||||
zoom = zoom * 2;
|
||||
zoom = zoom * 2
|
||||
}
|
||||
}
|
||||
|
||||
zoom = Math.max(minZoom, Math.min(maxZoom, zoom));
|
||||
applyZoom(x, y, zoom);
|
||||
zoom = Math.max(minZoom, Math.min(maxZoom, zoom))
|
||||
applyZoom(x, y, zoom)
|
||||
|
||||
e.preventDefault();
|
||||
}, { passive: true });
|
||||
e.preventDefault()
|
||||
}, { passive: true })
|
||||
|
||||
/*function setDesiredZoom(x, y, target){
|
||||
zoom = (zoom*2 + target)/3;
|
||||
//console.log(zoom);
|
||||
zoom = (zoom*2 + target)/3
|
||||
//console.log(zoom)
|
||||
if(Math.abs(1 - zoom/target) <= 0.01){
|
||||
zoom = target;
|
||||
zoom = target
|
||||
}
|
||||
applyZoom(x, y, zoom);
|
||||
applyZoom(x, y, zoom)
|
||||
if(zoom != target){
|
||||
zoomAnimationFrame = window.requestAnimationFrame(function(){
|
||||
setDesiredZoom(x, y, target);
|
||||
});
|
||||
setDesiredZoom(x, y, target)
|
||||
})
|
||||
}
|
||||
}*/
|
||||
|
||||
container.addEventListener("mousedown", function (e) {
|
||||
mousedown(e.clientX, e.clientY);
|
||||
e.preventDefault();
|
||||
});
|
||||
mousedown(e.clientX, e.clientY)
|
||||
e.preventDefault()
|
||||
})
|
||||
|
||||
container.addEventListener("touchstart", function (e) {
|
||||
|
||||
if (e.touches.length == 2) {
|
||||
e.preventDefault();
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
touchstart(e);
|
||||
touchstart(e)
|
||||
|
||||
}, { passive: true });
|
||||
}, { passive: true })
|
||||
|
||||
function mousedown(x, y) {
|
||||
lastPosition = [x, y];
|
||||
dragging = true;
|
||||
lastPosition = [x, y]
|
||||
dragging = true
|
||||
}
|
||||
|
||||
function touchstart(e) {
|
||||
|
||||
if (e.touches.length == 1) {
|
||||
|
||||
mousedown(e.touches[0].clientX, e.touches[0].clientY);
|
||||
mousedown(e.touches[0].clientX, e.touches[0].clientY)
|
||||
|
||||
} else if (e.touches.length == 2) {
|
||||
|
||||
initialPinchDistance = Math.sqrt(
|
||||
Math.pow(e.touches[0].clientX - e.touches[1].clientX, 2)
|
||||
+ Math.pow(e.touches[0].clientY - e.touches[1].clientY, 2)
|
||||
);
|
||||
)
|
||||
|
||||
initialPinchZoom = zoom;
|
||||
initialPinchZoom = zoom
|
||||
initialPinchZoomOrigin = [
|
||||
scaleZoomOrigin[0],
|
||||
scaleZoomOrigin[1]
|
||||
];
|
||||
]
|
||||
|
||||
mousedown(
|
||||
(e.touches[0].clientX + e.touches[1].clientX) / 2,
|
||||
(e.touches[0].clientY + e.touches[1].clientY) / 2
|
||||
);
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
window.addEventListener("mousemove", function (e) {
|
||||
updateLines();
|
||||
mousemove(e.clientX, e.clientY);
|
||||
updateLines()
|
||||
mousemove(e.clientX, e.clientY)
|
||||
if (dragging) {
|
||||
e.preventDefault();
|
||||
e.preventDefault()
|
||||
}
|
||||
});
|
||||
})
|
||||
window.addEventListener("touchmove", function (e) {
|
||||
|
||||
if (e.touches.length == 2 || e.scale > 1) {
|
||||
e.preventDefault();
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
touchmove(e);
|
||||
touchmove(e)
|
||||
|
||||
},
|
||||
{ passive: false }
|
||||
);
|
||||
)
|
||||
|
||||
function mousemove(x, y) {
|
||||
if (dragging) {
|
||||
const deltaX = x - lastPosition[0];
|
||||
const deltaY = y - lastPosition[1];
|
||||
lastPosition = [x, y];
|
||||
const deltaX = x - lastPosition[0]
|
||||
const deltaY = y - lastPosition[1]
|
||||
lastPosition = [x, y]
|
||||
|
||||
zoomOrigin[0] += deltaX;
|
||||
zoomOrigin[1] += deltaY;
|
||||
zoomOrigin[0] += deltaX
|
||||
zoomOrigin[1] += deltaY
|
||||
|
||||
scaleZoomOrigin[0] += deltaX / zoom;
|
||||
scaleZoomOrigin[1] += deltaY / zoom;
|
||||
scaleZoomOrigin[0] += deltaX / zoom
|
||||
scaleZoomOrigin[1] += deltaY / zoom
|
||||
|
||||
previousZoomOrigin = [zoomOrigin[0], zoomOrigin[1]];
|
||||
previousScaleZoomOrigin = [scaleZoomOrigin[0], scaleZoomOrigin[1]];
|
||||
previousZoomOrigin = [zoomOrigin[0], zoomOrigin[1]]
|
||||
previousScaleZoomOrigin = [scaleZoomOrigin[0], scaleZoomOrigin[1]]
|
||||
|
||||
updateLines();
|
||||
applyView();
|
||||
updateLines()
|
||||
applyView()
|
||||
}
|
||||
}
|
||||
|
||||
function touchmove(e) {
|
||||
|
||||
updateLines();
|
||||
updateLines()
|
||||
|
||||
if (e.touches.length == 1) {
|
||||
|
||||
mousemove(e.touches[0].clientX, e.touches[0].clientY);
|
||||
mousemove(e.touches[0].clientX, e.touches[0].clientY)
|
||||
|
||||
} else if (e.touches.length == 2) {
|
||||
|
||||
const newPinchDistance = Math.sqrt(
|
||||
Math.pow(e.touches[0].clientX - e.touches[1].clientX, 2)
|
||||
+ Math.pow(e.touches[0].clientY - e.touches[1].clientY, 2)
|
||||
);
|
||||
)
|
||||
|
||||
zoom = initialPinchZoom * newPinchDistance / initialPinchDistance;
|
||||
zoom = initialPinchZoom * newPinchDistance / initialPinchDistance
|
||||
|
||||
const x = (e.touches[0].clientX + e.touches[1].clientX) / 2 - container.offsetLeft;
|
||||
const y = (e.touches[0].clientY + e.touches[1].clientY) / 2 - container.offsetTop;
|
||||
const x = (e.touches[0].clientX + e.touches[1].clientX) / 2 - container.offsetLeft
|
||||
const y = (e.touches[0].clientY + e.touches[1].clientY) / 2 - container.offsetTop
|
||||
|
||||
applyZoom(x, y, zoom);
|
||||
applyZoom(x, y, zoom)
|
||||
|
||||
}
|
||||
|
||||
|
@ -462,33 +462,33 @@ async function init() {
|
|||
|
||||
function applyZoom(x, y, zoom) {
|
||||
|
||||
const deltaX = x - lastPosition[0];
|
||||
const deltaY = y - lastPosition[1];
|
||||
const deltaX = x - lastPosition[0]
|
||||
const deltaY = y - lastPosition[1]
|
||||
|
||||
const pinchTranslateX = (x - container.clientWidth / 2 - deltaX);
|
||||
const pinchTranslateY = (y - container.clientHeight / 2 - deltaY);
|
||||
const pinchTranslateX = (x - container.clientWidth / 2 - deltaX)
|
||||
const pinchTranslateY = (y - container.clientHeight / 2 - deltaY)
|
||||
|
||||
scaleZoomOrigin[0] = initialPinchZoomOrigin[0] + deltaX / zoom + pinchTranslateX / zoom - pinchTranslateX / initialPinchZoom;
|
||||
scaleZoomOrigin[1] = initialPinchZoomOrigin[1] + deltaY / zoom + pinchTranslateY / zoom - pinchTranslateY / initialPinchZoom;
|
||||
scaleZoomOrigin[0] = initialPinchZoomOrigin[0] + deltaX / zoom + pinchTranslateX / zoom - pinchTranslateX / initialPinchZoom
|
||||
scaleZoomOrigin[1] = initialPinchZoomOrigin[1] + deltaY / zoom + pinchTranslateY / zoom - pinchTranslateY / initialPinchZoom
|
||||
|
||||
zoomOrigin[0] = scaleZoomOrigin[0] * zoom;
|
||||
zoomOrigin[1] = scaleZoomOrigin[1] * zoom;
|
||||
zoomOrigin[0] = scaleZoomOrigin[0] * zoom
|
||||
zoomOrigin[1] = scaleZoomOrigin[1] * zoom
|
||||
|
||||
applyView();
|
||||
updateLines();
|
||||
applyView()
|
||||
updateLines()
|
||||
}
|
||||
|
||||
window.addEventListener("mouseup", function (e) {
|
||||
if (dragging) {
|
||||
e.preventDefault();
|
||||
e.preventDefault()
|
||||
}
|
||||
mouseup(e.clientX, e.clientY);
|
||||
});
|
||||
window.addEventListener("touchend", touchend);
|
||||
mouseup(e.clientX, e.clientY)
|
||||
})
|
||||
window.addEventListener("touchend", touchend)
|
||||
|
||||
function mouseup(x, y) {
|
||||
if (dragging) {
|
||||
dragging = false;
|
||||
dragging = false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -496,20 +496,20 @@ async function init() {
|
|||
|
||||
if (e.touches.length == 0) {
|
||||
|
||||
mouseup();
|
||||
mouseup()
|
||||
|
||||
} else if (e.touches.length == 1) {
|
||||
initialPinchZoom = zoom;
|
||||
lastPosition = [e.touches[0].clientX, e.touches[0].clientY];
|
||||
initialPinchZoom = zoom
|
||||
lastPosition = [e.touches[0].clientX, e.touches[0].clientY]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
window.addEventListener("resize", function () {
|
||||
//console.log(document.documentElement.clientWidth, document.documentElement.clientHeight);
|
||||
//console.log(document.documentElement.clientWidth, document.documentElement.clientHeight)
|
||||
|
||||
applyView();
|
||||
});
|
||||
applyView()
|
||||
})
|
||||
|
||||
document.body.dataset.initDone = ''
|
||||
|
||||
|
|
|
@ -17,66 +17,66 @@ function initOverlap() {
|
|||
|
||||
window.renderBackground = renderBackground
|
||||
|
||||
const hovered = [];
|
||||
const hovered = []
|
||||
|
||||
buildObjectsList(null, null);
|
||||
renderBackground(atlas);
|
||||
render();
|
||||
buildObjectsList(null, null)
|
||||
renderBackground(atlas)
|
||||
render()
|
||||
|
||||
document.addEventListener('timeupdate', (event) => {
|
||||
sortedAtlas = atlas.concat()
|
||||
resetEntriesList(null, null)
|
||||
renderBackground(sortedAtlas);
|
||||
render();
|
||||
renderBackground(sortedAtlas)
|
||||
render()
|
||||
})
|
||||
|
||||
applyView();
|
||||
render();
|
||||
updateLines();
|
||||
applyView()
|
||||
render()
|
||||
updateLines()
|
||||
|
||||
if (window.location.hash) {
|
||||
highlightEntryFromUrl();
|
||||
highlightEntryFromUrl()
|
||||
}
|
||||
|
||||
function renderBackground(atlas) {
|
||||
|
||||
backgroundContext.clearRect(0, 0, canvas.width, canvas.height);
|
||||
backgroundContext.clearRect(0, 0, canvas.width, canvas.height)
|
||||
|
||||
backgroundContext.fillStyle = "rgba(255, 255, 255, 1)";
|
||||
backgroundContext.fillRect(0, 0, canvas.width, canvas.height);
|
||||
backgroundContext.fillStyle = "rgba(255, 255, 255, 1)"
|
||||
backgroundContext.fillRect(0, 0, canvas.width, canvas.height)
|
||||
|
||||
for (let i = 0; i < atlas.length; i++) {
|
||||
|
||||
const path = atlas[i].path;
|
||||
const path = atlas[i].path
|
||||
|
||||
backgroundContext.beginPath();
|
||||
backgroundContext.beginPath()
|
||||
|
||||
if (path[0]) {
|
||||
backgroundContext.moveTo(path[0][0], path[0][1]);
|
||||
backgroundContext.moveTo(path[0][0], path[0][1])
|
||||
}
|
||||
|
||||
for (let p = 1; p < path.length; p++) {
|
||||
backgroundContext.lineTo(path[p][0], path[p][1]);
|
||||
backgroundContext.lineTo(path[p][0], path[p][1])
|
||||
}
|
||||
|
||||
backgroundContext.closePath();
|
||||
backgroundContext.closePath()
|
||||
|
||||
backgroundContext.fillStyle = "rgba(0, 0, 255, 0.2)";
|
||||
backgroundContext.fill();
|
||||
backgroundContext.fillStyle = "rgba(0, 0, 255, 0.2)"
|
||||
backgroundContext.fill()
|
||||
}
|
||||
|
||||
const pixels = backgroundContext.getImageData(0, 0, backgroundCanvas.width, backgroundCanvas.height).data;
|
||||
let blank = 0;
|
||||
const pixels = backgroundContext.getImageData(0, 0, backgroundCanvas.width, backgroundCanvas.height).data
|
||||
let blank = 0
|
||||
|
||||
for (let i = 0; i < pixels.length; i += 4) {
|
||||
if (pixels[i] == 255) {
|
||||
blank++;
|
||||
blank++
|
||||
}
|
||||
}
|
||||
|
||||
const blankPercentage = (blank / (2000 * 2000)) * 100
|
||||
|
||||
console.info(blank + " blank pixels, which are " + blankPercentage.toPrecision(4) + "% of the canvas (" + (100 - blankPercentage).toPrecision(4) + "% mapped)");
|
||||
console.info(blank + " blank pixels, which are " + blankPercentage.toPrecision(4) + "% of the canvas (" + (100 - blankPercentage).toPrecision(4) + "% mapped)")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
216
web/_js/stats.js
216
web/_js/stats.js
|
@ -13,190 +13,190 @@
|
|||
========================================================================
|
||||
*/
|
||||
|
||||
let areasSum = 0;
|
||||
const areas = [];
|
||||
let areasSum = 0
|
||||
const areas = []
|
||||
|
||||
for (let q = 0; q < atlas.length; q++) {
|
||||
|
||||
const path = atlas[q].path;
|
||||
const path = atlas[q].path
|
||||
|
||||
let area = 0,
|
||||
i,
|
||||
j,
|
||||
point1,
|
||||
point2;
|
||||
point2
|
||||
|
||||
for (i = 0, j = path.length - 1; i < path.length; j = i, i++) {
|
||||
point1 = path[i];
|
||||
point2 = path[j];
|
||||
area += point1[0] * point2[1];
|
||||
area -= point1[1] * point2[0];
|
||||
point1 = path[i]
|
||||
point2 = path[j]
|
||||
area += point1[0] * point2[1]
|
||||
area -= point1[1] * point2[0]
|
||||
}
|
||||
|
||||
area = Math.abs(area / 2);
|
||||
area = Math.abs(area / 2)
|
||||
|
||||
areasSum += area;
|
||||
areas.push(area);
|
||||
areasSum += area
|
||||
areas.push(area)
|
||||
|
||||
atlas[q].area = area;
|
||||
atlas[q].area = area
|
||||
|
||||
}
|
||||
|
||||
areas.sort(function (a, b) {
|
||||
if (a < b) {
|
||||
return -1;
|
||||
return -1
|
||||
}
|
||||
if (a > b) {
|
||||
return 1;
|
||||
return 1
|
||||
}
|
||||
// a must be equal to b
|
||||
return 0;
|
||||
});
|
||||
return 0
|
||||
})
|
||||
|
||||
atlas.sort(function (a, b) {
|
||||
if (a.area < b.area) {
|
||||
return -1;
|
||||
return -1
|
||||
}
|
||||
if (a.area > b.area) {
|
||||
return 1;
|
||||
return 1
|
||||
}
|
||||
// a must be equal to b
|
||||
return 0;
|
||||
});
|
||||
return 0
|
||||
})
|
||||
|
||||
const el = document.createElement("canvas");
|
||||
el.style.position = "absolute";
|
||||
el.style.top = "0px";
|
||||
el.style.zIndex = "10000";
|
||||
const ctx = el.getContext("2d");
|
||||
el.width = 1600;
|
||||
el.height = 500;
|
||||
const steps = 150;
|
||||
const max = 1500;
|
||||
const el = document.createElement("canvas")
|
||||
el.style.position = "absolute"
|
||||
el.style.top = "0px"
|
||||
el.style.zIndex = "10000"
|
||||
const ctx = el.getContext("2d")
|
||||
el.width = 1600
|
||||
el.height = 500
|
||||
const steps = 150
|
||||
const max = 1500
|
||||
|
||||
let largerThanMax = 0;
|
||||
let largerThanMax = 0
|
||||
|
||||
for (const i in areas) {
|
||||
if (areas[i] > max) {
|
||||
largerThanMax++;
|
||||
largerThanMax++
|
||||
}
|
||||
}
|
||||
|
||||
console.info("There are " + largerThanMax + " entries larger than " + max + ", accounting for " + (largerThanMax / areas.length * 100) + "% of all entries.");
|
||||
console.info("The largest entry has an area of " + areas[areas.length - 1] + " pixels.");
|
||||
console.info("There are " + largerThanMax + " entries larger than " + max + ", accounting for " + (largerThanMax / areas.length * 100) + "% of all entries.")
|
||||
console.info("The largest entry has an area of " + areas[areas.length - 1] + " pixels.")
|
||||
|
||||
const counts = [0];
|
||||
const brackets = [max / steps];
|
||||
const counts = [0]
|
||||
const brackets = [max / steps]
|
||||
|
||||
let bracket = 0;
|
||||
let bracket = 0
|
||||
|
||||
let mostCounts = 0;
|
||||
let mostCounts = 0
|
||||
|
||||
for (const i in areas) {
|
||||
if (areas[i] > (bracket + 1) * (max / steps)) {
|
||||
mostCounts = Math.max(mostCounts, counts[bracket]);
|
||||
bracket++;
|
||||
mostCounts = Math.max(mostCounts, counts[bracket])
|
||||
bracket++
|
||||
if (bracket >= steps) {
|
||||
break;
|
||||
break
|
||||
}
|
||||
counts[bracket] = 0;
|
||||
brackets[bracket] = (bracket + 1) * (max / steps);
|
||||
counts[bracket] = 0
|
||||
brackets[bracket] = (bracket + 1) * (max / steps)
|
||||
}
|
||||
counts[bracket]++;
|
||||
counts[bracket]++
|
||||
}
|
||||
//console.log(counts);
|
||||
//console.log(brackets);
|
||||
//console.log(mostCounts);
|
||||
//console.log(counts)
|
||||
//console.log(brackets)
|
||||
//console.log(mostCounts)
|
||||
|
||||
ctx.fillStyle = "#FFFFFF";
|
||||
ctx.fillRect(0, 0, el.width, el.height);
|
||||
ctx.strokeStyle = "#F5F5F5";
|
||||
ctx.fillStyle = "#FFFFFF"
|
||||
ctx.fillRect(0, 0, el.width, el.height)
|
||||
ctx.strokeStyle = "#F5F5F5"
|
||||
|
||||
ctx.fillStyle = "#333333";
|
||||
ctx.font = "15px sans";
|
||||
ctx.textAlign = "right";
|
||||
ctx.textBaseline = "middle";
|
||||
ctx.fillStyle = "#333333"
|
||||
ctx.font = "15px sans"
|
||||
ctx.textAlign = "right"
|
||||
ctx.textBaseline = "middle"
|
||||
|
||||
let linesDistance = 1;
|
||||
let linesDistance = 1
|
||||
|
||||
for (let i = 0; i <= Math.ceil((mostCounts / linesDistance) / 5) * 5; i++) {
|
||||
ctx.beginPath();
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(
|
||||
50
|
||||
, ~~(el.height - 50 - i * (linesDistance / mostCounts) * (el.height - 100)) + 0.5
|
||||
);
|
||||
)
|
||||
ctx.lineTo(
|
||||
el.width - 25
|
||||
, ~~(el.height - 50 - i * (linesDistance / mostCounts) * (el.height - 100)) + 0.5
|
||||
);
|
||||
ctx.stroke();
|
||||
)
|
||||
ctx.stroke()
|
||||
}
|
||||
|
||||
ctx.strokeStyle = "#333333";
|
||||
linesDistance = 5;
|
||||
ctx.strokeStyle = "#333333"
|
||||
linesDistance = 5
|
||||
|
||||
for (let i = 0; i <= Math.ceil(mostCounts / linesDistance); i++) {
|
||||
ctx.beginPath();
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(
|
||||
50
|
||||
, ~~(el.height - 50 - i * (linesDistance / mostCounts) * (el.height - 100)) + 0.5
|
||||
);
|
||||
)
|
||||
ctx.lineTo(
|
||||
el.width - 25
|
||||
, ~~(el.height - 50 - i * (linesDistance / mostCounts) * (el.height - 100)) + 0.5
|
||||
);
|
||||
ctx.stroke();
|
||||
)
|
||||
ctx.stroke()
|
||||
|
||||
ctx.fillText(
|
||||
i * linesDistance
|
||||
, 40
|
||||
, ~~(el.height - 50 - i * (linesDistance / mostCounts) * (el.height - 100)) + 0.5
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
const skip = 2;
|
||||
const skip = 2
|
||||
|
||||
ctx.textAlign = "center";
|
||||
ctx.textBaseline = "hanging";
|
||||
ctx.font = "10px sans";
|
||||
ctx.textAlign = "center"
|
||||
ctx.textBaseline = "hanging"
|
||||
ctx.font = "10px sans"
|
||||
|
||||
let a = 0;
|
||||
let a = 0
|
||||
for (let i = 0; i <= counts.length; i++) {
|
||||
if (i % skip == 0) {
|
||||
let y = 0;
|
||||
let y = 0
|
||||
if (a % 2 == 0) {
|
||||
y = ~~(el.height - 30) + 0.5;
|
||||
y = ~~(el.height - 30) + 0.5
|
||||
} else {
|
||||
y = ~~(el.height - 45) + 0.5;
|
||||
y = ~~(el.height - 45) + 0.5
|
||||
}
|
||||
a++;
|
||||
ctx.beginPath();
|
||||
a++
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(
|
||||
~~(((i) / steps) * (el.width - 125) + 75) + 0.5
|
||||
, ~~(el.height - 50) + 0.5
|
||||
);
|
||||
)
|
||||
ctx.lineTo(
|
||||
~~(((i) / steps) * (el.width - 125) + 75) + 0.5
|
||||
, y
|
||||
);
|
||||
ctx.stroke();
|
||||
)
|
||||
ctx.stroke()
|
||||
|
||||
ctx.fillText(
|
||||
(i) * (max / steps)
|
||||
, ~~(((i) / steps) * (el.width - 125) + 75) - 0.5
|
||||
, y + 5
|
||||
);
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ctx.fillStyle = "#FF0000";
|
||||
ctx.strokeStyle = "#CC0000";
|
||||
ctx.fillStyle = "#FF0000"
|
||||
ctx.strokeStyle = "#CC0000"
|
||||
|
||||
for (let i = 0; i < counts.length; i++) {
|
||||
if (i % 2 == 0) {
|
||||
ctx.fillStyle = "#FF0000";
|
||||
ctx.fillStyle = "#FF0000"
|
||||
} else {
|
||||
ctx.fillStyle = "#DD0000";
|
||||
ctx.fillStyle = "#DD0000"
|
||||
}
|
||||
|
||||
ctx.fillRect(
|
||||
|
@ -204,72 +204,72 @@ for (let i = 0; i < counts.length; i++) {
|
|||
, el.height - 50
|
||||
, Math.ceil(1 / steps * (el.width - 125))
|
||||
, ~~(-(counts[i] / mostCounts) * (el.height - 100))
|
||||
);
|
||||
)
|
||||
|
||||
/*ctx.beginPath();
|
||||
/*ctx.beginPath()
|
||||
ctx.moveTo(
|
||||
~~((i/steps)*(el.width-125)+75)+0.5
|
||||
,~~(el.height - 50)
|
||||
);
|
||||
)
|
||||
ctx.lineTo(
|
||||
~~((i/steps)*(el.width-125)+75)+0.5
|
||||
,~~(el.height-(counts[i]/mostCounts)*(el.height-100))-50+0.5
|
||||
);
|
||||
)
|
||||
ctx.lineTo(
|
||||
~~(((i+1)/steps)*(el.width-125)+75)+0.5
|
||||
,~~(el.height-(counts[i]/mostCounts)*(el.height-100))-50+0.5
|
||||
);
|
||||
)
|
||||
ctx.lineTo(
|
||||
~~(((i+1)/steps)*(el.width-125)+75)+0.5
|
||||
,~~(el.height - 50)
|
||||
);
|
||||
)
|
||||
ctx.stroke();*/
|
||||
}
|
||||
|
||||
document.getElementById("wrapper").appendChild(el);
|
||||
document.getElementById("wrapper").appendChild(el)
|
||||
|
||||
//console.log(areas);
|
||||
//console.log(areas)
|
||||
|
||||
console.info("Median area: " + areas[~~(areas.length / 2)]);
|
||||
console.info("Median area: " + areas[~~(areas.length / 2)])
|
||||
|
||||
console.info("Average area: " + (areasSum / atlas.length));
|
||||
console.info("Average area: " + (areasSum / atlas.length))
|
||||
|
||||
const topCount = 50;
|
||||
console.info("The " + topCount + " largest entries:");
|
||||
const topCount = 50
|
||||
console.info("The " + topCount + " largest entries:")
|
||||
|
||||
let outstring = "";
|
||||
let outstring = ""
|
||||
|
||||
for (let i = 0; i < topCount; i++) {
|
||||
outstring += ((i + 1) + "|[" + atlas[atlas.length - i - 1].name + "](http://place-atlas.stefanocoding.me/?id=" + atlas[atlas.length - i - 1].id + ")|" + ~~atlas[atlas.length - i - 1].area + "|" + Math.round(atlas[atlas.length - i - 1].area / 100) / 100 + "%\n");
|
||||
outstring += ((i + 1) + "|[" + atlas[atlas.length - i - 1].name + "](http://place-atlas.stefanocoding.me/?id=" + atlas[atlas.length - i - 1].id + ")|" + ~~atlas[atlas.length - i - 1].area + "|" + Math.round(atlas[atlas.length - i - 1].area / 100) / 100 + "%\n")
|
||||
}
|
||||
|
||||
console.info(outstring);
|
||||
console.info(outstring)
|
||||
|
||||
atlas.sort(function (a, b) {
|
||||
if (a.center[0] < b.center[0]) {
|
||||
return -1;
|
||||
return -1
|
||||
}
|
||||
if (a.center[0] > b.center[0]) {
|
||||
return 1;
|
||||
return 1
|
||||
}
|
||||
// a must be equal to b
|
||||
return 0;
|
||||
});
|
||||
return 0
|
||||
})
|
||||
|
||||
console.info("Median x: " + atlas[~~(atlas.length / 2)].center[0]);
|
||||
console.info("Median x: " + atlas[~~(atlas.length / 2)].center[0])
|
||||
|
||||
atlas.sort(function (a, b) {
|
||||
if (a.center[1] < b.center[1]) {
|
||||
return -1;
|
||||
return -1
|
||||
}
|
||||
if (a.center[1] > b.center[1]) {
|
||||
return 1;
|
||||
return 1
|
||||
}
|
||||
// a must be equal to b
|
||||
return 0;
|
||||
});
|
||||
return 0
|
||||
})
|
||||
|
||||
console.info("Median y: " + atlas[~~(atlas.length / 2)].center[1]);
|
||||
console.info("Median y: " + atlas[~~(atlas.length / 2)].center[1])
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -64,10 +64,10 @@ for (const variation in variationsConfig) {
|
|||
variantsEl.appendChild(optionEl)
|
||||
}
|
||||
|
||||
const timelineSlider = document.getElementById("timeControlsSlider");
|
||||
const timelineList = document.getElementById("timeControlsList");
|
||||
const tooltip = document.getElementById("timeControlsTooltip");
|
||||
const image = document.getElementById("image");
|
||||
const timelineSlider = document.getElementById("timeControlsSlider")
|
||||
const timelineList = document.getElementById("timeControlsList")
|
||||
const tooltip = document.getElementById("timeControlsTooltip")
|
||||
const image = document.getElementById("image")
|
||||
let abortController = new AbortController()
|
||||
let currentUpdateIndex = 0
|
||||
let updateTimeout = setTimeout(null, 0)
|
||||
|
@ -81,9 +81,9 @@ window.currentPeriod = currentPeriod
|
|||
window.currentVariation = currentVariation
|
||||
|
||||
// SETUP
|
||||
timelineSlider.max = variationsConfig[currentVariation].versions.length - 1;
|
||||
timelineSlider.value = currentPeriod;
|
||||
timelineList.children[0].value = defaultPeriod;
|
||||
timelineSlider.max = variationsConfig[currentVariation].versions.length - 1
|
||||
timelineSlider.value = currentPeriod
|
||||
timelineList.children[0].value = defaultPeriod
|
||||
|
||||
timelineSlider.addEventListener("input", (event) => {
|
||||
updateTooltip(parseInt(event.target.value), currentVariation)
|
||||
|
@ -108,8 +108,8 @@ const dispatchTimeUpdateEvent = (period = timelineSlider.value, atlas = atlas) =
|
|||
period: period,
|
||||
atlas: atlas
|
||||
}
|
||||
});
|
||||
document.dispatchEvent(timeUpdateEvent);
|
||||
})
|
||||
document.dispatchEvent(timeUpdateEvent)
|
||||
}
|
||||
|
||||
async function updateBackground(newPeriod = currentPeriod, newVariation = currentVariation) {
|
||||
|
@ -120,14 +120,14 @@ async function updateBackground(newPeriod = currentPeriod, newVariation = curren
|
|||
const variationConfig = variationsConfig[newVariation]
|
||||
|
||||
variantsEl.value = currentVariation
|
||||
variantsEl.previousElementSibling.innerHTML = variationConfig.icon;
|
||||
variantsEl.previousElementSibling.innerHTML = variationConfig.icon
|
||||
|
||||
const configObject = variationConfig.versions[currentPeriod];
|
||||
const configObject = variationConfig.versions[currentPeriod]
|
||||
if (typeof configObject.url === "string") {
|
||||
if (imageCache[configObject.url] === undefined) {
|
||||
const fetchResult = await fetch(configObject.url, {
|
||||
signal: abortController.signal
|
||||
});
|
||||
})
|
||||
if (currentUpdateIndex !== myUpdateIndex) {
|
||||
return [configObject, newPeriod, newVariation]
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ async function updateBackground(newPeriod = currentPeriod, newVariation = curren
|
|||
if (imageCache[url] === undefined) {
|
||||
const fetchResult = await fetch(url, {
|
||||
signal: abortController.signal
|
||||
});
|
||||
})
|
||||
if (currentUpdateIndex !== myUpdateIndex) {
|
||||
return
|
||||
}
|
||||
|
@ -181,13 +181,13 @@ async function updateTime(newPeriod = currentPeriod, newVariation = currentVaria
|
|||
currentPeriod = newPeriod
|
||||
if (currentVariation !== newVariation) {
|
||||
currentVariation = newVariation
|
||||
timelineSlider.max = variationConfig.versions.length - 1;
|
||||
timelineSlider.max = variationConfig.versions.length - 1
|
||||
if (!forcePeriod) {
|
||||
currentPeriod = variationConfig.default;
|
||||
currentPeriod = variationConfig.default
|
||||
newPeriod = currentPeriod
|
||||
}
|
||||
if (variationConfig.versions.length === 1) document.getElementById("bottomBar").classList.add('no-time-slider');
|
||||
else document.getElementById("bottomBar").classList.remove('no-time-slider');
|
||||
if (variationConfig.versions.length === 1) document.getElementById("bottomBar").classList.add('no-time-slider')
|
||||
else document.getElementById("bottomBar").classList.remove('no-time-slider')
|
||||
}
|
||||
timelineSlider.value = currentPeriod
|
||||
updateTooltip(newPeriod, newVariation)
|
||||
|
@ -240,13 +240,13 @@ function updateTooltip(newPeriod, newVariation) {
|
|||
|
||||
// If timestap is a number return a UTC formatted date otherwise use exact timestap label
|
||||
if (typeof configObject.timestamp === "number") tooltip.querySelector('div').textContent = new Date(configObject.timestamp * 1000).toUTCString()
|
||||
else tooltip.querySelector('div').textContent = configObject.timestamp;
|
||||
else tooltip.querySelector('div').textContent = configObject.timestamp
|
||||
|
||||
// Clamps position of tooltip to prevent from going off screen
|
||||
const timelineSliderRect = timelineSlider.getBoundingClientRect();
|
||||
let min = -timelineSliderRect.left+12;
|
||||
let max = (window.innerWidth-tooltip.offsetWidth)-timelineSliderRect.left+4;
|
||||
tooltip.style.left = Math.min(Math.max((timelineSlider.offsetWidth)*(timelineSlider.value)/(timelineSlider.max)-tooltip.offsetWidth/2, min), max) + "px";
|
||||
const timelineSliderRect = timelineSlider.getBoundingClientRect()
|
||||
let min = -timelineSliderRect.left + 12
|
||||
let max = (window.innerWidth - tooltip.offsetWidth) - timelineSliderRect.left + 4
|
||||
tooltip.style.left = Math.min(Math.max((timelineSlider.offsetWidth) * (timelineSlider.value) / (timelineSlider.max) - tooltip.offsetWidth / 2, min), max) + "px"
|
||||
}
|
||||
|
||||
tooltip.parentElement.addEventListener('mouseenter', () => updateTooltip(parseInt(timelineSlider.value), currentVariation))
|
||||
|
|
792
web/_js/view.js
792
web/_js/view.js
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue