mirror of https://github.com/placeAtlas/atlas.git
commit
f836e06071
|
@ -121,6 +121,14 @@ Hereforth is an example of the structured entry data. The example has been expan
|
||||||
|
|
||||||
## Development
|
## 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.
|
Other than contributing to the Atlas data, code contributions are also accepted. Here are some information regarding some aspects on the repository.
|
||||||
|
|
||||||
### Web interface
|
### Web interface
|
||||||
|
|
19
README.md
19
README.md
|
@ -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)
|
![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)
|
[![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-2022)](https://github.com/placeAtlas/atlas-2022/blob/master/LICENSE)
|
[![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)
|
[![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/)
|
[![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/)
|
[![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
|
||||||
|
|
||||||
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).
|
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
|
## 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.
|
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
|
## 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-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](https://img.shields.io/badge/all_contributors-7-orange.svg?style=flat)](#contributors)
|
||||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
<!-- 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 -->
|
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
||||||
<!-- prettier-ignore-start -->
|
<!-- prettier-ignore-start -->
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
"parcel": "^2.8.3",
|
"parcel": "^2.8.3",
|
||||||
"parcel-namer-rewrite": "^2.0.0-rc.3",
|
"parcel-namer-rewrite": "^2.0.0-rc.3",
|
||||||
"parcel-resolver-ignore": "^2.1.3",
|
"parcel-resolver-ignore": "^2.1.3",
|
||||||
"postcss": "^8.4.31"
|
"postcss": "^8.4.21"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/code-frame": {
|
"node_modules/@babel/code-frame": {
|
||||||
|
@ -1926,9 +1926,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/all-contributors-cli": {
|
"node_modules/all-contributors-cli": {
|
||||||
"version": "6.26.1",
|
"version": "6.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/all-contributors-cli/-/all-contributors-cli-6.26.1.tgz",
|
"resolved": "https://registry.npmjs.org/all-contributors-cli/-/all-contributors-cli-6.24.0.tgz",
|
||||||
"integrity": "sha512-Ymgo3FJACRBEd1eE653FD1J/+uD0kqpUNYfr9zNC1Qby0LgbhDBzB3EF6uvkAbYpycStkk41J+0oo37Lc02yEw==",
|
"integrity": "sha512-7oSKr2PnqxsOotuSwciltcFTS1eVRdjR0cn99hbElfff7gRQBShVhsf/XBprY41sLcgqTk0l0MKgKv6QNgZdMg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.7.6",
|
"@babel/runtime": "^7.7.6",
|
||||||
|
@ -1947,9 +1947,6 @@
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"prettier": "^2"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/all-contributors-cli/node_modules/ansi-styles": {
|
"node_modules/all-contributors-cli/node_modules/ansi-styles": {
|
||||||
|
@ -3762,16 +3759,10 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "3.3.6",
|
"version": "3.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
||||||
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
|
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"type": "github",
|
|
||||||
"url": "https://github.com/sponsors/ai"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"nanoid": "bin/nanoid.cjs"
|
"nanoid": "bin/nanoid.cjs"
|
||||||
},
|
},
|
||||||
|
@ -3974,9 +3965,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/parcel-resolver-ignore": {
|
"node_modules/parcel-resolver-ignore": {
|
||||||
"version": "2.1.5",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/parcel-resolver-ignore/-/parcel-resolver-ignore-2.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/parcel-resolver-ignore/-/parcel-resolver-ignore-2.1.3.tgz",
|
||||||
"integrity": "sha512-/2zgQw3J/2YA7L6JXg4XKBWT/SXDZx+PfweWcCsllchNVwFvK7jDJhG6h+puy+e15Rm9A/ubuuHYwANQHVXp2A==",
|
"integrity": "sha512-C8uLvR4o7SPRSsQ/Nylm1/PdsLwn/Z9bzCs66qT3XIebJC7ojaFFF3MDl/mie5audngjcFF8wzU0AoEQkZq2pA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"parcel": ">=2.0.0"
|
"parcel": ">=2.0.0"
|
||||||
|
@ -4137,9 +4128,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.31",
|
"version": "8.4.21",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz",
|
||||||
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
|
"integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -4149,14 +4140,10 @@
|
||||||
{
|
{
|
||||||
"type": "tidelift",
|
"type": "tidelift",
|
||||||
"url": "https://tidelift.com/funding/github/npm/postcss"
|
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "github",
|
|
||||||
"url": "https://github.com/sponsors/ai"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.6",
|
"nanoid": "^3.3.4",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.0.2"
|
||||||
},
|
},
|
||||||
|
@ -4691,22 +4678,6 @@
|
||||||
"node": ">=12"
|
"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": {
|
"node_modules/purgecss": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/purgecss/-/purgecss-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/purgecss/-/purgecss-5.0.0.tgz",
|
||||||
|
@ -6550,9 +6521,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"all-contributors-cli": {
|
"all-contributors-cli": {
|
||||||
"version": "6.26.1",
|
"version": "6.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/all-contributors-cli/-/all-contributors-cli-6.26.1.tgz",
|
"resolved": "https://registry.npmjs.org/all-contributors-cli/-/all-contributors-cli-6.24.0.tgz",
|
||||||
"integrity": "sha512-Ymgo3FJACRBEd1eE653FD1J/+uD0kqpUNYfr9zNC1Qby0LgbhDBzB3EF6uvkAbYpycStkk41J+0oo37Lc02yEw==",
|
"integrity": "sha512-7oSKr2PnqxsOotuSwciltcFTS1eVRdjR0cn99hbElfff7gRQBShVhsf/XBprY41sLcgqTk0l0MKgKv6QNgZdMg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/runtime": "^7.7.6",
|
"@babel/runtime": "^7.7.6",
|
||||||
|
@ -6564,7 +6535,6 @@
|
||||||
"lodash": "^4.11.2",
|
"lodash": "^4.11.2",
|
||||||
"node-fetch": "^2.6.0",
|
"node-fetch": "^2.6.0",
|
||||||
"pify": "^5.0.0",
|
"pify": "^5.0.0",
|
||||||
"prettier": "^2",
|
|
||||||
"yargs": "^15.0.1"
|
"yargs": "^15.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -7853,9 +7823,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"nanoid": {
|
"nanoid": {
|
||||||
"version": "3.3.6",
|
"version": "3.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
||||||
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
|
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node-addon-api": {
|
"node-addon-api": {
|
||||||
|
@ -8045,9 +8015,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"parcel-resolver-ignore": {
|
"parcel-resolver-ignore": {
|
||||||
"version": "2.1.5",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/parcel-resolver-ignore/-/parcel-resolver-ignore-2.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/parcel-resolver-ignore/-/parcel-resolver-ignore-2.1.3.tgz",
|
||||||
"integrity": "sha512-/2zgQw3J/2YA7L6JXg4XKBWT/SXDZx+PfweWcCsllchNVwFvK7jDJhG6h+puy+e15Rm9A/ubuuHYwANQHVXp2A==",
|
"integrity": "sha512-C8uLvR4o7SPRSsQ/Nylm1/PdsLwn/Z9bzCs66qT3XIebJC7ojaFFF3MDl/mie5audngjcFF8wzU0AoEQkZq2pA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
|
@ -8103,12 +8073,12 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"postcss": {
|
"postcss": {
|
||||||
"version": "8.4.31",
|
"version": "8.4.21",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz",
|
||||||
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
|
"integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"nanoid": "^3.3.6",
|
"nanoid": "^3.3.4",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.0.2"
|
||||||
}
|
}
|
||||||
|
@ -8473,13 +8443,6 @@
|
||||||
"is-json": "^2.0.1"
|
"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": {
|
"purgecss": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/purgecss/-/purgecss-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/purgecss/-/purgecss-5.0.0.tgz",
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
"parcel": "^2.8.3",
|
"parcel": "^2.8.3",
|
||||||
"parcel-namer-rewrite": "^2.0.0-rc.3",
|
"parcel-namer-rewrite": "^2.0.0-rc.3",
|
||||||
"parcel-resolver-ignore": "^2.1.3",
|
"parcel-resolver-ignore": "^2.1.3",
|
||||||
"postcss": "^8.4.31",
|
"postcss": "^8.4.21",
|
||||||
"all-contributors-cli": "^6.24.0"
|
"all-contributors-cli": "^6.24.0"
|
||||||
},
|
},
|
||||||
"parcel-namer-rewrite": {
|
"parcel-namer-rewrite": {
|
||||||
|
@ -18,7 +18,8 @@
|
||||||
},
|
},
|
||||||
"parcelIgnore": [
|
"parcelIgnore": [
|
||||||
"sw.js",
|
"sw.js",
|
||||||
"_img/.+"
|
"_img/.+",
|
||||||
|
"atlas.json"
|
||||||
],
|
],
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
">= 0.5%",
|
">= 0.5%",
|
||||||
|
|
|
@ -20,6 +20,5 @@ cp -r web/_img/ dist/
|
||||||
cp web/atlas.json dist/
|
cp web/atlas.json dist/
|
||||||
cp web/*.txt dist/
|
cp web/*.txt dist/
|
||||||
cp web/_headers dist/
|
cp web/_headers dist/
|
||||||
cp web/_redirects dist/
|
|
||||||
cp web/favicon.ico dist/
|
cp web/favicon.ico dist/
|
||||||
cp web/sw.js dist/
|
cp web/sw.js dist/
|
|
@ -19,6 +19,5 @@ cp -r web/_img/ dist/
|
||||||
cp web/atlas.json dist/
|
cp web/atlas.json dist/
|
||||||
cp web/*.txt dist/
|
cp web/*.txt dist/
|
||||||
cp web/_headers dist/
|
cp web/_headers dist/
|
||||||
cp web/_redirects dist/
|
|
||||||
cp web/favicon.ico dist/
|
cp web/favicon.ico dist/
|
||||||
cp web/sw.js dist/
|
cp web/sw.js dist/
|
|
@ -1,8 +1,7 @@
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
The 2022 r/place Atlas
|
The 2022 r/place Atlas
|
||||||
Copyright (c) 2017 Roland Rytz <roland@draemm.li>
|
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)
|
Licensed under AGPL-3.0 (https://2022.place-atlas.stefanocoding.me/license.txt)
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*!
|
/*!
|
||||||
* The 2022 r/place Atlas
|
* The 2022 r/place Atlas
|
||||||
* Copyright (c) 2017 Roland Rytz <roland@draemm.li>
|
* 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)
|
* 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);
|
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()) {
|
@supports (backdrop-filter: blur()) or (-webkit-backdrop-filter: blur()) {
|
||||||
.navbar, .offcanvas {
|
.navbar, .offcanvas {
|
||||||
-webkit-backdrop-filter: saturate(180%) blur(15px);
|
-webkit-backdrop-filter: saturate(180%) blur(15px);
|
||||||
|
@ -258,12 +266,12 @@ body[data-init-done] .listTransitioning #innerContainer {
|
||||||
}
|
}
|
||||||
|
|
||||||
#variantControls {
|
#variantControls {
|
||||||
flex: 1 0 auto;
|
flex: 2 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
#timeControls {
|
#timeControls {
|
||||||
position: relative;
|
position: relative;
|
||||||
flex: 6 0 300px;
|
flex: 12 0 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#bottomBar.no-time-slider #timeControls {
|
#bottomBar.no-time-slider #timeControls {
|
||||||
|
@ -440,13 +448,25 @@ body:not([data-dev]) .show-only-on-dev {
|
||||||
display: none !important
|
display: none !important
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#objectsList,
|
||||||
|
#offcanvasList,
|
||||||
|
#offcanvasDraw,
|
||||||
|
#closeObjectsListButton {
|
||||||
|
margin-top: var(--global-top-padding);
|
||||||
|
}
|
||||||
|
|
||||||
|
.copyleft {
|
||||||
|
display: inline-block;
|
||||||
|
transform: rotateY(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
/* about.html */
|
/* about.html */
|
||||||
|
|
||||||
#credits a {
|
#entry-contributors-wrapper a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#credits a:hover {
|
#entry-contributors-wrapper a:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
21
web/_headers
21
web/_headers
|
@ -1,8 +1,21 @@
|
||||||
/*
|
/*
|
||||||
Access-Control-Allow-Origin: *
|
Access-Control-Allow-Origin: *
|
||||||
|
|
||||||
/_img/canvas/*/*.png
|
# Hashed resources: 1 year and immutable
|
||||||
cache-control: public, max-age=604800
|
|
||||||
|
/_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
|
/_img/canvas/*.png
|
||||||
cache-control: public, max-age=604800
|
Cache-Control: public, max-age=31536000
|
||||||
|
|
||||||
|
/_img/canvas/*/*.png
|
||||||
|
Cache-Control: public, max-age=31536000
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*!
|
/*!
|
||||||
* The 2022 r/place Atlas
|
* The 2022 r/place Atlas
|
||||||
* Copyright (c) 2017 Roland Rytz <roland@draemm.li>
|
* 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)
|
* 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>
|
// <i aria-label="GitHub" class="bi bi-github"></i>
|
||||||
const gitHubEl = document.createElement("i")
|
const gitHubEl = document.createElement("i")
|
||||||
|
@ -34,6 +34,8 @@ fetch('all-authors.txt')
|
||||||
userEl.href = 'https://reddit.com/user/' + contributor
|
userEl.href = 'https://reddit.com/user/' + contributor
|
||||||
userEl.textContent = contributor
|
userEl.textContent = contributor
|
||||||
}
|
}
|
||||||
|
userEl.target = '_blank'
|
||||||
|
userEl.rel = 'noreferrer'
|
||||||
contributorsEl.appendChild(userEl)
|
contributorsEl.appendChild(userEl)
|
||||||
contributorsEl.appendChild(document.createTextNode(' '))
|
contributorsEl.appendChild(document.createTextNode(' '))
|
||||||
}
|
}
|
||||||
|
|
|
@ -265,8 +265,8 @@ window.useNumericalId = useNumericalId
|
||||||
|
|
||||||
console.info(`%cThe 2022 r/place Atlas
|
console.info(`%cThe 2022 r/place Atlas
|
||||||
%cCopyright (c) 2017 Roland Rytz <roland@draemm.li>
|
%cCopyright (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)
|
Licensed under AGPL-3.0 (https://2023.place-atlas.stefanocoding.me/license.txt)
|
||||||
|
|
||||||
https://2022.place-atlas.stefanocoding.me/
|
https://2022.place-atlas.stefanocoding.me/
|
||||||
https://discord.gg/pJkm23b2nA
|
https://discord.gg/pJkm23b2nA
|
||||||
|
@ -274,4 +274,4 @@ https://reddit.com/r/placeatlas2
|
||||||
https://github.com/placeAtlas/atlas-2022
|
https://github.com/placeAtlas/atlas-2022
|
||||||
|
|
||||||
To get the image of the canvas, use downloadCanvas().
|
To get the image of the canvas, use downloadCanvas().
|
||||||
`, 'font-size: 150%; line-height: 150%', '')
|
`, 'font-size: 150%; line-height: 150%', '')
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*!
|
/*!
|
||||||
* The 2022 r/place Atlas
|
* The 2022 r/place Atlas
|
||||||
* Copyright (c) 2017 Roland Rytz <roland@draemm.li>
|
* 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)
|
* Licensed under AGPL-3.0 (https://2022.place-atlas.stefanocoding.me/license.txt)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*!
|
/*!
|
||||||
* The 2022 r/place Atlas
|
* The 2022 r/place Atlas
|
||||||
* Copyright (c) 2017 Roland Rytz <roland@draemm.li>
|
* 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)
|
* Licensed under AGPL-3.0 (https://2022.place-atlas.stefanocoding.me/license.txt)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ const periodClipboard = {
|
||||||
const drawBackButton = document.createElement("a")
|
const drawBackButton = document.createElement("a")
|
||||||
drawBackButton.className = "btn btn-outline-primary"
|
drawBackButton.className = "btn btn-outline-primary"
|
||||||
drawBackButton.id = "drawBackButton"
|
drawBackButton.id = "drawBackButton"
|
||||||
drawBackButton.textContent = "Exit Draw Mode"
|
drawBackButton.textContent = "Exit Drawing"
|
||||||
|
|
||||||
const baseInputAddon = document.createElement("span")
|
const baseInputAddon = document.createElement("span")
|
||||||
baseInputAddon.className = "input-group-text"
|
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.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.parentElement.appendChild(drawBackButton)
|
||||||
showListButton.remove()
|
showListButton.remove()
|
||||||
|
drawButton.remove()
|
||||||
|
|
||||||
// Opens draw menu
|
// Opens draw menu
|
||||||
wrapper.classList.remove('listHidden')
|
wrapper.classList.remove('listHidden')
|
||||||
bsOffcanvasDraw.show()
|
bsOffcanvasDraw.show()
|
||||||
|
|
||||||
window.render = render
|
window.renderHighlight = renderHighlight
|
||||||
window.renderBackground = renderBackground
|
window.renderBackground = renderBackground
|
||||||
window.updateHovering = updateHovering
|
window.updateHovering = updateHovering
|
||||||
|
|
||||||
|
@ -125,13 +126,18 @@ function initDraw() {
|
||||||
|
|
||||||
let highlightUncharted = highlightUnchartedEl.checked
|
let highlightUncharted = highlightUnchartedEl.checked
|
||||||
|
|
||||||
renderBackground(atlas)
|
window.updateAtlas = updateAtlas
|
||||||
|
|
||||||
|
updateAtlas()
|
||||||
|
|
||||||
|
document.addEventListener('timeupdate', () => {
|
||||||
|
updateAtlas()
|
||||||
|
})
|
||||||
|
|
||||||
applyView()
|
applyView()
|
||||||
|
|
||||||
container.style.cursor = "crosshair"
|
container.style.cursor = "crosshair"
|
||||||
|
|
||||||
render(path)
|
|
||||||
|
|
||||||
container.addEventListener("mousedown", e => {
|
container.addEventListener("mousedown", e => {
|
||||||
lastPos = [
|
lastPos = [
|
||||||
e.clientX,
|
e.clientX,
|
||||||
|
@ -168,7 +174,7 @@ function initDraw() {
|
||||||
const coords = getCanvasCoords(e.clientX, e.clientY)
|
const coords = getCanvasCoords(e.clientX, e.clientY)
|
||||||
|
|
||||||
path.push(coords)
|
path.push(coords)
|
||||||
render(path)
|
renderHighlight(path)
|
||||||
|
|
||||||
undoHistory = []
|
undoHistory = []
|
||||||
redoButton.disabled = true
|
redoButton.disabled = true
|
||||||
|
@ -185,13 +191,13 @@ function initDraw() {
|
||||||
container.addEventListener("mousemove", e => {
|
container.addEventListener("mousemove", e => {
|
||||||
if (!dragging && drawing && path.length > 0) {
|
if (!dragging && drawing && path.length > 0) {
|
||||||
const coords = getCanvasCoords(e.clientX, e.clientY)
|
const coords = getCanvasCoords(e.clientX, e.clientY)
|
||||||
render([...path, coords])
|
renderHighlight([...path, coords])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
container.addEventListener("mouseout", function () {
|
container.addEventListener("mouseout", function () {
|
||||||
if (!dragging && drawing && path.length > 0) {
|
if (!dragging && drawing && path.length > 0) {
|
||||||
render(path)
|
renderHighlight(path)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -228,19 +234,19 @@ function initDraw() {
|
||||||
undoButton.addEventListener("click", e => {
|
undoButton.addEventListener("click", e => {
|
||||||
undo()
|
undo()
|
||||||
const coords = getCanvasCoords(e.clientX, e.clientY)
|
const coords = getCanvasCoords(e.clientX, e.clientY)
|
||||||
render([...path, coords])
|
renderHighlight([...path, coords])
|
||||||
})
|
})
|
||||||
|
|
||||||
redoButton.addEventListener("click", e => {
|
redoButton.addEventListener("click", e => {
|
||||||
redo()
|
redo()
|
||||||
const coords = getCanvasCoords(e.clientX, e.clientY)
|
const coords = getCanvasCoords(e.clientX, e.clientY)
|
||||||
render([...path, coords])
|
renderHighlight([...path, coords])
|
||||||
})
|
})
|
||||||
|
|
||||||
resetButton.addEventListener("click", e => {
|
resetButton.addEventListener("click", e => {
|
||||||
reset()
|
reset()
|
||||||
const coords = getCanvasCoords(e.clientX, e.clientY)
|
const coords = getCanvasCoords(e.clientX, e.clientY)
|
||||||
render([...path, coords])
|
renderHighlight([...path, coords])
|
||||||
})
|
})
|
||||||
|
|
||||||
resetButton.addEventListener("blur", function () {
|
resetButton.addEventListener("blur", function () {
|
||||||
|
@ -269,7 +275,7 @@ function initDraw() {
|
||||||
|
|
||||||
highlightUnchartedEl.addEventListener("click", function () {
|
highlightUnchartedEl.addEventListener("click", function () {
|
||||||
highlightUncharted = this.checked
|
highlightUncharted = this.checked
|
||||||
render(path)
|
renderHighlight(path)
|
||||||
})
|
})
|
||||||
|
|
||||||
function generateExportObject() {
|
function generateExportObject() {
|
||||||
|
@ -332,7 +338,7 @@ function initDraw() {
|
||||||
if (exportArea.value > 40000) {
|
if (exportArea.value > 40000) {
|
||||||
exportArea.value = " " + miniJsonString
|
exportArea.value = " " + miniJsonString
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reddit
|
// Reddit
|
||||||
|
|
||||||
let redditPostJsonString = " " + prettyJsonString.split("\n").join("\n ")
|
let redditPostJsonString = " " + prettyJsonString.split("\n").join("\n ")
|
||||||
|
@ -385,13 +391,11 @@ function initDraw() {
|
||||||
}
|
}
|
||||||
githubPostButton.href = githubPostUrl
|
githubPostButton.href = githubPostUrl
|
||||||
|
|
||||||
console.log(githubPostUrl)
|
|
||||||
|
|
||||||
exportModal.show()
|
exportModal.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
function preview() {
|
function preview() {
|
||||||
let infoElement = createInfoBlock(generateExportObject(), true)
|
let infoElement = createInfoBlock(generateExportObject(), 2)
|
||||||
objectsContainer.replaceChildren()
|
objectsContainer.replaceChildren()
|
||||||
objectsContainer.appendChild(infoElement)
|
objectsContainer.appendChild(infoElement)
|
||||||
closeObjectsListButton.classList.remove("d-none")
|
closeObjectsListButton.classList.remove("d-none")
|
||||||
|
@ -483,16 +487,16 @@ function initDraw() {
|
||||||
closeObjectsListButton.classList.add("d-none")
|
closeObjectsListButton.classList.add("d-none")
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderBackground() {
|
function renderBackground(atlas) {
|
||||||
|
|
||||||
backgroundContext.clearRect(0, 0, highlightCanvas.width, highlightCanvas.height)
|
backgroundContext.clearRect(0, 0, highlightCanvas.width, highlightCanvas.height)
|
||||||
|
|
||||||
backgroundContext.fillStyle = "rgba(0, 0, 0, 1)"
|
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()
|
backgroundContext.beginPath()
|
||||||
|
|
||||||
|
@ -510,7 +514,7 @@ function initDraw() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function render(path) {
|
function renderHighlight(path) {
|
||||||
|
|
||||||
if (!Array.isArray(path)) return
|
if (!Array.isArray(path)) return
|
||||||
|
|
||||||
|
@ -553,10 +557,16 @@ function initDraw() {
|
||||||
updateCoordsDisplay(e)
|
updateCoordsDisplay(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateAtlas() {
|
||||||
|
;[atlas, atlasOrder] = filterAtlas(atlasAll)
|
||||||
|
;[atlasDisplay, atlasOrder] = generateAtlasDisplay(atlas, atlasOrder, currentPeriod, currentVariation)
|
||||||
|
renderBackground(atlasDisplay)
|
||||||
|
renderHighlight(atlasDisplay)
|
||||||
|
}
|
||||||
|
|
||||||
const getEntry = id => {
|
const getEntry = id => {
|
||||||
if (!id) return
|
if (!id) return
|
||||||
const entries = atlasAll.filter(entry => entry.id.toString() === id.toString())
|
return atlasAll[id]
|
||||||
if (entries.length === 1) return entries[0]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function addFieldButton(inputButton, inputGroup, array, index, name) {
|
function addFieldButton(inputButton, inputGroup, array, index, name) {
|
||||||
|
@ -790,7 +800,7 @@ function initDraw() {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
document.getElementById("offcanvasDrawLabel").textContent = "New Entry"
|
document.getElementById("offcanvasDrawLabel").textContent = "New Entry"
|
||||||
pathWithPeriods.push([formatPeriod(currentPeriod, currentPeriod, currentVariation), []])
|
pathWithPeriods.push([formatPeriod(currentPeriod, null, currentVariation), []])
|
||||||
|
|
||||||
// Builds multi-input list
|
// Builds multi-input list
|
||||||
addWebsiteFields("", 0, [0])
|
addWebsiteFields("", 0, [0])
|
||||||
|
@ -805,25 +815,25 @@ function initDraw() {
|
||||||
const [,, hashX, hashY, hashZoom] = hash.split('/')
|
const [,, hashX, hashY, hashZoom] = hash.split('/')
|
||||||
|
|
||||||
setView(
|
setView(
|
||||||
(isNaN(hashX) || hashX === '') ? center[0] : Number(hashX),
|
(isNaN(hashX) || hashX === '') ? center[0] : Number(hashX),
|
||||||
(isNaN(hashY) || hashY === '') ? center[1] : Number(hashY),
|
(isNaN(hashY) || hashY === '') ? center[1] : Number(hashY),
|
||||||
(isNaN(hashZoom) || hashZoom === '') ? 4 : Number(hashZoom)
|
(isNaN(hashZoom) || hashZoom === '') ? 4 : Number(hashZoom)
|
||||||
)
|
)
|
||||||
|
|
||||||
document.addEventListener('timeupdate', () => {
|
document.addEventListener('timeupdate', () => {
|
||||||
renderBackground(atlas)
|
renderBackground(atlasDisplay)
|
||||||
updatePeriodGroups()
|
updatePeriodGroups()
|
||||||
})
|
})
|
||||||
|
|
||||||
periodsAdd.addEventListener('click', () => {
|
periodsAdd.addEventListener('click', () => {
|
||||||
pathWithPeriods.push([formatPeriod(currentPeriod, currentPeriod, currentVariation), []])
|
pathWithPeriods.push([formatPeriod(currentPeriod, null, currentVariation), []])
|
||||||
initPeriodGroups()
|
initPeriodGroups()
|
||||||
})
|
})
|
||||||
|
|
||||||
drawBackButton.href = "./" + formatHash(entry?.id)
|
drawBackButton.href = "./" + formatHash(entry?.id)
|
||||||
|
|
||||||
document.addEventListener('timeupdate', event => {
|
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 periodCopyEl = periodGroupEl.querySelector('.period-copy')
|
||||||
const periodDuplicateEl = periodGroupEl.querySelector('.period-duplicate')
|
const periodDuplicateEl = periodGroupEl.querySelector('.period-duplicate')
|
||||||
const periodDeleteEl = periodGroupEl.querySelector('.period-delete')
|
const periodDeleteEl = periodGroupEl.querySelector('.period-delete')
|
||||||
|
|
||||||
const periodVariationEl = periodGroupEl.querySelector('.period-variation')
|
const periodVariationEl = periodGroupEl.querySelector('.period-variation')
|
||||||
const periodStatusEl = periodGroupEl.querySelector('.period-status')
|
const periodStatusEl = periodGroupEl.querySelector('.period-status')
|
||||||
|
|
||||||
|
@ -926,19 +936,19 @@ function initPeriodGroups() {
|
||||||
})
|
})
|
||||||
startPeriodViewEl.addEventListener('click', () => {
|
startPeriodViewEl.addEventListener('click', () => {
|
||||||
updateTime(parseInt(startPeriodEl.value), getCurrentVariation())
|
updateTime(parseInt(startPeriodEl.value), getCurrentVariation())
|
||||||
|
|
||||||
// Set zoom view
|
// Set zoom view
|
||||||
periodCenter = calculateCenter(path)
|
periodCenter = calculateCenter(path)
|
||||||
setView(periodCenter[0], periodCenter[1], setZoomByPath(path))
|
setView(periodCenter[0], periodCenter[1], setZoomByPath(path))
|
||||||
})
|
})
|
||||||
|
|
||||||
function getCurrentVariation() {
|
function getCurrentVariation() {
|
||||||
return periodVariationEl[periodVariationEl.selectedIndex].value
|
return periodVariationEl[periodVariationEl.selectedIndex].value
|
||||||
}
|
}
|
||||||
|
|
||||||
function startPeriodUpdate(value) {
|
function startPeriodUpdate(value) {
|
||||||
endPeriodListEl.innerHTML = '<option value="' + (parseInt(value) + 1) + '"></option>'
|
endPeriodListEl.innerHTML = '<option value="' + (parseInt(value) + 1) + '"></option>'
|
||||||
|
|
||||||
// Update time only when value changes
|
// Update time only when value changes
|
||||||
if (startPeriodEl.value !== timelineSlider.value) {
|
if (startPeriodEl.value !== timelineSlider.value) {
|
||||||
timelineSlider.value = value
|
timelineSlider.value = value
|
||||||
|
@ -1224,7 +1234,7 @@ function updatePeriodGroups() {
|
||||||
function updatePath(newPath, newUndoHistory) {
|
function updatePath(newPath, newUndoHistory) {
|
||||||
path = newPath || path
|
path = newPath || path
|
||||||
if (path.length > 3) center = calculateCenter(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
|
undoButton.disabled = path.length === 0; // Maybe make it undo the cancel action in the future
|
||||||
undoHistory = newUndoHistory || []
|
undoHistory = newUndoHistory || []
|
||||||
redoButton.disabled = (!undoHistory.length)
|
redoButton.disabled = (!undoHistory.length)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*!
|
/*!
|
||||||
* The 2022 r/place Atlas
|
* The 2022 r/place Atlas
|
||||||
* Copyright (c) 2017 Roland Rytz <roland@draemm.li>
|
* 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)
|
* Licensed under AGPL-3.0 (https://2022.place-atlas.stefanocoding.me/license.txt)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -31,7 +31,10 @@ function createInfoListItem(name, value) {
|
||||||
return entryInfoListElement
|
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")
|
const element = document.createElement("div")
|
||||||
element.className = "card mb-2 overflow-hidden shadow"
|
element.className = "card mb-2 overflow-hidden shadow"
|
||||||
|
|
||||||
|
@ -40,21 +43,31 @@ function createInfoBlock(entry, isPreview) {
|
||||||
|
|
||||||
const linkElement = document.createElement("a")
|
const linkElement = document.createElement("a")
|
||||||
linkElement.className = "text-decoration-none d-flex justify-content-between text-body"
|
linkElement.className = "text-decoration-none d-flex justify-content-between text-body"
|
||||||
if (isPreview) linkElement.href = "#"
|
|
||||||
else {
|
let nearestPeriod = currentPeriod
|
||||||
linkElement.href = formatHash(entry.id, null, null, null, false, false, false)
|
let nearestVariation = currentVariation
|
||||||
linkElement.addEventListener('click', e => {
|
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()
|
e.preventDefault()
|
||||||
location.hash = formatHash(entry.id, null, null, null, false, false, false)
|
location.hash = hash
|
||||||
window.dispatchEvent(new HashChangeEvent("hashchange"))
|
window.dispatchEvent(new HashChangeEvent("hashchange"))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const linkNameElement = document.createElement("span")
|
const linkNameElement = document.createElement("span")
|
||||||
linkNameElement.className = "flex-grow-1 text-break"
|
linkNameElement.className = "flex-grow-1 text-break"
|
||||||
linkNameElement.textContent = entry.name
|
linkNameElement.textContent = entry.name
|
||||||
headerElement.appendChild(linkElement)
|
headerElement.appendChild(linkElement)
|
||||||
linkElement.appendChild(linkNameElement)
|
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)
|
element.appendChild(headerElement)
|
||||||
|
|
||||||
const bodyElement = document.createElement("div")
|
const bodyElement = document.createElement("div")
|
||||||
|
@ -92,7 +105,7 @@ function createInfoBlock(entry, isPreview) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Entry data submitted to preview does not include center or path
|
// Entry data submitted to preview does not include center or path
|
||||||
if (!isPreview) {
|
if (mode === 0) {
|
||||||
const [x, y] = entry?.center
|
const [x, y] = entry?.center
|
||||||
listElement.appendChild(createInfoListItem("Position: ", `${Math.floor(x)}, ${Math.floor(y)}`))
|
listElement.appendChild(createInfoListItem("Position: ", `${Math.floor(x)}, ${Math.floor(y)}`))
|
||||||
|
|
||||||
|
@ -170,11 +183,11 @@ function createInfoBlock(entry, isPreview) {
|
||||||
element.appendChild(idElementContainer)
|
element.appendChild(idElementContainer)
|
||||||
|
|
||||||
// Adds edit button only if element is not deleted
|
// 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")
|
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.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
|
editElement.title = "Edit " + entry.name
|
||||||
idElementContainer.appendChild(editElement)
|
idElementContainer.appendChild(editElement)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*!
|
/*!
|
||||||
* The 2022 r/place Atlas
|
* The 2022 r/place Atlas
|
||||||
* Copyright (c) 2017 Roland Rytz <roland@draemm.li>
|
* 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)
|
* Licensed under AGPL-3.0 (https://2022.place-atlas.stefanocoding.me/license.txt)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ const maxZoom = 128
|
||||||
const minZoom = 0.125
|
const minZoom = 0.125
|
||||||
|
|
||||||
let zoomOrigin = [0, 0]
|
let zoomOrigin = [0, 0]
|
||||||
let scaleZoomOrigin = [0, 0]
|
let scaleZoomOrigin = [canvasCenter.x, canvasCenter.y]
|
||||||
|
|
||||||
let dragging = false
|
let dragging = false
|
||||||
let lastPosition = [0, 0]
|
let lastPosition = [0, 0]
|
||||||
|
@ -54,7 +54,7 @@ function applyView() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setView(targetX, targetY, targetZoom) {
|
function setView(targetX, targetY, targetZoom) {
|
||||||
|
|
||||||
if (isNaN(targetX)) targetX = null
|
if (isNaN(targetX)) targetX = null
|
||||||
if (isNaN(targetY)) targetY = null
|
if (isNaN(targetY)) targetY = null
|
||||||
|
|
||||||
|
@ -72,8 +72,6 @@ function updateHash(...args) {
|
||||||
if (location.hash !== newLocation.hash) history.replaceState({}, "", newLocation)
|
if (location.hash !== newLocation.hash) history.replaceState({}, "", newLocation)
|
||||||
}
|
}
|
||||||
|
|
||||||
let atlas = null
|
|
||||||
window.atlas = atlas
|
|
||||||
let atlasAll = null
|
let atlasAll = null
|
||||||
window.atlasAll = atlasAll
|
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")
|
if (mode === "about") window.location.replace("./about.html")
|
||||||
|
|
||||||
// For Reviewing Reddit Changes
|
// For Reviewing Reddit Changes
|
||||||
// const atlasRef = '../tools/temp-atlas.json'
|
// const atlasRef = '../tools/temp-atlas.json'
|
||||||
const atlasRef = params.get('atlas') || './atlas.json'
|
const atlasAllUrl = params.get('atlas') || './atlas.json'
|
||||||
const atlasResp = await fetch(atlasRef)
|
atlasAll = generateAtlasAll(await (await fetch(atlasAllUrl)).json())
|
||||||
atlasAll = updateAtlasAll(await atlasResp.json())
|
// console.log(atlas, atlasOrder)
|
||||||
|
|
||||||
const hash = window.location.hash.substring(1)
|
const hash = window.location.hash.substring(1)
|
||||||
const [, hashPeriod, hashX, hashY, hashZoom] = hash.split('/')
|
const [, hashPeriod, hashX, hashY, hashZoom] = hash.split('/')
|
||||||
|
@ -148,45 +157,33 @@ async function init() {
|
||||||
initExplore()
|
initExplore()
|
||||||
} else if (mode.startsWith("diff")) {
|
} else if (mode.startsWith("diff")) {
|
||||||
try {
|
try {
|
||||||
const liveAtlasRef = params.get('liveatlas') || `https://${prodDomain}/atlas.json`
|
const liveAtlasUrl = params.get('liveatlas') || `https://${prodDomain}/atlas.json`
|
||||||
const liveAtlasResp = await fetch(liveAtlasRef)
|
let liveAtlasAll = generateAtlasAll(await (await fetch(liveAtlasUrl)).json())
|
||||||
let liveAtlas = await liveAtlasResp.json()
|
|
||||||
liveAtlas = updateAtlasAll(liveAtlas)
|
|
||||||
|
|
||||||
const liveAtlasReduced = liveAtlas.reduce((atlas, entry) => {
|
|
||||||
delete entry._index
|
|
||||||
atlas[entry.id] = entry
|
|
||||||
return atlas
|
|
||||||
}, {})
|
|
||||||
// Mark added/edited entries
|
// Mark added/edited entries
|
||||||
atlasAll = atlasAll.map(function (entry) {
|
for (const entry of Object.values(atlasAll)) {
|
||||||
delete entry._index
|
if (!liveAtlasAll[entry.id]) {
|
||||||
if (!liveAtlasReduced[entry.id]) {
|
|
||||||
entry.diff = "add"
|
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"
|
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) {
|
} catch (error) {
|
||||||
console.warn("Diff mode failed to load, reverting to normal view.", error)
|
console.warn("Diff mode failed to load, reverting to normal view.", error)
|
||||||
|
@ -255,7 +252,7 @@ async function init() {
|
||||||
zoom = 1
|
zoom = 1
|
||||||
zoomOrigin = [0, 0]
|
zoomOrigin = [0, 0]
|
||||||
scaleZoomOrigin = [0, 0]
|
scaleZoomOrigin = [0, 0]
|
||||||
updateLines()
|
renderLines()
|
||||||
applyView()
|
applyView()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -384,7 +381,6 @@ async function init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("mousemove", e => {
|
window.addEventListener("mousemove", e => {
|
||||||
// updateLines()
|
|
||||||
mousemove(e.clientX, e.clientY)
|
mousemove(e.clientX, e.clientY)
|
||||||
if (dragging) {
|
if (dragging) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
@ -417,7 +413,7 @@ async function init() {
|
||||||
scaleZoomOrigin[0] += deltaX / zoom
|
scaleZoomOrigin[0] += deltaX / zoom
|
||||||
scaleZoomOrigin[1] += deltaY / zoom
|
scaleZoomOrigin[1] += deltaY / zoom
|
||||||
|
|
||||||
updateLines()
|
renderLines()
|
||||||
applyView()
|
applyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,7 +456,7 @@ async function init() {
|
||||||
zoomOrigin[1] = scaleZoomOrigin[1] * zoom
|
zoomOrigin[1] = scaleZoomOrigin[1] * zoom
|
||||||
|
|
||||||
applyView()
|
applyView()
|
||||||
updateLines()
|
renderLines()
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("mouseup", e => {
|
window.addEventListener("mouseup", e => {
|
||||||
|
@ -478,7 +474,7 @@ async function init() {
|
||||||
})
|
})
|
||||||
window.addEventListener("touchend", touchend)
|
window.addEventListener("touchend", touchend)
|
||||||
|
|
||||||
function mouseup(x, y) {
|
function mouseup() {
|
||||||
dragging = false
|
dragging = false
|
||||||
updateHash()
|
updateHash()
|
||||||
}
|
}
|
||||||
|
@ -486,7 +482,7 @@ async function init() {
|
||||||
function touchend(e) {
|
function touchend(e) {
|
||||||
if (e.touches.length === 0) {
|
if (e.touches.length === 0) {
|
||||||
mouseup()
|
mouseup()
|
||||||
setTimeout(() => updateLines(), 0)
|
renderLines()
|
||||||
dragging = false
|
dragging = false
|
||||||
|
|
||||||
} else if (e.touches.length === 1) {
|
} 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) {
|
for (const index in atlas) {
|
||||||
const entry = atlas[index]
|
const entry = atlas[index]
|
||||||
entry._index = index
|
entry._index = index
|
||||||
|
@ -528,22 +525,37 @@ function updateAtlasAll(atlas = atlasAll) {
|
||||||
}
|
}
|
||||||
entry.path = currentPath
|
entry.path = currentPath
|
||||||
entry.center = currentCenter
|
entry.center = currentCenter
|
||||||
|
newAtlas[entry.id] = entry
|
||||||
}
|
}
|
||||||
return atlas
|
// console.log(newAtlas)
|
||||||
|
return newAtlas
|
||||||
}
|
}
|
||||||
|
|
||||||
// Announcement system
|
// Notice system
|
||||||
|
|
||||||
const announcementEl = document.querySelector("#headerAnnouncement")
|
const noticeEl = document.querySelector("#headerNotice")
|
||||||
const announcementButton = announcementEl.querySelector('[role=button]')
|
const noticeButton = noticeEl.querySelector('[role=button]')
|
||||||
const announcementText = announcementEl.querySelector('p').textContent.trim()
|
const noticeText = noticeEl.querySelector('p').textContent.trim()
|
||||||
|
|
||||||
if (announcementText && announcementText !== window.localStorage.getItem('announcement-closed')) {
|
const resizeGlobalTopPadding = () => {
|
||||||
announcementButton.click()
|
document.body.style.setProperty("--global-top-padding", noticeEl.offsetHeight + 'px')
|
||||||
document.querySelector('#objectsList').style.marginTop = '2.8rem'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
announcementEl.querySelector('[role=button]').addEventListener('click', () => {
|
if (window.localStorage.getItem('announcement-closed')) {
|
||||||
window.localStorage.setItem('announcement-closed', announcementText)
|
window.localStorage.setItem('closed-notice', window.localStorage.getItem('announcement-closed'))
|
||||||
document.querySelector('#objectsList').style.marginTop = '0'
|
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)
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*!
|
/*!
|
||||||
* The 2022 r/place Atlas
|
* The 2022 r/place Atlas
|
||||||
* Copyright (c) 2017 Roland Rytz <roland@draemm.li>
|
* 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)
|
* Licensed under AGPL-3.0 (https://2022.place-atlas.stefanocoding.me/license.txt)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -9,22 +9,16 @@ function initOverlap() {
|
||||||
|
|
||||||
window.renderBackground = renderBackground
|
window.renderBackground = renderBackground
|
||||||
|
|
||||||
|
updateAtlas()
|
||||||
|
|
||||||
// const hovered = []
|
// const hovered = []
|
||||||
|
|
||||||
resetEntriesList()
|
|
||||||
renderBackground(atlas)
|
|
||||||
render()
|
|
||||||
|
|
||||||
document.addEventListener('timeupdate', () => {
|
document.addEventListener('timeupdate', () => {
|
||||||
atlasDisplay = atlas.slice()
|
updateAtlas()
|
||||||
resetEntriesList()
|
|
||||||
renderBackground(atlasDisplay)
|
|
||||||
render()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
applyView()
|
applyView()
|
||||||
render()
|
renderLines()
|
||||||
updateLines()
|
|
||||||
|
|
||||||
if (window.location.hash) {
|
if (window.location.hash) {
|
||||||
updateViewFromHash()
|
updateViewFromHash()
|
||||||
|
@ -37,7 +31,7 @@ function initOverlap() {
|
||||||
backgroundContext.fillStyle = "rgba(255, 255, 255, 1)"
|
backgroundContext.fillStyle = "rgba(255, 255, 255, 1)"
|
||||||
backgroundContext.fillRect(0, 0, highlightCanvas.width, highlightCanvas.height)
|
backgroundContext.fillRect(0, 0, highlightCanvas.width, highlightCanvas.height)
|
||||||
|
|
||||||
for (const entry of atlas) {
|
for (const entry of Object.values(atlas)) {
|
||||||
|
|
||||||
const path = entry.path
|
const path = entry.path
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*!
|
/*!
|
||||||
* The 2022 r/place Atlas
|
* The 2022 r/place Atlas
|
||||||
* Copyright (c) 2017 Roland Rytz <roland@draemm.li>
|
* 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)
|
* 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 = ""
|
let outstring = ""
|
||||||
|
|
||||||
for (let i = 0; i < topCount; i++) {
|
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)
|
console.info(outstring)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*!
|
/*!
|
||||||
* The 2022 r/place Atlas
|
* The 2022 r/place Atlas
|
||||||
* Copyright (c) 2017 Roland Rytz <roland@draemm.li>
|
* 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)
|
* Licensed under AGPL-3.0 (https://2022.place-atlas.stefanocoding.me/license.txt)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -32,6 +32,12 @@ let currentPeriod = defaultPeriod
|
||||||
window.currentVariation = currentVariation
|
window.currentVariation = currentVariation
|
||||||
window.currentPeriod = currentPeriod
|
window.currentPeriod = currentPeriod
|
||||||
|
|
||||||
|
let atlasDisplay = {}
|
||||||
|
window.atlasDisplay = atlasDisplay
|
||||||
|
|
||||||
|
const additionalLayers = []
|
||||||
|
const additionalLayerCanvas = document.createElement('canvas')
|
||||||
|
|
||||||
// SETUP
|
// SETUP
|
||||||
if (variationsConfig[currentVariation].versions.length === 1) bottomBar.classList.add('no-time-slider')
|
if (variationsConfig[currentVariation].versions.length === 1) bottomBar.classList.add('no-time-slider')
|
||||||
|
|
||||||
|
@ -70,7 +76,7 @@ const dispatchTimeUpdateEvent = (period = currentPeriod, variation = currentVari
|
||||||
detail: {
|
detail: {
|
||||||
period: period,
|
period: period,
|
||||||
variation: variation,
|
variation: variation,
|
||||||
periodString: formatPeriod(period, period, variation),
|
periodString: formatPeriod(period, null, variation),
|
||||||
atlas: atlas
|
atlas: atlas
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -79,7 +85,7 @@ const dispatchTimeUpdateEvent = (period = currentPeriod, variation = currentVari
|
||||||
|
|
||||||
async function updateBackground(newPeriod = currentPeriod, newVariation = currentVariation) {
|
async function updateBackground(newPeriod = currentPeriod, newVariation = currentVariation) {
|
||||||
abortController.abort()
|
abortController.abort()
|
||||||
myAbortController = new AbortController()
|
const myAbortController = new AbortController()
|
||||||
abortController = myAbortController
|
abortController = myAbortController
|
||||||
currentUpdateIndex++
|
currentUpdateIndex++
|
||||||
const myUpdateIndex = currentUpdateIndex
|
const myUpdateIndex = currentUpdateIndex
|
||||||
|
@ -96,7 +102,7 @@ async function updateBackground(newPeriod = currentPeriod, newVariation = curren
|
||||||
variantsEl.parentElement.classList.remove('input-group')
|
variantsEl.parentElement.classList.remove('input-group')
|
||||||
}
|
}
|
||||||
|
|
||||||
const configObject = variationConfig.versions[currentPeriod]
|
const configObject = variationConfig.versions[newPeriod]
|
||||||
let layerUrls = []
|
let layerUrls = []
|
||||||
let layers = []
|
let layers = []
|
||||||
|
|
||||||
|
@ -110,39 +116,67 @@ async function updateBackground(newPeriod = currentPeriod, newVariation = curren
|
||||||
|
|
||||||
layers.length = layerUrls.length
|
layers.length = layerUrls.length
|
||||||
await Promise.all(layerUrls.map(async (url, i) => {
|
await Promise.all(layerUrls.map(async (url, i) => {
|
||||||
const imageBlob = await (await fetch(url, { signal: myAbortController.signal })).blob()
|
try {
|
||||||
const imageLayer = new Image()
|
const imageBlob = await (await fetch(url, { signal: myAbortController.signal })).blob()
|
||||||
await new Promise(resolve => {
|
const imageLayer = new Image()
|
||||||
imageLayer.onload = () => {
|
await new Promise(resolve => {
|
||||||
context.canvas.width = Math.max(imageLayer.width, context.canvas.width)
|
imageLayer.onload = () => {
|
||||||
context.canvas.height = Math.max(imageLayer.height, context.canvas.height)
|
context.canvas.width = Math.max(imageLayer.width, context.canvas.width)
|
||||||
layers[i] = imageLayer
|
context.canvas.height = Math.max(imageLayer.height, context.canvas.height)
|
||||||
resolve()
|
layers[i] = imageLayer
|
||||||
}
|
resolve()
|
||||||
imageLayer.src = URL.createObjectURL(imageBlob)
|
}
|
||||||
})
|
imageLayer.src = URL.createObjectURL(imageBlob)
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
const aborted = myAbortController.signal.aborted
|
||||||
|
if (!aborted) throw e
|
||||||
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
if (myAbortController.signal.aborted || newPeriod !== currentPeriod || newVariation !== currentVariation) {
|
if (myAbortController.signal.aborted || newPeriod !== currentPeriod || newVariation !== currentVariation || currentUpdateIndex !== myUpdateIndex) {
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const imageLayer of layers) {
|
for (const imageLayer of layers) {
|
||||||
context.drawImage(imageLayer, 0, 0)
|
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]
|
if (currentUpdateIndex !== myUpdateIndex) return [configObject, newPeriod, newVariation]
|
||||||
const blob = await new Promise(resolve => canvas.toBlob(resolve))
|
const blob = await new Promise(resolve => canvas.toBlob(resolve))
|
||||||
canvasUrl = URL.createObjectURL(blob)
|
canvasUrl = URL.createObjectURL(blob)
|
||||||
image.src = canvasUrl
|
image.src = canvasUrl
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let loadingTimeout = setTimeout(() => {}, 0)
|
||||||
|
|
||||||
async function updateTime(newPeriod = currentPeriod, newVariation = currentVariation, forceLoad = false) {
|
async function updateTime(newPeriod = currentPeriod, newVariation = currentVariation, forceLoad = false) {
|
||||||
if (newPeriod === currentPeriod && !forceLoad) {
|
if (newPeriod === currentPeriod && newVariation === currentVariation && !forceLoad) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
document.body.dataset.canvasLoading = ""
|
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 oldPeriod = currentPeriod
|
||||||
const oldVariation = currentVariation
|
const oldVariation = currentVariation
|
||||||
|
|
||||||
|
@ -167,12 +201,16 @@ async function updateTime(newPeriod = currentPeriod, newVariation = currentVaria
|
||||||
timelineSlider.value = currentPeriod
|
timelineSlider.value = currentPeriod
|
||||||
updateTooltip(newPeriod, newVariation)
|
updateTooltip(newPeriod, newVariation)
|
||||||
|
|
||||||
await updateBackground(newPeriod, newVariation)
|
const updateBackgroundResult = await updateBackground(newPeriod, newVariation)
|
||||||
|
|
||||||
atlas = generateAtlasForPeriod(newPeriod, newVariation)
|
if (!updateBackgroundResult) return
|
||||||
|
|
||||||
dispatchTimeUpdateEvent(newPeriod, newVariation, atlas)
|
dispatchTimeUpdateEvent(newPeriod, newVariation, atlas)
|
||||||
delete document.body.dataset.canvasLoading
|
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 = ""
|
tooltip.dataset.forceVisible = ""
|
||||||
clearTimeout(tooltipDelayHide)
|
clearTimeout(tooltipDelayHide)
|
||||||
tooltipDelayHide = setTimeout(() => {
|
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
|
let chosenIndex
|
||||||
|
|
||||||
const validPeriods2 = Object.keys(entry.path)
|
const validPeriods2 = Object.keys(entry.path)
|
||||||
|
|
||||||
for (const i in validPeriods2) {
|
periodCheck: for (const i in validPeriods2) {
|
||||||
const validPeriods = validPeriods2[i].split(', ')
|
const validPeriods = validPeriods2[i].split(', ')
|
||||||
for (const j in validPeriods) {
|
for (const j in validPeriods) {
|
||||||
const [start, end, variation] = parsePeriod(validPeriods[j])
|
const [start, end, variation] = parsePeriod(validPeriods[j])
|
||||||
if (isOnPeriod(start, end, variation, newPeriod, newVariation)) {
|
if (isOnPeriod(start, end, variation, newPeriod, newVariation)) {
|
||||||
chosenIndex = i
|
chosenIndex = i
|
||||||
break
|
break periodCheck
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (chosenIndex !== undefined) break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chosenIndex === undefined) continue
|
if (chosenIndex === undefined) continue
|
||||||
|
@ -207,14 +251,18 @@ function generateAtlasForPeriod(newPeriod = currentPeriod, newVariation = curren
|
||||||
|
|
||||||
if (pathChosen === undefined) continue
|
if (pathChosen === undefined) continue
|
||||||
|
|
||||||
atlas.push({
|
newAtlas[id] = {
|
||||||
...entry,
|
...entry,
|
||||||
path: pathChosen,
|
path: pathChosen,
|
||||||
center: centerChosen,
|
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) {
|
function formatPeriod(targetStart, targetEnd, targetVariation, forUrl = false) {
|
||||||
targetStart ??= currentPeriod
|
targetStart ??= currentPeriod
|
||||||
targetEnd ??= currentPeriod
|
targetEnd ??= targetStart
|
||||||
targetVariation ??= currentVariation
|
targetVariation ??= currentVariation
|
||||||
|
|
||||||
let periodString, variationString
|
let periodString, variationString
|
||||||
|
@ -297,12 +345,11 @@ function setReferenceVal(reference, newValue) {
|
||||||
else return 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('/')
|
let hashData = window.location.hash.substring(1).split('/')
|
||||||
|
|
||||||
targetEntry = setReferenceVal(targetEntry, hashData[0])
|
targetEntry = setReferenceVal(targetEntry, hashData[0])
|
||||||
targetPeriodStart = setReferenceVal(targetPeriodStart, currentPeriod)
|
targetPeriod = setReferenceVal(targetPeriod, currentPeriod)
|
||||||
targetPeriodEnd = setReferenceVal(targetPeriodEnd, currentPeriod)
|
|
||||||
targetVariation = setReferenceVal(targetVariation, currentVariation)
|
targetVariation = setReferenceVal(targetVariation, currentVariation)
|
||||||
targetX = setReferenceVal(targetX, canvasCenter.x - scaleZoomOrigin[0])
|
targetX = setReferenceVal(targetX, canvasCenter.x - scaleZoomOrigin[0])
|
||||||
targetY = setReferenceVal(targetY, canvasCenter.y - scaleZoomOrigin[1])
|
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+$/, '')
|
if (targetZoom) targetZoom = targetZoom.toFixed(3).replace(/\.?0+$/, '')
|
||||||
|
|
||||||
const result = [targetEntry]
|
const result = [targetEntry]
|
||||||
const targetPeriod = formatPeriod(targetPeriodStart, targetPeriodEnd, targetVariation, true)
|
const targetPeriodFormat = formatPeriod(targetPeriod, null, targetVariation, true)
|
||||||
result.push(targetPeriod, targetX, targetY, targetZoom)
|
result.push(targetPeriodFormat, targetX, targetY, targetZoom)
|
||||||
if (!result.some(el => el || el === 0)) return ''
|
if (!result.some(el => el || el === 0)) return ''
|
||||||
return '#' + result.join('/').replace(/\/+$/, '')
|
return '#' + result.join('/').replace(/\/+$/, '')
|
||||||
}
|
}
|
||||||
|
@ -327,4 +374,63 @@ function downloadCanvas() {
|
||||||
document.body.appendChild(linkEl)
|
document.body.appendChild(linkEl)
|
||||||
linkEl.click()
|
linkEl.click()
|
||||||
document.body.removeChild(linkEl)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*!
|
/*!
|
||||||
* The 2022 r/place Atlas
|
* The 2022 r/place Atlas
|
||||||
* Copyright (c) 2017 Roland Rytz <roland@draemm.li>
|
* 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)
|
* 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.id = "objectEditNav"
|
||||||
objectEditNav.textContent = "Edit"
|
objectEditNav.textContent = "Edit"
|
||||||
|
|
||||||
let atlasDisplay
|
let atlas = null
|
||||||
|
window.atlas = atlas
|
||||||
|
|
||||||
|
let atlasOrder = []
|
||||||
|
window.atlasOrder = atlasOrder
|
||||||
|
|
||||||
const entriesLimit = 50
|
const entriesLimit = 50
|
||||||
let entriesOffset = 0
|
let entriesOffset = 0
|
||||||
|
@ -65,18 +69,18 @@ const moreEntriesObserver = new IntersectionObserver(entries => {
|
||||||
|
|
||||||
moreEntriesObserver.observe(moreEntriesButton)
|
moreEntriesObserver.observe(moreEntriesButton)
|
||||||
|
|
||||||
let defaultSort = sortInput.value
|
let defaultSort = sortInput.value
|
||||||
|
|
||||||
let lastPos = [0, 0]
|
let lastPos = [0, 0]
|
||||||
|
|
||||||
let fixed = false; // Fix hovered items in place, so that clicking on links is possible
|
let fixed = false; // Fix hovered items in place, so that clicking on links is possible
|
||||||
|
|
||||||
searchInput.addEventListener("input", function () {
|
searchInput.addEventListener("input", function () {
|
||||||
resetEntriesList()
|
updateAtlas()
|
||||||
})
|
})
|
||||||
|
|
||||||
sortInput.addEventListener("input", function () {
|
sortInput.addEventListener("input", function () {
|
||||||
resetEntriesList()
|
updateAtlas()
|
||||||
})
|
})
|
||||||
|
|
||||||
offcanvasDraw.addEventListener('show.bs.offcanvas', () => {
|
offcanvasDraw.addEventListener('show.bs.offcanvas', () => {
|
||||||
|
@ -112,8 +116,8 @@ offcanvasList.addEventListener('shown.bs.offcanvas', e => {
|
||||||
wrapper.classList.remove('listTransitioning')
|
wrapper.classList.remove('listTransitioning')
|
||||||
updateHovering(e)
|
updateHovering(e)
|
||||||
applyView()
|
applyView()
|
||||||
render()
|
renderHighlight()
|
||||||
updateLines()
|
renderLines()
|
||||||
})
|
})
|
||||||
|
|
||||||
offcanvasList.addEventListener('hide.bs.offcanvas', () => {
|
offcanvasList.addEventListener('hide.bs.offcanvas', () => {
|
||||||
|
@ -127,63 +131,59 @@ offcanvasList.addEventListener('hidden.bs.offcanvas', e => {
|
||||||
wrapper.classList.remove('listTransitioning')
|
wrapper.classList.remove('listTransitioning')
|
||||||
updateHovering(e)
|
updateHovering(e)
|
||||||
applyView()
|
applyView()
|
||||||
render()
|
renderHighlight()
|
||||||
updateLines()
|
renderLines()
|
||||||
})
|
})
|
||||||
|
|
||||||
closeObjectsListButton.addEventListener("click", clearObjectsList)
|
closeObjectsListButton.addEventListener("click", clearObjectsList)
|
||||||
|
|
||||||
bottomBar.addEventListener("mouseover", () => {
|
|
||||||
if (!fixed) clearObjectsList()
|
|
||||||
})
|
|
||||||
|
|
||||||
function clearObjectsList() {
|
function clearObjectsList() {
|
||||||
|
hovered = []
|
||||||
|
fixed = false
|
||||||
|
renderLines()
|
||||||
|
renderHighlight()
|
||||||
|
document.title = pageTitle
|
||||||
closeObjectsListButton.classList.add("d-none")
|
closeObjectsListButton.classList.add("d-none")
|
||||||
objectsListOverflowNotice.classList.add("d-none")
|
objectsListOverflowNotice.classList.add("d-none")
|
||||||
entriesList.classList.remove("disableHover")
|
entriesList.classList.remove("disableHover")
|
||||||
hovered = []
|
|
||||||
objectsContainer.replaceChildren()
|
objectsContainer.replaceChildren()
|
||||||
updateLines()
|
|
||||||
fixed = false
|
|
||||||
render()
|
|
||||||
objectEditNav.remove()
|
objectEditNav.remove()
|
||||||
updateHash(false)
|
updateHash(false)
|
||||||
document.title = pageTitle
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleFixed(e, tapped) {
|
function toggleFixed(e, tapped) {
|
||||||
if (!fixed && hovered.length === 0) {
|
if (!fixed && hovered.length === 0) {
|
||||||
entriesList.classList.remove("disableHover")
|
entriesList.classList.remove("disableHover")
|
||||||
return 0
|
return
|
||||||
}
|
}
|
||||||
fixed = !fixed
|
fixed = !fixed
|
||||||
if (!fixed) {
|
if (!fixed) {
|
||||||
updateHovering(e, tapped)
|
updateHovering(e, tapped)
|
||||||
render()
|
renderHighlight()
|
||||||
}
|
}
|
||||||
entriesList.classList.add("disableHover")
|
entriesList.classList.add("disableHover")
|
||||||
objectsListOverflowNotice.classList.add("d-none")
|
objectsListOverflowNotice.classList.add("d-none")
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("resize", updateLines)
|
window.addEventListener("dblClick", renderLines)
|
||||||
window.addEventListener("mousemove", updateLines)
|
window.addEventListener("wheel", renderLines)
|
||||||
window.addEventListener("dblClick", updateLines)
|
|
||||||
window.addEventListener("wheel", updateLines)
|
|
||||||
|
|
||||||
objectsContainer.addEventListener("scroll", () => {
|
objectsContainer.addEventListener("scroll", () => {
|
||||||
updateLines()
|
renderLines()
|
||||||
})
|
})
|
||||||
|
|
||||||
window.addEventListener("resize", () => {
|
window.addEventListener("resize", () => {
|
||||||
|
|
||||||
applyView()
|
applyView()
|
||||||
render()
|
renderHighlight()
|
||||||
updateLines()
|
renderLines()
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
function updateLines() {
|
async function renderLines() {
|
||||||
|
if (hovered.length === 0) {
|
||||||
|
linesContext.clearRect(0, 0, linesCanvas.width, linesCanvas.height)
|
||||||
|
return
|
||||||
|
}
|
||||||
// Line border
|
// Line border
|
||||||
linesCanvas.width = linesCanvas.clientWidth
|
linesCanvas.width = linesCanvas.clientWidth
|
||||||
linesCanvas.height = linesCanvas.clientHeight
|
linesCanvas.height = linesCanvas.clientHeight
|
||||||
|
@ -260,9 +260,9 @@ function renderBackground(atlas) {
|
||||||
backgroundContext.fillStyle = "rgba(0, 0, 0, 0.6)"
|
backgroundContext.fillStyle = "rgba(0, 0, 0, 0.6)"
|
||||||
backgroundContext.fillRect(0, 0, backgroundCanvas.width, backgroundCanvas.height)
|
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()
|
backgroundContext.beginPath()
|
||||||
|
|
||||||
|
@ -279,7 +279,7 @@ function renderBackground(atlas) {
|
||||||
backgroundContext.closePath()
|
backgroundContext.closePath()
|
||||||
|
|
||||||
let bgStrokeStyle
|
let bgStrokeStyle
|
||||||
switch (atlas[i].diff) {
|
switch (entry.diff) {
|
||||||
case "add":
|
case "add":
|
||||||
bgStrokeStyle = "rgba(0, 255, 0, 1)"
|
bgStrokeStyle = "rgba(0, 255, 0, 1)"
|
||||||
backgroundContext.lineWidth = 2
|
backgroundContext.lineWidth = 2
|
||||||
|
@ -299,45 +299,39 @@ function renderBackground(atlas) {
|
||||||
backgroundContext.strokeStyle = bgStrokeStyle
|
backgroundContext.strokeStyle = bgStrokeStyle
|
||||||
backgroundContext.stroke()
|
backgroundContext.stroke()
|
||||||
backgroundContext.lineWidth = 1
|
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) {
|
document.getElementById("atlasSize").innerHTML = ""
|
||||||
atlasDisplay = atlas.filter(entry => {
|
|
||||||
return (
|
if (search) {
|
||||||
entry.name.toLowerCase().includes(filter.toLowerCase())
|
for (const [id, entry] of Object.entries(prevAtlas)) {
|
||||||
|| entry.description?.toLowerCase().includes(filter.toLowerCase())
|
if (!(
|
||||||
|| Object.values(entry.links).flat().some(str => str.toLowerCase().includes(filter))
|
entry.name.toLowerCase().includes(search.toLowerCase()) ||
|
||||||
|| entry.id.toString() === filter
|
entry.description?.toLowerCase().includes(search.toLowerCase()) ||
|
||||||
)
|
Object.values(entry.links).flat().some(str => str.toLowerCase().includes(search)) ||
|
||||||
})
|
id.toString() === search
|
||||||
document.getElementById("atlasSize").innerHTML = "Found " + atlasDisplay.length + " entries."
|
)) delete newAtlas[id]
|
||||||
} else {
|
}
|
||||||
document.getElementById("atlasSize").innerHTML = "The Atlas contains " + atlasDisplay.length + " entries."
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderBackground(atlasDisplay)
|
// document.getElementById("sort").value = sort
|
||||||
render()
|
|
||||||
|
|
||||||
sort ||= defaultSort
|
|
||||||
document.getElementById("sort").value = sort
|
|
||||||
|
|
||||||
//console.log(sort)
|
|
||||||
|
|
||||||
let sortFunction
|
let sortFunction
|
||||||
|
|
||||||
//console.log(sort)
|
|
||||||
|
|
||||||
switch (sort) {
|
switch (sort) {
|
||||||
case "shuffle":
|
case "shuffle":
|
||||||
sortFunction = null
|
sortFunction = () => Math.random() - 0.5
|
||||||
if (entriesOffset === 0) {
|
|
||||||
shuffle()
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
case "alphaAsc":
|
case "alphaAsc":
|
||||||
sortFunction = (a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase())
|
sortFunction = (a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase())
|
||||||
|
@ -369,100 +363,130 @@ function buildObjectsList(filter, sort) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newAtlasOrder = Object.keys(newAtlas)
|
||||||
if (sortFunction) {
|
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)
|
moreEntriesButton.removeEventListener('click', showMoreEntries)
|
||||||
showMoreEntries = () => {
|
showMoreEntries = () => {
|
||||||
|
|
||||||
if (entriesList.contains(moreEntriesButton)) {
|
if (entriesList.contains(moreEntriesButton)) {
|
||||||
entriesList.removeChild(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
|
let entriesLeft = entriesLimit
|
||||||
|
let element
|
||||||
if (atlasDisplay.length > entriesOffset) {
|
|
||||||
moreEntriesButton.innerHTML = "Show " + Math.min(entriesLimit, atlasDisplay.length - entriesOffset) + " more"
|
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)
|
entriesList.appendChild(moreEntriesButton)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
moreEntriesButton.addEventListener('click', showMoreEntries)
|
moreEntriesButton.addEventListener('click', showMoreEntries)
|
||||||
showMoreEntries()
|
showMoreEntries()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function shuffle() {
|
async function renderHighlight() {
|
||||||
//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() {
|
|
||||||
|
|
||||||
highlightContext.clearRect(0, 0, highlightCanvas.width, highlightCanvas.height)
|
highlightContext.clearRect(0, 0, highlightCanvas.width, highlightCanvas.height)
|
||||||
|
|
||||||
|
@ -478,10 +502,8 @@ async function render() {
|
||||||
container.style.cursor = "default"
|
container.style.cursor = "default"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (let i = 0; i < hovered.length; i++) {
|
for (let i = 0; i < hovered.length; i++) {
|
||||||
|
|
||||||
|
|
||||||
const path = hovered[i].path
|
const path = hovered[i].path
|
||||||
|
|
||||||
highlightContext.beginPath()
|
highlightContext.beginPath()
|
||||||
|
@ -507,28 +529,6 @@ async function render() {
|
||||||
highlightContext.globalCompositeOperation = "source-out"
|
highlightContext.globalCompositeOperation = "source-out"
|
||||||
highlightContext.drawImage(backgroundCanvas, 0, 0)
|
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++) {
|
for (let i = 0; i < hovered.length; i++) {
|
||||||
|
|
||||||
const path = hovered[i].path
|
const path = hovered[i].path
|
||||||
|
@ -591,12 +591,16 @@ function updateHovering(e, tapped) {
|
||||||
const pos = updateCoordsDisplay(e)
|
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
|
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 = []
|
let newHovered = []
|
||||||
for (const entry of atlasDisplay) {
|
for (const entry of Object.values(atlasDisplay)) {
|
||||||
if (pointIsInPolygon(pos, entry.path)) newHovered.push(entry)
|
if (pointIsInPolygon(pos, entry.path)) newHovered.push(entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newHovered = newHovered.sort(function (a, b) {
|
||||||
|
return calcPolygonArea(a.path) - calcPolygonArea(b.path)
|
||||||
|
})
|
||||||
|
|
||||||
let changed = false
|
let changed = false
|
||||||
|
|
||||||
if (hovered.length === newHovered.length) {
|
if (hovered.length === newHovered.length) {
|
||||||
|
@ -612,9 +616,7 @@ function updateHovering(e, tapped) {
|
||||||
|
|
||||||
if (!changed) return
|
if (!changed) return
|
||||||
|
|
||||||
hovered = newHovered.sort(function (a, b) {
|
hovered = newHovered
|
||||||
return calcPolygonArea(a.path) - calcPolygonArea(b.path)
|
|
||||||
})
|
|
||||||
|
|
||||||
objectsContainer.replaceChildren()
|
objectsContainer.replaceChildren()
|
||||||
|
|
||||||
|
@ -639,12 +641,13 @@ function updateHovering(e, tapped) {
|
||||||
objectsListOverflowNotice.classList.add("d-none")
|
objectsListOverflowNotice.classList.add("d-none")
|
||||||
entriesList.classList.remove("disableHover")
|
entriesList.classList.remove("disableHover")
|
||||||
}
|
}
|
||||||
render()
|
renderLines()
|
||||||
|
renderHighlight()
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("hashchange", updateViewFromHash)
|
window.addEventListener("hashchange", updateViewFromHash)
|
||||||
|
|
||||||
function updateViewFromHash() {
|
async function updateViewFromHash() {
|
||||||
|
|
||||||
const hash = window.location.hash.substring(1); //Remove hash prefix
|
const hash = window.location.hash.substring(1); //Remove hash prefix
|
||||||
let [hashEntryId, hashPeriod, hashX, hashY, hashZoom] = hash.split('/')
|
let [hashEntryId, hashPeriod, hashX, hashY, hashZoom] = hash.split('/')
|
||||||
|
@ -666,11 +669,11 @@ function updateViewFromHash() {
|
||||||
targetPeriod = defaultPeriod
|
targetPeriod = defaultPeriod
|
||||||
targetVariation = defaultVariation
|
targetVariation = defaultVariation
|
||||||
}
|
}
|
||||||
updateTime(targetPeriod, targetVariation, true)
|
await updateTime(targetPeriod, targetVariation)
|
||||||
|
|
||||||
setView(
|
setView(
|
||||||
(isNaN(hashX) || hashX === '') ? undefined : Number(hashX),
|
(isNaN(hashX) || hashX === '') ? undefined : Number(hashX),
|
||||||
(isNaN(hashY) || hashY === '') ? undefined : Number(hashY),
|
(isNaN(hashY) || hashY === '') ? undefined : Number(hashY),
|
||||||
(isNaN(hashZoom) || hashZoom === '') ? undefined : Number(hashZoom)
|
(isNaN(hashZoom) || hashZoom === '') ? undefined : Number(hashZoom)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -678,13 +681,8 @@ function updateViewFromHash() {
|
||||||
|
|
||||||
// Highlight entry from hash
|
// Highlight entry from hash
|
||||||
|
|
||||||
const entries = atlas.filter(e => {
|
const entry = atlasDisplay[hashEntryId]
|
||||||
return e.id.toString() === hashEntryId
|
if (!entry) return
|
||||||
})
|
|
||||||
|
|
||||||
if (entries.length !== 1) return
|
|
||||||
|
|
||||||
const entry = entries[0]
|
|
||||||
|
|
||||||
document.title = entry.name + " on " + pageTitle
|
document.title = entry.name + " on " + pageTitle
|
||||||
|
|
||||||
|
@ -702,24 +700,24 @@ function updateViewFromHash() {
|
||||||
objectsContainer.replaceChildren()
|
objectsContainer.replaceChildren()
|
||||||
objectsContainer.appendChild(infoElement)
|
objectsContainer.appendChild(infoElement)
|
||||||
|
|
||||||
renderBackground(atlas)
|
|
||||||
setView(
|
setView(
|
||||||
(isNaN(hashX) || hashX === '') ? entry.center[0] : Number(hashX),
|
(isNaN(hashX) || hashX === '') ? entry.center[0] : Number(hashX),
|
||||||
(isNaN(hashY) || hashY === '') ? entry.center[1] : Number(hashY),
|
(isNaN(hashY) || hashY === '') ? entry.center[1] : Number(hashY),
|
||||||
(isNaN(hashZoom) || hashZoom === '') ? setZoomByPath(entry.path) : Number(hashZoom)
|
(isNaN(hashZoom) || hashZoom === '') ? calculateZoomFromPath(entry.path) : Number(hashZoom)
|
||||||
)
|
)
|
||||||
|
|
||||||
closeObjectsListButton.classList.remove("d-none")
|
closeObjectsListButton.classList.remove("d-none")
|
||||||
entriesList.classList.add("disableHover")
|
entriesList.classList.add("disableHover")
|
||||||
|
|
||||||
hovered = [entry]
|
hovered = [{...entry, element: infoElement}]
|
||||||
render()
|
renderBackground(atlasDisplay)
|
||||||
hovered[0].element = infoElement
|
renderHighlight(atlasDisplay)
|
||||||
updateLines()
|
renderLines()
|
||||||
}
|
}
|
||||||
|
|
||||||
function setZoomByPath(path) {
|
function calculateZoomFromPath(path) {
|
||||||
|
|
||||||
|
let zoom
|
||||||
let boundingBox = [canvasSize.x + canvasOffset.x, canvasOffset.x, canvasSize.y + canvasOffset.y, canvasOffset.y]
|
let boundingBox = [canvasSize.x + canvasOffset.x, canvasOffset.x, canvasSize.y + canvasOffset.y, canvasOffset.y]
|
||||||
path?.forEach(([x, y]) => {
|
path?.forEach(([x, y]) => {
|
||||||
boundingBox[0] = Math.min(boundingBox[0], x)
|
boundingBox[0] = Math.min(boundingBox[0], x)
|
||||||
|
@ -741,13 +739,10 @@ function setZoomByPath(path) {
|
||||||
|
|
||||||
function initView() {
|
function initView() {
|
||||||
|
|
||||||
buildObjectsList(null, null)
|
updateAtlas()
|
||||||
renderBackground(atlas)
|
|
||||||
render()
|
|
||||||
|
|
||||||
document.addEventListener('timeupdate', () => {
|
document.addEventListener('timeupdate', () => {
|
||||||
atlasDisplay = atlas.slice()
|
updateAtlas()
|
||||||
resetEntriesList()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// parse linked atlas entry id from link hash
|
// parse linked atlas entry id from link hash
|
||||||
|
@ -758,22 +753,20 @@ function initView() {
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
applyView()
|
applyView()
|
||||||
render()
|
renderLines()
|
||||||
updateLines()
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function initExplore() {
|
function initExplore() {
|
||||||
|
|
||||||
window.updateHovering = updateHovering
|
window.updateHovering = updateHovering
|
||||||
window.render = () => { }
|
window.renderHighlight = () => { }
|
||||||
|
|
||||||
function updateHovering(e, tapped) {
|
function updateHovering(e, tapped) {
|
||||||
if (dragging || (fixed && !tapped)) return
|
if (dragging || (fixed && !tapped)) return
|
||||||
updateCoordsDisplay(e)
|
updateCoordsDisplay(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
renderBackground(atlas)
|
renderBackground({})
|
||||||
|
|
||||||
applyView()
|
applyView()
|
||||||
|
|
||||||
|
@ -790,7 +783,7 @@ function initGlobal() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
document.addEventListener('timeupdate', event => {
|
document.addEventListener('timeupdate', () => {
|
||||||
updateHash()
|
updateHash()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -837,6 +830,84 @@ function initViewGlobal() {
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('timeupdate', event => {
|
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
|
||||||
|
|
||||||
|
}
|
||||||
|
|
156
web/about.html
156
web/about.html
|
@ -1,7 +1,7 @@
|
||||||
<!--
|
<!--
|
||||||
The 2022 r/place Atlas
|
The 2022 r/place Atlas
|
||||||
Copyright (c) 2017 Roland Rytz <roland@draemm.li>
|
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)
|
Licensed under AGPL-3.0 (https://2022.place-atlas.stefanocoding.me/license.txt)
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
@ -10,8 +10,8 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>About - The 2022 r/place Atlas</title>
|
<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="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 contributors (original by Roland Rytz)">
|
<meta name="author" content="Place Atlas Initiative and contributors (original by Roland Rytz)">
|
||||||
<meta name="application-name" content="2022 r/place Atlas">
|
<meta name="application-name" content="2022 r/place Atlas">
|
||||||
<meta name="robots" content="index, follow">
|
<meta name="robots" content="index, follow">
|
||||||
|
|
||||||
|
@ -23,18 +23,19 @@
|
||||||
<meta property="og:image:width" content="512">
|
<meta property="og:image:width" content="512">
|
||||||
<meta property="og:image:height" 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 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: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:url" content="https://2022.place-atlas.stefanocoding.me/">
|
||||||
<meta name="twitter:title" content="About - The 2022 r/place Atlas">
|
<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" content="https://2022.place-atlas.stefanocoding.me/_img/logo.png">
|
||||||
<meta name="twitter:image:alt" content="The 2022 r/place Atlas logo">
|
<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="viewport" content="width=device-width, height=device-height, initial-scale=1, viewport-fit=cover">
|
||||||
<meta name="color-scheme" content="light dark">
|
<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="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 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>
|
<i class="bi bi-list" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="navbar-collapse collapse" id="navbarCollapse">
|
<div class="navbar-collapse collapse" id="navbarCollapse">
|
||||||
<ul class="navbar-nav ms-auto pt-2 pt-md-0">
|
<ul class="navbar-nav flex-row flex-wrap ms-auto pt-2 pt-md-0">
|
||||||
<li class="nav-item dropdown">
|
<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">
|
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false" aria-current="page">
|
||||||
Atlas Map
|
Atlas Map
|
||||||
</a>
|
</a>
|
||||||
|
@ -72,9 +73,12 @@
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item col-6 col-md-auto">
|
<li class="nav-item col-6 col-md-auto">
|
||||||
<a class="nav-link" href="https://place-wiki.stefanocoding.me/">Place Wiki</a>
|
<a class="nav-link" href="https://place-wiki.stefanocoding.me/" target="_blank">Place Wiki</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<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>
|
<a class="nav-link active" href="#" aria-current="page">About</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -86,119 +90,35 @@
|
||||||
<div class="row g-5">
|
<div class="row g-5">
|
||||||
<div class="col-md-7 col-xl-8">
|
<div class="col-md-7 col-xl-8">
|
||||||
<h1 class="display-5 fw-bold mb-4">The 2022 r/place Atlas</h1>
|
<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>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/">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>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>
|
<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" 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>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>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>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>
|
<h2>Contributing</h2>
|
||||||
<p>This project is open source, and contributions are welcome. In fact, the Atlas relies on user contributions.</p>
|
<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>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/">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><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">
|
<div id="credits">
|
||||||
<h2>Credit</h2>
|
<h2 class="mb-2">Credits</h2>
|
||||||
<h3>Project Contributors</h3>
|
<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>
|
<ul>
|
||||||
<li>Project Lead:
|
<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>
|
||||||
<a href="https://reddit.com/user/TCOOfficiall">TCOOfficiall</a> (Stefano Haagmans)
|
<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>
|
||||||
<a href="https://stefanocoding.me/"><i aria-label="Website" class="bi bi-globe"></i></a>
|
<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>
|
||||||
<a href="https://github.com/Codixer"><i aria-label="GitHub" class="bi bi-github"></i></a>
|
<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>
|
<li>Thank you to <a href="https://place.thatguyalex.com/" target="_blank" rel="noreferrer">Alex Tsernoh</a> for providing the initial canvas images.</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>
|
|
||||||
</ul>
|
</ul>
|
||||||
<h3>Contributors</h3>
|
<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> contributors.</p>
|
<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, amended existing ones, reported bugs and just supported the project in general.</p>
|
<p>Thank you to everyone who submitted new entries and amended existing ones.</p>
|
||||||
<div id="contributors-wrapper" style="text-align: justify;"></div>
|
<div id="entry-contributors-wrapper" style="text-align: justify;"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-5 col-xl-4">
|
<div class="col-md-5 col-xl-4">
|
||||||
|
@ -218,9 +138,9 @@
|
||||||
<h4>Sponsor this project</h4>
|
<h4>Sponsor this project</h4>
|
||||||
<p>Current 2022 Atlas Maintainers:</p>
|
<p>Current 2022 Atlas Maintainers:</p>
|
||||||
<ul class="mb-0">
|
<ul class="mb-0">
|
||||||
<li><a href="https://paypal.me/placeAtlas/5">PayPal</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">Patreon</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">Ko-Fi</a></li>
|
<li><a href="https://ko-fi.com/placeatlas" target="_blank" rel="noreferrer">Ko-Fi</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
|
@ -235,7 +155,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<footer class="pt-3 mt-4 text-muted border-top">
|
<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>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<!--
|
<!--
|
||||||
The 2022 r/place Atlas
|
The 2022 r/place Atlas
|
||||||
Copyright (c) 2017 Roland Rytz <roland@draemm.li>
|
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)
|
Licensed under AGPL-3.0 (https://2022.place-atlas.stefanocoding.me/license.txt)
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
@ -11,10 +11,10 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>The 2022 r/place Atlas</title>
|
<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="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="author" content="Place Atlas Initiative and contributors (original by Roland Rytz)">
|
||||||
<meta name="application-name" content="The r/place Atlas 2022">
|
<meta name="application-name" content="The 2022 r/place Atlas">
|
||||||
<meta name="robots" content="index, follow">
|
<meta name="robots" content="index, follow">
|
||||||
|
|
||||||
<meta property="og:title" content="The 2022 r/place Atlas">
|
<meta property="og:title" content="The 2022 r/place Atlas">
|
||||||
<meta property="og:type" content="website">
|
<meta property="og:type" content="website">
|
||||||
<meta property="og:url" content="https://2022.place-atlas.stefanocoding.me/">
|
<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:type" content="image/png">
|
||||||
<meta property="og:image:width" content="512">
|
<meta property="og:image:width" content="512">
|
||||||
<meta property="og:image:height" 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 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: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:url" content="https://2022.place-atlas.stefanocoding.me/">
|
||||||
<meta name="twitter:title" content="The 2022 r/place Atlas">
|
<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.">
|
<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="twitter:image:alt" content="The 2022 r/place Atlas logo">
|
||||||
|
|
||||||
<!-- <meta name="google-site-verification" content="gZGHpBSMzffAbIn0qB8b00We6EwSGkDTfDoQVv-NWss"/> -->
|
<!-- <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="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="mobile-web-app-capable" content="yes">
|
||||||
<meta name="color-scheme" content="light dark">
|
<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: light)" content="white">
|
||||||
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#222">
|
<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="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 alternate" href="_img/favicon.png" type="image/png" class="js-site-favicon">
|
||||||
<link rel="icon" href="_img/favicon.svg" type="image/svg+xml" class="js-site-favicon">
|
<link rel="icon" href="_img/favicon.svg" type="image/svg+xml" class="js-site-favicon">
|
||||||
|
|
||||||
<link rel="stylesheet" href="./_css/style.css">
|
<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-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="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css">
|
||||||
<link rel="manifest" href="./manifest.webmanifest">
|
<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 type="module" src="https://cdn.jsdelivr.net/npm/@pwabuilder/pwaupdate/dist/pwa-update.js"></script>
|
||||||
<script src="./_js/favicon.js" defer></script>
|
<script src="./_js/favicon.js" defer></script>
|
||||||
<script type="application/ld+json">
|
<script type="application/ld+json">
|
||||||
|
@ -83,10 +81,10 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"@type": "Organization",
|
"@type": "Organization",
|
||||||
"name": "Place Atlas",
|
"name": "Place Atlas Initiative",
|
||||||
"alternateName": "r/placeatlas2",
|
"alternateName": "r/placeAtlas2023",
|
||||||
"url": "https://github.com/placeAtlas",
|
"url": "https://place-atlas.stefanocoding.me",
|
||||||
"image": "http://2022.place-atlas.stefanocoding.me/_img/logo.png",
|
"image": "https://place-atlas.stefanocoding.me/assets/logo.png",
|
||||||
"founder": {
|
"founder": {
|
||||||
"@type": "Person",
|
"@type": "Person",
|
||||||
"@id": "#Codixer",
|
"@id": "#Codixer",
|
||||||
|
@ -115,14 +113,14 @@
|
||||||
<body>
|
<body>
|
||||||
<div id="wrapper" class="listHidden">
|
<div id="wrapper" class="listHidden">
|
||||||
<header class="fixed-top">
|
<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">
|
<div class="d-flex w-100 py-2 align-items-center">
|
||||||
<i class="bi bi-info-circle-fill fs-5"></i>
|
<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>
|
<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="#headerAnnouncement" role="button" aria-expanded="false" aria-controls="headerAnnouncement"><i class="bi bi-x-lg"></i></a>
|
<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>
|
</div>
|
||||||
</aside>
|
</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">
|
<div class="container-fluid">
|
||||||
<a class="navbar-brand text-body d-flex align-items-center" href="./">
|
<a class="navbar-brand text-body d-flex align-items-center" href="./">
|
||||||
<picture>
|
<picture>
|
||||||
|
@ -135,21 +133,22 @@
|
||||||
<i class="bi bi-list" aria-hidden="true"></i>
|
<i class="bi bi-list" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="collapse navbar-collapse" id="navbarCollapse">
|
<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">
|
<li class="nav-item">
|
||||||
<div class="btn-group" role="group">
|
<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>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</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">
|
<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>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<hr class="d-md-none">
|
<hr class="d-lg-none">
|
||||||
<ul class="navbar-nav flex-row flex-wrap ms-auto">
|
<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">
|
<a class="nav-link dropdown-toggle active" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false" aria-current="page">
|
||||||
Atlas Map
|
Atlas Map
|
||||||
</a>
|
</a>
|
||||||
|
@ -159,10 +158,13 @@
|
||||||
<li><a class="dropdown-item" href="https://2023.place-atlas.stefanocoding.me/">2023</a></li>
|
<li><a class="dropdown-item" href="https://2023.place-atlas.stefanocoding.me/">2023</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</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://place-wiki.stefanocoding.me/">Place Wiki</a>
|
<a class="nav-link" href="https://place-wiki.stefanocoding.me/" target="_blank">Place Wiki</a>
|
||||||
</li>
|
</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>
|
<a class="nav-link" href="./about.html">About</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -179,8 +181,8 @@
|
||||||
<h4 class="mb-3">Hang on…</h4>
|
<h4 class="mb-3">Hang on…</h4>
|
||||||
<noscript>
|
<noscript>
|
||||||
<p>Sorry, you need JavaScript to view the Atlas.</p>
|
<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>All JS scripts on this project is under a free license.</p>
|
||||||
<p><a href="https://github.com/placeAtlas/atlas-2022">See the source on GitHub</a></p>
|
<p><a href="https://github.com/placeAtlas/atlas-2022" target="_blank">See the source on GitHub.</a></p>
|
||||||
</noscript>
|
</noscript>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -199,8 +201,7 @@
|
||||||
</header>
|
</header>
|
||||||
<div class="py-3 mx-3 border-bottom">
|
<div class="py-3 mx-3 border-bottom">
|
||||||
<div class="d-flex gap-2 mb-2">
|
<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-100" id="dropdownModes" data-bs-toggle="dropdown" aria-expanded="false">Layer Views</button>
|
||||||
<button type="button" class="btn btn-primary dropdown-toggle w-50" id="dropdownModes" data-bs-toggle="dropdown" aria-expanded="false">Modes</button>
|
|
||||||
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="dropdownModes">
|
<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="./">Normal</a></li>
|
||||||
<li><a class="dropdown-item" href="./?mode=explore">Explore</a></li>
|
<li><a class="dropdown-item" href="./?mode=explore">Explore</a></li>
|
||||||
|
@ -211,11 +212,11 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-group w-100 mb-3" role="group" aria-label="Social links and donate button">
|
<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>
|
<i class="bi bi-discord" aria-hidden="true"></i>
|
||||||
Discord
|
Discord
|
||||||
</a>
|
</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>
|
<i class="bi bi-reddit" aria-hidden="true"></i>
|
||||||
Reddit
|
Reddit
|
||||||
</a>
|
</a>
|
||||||
|
@ -272,7 +273,7 @@
|
||||||
</datalist>
|
</datalist>
|
||||||
</div>
|
</div>
|
||||||
<div id="author" class="bg-body d-flex align-items-center justify-content-center py-1 px-2 rounded shadow" style="--bs-bg-opacity: .9;">
|
<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>
|
</div>
|
||||||
<div class="offcanvas offcanvas-start bg-body" data-bs-scroll="true" data-bs-backdrop="false" tabindex="-1" id="offcanvasDraw" aria-labelledby="offcanvasDrawLabel">
|
<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
|
Redo
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</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>
|
<button type="button" class="btn btn-secondary" id="resetButton">Reset</button>
|
||||||
|
|
||||||
<div class="form-check" id="highlightUnchartedLabel">
|
<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>
|
<button type="button" class="btn btn-primary d-block mx-auto" id="periodsAdd">Add Period</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="hint">
|
<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>
|
<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>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>
|
<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>
|
<hr>
|
||||||
<div class="text-white p-3 rounded shadow" style="background-color: #5865F2;">
|
<div class="text-white p-3 rounded shadow" style="background-color: #5865F2;">
|
||||||
<h6>Need Help?</h6>
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -328,11 +329,11 @@
|
||||||
<form id="objectInfo" class="d-flex flex-column p-3 bg-secondary bg-opacity-10 rounded">
|
<form id="objectInfo" class="d-flex flex-column p-3 bg-secondary bg-opacity-10 rounded">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="nameField" class="form-label">Title</label>
|
<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>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="descriptionField" class="form-label">Description</label>
|
<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>
|
</div>
|
||||||
<label id="websiteLabel" class="form-label">Website</label>
|
<label id="websiteLabel" class="form-label">Website</label>
|
||||||
<div id="websiteGroup" class="mb-3 d-flex flex-column gap-2"></div>
|
<div id="websiteGroup" class="mb-3 d-flex flex-column gap-2"></div>
|
||||||
|
@ -370,10 +371,10 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body d-flex flex-column">
|
<div class="modal-body d-flex flex-column">
|
||||||
<p>
|
<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>
|
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>
|
<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>
|
||||||
<p>We will then check it and add it to the Atlas.</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>
|
<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">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Done</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Done</button>
|
||||||
<button id="exportCopy" type="button" class="btn btn-secondary">Copy</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="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="noopener noreferrer">Post Direct on Reddit</a>
|
<a id="exportRedditPost" class="btn btn-primary" href="#" target="_blank" rel="noreferrer">Post Direct on Reddit</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -396,21 +397,21 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p>Current 2022 Atlas Maintainers:</p>
|
<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>
|
<i class="bi bi-paypal" aria-hidden="true"></i>
|
||||||
PayPal
|
PayPal
|
||||||
</a>
|
</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>
|
<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
|
Patreon
|
||||||
</a>
|
</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>
|
<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
|
Ko-Fi
|
||||||
</a>
|
</a>
|
||||||
<hr>
|
<hr>
|
||||||
<p>Original 2017 Atlas Developer (draemmli aka Roland Rytz): </p>
|
<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>
|
<i class="bi bi-paypal" aria-hidden="true"></i>
|
||||||
PayPal
|
PayPal
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
"scope": "/",
|
"scope": "/",
|
||||||
"start_url": "/",
|
"start_url": "/",
|
||||||
"name": "The r/place Atlas",
|
"name": "The 2022 r/place Atlas",
|
||||||
"short_name": "r/placeAtlas2",
|
"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": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "./_img/pwa/logo-round-192x192.png",
|
"src": "./_img/pwa/logo-round-192x192.png",
|
||||||
|
|
19
web/sw.js
19
web/sw.js
|
@ -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');
|
importScripts('https://cdn.jsdelivr.net/npm/workbox-sw@6.5.4/build/workbox-sw.js');
|
||||||
|
|
||||||
self.addEventListener("message", event => {
|
self.addEventListener("message", event => {
|
||||||
|
@ -9,13 +7,15 @@ self.addEventListener("message", event => {
|
||||||
});
|
});
|
||||||
|
|
||||||
workbox.routing.registerRoute(
|
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({
|
new workbox.strategies.NetworkFirst({
|
||||||
cacheName: "main",
|
cacheName: "main",
|
||||||
plugins: [
|
plugins: [
|
||||||
new workbox.backgroundSync.BackgroundSyncPlugin(
|
new workbox.backgroundSync.BackgroundSyncPlugin(
|
||||||
"main-queue", {
|
"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(
|
workbox.routing.registerRoute(
|
||||||
({ url }) => url.pathname.startsWith('/_img/canvas/'),
|
({ 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({
|
new workbox.strategies.CacheFirst({
|
||||||
cacheName: "canvas",
|
cacheName: "canvas"
|
||||||
plugins: [
|
|
||||||
new workbox.backgroundSync.BackgroundSyncPlugin(
|
|
||||||
"canvas-queue", {
|
|
||||||
maxRetentionTime: 4 * 7 * 24 * 60 // 4 weeks (in minutes)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
);
|
);
|
Loading…
Reference in New Issue