Merge pull request #1492 from Hans5958/sync/240112

Update codebase
This commit is contained in:
Hans5958 2024-01-24 23:20:04 +07:00 committed by GitHub
commit f836e06071
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 761 additions and 632 deletions

View File

@ -121,6 +121,14 @@ Hereforth is an example of the structured entry data. The example has been expan
## Development
> [!IMPORTANT]
>
> Instead of here, consider directing your contributions to [The 2023 r/place Atlas](https://github.com/placeAtlas/atlas-2023).
>
> Updates from the latest Atlas would be backported occasionally for the benefit of the other instances (e.g. the 2017 Atlas and the 2022 Atlas). Furthermore, there is a great chance that what you want to do would also benefit the other instances.
>
> There may some cases where what you want to do only apply on this specific instance. In that case, you may proceed. When in doubt, don't hesitate to contact us.
Other than contributing to the Atlas data, code contributions are also accepted. Here are some information regarding some aspects on the repository.
### Web interface

View File

@ -1,20 +1,20 @@
[![Entry count](https://img.shields.io/badge/dynamic/json?color=blue&label=entries&query=%24.length&url=https%3A%2F%2Fgithub.com%2FplaceAtlas%2Fatlas%2Fblob%2Fmaster%2Fweb%2Fatlas.json%3Fraw%3Dtrue)](https://2022.place-atlas.stefanocoding.me/)
[![Entry count](https://img.shields.io/badge/dynamic/json?color=blue&label=entries&query=%24.length&url=https%3A%2F%2Fgithub.com%2FplaceAtlas%2Fatlas-2022%2Fblob%2Fmaster%2Fweb%2Fatlas.json%3Fraw%3Dtrue)](https://2022.place-atlas.stefanocoding.me/)
![Commit activity](https://img.shields.io/github/commit-activity/w/placeAtlas/atlas-2022)
[![Netlify](https://img.shields.io/netlify/1e7291ce-0680-45ed-9843-47a32a992bbb?logo=netlify&logoColor=white)](https://app.netlify.com/sites/place-atlas/deploys)
[![License](https://img.shields.io/github/license/placeAtlas/atlas-2022)](https://github.com/placeAtlas/atlas-2022/blob/master/LICENSE)
[![Netlify](https://img.shields.io/netlify/1e7291ce-0680-45ed-9843-47a32a992bbb?logo=netlify&logoColor=white)](https://app.netlify.com/sites/place-atlas-2022/deploys)
[![License](https://img.shields.io/github/license/placeAtlas/atlas)](https://github.com/placeAtlas/atlas-2022/blob/master/LICENSE)
[![Discord](https://img.shields.io/discord/960791635342524496?color=%235865F2&logo=discord&logoColor=white)](https://discord.gg/pJkm23b2nA)
[![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=2022.place-atlas.stefanocoding.me&color=blue)](https://2022.place-atlas.stefanocoding.me/)
# The 2022 r/place Atlas
The 2022 r/place Atlas is a project aiming to chart all the artworks created during the r/place April Fools event on Reddit in 2022. It is made with information to each artwork of the canvas provided by the community.
The 2022 r/place Atlas is an interactive map aiming to chart all the artworks created during the r/place April Fools event on Reddit in 2022. It is made with information to each artwork of the canvas provided by the community.
This project was established by Roland Rytz for the event in 2017, and further developed and maintained by the Place Atlas team and contributors.
This project was established by Roland Rytz for the event in 2017, and further developed and maintained by the [Place Atlas Initiative](https://place-atlas.stefanocoding.me) and [contributors](https://github.com/placeAtlas/atlas-2022/graphs/contributors).
This project is licensed under the [GNU Affero General Public License v3.0](LICENSE).
You can check out the website by visiting [2022.place-atlas.stefanocoding.me](https://2022.place-atlas.stefanocoding.me/). If you want to keep distance from GitHub, you may visit [r/placeAtlas2](https://www.reddit.com/r/placeAtlas2/).
You can check out the website by visiting [2022.place-atlas.stefanocoding.me](https://2022.place-atlas.stefanocoding.me/). The subreddit, [r/placeAtlas2](https://www.reddit.com/r/placeAtlas2/), is available for communications via Reddit.
## Contributing
@ -22,15 +22,18 @@ This project is open source, and contributions are welcome. In fact, the Atlas r
Please read [CONTRIBUTING.md](CONTRIBUTING.md) to learn how to submit a new entry, edit existing entries, or contribute to the development of the codebase.
[The r/placeAlas2 subreddit](https://reddit.com/r/placeAtlas2/) and [the Discord server](https://discord.gg/pJkm23b2nA) is also the place to submit all bug reports, feature requests, or questions.
[The r/placeAtlas2 subreddit](https://reddit.com/r/placeAtlas2/) and [the Discord server](https://discord.gg/pJkm23b2nA) is also the place to submit all bug reports, feature requests, or questions.
## Contributors
> [!NOTE]
> For more credits, including entry contributors, please see [the Credits sections on the About page](https://2022.place-atlas.stefanocoding.me/about#credits).
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-7-orange.svg?style=flat)](#contributors)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key))):
Many thanks to these wonderful people for contributing on the scope of this repository. ([emoji key](https://allcontributors.org/docs/en/emoji-key)).
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->

91
package-lock.json generated
View File

@ -14,7 +14,7 @@
"parcel": "^2.8.3",
"parcel-namer-rewrite": "^2.0.0-rc.3",
"parcel-resolver-ignore": "^2.1.3",
"postcss": "^8.4.31"
"postcss": "^8.4.21"
}
},
"node_modules/@babel/code-frame": {
@ -1926,9 +1926,9 @@
}
},
"node_modules/all-contributors-cli": {
"version": "6.26.1",
"resolved": "https://registry.npmjs.org/all-contributors-cli/-/all-contributors-cli-6.26.1.tgz",
"integrity": "sha512-Ymgo3FJACRBEd1eE653FD1J/+uD0kqpUNYfr9zNC1Qby0LgbhDBzB3EF6uvkAbYpycStkk41J+0oo37Lc02yEw==",
"version": "6.24.0",
"resolved": "https://registry.npmjs.org/all-contributors-cli/-/all-contributors-cli-6.24.0.tgz",
"integrity": "sha512-7oSKr2PnqxsOotuSwciltcFTS1eVRdjR0cn99hbElfff7gRQBShVhsf/XBprY41sLcgqTk0l0MKgKv6QNgZdMg==",
"dev": true,
"dependencies": {
"@babel/runtime": "^7.7.6",
@ -1947,9 +1947,6 @@
},
"engines": {
"node": ">=4"
},
"optionalDependencies": {
"prettier": "^2"
}
},
"node_modules/all-contributors-cli/node_modules/ansi-styles": {
@ -3762,16 +3759,10 @@
"dev": true
},
"node_modules/nanoid": {
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"bin": {
"nanoid": "bin/nanoid.cjs"
},
@ -3974,9 +3965,9 @@
}
},
"node_modules/parcel-resolver-ignore": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/parcel-resolver-ignore/-/parcel-resolver-ignore-2.1.5.tgz",
"integrity": "sha512-/2zgQw3J/2YA7L6JXg4XKBWT/SXDZx+PfweWcCsllchNVwFvK7jDJhG6h+puy+e15Rm9A/ubuuHYwANQHVXp2A==",
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/parcel-resolver-ignore/-/parcel-resolver-ignore-2.1.3.tgz",
"integrity": "sha512-C8uLvR4o7SPRSsQ/Nylm1/PdsLwn/Z9bzCs66qT3XIebJC7ojaFFF3MDl/mie5audngjcFF8wzU0AoEQkZq2pA==",
"dev": true,
"engines": {
"parcel": ">=2.0.0"
@ -4137,9 +4128,9 @@
}
},
"node_modules/postcss": {
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"version": "8.4.21",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz",
"integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==",
"dev": true,
"funding": [
{
@ -4149,14 +4140,10 @@
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"dependencies": {
"nanoid": "^3.3.6",
"nanoid": "^3.3.4",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
},
@ -4691,22 +4678,6 @@
"node": ">=12"
}
},
"node_modules/prettier": {
"version": "2.8.8",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
"dev": true,
"optional": true,
"bin": {
"prettier": "bin-prettier.js"
},
"engines": {
"node": ">=10.13.0"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/purgecss": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/purgecss/-/purgecss-5.0.0.tgz",
@ -6550,9 +6521,9 @@
"dev": true
},
"all-contributors-cli": {
"version": "6.26.1",
"resolved": "https://registry.npmjs.org/all-contributors-cli/-/all-contributors-cli-6.26.1.tgz",
"integrity": "sha512-Ymgo3FJACRBEd1eE653FD1J/+uD0kqpUNYfr9zNC1Qby0LgbhDBzB3EF6uvkAbYpycStkk41J+0oo37Lc02yEw==",
"version": "6.24.0",
"resolved": "https://registry.npmjs.org/all-contributors-cli/-/all-contributors-cli-6.24.0.tgz",
"integrity": "sha512-7oSKr2PnqxsOotuSwciltcFTS1eVRdjR0cn99hbElfff7gRQBShVhsf/XBprY41sLcgqTk0l0MKgKv6QNgZdMg==",
"dev": true,
"requires": {
"@babel/runtime": "^7.7.6",
@ -6564,7 +6535,6 @@
"lodash": "^4.11.2",
"node-fetch": "^2.6.0",
"pify": "^5.0.0",
"prettier": "^2",
"yargs": "^15.0.1"
},
"dependencies": {
@ -7853,9 +7823,9 @@
"dev": true
},
"nanoid": {
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
"dev": true
},
"node-addon-api": {
@ -8045,9 +8015,9 @@
}
},
"parcel-resolver-ignore": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/parcel-resolver-ignore/-/parcel-resolver-ignore-2.1.5.tgz",
"integrity": "sha512-/2zgQw3J/2YA7L6JXg4XKBWT/SXDZx+PfweWcCsllchNVwFvK7jDJhG6h+puy+e15Rm9A/ubuuHYwANQHVXp2A==",
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/parcel-resolver-ignore/-/parcel-resolver-ignore-2.1.3.tgz",
"integrity": "sha512-C8uLvR4o7SPRSsQ/Nylm1/PdsLwn/Z9bzCs66qT3XIebJC7ojaFFF3MDl/mie5audngjcFF8wzU0AoEQkZq2pA==",
"dev": true,
"requires": {}
},
@ -8103,12 +8073,12 @@
"dev": true
},
"postcss": {
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"version": "8.4.21",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz",
"integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==",
"dev": true,
"requires": {
"nanoid": "^3.3.6",
"nanoid": "^3.3.4",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
}
@ -8473,13 +8443,6 @@
"is-json": "^2.0.1"
}
},
"prettier": {
"version": "2.8.8",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
"dev": true,
"optional": true
},
"purgecss": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/purgecss/-/purgecss-5.0.0.tgz",

View File

@ -7,7 +7,7 @@
"parcel": "^2.8.3",
"parcel-namer-rewrite": "^2.0.0-rc.3",
"parcel-resolver-ignore": "^2.1.3",
"postcss": "^8.4.31",
"postcss": "^8.4.21",
"all-contributors-cli": "^6.24.0"
},
"parcel-namer-rewrite": {
@ -18,7 +18,8 @@
},
"parcelIgnore": [
"sw.js",
"_img/.+"
"_img/.+",
"atlas.json"
],
"browserslist": [
">= 0.5%",

View File

@ -20,6 +20,5 @@ cp -r web/_img/ dist/
cp web/atlas.json dist/
cp web/*.txt dist/
cp web/_headers dist/
cp web/_redirects dist/
cp web/favicon.ico dist/
cp web/sw.js dist/

View File

@ -19,6 +19,5 @@ cp -r web/_img/ dist/
cp web/atlas.json dist/
cp web/*.txt dist/
cp web/_headers dist/
cp web/_redirects dist/
cp web/favicon.ico dist/
cp web/sw.js dist/

View File

@ -1,8 +1,7 @@
<!--
The 2022 r/place Atlas
Copyright (c) 2017 Roland Rytz <roland@draemm.li>
Copyright (c) 2022 Place Atlas contributors
Copyright (c) 2022 Place Atlas Initiative and contributors
Licensed under AGPL-3.0 (https://2022.place-atlas.stefanocoding.me/license.txt)
-->

View File

@ -1,7 +1,7 @@
/*!
* The 2022 r/place Atlas
* Copyright (c) 2017 Roland Rytz <roland@draemm.li>
* Copyright (c) 2022 Place Atlas contributors
* Copyright (c) 2022 Place Atlas Initiative and contributors
* Licensed under AGPL-3.0 (https://2022.place-atlas.stefanocoding.me/license.txt)
*/
@ -52,6 +52,14 @@ body[data-mode] {
padding-left: env(safe-area-inset-left);
}
.opacity-0 {
opacity: 0;
}
.transition-opacity {
transition: opacity .15s linear;
}
@supports (backdrop-filter: blur()) or (-webkit-backdrop-filter: blur()) {
.navbar, .offcanvas {
-webkit-backdrop-filter: saturate(180%) blur(15px);
@ -258,12 +266,12 @@ body[data-init-done] .listTransitioning #innerContainer {
}
#variantControls {
flex: 1 0 auto;
flex: 2 0 auto;
}
#timeControls {
position: relative;
flex: 6 0 300px;
flex: 12 0 300px;
}
#bottomBar.no-time-slider #timeControls {
@ -440,13 +448,25 @@ body:not([data-dev]) .show-only-on-dev {
display: none !important
}
#objectsList,
#offcanvasList,
#offcanvasDraw,
#closeObjectsListButton {
margin-top: var(--global-top-padding);
}
.copyleft {
display: inline-block;
transform: rotateY(180deg);
}
/* about.html */
#credits a {
#entry-contributors-wrapper a {
text-decoration: none;
}
#credits a:hover {
#entry-contributors-wrapper a:hover {
text-decoration: underline;
}

View File

@ -1,8 +1,21 @@
/*
Access-Control-Allow-Origin: *
/_img/canvas/*/*.png
cache-control: public, max-age=604800
# Hashed resources: 1 year and immutable
/_js/*
Cache-Control: public, immutable, max-age=31536000
/_css/*
Cache-Control: public, immutable, max-age=31536000
# Canvas images: 1 year
/_img/canvas/*
Cache-Control: public, max-age=31536000
/_img/canvas/*.png
cache-control: public, max-age=604800
Cache-Control: public, max-age=31536000
/_img/canvas/*/*.png
Cache-Control: public, max-age=31536000

View File

@ -1,11 +1,11 @@
/*!
* The 2022 r/place Atlas
* Copyright (c) 2017 Roland Rytz <roland@draemm.li>
* Copyright (c) 2022 Place Atlas contributors
* Copyright (c) 2022 Place Atlas Initiative and contributors
* Licensed under AGPL-3.0 (https://2022.place-atlas.stefanocoding.me/license.txt)
*/
const contributorsEl = document.querySelector('#contributors-wrapper')
const contributorsEl = document.querySelector('#entry-contributors-wrapper')
// <i aria-label="GitHub" class="bi bi-github"></i>
const gitHubEl = document.createElement("i")
@ -34,6 +34,8 @@ fetch('all-authors.txt')
userEl.href = 'https://reddit.com/user/' + contributor
userEl.textContent = contributor
}
userEl.target = '_blank'
userEl.rel = 'noreferrer'
contributorsEl.appendChild(userEl)
contributorsEl.appendChild(document.createTextNode(' '))
}

View File

@ -265,8 +265,8 @@ window.useNumericalId = useNumericalId
console.info(`%cThe 2022 r/place Atlas
%cCopyright (c) 2017 Roland Rytz <roland@draemm.li>
Copyright (c) 2022 Place Atlas contributors
Licensed under AGPL-3.0 (https://2022.place-atlas.stefanocoding.me/license.txt)
Copyright (c) 2022 Place Atlas Initiative and contributors
Licensed under AGPL-3.0 (https://2023.place-atlas.stefanocoding.me/license.txt)
https://2022.place-atlas.stefanocoding.me/
https://discord.gg/pJkm23b2nA
@ -274,4 +274,4 @@ https://reddit.com/r/placeatlas2
https://github.com/placeAtlas/atlas-2022
To get the image of the canvas, use downloadCanvas().
`, 'font-size: 150%; line-height: 150%', '')
`, 'font-size: 150%; line-height: 150%', '')

View File

@ -1,7 +1,7 @@
/*!
* The 2022 r/place Atlas
* Copyright (c) 2017 Roland Rytz <roland@draemm.li>
* Copyright (c) 2022 Place Atlas contributors
* Copyright (c) 2022 Place Atlas Initiative and contributors
* Licensed under AGPL-3.0 (https://2022.place-atlas.stefanocoding.me/license.txt)
*/

View File

@ -1,7 +1,7 @@
/*!
* The 2022 r/place Atlas
* Copyright (c) 2017 Roland Rytz <roland@draemm.li>
* Copyright (c) 2022 Place Atlas contributors
* Copyright (c) 2022 Place Atlas Initiative and contributors
* Licensed under AGPL-3.0 (https://2022.place-atlas.stefanocoding.me/license.txt)
*/
@ -69,7 +69,7 @@ const periodClipboard = {
const drawBackButton = document.createElement("a")
drawBackButton.className = "btn btn-outline-primary"
drawBackButton.id = "drawBackButton"
drawBackButton.textContent = "Exit Draw Mode"
drawBackButton.textContent = "Exit Drawing"
const baseInputAddon = document.createElement("span")
baseInputAddon.className = "input-group-text"
@ -106,12 +106,13 @@ function initDraw() {
showListButton.insertAdjacentHTML("afterend", '<button class="btn btn-outline-primary" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasDraw" aria-controls="offcanvasDraw">Menu</button>')
showListButton.parentElement.appendChild(drawBackButton)
showListButton.remove()
drawButton.remove()
// Opens draw menu
wrapper.classList.remove('listHidden')
bsOffcanvasDraw.show()
window.render = render
window.renderHighlight = renderHighlight
window.renderBackground = renderBackground
window.updateHovering = updateHovering
@ -125,13 +126,18 @@ function initDraw() {
let highlightUncharted = highlightUnchartedEl.checked
renderBackground(atlas)
window.updateAtlas = updateAtlas
updateAtlas()
document.addEventListener('timeupdate', () => {
updateAtlas()
})
applyView()
container.style.cursor = "crosshair"
render(path)
container.addEventListener("mousedown", e => {
lastPos = [
e.clientX,
@ -168,7 +174,7 @@ function initDraw() {
const coords = getCanvasCoords(e.clientX, e.clientY)
path.push(coords)
render(path)
renderHighlight(path)
undoHistory = []
redoButton.disabled = true
@ -185,13 +191,13 @@ function initDraw() {
container.addEventListener("mousemove", e => {
if (!dragging && drawing && path.length > 0) {
const coords = getCanvasCoords(e.clientX, e.clientY)
render([...path, coords])
renderHighlight([...path, coords])
}
})
container.addEventListener("mouseout", function () {
if (!dragging && drawing && path.length > 0) {
render(path)
renderHighlight(path)
}
})
@ -228,19 +234,19 @@ function initDraw() {
undoButton.addEventListener("click", e => {
undo()
const coords = getCanvasCoords(e.clientX, e.clientY)
render([...path, coords])
renderHighlight([...path, coords])
})
redoButton.addEventListener("click", e => {
redo()
const coords = getCanvasCoords(e.clientX, e.clientY)
render([...path, coords])
renderHighlight([...path, coords])
})
resetButton.addEventListener("click", e => {
reset()
const coords = getCanvasCoords(e.clientX, e.clientY)
render([...path, coords])
renderHighlight([...path, coords])
})
resetButton.addEventListener("blur", function () {
@ -269,7 +275,7 @@ function initDraw() {
highlightUnchartedEl.addEventListener("click", function () {
highlightUncharted = this.checked
render(path)
renderHighlight(path)
})
function generateExportObject() {
@ -332,7 +338,7 @@ function initDraw() {
if (exportArea.value > 40000) {
exportArea.value = " " + miniJsonString
}
// Reddit
let redditPostJsonString = " " + prettyJsonString.split("\n").join("\n ")
@ -385,13 +391,11 @@ function initDraw() {
}
githubPostButton.href = githubPostUrl
console.log(githubPostUrl)
exportModal.show()
}
function preview() {
let infoElement = createInfoBlock(generateExportObject(), true)
let infoElement = createInfoBlock(generateExportObject(), 2)
objectsContainer.replaceChildren()
objectsContainer.appendChild(infoElement)
closeObjectsListButton.classList.remove("d-none")
@ -483,16 +487,16 @@ function initDraw() {
closeObjectsListButton.classList.add("d-none")
}
function renderBackground() {
function renderBackground(atlas) {
backgroundContext.clearRect(0, 0, highlightCanvas.width, highlightCanvas.height)
backgroundContext.fillStyle = "rgba(0, 0, 0, 1)"
//backgroundContext.fillRect(0, 0, canvas.width, canvas.height)
//backgroundContext.fillRect(0, 0, canvas.width, renderBackgroundcanvas.height)
for (let i = 0; i < atlas.length; i++) {
for (const entry of Object.values(atlas)) {
const path = atlas[i].path
const path = entry.path
backgroundContext.beginPath()
@ -510,7 +514,7 @@ function initDraw() {
}
}
function render(path) {
function renderHighlight(path) {
if (!Array.isArray(path)) return
@ -553,10 +557,16 @@ function initDraw() {
updateCoordsDisplay(e)
}
function updateAtlas() {
;[atlas, atlasOrder] = filterAtlas(atlasAll)
;[atlasDisplay, atlasOrder] = generateAtlasDisplay(atlas, atlasOrder, currentPeriod, currentVariation)
renderBackground(atlasDisplay)
renderHighlight(atlasDisplay)
}
const getEntry = id => {
if (!id) return
const entries = atlasAll.filter(entry => entry.id.toString() === id.toString())
if (entries.length === 1) return entries[0]
return atlasAll[id]
}
function addFieldButton(inputButton, inputGroup, array, index, name) {
@ -790,7 +800,7 @@ function initDraw() {
} else {
document.getElementById("offcanvasDrawLabel").textContent = "New Entry"
pathWithPeriods.push([formatPeriod(currentPeriod, currentPeriod, currentVariation), []])
pathWithPeriods.push([formatPeriod(currentPeriod, null, currentVariation), []])
// Builds multi-input list
addWebsiteFields("", 0, [0])
@ -805,25 +815,25 @@ function initDraw() {
const [,, hashX, hashY, hashZoom] = hash.split('/')
setView(
(isNaN(hashX) || hashX === '') ? center[0] : Number(hashX),
(isNaN(hashY) || hashY === '') ? center[1] : Number(hashY),
(isNaN(hashX) || hashX === '') ? center[0] : Number(hashX),
(isNaN(hashY) || hashY === '') ? center[1] : Number(hashY),
(isNaN(hashZoom) || hashZoom === '') ? 4 : Number(hashZoom)
)
document.addEventListener('timeupdate', () => {
renderBackground(atlas)
renderBackground(atlasDisplay)
updatePeriodGroups()
})
periodsAdd.addEventListener('click', () => {
pathWithPeriods.push([formatPeriod(currentPeriod, currentPeriod, currentVariation), []])
pathWithPeriods.push([formatPeriod(currentPeriod, null, currentVariation), []])
initPeriodGroups()
})
drawBackButton.href = "./" + formatHash(entry?.id)
document.addEventListener('timeupdate', event => {
drawBackButton.href = "./" + formatHash(entry?.id, event.detail.period, event.detail.period, event.detail.variation)
drawBackButton.href = "./" + formatHash(entry?.id, event.detail.period, event.detail.variation)
})
}
@ -862,7 +872,7 @@ function initPeriodGroups() {
const periodCopyEl = periodGroupEl.querySelector('.period-copy')
const periodDuplicateEl = periodGroupEl.querySelector('.period-duplicate')
const periodDeleteEl = periodGroupEl.querySelector('.period-delete')
const periodVariationEl = periodGroupEl.querySelector('.period-variation')
const periodStatusEl = periodGroupEl.querySelector('.period-status')
@ -926,19 +936,19 @@ function initPeriodGroups() {
})
startPeriodViewEl.addEventListener('click', () => {
updateTime(parseInt(startPeriodEl.value), getCurrentVariation())
// Set zoom view
periodCenter = calculateCenter(path)
setView(periodCenter[0], periodCenter[1], setZoomByPath(path))
})
function getCurrentVariation() {
return periodVariationEl[periodVariationEl.selectedIndex].value
}
function startPeriodUpdate(value) {
endPeriodListEl.innerHTML = '<option value="' + (parseInt(value) + 1) + '"></option>'
// Update time only when value changes
if (startPeriodEl.value !== timelineSlider.value) {
timelineSlider.value = value
@ -1224,7 +1234,7 @@ function updatePeriodGroups() {
function updatePath(newPath, newUndoHistory) {
path = newPath || path
if (path.length > 3) center = calculateCenter(path)
render(path)
renderHighlight(path)
undoButton.disabled = path.length === 0; // Maybe make it undo the cancel action in the future
undoHistory = newUndoHistory || []
redoButton.disabled = (!undoHistory.length)

View File

@ -1,7 +1,7 @@
/*!
* The 2022 r/place Atlas
* Copyright (c) 2017 Roland Rytz <roland@draemm.li>
* Copyright (c) 2022 Place Atlas contributors
* Copyright (c) 2022 Place Atlas Initiative and contributors
* Licensed under AGPL-3.0 (https://2022.place-atlas.stefanocoding.me/license.txt)
*/
@ -31,7 +31,10 @@ function createInfoListItem(name, value) {
return entryInfoListElement
}
function createInfoBlock(entry, isPreview) {
// mode 0 = normal
// mode 1 = entry list but none on atlas
// mode 2 = preview
function createInfoBlock(entry, mode = 0) {
const element = document.createElement("div")
element.className = "card mb-2 overflow-hidden shadow"
@ -40,21 +43,31 @@ function createInfoBlock(entry, isPreview) {
const linkElement = document.createElement("a")
linkElement.className = "text-decoration-none d-flex justify-content-between text-body"
if (isPreview) linkElement.href = "#"
else {
linkElement.href = formatHash(entry.id, null, null, null, false, false, false)
linkElement.addEventListener('click', e => {
let nearestPeriod = currentPeriod
let nearestVariation = currentVariation
if (!atlasDisplay[entry.id]) {
[nearestPeriod, nearestVariation] = getNearestPeriod(entry, currentPeriod, currentVariation)
}
if (mode === 2) {
linkElement.href = "#"
} else {
const hash = formatHash(entry.id, nearestPeriod, nearestVariation, false, false, false)
linkElement.href = hash
if (mode === 0) linkElement.addEventListener('click', e => {
e.preventDefault()
location.hash = formatHash(entry.id, null, null, null, false, false, false)
location.hash = hash
window.dispatchEvent(new HashChangeEvent("hashchange"))
})
}
const linkNameElement = document.createElement("span")
linkNameElement.className = "flex-grow-1 text-break"
linkNameElement.textContent = entry.name
headerElement.appendChild(linkElement)
linkElement.appendChild(linkNameElement)
linkElement.insertAdjacentHTML("beforeend", '<i class="bi bi-link-45deg align-self-center link-primary" aria-hidden="true"></i>')
linkElement.insertAdjacentHTML("beforeend", '<i class="bi bi-link-45deg align-self-center link-primary" aria-hidden="true" title="Copy direct link"></i>')
element.appendChild(headerElement)
const bodyElement = document.createElement("div")
@ -92,7 +105,7 @@ function createInfoBlock(entry, isPreview) {
}
// Entry data submitted to preview does not include center or path
if (!isPreview) {
if (mode === 0) {
const [x, y] = entry?.center
listElement.appendChild(createInfoListItem("Position: ", `${Math.floor(x)}, ${Math.floor(y)}`))
@ -170,11 +183,11 @@ function createInfoBlock(entry, isPreview) {
element.appendChild(idElementContainer)
// Adds edit button only if element is not deleted
if (!isPreview && (!entry.diff || entry.diff !== "delete")) {
if (mode < 2 && (!entry.diff || entry.diff !== "delete")) {
const editElement = document.createElement("a")
editElement.textContent = "Edit"
editElement.innerHTML = '<i class="bi bi-pencil-fill" aria-hidden="true"></i> Edit'
editElement.className = "btn btn-sm btn-outline-primary"
editElement.href = "./?mode=draw&id=" + entry.id + formatHash(false)
editElement.href = "./?mode=draw&id=" + entry.id + formatHash(false, nearestPeriod, nearestVariation, false, false, false)
editElement.title = "Edit " + entry.name
idElementContainer.appendChild(editElement)
}

View File

@ -1,7 +1,7 @@
/*!
* The 2022 r/place Atlas
* Copyright (c) 2017 Roland Rytz <roland@draemm.li>
* Copyright (c) 2022 Place Atlas contributors
* Copyright (c) 2022 Place Atlas Initiative and contributors
* Licensed under AGPL-3.0 (https://2022.place-atlas.stefanocoding.me/license.txt)
*/
@ -26,7 +26,7 @@ const maxZoom = 128
const minZoom = 0.125
let zoomOrigin = [0, 0]
let scaleZoomOrigin = [0, 0]
let scaleZoomOrigin = [canvasCenter.x, canvasCenter.y]
let dragging = false
let lastPosition = [0, 0]
@ -54,7 +54,7 @@ function applyView() {
}
function setView(targetX, targetY, targetZoom) {
if (isNaN(targetX)) targetX = null
if (isNaN(targetY)) targetY = null
@ -72,8 +72,6 @@ function updateHash(...args) {
if (location.hash !== newLocation.hash) history.replaceState({}, "", newLocation)
}
let atlas = null
window.atlas = atlas
let atlasAll = null
window.atlasAll = atlasAll
@ -102,13 +100,24 @@ async function init() {
}
}
// Experimental: TemplateManager support
// Add a .json file of TemplateManager on the "template" URL param.
// e.g. ?template=https://osu.place/e/osuplace2023.json
// CORS bypass is required (e.g. a proxy, CORS Anywhere).
if (params.get("template")) {
const [ templateDatas ] = await loadTemplateData(params.get("template"))
const templateLayers = await loadTemplateImages(templateDatas)
additionalLayers.push(...templateLayers)
updateAdditionalLayer(additionalLayers)
}
if (mode === "about") window.location.replace("./about.html")
// For Reviewing Reddit Changes
// const atlasRef = '../tools/temp-atlas.json'
const atlasRef = params.get('atlas') || './atlas.json'
const atlasResp = await fetch(atlasRef)
atlasAll = updateAtlasAll(await atlasResp.json())
const atlasAllUrl = params.get('atlas') || './atlas.json'
atlasAll = generateAtlasAll(await (await fetch(atlasAllUrl)).json())
// console.log(atlas, atlasOrder)
const hash = window.location.hash.substring(1)
const [, hashPeriod, hashX, hashY, hashZoom] = hash.split('/')
@ -148,45 +157,33 @@ async function init() {
initExplore()
} else if (mode.startsWith("diff")) {
try {
const liveAtlasRef = params.get('liveatlas') || `https://${prodDomain}/atlas.json`
const liveAtlasResp = await fetch(liveAtlasRef)
let liveAtlas = await liveAtlasResp.json()
liveAtlas = updateAtlasAll(liveAtlas)
const liveAtlasUrl = params.get('liveatlas') || `https://${prodDomain}/atlas.json`
let liveAtlasAll = generateAtlasAll(await (await fetch(liveAtlasUrl)).json())
const liveAtlasReduced = liveAtlas.reduce((atlas, entry) => {
delete entry._index
atlas[entry.id] = entry
return atlas
}, {})
// Mark added/edited entries
atlasAll = atlasAll.map(function (entry) {
delete entry._index
if (!liveAtlasReduced[entry.id]) {
for (const entry of Object.values(atlasAll)) {
if (!liveAtlasAll[entry.id]) {
entry.diff = "add"
} else if (JSON.stringify(entry) !== JSON.stringify(liveAtlasReduced[entry.id])) {
} else {
if (JSON.stringify({ ...entry, _index: undefined }) === JSON.stringify({ ...liveAtlasAll[entry.id], _index: undefined })) continue
entry.diff = "edit"
}
return entry
})
// Mark removed entries
const atlasReduced = atlasAll.reduce((atlas, entry) => {
delete entry._index
atlas[entry.id] = entry
return atlas
}, {})
const removedEntries = liveAtlas.filter(entry => !atlasReduced[entry.id]).map(entry => {
delete entry._index
entry.diff = "delete"
return entry
})
atlasAll.push(...removedEntries)
if (mode.includes("only")) {
atlasAll = atlasAll.filter(entry => entry.diff)
}
atlas = generateAtlasForPeriod()
// Mark removed entries
for (const entry of Object.values(liveAtlasAll)) {
if (!atlasAll[entry.id]) {
entry.diff = "delete"
atlasAll[entry.id] = entry
}
}
if (mode.includes('only')) {
for (const key of Object.keys(atlasAll)) {
if (atlasAll[key].diff) continue
delete atlasAll[key]
}
}
} catch (error) {
console.warn("Diff mode failed to load, reverting to normal view.", error)
@ -255,7 +252,7 @@ async function init() {
zoom = 1
zoomOrigin = [0, 0]
scaleZoomOrigin = [0, 0]
updateLines()
renderLines()
applyView()
})
@ -384,7 +381,6 @@ async function init() {
}
window.addEventListener("mousemove", e => {
// updateLines()
mousemove(e.clientX, e.clientY)
if (dragging) {
e.preventDefault()
@ -417,7 +413,7 @@ async function init() {
scaleZoomOrigin[0] += deltaX / zoom
scaleZoomOrigin[1] += deltaY / zoom
updateLines()
renderLines()
applyView()
}
@ -460,7 +456,7 @@ async function init() {
zoomOrigin[1] = scaleZoomOrigin[1] * zoom
applyView()
updateLines()
renderLines()
}
window.addEventListener("mouseup", e => {
@ -478,7 +474,7 @@ async function init() {
})
window.addEventListener("touchend", touchend)
function mouseup(x, y) {
function mouseup() {
dragging = false
updateHash()
}
@ -486,7 +482,7 @@ async function init() {
function touchend(e) {
if (e.touches.length === 0) {
mouseup()
setTimeout(() => updateLines(), 0)
renderLines()
dragging = false
} else if (e.touches.length === 1) {
@ -506,7 +502,8 @@ async function init() {
}
function updateAtlasAll(atlas = atlasAll) {
function generateAtlasAll(atlas = atlasAll) {
const newAtlas = {}
for (const index in atlas) {
const entry = atlas[index]
entry._index = index
@ -528,22 +525,37 @@ function updateAtlasAll(atlas = atlasAll) {
}
entry.path = currentPath
entry.center = currentCenter
newAtlas[entry.id] = entry
}
return atlas
// console.log(newAtlas)
return newAtlas
}
// Announcement system
// Notice system
const announcementEl = document.querySelector("#headerAnnouncement")
const announcementButton = announcementEl.querySelector('[role=button]')
const announcementText = announcementEl.querySelector('p').textContent.trim()
const noticeEl = document.querySelector("#headerNotice")
const noticeButton = noticeEl.querySelector('[role=button]')
const noticeText = noticeEl.querySelector('p').textContent.trim()
if (announcementText && announcementText !== window.localStorage.getItem('announcement-closed')) {
announcementButton.click()
document.querySelector('#objectsList').style.marginTop = '2.8rem'
const resizeGlobalTopPadding = () => {
document.body.style.setProperty("--global-top-padding", noticeEl.offsetHeight + 'px')
}
announcementEl.querySelector('[role=button]').addEventListener('click', () => {
window.localStorage.setItem('announcement-closed', announcementText)
document.querySelector('#objectsList').style.marginTop = '0'
if (window.localStorage.getItem('announcement-closed')) {
window.localStorage.setItem('closed-notice', window.localStorage.getItem('announcement-closed'))
window.localStorage.removeItem('announcement-closed')
}
if (noticeText && noticeText !== window.localStorage.getItem('closed-notice')) {
noticeButton.click()
setTimeout(() => {
document.body.style.setProperty("--global-top-padding", noticeEl.offsetHeight + 'px')
}, 500)
window.addEventListener('resize', resizeGlobalTopPadding)
}
noticeEl.querySelector('[role=button]').addEventListener('click', () => {
window.localStorage.setItem('closed-notice', noticeText)
window.removeEventListener('resize', resizeGlobalTopPadding)
document.body.style.setProperty("--global-top-padding", null)
})

View File

@ -1,7 +1,7 @@
/*!
* The 2022 r/place Atlas
* Copyright (c) 2017 Roland Rytz <roland@draemm.li>
* Copyright (c) 2022 Place Atlas contributors
* Copyright (c) 2022 Place Atlas Initiative and contributors
* Licensed under AGPL-3.0 (https://2022.place-atlas.stefanocoding.me/license.txt)
*/
@ -9,22 +9,16 @@ function initOverlap() {
window.renderBackground = renderBackground
updateAtlas()
// const hovered = []
resetEntriesList()
renderBackground(atlas)
render()
document.addEventListener('timeupdate', () => {
atlasDisplay = atlas.slice()
resetEntriesList()
renderBackground(atlasDisplay)
render()
updateAtlas()
})
applyView()
render()
updateLines()
renderLines()
if (window.location.hash) {
updateViewFromHash()
@ -37,7 +31,7 @@ function initOverlap() {
backgroundContext.fillStyle = "rgba(255, 255, 255, 1)"
backgroundContext.fillRect(0, 0, highlightCanvas.width, highlightCanvas.height)
for (const entry of atlas) {
for (const entry of Object.values(atlas)) {
const path = entry.path

View File

@ -1,7 +1,7 @@
/*!
* The 2022 r/place Atlas
* Copyright (c) 2017 Roland Rytz <roland@draemm.li>
* Copyright (c) 2022 Place Atlas contributors
* Copyright (c) 2022 Place Atlas Initiative and contributors
* Licensed under AGPL-3.0 (https://2022.place-atlas.stefanocoding.me/license.txt)
*/
@ -203,7 +203,7 @@ console.info("The " + topCount + " largest entries:")
let outstring = ""
for (let i = 0; i < topCount; i++) {
outstring += ((i + 1) + "|[" + atlas[atlas.length - i - 1].name + "](http://2022.place-atlas.stefanocoding.me/?id=" + atlas[atlas.length - i - 1].id + ")|" + ~~atlas[atlas.length - i - 1].area + "|" + Math.round(atlas[atlas.length - i - 1].area / 100) / 100 + "%\n")
outstring += ((i + 1) + "|[" + atlas[atlas.length - i - 1].name + "](http://2023.place-atlas.stefanocoding.me/?id=" + atlas[atlas.length - i - 1].id + ")|" + ~~atlas[atlas.length - i - 1].area + "|" + Math.round(atlas[atlas.length - i - 1].area / 100) / 100 + "%\n")
}
console.info(outstring)

View File

@ -1,7 +1,7 @@
/*!
* The 2022 r/place Atlas
* Copyright (c) 2017 Roland Rytz <roland@draemm.li>
* Copyright (c) 2022 Place Atlas contributors
* Copyright (c) 2022 Place Atlas Initiative and contributors
* Licensed under AGPL-3.0 (https://2022.place-atlas.stefanocoding.me/license.txt)
*/
@ -32,6 +32,12 @@ let currentPeriod = defaultPeriod
window.currentVariation = currentVariation
window.currentPeriod = currentPeriod
let atlasDisplay = {}
window.atlasDisplay = atlasDisplay
const additionalLayers = []
const additionalLayerCanvas = document.createElement('canvas')
// SETUP
if (variationsConfig[currentVariation].versions.length === 1) bottomBar.classList.add('no-time-slider')
@ -70,7 +76,7 @@ const dispatchTimeUpdateEvent = (period = currentPeriod, variation = currentVari
detail: {
period: period,
variation: variation,
periodString: formatPeriod(period, period, variation),
periodString: formatPeriod(period, null, variation),
atlas: atlas
}
})
@ -79,7 +85,7 @@ const dispatchTimeUpdateEvent = (period = currentPeriod, variation = currentVari
async function updateBackground(newPeriod = currentPeriod, newVariation = currentVariation) {
abortController.abort()
myAbortController = new AbortController()
const myAbortController = new AbortController()
abortController = myAbortController
currentUpdateIndex++
const myUpdateIndex = currentUpdateIndex
@ -96,7 +102,7 @@ async function updateBackground(newPeriod = currentPeriod, newVariation = curren
variantsEl.parentElement.classList.remove('input-group')
}
const configObject = variationConfig.versions[currentPeriod]
const configObject = variationConfig.versions[newPeriod]
let layerUrls = []
let layers = []
@ -110,39 +116,67 @@ async function updateBackground(newPeriod = currentPeriod, newVariation = curren
layers.length = layerUrls.length
await Promise.all(layerUrls.map(async (url, i) => {
const imageBlob = await (await fetch(url, { signal: myAbortController.signal })).blob()
const imageLayer = new Image()
await new Promise(resolve => {
imageLayer.onload = () => {
context.canvas.width = Math.max(imageLayer.width, context.canvas.width)
context.canvas.height = Math.max(imageLayer.height, context.canvas.height)
layers[i] = imageLayer
resolve()
}
imageLayer.src = URL.createObjectURL(imageBlob)
})
try {
const imageBlob = await (await fetch(url, { signal: myAbortController.signal })).blob()
const imageLayer = new Image()
await new Promise(resolve => {
imageLayer.onload = () => {
context.canvas.width = Math.max(imageLayer.width, context.canvas.width)
context.canvas.height = Math.max(imageLayer.height, context.canvas.height)
layers[i] = imageLayer
resolve()
}
imageLayer.src = URL.createObjectURL(imageBlob)
})
} catch (e) {
const aborted = myAbortController.signal.aborted
if (!aborted) throw e
}
}))
if (myAbortController.signal.aborted || newPeriod !== currentPeriod || newVariation !== currentVariation) {
return
if (myAbortController.signal.aborted || newPeriod !== currentPeriod || newVariation !== currentVariation || currentUpdateIndex !== myUpdateIndex) {
return false
}
for (const imageLayer of layers) {
context.drawImage(imageLayer, 0, 0)
}
context.drawImage(additionalLayerCanvas, 0, 0)
if (myAbortController.signal.aborted || newPeriod !== currentPeriod || newVariation !== currentVariation || currentUpdateIndex !== myUpdateIndex) {
return false
}
if (currentUpdateIndex !== myUpdateIndex) return [configObject, newPeriod, newVariation]
const blob = await new Promise(resolve => canvas.toBlob(resolve))
canvasUrl = URL.createObjectURL(blob)
image.src = canvasUrl
return true
}
let loadingTimeout = setTimeout(() => {}, 0)
async function updateTime(newPeriod = currentPeriod, newVariation = currentVariation, forceLoad = false) {
if (newPeriod === currentPeriod && !forceLoad) {
return;
if (newPeriod === currentPeriod && newVariation === currentVariation && !forceLoad) {
return
}
document.body.dataset.canvasLoading = ""
const loadingEl = document.getElementById("loading")
const previouslyHidden = loadingEl.classList.contains("d-none")
if (previouslyHidden) loadingEl.classList.add("opacity-0", "transition-opacity")
clearTimeout(loadingTimeout)
loadingTimeout = setTimeout(() => {
loadingEl.classList.remove("d-none")
if (previouslyHidden) setTimeout(() => {
loadingEl.classList.remove("opacity-0")
}, 0)
}, 2000)
// const oldPeriod = currentPeriod
const oldVariation = currentVariation
@ -167,12 +201,16 @@ async function updateTime(newPeriod = currentPeriod, newVariation = currentVaria
timelineSlider.value = currentPeriod
updateTooltip(newPeriod, newVariation)
await updateBackground(newPeriod, newVariation)
const updateBackgroundResult = await updateBackground(newPeriod, newVariation)
atlas = generateAtlasForPeriod(newPeriod, newVariation)
if (!updateBackgroundResult) return
dispatchTimeUpdateEvent(newPeriod, newVariation, atlas)
delete document.body.dataset.canvasLoading
clearTimeout(loadingTimeout)
document.getElementById("loading").classList.add("d-none")
document.getElementById("loading").classList.remove("opacity-0", "opacity-100", "transition-opacity")
tooltip.dataset.forceVisible = ""
clearTimeout(tooltipDelayHide)
tooltipDelayHide = setTimeout(() => {
@ -181,24 +219,30 @@ async function updateTime(newPeriod = currentPeriod, newVariation = currentVaria
}
function generateAtlasForPeriod(newPeriod = currentPeriod, newVariation = currentVariation) {
function generateAtlasDisplay(prevAtlas, prevAtlasOrder, newPeriod = currentPeriod, newVariation = currentVariation) {
const newAtlas = {}
const newAtlasOrderDisplayed = []
const newAtlasOrderNotDisplayed = []
for (const id of prevAtlasOrder) {
newAtlasOrderNotDisplayed.push(id)
const entry = prevAtlas[id]
const atlas = []
for (const entry of atlasAll) {
let chosenIndex
const validPeriods2 = Object.keys(entry.path)
for (const i in validPeriods2) {
periodCheck: for (const i in validPeriods2) {
const validPeriods = validPeriods2[i].split(', ')
for (const j in validPeriods) {
const [start, end, variation] = parsePeriod(validPeriods[j])
if (isOnPeriod(start, end, variation, newPeriod, newVariation)) {
chosenIndex = i
break
break periodCheck
}
}
if (chosenIndex !== undefined) break
}
if (chosenIndex === undefined) continue
@ -207,14 +251,18 @@ function generateAtlasForPeriod(newPeriod = currentPeriod, newVariation = curren
if (pathChosen === undefined) continue
atlas.push({
newAtlas[id] = {
...entry,
path: pathChosen,
center: centerChosen,
})
}
newAtlasOrderNotDisplayed.pop()
newAtlasOrderDisplayed.push(id)
}
return atlas
return [newAtlas, [...newAtlasOrderDisplayed, ...newAtlasOrderNotDisplayed]]
}
@ -273,7 +321,7 @@ function parsePeriod(periodString) {
function formatPeriod(targetStart, targetEnd, targetVariation, forUrl = false) {
targetStart ??= currentPeriod
targetEnd ??= currentPeriod
targetEnd ??= targetStart
targetVariation ??= currentVariation
let periodString, variationString
@ -297,12 +345,11 @@ function setReferenceVal(reference, newValue) {
else return reference ?? newValue
}
function formatHash(targetEntry, targetPeriodStart, targetPeriodEnd, targetVariation, targetX, targetY, targetZoom) {
function formatHash(targetEntry, targetPeriod, targetVariation, targetX, targetY, targetZoom) {
let hashData = window.location.hash.substring(1).split('/')
targetEntry = setReferenceVal(targetEntry, hashData[0])
targetPeriodStart = setReferenceVal(targetPeriodStart, currentPeriod)
targetPeriodEnd = setReferenceVal(targetPeriodEnd, currentPeriod)
targetPeriod = setReferenceVal(targetPeriod, currentPeriod)
targetVariation = setReferenceVal(targetVariation, currentVariation)
targetX = setReferenceVal(targetX, canvasCenter.x - scaleZoomOrigin[0])
targetY = setReferenceVal(targetY, canvasCenter.y - scaleZoomOrigin[1])
@ -313,8 +360,8 @@ function formatHash(targetEntry, targetPeriodStart, targetPeriodEnd, targetVaria
if (targetZoom) targetZoom = targetZoom.toFixed(3).replace(/\.?0+$/, '')
const result = [targetEntry]
const targetPeriod = formatPeriod(targetPeriodStart, targetPeriodEnd, targetVariation, true)
result.push(targetPeriod, targetX, targetY, targetZoom)
const targetPeriodFormat = formatPeriod(targetPeriod, null, targetVariation, true)
result.push(targetPeriodFormat, targetX, targetY, targetZoom)
if (!result.some(el => el || el === 0)) return ''
return '#' + result.join('/').replace(/\/+$/, '')
}
@ -327,4 +374,63 @@ function downloadCanvas() {
document.body.appendChild(linkEl)
linkEl.click()
document.body.removeChild(linkEl)
}
}
function getNearestPeriod(entry, targetPeriod, targetVariation) {
const pathKeys = Object.keys(entry.path)
let nearestScore, nearestPeriod, nearestVariation, nearestKey
function updateNearest(newScore, newPeriod, newVariation, newKey) {
if (newScore >= nearestScore) return
nearestScore = newScore
nearestPeriod = newPeriod
nearestVariation = newVariation
nearestKey = newKey
}
checkPaths: for (const pathKey of pathKeys) {
const pathPeriods = pathKey.split(', ')
checkPathPeriod: for (const j in pathPeriods) {
const [pathStart, pathEnd, pathVariation] = parsePeriod(pathPeriods[j])
if (isOnPeriod(pathStart, pathEnd, pathVariation, targetPeriod, targetVariation)) {
updateNearest(0, targetPeriod, targetVariation)
break checkPaths
} else if (pathVariation !== targetVariation) {
updateNearest(Infinity, pathStart, pathVariation, pathKey)
continue checkPathPeriod
} else if (Math.abs(pathStart - targetPeriod) < Math.abs(pathEnd - targetPeriod)) {
updateNearest(Math.abs(pathStart - targetPeriod), pathStart, pathVariation, pathKey)
} else {
updateNearest(Math.abs(pathEnd - targetPeriod), pathStart, pathVariation, pathKey)
}
}
}
return [ nearestPeriod, nearestVariation, nearestKey ]
}
const updateAdditionalLayer = () => {
const layers = additionalLayers
const canvas = additionalLayerCanvas
const context = additionalLayerCanvas.getContext('2d')
canvas.width = 0
canvas.height = 0
for (const layer of layers) {
if (!layer.imageLayer) continue
canvas.width = Math.max(layer.x + layer.imageLayer.width, canvas.width)
canvas.height = Math.max(layer.y + layer.imageLayer.height, canvas.height)
}
for (const layer of layers) {
if (!layer.imageLayer) continue
context.drawImage(layer.imageLayer, layer.x, layer.y)
console.log(layer.imageLayer)
}
}

View File

@ -1,7 +1,7 @@
/*!
* The 2022 r/place Atlas
* Copyright (c) 2017 Roland Rytz <roland@draemm.li>
* Copyright (c) 2022 Place Atlas contributors
* Copyright (c) 2022 Place Atlas Initiative and contributors
* Licensed under AGPL-3.0 (https://2022.place-atlas.stefanocoding.me/license.txt)
*/
@ -43,7 +43,11 @@ objectEditNav.className = "btn btn-outline-primary"
objectEditNav.id = "objectEditNav"
objectEditNav.textContent = "Edit"
let atlasDisplay
let atlas = null
window.atlas = atlas
let atlasOrder = []
window.atlasOrder = atlasOrder
const entriesLimit = 50
let entriesOffset = 0
@ -65,18 +69,18 @@ const moreEntriesObserver = new IntersectionObserver(entries => {
moreEntriesObserver.observe(moreEntriesButton)
let defaultSort = sortInput.value
let defaultSort = sortInput.value
let lastPos = [0, 0]
let fixed = false; // Fix hovered items in place, so that clicking on links is possible
searchInput.addEventListener("input", function () {
resetEntriesList()
updateAtlas()
})
sortInput.addEventListener("input", function () {
resetEntriesList()
updateAtlas()
})
offcanvasDraw.addEventListener('show.bs.offcanvas', () => {
@ -112,8 +116,8 @@ offcanvasList.addEventListener('shown.bs.offcanvas', e => {
wrapper.classList.remove('listTransitioning')
updateHovering(e)
applyView()
render()
updateLines()
renderHighlight()
renderLines()
})
offcanvasList.addEventListener('hide.bs.offcanvas', () => {
@ -127,63 +131,59 @@ offcanvasList.addEventListener('hidden.bs.offcanvas', e => {
wrapper.classList.remove('listTransitioning')
updateHovering(e)
applyView()
render()
updateLines()
renderHighlight()
renderLines()
})
closeObjectsListButton.addEventListener("click", clearObjectsList)
bottomBar.addEventListener("mouseover", () => {
if (!fixed) clearObjectsList()
})
function clearObjectsList() {
hovered = []
fixed = false
renderLines()
renderHighlight()
document.title = pageTitle
closeObjectsListButton.classList.add("d-none")
objectsListOverflowNotice.classList.add("d-none")
entriesList.classList.remove("disableHover")
hovered = []
objectsContainer.replaceChildren()
updateLines()
fixed = false
render()
objectEditNav.remove()
updateHash(false)
document.title = pageTitle
}
function toggleFixed(e, tapped) {
if (!fixed && hovered.length === 0) {
entriesList.classList.remove("disableHover")
return 0
return
}
fixed = !fixed
if (!fixed) {
updateHovering(e, tapped)
render()
renderHighlight()
}
entriesList.classList.add("disableHover")
objectsListOverflowNotice.classList.add("d-none")
}
window.addEventListener("resize", updateLines)
window.addEventListener("mousemove", updateLines)
window.addEventListener("dblClick", updateLines)
window.addEventListener("wheel", updateLines)
window.addEventListener("dblClick", renderLines)
window.addEventListener("wheel", renderLines)
objectsContainer.addEventListener("scroll", () => {
updateLines()
renderLines()
})
window.addEventListener("resize", () => {
applyView()
render()
updateLines()
renderHighlight()
renderLines()
})
function updateLines() {
async function renderLines() {
if (hovered.length === 0) {
linesContext.clearRect(0, 0, linesCanvas.width, linesCanvas.height)
return
}
// Line border
linesCanvas.width = linesCanvas.clientWidth
linesCanvas.height = linesCanvas.clientHeight
@ -260,9 +260,9 @@ function renderBackground(atlas) {
backgroundContext.fillStyle = "rgba(0, 0, 0, 0.6)"
backgroundContext.fillRect(0, 0, backgroundCanvas.width, backgroundCanvas.height)
for (let i = 0; i < atlas.length; i++) {
for (const entry of Object.values(atlas)) {
const path = atlas[i].path
const path = entry.path
backgroundContext.beginPath()
@ -279,7 +279,7 @@ function renderBackground(atlas) {
backgroundContext.closePath()
let bgStrokeStyle
switch (atlas[i].diff) {
switch (entry.diff) {
case "add":
bgStrokeStyle = "rgba(0, 255, 0, 1)"
backgroundContext.lineWidth = 2
@ -299,45 +299,39 @@ function renderBackground(atlas) {
backgroundContext.strokeStyle = bgStrokeStyle
backgroundContext.stroke()
backgroundContext.lineWidth = 1
}
}
function buildObjectsList(filter, sort) {
function filterAtlas(prevAtlas) {
atlasDisplay = atlas.slice()
const sort = sortInput.value || defaultSort
const search = searchInput?.value.toLowerCase()
let newAtlas = Object.assign({}, prevAtlas)
let newAtlasOrder = []
if (filter) {
atlasDisplay = atlas.filter(entry => {
return (
entry.name.toLowerCase().includes(filter.toLowerCase())
|| entry.description?.toLowerCase().includes(filter.toLowerCase())
|| Object.values(entry.links).flat().some(str => str.toLowerCase().includes(filter))
|| entry.id.toString() === filter
)
})
document.getElementById("atlasSize").innerHTML = "Found " + atlasDisplay.length + " entries."
} else {
document.getElementById("atlasSize").innerHTML = "The Atlas contains " + atlasDisplay.length + " entries."
document.getElementById("atlasSize").innerHTML = ""
if (search) {
for (const [id, entry] of Object.entries(prevAtlas)) {
if (!(
entry.name.toLowerCase().includes(search.toLowerCase()) ||
entry.description?.toLowerCase().includes(search.toLowerCase()) ||
Object.values(entry.links).flat().some(str => str.toLowerCase().includes(search)) ||
id.toString() === search
)) delete newAtlas[id]
}
}
renderBackground(atlasDisplay)
render()
sort ||= defaultSort
document.getElementById("sort").value = sort
//console.log(sort)
// document.getElementById("sort").value = sort
let sortFunction
//console.log(sort)
switch (sort) {
case "shuffle":
sortFunction = null
if (entriesOffset === 0) {
shuffle()
}
sortFunction = () => Math.random() - 0.5
break
case "alphaAsc":
sortFunction = (a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase())
@ -369,100 +363,130 @@ function buildObjectsList(filter, sort) {
break
}
newAtlasOrder = Object.keys(newAtlas)
if (sortFunction) {
atlasDisplay.sort(sortFunction)
newAtlasOrder = newAtlasOrder.sort((a, b) => sortFunction(prevAtlas[a], prevAtlas[b]))
}
// console.log(newAtlas, newAtlasOrder)
return [newAtlas, newAtlasOrder]
}
function updateAtlas() {
;[atlas, atlasOrder] = filterAtlas(atlasAll)
;[atlasDisplay, atlasOrder] = generateAtlasDisplay(atlas, atlasOrder, currentPeriod, currentVariation)
const atlasSizeEl = document.getElementById("atlasSize")
if (Object.keys(atlas).length === Object.keys(atlasAll).length) {
atlasSizeEl.innerHTML = Object.keys(atlasAll).length + " entries in total."
} else {
atlasSizeEl.innerHTML = "Found " + Object.keys(atlas).length + " entries."
}
atlasSizeEl.innerHTML += " Displaying " + Object.keys(atlasDisplay).length + " entries."
resetEntriesList()
renderBackground(atlasDisplay)
renderHighlight(atlasDisplay)
}
async function resetEntriesList() {
entriesOffset = 0
entriesList.replaceChildren()
entriesList.appendChild(moreEntriesButton)
moreEntriesButton.removeEventListener('click', showMoreEntries)
showMoreEntries = () => {
if (entriesList.contains(moreEntriesButton)) {
entriesList.removeChild(moreEntriesButton)
}
for (let i = entriesOffset; i < entriesOffset + entriesLimit; i++) {
if (i >= atlasDisplay.length) break
const element = createInfoBlock(atlasDisplay[i])
const entry = atlasDisplay[i]
element.addEventListener("mouseenter", function () {
if (fixed || dragging) return
objectsContainer.replaceChildren()
previousScaleZoomOrigin ??= [...scaleZoomOrigin]
previousZoom ??= zoom
setView(entry.center[0], entry.center[1], setZoomByPath(entry.path))
hovered = [entry]
render()
hovered[0].element = this
updateLines()
})
element.addEventListener("click", e => {
toggleFixed(e)
if (!fixed) return
previousScaleZoomOrigin ??= [...scaleZoomOrigin]
previousZoom ??= zoom
applyView()
})
element.addEventListener("mouseleave", () => {
if (fixed || dragging) return
scaleZoomOrigin = [...previousScaleZoomOrigin]
zoom = previousZoom
previousScaleZoomOrigin = undefined
previousZoom = undefined
applyView()
hovered = []
updateLines()
render()
})
entriesList.appendChild(element)
}
entriesOffset += entriesLimit
if (atlasDisplay.length > entriesOffset) {
moreEntriesButton.innerHTML = "Show " + Math.min(entriesLimit, atlasDisplay.length - entriesOffset) + " more"
let entriesLeft = entriesLimit
let element
while (entriesLeft > 0 && atlasOrder.length > entriesOffset) {
if (atlasDisplay[atlasOrder[entriesOffset]]) {
// console.log(i, entriesLeft)
let entry = atlasDisplay[atlasOrder[entriesOffset]]
element = createInfoBlock(entry)
element.addEventListener("mouseenter", function () {
if (fixed || dragging) return
objectsContainer.replaceChildren()
previousScaleZoomOrigin ??= [...scaleZoomOrigin]
previousZoom ??= zoom
setView(entry.center[0], entry.center[1], calculateZoomFromPath(entry.path))
hovered = [entry]
renderHighlight()
hovered[0].element = this
renderLines()
})
element.addEventListener("click", e => {
fixed = true
previousScaleZoomOrigin ??= [...scaleZoomOrigin]
previousZoom ??= zoom
applyView()
})
element.addEventListener("mouseleave", () => {
if (fixed || dragging) return
scaleZoomOrigin = [...previousScaleZoomOrigin]
zoom = previousZoom
previousScaleZoomOrigin = undefined
previousZoom = undefined
applyView()
hovered = []
renderLines()
renderHighlight()
})
} else {
let entry = atlas[atlasOrder[entriesOffset]]
element = createInfoBlock(entry, 1)
element.addEventListener("click", async e => {
e.preventDefault()
const [nearestPeriod, nearestVariation] = getNearestPeriod(entry, currentPeriod, currentVariation)
await updateTime(nearestPeriod, nearestVariation, true)
entry = atlasDisplay[entry.id]
element = createInfoBlock(entry)
hovered = [{ ...entry, element }]
fixed = true
previousScaleZoomOrigin = undefined
previousZoom = undefined
const hash = formatHash(entry.id, nearestPeriod, nearestVariation, entry.center[0], entry.center[1], calculateZoomFromPath(entry.path))
location.hash = hash
})
}
entriesOffset += 1
entriesLeft -= 1
entriesList.appendChild(element)
}
if (atlasOrder.length > entriesOffset) {
moreEntriesButton.innerHTML = "Show " + Math.min(entriesLimit, atlasOrder.length - entriesOffset) + " more"
entriesList.appendChild(moreEntriesButton)
}
}
moreEntriesButton.addEventListener('click', showMoreEntries)
showMoreEntries()
}
function shuffle() {
//console.log("shuffled atlas")
for (let i = atlasDisplay.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1))
const temp = atlasDisplay[i]
atlasDisplay[i] = atlasDisplay[j]
atlasDisplay[j] = temp
}
}
function resetEntriesList() {
entriesOffset = 0
entriesList.replaceChildren()
entriesList.appendChild(moreEntriesButton)
const sort = sortInput.value || defaultSort
const search = searchInput?.value.toLowerCase()
buildObjectsList(search, sort)
}
async function render() {
async function renderHighlight() {
highlightContext.clearRect(0, 0, highlightCanvas.width, highlightCanvas.height)
@ -478,10 +502,8 @@ async function render() {
container.style.cursor = "default"
}
for (let i = 0; i < hovered.length; i++) {
const path = hovered[i].path
highlightContext.beginPath()
@ -507,28 +529,6 @@ async function render() {
highlightContext.globalCompositeOperation = "source-out"
highlightContext.drawImage(backgroundCanvas, 0, 0)
if (hovered.length === 1 && hovered[0].path.length && hovered[0].overrideImage) {
const undisputableHovered = hovered[0]
// Find the left-topmost point of all the paths
const entryPosition = getPositionOfEntry(undisputableHovered)
if (entryPosition) {
const [startX, startY] = entryPosition
const overrideImage = new Image()
const loadingPromise = new Promise((res, rej) => {
overrideImage.onerror = rej
overrideImage.onload = res
})
overrideImage.src = "imageOverrides/" + undisputableHovered.overrideImage
try {
await loadingPromise
highlightContext.globalCompositeOperation = "source-over"
highlightContext.drawImage(overrideImage, startX, startY)
} catch (ex) {
console.error("Cannot override image.", ex)
}
}
}
for (let i = 0; i < hovered.length; i++) {
const path = hovered[i].path
@ -591,12 +591,16 @@ function updateHovering(e, tapped) {
const pos = updateCoordsDisplay(e)
if (!(pos[0] <= canvasSize.x + canvasOffset.x + 200 && pos[0] >= canvasOffset.x - 200 && pos[1] <= canvasSize.y + canvasOffset.y + 200 && pos[1] >= canvasOffset.x - 200)) return
const newHovered = []
for (const entry of atlasDisplay) {
let newHovered = []
for (const entry of Object.values(atlasDisplay)) {
if (pointIsInPolygon(pos, entry.path)) newHovered.push(entry)
}
newHovered = newHovered.sort(function (a, b) {
return calcPolygonArea(a.path) - calcPolygonArea(b.path)
})
let changed = false
if (hovered.length === newHovered.length) {
@ -612,9 +616,7 @@ function updateHovering(e, tapped) {
if (!changed) return
hovered = newHovered.sort(function (a, b) {
return calcPolygonArea(a.path) - calcPolygonArea(b.path)
})
hovered = newHovered
objectsContainer.replaceChildren()
@ -639,12 +641,13 @@ function updateHovering(e, tapped) {
objectsListOverflowNotice.classList.add("d-none")
entriesList.classList.remove("disableHover")
}
render()
renderLines()
renderHighlight()
}
window.addEventListener("hashchange", updateViewFromHash)
function updateViewFromHash() {
async function updateViewFromHash() {
const hash = window.location.hash.substring(1); //Remove hash prefix
let [hashEntryId, hashPeriod, hashX, hashY, hashZoom] = hash.split('/')
@ -666,11 +669,11 @@ function updateViewFromHash() {
targetPeriod = defaultPeriod
targetVariation = defaultVariation
}
updateTime(targetPeriod, targetVariation, true)
await updateTime(targetPeriod, targetVariation)
setView(
(isNaN(hashX) || hashX === '') ? undefined : Number(hashX),
(isNaN(hashY) || hashY === '') ? undefined : Number(hashY),
(isNaN(hashX) || hashX === '') ? undefined : Number(hashX),
(isNaN(hashY) || hashY === '') ? undefined : Number(hashY),
(isNaN(hashZoom) || hashZoom === '') ? undefined : Number(hashZoom)
)
@ -678,13 +681,8 @@ function updateViewFromHash() {
// Highlight entry from hash
const entries = atlas.filter(e => {
return e.id.toString() === hashEntryId
})
if (entries.length !== 1) return
const entry = entries[0]
const entry = atlasDisplay[hashEntryId]
if (!entry) return
document.title = entry.name + " on " + pageTitle
@ -702,24 +700,24 @@ function updateViewFromHash() {
objectsContainer.replaceChildren()
objectsContainer.appendChild(infoElement)
renderBackground(atlas)
setView(
(isNaN(hashX) || hashX === '') ? entry.center[0] : Number(hashX),
(isNaN(hashY) || hashY === '') ? entry.center[1] : Number(hashY),
(isNaN(hashZoom) || hashZoom === '') ? setZoomByPath(entry.path) : Number(hashZoom)
(isNaN(hashX) || hashX === '') ? entry.center[0] : Number(hashX),
(isNaN(hashY) || hashY === '') ? entry.center[1] : Number(hashY),
(isNaN(hashZoom) || hashZoom === '') ? calculateZoomFromPath(entry.path) : Number(hashZoom)
)
closeObjectsListButton.classList.remove("d-none")
entriesList.classList.add("disableHover")
hovered = [entry]
render()
hovered[0].element = infoElement
updateLines()
hovered = [{...entry, element: infoElement}]
renderBackground(atlasDisplay)
renderHighlight(atlasDisplay)
renderLines()
}
function setZoomByPath(path) {
function calculateZoomFromPath(path) {
let zoom
let boundingBox = [canvasSize.x + canvasOffset.x, canvasOffset.x, canvasSize.y + canvasOffset.y, canvasOffset.y]
path?.forEach(([x, y]) => {
boundingBox[0] = Math.min(boundingBox[0], x)
@ -741,13 +739,10 @@ function setZoomByPath(path) {
function initView() {
buildObjectsList(null, null)
renderBackground(atlas)
render()
updateAtlas()
document.addEventListener('timeupdate', () => {
atlasDisplay = atlas.slice()
resetEntriesList()
updateAtlas()
})
// parse linked atlas entry id from link hash
@ -758,22 +753,20 @@ function initView() {
}*/
applyView()
render()
updateLines()
renderLines()
}
function initExplore() {
window.updateHovering = updateHovering
window.render = () => { }
window.renderHighlight = () => { }
function updateHovering(e, tapped) {
if (dragging || (fixed && !tapped)) return
updateCoordsDisplay(e)
}
renderBackground(atlas)
renderBackground({})
applyView()
@ -790,7 +783,7 @@ function initGlobal() {
}
})
document.addEventListener('timeupdate', event => {
document.addEventListener('timeupdate', () => {
updateHash()
})
}
@ -837,6 +830,84 @@ function initViewGlobal() {
}
document.addEventListener('timeupdate', event => {
drawButton.href = "./?mode=draw" + formatHash(null, event.detail.period, event.detail.period, event.detail.variation)
drawButton.href = "./?mode=draw" + formatHash(null, event.detail.period, event.detail.variation)
})
document.addEventListener("mouseleave", () => {
if (!fixed) clearObjectsList()
})
}
async function loadTemplateData(initUrl, datas, blacklistUrls, level = 0) {
datas ??= {}
blacklistUrls ??= new Set()
if (datas[initUrl] || blacklistUrls.has(initUrl)) return [ datas, blacklistUrls ]
datas[initUrl] = {}
try {
const data = await (await fetch(initUrl)).json()
datas[initUrl] = data
for (const blacklisted of data?.blacklist) {
blacklistUrls.add(blacklisted.url)
}
await Promise.all(data?.whitelist.map(async wl => {
const [ wlDatas, wlBlacklistUrls ] = await loadTemplateData(wl.url, datas, blacklistUrls, level + 1)
Object.assign(datas, wlDatas)
blacklistUrls.add(...wlBlacklistUrls)
}))
} catch (e) {}
return [ datas, [...blacklistUrls] ]
}
async function loadTemplateImages(datas) {
const templates = []
for (const data of Object.values(datas)) {
if (!data?.templates) continue
for (const template of data?.templates) {
templates.push(template)
}
}
await Promise.all(templates.map(async (template, i) => {
if (!template.sources) return
for (const source of template.sources) {
try {
const sourceResponse = await (await fetch(source)).blob()
template.blob = URL.createObjectURL(sourceResponse)
break
} catch (e) {}
}
delete template.sources
if (!template.blob) return
const imageLayer = new Image()
await new Promise(resolve => {
imageLayer.onload = () => {
template.imageLayer = imageLayer
delete template.blob
resolve()
}
imageLayer.onerror = () => {
delete template
resolve()
}
imageLayer.src = template.blob
})
}))
for (const layer of templates) {
if (!layer.imageLayer) delete layer
}
return templates
}

View File

@ -1,7 +1,7 @@
<!--
The 2022 r/place Atlas
Copyright (c) 2017 Roland Rytz <roland@draemm.li>
Copyright (c) 2022 Place Atlas contributors
Copyright (c) 2022 Place Atlas Initiative and contributors
Licensed under AGPL-3.0 (https://2022.place-atlas.stefanocoding.me/license.txt)
-->
@ -10,8 +10,8 @@
<head>
<meta charset="UTF-8">
<title>About - The 2022 r/place Atlas</title>
<meta name="description" content="This is an atlas aiming to chart all the artworks created during the r/place April Fools event on Reddit in 2022. It is made with information to each artwork of the canvas provided by the community.">
<meta name="author" content="Place Atlas contributors (original by Roland Rytz)">
<meta name="description" content="This is an interactive map aiming to chart all the artworks created during the r/place April Fools event on Reddit in 2022. It is made with information to each artwork of the canvas provided by the community.">
<meta name="author" content="Place Atlas Initiative and contributors (original by Roland Rytz)">
<meta name="application-name" content="2022 r/place Atlas">
<meta name="robots" content="index, follow">
@ -23,18 +23,19 @@
<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="This is an atlas aiming to chart all the artworks created during the r/place April Fools event on Reddit in 2022. It is made with information to each artwork of the canvas provided by the community.">
<meta property="og:description" content="This is an interactive map aiming to chart all the artworks created during the r/place April Fools event on Reddit in 2022. It is made with information to each artwork of the canvas provided by the community.">
<meta name="twitter:card" content="summary">
<meta name="twitter:creator" content="Place Atlas contributors (original by Roland Rytz)">
<meta name="twitter:url" content="https://2022.place-atlas.stefanocoding.me/">
<meta name="twitter:title" content="About - The 2022 r/place Atlas">
<meta name="twitter:description" content="This is an atlas aiming to chart all the artworks created during the r/place April Fools event on Reddit in 2022. It is made with information to each artwork of the canvas provided by the community.">
<meta name="twitter:description" content="This is an interactive map aiming to chart all the artworks created during the r/place April Fools event on Reddit in 2022. It is made with information to each artwork of the canvas provided by the community.">
<meta name="twitter:image" content="https://2022.place-atlas.stefanocoding.me/_img/logo.png">
<meta name="twitter:image:alt" content="The 2022 r/place Atlas logo">
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, viewport-fit=cover">
<meta name="color-scheme" content="light dark">
<meta name="theme-color" media="(prefers-color-scheme: light)" content="white">
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#222">
<link rel="apple-touch-icon" href="_img/apple-touch-icon.png" sizes="180x180">
<link rel="icon alternate" href="_img/favicon.png" type="image/png" class="js-site-favicon">
@ -60,8 +61,8 @@
<i class="bi bi-list" aria-hidden="true"></i>
</button>
<div class="navbar-collapse collapse" id="navbarCollapse">
<ul class="navbar-nav ms-auto pt-2 pt-md-0">
<li class="nav-item dropdown">
<ul class="navbar-nav flex-row flex-wrap ms-auto pt-2 pt-md-0">
<li class="nav-item col-6 col-md-auto dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false" aria-current="page">
Atlas Map
</a>
@ -72,9 +73,12 @@
</ul>
</li>
<li class="nav-item col-6 col-md-auto">
<a class="nav-link" href="https://place-wiki.stefanocoding.me/">Place Wiki</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://place-wiki.stefanocoding.me/" target="_blank">Place Wiki</a>
</li>
<li class="nav-item col-6 col-md-auto">
<a class="nav-link" href="https://github.com/placeAtlas/atlas-2022" target="_blank">Source</a>
</li>
<li class="nav-item col-6 col-md-auto">
<a class="nav-link active" href="#" aria-current="page">About</a>
</li>
</ul>
@ -86,119 +90,35 @@
<div class="row g-5">
<div class="col-md-7 col-xl-8">
<h1 class="display-5 fw-bold mb-4">The 2022 r/place Atlas</h1>
<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. It is made with information to each artwork of the canvas provided by the community.</p>
<p>The original code was developed by <a href="https://draemm.li/various/place-atlas/">Roland Rytz</a> <a href="mailto:roland.rytz@gmail.com"><i aria-label="Mail" class="bi bi-envelope"></i></a> <a href="https://reddit.com/user/draemmli/"><i aria-label="Reddit" class="bi bi-reddit"></i></a> and is available under the free <a href="https://www.gnu.org/licenses/agpl-3.0.en.html">AGPL license</a> on <a href="https://github.com/RolandR/place-atlas">GitHub</a>.</p>
<p>This is an interactive map aiming to chart all the artworks created during the <a href="https://www.reddit.com/r/place/" target="_blank" rel="noreferrer">r/place</a> April Fools event on Reddit in 2022. It is made with information to each artwork of the canvas provided by the community.</p>
<p>The original code was developed by <a href="https://draemm.li/various/place-atlas/" target="_blank" rel="noreferrer">Roland Rytz</a> <a href="mailto:roland.rytz@gmail.com"><i aria-label="Mail" class="bi bi-envelope"></i></a> <a href="https://reddit.com/user/draemmli/" target="_blank" rel="noreferrer"><i aria-label="Reddit" class="bi bi-reddit"></i></a> and is available under the free <a href="https://www.gnu.org/licenses/agpl-3.0.en.html" target="_blank" rel="noreferrer">AGPL license</a> on <a href="https://github.com/RolandR/place-atlas" target="_blank">GitHub</a>.</p>
<p>The currently maintained version of the website is managed by <a href="https://place-atlas.stefanocoding.me" target="_blank">Place Atlas Initiative</a>, led by Stefano Haagmans and is obtainable under the same license within a <a href="https://github.com/placeAtlas/atlas-2022" target="_blank">GitHub fork</a>.</p>
<hr>
<p>The currently maintained version of the website is managed by <a href="https://github.com/placeAtlas">the Place Atlas team</a>, led by Stefano Haagmans and is obtainable under the same license within a <a href="https://github.com/placeAtlas/atlas-2022">GitHub fork</a>. Initial 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">PayPal</a>, <a href="https://www.patreon.com/placeAtlas">Patreon</a>, or <a href="https://ko-fi.com/placeatlas">Ko-Fi</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="noreferrer">PayPal</a>, <a href="https://www.patreon.com/placeAtlas" target="_blank" rel="noreferrer">Patreon</a>, or <a href="https://ko-fi.com/placeatlas" target="_blank" rel="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">PayPal</a>. If you donate more than 10(€/$/CHF/mBTC), He'll (hopefully) send you a nice sticker of the 2017 Place canvas!</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="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>
<p class="blockquote-footer mt-0">Stefano Haagmans</p>
<h2>Contributing</h2>
<p>This project is open source, and contributions are welcome. In fact, the Atlas relies on user contributions.</p>
<p>To contribute a label for an artwork, please read <a href="https://github.com/placeAtlas/atlas-2022/blob/master/CONTRIBUTING.md">this guide</a> to learn how to submit a new entry, edit existing entries, or contribute to the development of the codebase.</p>
<p><a href="https://reddit.com/r/placeAtlas2/">The r/placeAtlas2 subreddit</a> and <a href="https://discord.gg/pJkm23b2nA">the Discord server</a> is also the place to submit all bug reports, feature requests, or questions.</p>
<p>To contribute a label for an artwork, please read <a href="https://github.com/placeAtlas/atlas-2022/blob/master/CONTRIBUTING.md" target="_blank">the contributing guide</a> to learn how to submit a new entry, edit existing entries, or contribute to the development of the codebase.</p>
<p><a href="https://reddit.com/r/placeAtlas2/" target="_blank" rel="noreferrer">The r/placeAtlas2 subreddit</a> and <a href="https://discord.gg/pJkm23b2nA" target="_blank" rel="noreferrer">the Discord server</a> is also the place to submit all bug reports, feature requests, or questions.</p>
<div id="credits">
<h2>Credit</h2>
<h2 class="mb-2">Credits</h2>
<h3>Project Contributors</h3>
<p>This section is focused towards the project development as a whole, excluding entry contributions, but including, and not limited to, code contributions, toolset, documentation, etc.</p>
<ul>
<li>Project Lead:
<a href="https://reddit.com/user/TCOOfficiall">TCOOfficiall</a> (Stefano Haagmans)
<a href="https://stefanocoding.me/"><i aria-label="Website" class="bi bi-globe"></i></a>
<a href="https://github.com/Codixer"><i aria-label="GitHub" class="bi bi-github"></i></a>
</li>
<li>Archival Team:
<ul>
<li>
<a href="https://github.com/electric-blue">electric-blue</a> (tycho)
<a href="https://github.com/ab-gh"><i aria-label="GitHub" class="bi bi-github"></i></a>
</li>
<li>
Nick12
<a href="https://github.com/nico-abram"><i aria-label="GitHub" class="bi bi-github"></i></a>
</li>
<li>
<a href="https://reddit.com/user/m654zy">m654zy</a>
</li>
<li>
<a href="https://reddit.com/user/AnonymousRandPerson">AnonymousRandPerson</a>
<a href="https://github.com/AnonymousRandomPerson"><i aria-label="GitHub" class="bi bi-github"></i></a>
</li>
</ul>
</li>
<li>Development Team:
<ul>
<li>skyyc</li>
<li>
<a href="https://reddit.com/user/prosto_sanja">prosto_sanja</a> (Alex Tsernoh)
<a href="https://place.thatguyalex.com/"><i aria-label="Website" class="bi bi-globe"></i></a>
<a href="https://github.com/ProstoSanja"><i aria-label="GitHub" class="bi bi-github"></i></a>
</li>
<li>jso</li>
<li>
<a href="https://reddit.com/user/Hans5958_">Hans5958_</a>
<a href="https://hans5958.github.io/"><i aria-label="Website" class="bi bi-globe"></i></a>
<a href="https://github.com/Hans5958"><i aria-label="GitHub" class="bi bi-github"></i></a>
</li>
<li>
<a href="https://reddit.com/user/mxdanger">mxdanger</a>
<a href="https://github.com/mxdanger"><i aria-label="GitHub" class="bi bi-github"></i></a>
</li>
</ul>
</li>
<li>Wiki Team:
<ul>
<li>
<a href="https://reddit.com/user/xXLInkster17Xx">xXLInkster17Xx</a> (Aeywoo)
<a href="https://github.com/Aeywoo"><i aria-label="GitHub" class="bi bi-github"></i></a>
</li>
<li>
Nick12
<a href="https://github.com/nico-abram"><i aria-label="GitHub" class="bi bi-github"></i></a>
</li>
<li>pax</li>
<li>Artillect</li>
<li>axollyon</li>
<li>
<a href="https://reddit.com/user/Crkza">Crzka</a> (Cappy)
<a href="https://github.com/korewaChino"><i aria-label="GitHub" class="bi bi-github"></i></a>
</li>
<li>CodeDev</li>
<li>dntk</li>
<li>Eurobat</li>
<li>FuriousChocolate</li>
<li>
<a href="https://reddit.com/geekahedron">geekahedron</a>
</li>
<li>Jim Milton</li>
<li>
Noah
<a href="https://github.com/NoahS04"><i aria-label="GitHub" class="bi bi-github"></i></a>
</li>
<li>Saya</li>
<li>
Sodapone
<a href="https://github.com/Sodapone"><i aria-label="GitHub" class="bi bi-github"></i></a>
</li>
<li>
tea
<a href="https://github.com/dreamingkills"><i aria-label="GitHub" class="bi bi-github"></i></a>
</li>
<li>Zurke</li>
</ul>
</li>
<li>Others:
<ul>
<li>"The Final Clean" canvas: r/TheFinalClean community</li>
<li>Everyone who contributes from <a href="https://github.com/placeAtlas/atlas-2022/graphs/contributors">GitHub</a>, <a href="https://discord.gg/pJkm23b2nA">Discord</a>, or other channels.</li>
</ul>
</li>
<li><b>Place Atlas Initiative</b> is the primary maintainer of the project. Please see <a href="https://place-atlas.stefanocoding.me/#team" target="_blank">the Team section</a> for the current list.</li>
<li>All contributors of this repository are listed on <a href="https://github.com/placeAtlas/atlas-2022/graphs/contributors" target="_blank">the Contributors page on GitHub</a>. The Contributors section with <a href="https://allcontributors.org/" target="_blank" rel="noreferrer">All Contributors</a> spec is also available on <a href="https://github.com/placeAtlas/atlas-2022#contributors" target="_blank">the README</a>.</li>
<li>Thank you to those who are contributing in other channels, such as Discord and Reddit (such as reporting bugs), and those who have supported the project in general.</li>
<li>Thank you to <a href="https://www.reddit.com/r/thefinalclean/" target="_blank" rel="noreferrer">The Final Clean community</a> (Pixel Janitors) for "The Final Clean" canvas.</li>
<li>Thank you to <a href="https://place.thatguyalex.com/" target="_blank" rel="noreferrer">Alex Tsernoh</a> for providing the initial canvas images.</li>
</ul>
<h3>Contributors</h3>
<p>The 2022 Atlas would not have been possible without the help of our <span id="contributors-count"></span> contributors.</p>
<p>Thank you to everyone who submitted new entries, amended existing ones, reported bugs and just supported the project in general.</p>
<div id="contributors-wrapper" style="text-align: justify;"></div>
<h3 class="mt-4">Entry Contributors</h3>
<p>The 2022 Atlas would not have been possible without the help of our <span id="contributors-count"></span> entry contributors.</p>
<p>Thank you to everyone who submitted new entries and amended existing ones.</p>
<div id="entry-contributors-wrapper" style="text-align: justify;"></div>
</div>
</div>
<div class="col-md-5 col-xl-4">
@ -218,9 +138,9 @@
<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>
<li><a href="https://paypal.me/placeAtlas/5" target="_blank" rel="noreferrer">PayPal</a></li>
<li><a href="https://www.patreon.com/placeAtlas" target="_blank" rel="noreferrer">Patreon</a></li>
<li><a href="https://ko-fi.com/placeatlas" target="_blank" rel="noreferrer">Ko-Fi</a></li>
</ul>
</div>
<div class="p-4">
@ -235,7 +155,7 @@
</div>
</div>
<footer class="pt-3 mt-4 text-muted border-top">
Original by <a href="https://draemm.li/various/place-atlas/" target="_blank" rel="noopener noreferrer author">Roland Rytz</a> (<a href="https://github.com/RolandR/place-atlas">source</a>). Maintained by <a href="https://github.com/placeAtlas/atlas-2022/contributors">Place Atlas contributors</a> (<a href="https://github.com/placeAtlas/atlas-2022">source</a>).
Original by <a href="https://draemm.li/various/place-atlas/" target="_blank" rel="noreferrer">Roland Rytz</a> (<a href="https://github.com/RolandR/place-atlas" target="_blank">source</a>). Maintained by <a href="https://place-atlas.stefanocoding.me" target="_blank">Place Atlas Initiative</a> and <a href="https://github.com/placeAtlas/atlas-2022/graphs/contributors" target="_blank">contributors</a> (<a href="https://github.com/placeAtlas/atlas-2022" target="_blank">source</a>).
</footer>
</div>
</main>

View File

@ -1,7 +1,7 @@
<!--
The 2022 r/place Atlas
Copyright (c) 2017 Roland Rytz <roland@draemm.li>
Copyright (c) 2022 Place Atlas contributors
Copyright (c) 2022 Place Atlas Initiative and contributors
Licensed under AGPL-3.0 (https://2022.place-atlas.stefanocoding.me/license.txt)
-->
@ -11,10 +11,10 @@
<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 provided by the community.">
<meta name="author" content="Place Atlas contributors (original by Roland Rytz)">
<meta name="application-name" content="The r/place Atlas 2022">
<meta name="author" content="Place Atlas Initiative and contributors (original by Roland Rytz)">
<meta name="application-name" content="The 2022 r/place Atlas">
<meta name="robots" content="index, follow">
<meta property="og:title" content="The 2022 r/place Atlas">
<meta property="og:type" content="website">
<meta property="og:url" content="https://2022.place-atlas.stefanocoding.me/">
@ -22,11 +22,10 @@
<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:image:alt" content="The 2022 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 provided by the community.">
<meta name="twitter:card" content="summary">
<meta name="twitter:creator" content="Place Atlas contributors (original by Roland Rytz)">
<meta name="twitter:url" content="https://2022.place-atlas.stefanocoding.me/">
<meta name="twitter:title" content="The 2022 r/place Atlas">
<meta name="twitter:description" content="An interactive map of Reddit's 2022 r/place, with information to each artwork of the canvas provided by the community.">
@ -34,22 +33,21 @@
<meta name="twitter:image:alt" content="The 2022 r/place Atlas logo">
<!-- <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, viewport-fit=cover"> <!-- user-scalable=no -->
<meta name="mobile-web-app-capable" content="yes">
<meta name="color-scheme" content="light dark">
<meta name="theme-color" media="(prefers-color-scheme: light)" content="white">
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#222">
<link rel="apple-touch-icon" href="_img/apple-touch-icon.png" sizes="180x180">
<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="stylesheet" href="./_css/style.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-dark-5@1.1.3/dist/css/bootstrap-dark.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css">
<link rel="manifest" href="./manifest.webmanifest">
<link rel="me" href="https://enshittification.social/@Codixer">
<script type="module" src="https://cdn.jsdelivr.net/npm/@pwabuilder/pwaupdate/dist/pwa-update.js"></script>
<script src="./_js/favicon.js" defer></script>
<script type="application/ld+json">
@ -83,10 +81,10 @@
},
{
"@type": "Organization",
"name": "Place Atlas",
"alternateName": "r/placeatlas2",
"url": "https://github.com/placeAtlas",
"image": "http://2022.place-atlas.stefanocoding.me/_img/logo.png",
"name": "Place Atlas Initiative",
"alternateName": "r/placeAtlas2023",
"url": "https://place-atlas.stefanocoding.me",
"image": "https://place-atlas.stefanocoding.me/assets/logo.png",
"founder": {
"@type": "Person",
"@id": "#Codixer",
@ -115,14 +113,14 @@
<body>
<div id="wrapper" class="listHidden">
<header class="fixed-top">
<aside class="container-fluid alert-primary collapse" id="headerAnnouncement">
<aside class="container-fluid alert-primary collapse" id="headerNotice">
<div class="d-flex w-100 py-2 align-items-center">
<i class="bi bi-info-circle-fill fs-5"></i>
<p class="mb-0 flex-grow-1 px-2"> This is the 2022 edition of the r/place Atlas. Check out <a class="alert-link" href="https://2023.place-atlas.stefanocoding.me">the 2023 r/place Atlas</a>!</p>
<a class="fs-5" data-bs-toggle="collapse" href="#headerAnnouncement" role="button" aria-expanded="false" aria-controls="headerAnnouncement"><i class="bi bi-x-lg"></i></a>
<p class="mb-0 flex-grow-1 px-2">This is the 2022 edition of the r/place Atlas. For the latest one, check out <a class="alert-link" href="https://2023.place-atlas.stefanocoding.me">the 2023 r/place Atlas</a>.</p>
<a class="fs-5" data-bs-toggle="collapse" href="#headerNotice" role="button" aria-expanded="false" aria-controls="headerNotice"><i class="bi bi-x-lg"></i></a>
</div>
</aside>
<nav id="main-navbar" class="navbar navbar-expand-md bg-body border-bottom">
<nav id="main-navbar" class="navbar navbar-expand-lg bg-body border-bottom">
<div class="container-fluid">
<a class="navbar-brand text-body d-flex align-items-center" href="./">
<picture>
@ -135,21 +133,22 @@
<i class="bi bi-list" aria-hidden="true"></i>
</button>
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav me-auto my-2 my-md-0">
<ul class="navbar-nav me-auto my-2 my-lg-0">
<li class="nav-item">
<div class="btn-group" role="group">
<button id="showListButton" class="btn btn-outline-primary" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasList" aria-controls="offcanvasList">Entries List</button>
<button id="showListButton" class="btn btn-outline-primary" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasList" aria-controls="offcanvasList">Menu</button>
<a class="btn btn-outline-primary" id="drawLink" href="./?mode=draw">Draw</a>
</div>
</li>
</ul>
<ul class="navbar-nav mx-auto d-block d-md-none d-lg-block">
<ul class="navbar-nav mx-auto d-block">
<li class="nav-item d-flex align-items-center gap-2">
<span class="p-2">Coordinates: <span class="badge bg-secondary" id="coords_p">0, 0</span></span>
<span class="p-lg-2">Coordinates: <span class="badge bg-secondary" id="coords_p">0, 0</span></span>
</li>
</ul>
<hr class="d-md-none">
<hr class="d-lg-none">
<ul class="navbar-nav flex-row flex-wrap ms-auto">
<li class="nav-item dropdown">
<li class="nav-item col-6 col-lg-auto dropdown">
<a class="nav-link dropdown-toggle active" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false" aria-current="page">
Atlas Map
</a>
@ -159,10 +158,13 @@
<li><a class="dropdown-item" href="https://2023.place-atlas.stefanocoding.me/">2023</a></li>
</ul>
</li>
<li class="nav-item col-6 col-md-auto">
<a class="nav-link" href="https://place-wiki.stefanocoding.me/">Place Wiki</a>
<li class="nav-item col-6 col-lg-auto">
<a class="nav-link" href="https://place-wiki.stefanocoding.me/" target="_blank">Place Wiki</a>
</li>
<li class="nav-item col-6 col-md-auto">
<li class="nav-item col-6 col-lg-auto">
<a class="nav-link" href="https://github.com/placeAtlas/atlas-2022" target="_blank">Source</a>
</li>
<li class="nav-item col-6 col-lg-auto">
<a class="nav-link" href="./about.html">About</a>
</li>
</ul>
@ -179,8 +181,8 @@
<h4 class="mb-3">Hang on…</h4>
<noscript>
<p>Sorry, you need JavaScript to view the Atlas.</p>
<p>All JavaScript on this site is licensed under either the MIT or AGPL license.</p>
<p><a href="https://github.com/placeAtlas/atlas-2022">See the source on GitHub</a></p>
<p>All JS scripts on this project is under a free license.</p>
<p><a href="https://github.com/placeAtlas/atlas-2022" target="_blank">See the source on GitHub.</a></p>
</noscript>
</div>
</div>
@ -199,8 +201,7 @@
</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>
<button type="button" class="btn btn-primary dropdown-toggle w-100" id="dropdownModes" data-bs-toggle="dropdown" aria-expanded="false">Layer Views</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>
@ -211,11 +212,11 @@
</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">
<a class="btn btn-outline-primary" href="https://discord.gg/pJkm23b2nA" target="_blank" rel="noreferrer">
<i class="bi bi-discord" aria-hidden="true"></i>
Discord
</a>
<a class="btn btn-outline-primary" href="https://www.reddit.com/r/placeAtlas2/" target="_blank" rel="noopener noreferrer">
<a class="btn btn-outline-primary" href="https://www.reddit.com/r/placeAtlas2022/" target="_blank" rel="noreferrer">
<i class="bi bi-reddit" aria-hidden="true"></i>
Reddit
</a>
@ -272,7 +273,7 @@
</datalist>
</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.7rem;">Code by <a href="https://github.com/placeAtlas" target="_blank" rel="noopener noreferrer">Place Atlas</a>. Source on <a href="https://github.com/placeAtlas/atlas-2022" target="_blank" rel="noopener noreferrer">GitHub</a>. Site powered by <a href="https://www.netlify.com" target="_blank" rel="noopener noreferrer">Netlify</a>.</span>
<span style="font-size: 0.7rem;">AGPL-3.0 <span class="copyleft">©</span> <a href="https://place-atlas.stefanocoding.me" target="_blank">Place Atlas Initiative</a> and <a href="https://github.com/placeAtlas/atlas-2022/graphs/contributors" target="_blank">contributors</a>. Powered by <a href="https://www.netlify.com" target="_blank" rel="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">
@ -295,7 +296,7 @@
Redo
</button>
</div>
<button type="button" class="btn btn-primary" id="finishButton" title="Finish drawing" disabled>Finish</button>
<button type="button" class="btn btn-primary" id="finishButton" title="Finish drawing" disabled>Next</button>
<button type="button" class="btn btn-secondary" id="resetButton">Reset</button>
<div class="form-check" id="highlightUnchartedLabel">
@ -312,7 +313,7 @@
<button type="button" class="btn btn-primary d-block mx-auto" id="periodsAdd">Add Period</button>
</div>
<div id="hint">
<p class="text-center">Please read <a href="https://github.com/placeAtlas/atlas-2022/blob/master/CONTRIBUTING.md" target="_blank" rel="noopener noreferrer">this guide</a> for instructions.</p>
<p class="text-center">Please read <a href="https://github.com/placeAtlas/atlas-2022/blob/master/CONTRIBUTING.md" target="_blank">the contributing guide</a> for instructions.</p>
<hr>
<p>You can suggest new entries to the Atlas for art that isn't mapped yet, or update entries by editing it.</p>
<p>Click anywhere on the image to start drawing a shape. Switch between periods by adding a period, and/or seek through the timeline.</p>
@ -320,7 +321,7 @@
<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>
<p class="mb-0">You can ask for help on <a class="link-light" href="https://discord.gg/pJkm23b2nA" target="_blank" rel="noreferrer">our Discord server</a>!</p>
</div>
</div>
</div>
@ -328,11 +329,11 @@
<form id="objectInfo" class="d-flex flex-column p-3 bg-secondary bg-opacity-10 rounded">
<div class="mb-3">
<label for="nameField" class="form-label">Title</label>
<input type="text" id="nameField" class="form-control" placeholder="A short title" pattern="(.|\s)*\S(.|\s)*" title="Cannot be blank" required>
<input type="text" id="nameField" class="form-control" placeholder="A short title" pattern="(.|\s)*\S(.|\s)*" required>
</div>
<div class="mb-3">
<label for="descriptionField" class="form-label">Description</label>
<textarea id="descriptionField" class="form-control overflow-hidden" placeholder="A short description to be understood by everyone"></textarea>
<textarea id="descriptionField" class="form-control overflow-hidden" placeholder="A short description to be understood by everyone."></textarea>
</div>
<label id="websiteLabel" class="form-label">Website</label>
<div id="websiteGroup" class="mb-3 d-flex flex-column gap-2"></div>
@ -370,10 +371,10 @@
</div>
<div class="modal-body d-flex flex-column">
<p>
If you want to use Reddit, use the <span class="badge bg-primary">Post Direct to Reddit</span> 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.
If you want to use Reddit, use the <span class="badge bg-primary">Post Direct to Reddit</span> 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="noreferrer">r/placeAtlas2</a> on Reddit.
Don't forget to flair it with the <span class="badge rounded-pill bg-primary"><i class="bi bi-tag" aria-hidden="true"></i> <span id="redditFlair">New Entry</span></span> flair.</p>
<p>
If you want to use GitHub, use the <span class="badge bg-primary">Submit Direct to GitHub</span> button, or read <a href="https://github.com/placeAtlas/atlas-2022/blob/master/CONTRIBUTING.md#through-github" target="_blank" rel="noopener noreferrer">the contributing guide</a> to submit a patch.
If you want to use GitHub, use the <span class="badge bg-primary">Submit Direct to GitHub</span> button, or read <a href="https://github.com/placeAtlas/atlas-2022/blob/master/CONTRIBUTING.md#through-github" target="_blank">the contributing guide</a> to submit a patch.
</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" readonly></textarea>
@ -381,8 +382,8 @@
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Done</button>
<button id="exportCopy" type="button" class="btn btn-secondary">Copy</button>
<a id="exportGithubPost" class="btn btn-primary" href="#" target="_blank" rel="noopener noreferrer">Submit Direct on GitHub</a>
<a id="exportRedditPost" class="btn btn-primary" href="#" target="_blank" rel="noopener noreferrer">Post Direct on Reddit</a>
<a id="exportGithubPost" class="btn btn-primary" href="#" target="_blank" rel="noreferrer">Submit Direct on GitHub</a>
<a id="exportRedditPost" class="btn btn-primary" href="#" target="_blank" rel="noreferrer">Post Direct on Reddit</a>
</div>
</div>
</div>
@ -396,21 +397,21 @@
</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">
<a class="btn btn-primary" target="_blank" rel="noreferrer" href="https://paypal.me/placeAtlas/5">
<i class="bi bi-paypal" aria-hidden="true"></i>
PayPal
</a>
<a class="btn btn-primary" target="_blank" rel="noopener noreferrer" href="https://www.patreon.com/placeAtlas">
<a class="btn btn-primary" target="_blank" rel="noreferrer" href="https://www.patreon.com/placeAtlas">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="icon" 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">
<a class="btn btn-primary" target="_blank" rel="noreferrer" href="https://ko-fi.com/placeatlas">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="icon" 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">
<a class="btn btn-primary" target="_blank" rel="noreferrer" href="https://paypal.me/draemmli">
<i class="bi bi-paypal" aria-hidden="true"></i>
PayPal
</a>

View File

@ -3,9 +3,9 @@
"display": "standalone",
"scope": "/",
"start_url": "/",
"name": "The r/place Atlas",
"name": "The 2022 r/place Atlas",
"short_name": "r/placeAtlas2",
"description": "The atlas for the r/place event of 2022 hosted on Reddit.",
"description": "The atlas for Reddit's r/place event of 2022.",
"icons": [
{
"src": "./_img/pwa/logo-round-192x192.png",

View File

@ -1,5 +1,3 @@
// This is the "Offline copy of assets" service worker
importScripts('https://cdn.jsdelivr.net/npm/workbox-sw@6.5.4/build/workbox-sw.js');
self.addEventListener("message", event => {
@ -9,13 +7,15 @@ self.addEventListener("message", event => {
});
workbox.routing.registerRoute(
({ url }) => {!url.pathname.startsWith('/_img/canvas/')},
({ url }) => !url.pathname.startsWith('/_img/canvas/'),
// `workbox.strategies.StaleWhileRevalidate` is used to reduce server contact.
// Change to `workbox.strategies.NetworkFirst` when updating is required.
new workbox.strategies.NetworkFirst({
cacheName: "main",
plugins: [
new workbox.backgroundSync.BackgroundSyncPlugin(
"main-queue", {
maxRetentionTime: 24 * 60 // 24 hours (in minutes)
maxRetentionTime: 4 * 7 * 24 * 60 // 4 weeks (in minutes)
}
)
]
@ -24,14 +24,9 @@ workbox.routing.registerRoute(
workbox.routing.registerRoute(
({ url }) => url.pathname.startsWith('/_img/canvas/'),
// `workbox.strategies.CacheFirst` is used to minimize server contact, due to their size.
// Change to `workbox.strategies.StateWhileRevalidate` when updating is required.
new workbox.strategies.CacheFirst({
cacheName: "canvas",
plugins: [
new workbox.backgroundSync.BackgroundSyncPlugin(
"canvas-queue", {
maxRetentionTime: 4 * 7 * 24 * 60 // 4 weeks (in minutes)
}
)
]
cacheName: "canvas"
})
);