Merge pull request #1334 from mxdanger/interface

This commit is contained in:
Hans5958 2022-04-28 17:28:30 +07:00 committed by GitHub
commit f40804df31
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 1394 additions and 1835 deletions

View file

@ -6,9 +6,9 @@
[![Subreddit subscribers](https://img.shields.io/reddit/subreddit-subscribers/placeAtlas2?color=%23FF4500&label=r%2FplaceAtlas2&logo=reddit&logoColor=white)](https://www.reddit.com/r/placeAtlas2/) [![Subreddit subscribers](https://img.shields.io/reddit/subreddit-subscribers/placeAtlas2?color=%23FF4500&label=r%2FplaceAtlas2&logo=reddit&logoColor=white)](https://www.reddit.com/r/placeAtlas2/)
[![Website](https://img.shields.io/static/v1?label=website&message=place-atlas.stefanocoding.me&color=blue)](https://place-atlas.stefanocoding.me/) [![Website](https://img.shields.io/static/v1?label=website&message=place-atlas.stefanocoding.me&color=blue)](https://place-atlas.stefanocoding.me/)
# The 2022 /r/place Atlas # The 2022 r/place Atlas
The 2022 /r/place Atlas is a project aiming to catalog all the artworks created during Reddit's 2022 /r/place event. The 2022 r/place Atlas is a project aiming to catalog all the artworks created during Reddit's 2022 r/place event.
This project was established by Roland Rytz for the event in 2017, and further developed by Place Atlas team and contributors. This project was established by Roland Rytz for the event in 2017, and further developed by Place Atlas team and contributors.
@ -16,7 +16,7 @@ This project is licensed under the GNU Affero General Public License v3.0.
You can check out the website by clicking [here](https://place-atlas.stefanocoding.me/). You can check out the website by clicking [here](https://place-atlas.stefanocoding.me/).
If you don't know GitHub and wanted to submit new entries or request changes to existing ones, please visit [/r/placeAtlas2](https://www.reddit.com/r/placeAtlas2/). If you don't know GitHub and wanted to submit new entries or request changes to existing ones, please visit [r/placeAtlas2](https://www.reddit.com/r/placeAtlas2/).
## Contributing ## Contributing

File diff suppressed because it is too large Load diff

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><defs><style>.cls-1{fill:#fff;}.cls-2{fill:#ff4500;}</style></defs><rect class="cls-1" width="512" height="512"/><polygon class="cls-2" points="364 76 364 148 148 148 148 436 76 436 76 76 364 76"/><polygon class="cls-2" points="436 148 436 436 220 436 220 364 364 364 364 148 436 148"/><polygon class="cls-2" points="364 148 205 205 307 307 364 148"/><polygon points="205 205 148 364 307 307 205 205"/></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><defs><style>.cls-1{fill:#000;}.cls-2{fill:#ff4500;}@media (prefers-color-scheme:dark){.cls-1 {fill: #fff;}</style></defs><polygon class="cls-2" points="364 76 364 148 148 148 148 436 76 436 76 76 364 76"/><polygon class="cls-2" points="436 148 436 436 220 436 220 364 364 364 364 148 436 148"/><polygon class="cls-2" points="364 148 205 205 307 307 364 148"/><polygon class="cls-1" points="205 205 148 364 307 307 205 205"/></svg>

Before

Width:  |  Height:  |  Size: 470 B

After

Width:  |  Height:  |  Size: 493 B

1
web/_img/place-logo.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 192 192"><polygon points="154 0 154 38 39 38 39 192 0 192 0 0"/><polygon points="192 38 192 192 77 192 77 153 154 153 154 38"/><rect x="77" y="77" width="38" height="38"/></svg>

After

Width:  |  Height:  |  Size: 273 B

1
web/_img/tfc-logo.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 192 192"><defs><style>.a{fill-rule:evenodd;}</style></defs><path class="a" d="M69.79,83.55c-.47,.65-.59,1.35-.59,1.35-.26,1.47,.76,2.72,.92,3.12,2.84,7.1,4.49,13.93,3.97,16.39-.47,2.18-5.6,5.65-12.36,8.33-3.63,1.44-6.11,2.99-8.04,5.01-7.17,7.51-10.24,17.86-7.14,24.05,3.93,7.84,18.38,5.86,28.05-3.85,2.09-2.1,3.15-3.83,6.63-10.77,2.97-5.93,4.26-8.05,5.47-8.95,2.04-1.52,9.82,.1,17.41,3.64,1.71,.8,2.31,1.04,2.78,.98,0,0,.22-.05,.43-.14,1.31-.59,17.43-17,25.58-25.34-1.79,.09-3.57,.18-5.36,.28-2.84,2.63-5.68,5.27-8.52,7.9-10.85-10.85-21.7-21.71-32.55-32.56,1.73-1.8,3.46-3.6,5.18-5.4-.29-1.56-.57-3.12-.86-4.69-1.34,1.27-19.42,18.45-21.01,20.66Zm-10.45,44.57c2.5,0,4.53,2.03,4.53,4.53s-2.03,4.53-4.53,4.53-4.53-2.03-4.53-4.53,2.03-4.53,4.53-4.53Z"/><path class="f" d="M132.9,97.36c-.88,.22-7.88,1.92-9.91-1.04-1.11-1.62-1.05-4.71-.52-6.57,.74-2.59,.9-4.06,.25-4.73-.73-.76-2.03-.31-3.73-.18-3.4,.27-8.08-.86-9.6-3.16-2.77-4.21,4.48-13.03,2.31-14.69-.17-.13-.34-.16-.67-.22-4.24-.73-6.79,4.71-11.66,5.1-2.93,.24-6.21-1.39-7.72-4.02-1.11-1.94-1-3.96-.86-4.95h0s7.38-7.39,17.6-17.52c12.75,12.73,25.51,25.47,38.26,38.2l-13.75,13.79Z"/><polygon points="154 0 154 38 39 38 39 192 0 192 0 0"/><polygon points="192 38 192 192 77 192 77 153 154 153 154 38"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -15,10 +15,10 @@
window.addEventListener("error", function (e) { window.addEventListener("error", function (e) {
console.error(e); console.error(e);
let errorMessage = "<p class=\"error\">An error has occurred:</p>"; let errorMessage = "<h4 class=\"mb-3\">An error has occurred:</h4>";
errorMessage += "<p class=\"errorBody\">" + e.message + "</p>"; errorMessage += "<p class=\"text-danger\">" + e.message + "</p>";
errorMessage += "<p class=\"errorBody\">on line " + e.lineno + "</p>"; errorMessage += "<p class=\"text-danger\">on line " + e.lineno + "</p>";
errorMessage += "<p class=\"error\">If this keeps happening, feel free to tell us on <a href=\"https://discord.gg/pJkm23b2nA\">our Discord server</a>.</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; document.getElementById("loadingContent").innerHTML = errorMessage;
}); });

View file

@ -20,35 +20,48 @@ const highlightUnchartedLabel = document.getElementById("highlightUnchartedLabel
let entryId = 0 let entryId = 0
const objectInfoBox = document.getElementById("objectInfo"); const objectInfoBox = document.getElementById("objectInfo");
var drawControlsBody = document.getElementById("offcanvasDraw-drawControls");
var objectInfoBody = document.getElementById("offcanvasDraw-objectInfo");
var objectInfoForm = document.getElementById("objectInfo");
const hintText = document.getElementById("hint"); const hintText = document.getElementById("hint");
const periodsStatus = document.getElementById('periodsStatus') const periodsStatus = document.getElementById('periodsStatus');
const periodGroups = document.getElementById('periodGroups') const periodGroups = document.getElementById('periodGroups');
const periodGroupTemplate = document.getElementById('period-group').content.firstElementChild.cloneNode(true) const periodGroupTemplate = document.getElementById('period-group').content.firstElementChild.cloneNode(true);
const periodsAdd = document.getElementById('periodsAdd') const periodsAdd = document.getElementById('periodsAdd');
const exportButton = document.getElementById("exportButton"); const exportButton = document.getElementById("exportButton");
const cancelButton = document.getElementById("cancelButton"); const cancelButton = document.getElementById("cancelButton");
const exportModal = new bootstrap.Modal(document.getElementById("exportModal"));
const exportModalElement = document.getElementById("exportModal");
const exportOverlay = document.getElementById("exportOverlay"); const exportOverlay = document.getElementById("exportOverlay");
const exportCloseButton = document.getElementById("exportCloseButton"); const exportCloseButton = document.getElementById("exportCloseButton");
const exportBackButton = document.getElementById("exportBackButton") const exportBackButton = document.getElementById("exportBackButton");
const nameField = document.getElementById("nameField") const nameField = document.getElementById("nameField");
const descriptionField = document.getElementById("descriptionField") const descriptionField = document.getElementById("descriptionField");
const websiteField = document.getElementById("websiteField") const websiteGroup = document.getElementById("websiteGroup");
const subredditField = document.getElementById("subredditField") const subredditGroup = document.getElementById("subredditGroup");
const discordField = document.getElementById("discordField") const discordGroup = document.getElementById("discordGroup");
const wikiField = document.getElementById("wikiField") const wikiGroup = document.getElementById("wikiGroup");
const exportArea = document.getElementById("exportString"); const exportArea = document.getElementById("exportString");
let path = []; let path = [];
let center = [1000, 1000]; let center = [1000, 1000];
let pathWithPeriods = [] let websiteGroupElements = [];
let periodGroupElements = [] let subredditGroupElements = [];
let discordGroupElements = [];
let wikiGroupElements = [];
let disableDrawingOverride = false let pathWithPeriods = [];
let periodGroupElements = [];
let disableDrawingOverride = false;
let drawing = true; let drawing = true;
let undoHistory = []; let undoHistory = [];
@ -58,7 +71,7 @@ const periodClipboard = {
"path": null "path": null
} }
;[...document.querySelectorAll("#drawControlsContainer textarea")].forEach(el => { ;[...document.querySelectorAll("#objectInfo textarea")].forEach(el => {
el.addEventListener("input", function () { el.addEventListener("input", function () {
this.style.height = "auto"; this.style.height = "auto";
this.style.height = (this.scrollHeight) + "px" this.style.height = (this.scrollHeight) + "px"
@ -70,6 +83,14 @@ function initDraw() {
wrapper.classList.remove('listHidden') wrapper.classList.remove('listHidden')
var backButton = document.getElementById("showListButton");
backButton.insertAdjacentHTML("afterend", '<button class="btn btn-outline-primary" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasDraw" aria-controls="offcanvasDraw">Menu</button><a id="drawBackButton" class="btn btn-outline-primary" href="./">Exit Draw Mode</a>');
backButton.remove();
var myOffcanvas = document.getElementById("offcanvasDraw");
var bsOffcanvas = new bootstrap.Offcanvas(myOffcanvas);
bsOffcanvas.show();
window.render = render window.render = render
window.renderBackground = renderBackground window.renderBackground = renderBackground
window.updateHovering = updateHovering window.updateHovering = updateHovering
@ -152,17 +173,13 @@ function initDraw() {
}); });
window.addEventListener("keyup", function (e) { window.addEventListener("keyup", function(e){
if (e.key == "Enter") { if (e.key == "z" && e.ctrlKey){
finish();
} else if (e.key == "z" && e.ctrlKey) {
undo(); undo();
} else if (e.key == "y" && e.ctrlKey) { } else if (e.key == "y" && e.ctrlKey) {
redo(); redo();
} else if (e.key == "Escape") { } else if (e.key === "Shift" ){
exportOverlay.style.display = "none"; if(e.code === "ShiftRight"){
} else if (e.key === "Shift") {
if (e.code === "ShiftRight") {
rShiftPressed = false; rShiftPressed = false;
} else if (e.code === "ShiftLeft") { } else if (e.code === "ShiftLeft") {
lShiftPressed = false; lShiftPressed = false;
@ -171,7 +188,7 @@ function initDraw() {
} }
}); });
window.addEventListener("keydown", function (e) { window.addEventListener("keydown", function(e) {
if (e.key === "Shift") { if (e.key === "Shift") {
if (e.code === "ShiftRight") { if (e.code === "ShiftRight") {
rShiftPressed = true; rShiftPressed = true;
@ -202,39 +219,21 @@ function initDraw() {
back(); back();
}); });
nameField.addEventListener("keyup", function (e) { // refocus on button when modal is closed
if (e.key == "Enter") { exportModalElement.addEventListener('hidden.bs.modal', function() {
exportJson(); document.getElementById("exportButton").focus();
}
}); });
// websiteField.addEventListener("keyup", function(e){ exportModalElement.addEventListener('shown.bs.modal', function() {
// if(e.key == "Enter"){ document.getElementById("exportButton").focus();
// exportJson();
// }
// });
// subredditField.addEventListener("keyup", function(e){
// if(e.key == "Enter"){
// exportJson();
// }
// });
exportButton.addEventListener("click", function (e) {
exportJson();
}); });
exportCloseButton.addEventListener("click", function (e) { objectInfoForm.addEventListener('submit', function(e) {
reset(); e.preventDefault()
exportOverlay.style.display = "none"; exportJson()
}); });
exportBackButton.addEventListener("click", function (e) { document.getElementById("highlightUncharted").addEventListener("click", function(e){
finish();
exportOverlay.style.display = "none";
});
document.getElementById("highlightUncharted").addEventListener("click", function (e) {
highlightUncharted = this.checked; highlightUncharted = this.checked;
render(path); render(path);
}); });
@ -267,10 +266,10 @@ function initDraw() {
exportObject.center[key] = calculateCenter(value) exportObject.center[key] = calculateCenter(value)
}) })
const inputWebsite = websiteField.value.split('\n').map(line => line.trim()).filter(line => line) const inputWebsite = websiteGroupElements.map(element => element.value.trim()).filter(element => element);
const inputSubreddit = subredditField.value.split('\n').map(line => line.trim().replace(/(?:(?:(?:(?:https?:\/\/)?(?:(?:www|old|new|np)\.)?)?reddit\.com)?\/)?[rR]\/([A-Za-z0-9][A-Za-z0-9_]{2,20})(?:\/[^" ]*)*/, '$1')).filter(line => line) const inputSubreddit = subredditGroupElements.map(element => element.value.trim().replace(/(?:(?:(?:(?:https?:\/\/)?(?:(?:www|old|new|np)\.)?)?reddit\.com)?\/)?[rR]\/([A-Za-z0-9][A-Za-z0-9_]{2,20})(?:\/[^" ]*)*/, '$1')).filter(element => element);
const inputDiscord = discordField.value.split('\n').map(line => line.trim().replace(/(?:https?:\/\/)?(?:www\.)?(?:(?:discord)?\.?gg|discord(?:app?)\.com\/invite)\/([^\s/]+?)(?=\b)/, '$1')).filter(line => line) const inputDiscord = discordGroupElements.map(element => element.value.trim().replace(/(?:https?:\/\/)?(?:www\.)?(?:(?:discord)?\.?gg|discord(?:app?)\.com\/invite)\/([^\s/]+?)(?=\b)/, '$1')).filter(element => element);
const inputWiki = wikiField.value.split('\n').map(line => line.trim().replace(/ /g, '_')).filter(line => line) const inputWiki = wikiGroupElements.map(element => element.value.trim().replace(/ /g, '_')).filter(element => element);
if (inputWebsite.length) exportObject.links.website = inputWebsite if (inputWebsite.length) exportObject.links.website = inputWebsite
if (inputSubreddit.length) exportObject.links.subreddit = inputSubreddit if (inputSubreddit.length) exportObject.links.subreddit = inputSubreddit
@ -288,10 +287,10 @@ function initDraw() {
} }
document.getElementById("exportDirectPost").href = directPostUrl; document.getElementById("exportDirectPost").href = directPostUrl;
exportOverlay.style.display = "flex"; if (entryId == 0) document.getElementById("redditFlair").textContent = "New Entry";
else document.getElementById("redditFlair").textContent = "Edit Entry";
exportArea.focus(); exportModal.show();
exportArea.select();
} }
function undo() { function undo() {
@ -315,10 +314,9 @@ function initDraw() {
updatePath() updatePath()
drawing = false; drawing = false;
disableDrawingOverride = true; disableDrawingOverride = true;
objectInfoBox.style.display = "block"; objectInfoBody.removeAttribute("style");
objectDraw.style.display = "none"; drawControlsBody.style.display = "none";
hintText.style.display = "none"; [...document.querySelectorAll("#objectInfo textarea")].forEach(el => {
[...document.querySelectorAll("#drawControlsContainer textarea")].forEach(el => {
if (el.value) el.style.height = (el.scrollHeight) + "px" if (el.value) el.style.height = (el.scrollHeight) + "px"
}) })
// if (isOnPeriod()) { // if (isOnPeriod()) {
@ -329,31 +327,56 @@ function initDraw() {
} }
function reset() { function reset() {
updatePath([]) // Requires button to be pressed twice to confirm reset
undoHistory = []; if (resetButton.textContent == "Confirm Reset") {
drawing = true; resetButton.textContent = "Reset";
disableDrawingOverride = false; resetButton.className = "btn btn-secondary";
objectInfoBox.style.display = "none";
objectDraw.style.display = "block";
hintText.style.display = "block";
nameField.value = ""; updatePath([])
descriptionField.value = ""; undoHistory = [];
websiteField.value = ""; drawing = true;
subredditField.value = ""; disableDrawingOverride = false;
objectInfoBody.style.display = "none";
drawControlsBody.removeAttribute("style");
pathWithPeriods = [] // Blanks input values
pathWithPeriods.push([defaultPeriod, []]) nameField.value = "";
initPeriodGroups() descriptionField.value = "";
// Clears input array
websiteGroupElements = [];
subredditGroupElements = [];
discordGroupElements = [];
wikiGroupElements = [];
// Rebuilds multi-input list
websiteGroup.replaceChildren();
subredditGroup.replaceChildren();
discordGroup.replaceChildren();
wikiGroup.replaceChildren();
addWebsiteFields("", 0, [0]);
addSubredditFields("", 0, [0]);
addDiscordFields("", 0, [0]);
addWikiFields("", 0, [0]);
// Resets periods
pathWithPeriods = []
pathWithPeriods.push([defaultPeriod, []])
initPeriodGroups()
} else {
resetButton.textContent = "Confirm Reset";
resetButton.className = "btn btn-danger";
}
} }
function back() { function back() {
drawing = true; drawing = true;
disableDrawingOverride = false; disableDrawingOverride = false;
updatePath() updatePath()
objectInfoBox.style.display = "none"; objectInfoBody.style.display = "none";
objectDraw.style.display = "block"; drawControlsBody.removeAttribute("style");
hintText.style.display = "block"; resetButton.textContent = "Reset";
resetButton.className = "btn btn-secondary";
} }
function renderBackground() { function renderBackground() {
@ -427,8 +450,15 @@ function initDraw() {
(e.clientX - (container.clientWidth / 2 - innerContainer.clientWidth / 2 + zoomOrigin[0] + container.offsetLeft)) / zoom (e.clientX - (container.clientWidth / 2 - innerContainer.clientWidth / 2 + zoomOrigin[0] + container.offsetLeft)) / zoom
, (e.clientY - (container.clientHeight / 2 - innerContainer.clientHeight / 2 + zoomOrigin[1] + container.offsetTop)) / zoom , (e.clientY - (container.clientHeight / 2 - innerContainer.clientHeight / 2 + zoomOrigin[1] + container.offsetTop)) / zoom
]; ];
const coords_p = document.getElementById("coords_p"); const coords_p = document.getElementById("coords_p");
coords_p.innerText = Math.ceil(pos[0]) + ", " + Math.ceil(pos[1]);
// Displays coordinates as zero instead of NaN
if (isNaN(pos[0]) == true) {
coords_p.innerText = "0, 0";
} else {
coords_p.innerText = Math.ceil(pos[0]) + ", " + Math.ceil(pos[1]);
}
} }
} }
@ -440,14 +470,224 @@ function initDraw() {
const params = new URLSearchParams(document.location.search) const params = new URLSearchParams(document.location.search)
function addFieldButton(inputButton, inputGroup, array, index, name) {
console.log("add button fired");
if (inputButton.title == "Remove " + name) {
console.log("add (now remove) button fired");
removeFieldButton(inputGroup, array, index);
return;
}
inputButton.className = "btn btn-outline-secondary";
inputButton.title = "Remove " + name;
inputButton.innerHTML = '<i class="bi bi-trash-fill"></i>';
console.log(array);
if (name == "website") {
addWebsiteFields(null, array.length, array);
} else if (name == "subreddit") {
addSubredditFields(null, array.length, array);
} else if (name == "Discord invite") {
addDiscordFields(null, array.length, array);
} else if (name == "wiki page") {
addWikiFields(null, array.length, array);
}
}
function removeFieldButton(inputGroup, array, index) {
console.log("remove button fired");
delete array[index];
inputGroup.remove();
console.log(array);
}
function addWebsiteFields(link, index, array) {
const inputGroup = document.createElement("div");
inputGroup.className = "input-group";
websiteGroup.appendChild(inputGroup);
const inputField = document.createElement("input");
inputField.type = "url";
inputField.name = "url";
inputField.className = "form-control";
inputField.id = "websiteField" + index;
inputField.placeholder = "https://example.com";
inputField.pattern = "https?://.*";
inputField.title = "Website URL using the http:// or https:// protocol";
inputField.setAttribute("aria-labelledby", "websiteLabel");
inputField.value = link
inputGroup.appendChild(inputField);
websiteGroupElements.push(inputField);
const inputButton = document.createElement("button");
inputButton.type = "button";
// If button is the last in the array give it the add button
if (array.length == index + 1) {
inputButton.className = "btn btn-secondary";
inputButton.title = "Add website";
inputButton.innerHTML = '<i class="bi bi-plus-lg"></i>';
inputButton.addEventListener('click', () => addFieldButton(inputButton, inputGroup, websiteGroupElements, index, "website"));
} else {
inputButton.className = "btn btn-outline-secondary";
inputButton.title = "Remove website";
inputButton.innerHTML = '<i class="bi bi-trash-fill"></i>';
inputButton.addEventListener('click', () => removeFieldButton(inputGroup, array, index));
}
inputGroup.appendChild(inputButton);
}
function addSubredditFields(link, index, array) {
const inputGroup = document.createElement("div");
inputGroup.className = "input-group";
subredditGroup.appendChild(inputGroup);
const inputAddon = document.createElement("span");
inputAddon.className = "input-group-text";
inputAddon.id = "subredditField" + index + "-addon";
inputAddon.textContent = "reddit.com/";
inputGroup.appendChild(inputAddon);
const inputField = document.createElement("input");
inputField.type = "text";
inputField.className = "form-control";
inputField.id = "subredditField" + index;
inputField.placeholder = "r/example";
inputField.pattern = "^r\/\\w+$";
inputField.title = "Subbredit in format of r/example";
inputField.maxLength = "23";
inputField.spellcheck = false;
inputField.setAttribute("aria-labelledby", "subredditLabel");
inputField.setAttribute("aria-describedby", "subredditField" + index + "-addon");
if (link) {
inputField.value = "r/" + link
} else {
inputField.value = "";
}
inputGroup.appendChild(inputField);
subredditGroupElements.push(inputField);
const inputButton = document.createElement("button");
inputButton.type = "button";
// If button is the last in the array give it the add button
if (array.length == index + 1) {
inputButton.className = "btn btn-secondary";
inputButton.title = "Add subreddit";
inputButton.innerHTML = '<i class="bi bi-plus-lg"></i>';
inputButton.addEventListener('click', () => addFieldButton(inputButton, inputGroup, subredditGroupElements, index, "subreddit"));
} else {
inputButton.className = "btn btn-outline-secondary";
inputButton.title = "Remove subreddit";
inputButton.innerHTML = '<i class="bi bi-trash-fill"></i>';
inputButton.addEventListener('click', () => removeFieldButton(inputGroup, array, index));
}
inputGroup.appendChild(inputButton);
}
function addDiscordFields(link, index, array) {
const inputGroup = document.createElement("div");
inputGroup.className = "input-group";
discordGroup.appendChild(inputGroup);
const inputAddon = document.createElement("span");
inputAddon.className = "input-group-text";
inputAddon.id = "discordField" + index + "-addon";
inputAddon.textContent = "discord.gg/";
inputGroup.appendChild(inputAddon);
const inputField = document.createElement("input");
inputField.type = "text";
inputField.className = "form-control";
inputField.id = "discordField" + index;
inputField.placeholder = "pJkm23b2nA";
inputField.spellcheck = false;
inputField.setAttribute("aria-labelledby", "discordLabel");
inputField.setAttribute("aria-describedby", "discordField" + index + "-addon");
inputField.value = link
inputGroup.appendChild(inputField);
discordGroupElements.push(inputField);
const inputButton = document.createElement("button");
inputButton.type = "button";
// If button is the last in the array give it the add button
if (array.length == index + 1) {
inputButton.className = "btn btn-secondary";
inputButton.title = "Add Discord invite";
inputButton.innerHTML = '<i class="bi bi-plus-lg"></i>';
inputButton.addEventListener('click', () => addFieldButton(inputButton, inputGroup, discordGroupElements, index, "Discord invite"));
} else {
inputButton.className = "btn btn-outline-secondary";
inputButton.title = "Remove Discord invite";
inputButton.innerHTML = '<i class="bi bi-trash-fill"></i>';
inputButton.addEventListener('click', () => removeFieldButton(inputGroup, array, index));
}
inputGroup.appendChild(inputButton);
}
function addWikiFields(link, index, array) {
const inputGroup = document.createElement("div");
inputGroup.className = "input-group";
wikiGroup.appendChild(inputGroup);
const inputField = document.createElement("input");
inputField.type = "text";
inputField.className = "form-control";
inputField.id = "wikiField" + index;
inputField.placeholder = "Page title";
inputField.spellcheck = false;
inputField.setAttribute("aria-labelledby", "wikiLabel");
inputField.value = link
inputGroup.appendChild(inputField);
wikiGroupElements.push(inputField);
const inputButton = document.createElement("button");
inputButton.type = "button";
// If button is the last in the array give it the add button
if (array.length == index + 1) {
inputButton.className = "btn btn-secondary";
inputButton.title = "Add wiki page";
inputButton.innerHTML = '<i class="bi bi-plus-lg"></i>';
inputButton.addEventListener('click', () => addFieldButton(inputButton, inputGroup, wikiGroupElements, index, "wiki page"));
} else {
inputButton.className = "btn btn-outline-secondary";
inputButton.title = "Remove wiki page";
inputButton.innerHTML = '<i class="bi bi-trash-fill"></i>';
inputButton.addEventListener('click', () => removeFieldButton(inputGroup, array, index));
}
inputGroup.appendChild(inputButton);
}
if (params.has('id')) { if (params.has('id')) {
const entry = getEntry(params.get('id')) const entry = getEntry(params.get('id'))
nameField.value = entry.name nameField.value = entry.name
descriptionField.value = entry.description descriptionField.value = entry.description
websiteField.value = entry.links.website.join('\n')
subredditField.value = entry.links.subreddit.map(sub => '/r/' + sub).join('\n') if (entry.links.website.length) {
discordField.value = entry.links.discord.join('\n') entry.links.website.forEach((link, index, array) => {
wikiField.value = entry.links.wiki.map(page => page.replace(/_/, ' ')).join('\n') addWebsiteFields(link, index, array);
});
} else {
addWebsiteFields("", -1, entry.links.website);
}
if (entry.links.subreddit.length) {
entry.links.subreddit.forEach((link, index, array) => {
addSubredditFields(link, index, array);
});
} else {
addSubredditFields("", -1, entry.links.subreddit);
}
if (entry.links.discord.length) {
entry.links.discord.forEach((link, index, array) => {
addDiscordFields(link, index, array);
});
} else {
addDiscordFields("", -1, entry.links.discord);
}
if (entry.links.wiki.length) {
entry.links.wiki.forEach((link, index, array) => {
addWikiFields(link, index, array);
});
} else {
addWikiFields("", -1, entry.links.wiki);
}
redoButton.disabled = true; redoButton.disabled = true;
undoButton.disabled = false; undoButton.disabled = false;
entryId = params.get('id') entryId = params.get('id')
@ -459,7 +699,12 @@ function initDraw() {
}) })
} else { } else {
document.getElementById("offcanvasDrawLabel").textContent = "New Entry";
pathWithPeriods.push([defaultPeriod, []]) pathWithPeriods.push([defaultPeriod, []])
addWebsiteFields("", 0, [0]);
addSubredditFields("", 0, [0]);
addDiscordFields("", 0, [0]);
addWikiFields("", 0, [0]);
} }
initPeriodGroups() initPeriodGroups()
@ -506,7 +751,6 @@ function initPeriodGroups() {
const startPeriodEl = periodGroupEl.querySelector('.period-start') const startPeriodEl = periodGroupEl.querySelector('.period-start')
const endPeriodEl = periodGroupEl.querySelector('.period-end') const endPeriodEl = periodGroupEl.querySelector('.period-end')
const periodVisibilityEl = periodGroupEl.querySelector('.period-visible')
const periodDeleteEl = periodGroupEl.querySelector('.period-delete') const periodDeleteEl = periodGroupEl.querySelector('.period-delete')
const periodDuplicateEl = periodGroupEl.querySelector('.period-duplicate') const periodDuplicateEl = periodGroupEl.querySelector('.period-duplicate')
const periodVariationEl = periodGroupEl.querySelector('.period-variation') const periodVariationEl = periodGroupEl.querySelector('.period-variation')
@ -515,10 +759,9 @@ function initPeriodGroups() {
const [start, end, variation] = parsePeriod(period) const [start, end, variation] = parsePeriod(period)
startPeriodEl.id = "periodStart" + index startPeriodEl.id = "periodStart" + index
startPeriodEl.previousSibling.for = startPeriodEl.id startPeriodEl.previousElementSibling.htmlFor = startPeriodEl.id
endPeriodEl.id = "periodEnd" + index endPeriodEl.id = "periodEnd" + index
endPeriodEl.previousSibling.for = endPeriodEl.id endPeriodEl.previousElementSibling.htmlFor = endPeriodEl.id
periodVisibilityEl.id = "periodVisibility" + index
periodVariationEl.id = "periodVariation" + index periodVariationEl.id = "periodVariation" + index
periodCopyEl.id = "periodCopy" + index periodCopyEl.id = "periodCopy" + index
@ -553,6 +796,7 @@ function initPeriodGroups() {
startPeriodEl.max = newVariationConfig.versions.length - 1 startPeriodEl.max = newVariationConfig.versions.length - 1
endPeriodEl.value = newVariationConfig.default endPeriodEl.value = newVariationConfig.default
endPeriodEl.max = newVariationConfig.versions.length - 1 endPeriodEl.max = newVariationConfig.versions.length - 1
periodVariationEl.previousElementSibling.innerHTML = newVariationConfig.icon;
if (startPeriodEl.max == 0) periodGroupEl.classList.add('no-time-slider') if (startPeriodEl.max == 0) periodGroupEl.classList.add('no-time-slider')
else periodGroupEl.classList.remove('no-time-slider') else periodGroupEl.classList.remove('no-time-slider')
updateTime(newVariationConfig.default, newVariation) updateTime(newVariationConfig.default, newVariation)
@ -560,17 +804,23 @@ function initPeriodGroups() {
periodCopyEl.addEventListener("click", event => { periodCopyEl.addEventListener("click", event => {
const index = parseInt(event.target.id.split('periodCopy')[1]) const index = parseInt(event.target.id.split('periodCopy')[1])
if (event.target.textContent === "Copy") { if (event.target.textContent === " Copy") {
event.target.textContent = "End" event.target.className = "period-copy btn btn-primary btn-sm flex-fill";
event.target.innerHTML = '<i class="bi bi-clipboard-x" aria-hidden="true"></i> End'
periodClipboard.index = index periodClipboard.index = index
periodClipboard.path = [...pathWithPeriods[index][1]] periodClipboard.path = [...pathWithPeriods[index][1]]
startPeriodEl.disabled = true;
endPeriodEl.disabled = true;
updatePeriodGroups() updatePeriodGroups()
} else if (event.target.textContent === "End") { } else if (event.target.textContent === " End") {
event.target.textContent = "Copy" event.target.className = "period-copy btn btn-secondary btn-sm flex-fill";
event.target.innerHTML = '<i class="bi bi-clipboard" aria-hidden="true"></i> Copy'
periodClipboard.index = null periodClipboard.index = null
periodClipboard.path = null periodClipboard.path = null
startPeriodEl.disabled = false;
endPeriodEl.disabled = false;
updatePeriodGroups() updatePeriodGroups()
} else if (event.target.textContent === "Paste") { } else if (event.target.textContent === " Paste") {
pathWithPeriods[index][1] = [...periodClipboard.path] pathWithPeriods[index][1] = [...periodClipboard.path]
if (pathWithPeriods.length > 2) console.log(pathWithPeriods[2]) if (pathWithPeriods.length > 2) console.log(pathWithPeriods[2])
initPeriodGroups() initPeriodGroups()
@ -587,19 +837,18 @@ function initPeriodGroups() {
} }
periodVariationEl.value = variation periodVariationEl.value = variation
periodVariationEl.previousElementSibling.innerHTML = variationsConfig[variation].icon;
periodGroupElements.push({ periodGroupElements.push({
periodGroupEl, periodGroupEl,
startPeriodEl, startPeriodEl,
endPeriodEl, endPeriodEl,
periodVisibilityEl,
periodVariationEl, periodVariationEl,
periodCopyEl periodCopyEl
}) })
}) })
updatePeriodGroups() updatePeriodGroups()
} }
function updatePeriodGroups() { function updatePeriodGroups() {
@ -613,7 +862,6 @@ function updatePeriodGroups() {
periodGroupEl, periodGroupEl,
startPeriodEl, startPeriodEl,
endPeriodEl, endPeriodEl,
periodVisibilityEl,
periodVariationEl, periodVariationEl,
periodCopyEl periodCopyEl
} = elements } = elements
@ -642,17 +890,20 @@ function updatePeriodGroups() {
if (periodClipboard.index !== null) { if (periodClipboard.index !== null) {
if (index !== periodClipboard.index) { if (index !== periodClipboard.index) {
periodCopyEl.textContent = "Paste" periodCopyEl.innerHTML = '<i class="bi bi-clipboard-plus" aria-hidden="true"></i> Paste'
if (JSON.stringify(pathWithPeriods[index][1]) === JSON.stringify(periodClipboard.path)) { if (JSON.stringify(pathWithPeriods[index][1]) === JSON.stringify(periodClipboard.path)) {
periodCopyEl.innerHTML = '<i class="bi bi-clipboard-check" aria-hidden="true"></i> Paste'
periodCopyEl.disabled = true periodCopyEl.disabled = true
} else { } else {
periodCopyEl.innerHTML = '<i class="bi bi-clipboard-plus" aria-hidden="true"></i> Paste'
periodCopyEl.disabled = false periodCopyEl.disabled = false
} }
} else { } else {
periodCopyEl.textContent = "End" periodCopyEl.className = "period-copy btn btn-primary btn-sm flex-fill";
periodCopyEl.innerHTML = '<i class="bi bi-clipboard-x" aria-hidden="true"></i> End'
} }
} else { } else {
periodCopyEl.textContent = "Copy" periodCopyEl.innerHTML = '<i class="bi bi-clipboard" aria-hidden="true"></i> Copy'
periodCopyEl.disabled = false periodCopyEl.disabled = false
} }
}) })

View file

@ -14,92 +14,175 @@
*/ */
function createInfoBlock(entry) { function createInfoBlock(entry) {
function createInfoParagraph(name, value) { function createLabel(name, value, parent) {
const entryParagraphPositionElement = document.createElement("p"); const nameElement = document.createElement("span");
const nameElement = document.createElement("span"); nameElement.className = "fw-bold";
nameElement.style.fontWeight = "bold"; nameElement.textContent = name;
nameElement.innerText = name; const valueElement = document.createElement("span");
const valueElement = document.createElement("span"); valueElement.textContent = value;
valueElement.innerText = value; parent.appendChild(nameElement);
entryParagraphPositionElement.appendChild(nameElement); parent.appendChild(valueElement);
entryParagraphPositionElement.appendChild(valueElement); return parent;
return entryParagraphPositionElement; }
} function createInfoListItem(name, value) {
const entryInfoListElement = document.createElement("li");
entryInfoListElement.className = "list-group-item";
createLabel(name, value, entryInfoListElement);
return entryInfoListElement;
}
const element = document.createElement("div"); const element = document.createElement("div");
element.className = "object"; element.className = "card mb-2 overflow-hidden shadow";
const headerElement = document.createElement("h2"); const headerElement = document.createElement("h4");
const linkElement = document.createElement("a"); headerElement.className = "card-header";
linkElement.href = "#" + entry.id; const linkElement = document.createElement("a");
linkElement.innerText = entry.name; linkElement.className = "text-decoration-none d-flex justify-content-between text-body";
headerElement.appendChild(linkElement); linkElement.href = "#" + entry.id;
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"></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);
element.appendChild(headerElement); const bodyElement = document.createElement("div");
bodyElement.className = "card-body d-flex flex-column gap-3";
element.appendChild(bodyElement);
if (entry.diff) { if (entry.description) {
const diffElement = createInfoParagraph("Diff: ", entry.diff); const descElement = document.createElement("div");
diffElement.className = entry.diff; descElement.id = "objectDescription";
element.appendChild(diffElement); let formattedDesc = entry.description.replace(/\n{2}/g, '</p><p>');
} formattedDesc = formattedDesc.replace(/\n/g, '<br>');
descElement.innerHTML = '<p>' + formattedDesc + '</p>';
bodyElement.appendChild(descElement);
}
if (entry.description) { const linkListElement = document.createElement("div");
const descElement = document.createElement("p"); linkListElement.className = "d-flex flex-column gap-2";
descElement.innerText = entry.description; bodyElement.appendChild(linkListElement);
element.appendChild(descElement);
}
const [x, y] = entry.center; const listElement = document.createElement("ul");
element.appendChild(createInfoParagraph("Position: ", `${Math.floor(x)}, ${Math.floor(y)}`)); listElement.className = "list-group list-group-flush";
element.appendChild(listElement);
if (entry.path) { if (entry.diff) {
const area = calcPolygonArea(entry.path); let diffElement = createInfoListItem("Diff: ", entry.diff);
element.appendChild(createInfoParagraph("Area: ", `${area} pixels`)); if (entry.diff == "add") {
} diffElement.className = "list-group-item list-group-item-success";
} else if (entry.diff == "edit") {
diffElement.className = "list-group-item list-group-item-warning";
} else if (entry.diff == "delete") {
diffElement.className = "list-group-item list-group-item-danger";
}
listElement.appendChild(diffElement);
}
entry.links.subreddit.forEach(subreddit => { const [x, y] = entry.center;
subreddit = "/r/" + subreddit; listElement.appendChild(createInfoListItem("Position: ", `${Math.floor(x)}, ${Math.floor(y)}`));
const subredditLinkElement = document.createElement("a");
subredditLinkElement.target = "_blank";
subredditLinkElement.href = "https://reddit.com" + subreddit;
subredditLinkElement.innerText = subreddit;
element.appendChild(subredditLinkElement);
})
entry.links.website.forEach(link => { if(entry.path){
const websiteLinkElement = document.createElement("a"); const area = calcPolygonArea(entry.path);
websiteLinkElement.target = "_blank"; listElement.appendChild(createInfoListItem("Area: ", `${area} pixels`));
websiteLinkElement.href = link; }
websiteLinkElement.innerText = "Website";
element.appendChild(websiteLinkElement);
})
entry.links.discord.forEach(link => { if (entry.links.subreddit.length) {
const websiteLinkElement = document.createElement("a"); const subredditGroupElement = document.createElement("div");
websiteLinkElement.target = "_blank"; subredditGroupElement.className = "btn-group-vertical";
websiteLinkElement.href = "https://discord.gg/" + link; linkListElement.appendChild(subredditGroupElement);
websiteLinkElement.innerText = "Discord";
element.appendChild(websiteLinkElement);
})
entry.links.wiki.forEach(link => { entry.links.subreddit.forEach(subreddit => {
const websiteLinkElement = document.createElement("a"); if (subreddit) {
websiteLinkElement.target = "_blank"; subreddit = "r/" + subreddit;
websiteLinkElement.href = "https://place-wiki.stefanocoding.me/wiki/" + link.replace(/ /g, '_'); const subredditLinkElement = document.createElement("a");
websiteLinkElement.innerText = "Wiki Article"; subredditLinkElement.className = "btn btn-primary text-truncate";
element.appendChild(websiteLinkElement); subredditLinkElement.target = "_blank";
}) subredditLinkElement.rel = "noopener noreferrer";
subredditLinkElement.href = "https://reddit.com/" + subreddit;
subredditLinkElement.textContent = subreddit;
subredditGroupElement.appendChild(subredditLinkElement);
}
});
};
const idElement = createInfoParagraph("ID: ", entry.id); if (entry.links.website.length) {
element.appendChild(idElement); const websiteGroupElement = document.createElement("div");
websiteGroupElement.className = "btn-group-vertical";
linkListElement.appendChild(websiteGroupElement);
if (!entry.diff || entry.diff !== "delete") { entry.links.website.forEach(link => {
const editElement = document.createElement("a"); if (link) {
editElement.innerText = "Edit" const websiteLinkElement = document.createElement("a");
editElement.className = "objectEdit" websiteLinkElement.className = "btn btn-primary"
editElement.href = "./?mode=draw&id=" + entry.id websiteLinkElement.target = "_blank";
element.appendChild(editElement); websiteLinkElement.rel = "noopener noreferrer";
} websiteLinkElement.href = link;
websiteLinkElement.textContent = "Website";
websiteGroupElement.appendChild(websiteLinkElement);
}
});
}
if (entry.links.discord.length) {
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");
discordLinkElement.target = "_blank";
discordLinkElement.href = "https://discord.gg/" + link;
discordLinkElement.textContent = "Discord";
discordGroupElement.appendChild(discordLinkElement);
}
});
}
if (entry.links.wiki.length) {
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");
wikiLinkElement.target = "_blank";
websiteLinkElement.rel = "noopener noreferrer";
wikiLinkElement.href = "https://place-wiki.stefanocoding.me/wiki/" + link.replace(/ /g, '_');
wikiLinkElement.textContent = "Wiki Article";
wikiGroupElement.appendChild(wikiLinkElement);
}
});
}
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);
if (!entry.diff || entry.diff !== "delete") {
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);
}
if (!linkListElement.hasChildNodes()) {
linkListElement.remove();
}
if (!bodyElement.hasChildNodes()) {
bodyElement.remove();
}
return element; return element;
} }

View file

@ -37,13 +37,13 @@ let lastPosition = [0, 0];
const viewportSize = [0, 0]; const viewportSize = [0, 0];
document.getElementById("entriesListDonate").addEventListener("click", function (e) { // 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("closeDonateButton").addEventListener("click", function(e){
document.getElementById("donateOverlay").style.display = "none"; // document.getElementById("donateOverlay").style.display = "none";
}); // });
function applyView() { function applyView() {
@ -193,6 +193,8 @@ async function init() {
initView(); initView();
} }
document.getElementById("loading").classList.add("d-none");
document.getElementById("zoomInButton").addEventListener("click", function (e) { document.getElementById("zoomInButton").addEventListener("click", function (e) {
/*if(zoomAnimationFrame){ /*if(zoomAnimationFrame){

File diff suppressed because one or more lines are too long

View file

@ -29,6 +29,7 @@ const wrapper = document.getElementById("wrapper");
const objectsContainer = document.getElementById("objectsList"); const objectsContainer = document.getElementById("objectsList");
const closeObjectsListButton = document.getElementById("closeObjectsListButton"); const closeObjectsListButton = document.getElementById("closeObjectsListButton");
const objectsListOverflowNotice = document.getElementById("objectsListOverflowNotice");
const filterInput = document.getElementById("searchList"); const filterInput = document.getElementById("searchList");
@ -42,6 +43,10 @@ const entriesLimit = 50;
let entriesOffset = 0; let entriesOffset = 0;
const moreEntriesButton = document.createElement("button"); const moreEntriesButton = document.createElement("button");
moreEntriesButton.innerHTML = "Show " + entriesLimit + " more"; moreEntriesButton.innerHTML = "Show " + entriesLimit + " more";
moreEntriesButton.type = "button"
moreEntriesButton.className = "btn btn-primary d-block mb-2 mx-auto"
moreEntriesButton.id = "moreEntriesButton"; moreEntriesButton.id = "moreEntriesButton";
moreEntriesButton.onclick = function () { moreEntriesButton.onclick = function () {
buildObjectsList(null, null); buildObjectsList(null, null);
@ -56,17 +61,7 @@ let lastPos = [0, 0];
let fixed = false; // Fix hovered items in place, so that clicking on links is possible let fixed = false; // Fix hovered items in place, so that clicking on links is possible
if (document.documentElement.clientWidth > 2000) { filterInput.addEventListener("input", function(e){
entriesListShown = true;
wrapper.classList.remove('listHidden')
}
if (document.documentElement.clientWidth < 2000) {
entriesListShown = false;
wrapper.classList.add('listHidden')
}
filterInput.addEventListener("input", function (e) {
entriesOffset = 0; entriesOffset = 0;
entriesList.innerHTML = ""; entriesList.innerHTML = "";
entriesList.appendChild(moreEntriesButton); entriesList.appendChild(moreEntriesButton);
@ -91,25 +86,71 @@ document.getElementById("sort").addEventListener("input", function (e) {
}); });
hideListButton.addEventListener("click", function (e) { var showDraw = document.getElementById('offcanvasDraw')
entriesListShown = !entriesListShown; showDraw.addEventListener('show.bs.offcanvas', function() {
if (entriesListShown) { wrapper.classList.remove('listHidden');
wrapper.classList.remove('listHidden') wrapper.classList.add('listTransitioning');
} else { applyView();
wrapper.classList.add('listHidden') })
}
var shownDraw = document.getElementById('offcanvasDraw')
shownDraw.addEventListener('shown.bs.offcanvas', function() {
wrapper.classList.remove('listTransitioning');
applyView();
})
var hideDraw = document.getElementById('offcanvasDraw')
hideDraw.addEventListener('hide.bs.offcanvas', function() {
wrapper.classList.add('listHidden');
wrapper.classList.add('listTransitioning');
applyView();
})
var hiddenDraw = document.getElementById('offcanvasDraw')
hiddenDraw.addEventListener('hidden.bs.offcanvas', function() {
wrapper.classList.remove('listTransitioning');
applyView();
})
var showList = document.getElementById('offcanvasList')
showList.addEventListener('show.bs.offcanvas', function(e) {
wrapper.classList.remove('listHidden');
wrapper.classList.add('listTransitioning');
applyView();
});
var shownList = document.getElementById('offcanvasList')
shownList.addEventListener('shown.bs.offcanvas', function(e) {
entriesListShown = true;
wrapper.classList.remove('listTransitioning');
updateHovering(e); updateHovering(e);
applyView(); applyView();
render(); render();
updateLines(); updateLines();
return false;
}); });
closeObjectsListButton.addEventListener("click", function (e) { var hideList = document.getElementById('offcanvasList')
hovered = []; hideList.addEventListener('hide.bs.offcanvas', function(e) {
objectsContainer.innerHTML = ""; wrapper.classList.add('listHidden');
wrapper.classList.add('listTransitioning');
applyView();
});
var hiddenList = document.getElementById('offcanvasList')
hiddenList.addEventListener('hidden.bs.offcanvas', function(e) {
entriesListShown = false;
wrapper.classList.remove('listTransitioning');
updateHovering(e);
applyView();
render();
updateLines(); updateLines();
closeObjectsListButton.className = "hidden"; });
closeObjectsListButton.addEventListener("click", function(){
hovered = [];
objectsContainer.replaceChildren();
updateLines();
closeObjectsListButton.classList.add("d-none");
fixed = false; fixed = false;
render(); render();
}); });
@ -123,7 +164,9 @@ function toggleFixed(e, tapped) {
if (!fixed) { if (!fixed) {
updateHovering(e, tapped); updateHovering(e, tapped);
render(); render();
console.log("fixed");
} }
objectsListOverflowNotice.classList.add("d-none");
} }
window.addEventListener("resize", updateLines); window.addEventListener("resize", updateLines);
@ -136,19 +179,19 @@ objectsContainer.addEventListener("scroll", function (e) {
updateLines(); updateLines();
}); });
window.addEventListener("resize", function (e) { window.addEventListener("resize", function(e){
//console.log(document.documentElement.clientWidth, document.documentElement.clientHeight); //console.log(document.documentElement.clientWidth, document.documentElement.clientHeight);
let viewportWidth = document.documentElement.clientWidth; let viewportWidth = document.documentElement.clientWidth;
if (document.documentElement.clientWidth > 2000 && viewportWidth <= 2000) { if (document.documentElement.clientWidth > 2000 && viewportWidth <= 2000) {
entriesListShown = true; entriesListShown = true;
wrapper.className = wrapper.className.replace(/ listHidden/g, ""); wrapper.classList.remove("listHidden");
} }
if (document.documentElement.clientWidth < 2000 && viewportWidth >= 2000) { if (document.documentElement.clientWidth < 2000 && viewportWidth >= 2000) {
entriesListShown = false; entriesListShown = false;
wrapper.className += " listHidden"; wrapper.classList.add("listHidden");
} }
updateHovering(e); updateHovering(e);
@ -395,7 +438,7 @@ function buildObjectsList(filter = null, sort = null) {
element.addEventListener("mouseenter", function (e) { element.addEventListener("mouseenter", function (e) {
if (!fixed && !dragging) { if (!fixed && !dragging) {
objectsContainer.innerHTML = ""; objectsContainer.replaceChildren();
previousZoomOrigin = [zoomOrigin[0], zoomOrigin[1]]; previousZoomOrigin = [zoomOrigin[0], zoomOrigin[1]];
previousScaleZoomOrigin = [scaleZoomOrigin[0], scaleZoomOrigin[1]]; previousScaleZoomOrigin = [scaleZoomOrigin[0], scaleZoomOrigin[1]];
@ -432,10 +475,10 @@ function buildObjectsList(filter = null, sort = null) {
applyView(); applyView();
} }
if (document.documentElement.clientWidth < 500) { if (document.documentElement.clientWidth < 500) {
objectsContainer.innerHTML = ""; objectsContainer.replaceChildren();
entriesListShown = false; entriesListShown = false;
wrapper.className += " listHidden"; wrapper.classList.add("listHidden");
zoom = 4; zoom = 4;
renderBackground(atlas); renderBackground(atlas);
@ -503,7 +546,7 @@ function shuffle() {
function resetEntriesList() { function resetEntriesList() {
entriesOffset = 0; entriesOffset = 0;
entriesList.innerHTML = ""; entriesList.replaceChildren();
entriesList.appendChild(moreEntriesButton); entriesList.appendChild(moreEntriesButton);
buildObjectsList(filter = null, sort = null) buildObjectsList(filter = null, sort = null)
@ -624,7 +667,13 @@ function updateHovering(e, tapped) {
, (e.clientY - (container.clientHeight / 2 - innerContainer.clientHeight / 2 + zoomOrigin[1] + container.offsetTop)) / zoom , (e.clientY - (container.clientHeight / 2 - innerContainer.clientHeight / 2 + zoomOrigin[1] + container.offsetTop)) / zoom
]; ];
const coords_p = document.getElementById("coords_p"); const coords_p = document.getElementById("coords_p");
coords_p.innerText = Math.ceil(pos[0]) + ", " + Math.ceil(pos[1]);
// Displays coordinates as zero instead of NaN
if (isNaN(pos[0]) == true) {
coords_p.innerText = "0, 0";
} else {
coords_p.innerText = Math.ceil(pos[0]) + ", " + Math.ceil(pos[1]);
}
if (pos[0] <= 2200 && pos[0] >= -100 && pos[0] <= 2200 && pos[0] >= -100) { if (pos[0] <= 2200 && pos[0] >= -100 && pos[0] <= 2200 && pos[0] >= -100) {
const newHovered = []; const newHovered = [];
@ -652,7 +701,7 @@ function updateHovering(e, tapped) {
return calcPolygonArea(a.path) - calcPolygonArea(b.path); return calcPolygonArea(a.path) - calcPolygonArea(b.path);
}); });
objectsContainer.innerHTML = ""; objectsContainer.replaceChildren();
for (const i in hovered) { for (const i in hovered) {
const element = createInfoBlock(hovered[i]); const element = createInfoBlock(hovered[i]);
@ -662,13 +711,19 @@ function updateHovering(e, tapped) {
hovered[i].element = element; hovered[i].element = element;
} }
if (hovered.length > 0) { if (hovered.length > 0){
closeObjectsListButton.className = ""; document.getElementById("timeControlsSlider").blur();
closeObjectsListButton.classList.remove("d-none");
if ((objectsContainer.scrollHeight > objectsContainer.clientHeight) && !tapped) {
objectsListOverflowNotice.classList.remove("d-none");
} else {
objectsListOverflowNotice.classList.add("d-none");
}
} else { } else {
closeObjectsListButton.className = "hidden"; closeObjectsListButton.classList.add("d-none");
objectsListOverflowNotice.classList.add("d-none");
} }
render(); render();
} }
} }
@ -690,10 +745,27 @@ function highlightEntryFromUrl() {
if (entries.length === 1) { if (entries.length === 1) {
const entry = entries[0]; const entry = entries[0];
document.title = entry.name + " on the 2022 /r/place Atlas"; document.title = entry.name + " on the 2022 r/place Atlas";
if ((!entry.diff || entry.diff !== "delete")) {
if (document.getElementById("objectEditNav")) {
document.getElementById("objectEditNav").href = "./?mode=draw&id=" + id;
document.getElementById("objectEditNav").title = "Edit " + entry.name;
} else {
const objectEditNav = document.createElement("a");
objectEditNav.className = "btn btn-outline-primary";
objectEditNav.id = "objectEditNav";
objectEditNav.innerText = "Edit";
objectEditNav.href = "./?mode=draw&id=" + id;
objectEditNav.title = "Edit " + entry.name;
document.getElementById("showListButton").parentElement.appendChild(objectEditNav);
}
} else if (entry.diff == "delete" && document.getElementById("objectEditNav")) {
document.getElementById("objectEditNav").remove();
}
const infoElement = createInfoBlock(entry); const infoElement = createInfoBlock(entry);
objectsContainer.innerHTML = ""; objectsContainer.replaceChildren();
objectsContainer.appendChild(infoElement); objectsContainer.appendChild(infoElement);
//console.log(entry.center[0]); //console.log(entry.center[0]);
@ -719,7 +791,7 @@ function highlightEntryFromUrl() {
hovered = [entry]; hovered = [entry];
render(); render();
hovered[0].element = infoElement; hovered[0].element = infoElement;
closeObjectsListButton.className = ""; closeObjectsListButton.classList.remove("d-none");
updateLines(); updateLines();
fixed = true; fixed = true;
} }

View file

@ -15,92 +15,122 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head>
<meta charset="UTF-8">
<title>The 2022 r/place Atlas</title>
<meta name="description" content="An Atlas of Reddit's r/place, with information to each artwork of the canvas.">
<meta name="author" content="Roland Rytz">
<meta name="application-name" content="2022 r/place Atlas">
<meta name="robots" content="index, follow">
<head> <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1">
<meta charset="UTF-8"> <meta name="color-scheme" content="light dark">
<title>The 2022 /r/place Atlas</title>
<meta name="description" content="An Atlas of Reddit's /r/place, with information to each artwork of the canvas.">
<meta name="author" content="Roland Rytz">
<meta name="application-name" content="2022 /r/place Atlas">
<meta name="robots" content="index, follow">
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1"> <link rel="apple-touch-icon" href="_img/apple-touch-icon.png" sizes="180x180">
<meta name="color-scheme" content="dark"> <link rel="icon alternate" href="_img/favicon.png" type="image/png" class="js-site-favicon">
<link rel="icon" href="_img/favicon.svg" type="image/svg+xml" class="js-site-favicon">
<link rel="icon alternate" href="_img/favicon.png" type="image/png" class="js-site-favicon"> <link href="./_css/style.css" rel="stylesheet" type="text/css">
<link rel="icon" href="_img/favicon.svg" type="image/svg+xml" class="js-site-favicon">
<link href="./_css/style.css" rel="stylesheet" type="text/css" media="all"> <link href="https://cdn.jsdelivr.net/npm/bootstrap-dark-5@1.1.3/dist/css/bootstrap-dark.min.css" rel="stylesheet">
<script type="text/javascript" src="./_js/favicon.js" defer></script> <script type="text/javascript" src="./_js/favicon.js" defer></script>
</head>
</head> <body>
<nav class="navbar navbar-expand-md fixed-top bg-body border-bottom">
<body> <div class="container">
<div id="wrapper"> <a class="navbar-brand text-body" href="./">
<header class="aboutHeader"> <picture>
<a href="./"> <source srcset="./_img/favicon-dark.svg" media="(prefers-color-scheme: dark)">
<img id="logo" src="./_img/logo.svg" height="50" width="50" alt=""> <img class="d-inline-block align-text-top me-2" src="./_img/favicon.svg" height="32" width="32" alt="">
<h1>The 2022 /r/place Atlas</h1> </picture>
</a> The 2022 r/place Atlas
<!--nav>
<a id="viewLink" href="./" class="current">View</a>
<a id="drawLink" href="./?mode=draw">Draw</a>
<a id="aboutLink" href="./about.html">About</a>
</nav-->
</header>
<div id="author" style="right:25px">
Code by <a href="https://draemm.li/various/place-atlas/" target="_blank" rel="author">Roland Rytz</a>. Source on <a target="_blank" href="https://github.com/RolandR/place-atlas">GitHub</a> (<a target="_blank" href="https://github.com/Codixer/place-atlas">2022 Version Github</a>).
</div>
<div id="aboutContainer">
<div id="about">
<a id="aboutBackButton" class="button" href="./">&lt; Back to the Atlas</a>
<a href="https://www.netlify.com" id="netlifyBadges">
<img src="https://www.netlify.com/img/global/badges/netlify-color-bg.svg" alt="Deploys by Netlify" />
<img src="https://api.netlify.com/api/v1/badges/1e7291ce-0680-45ed-9843-47a32a992bbb/deploy-status" alt="Deploys by Netlify" />
</a> </a>
<h2 id="abouth2">The 2022 /r/place Atlas</h2> <button class="navbar-toggler text-body collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
<p>This is an Atlas aiming to chart all the artworks created during the <a href="https://www.reddit.com/r/place/">/r/place</a> April Fools event on <a href="https://www.reddit.com/" target="_blank">Reddit</a> in 2022.</p> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" class="bi bi-list" viewBox="0 0 16 16">
<p>The original code was developed by <a href="https://draemm.li/various/place-atlas/" target="_blank" rel="author">Roland Rytz</a> (<a href="mailto:roland.rytz@gmail.com" target="_blank">mail</a>, <a href="https://reddit.com/user/draemmli/" target="_blank">reddit</a>) and is available under the free <a href="https://www.gnu.org/licenses/agpl-3.0.en.html" target="_blank">AGPL license</a> on <a target="_blank" href="https://github.com/RolandR/place-atlas">GitHub</a>.</p> <path fill-rule="evenodd" d="M2.5 12a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5z"/>
<br> </svg>
<p>The currently maintained version of the website is managed by <a href="/" target="_blank" rel="author">Stefano Haagmans</a> and is obtainable under the same license within a <a target="_blank" href="https://github.com/placeAtlas/atlas">GitHub fork</a>. Images are provided by <a target="_blank" href="https://place.thatguyalex.com/">Alex Tsernoh</a>.</p> </button>
<p>Maintaining and updating the website takes work, but I enjoy doing it for free and giving this to people. But if you would like to support me, or the people who helped me with contributions to this project. You're free to support us though <a target="_blank" href="https://paypal.me/placeAtlas/5">PayPal</a>, <a target="_blank" href="https://www.patreon.com/placeAtlas">Patreon</a>, or <a target="_blank" href="https://ko-fi.com/placeatlas">Ko-Fi</a>.</p> <div class="navbar-collapse collapse" id="navbarCollapse">
<p>To maintain the same tradition, I will also be offering stickers to anyone donating more then 20$ (Due to the size increase). But, you're not forced to do anything! This only shows appreciation to us and the people who've worked on this project</p> <ul class="navbar-nav ms-auto pt-2 pt-md-0">
<br> <li class="nav-item">
<p>Roland Rytz worked on the Atlas full-time (and more!) for over two weeks during the 2017 r/place event.</p> <a class="nav-link" href="./">Atlas Map</a>
<p>If you'd like to support Roland, you can do so by <a target="_blank" href="https://paypal.me/draemmli">PayPal</a>.</p> </li>
<p>If you donate more than 10(€/$/CHF/mBTC), He'll (hopefully) send you a nice sticker of the 2017 Place canvas!</p> <li class="nav-item">
<a class="nav-link" href="https://place-wiki.stefanocoding.me/">Wiki</a>
<h2>Contributing</h2> </li>
<p>The Atlas relies on user contributions.</p> <li class="nav-item">
<p>To contribute a label for an artwork, please read <a href="https://www.reddit.com/r/placeAtlas2/comments/tu203o/how_to_contribute/" target="_blank">this post on Reddit</a> to learn how to submit a new entry.</p> <a class="nav-link active" href="#" aria-current="page">About</a>
<p>Alternatively, contributions can be made directly on <a href="https://github.com/placeAtlas/atlas/blob/master/CONTRIBUTING.md">GitHub</a>.</p> </li>
<p>The <a href="https://reddit.com/r/placeAtlas2/" target="_blank">/r/placeAtlas2</a> subreddit is also the place to submit all bug reports, feature requests or questions.</p> </ul>
<h2>Current Contributors and Maintainers</h2>
<div id="contributors">
<a href="https://reddit.com/user/TCOOfficiall" target="_blank">TCOOfficiall (current maintainer)</a> ·
<a href="https://reddit.com/user/prosto_sanja" target="_blank">prosto_sanja (images)</a> <a href="https://place.thatguyalex.com/" target="_blank">(website)</a> ·
<a href="https://reddit.com/user/electric-blue" target="_blank">electric-blue</a> ·
<a href="https://reddit.com/user/m654zy" target="_blank">m654zy</a> ·
<a href="https://reddit.com/user/xXLInkster17Xx" target="_blank">xXLInkster17Xx</a>
</div> </div>
<p>The 2022 Atlas would not have been possible without the help of our Reddit contributors. This section will be updated with all of the contributor's usernames.</p>
<p>Thank you to everyone who submitted new entries, amended existing ones, reported bugs and just supported the project in general.</p>
<h2 id="contacth2">Contact?</h2>
<p>If you're press, a influencer or anything media connected, or you would like to use the atlas in one. Please contact us beforehand through:</p>
<p> - <a href="mailto:press@stefanocoding.me" target="_blank">press@stefanocoding.me</a></p>
<br>
<p>If you need to contact me regarding anything else, you can reach me through:</p>
<p> - <a href="mailto:stefano@stefanocoding.me" target="_blank">stefano@stefanocoding.me</a></p>
</div> </div>
</div> </nav>
</div> <main class="pt-5">
</div> <div class="container py-4">
</body> <div class="row g-5">
<div class="col-md-7 col-xl-8">
<h1 class="display-5 fw-bold">The 2022 r/place Atlas</h2>
<p>This is an Atlas aiming to chart all the artworks created during the <a href="https://www.reddit.com/r/place/">r/place</a> April Fools event on Reddit in 2022.</p>
<p>The original code was developed by <a href="https://draemm.li/various/place-atlas/" target="_blank" rel="noopener noreferrer">Roland Rytz</a> (<a href="mailto:roland.rytz@gmail.com">mail</a>, <a href="https://reddit.com/user/draemmli/" target="_blank" rel="noopener noreferrer">reddit</a>) and is available under the free <a href="https://www.gnu.org/licenses/agpl-3.0.en.html" target="_blank" rel="noopener noreferrer">AGPL license</a> on <a href="https://github.com/RolandR/place-atlas" target="_blank" rel="noopener noreferrer">GitHub</a>.</p>
<hr>
<p>The currently maintained version of the website is managed by Stefano Haagmans and is obtainable under the same license within a <a href="https://github.com/placeAtlas/atlas" target="_blank" rel="noopener noreferrer">GitHub fork</a>. Images are provided by <a href="https://place.thatguyalex.com/">Alex Tsernoh</a>.</p>
<p>Maintaining and updating the website takes work, but I enjoy doing it for free and giving this to people. But if you would like to support me, or the people who helped me with contributions to this project. You're free to support us though <a href="https://paypal.me/placeAtlas/5" target="_blank" rel="noopener noreferrer">PayPal</a>, <a href="https://www.patreon.com/placeAtlas" target="_blank" rel="noopener noreferrer">Patreon</a>, or <a href="https://ko-fi.com/placeatlas" target="_blank" rel="noopener noreferrer">Ko-Fi</a>.</p>
<p>To maintain the same tradition, I will also be offering stickers to anyone donating more then 20$ (Due to the size increase). But, you're not forced to do anything! This only shows appreciation to us and the people who've worked on this project</p>
<p>Roland Rytz worked on the Atlas full-time (and more!) for over two weeks during the 2017 r/place event. If you'd like to support Roland, you can do so by <a href="https://paypal.me/draemmli" target="_blank" rel="noopener noreferrer">PayPal</a>. If you donate more than 10(€/$/CHF/mBTC), He'll (hopefully) send you a nice sticker of the 2017 Place canvas!</p>
<h2>Contributing</h2>
<p>The Atlas relies on user contributions.</p>
<p>To contribute a label for an artwork, please read <a href="https://www.reddit.com/r/placeAtlas2/comments/tu203o/how_to_contribute/" target="_blank" rel="noopener noreferrer">this post on Reddit</a> to learn how to submit a new entry. Alternatively, contributions can be made directly on <a href="https://github.com/placeAtlas/atlas/blob/master/CONTRIBUTING.md">GitHub</a>.</p>
<p>The <a href="https://reddit.com/r/placeAtlas2/" target="_blank" rel="noopener noreferrer">r/placeAtlas2</a> subreddit is also the place to submit all bug reports, feature requests or questions.</p>
<h2>Contributors and Maintainers</h2>
<ul>
<li>Current maintainer: <a href="https://reddit.com/user/TCOOfficiall" target="_blank" rel="noopener noreferrer">TCOOfficiall</a></li>
<li>Images: <a href="https://reddit.com/user/prosto_sanja" target="_blank" rel="noopener noreferrer">prosto_sanja</a> (<a href="https://place.thatguyalex.com/" target="_blank" rel="noopener noreferrer">website</a>)</li>
<li>Contributor: <a href="https://reddit.com/user/electric-blue" target="_blank" rel="noopener noreferrer">electric-blue</a></li>
<li>Contributor: <a href="https://reddit.com/user/m654zy" target="_blank" rel="noopener noreferrer">m654zy</a></li>
<li>Contributor: <a href="https://reddit.com/user/xXLInkster17Xx" target="_blank" rel="noopener noreferrer">xXLInkster17Xx</a></li>
</ul>
<p>The 2022 Atlas would not have been possible without the help of our Reddit contributors. This section will be updated with all of the contributor's usernames.</p>
<p>Thank you to everyone who submitted new entries, amended existing ones, reported bugs and just supported the project in general.</p>
</div>
<div class="col-md-5 col-xl-4">
<div class="position-sticky" style="top: 5rem;">
<div class="p-4 mb-3 bg-secondary bg-opacity-10 rounded">
<h4>Contact?</h4>
<p>If you're press, a influencer or anything media connected, or you would like to use the atlas in one. Please contact us beforehand through:</p>
<ul>
<li><a href="mailto:press@stefanocoding.me">press@stefanocoding.me</a></li>
</ul>
<p>If you need to contact me regarding anything else, you can reach me through:</p>
<ul>
<li><a href="mailto:stefano@stefanocoding.me">stefano@stefanocoding.me</a></li>
</ul>
</div>
<div class="p-4">
<h4>Sponsor this project</h4>
<p>Current 2022 Atlas Maintainers:</p>
<ul class="mb-0">
<li><a href="https://paypal.me/placeAtlas/5">PayPal</a></li>
<li><a href="https://www.patreon.com/placeAtlas">Patreon</a></li>
<li><a href="https://ko-fi.com/placeatlas">Ko-Fi</a></li>
</ul>
</div>
<div class="p-4">
<h4>Deployment</h4>
<p>Site powered by Netlify.</p>
<a class="d-flex flex-wrap justify-content-left gap-2" href="https://www.netlify.com" target="_blank" rel="noopener">
<img src="https://www.netlify.com/img/global/badges/netlify-color-bg.svg" alt="Deploys by Netlify" />
<img src="https://api.netlify.com/api/v1/badges/1e7291ce-0680-45ed-9843-47a32a992bbb/deploy-status" type="image/svg+xml" alt="Netlify status" />
</a>
</div>
</div>
</div>
</div>
<footer class="pt-3 mt-4 text-muted border-top">
Code by <a href="https://draemm.li/various/place-atlas/" target="_blank" rel="noopener noreferrer author">Roland Rytz</a>. Source on <a href="https://github.com/RolandR/place-atlas" target="_blank" rel="noopener noreferrer">GitHub</a> (<a href="https://github.com/placeAtlas/atlas" target="_blank" rel="noopener noreferrer">2022 Version Github</a>).
</footer>
</div>
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
</body>
</html> </html>

View file

@ -15,355 +15,449 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head>
<meta charset="UTF-8">
<title>The 2022 r/place Atlas</title>
<meta name="description" content="An interactive map of Reddit's 2022 r/place, with information to each artwork of the canvas.">
<meta name="author" content="Roland Rytz (2022 by Stefano#7366)">
<meta name="application-name" content="The r/place Atlas 2022">
<meta name="robots" content="index, follow">
<head> <meta property="og:title" content="The 2022 r/place Atlas">
<meta charset="UTF-8"> <meta property="og:type" content="website">
<title>The 2022 /r/place Atlas</title> <meta property="og:url" content="https://place-atlas.stefanocoding.me/">
<meta name="description" content="An interactive map of Reddit's 2022 /r/place, with information to each artwork of the canvas."> <meta property="og:image" content="https://place-atlas.stefanocoding.me/_img/logo.png">
<meta name="author" content="Place Atlas contributors"> <meta property="og:image:type" content="image/png">
<meta name="application-name" content="The /r/place Atlas 2022"> <meta property="og:image:width" content="512">
<meta name="robots" content="index, follow"> <meta property="og:image:height" content="512">
<meta property="og:image:alt" content="The r/place Atlas logo">
<meta property="og:description" content="An interactive map of Reddit's 2022 r/place, with information to each artwork of the canvas.">
<meta property="og:title" content="The 2022 /r/place Atlas"> <!-- <meta name="google-site-verification" content="gZGHpBSMzffAbIn0qB8b00We6EwSGkDTfDoQVv-NWss"/> -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://place-atlas.stefanocoding.me/">
<meta property="og:image" content="https://place-atlas.stefanocoding.me/_img/logo.png">
<meta property="og:image:type" content="image/png">
<meta property="og:image:width" content="512">
<meta property="og:image:height" content="512">
<meta property="og:image:alt" content="The /r/place Atlas logo">
<meta property="og:description" content="An interactive map of Reddit's 2022 /r/place, with information to each artwork of the canvas.">
<!-- <meta name="google-site-verification" content="gZGHpBSMzffAbIn0qB8b00We6EwSGkDTfDoQVv-NWss"/> --> <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, minimum-scale=1, maximum-scale=1, shrink-to-fit=no"> <!-- user-scalable=no -->
<meta name="mobile-web-app-capable" content="yes">
<meta name="color-scheme" content="light dark">
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, minimum-scale=1, maximum-scale=1, shrink-to-fit=no"> <!-- user-scalable=no --> <link rel="apple-touch-icon" href="_img/apple-touch-icon.png" sizes="180x180">
<meta name="mobile-web-app-capable" content="yes"> <link rel="icon alternate" href="_img/favicon.png" type="image/png" class="js-site-favicon">
<meta name="color-scheme" content="dark"> <link rel="icon" href="_img/favicon.svg" type="image/svg+xml" class="js-site-favicon">
<link rel="apple-touch-icon" href="_img/apple-touch-icon.png" sizes="180x180"> <link rel="stylesheet" href="./_css/style.css" type="text/css">
<link rel="icon alternate" href="_img/favicon.png" type="image/png" class="js-site-favicon"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-dark-5@1.1.3/dist/css/bootstrap-dark.min.css">
<link rel="icon" href="_img/favicon.svg" type="image/svg+xml" class="js-site-favicon"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css">
<link href="./_css/style.css" rel="stylesheet" type="text/css" media="all"> <link rel="manifest" href="./manifest.webmanifest">
<link rel="manifest" href="./manifest.webmanifest">
<script type="text/javascript" src="./_js/favicon.js" defer></script> <script type="text/javascript" src="./_js/favicon.js" defer></script>
<script type="application/ld+json"> <script type="application/ld+json">
{ {
"@context": "http://schema.org", "@context": "https://schema.org",
"@type": "WebSite", "@type": "WebSite",
"name": "The 2022 /r/place Atlas", "name": "The 2022 r/place Atlas",
"url": "http://place-atlas.stefanocoding.me/", "url": "https://place-atlas.stefanocoding.me/",
"author": [ "author": [
{ {
"@type": "Person", "@type": "Person",
"name": "Roland Rytz", "name": "Roland Rytz",
"email": "roland.rytz@gmail.com", "email": "roland.rytz@gmail.com",
"url": "https://draemm.li", "url": "https://draemm.li",
"familyName": "Rytz", "familyName": "Rytz",
"givenName": "Roland", "givenName": "Roland",
"alternateName": "draemmli", "alternateName": "draemmli",
"gender": "Male", "gender": "Male",
"nationality": "Switzerland" "nationality": "Switzerland"
}, },
{ {
"@type": "Person", "@type": "Person",
"name": "Stefano Haagmans", "name": "Stefano Haagmans",
"email": "stefano@stefanocoding.me", "email": "stefano@stefanocoding.me",
"url": "https://stefanocoding.me/", "url": "https://stefanocoding.me",
"familyName": "Haagmans", "familyName": "Haagmans",
"givenName": "Stefano", "givenName": "Stefano",
"alternateName": "Codixer", "alternateName": "Codixer",
"gender": "Male", "gender": "Male",
"nationality": "Netherlands" "nationality": "Netherlands"
}, },
{ {
"@type": "Organization", "@type": "Organization",
"name": "Place Atlas", "name": "Place Atlas",
"alternateName": "r/placeatlas2", "alternateName": "r/placeatlas2",
"url": "https://github.com/placeAtlas", "url": "https://github.com/placeAtlas",
"image": "http://place-atlas.stefanocodsing.me/_img/logo.png", "image": "http://place-atlas.stefanocoding.me/_img/logo.png",
"founder": { "founder": {
"@type": "Person", "@type": "Person",
"@id": "#Codixer", "@id": "#Codixer",
"name": "Stefano Haagmans", "name": "Stefano Haagmans",
"email": "stefano@stefanocoding.me", "email": "stefano@stefanocoding.me",
"url": "https://stefanocoding.me/", "url": "https://stefanocoding.me/",
"familyName": "Haagmans", "familyName": "Haagmans",
"givenName": "Stefano", "givenName": "Stefano",
"alternateName": "Codixer", "alternateName": "Codixer",
"gender": "Male", "gender": "Male",
"nationality": "Netherlands" "nationality": "Netherlands"
}
} }
} ],
], "copyrightYear": 2017,
"copyrightYear": 2017, "license": "https://place-atlas.stefanocoding.me/license.txt",
"license": "https://place-atlas.stefanocoding.me/license.txt", "inLanguage": "English",
"inLanguage": "English", "isAccessibleForFree": true,
"isAccessibleForFree": true, "keywords": "reddit, r/place, place, experiment",
"keywords": "reddit, /r/place, place, experiment", "thumbnailUrl": "https://place-atlas.stefanocoding.me/_img/logo.png",
"thumbnailUrl": "http://place-atlas.stefanocoding.me/_img/logo.png", "image": "https://place-atlas.stefanocoding.me/_img/logo.png",
"image": "http://place-atlas.stefanocoding.me/_img/logo.png", "description": "An interactive map of Reddit's 2022 r/place, with information to each artwork of the canvas."
"description": "An interactive map of Reddit's 2022 /r/place, with information to each artwork of the canvas." }
} </script>
</script> </head>
</head> <body>
<div id="wrapper" class="listHidden">
<body> <nav id="main-navbar" class="navbar navbar-expand-md fixed-top bg-body border-bottom">
<div id="wrapper"> <div class="container-fluid">
<header> <a class="navbar-brand text-body" href="./">
<a href="./"> <picture>
<img id="logo" src="./_img/logo.svg" height="50" width="50" alt="Logo"> <source srcset="./_img/favicon-dark.svg" media="(prefers-color-scheme: dark)">
<!-- If you wonder why I shrink the image in html, <img class="d-inline-block align-text-top me-2" src="./_img/favicon.svg" height="32" width="32" alt="">
it's because this is the image that will be used </picture>
by reddit and the like as the thumbnail for the site. The 2022 r/place Atlas
The original is only 5.9kB, which wouldn't get much <span class="badge bg-warning text-dark d-none d-md-inline-block">Beta</span>
smaller by reducing the actualy size. --> </a>
<h1 id="title">The 2022 /r/place Atlas</h1> <button class="navbar-toggler text-body collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
</a> <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" class="bi bi-list" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M2.5 12a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5z"/>
</header> </svg>
</button>
<div id="container"> <div class="collapse navbar-collapse" id="navbarCollapse">
<div id="loading"> <ul class="navbar-nav me-auto my-2 my-md-0">
<div id="loadingContent"> <li class="nav-item">
<div></div><br> <div class="btn-group" role="group">
<span>&nbsp;&nbsp;Hang on...</span> <button id="showListButton" class="btn btn-outline-primary" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasList" aria-controls="offcanvasList">Entries List</button>
<noscript> </div>
<p>Sorry, you need JavaScript to view the Atlas.</p> </li>
<p>All JavaScript on this site is licensed under either the MIT or AGPL license.</p> </ul>
<p><a href="https://github.com/placeAtlas/atlas">See the source on GitHub</a></p> <ul class="navbar-nav mx-auto d-block d-md-none d-lg-block">
</noscript> <li class="nav-item d-flex align-items-center gap-2">
</div> <span class="p-2">Coordinates: <span class="badge bg-secondary" id="coords_p">0, 0</span></span>
</div> </li>
<canvas id="linesCanvas"></canvas> </ul>
<div id="innerContainer"> <hr class="d-md-none">
<canvas id="highlightCanvas" width="2000" height="2000"></canvas> <ul class="navbar-nav flex-row flex-wrap ms-auto">
<li class="nav-item col-6 col-md-auto">
<img id="image" width="2000" height="2000" alt="Canvas of /r/place in the state of when the experiment was concluded." /> <a class="nav-link active" href="./" aria-current="page">Atlas Map</a>
</div> </li>
</div> <li class="nav-item col-6 col-md-auto">
<a class="nav-link" href="https://place-wiki.stefanocoding.me/">Wiki</a>
<div id="entriesListContainer"> </li>
<nav id="entriesListNav"> <li class="nav-item col-6 col-md-auto">
<a id="aboutLink" href="./about.html" class="button">About</a> <a class="nav-link" href="./about.html">About</a>
<a id="drawLink" href="./index.html?mode=draw" class="button">Draw</a> </li>
<div class="dropdown button" id="viewModes"> <li>
<span>Modes</span> <a class="nav-link px-3 bg-warning text-dark d-md-none rounded" href="https://github.com/placeAtlas/atlas/issues">Beta</a>
<span class="buffer"></span> </li>
<div class="dropdown-content"> </ul>
<a href="./">Normal</a>
<a href="./?mode=explore">Explore</a>
<a href="./?mode=overlap">Overlap</a>
<a href="./?mode=diff" class="show-only-on-dev">With Diff</a>
<a href="./?mode=diffonly" class="show-only-on-dev">Diff Only</a>
</div> </div>
</div> </div>
<a title="Discord" href="https://discord.gg/pJkm23b2nA" class="button small" id="entriesListDiscord">
<svg xmlns="http://www.w3.org/2000/svg" width="71" height="55" viewBox="0 0 71 55">
<path fill="#FFF" d="M60 5a59 59 0 0 0-15-4l-1 3H27a37 37 0 0 0-2-4 58 58 0 0 0-14 5A60 60 0 0 0 0 46a59 59 0 0 0 18 8l4-5v-1l-6-2v-1a30 30 0 0 0 2-1 42 42 0 0 0 36 0l1 1v1l-6 2v1a47 47 0 0 0 4 6 59 59 0 0 0 18-10A60 60 0 0 0 60 5ZM24 37c-4 0-7-3-7-7s3-7 7-7c3 0 6 3 6 7s-3 7-6 7Zm23 0c-3 0-6-3-6-7s3-7 6-7c4 0 7 3 7 7s-3 7-7 7Z" / alt="Discord">
</svg>
</a>
<button title="Donate!" id="entriesListDonate" class="small">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
<path d="M291 384c-1-6-6-8-13-9v-9h-5v9h-4v-9h-6v9h-10v6h3c3 0 3 1 3 2v10h1-1v14c0 1 0 2-2 2h-3l-1 6h10v9h6v-9h4v9h5v-9c9 0 15-3 16-11 1-7-3-10-8-11 3-1 5-4 5-9zm-7 19c0 7-12 6-15 6v-12c3 0 15-1 15 6zm-3-16c0 6-9 5-12 5v-11c3 0 12-1 12 6z" style="fill:#fff" transform="translate(-239 -363)" / alt="Donate">
</svg>
</button>
</nav> </nav>
<div id="entriesListControls"> <div id="container">
<input autofocus id="searchList" type="text" placeholder="Search..."> <div id="loading" class="d-flex justify-content-center">
<span id="atlasSize"></span> <div id="loadingContent" class="my-auto mx-3 text-center text-white">
<div id="sortContainer"><label>Sort:</label> <div class="spinner-border text-warning mb-3" style="width: 5rem; height: 5rem;" role="status">
<select id="sort"> <span class="visually-hidden">Loading...</span>
<option value="shuffle">Random</option> </div>
<option value="relevant" id="relevantOption" disabled>Relevant</option> <h4 class="mb-3">Hang on…</h4>
<option value="alphaAsc">↓ Alphabetical</option> <noscript>
<option value="alphaDesc">↑ Alphabetical</option> <p>Sorry, you need JavaScript to view the Atlas.</p>
<option value="newest">Newest</option> <p>All JavaScript on this site is licensed under either the MIT or AGPL license.</p>
<option value="oldest">Oldest</option> <p><a href="https://github.com/placeAtlas/atlas">See the source on GitHub</a></p>
<option value="area">Area</option> </noscript>
</select>
</div>
</div>
<div id="entriesList">
</div>
</div>
<div id="entriesListBackground"></div>
<button id="hideListButton" aria-label:="Show List Button"></button>
<div id="coordsWrapper" class="collapsed">
<div id="coords">
<p id="coords_p">0, 0</p>
</div>
</div>
<div id="bottomBar">
<div id="zoomControls">
<button title="Zoom In" id="zoomInButton"></button>
<button title="Reset View" id="zoomResetButton"></button>
<button title="Zoom Out" id="zoomOutButton"></button>
</div>
<div id="timeControls">
<div id="timeControlsTooltip">
<p>Time control slider</p>
</div>
<input type="range" min="0" max="1" value="1" class="slider" id="timeControlsSlider">
</div>
<div id="variantControls">
<select name="variants" id="variants">
</select>
</div>
<div id="author">
<p>Code owned by <a href="https://github.com/placeAtlas/atlas" target="_blank" rel="author">Place Atlas</a>. Source on <a target="_blank" href="https://github.com/placeAtlas/atlas">GitHub</a>. Site powered by <a href="https://www.netlify.com">Netlify</a>. Images provided by <a target="_blank" href="https://place.thatguyalex.com/">Alex Tsernoh</a>.</p>
</div>
</div>
<div id="drawControlsContainer">
<a id="drawBackButton" class="button" href="./">&lt; Back to the Atlas</a>
<div id="drawControls">
<div id="objectDraw">
<div class="inline">
<button id="undoButton" disabled>Undo</button>
<button disabled id="redoButton">Redo</button>
</div> </div>
<button disabled id="finishButton">Finish (Enter)</button> </div>
<button id="resetButton">Reset</button> <canvas id="linesCanvas"></canvas>
<label id="highlightUnchartedLabel" title="Highlight uncharted areas of the map" class="checkboxLabel button"> <div id="innerContainer">
<input type="checkbox" id="highlightUncharted" checked> Highlight Empty <canvas id="highlightCanvas" width="2000" height="2000"></canvas>
</label>
<div id="periods"> <img id="image" width="2000" height="2000" alt="" />
<p>Periods</p> </div>
<p id="periodsStatus"></p> </div>
<div class="offcanvas offcanvas-start bg-body" data-bs-scroll="true" data-bs-backdrop="false" tabindex="-1" id="offcanvasList" aria-labelledby="offcanvasListLabel">
<header class="offcanvas-header py-2 border-bottom">
<div class="d-flex align-items-center py-1">
<h5 class="offcanvas-title" id="offcanvasListLabel">Atlas Entries List</h5>
</div>
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</header>
<div class="py-3 mx-3 border-bottom">
<div class="d-flex gap-2 mb-2">
<a class="btn btn-primary w-50" id="drawLink" href="./?mode=draw">Draw</a>
<button type="button" class="btn btn-primary dropdown-toggle w-50" id="dropdownModes" data-bs-toggle="dropdown" aria-expanded="false">Modes</button>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="dropdownModes">
<li><a class="dropdown-item" href="./">Normal</a></li>
<li><a class="dropdown-item" href="./?mode=explore">Explore</a></li>
<li><a class="dropdown-item" href="./?mode=overlap">Overlap</a></li>
<li><hr class="dropdown-divider show-only-on-dev"></li>
<li><a class="dropdown-item show-only-on-dev" href="./?mode=diff" title="View normal mode with diff">With Diff</a></li>
<li><a class="dropdown-item show-only-on-dev" href="./?mode=diffonly" title="View only diff">Diff Only</a></li>
</ul>
</div>
<div class="btn-group w-100 mb-3" role="group" aria-label="Social links and donate button">
<a class="btn btn-outline-primary" href="https://discord.gg/pJkm23b2nA" target="_blank" rel="noopener noreferrer">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-discord" viewBox="0 0 16 16"><path d="M13.545 2.907a13.227 13.227 0 0 0-3.257-1.011.05.05 0 0 0-.052.025c-.141.25-.297.577-.406.833a12.19 12.19 0 0 0-3.658 0 8.258 8.258 0 0 0-.412-.833.051.051 0 0 0-.052-.025c-1.125.194-2.22.534-3.257 1.011a.041.041 0 0 0-.021.018C.356 6.024-.213 9.047.066 12.032c.001.014.01.028.021.037a13.276 13.276 0 0 0 3.995 2.02.05.05 0 0 0 .056-.019c.308-.42.582-.863.818-1.329a.05.05 0 0 0-.01-.059.051.051 0 0 0-.018-.011 8.875 8.875 0 0 1-1.248-.595.05.05 0 0 1-.02-.066.051.051 0 0 1 .015-.019c.084-.063.168-.129.248-.195a.05.05 0 0 1 .051-.007c2.619 1.196 5.454 1.196 8.041 0a.052.052 0 0 1 .053.007c.08.066.164.132.248.195a.051.051 0 0 1-.004.085 8.254 8.254 0 0 1-1.249.594.05.05 0 0 0-.03.03.052.052 0 0 0 .003.041c.24.465.515.909.817 1.329a.05.05 0 0 0 .056.019 13.235 13.235 0 0 0 4.001-2.02.049.049 0 0 0 .021-.037c.334-3.451-.559-6.449-2.366-9.106a.034.034 0 0 0-.02-.019Zm-8.198 7.307c-.789 0-1.438-.724-1.438-1.612 0-.889.637-1.613 1.438-1.613.807 0 1.45.73 1.438 1.613 0 .888-.637 1.612-1.438 1.612Zm5.316 0c-.788 0-1.438-.724-1.438-1.612 0-.889.637-1.613 1.438-1.613.807 0 1.451.73 1.438 1.613 0 .888-.631 1.612-1.438 1.612Z"></path></svg>
Discord
</a>
<a class="btn btn-outline-primary" href="https://www.reddit.com/r/placeAtlas2/" target="_blank" rel="noopener noreferrer">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-reddit" viewBox="0 0 16 16"><path d="M6.167 8a.831.831 0 0 0-.83.83c0 .459.372.84.83.831a.831.831 0 0 0 0-1.661zm1.843 3.647c.315 0 1.403-.038 1.976-.611a.232.232 0 0 0 0-.306.213.213 0 0 0-.306 0c-.353.363-1.126.487-1.67.487-.545 0-1.308-.124-1.671-.487a.213.213 0 0 0-.306 0 .213.213 0 0 0 0 .306c.564.563 1.652.61 1.977.61zm.992-2.807c0 .458.373.83.831.83.458 0 .83-.381.83-.83a.831.831 0 0 0-1.66 0z"/><path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.828-1.165c-.315 0-.602.124-.812.325-.801-.573-1.9-.945-3.121-.993l.534-2.501 1.738.372a.83.83 0 1 0 .83-.869.83.83 0 0 0-.744.468l-1.938-.41a.203.203 0 0 0-.153.028.186.186 0 0 0-.086.134l-.592 2.788c-1.24.038-2.358.41-3.17.992-.21-.2-.496-.324-.81-.324a1.163 1.163 0 0 0-.478 2.224c-.02.115-.029.23-.029.353 0 1.795 2.091 3.256 4.669 3.256 2.577 0 4.668-1.451 4.668-3.256 0-.114-.01-.238-.029-.353.401-.181.688-.592.688-1.069 0-.65-.525-1.165-1.165-1.165z"/></svg>
Reddit
</a>
<button type="button" title="Donation links" class="btn btn-outline-primary" data-bs-toggle="modal" data-bs-target="#donateModal">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-currency-exchange" viewBox="0 0 16 16">
<path d="M0 5a5.002 5.002 0 0 0 4.027 4.905 6.46 6.46 0 0 1 .544-2.073C3.695 7.536 3.132 6.864 3 5.91h-.5v-.426h.466V5.05c0-.046 0-.093.004-.135H2.5v-.427h.511C3.236 3.24 4.213 2.5 5.681 2.5c.316 0 .59.031.819.085v.733a3.46 3.46 0 0 0-.815-.082c-.919 0-1.538.466-1.734 1.252h1.917v.427h-1.98c-.003.046-.003.097-.003.147v.422h1.983v.427H3.93c.118.602.468 1.03 1.005 1.229a6.5 6.5 0 0 1 4.97-3.113A5.002 5.002 0 0 0 0 5zm16 5.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0zm-7.75 1.322c.069.835.746 1.485 1.964 1.562V14h.54v-.62c1.259-.086 1.996-.74 1.996-1.69 0-.865-.563-1.31-1.57-1.54l-.426-.1V8.374c.54.06.884.347.966.745h.948c-.07-.804-.779-1.433-1.914-1.502V7h-.54v.629c-1.076.103-1.808.732-1.808 1.622 0 .787.544 1.288 1.45 1.493l.358.085v1.78c-.554-.08-.92-.376-1.003-.787H8.25zm1.96-1.895c-.532-.12-.82-.364-.82-.732 0-.41.311-.719.824-.809v1.54h-.005zm.622 1.044c.645.145.943.38.943.796 0 .474-.37.8-1.02.86v-1.674l.077.018z"/>
</svg>
Donate
</button>
</div>
<div id="entriesListControls" class="d-flex flex-column gap-2 p-3 bg-secondary bg-opacity-10 rounded">
<span id="atlasSize"></span>
<input autofocus class="form-control" id="searchList" type="search" placeholder="Search…" autocomplete="off" spellcheck="false" aria-describedby="atlasSize">
<div class="d-flex align-items-center gap-2">
<label for="sort">Sort:</label>
<select class="form-select" id="sort" title="Sort entries">
<option selected value="shuffle">Random</option>
<option value="relevant" id="relevantOption" disabled>Relevant</option>
<option value="alphaAsc" label="↓ Alphabetical">Descending Alphabetical</option>
<option value="alphaDesc" label="↑ Alphabetical">Ascending Alphabetical</option>
<option value="newest">Newest</option>
<option value="oldest">Oldest</option>
<option value="area">Area</option>
</select>
</div>
</div>
</div>
<div id="entriesList" class="card-deck ps-2 ms-2 pe-3 me-3 mt-2 pt-2 overflow-auto"></div>
</div>
<div id="bottomBar" class="d-flex flex-wrap gap-2 p-2">
<div id="zoomControls" class="btn-group shadow" role="group" aria-label="Zoom controls">
<button type="button" class="btn btn-secondary" id="zoomInButton" title="Zoom in">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-plus-lg" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8 2a.5.5 0 0 1 .5.5v5h5a.5.5 0 0 1 0 1h-5v5a.5.5 0 0 1-1 0v-5h-5a.5.5 0 0 1 0-1h5v-5A.5.5 0 0 1 8 2Z"/>
</svg>
</button>
<button type="button" class="btn btn-secondary" id="zoomResetButton" title="Reset view">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-square" viewBox="0 0 16 16">
<path d="M14 1a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h12zM2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2z"/>
</svg>
</button>
<button type="button" class="btn btn-secondary" id="zoomOutButton" title="Zoom out">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-dash-lg" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M2 8a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11A.5.5 0 0 1 2 8Z"/>
</svg>
</button>
</div>
<div id="variantControls">
<div class="input-group">
<span class="input-group-text">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 192 192" aria-hidden="true"><polygon points="154 0 154 38 39 38 39 192 0 192 0 0"></polygon><polygon points="192 38 192 192 77 192 77 153 154 153 154 38"></polygon><rect x="77" y="77" width="38" height="38"></rect></svg>
</span>
<select class="form-select shadow" name="variants" id="variants" title="Background image variants"></select>
</div>
</div>
<div id="timeControls" class="bg-body px-2 py-1 border rounded shadow">
<label for="timeControlsSlider" class="visually-hidden">Time control slider</label>
<input type="range" class="form-range" min="1" max="1" value="1" id="timeControlsSlider" aria-describedby="timeControlsTooltip"></input>
<div class="tooltip border rounded text-nowrap" role="tooltip" id="timeControlsTooltip"><div class="bg-body rounded p-1">Tooltip</div></div>
</div>
<div id="author" class="bg-body d-flex align-items-center justify-content-center py-1 px-2 rounded shadow" style="--bs-bg-opacity: .9;">
<span style="font-size: 0.75rem;">Code owned by <a href="https://github.com/placeAtlas" target="_blank" rel="noopener noreferrer">Place Atlas</a>. Source on <a href="https://github.com/placeAtlas/atlas" target="_blank" rel="noopener noreferrer">GitHub</a>. Site powered by <a href="https://www.netlify.com" target="_blank" rel="noopener noreferrer">Netlify</a>.</span>
</div>
</div>
<div class="offcanvas offcanvas-start bg-body" data-bs-scroll="true" data-bs-backdrop="false" tabindex="-1" id="offcanvasDraw" aria-labelledby="offcanvasDrawLabel">
<header class="offcanvas-header py-2 border-bottom">
<div class="d-flex align-items-center py-1">
<h5 class="offcanvas-title" id="offcanvasDrawLabel">Edit Entry</h5>
</div>
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</header>
<div class="offcanvas-body" id="offcanvasDraw-drawControls">
<div id="drawControls" class="d-flex flex-column gap-2 p-3 pb-2 mb-3 bg-secondary bg-opacity-10 rounded">
<h5>Draw</h5>
<div class="d-flex gap-2">
<button type="button" class="btn btn-secondary flex-fill" id="undoButton" title="Undo line [ctrl-z]" disabled>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-counterclockwise" viewBox="0 0 16 16" aria-hidden="true"><path fill-rule="evenodd" d="M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.417A6 6 0 1 0 8 2v1z"/><path d="M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466z"/></svg>
Undo
</button>
<button type="button" class="btn btn-secondary flex-fill" id="redoButton" title="Redo line [ctrl-y]" disabled>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-clockwise" viewBox="0 0 16 16" aria-hidden="true"><path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z"/><path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z"/></svg>
Redo
</button>
</div>
<button type="button" class="btn btn-primary" id="finishButton" title="Finish drawing [enter]" disabled>Finish</button>
<button type="button" class="btn btn-secondary" id="resetButton">Reset</button>
<div class="form-check" id="highlightUnchartedLabel">
<input class="form-check-input" type="checkbox" id="highlightUncharted" checked>
<label class="form-check-label mb-0" for="highlightUncharted" title="Highlight uncharted areas of the map">
Highlight Empty
</label>
</div>
</div>
<div id="periods" class="p-2 pt-3 mb-3 bg-secondary bg-opacity-10 rounded">
<h5 class="px-2">Timeline</h5>
<p id="periodsStatus" class="px-2"></p>
<div id="periodGroups"></div> <div id="periodGroups"></div>
<button id="periodsAdd">Add Period</button> <button type="button" class="btn btn-primary d-block mx-auto" id="periodsAdd">Add Period</button>
</div>
<div id="hint">
<p>Please read <a href="https://www.reddit.com/r/placeAtlas2/comments/tu203o/how_to_contribute/" target="_blank" rel="noopener noreferrer">this Reddit post</a> for instructions.</p>
<hr>
<p>You can suggest new entries to the Atlas for art that isn't mapped yet.</p>
<p>Click anywhere on the image to start drawing a shape. When you're happy with the result, click the "Finish" button above or press the Enter key.</p>
<p>You can then add more information about your object.</p>
<hr>
<div class="text-white p-3 rounded shadow" style="background-color: #5865F2;">
<h6>Need Help?</h6>
<p class="mb-0">You can ask for help on <a class="link-light" href="https://discord.gg/pJkm23b2nA" target="_blank" rel="noopener noreferrer">our Discord server</a>!</p>
</div>
</div> </div>
</div> </div>
<div id="objectInfo"> <div class="offcanvas-body" id="offcanvasDraw-objectInfo" style="display: none;">
<label for="nameField">Name</label> <form id="objectInfo" class="d-flex flex-column p-3 bg-secondary bg-opacity-10 rounded">
<input id="nameField" type="text" value="" placeholder="A short title"> <div class="mb-3">
<label for="descriptionField">Description</label> <label for="nameField" class="form-label">Title</label>
<textarea id="descriptionField" placeholder="A short description to be understood by everyone"></textarea> <input type="text" id="nameField" class="form-control" placeholder="A short title" required>
<label for="websiteField">Website</label> </div>
<textarea id="websiteField" placeholder="https://example.com"></textarea> <div class="mb-3">
<label for="subredditField">Subreddit</label> <label for="descriptionField" class="form-label">Description</label>
<textarea id="subredditField" placeholder="/r/example"></textarea> <textarea id="descriptionField" class="form-control overflow-hidden" placeholder="A short description to be understood by everyone"></textarea>
<label for="discordField">Discord</label> </div>
<textarea id="discordField" placeholder="pJkm23b2nA"></textarea> <label id="websiteLabel" class="form-label">Website</label>
<label for="wikiField">Wiki</label> <div id="websiteGroup" class="mb-3 d-flex flex-column gap-2"></div>
<textarea id="wikiField" placeholder="Page Title"></textarea> <label id="subredditLabel" class="form-label">Subreddit</label>
<div class="inline"> <div id="subredditGroup" class="mb-3 d-flex flex-column gap-2"></div>
<button id="cancelButton">Back</button> <label id="discordLabel" class="form-label">Discord</label>
<button id="exportButton">OK</button> <div id="discordGroup" class="mb-3 d-flex flex-column gap-2"></div>
<label id="wikiLabel" class="form-label">
<a class="text-decoration-none" href="https://place-wiki.stefanocoding.me/" target="_blank" rel="noopener noreferrer">
<span class="text-body">Wiki</span>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-box-arrow-up-right" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z"/>
<path fill-rule="evenodd" d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z"/>
</svg>
</a>
</label>
<div id="wikiGroup" class="mb-3 d-flex flex-column gap-2"></div>
<div id="infoButtons" class="d-flex gap-2">
<button type="button" class="btn btn-secondary w-50" id="cancelButton">Back</button>
<button type="submit" class="btn btn-primary w-50" id="exportButton">Ok</button>
</div>
</form>
</div>
</div>
<button type="button" id="closeObjectsListButton" class="d-none btn btn-secondary shadow" aria-label="Close">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-x-lg" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M13.854 2.146a.5.5 0 0 1 0 .708l-11 11a.5.5 0 0 1-.708-.708l11-11a.5.5 0 0 1 .708 0Z"/>
<path fill-rule="evenodd" d="M2.146 2.146a.5.5 0 0 0 0 .708l11 11a.5.5 0 0 0 .708-.708l-11-11a.5.5 0 0 0-.708 0Z"/>
</svg>
</button>
<div id="objectsList" class="p-2"></div>
<span id="objectsListOverflowNotice" class="p-2 me-2 btn-primary rounded text-center d-none">Click the map to lock your selection</span>
</div>
<div class="modal fade" id="exportModal" tabindex="-1" aria-labelledby="exportModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-scrollable modal-xl modal-fullscreen-md-down">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exportModalLabel">Export Entry</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body d-flex flex-column">
<p>Use the Post Direct to Reddit button or manually copy the text below and submit it as a new text post to <a href="https://www.reddit.com/r/placeAtlas2/" target="_blank" rel="noopener noreferrer">/r/placeAtlas2</a> on Reddit.</p>
<p>Don't forget to flair it with the <span class="badge rounded-pill bg-primary"><i class="bi bi-tag"></i> <span id="redditFlair">New Entry</span></span> tag.</p>
<p>We will then check it and add it to the atlas.</p>
<textarea class="form-control flex-grow-1" cols="40" rows="20" id="exportString" title="Raw JSON string"></textarea>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Done</button>
<a id="exportDirectPost" class="btn btn-primary" href="#" target="_blank" rel="noopener noreferrer">Post Direct to Reddit</a>
</div>
</div>
</div>
</div>
<div class="modal fade" id="donateModal" tabindex="-1" aria-labelledby="donateModalLabel" aria-hidden="true">
<div class="modal-dialog modal-fullscreen-sm-down">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="donateModalLabel">Donation Links</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>Current 2022 Atlas Maintainers:</p>
<a class="btn btn-primary" target="_blank" rel="noopener noreferrer" href="https://paypal.me/placeAtlas/5">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-paypal" viewBox="0 0 16 16" aria-hidden="true"><path d="M14.06 3.713c.12-1.071-.093-1.832-.702-2.526C12.628.356 11.312 0 9.626 0H4.734a.7.7 0 0 0-.691.59L2.005 13.509a.42.42 0 0 0 .415.486h2.756l-.202 1.28a.628.628 0 0 0 .62.726H8.14c.429 0 .793-.31.862-.731l.025-.13.48-3.043.03-.164.001-.007a.351.351 0 0 1 .348-.297h.38c1.266 0 2.425-.256 3.345-.91.379-.27.712-.603.993-1.005a4.942 4.942 0 0 0 .88-2.195c.242-1.246.13-2.356-.57-3.154a2.687 2.687 0 0 0-.76-.59l-.094-.061ZM6.543 8.82a.695.695 0 0 1 .321-.079H8.3c2.82 0 5.027-1.144 5.672-4.456l.003-.016c.217.124.4.27.548.438.546.623.679 1.535.45 2.71-.272 1.397-.866 2.307-1.663 2.874-.802.57-1.842.815-3.043.815h-.38a.873.873 0 0 0-.863.734l-.03.164-.48 3.043-.024.13-.001.004a.352.352 0 0 1-.348.296H5.595a.106.106 0 0 1-.105-.123l.208-1.32.845-5.214Z"/></svg>
PayPal
</a>
<a class="btn btn-primary" target="_blank" rel="noopener noreferrer" href="https://www.patreon.com/placeAtlas">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi" viewBox="0 0 24 24" aria-hidden="true"><path d="M0 .48v23.04h4.22V.48zm15.385 0c-4.764 0-8.641 3.88-8.641 8.65 0 4.755 3.877 8.623 8.641 8.623 4.75 0 8.615-3.868 8.615-8.623C24 4.36 20.136.48 15.385.48z"/></svg>
Patreon
</a>
<a class="btn btn-primary" target="_blank" rel="noopener noreferrer" href="https://ko-fi.com/placeatlas">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi" viewBox="0 0 24 24" aria-hidden="true"><path d="M23.881 8.948c-.773-4.085-4.859-4.593-4.859-4.593H.723c-.604 0-.679.798-.679.798s-.082 7.324-.022 11.822c.164 2.424 2.586 2.672 2.586 2.672s8.267-.023 11.966-.049c2.438-.426 2.683-2.566 2.658-3.734 4.352.24 7.422-2.831 6.649-6.916zm-11.062 3.511c-1.246 1.453-4.011 3.976-4.011 3.976s-.121.119-.31.023c-.076-.057-.108-.09-.108-.09-.443-.441-3.368-3.049-4.034-3.954-.709-.965-1.041-2.7-.091-3.71.951-1.01 3.005-1.086 4.363.407 0 0 1.565-1.782 3.468-.963 1.904.82 1.832 3.011.723 4.311zm6.173.478c-.928.116-1.682.028-1.682.028V7.284h1.77s1.971.551 1.971 2.638c0 1.913-.985 2.667-2.059 3.015z"/></svg>
Ko-Fi
</a>
<hr>
<p>Original 2017 Atlas Developer (draemmli aka Roland Rytz): </p>
<a class="btn btn-primary" target="_blank" rel="noopener noreferrer" href="https://paypal.me/draemmli">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-paypal" viewBox="0 0 16 16" aria-hidden="true"><path d="M14.06 3.713c.12-1.071-.093-1.832-.702-2.526C12.628.356 11.312 0 9.626 0H4.734a.7.7 0 0 0-.691.59L2.005 13.509a.42.42 0 0 0 .415.486h2.756l-.202 1.28a.628.628 0 0 0 .62.726H8.14c.429 0 .793-.31.862-.731l.025-.13.48-3.043.03-.164.001-.007a.351.351 0 0 1 .348-.297h.38c1.266 0 2.425-.256 3.345-.91.379-.27.712-.603.993-1.005a4.942 4.942 0 0 0 .88-2.195c.242-1.246.13-2.356-.57-3.154a2.687 2.687 0 0 0-.76-.59l-.094-.061ZM6.543 8.82a.695.695 0 0 1 .321-.079H8.3c2.82 0 5.027-1.144 5.672-4.456l.003-.016c.217.124.4.27.548.438.546.623.679 1.535.45 2.71-.272 1.397-.866 2.307-1.663 2.874-.802.57-1.842.815-3.043.815h-.38a.873.873 0 0 0-.863.734l-.03.164-.48 3.043-.024.13-.001.004a.352.352 0 0 1-.348.296H5.595a.106.106 0 0 1-.105-.123l.208-1.32.845-5.214Z"/></svg>
PayPal
</a>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div> </div>
</div> </div>
</div> </div>
<div id="hint"> </div>
<p>You can suggest new entries to the Atlas for art that isn't mapped yet.</p> <template id="period-group">
<p>Please read <a href="https://www.reddit.com/r/placeAtlas2/comments/tu203o/how_to_contribute/" target="_blank">this reddit post</a> for instructions.</p> <div class="period-group card mb-2">
<p>Click anywhere on the image to start drawing a shape. <div class="card-body">
When you're happy with the result, click the "Finish" button above or press the Enter key.</p> <label for="period-start" class="form-label">Start Period</label>
<p>You can then add more information about your object.</p> <input type="range" class="period-start form-range" id="period-start" min="0">
<div style="background-color:#7289DA; padding:20px"> <label for="period-end" class="form-label">End Period</label>
<p><b>Need Help?</b></p> <input type="range" class="period-end form-range mb-2" id="period-end" min="0">
<b>You can ask for help on <a href="https://discord.gg/pJkm23b2nA">our Discord server</a>!</b><br> <div class="d-flex flex-wrap gap-2 mb-2">
<button type="button" class="period-copy btn btn-secondary btn-sm flex-fill" id="period-copy">
<i class="bi bi-clipboard" aria-hidden="true"></i>
Copy
</button>
<button type="button" class="period-duplicate btn btn-secondary btn-sm flex-fill" id="period-duplicate">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-back" viewBox="0 0 16 16" aria-hidden="true">
<path d="M0 2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v2h2a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-2H2a2 2 0 0 1-2-2V2zm2-1a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H2z"/>
</svg>
Duplicate
</button>
<button type="button" class="period-delete btn btn-danger btn-sm flex-fill" id="period-delete">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash-fill" viewBox="0 0 16 16" aria-hidden="true">
<path d="M2.5 1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1H3v9a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4h.5a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H10a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1H2.5zm3 4a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5zM8 5a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7A.5.5 0 0 1 8 5zm3 .5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 1 0z"/>
</svg>
Delete
</button>
</div>
<div class="input-group">
<span class="input-group-text"></span>
<select class="period-variation form-select" title="Select which layer this path is used for"></select>
</div>
</div> </div>
</div> </div>
</div> </template>
<button class="hidden" id="closeObjectsListButton"></button>
<div id="objectsList">
</div>
<div id="exportOverlay" class="overlay">
<div id="exportWindow">
<p><b>Recommended:</b> Post directly after clicking this button. Don't forget to flair it with the "New Entry" tag. </p>
<div class="exportButtons">
<a href="_blank" id="exportDirectPost" class="button">Post Direct to Reddit</a>
</div>
<hr style="border-bottom: solid black 1px" />
<i>or...</i>
<p>Please copy the text below and submit it as a
new text post to <a target="_blank" href="https://www.reddit.com/r/placeAtlas2/">/r/placeAtlas2</a> on Reddit.</p>
<p>Don't forget to flair it with the "New Entry" tag.</p>
<p>We will then check it and add it to the atlas.</p>
<textarea cols="20" rows="5" id="exportString"></textarea>
<div class="exportButtons" id="exportButtons">
<button id="exportBackButton">Back</button>
<button id="exportCloseButton">Done</button>
</div>
</div>
</div>
<div id="donateOverlay" class="overlay">
<div id="donateWindow">
<h2>Donation Links</h2>
<p>Current 2022 Atlas Maintainers:</p>
<a class="button" target="_blank" href="https://paypal.me/placeAtlas/5">
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<title>PayPal</title>
<path fill="white" d="M7.076 21.337H2.47a.641.641 0 0 1-.633-.74L4.944.901C5.026.382 5.474 0 5.998 0h7.46c2.57 0 4.578.543 5.69 1.81 1.01 1.15 1.304 2.42 1.012 4.287-.023.143-.047.288-.077.437-.983 5.05-4.349 6.797-8.647 6.797h-2.19c-.524 0-.968.382-1.05.9l-1.12 7.106zm14.146-14.42a3.35 3.35 0 0 0-.607-.541c-.013.076-.026.175-.041.254-.93 4.778-4.005 7.201-9.138 7.201h-2.19a.563.563 0 0 0-.556.479l-1.187 7.527h-.506l-.24 1.516a.56.56 0 0 0 .554.647h3.882c.46 0 .85-.334.922-.788.06-.26.76-4.852.816-5.09a.932.932 0 0 1 .923-.788h.58c3.76 0 6.705-1.528 7.565-5.946.36-1.847.174-3.388-.777-4.471z" />
</svg>
PayPal
</a>
<a class="button" target="_blank" href="https://www.patreon.com/placeAtlas">
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<title>Patreon</title>
<path fill="white" d="M0 .48v23.04h4.22V.48zm15.385 0c-4.764 0-8.641 3.88-8.641 8.65 0 4.755 3.877 8.623 8.641 8.623 4.75 0 8.615-3.868 8.615-8.623C24 4.36 20.136.48 15.385.48z" />
</svg>
Patreon
</a>
<a class="button" target="_blank" href="https://ko-fi.com/placeatlas">
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<title>Ko-fi</title>
<path fill="white" d="M23.881 8.948c-.773-4.085-4.859-4.593-4.859-4.593H.723c-.604 0-.679.798-.679.798s-.082 7.324-.022 11.822c.164 2.424 2.586 2.672 2.586 2.672s8.267-.023 11.966-.049c2.438-.426 2.683-2.566 2.658-3.734 4.352.24 7.422-2.831 6.649-6.916zm-11.062 3.511c-1.246 1.453-4.011 3.976-4.011 3.976s-.121.119-.31.023c-.076-.057-.108-.09-.108-.09-.443-.441-3.368-3.049-4.034-3.954-.709-.965-1.041-2.7-.091-3.71.951-1.01 3.005-1.086 4.363.407 0 0 1.565-1.782 3.468-.963 1.904.82 1.832 3.011.723 4.311zm6.173.478c-.928.116-1.682.028-1.682.028V7.284h1.77s1.971.551 1.971 2.638c0 1.913-.985 2.667-2.059 3.015z" />
</svg>
Ko-Fi
</a>
<p>Original 2017 Atlas Developer (draemmli aka Roland Rytz): </p>
<a class="button" target="_blank" href="https://paypal.me/draemmli">
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<title>PayPal</title>
<path fill="white" d="M7.076 21.337H2.47a.641.641 0 0 1-.633-.74L4.944.901C5.026.382 5.474 0 5.998 0h7.46c2.57 0 4.578.543 5.69 1.81 1.01 1.15 1.304 2.42 1.012 4.287-.023.143-.047.288-.077.437-.983 5.05-4.349 6.797-8.647 6.797h-2.19c-.524 0-.968.382-1.05.9l-1.12 7.106zm14.146-14.42a3.35 3.35 0 0 0-.607-.541c-.013.076-.026.175-.041.254-.93 4.778-4.005 7.201-9.138 7.201h-2.19a.563.563 0 0 0-.556.479l-1.187 7.527h-.506l-.24 1.516a.56.56 0 0 0 .554.647h3.882c.46 0 .85-.334.922-.788.06-.26.76-4.852.816-5.09a.932.932 0 0 1 .923-.788h.58c3.76 0 6.705-1.528 7.565-5.946.36-1.847.174-3.388-.777-4.471z" />
</svg>
PayPal
</a>
<br>
<button id="closeDonateButton">Close</button>
</div>
</div>
</div>
<template id="period-group">
<div class="period-group">
<label for="period-start">Start Period</label>
<input class="period-start" type="range" min="0">
<label for="period-end">End Period</label>
<input class="period-end" type="range" min="0">
<p class="period-visible"></p>
<div class="inline">
<button class="period-copy">Copy</button>
<button class="period-delete">Delete</button>
<button class="period-duplicate">Duplicate</button>
</div>
<select class="period-variation"></select>
</div>
</template>
<script type="text/javascript" src="./_js/time.js"></script>
<script type="text/javascript" src="./_js/infoblock.js"></script>
<script type="text/javascript" src="./_js/pointInPolygon.js"></script>
<script type="text/javascript" src="./_js/atlas.js"></script>
<script type="text/javascript" src="./_js/view.js"></script>
<script type="text/javascript" src="./_js/overlap.js"></script>
<script type="text/javascript" src="./_js/polylabel.js"></script>
<script type="text/javascript" src="./_js/draw.js"></script>
<script type="text/javascript" src="./_js/main.js"></script>
<!-- <script type="text/javascript" src="./_js/stats.js"></script>
<script type="text/javascript" src="./_js/minified.js"></script> -->
</body>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<script type="text/javascript" src="./_js/time.js"></script>
<script type="text/javascript" src="./_js/infoblock.js"></script>
<script type="text/javascript" src="./_js/pointInPolygon.js"></script>
<script type="text/javascript" src="./_js/atlas.js"></script>
<script type="text/javascript" src="./_js/view.js"></script>
<script type="text/javascript" src="./_js/overlap.js"></script>
<script type="text/javascript" src="./_js/polylabel.js"></script>
<script type="text/javascript" src="./_js/draw.js"></script>
<script type="text/javascript" src="./_js/main.js"></script>
<!-- <script type="text/javascript" src="./_js/stats.js"></script>
<script type="text/javascript" src="./_js/minified.js"></script> -->
</body>
</html> </html>