Merge pull request #1092 from Hans5958/owo

Various fixes, improve script again and web
This commit is contained in:
Stefano 2022-04-09 12:20:24 +02:00 committed by GitHub
commit 75ba633f92
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 1889 additions and 2253 deletions

View file

@ -1,4 +1,4 @@
[![Entry count](https://img.shields.io/badge/dynamic/json?color=blue&label=count&query=%24.length&url=https%3A%2F%2Fgithub.com%2FplaceAtlas%2Fatlas%2Fblob%2Fmaster%2Fweb%2Fatlas.json%3Fraw%3Dtrue)](https://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%2Fblob%2Fmaster%2Fweb%2Fatlas.json%3Fraw%3Dtrue)](https://place-atlas.stefanocoding.me/)
![Commit activity](https://img.shields.io/github/commit-activity/w/placeAtlas/atlas) ![Commit activity](https://img.shields.io/github/commit-activity/w/placeAtlas/atlas)
[![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/deploys)
[![License](https://img.shields.io/github/license/placeAtlas/atlas)](https://github.com/placeAtlas/atlas/blob/master/LICENSE) [![License](https://img.shields.io/github/license/placeAtlas/atlas)](https://github.com/placeAtlas/atlas/blob/master/LICENSE)

View file

@ -35,7 +35,10 @@
} }
CL_REGEX = r'\[(.+?)\]\((.+?)\)' CL_REGEX = r'\[(.+?)\]\((.+?)\)'
CWTS_REGEX = r'^(?:(?:https?:\/\/)?(?:(?:www|old|new|np)\.)?)?reddit\.com\/r\/([A-Za-z0-9][A-Za-z0-9_]{1,20})(?:\/)$' CWTS_REGEX = {
"url": r'^(?:(?:https?:\/\/)?(?:(?:www|old|new|np)\.)?)?reddit\.com\/r\/([A-Za-z0-9][A-Za-z0-9_]{1,20})(?:\/)$',
"subreddit": r'^\/*[rR]\/([A-Za-z0-9][A-Za-z0-9_]{1,20})\/?$'
}
CSTW_REGEX = { CSTW_REGEX = {
"website": r'^https?://[^\s/$.?#].[^\s]*$', "website": r'^https?://[^\s/$.?#].[^\s]*$',
"user": r'^\/*u\/([A-Za-z0-9][A-Za-z0-9_]{1,20})$' "user": r'^\/*u\/([A-Za-z0-9][A-Za-z0-9_]{1,20})$'
@ -46,6 +49,9 @@
USER_TEMPLATE = r"/u/\1" USER_TEMPLATE = r"/u/\1"
def format_subreddit(entry: dict): def format_subreddit(entry: dict):
"""
Fix formatting of the value on "subreddit".
"""
if not "subreddit" in entry or not entry['subreddit']: if not "subreddit" in entry or not entry['subreddit']:
return entry return entry
@ -65,9 +71,7 @@ def format_subreddit(entry: dict):
return entry return entry
def collapse_links(entry: dict): def collapse_links(entry: dict):
if not "website" in entry or not entry['website']: if "website" in entry and entry['website']:
return entry
website = entry["website"]; website = entry["website"];
if re.search(CL_REGEX, website): if re.search(CL_REGEX, website):
match = re.search(CL_REGEX, website) match = re.search(CL_REGEX, website)
@ -75,9 +79,22 @@ def collapse_links(entry: dict):
website = match.group(2) website = match.group(2)
entry["website"] = website entry["website"] = website
if "subreddit" in entry and entry['subreddit']:
subreddit = entry["subreddit"];
if re.search(CL_REGEX, subreddit):
match = re.search(CL_REGEX, subreddit)
if match.group(1) == match.group(2):
subreddit = match.group(2)
entry["subreddit"] = subreddit
return entry return entry
def remove_extras(entry: dict): def remove_extras(entry: dict):
"""
Removing unnecessary extra characters and converts select characters.
"""
if "subreddit" in entry and entry["subreddit"]: if "subreddit" in entry and entry["subreddit"]:
# if not entry["subreddit"].startswith('/r/'): # if not entry["subreddit"].startswith('/r/'):
# entry["subreddit"] = re.sub(r'^(.*)(?=\/r\/)', r'', entry["subreddit"]) # entry["subreddit"] = re.sub(r'^(.*)(?=\/r\/)', r'', entry["subreddit"])
@ -94,6 +111,9 @@ def remove_extras(entry: dict):
entry[key] = re.sub(r'\n{3,}', r'\n\n', entry[key]) entry[key] = re.sub(r'\n{3,}', r'\n\n', entry[key])
entry[key] = re.sub(r'r\/{2,}', r'r\/', entry[key]) entry[key] = re.sub(r'r\/{2,}', r'r\/', entry[key])
entry[key] = re.sub(r',{2,}', r',', entry[key]) entry[key] = re.sub(r',{2,}', r',', entry[key])
# Smart quotation marks
entry[key] = re.sub(r'[\u201c\u201d]', '"', entry[key])
entry[key] = re.sub(r'[\u2018\u2019]', "'", entry[key])
# Psuedo-empty strings # Psuedo-empty strings
if entry[key] in ["n/a", "N/A", "na", "NA", "-", "null", "none", "None"]: if entry[key] in ["n/a", "N/A", "na", "NA", "-", "null", "none", "None"]:
entry[key] = "" entry[key] = ""
@ -101,6 +121,9 @@ def remove_extras(entry: dict):
return entry return entry
def fix_r_caps(entry: dict): def fix_r_caps(entry: dict):
"""
Fixes capitalization of /r/. (/R/place -> /r/place)
"""
if not "description" in entry or not entry['description']: if not "description" in entry or not entry['description']:
return entry return entry
@ -110,6 +133,9 @@ def fix_r_caps(entry: dict):
return entry return entry
def fix_no_protocol_urls(entry: dict): def fix_no_protocol_urls(entry: dict):
"""
Fixes URLs with no protocol by adding "https://" protocol.
"""
if not "website" in entry or not entry['website']: if not "website" in entry or not entry['website']:
return entry return entry
@ -119,11 +145,21 @@ def fix_no_protocol_urls(entry: dict):
return entry return entry
def convert_website_to_subreddit(entry: dict): def convert_website_to_subreddit(entry: dict):
"""
Converts the subreddit link on "website" to "subreddit" if possible.
"""
if not "website" in entry or not entry['website']: if not "website" in entry or not entry['website']:
return entry return entry
if re.match(CWTS_REGEX, entry["website"]): if re.match(CWTS_REGEX["url"], entry["website"]):
new_subreddit = re.sub(CWTS_REGEX, SUBREDDIT_TEMPLATE, entry["website"]) new_subreddit = re.sub(CWTS_REGEX["url"], SUBREDDIT_TEMPLATE, entry["website"])
if (new_subreddit.lower() == entry["subreddit"].lower()):
entry["website"] = ""
elif not "subreddit" in entry or entry['subreddit'] == "":
entry["subreddit"] = new_subreddit
entry["website"] = ""
elif re.match(CWTS_REGEX["subreddit"], entry["website"]):
new_subreddit = re.sub(CWTS_REGEX["subreddit"], SUBREDDIT_TEMPLATE, entry["website"])
if (new_subreddit.lower() == entry["subreddit"].lower()): if (new_subreddit.lower() == entry["subreddit"].lower()):
entry["website"] = "" entry["website"] = ""
elif not "subreddit" in entry or entry['subreddit'] == "": elif not "subreddit" in entry or entry['subreddit'] == "":
@ -133,6 +169,9 @@ def convert_website_to_subreddit(entry: dict):
return entry return entry
def convert_subreddit_to_website(entry: dict): def convert_subreddit_to_website(entry: dict):
"""
Converts the links on "subreddit" to a "website" if needed. This also supports Reddit users (/u/reddit).
"""
if not "subreddit" in entry or not entry['subreddit']: if not "subreddit" in entry or not entry['subreddit']:
return entry return entry
@ -150,29 +189,61 @@ def convert_subreddit_to_website(entry: dict):
return entry return entry
def validate(entry: dict): def validate(entry: dict):
"""
Validates the entry. Catch errors and tell warnings related to the entry.
Status code key:
0: All valid, no problems
1: Informational logs that may be ignored
2: Warnings that may effect user experience when interacting with the entry
3: Errors that make the entry inaccessible or broken.
"""
return_status = 0
if (not "id" in entry or (not entry['id'] and not entry['id'] == 0)): if (not "id" in entry or (not entry['id'] and not entry['id'] == 0)):
print(f"Wait, no id here! How did this happened? {entry}") print(f"Wait, no id here! How did this happened? {entry}")
return return_status = 3
entry['id'] = '[MISSING_ID]'
if not ("path" in entry and isinstance(entry["path"], list) and len(entry["path"]) > 0):
print(f"Entry {entry['id']} has no points!")
return_status = 3
elif len(entry["path"]) < 3:
print(f"Entry {entry['id']} only has {len(entry['path'])} point(s)!")
return_status = 3
for key in entry: for key in entry:
if key in VALIDATE_REGEX and not re.match(VALIDATE_REGEX[key], entry[key]): if key in VALIDATE_REGEX and not re.match(VALIDATE_REGEX[key], entry[key]):
if return_status < 2: return_status = 2
print(f"{key} of entry {entry['id']} is still invalid! {entry[key]}") print(f"{key} of entry {entry['id']} is still invalid! {entry[key]}")
return return_status
def per_line_entries(entries: list): def per_line_entries(entries: list):
"""
Returns a string of all the entries, with every entry in one line.
"""
out = "[\n" out = "[\n"
for entry in entries: for entry in entries:
out += json.dumps(entry) + ",\n" if entry:
out += json.dumps(entry, ensure_ascii=False) + ",\n"
out = out[:-2] + "\n]" out = out[:-2] + "\n]"
return out return out
def format_all(entry: dict, silent=False): def format_all(entry: dict, silent=False):
"""
Format using all the available formatters.
Outputs a tuple containing the entry and the validation status code.
Status code key:
0: All valid, no problems
1: Informational logs that may be ignored
2: Warnings that may effect user experience when interacting with the entry
3: Errors that make the entry inaccessible or broken.
"""
def print_(*args, **kwargs): def print_(*args, **kwargs):
if not silent: if not silent:
print(*args, **kwargs) print(*args, **kwargs)
print_("Fixing r/ capitalization...") print_("Fixing r/ capitalization...")
entry = fix_r_caps(entry) entry = fix_r_caps(entry)
print_("Fixing links without protocol...")
entry = fix_no_protocol_urls(entry)
print_("Fix formatting of subreddit...") print_("Fix formatting of subreddit...")
entry = format_subreddit(entry) entry = format_subreddit(entry)
print_("Collapsing Markdown links...") print_("Collapsing Markdown links...")
@ -181,12 +252,14 @@ def print_(*args, **kwargs):
entry = convert_website_to_subreddit(entry) entry = convert_website_to_subreddit(entry)
print_("Converting subreddit links to website (if needed)...") print_("Converting subreddit links to website (if needed)...")
entry = convert_subreddit_to_website(entry) entry = convert_subreddit_to_website(entry)
print_("Fixing links without protocol...")
entry = fix_no_protocol_urls(entry)
print_("Removing extras...") print_("Removing extras...")
entry = remove_extras(entry) entry = remove_extras(entry)
print_("Validating...") print_("Validating...")
validate(entry) status_code = validate(entry)
print_("Completed!") print_("Completed!")
return entry return ( entry, status_code )
if __name__ == '__main__': if __name__ == '__main__':
@ -198,7 +271,12 @@ def go(path):
entries = json.loads(f1.read()) entries = json.loads(f1.read())
for i in range(len(entries)): for i in range(len(entries)):
entries[i] = format_all(entries[i], True) entry_formatted, validation_status = format_all(entries[i], True)
if validation_status > 2:
print(f"Entry {entry_formatted['id']} will be removed! {json.dumps(entry_formatted)}")
entries[i] = None
else:
entries[i] = entry_formatted
if not (i % 500): if not (i % 500):
print(f"{i} checked.") print(f"{i} checked.")
@ -210,4 +288,3 @@ def go(path):
print("Writing completed. All done.") print("Writing completed. All done.")
go("../web/atlas.json") go("../web/atlas.json")
go("../web/atlas-before-ids-migration.json")

View file

@ -13,8 +13,8 @@
credentials = file.readlines() credentials = file.readlines()
client_id = credentials[0].strip() client_id = credentials[0].strip()
client_secret = credentials[1].strip() client_secret = credentials[1].strip()
username = credentials[2].strip() username = credentials[2].strip() if len(credentials) > 3 else ""
password = credentials[3].strip() password = credentials[3].strip() if len(credentials) > 3 else ""
reddit = praw.Reddit( reddit = praw.Reddit(
client_id=client_id, client_id=client_id,
@ -102,9 +102,6 @@ def set_flair(submission, flair):
if submission_json: if submission_json:
# Assert if path does not empty
assert len(submission_json["path"]) > 0
submission_json_dummy = {"id": submission.id, "submitted_by": ""} submission_json_dummy = {"id": submission.id, "submitted_by": ""}
try: try:
submission_json_dummy["submitted_by"] = submission.author.name submission_json_dummy["submitted_by"] = submission.author.name
@ -113,9 +110,12 @@ def set_flair(submission, flair):
for key in submission_json: for key in submission_json:
if not key in submission_json_dummy: if not key in submission_json_dummy:
submission_json_dummy[key] = submission_json[key]; submission_json_dummy[key] = submission_json[key];
submission_json = format_all(submission_json_dummy, True) (submission_json, validation_status) = format_all(submission_json_dummy, True)
outfile.write(json.dumps(submission_json) + ",\n") assert validation_status < 3, \
"Submission invalid after validation. This may be caused by not enough points on the path."
outfile.write(json.dumps(submission_json, ensure_ascii=False) + ",\n")
successcount += 1 successcount += 1
set_flair(submission, "Processed Entry") set_flair(submission, "Processed Entry")

View file

@ -1,23 +1,16 @@
<!-- <!--
======================================================================== ========================================================================
The /r/place Atlas The 2022 /r/place Atlas
An Atlas of Reddit's /r/place, with information to each An Atlas of Reddit's 2022 /r/place, with information to each
artwork of the canvas provided by the community. artwork of the canvas provided by the community.
Copyright (C) 2017 Roland Rytz <roland@draemm.li> Copyright (c) 2017 Roland Rytz <roland@draemm.li>
Licensed under the GNU Affero General Public License Version 3 Copyright (c) 2022 r/placeAtlas2 contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
For more information, see:
http://place-atlas.stefanocoding.me/license.txt
Licensed under the GNU Affero General Public License Version 3
https://place-atlas.stefanocoding.me/license.txt
======================================================================== ========================================================================
--> -->

View file

@ -1,22 +1,15 @@
/* /*
======================================================================== ========================================================================
The /r/place Atlas The 2022 /r/place Atlas
An Atlas of Reddit's /r/place, with information to each An Atlas of Reddit's 2022 /r/place, with information to each
artwork of the canvas provided by the community. artwork of the canvas provided by the community.
Copyright (C) 2017 Roland Rytz <roland@draemm.li> Copyright (c) 2017 Roland Rytz <roland@draemm.li>
Licensed under the GNU Affero General Public License Version 3 Copyright (c) 2022 r/placeAtlas2 contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
For more information, see:
https://draemm.li/various/place-atlas/license.txt
Licensed under the GNU Affero General Public License Version 3
https://place-atlas.stefanocoding.me/license.txt
======================================================================== ========================================================================
*/ */
@ -78,9 +71,7 @@ a:hover {
} }
button, button,
#exportDirectPost, .button {
#aboutBackButton,
#drawBackButton {
background-image: linear-gradient(to bottom, #888, #666); background-image: linear-gradient(to bottom, #888, #666);
border: 1px #000 solid; border: 1px #000 solid;
color: #FFF; color: #FFF;
@ -91,12 +82,15 @@ #drawBackButton {
text-shadow: 1px 1px 0 #444; text-shadow: 1px 1px 0 #444;
} }
button::-moz-focus-inner { button::-moz-focus-inner,
.button::-moz-focus-inner {
border: 0; border: 0;
} }
button:disabled, button:disabled,
button:disabled:hover { button:disabled:hover,
.button:disabled,
.button:disabled:hover {
background-image: none; background-image: none;
background-color: #666; background-color: #666;
color: #AAA; color: #AAA;
@ -104,9 +98,7 @@ button:disabled:hover {
} }
button:hover, button:hover,
#exportDirectPost:hover, .button:hover {
#aboutBackButton:hover,
#drawBackButton:hover {
background-image: linear-gradient(to bottom, #999, #777); background-image: linear-gradient(to bottom, #999, #777);
text-decoration: none; text-decoration: none;
} }
@ -257,7 +249,7 @@ #loading {
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
z-index: 100; z-index: 1000;
} }
#loading > div { #loading > div {
@ -514,7 +506,7 @@ #drawControlsContainer {
padding: 0 20px; padding: 0 20px;
} }
.draw #drawControlsContainer { [data-mode="draw"] #drawControlsContainer {
display: block; display: block;
} }
@ -616,6 +608,7 @@ .overlay {
background-color: rgba(0, 0, 0, .8); background-color: rgba(0, 0, 0, .8);
display: none; display: none;
justify-content: center; justify-content: center;
z-index: 1000;
} }
#exportWindow { #exportWindow {
@ -664,15 +657,14 @@ #coordsWrapper {
display: flex; display: flex;
gap: 10px; gap: 10px;
z-index: 100; z-index: 100;
}
.collapsed {
top: 49px;
left: 149px;
}
.uncollapsed {
top: 49px; top: 49px;
left: 380px; left: 380px;
} }
#wrapper.listHidden #coordsWrapper {
top: 49px;
left: 149px;
}
@media (max-width: 750px) { @media (max-width: 750px) {
#coordsWrapper { #coordsWrapper {
display: none; display: none;
@ -683,7 +675,6 @@ #coords {
border: 1px #000 solid; border: 1px #000 solid;
padding: 3px; padding: 3px;
font-size: 18px; font-size: 18px;
z-index: 1100;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@ -702,7 +693,6 @@ #bottomBar {
right: 10px; right: 10px;
display: flex; display: flex;
gap: 10px; gap: 10px;
z-index: 100;
} }
div:not(.listHidden) > #bottomBar { div:not(.listHidden) > #bottomBar {
@ -863,18 +853,18 @@ @media (max-width: 500px) {
height: 40px; height: 40px;
} }
#entriesListContainer > nav { #entriesListNav {
width: calc(100% - 45px); width: calc(100% - 45px);
} }
} }
@media (max-width: 350px) { @media (max-width: 350px) {
#entriesListContainer > nav > a#drawLink { #entriesListNav > a#drawLink {
display: none; display: none;
} }
} }
.draw #entriesListContainer { [data-mode="draw"] #entriesListContainer {
display: none; display: none;
} }
@ -882,55 +872,48 @@ .listHidden #entriesListContainer {
display: none; display: none;
} }
#entriesListContainer > nav { #entriesListNav {
margin: 10px 0; margin: 10px 0;
display: flex; display: flex;
flex-shrink: 0; flex-shrink: 0;
justify-content: center; justify-content: center;
} }
#entriesListContainer > nav > a, #entriesListNav > * {
#entriesListContainer > nav > button {
background-image: linear-gradient(to bottom, #888, #666);
border: 1px #000 solid;
color: #FFF;
text-align: center;
display: block; display: block;
padding: 4px;
cursor: pointer; cursor: pointer;
width: 120px; width: 120px;
height: 30px; height: 30px;
margin-right: 10px; margin-right: 10px;
text-shadow: 1px 1px 0 #444;
} }
#entriesListContainer > nav > button { #entriesListNav > .small {
width: 30px; width: 30px;
padding: 2px; padding: 2px;
flex-shrink: 0; flex-shrink: 0;
} }
#entriesListContainer > nav > button > img { #entriesListNav > .small > img {
height: 22px; height: 22px;
width: 22px; width: 22px;
} }
#entriesListContainer > nav > button:last-child { #entriesListNav > .small:last-child {
margin-right: 0; margin-right: 0;
} }
#entriesListContainer > nav > a:hover { #entriesListNav > a:hover {
text-decoration: none; text-decoration: none;
background-image: linear-gradient(to bottom, #999, #777); background-image: linear-gradient(to bottom, #999, #777);
} }
#entriesListContainer > nav > button:hover { #entriesListNav > .small:hover {
background-image: none; background-image: none;
background: transparent; background: transparent;
border-color: transparent; border-color: transparent;
} }
#entriesListContainer > nav > button:hover > img { #entriesListDonate:hover > img {
text-decoration: none; text-decoration: none;
background-image: linear-gradient(to bottom, #FFAA00, #FFAA00); background-image: linear-gradient(to bottom, #FFAA00, #FFAA00);
border-radius: 15px; border-radius: 15px;
@ -939,7 +922,7 @@ #entriesListContainer > nav > button:hover > img {
height: 28px; height: 28px;
width: 28px; width: 28px;
} }
#entriesListContainer > nav > button:hover > img.Discord { #entriesListDiscord:hover > img {
text-decoration: none; text-decoration: none;
background-image: linear-gradient(to bottom, #7289DA, #7289DA); background-image: linear-gradient(to bottom, #7289DA, #7289DA);
border-radius: 12px; border-radius: 12px;
@ -955,12 +938,12 @@ #entriesListBackground {
top: 50px; top: 50px;
bottom: 0; bottom: 0;
width: 360px; width: 360px;
z-index: -600; z-index: -400;
background-color: #333; background-color: #333;
border-right: 1px #000 solid; border-right: 1px #000 solid;
} }
.draw #entriesListBackground { [data-mode="draw"] #entriesListBackground {
display: none; display: none;
} }
@ -994,7 +977,7 @@ #hideListButton:hover {
background-color: #555; background-color: #555;
} }
.draw #hideListButton { [data-mode="draw"] #hideListButton {
display: none; display: none;
} }
@ -1029,6 +1012,10 @@ #entriesListControls input:focus {
border-color: #CCC; border-color: #CCC;
} }
[data-mode="explore"] #entriesListControls {
display: none;
}
#atlasSize { #atlasSize {
display: block; display: block;
margin: 3px 0 5px 0; margin: 3px 0 5px 0;
@ -1080,7 +1067,7 @@ #aboutContainer {
} }
#aboutBackButton { #aboutBackButton {
margin: 20px 20px 0 20px; margin: 20px 0 20px;
padding: 10px 20px; padding: 10px 20px;
} }
@ -1124,11 +1111,10 @@ #contributors a {
line-height: 26px; line-height: 26px;
} }
#bitcoinButton { #donateButton {
cursor: pointer; cursor: pointer;
} }
#bitcoinWindow,
#donateWindow { #donateWindow {
display: inline-block; display: inline-block;
z-index: 2000; z-index: 2000;
@ -1150,10 +1136,6 @@ #donateWindow {
max-width: 800px; max-width: 800px;
} }
#donateWindow > #bitcoinQR {
}
#donateWindow > p { #donateWindow > p {
margin: 2px 0; margin: 2px 0;
padding: 0 20px; padding: 0 20px;
@ -1161,13 +1143,11 @@ #donateWindow > p {
width: 100%; width: 100%;
} }
#bitcoinWindow > *,
#donateWindow > * { #donateWindow > * {
display: inline-block; display: inline-block;
margin: 5px 0; margin: 5px 0;
} }
#bitcoinWindow > h2,
#donateWindow > h2 { #donateWindow > h2 {
font-weight: 200; font-weight: 200;
background-color: #555; background-color: #555;
@ -1177,7 +1157,6 @@ #donateWindow > h2 {
text-shadow: 1px 1px 0 #000; text-shadow: 1px 1px 0 #000;
} }
#bitcoinWindow input,
#donateWindow input { #donateWindow input {
width: 100%; width: 100%;
max-width: 350px; max-width: 350px;
@ -1188,7 +1167,6 @@ #donateWindow input {
color: #FFF; color: #FFF;
} }
#bitcoinWindow button,
#donateWindow button { #donateWindow button {
padding: 10px 20px; padding: 10px 20px;
margin-bottom: 20px; margin-bottom: 20px;
@ -1201,7 +1179,68 @@ h2#abouth2 {
text-shadow: 2px 2px 0 #000; text-shadow: 2px 2px 0 #000;
} }
#bitcoinNotice { #viewModes {
color: #AAA; position: relative;
margin-top: 7px; display: inline-block;
}
#viewModes .buffer {
bottom: -10px;
left: 0;
position: absolute;
height: 20px;
width: 100%
}
#viewModes .dropdown-content {
margin-top: 1.5rem;
top: 10px;
left: 0;
position: absolute;
display: none;
background: #666;
border: 1px #000 solid;
cursor: pointer;
width: 125%
}
#viewModes .dropdown-content a {
color: #FFF;
text-align: left;
padding: 5px 10px;
display: block;
text-decoration: none;
text-shadow: 1px 1px 0 #444;
}
#viewModes .dropdown-content a:hover {
background-image: linear-gradient(to bottom, #999, #777);
}
#viewModes:hover .dropdown-content,
#viewModes:active .dropdown-content {
display: block;
}
body:not([data-dev]) .show-only-on-dev {
display: none !important;
}
#netlifyBadges {
display: flex;
align-items: center;
gap: .5rem
}
#donateWindow a.button {
padding: 1rem
}
#donateWindow a.button svg {
height: 1em;
vertical-align: -0.125em;
}
#donateWindow a.button path {
color: white;
} }

View file

@ -1,22 +1,15 @@
/* /*
======================================================================== ========================================================================
The /r/place Atlas The 2022 /r/place Atlas
An Atlas of Reddit's /r/place, with information to each An Atlas of Reddit's 2022 /r/place, with information to each
artwork of the canvas provided by the community. artwork of the canvas provided by the community.
Copyright (C) 2017 Roland Rytz <roland@draemm.li> Copyright (c) 2017 Roland Rytz <roland@draemm.li>
Licensed under the GNU Affero General Public License Version 3 Copyright (c) 2022 r/placeAtlas2 contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
For more information, see:
http://place-atlas.stefanocoding.me/license.txt
Licensed under the GNU Affero General Public License Version 3
https://place-atlas.stefanocoding.me/license.txt
======================================================================== ========================================================================
*/ */
@ -25,7 +18,7 @@ window.addEventListener("error", function (e) {
var errorMessage = "<p class=\"error\">An error has occurred:</p>"; var errorMessage = "<p class=\"error\">An error has occurred:</p>";
errorMessage += "<p class=\"errorBody\">" + e.message + "</p>"; errorMessage += "<p class=\"errorBody\">" + e.message + "</p>";
errorMessage += "<p class=\"errorBody\">on line " + e.lineno + "</p>"; errorMessage += "<p class=\"errorBody\">on line " + e.lineno + "</p>";
errorMessage += "<p class=\"error\">If this keeps happening, feel free to send me a <a href=\"mailto:roland.rytz@gmail.com\">mail</a>.</p>"; errorMessage += "<p class=\"error\">If this keeps happening, feel free to tell us on <a href=\"https://discord.gg/pJkm23b2nA\">our Discord server</a>.</p>";
document.getElementById("loadingContent").innerHTML = errorMessage; document.getElementById("loadingContent").innerHTML = errorMessage;
}); });

View file

@ -1,32 +1,26 @@
/* /*
======================================================================== ========================================================================
The /r/place Atlas The 2022 /r/place Atlas
An Atlas of Reddit's /r/place, with information to each An Atlas of Reddit's 2022 /r/place, with information to each
artwork of the canvas provided by the community. artwork of the canvas provided by the community.
Copyright (C) 2017 Roland Rytz <roland@draemm.li> Copyright (c) 2017 Roland Rytz <roland@draemm.li>
Licensed under the GNU Affero General Public License Version 3 Copyright (c) 2022 r/placeAtlas2 contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
For more information, see:
http://place-atlas.stefanocoding.me/license.txt
Licensed under the GNU Affero General Public License Version 3
https://place-atlas.stefanocoding.me/license.txt
======================================================================== ========================================================================
*/ */
function initDraw(){ function initDraw(){
wrapper.classList.remove('listHidden')
window.render = render
window.renderBackground = renderBackground
window.updateHovering = updateHovering
var finishButton = document.getElementById("finishButton"); var finishButton = document.getElementById("finishButton");
var resetButton = document.getElementById("resetButton"); var resetButton = document.getElementById("resetButton");
var undoButton = document.getElementById("undoButton"); var undoButton = document.getElementById("undoButton");
@ -46,14 +40,10 @@ function initDraw(){
var lShiftPressed = false; var lShiftPressed = false;
var shiftPressed = false; var shiftPressed = false;
var backgroundCanvas = document.createElement("canvas");
backgroundCanvas.width = 2000;
backgroundCanvas.height = 2000;
var backgroundContext = backgroundCanvas.getContext("2d");
var highlightUncharted = true; var highlightUncharted = true;
renderBackground(); renderBackground();
applyView();
container.style.cursor = "crosshair"; container.style.cursor = "crosshair";
@ -62,8 +52,6 @@ function initDraw(){
var undoHistory = []; var undoHistory = [];
var lastPos = [0, 0];
render(path); render(path);
container.addEventListener("mousedown", function(e){ container.addEventListener("mousedown", function(e){
@ -119,6 +107,8 @@ function initDraw(){
if(!dragging && drawing && path.length > 0){ if(!dragging && drawing && path.length > 0){
console.log(123)
var coords = getCanvasCoords(e.clientX, e.clientY); var coords = getCanvasCoords(e.clientX, e.clientY);
render(path.concat([coords])); render(path.concat([coords]));
} }
@ -390,6 +380,18 @@ function initDraw(){
} }
function updateHovering(e, tapped){
if(!dragging && (!fixed || tapped)){
var pos = [
(e.clientX - (container.clientWidth/2 - innerContainer.clientWidth/2 + zoomOrigin[0] + container.offsetLeft))/zoom
,(e.clientY - (container.clientHeight/2 - innerContainer.clientHeight/2 + zoomOrigin[1] + container.offsetTop))/zoom
];
var coords_p = document.getElementById("coords_p");
coords_p.innerText = Math.ceil(pos[0]) + ", " + Math.ceil(pos[1]);
}
}
} }

View file

@ -1,3 +1,18 @@
/*
========================================================================
The 2022 /r/place Atlas
An Atlas of Reddit's 2022 /r/place, with information to each
artwork of the canvas provided by the community.
Copyright (c) 2017 Roland Rytz <roland@draemm.li>
Copyright (c) 2022 r/placeAtlas2 contributors
Licensed under the GNU Affero General Public License Version 3
https://place-atlas.stefanocoding.me/license.txt
========================================================================
*/
function createInfoBlock(entry) { function createInfoBlock(entry) {
function createInfoParagraph(name, value){ function createInfoParagraph(name, value){
let entryParagraphPositionElement = document.createElement("p"); let entryParagraphPositionElement = document.createElement("p");
@ -35,7 +50,7 @@ function createInfoBlock(entry) {
} }
let [x, y] = entry.center; let [x, y] = entry.center;
element.appendChild(createInfoParagraph("Position: ", `${Math.floor(x)}x${Math.floor(y)}`)); element.appendChild(createInfoParagraph("Position: ", `${Math.floor(x)}, ${Math.floor(y)}`));
if(entry.path){ if(entry.path){
let area = calcPolygonArea(entry.path); let area = calcPolygonArea(entry.path);

View file

@ -1,28 +1,19 @@
/* /*
======================================================================== ========================================================================
The /r/place Atlas The 2022 /r/place Atlas
An Atlas of Reddit's /r/place, with information to each An Atlas of Reddit's 2022 /r/place, with information to each
artwork of the canvas provided by the community. artwork of the canvas provided by the community.
Copyright (C) 2017 Roland Rytz <roland@draemm.li> Copyright (c) 2017 Roland Rytz <roland@draemm.li>
Licensed under the GNU Affero General Public License Version 3 Copyright (c) 2022 r/placeAtlas2 contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
For more information, see:
http://place-atlas.stefanocoding.me/license.txt
Licensed under the GNU Affero General Public License Version 3
https://place-atlas.stefanocoding.me/license.txt
======================================================================== ========================================================================
*/ */
const prodDomain = "place-atlas.stefanocoding.me"
var innerContainer = document.getElementById("innerContainer"); var innerContainer = document.getElementById("innerContainer");
var container = document.getElementById("container"); var container = document.getElementById("container");
@ -46,12 +37,11 @@ var lastPosition = [0, 0];
var viewportSize = [0, 0]; var viewportSize = [0, 0];
document.getElementById("donateButton").addEventListener("click", function(e){ document.getElementById("entriesListDonate").addEventListener("click", function(e){
// document.getElementById("bitcoinQR").src = "./_img/bitcoinQR.png?from=index";
document.getElementById("donateOverlay").style.display = "flex"; document.getElementById("donateOverlay").style.display = "flex";
}); });
document.getElementById("closeBitcoinButton").addEventListener("click", function(e){ document.getElementById("closeDonateButton").addEventListener("click", function(e){
document.getElementById("donateOverlay").style.display = "none"; document.getElementById("donateOverlay").style.display = "none";
}); });
@ -75,6 +65,8 @@ function applyView(){
var atlas = null; var atlas = null;
if (document.location.host !== prodDomain) document.body.dataset.dev = ""
init(); init();
async function init(){ async function init(){
@ -120,25 +112,20 @@ async function init(){
} }
} }
if(mode == "view"){ document.body.dataset.mode = mode
wrapper.className = wrapper.className.replace(/ drawMode/g, ""); initGlobal()
initView(); if (mode !== "draw") initViewGlobal()
} else if(mode=="draw"){ if(mode === "draw"){
wrapper.className += " draw";
initDraw(); initDraw();
} else if(mode === "about"){
} else if(mode=="about"){
window.location = "./about.html"; window.location = "./about.html";
} else if(mode=="overlap"){ } else if(mode === "overlap"){
wrapper.className = wrapper.className.replace(/ drawMode/g, "");
if(initOverlap){ if(initOverlap){
initOverlap(); initOverlap();
} }
} else if(mode.startsWith("diff")){ } else if(mode.startsWith("diff")){
wrapper.className = wrapper.className.replace(/ drawMode/g, "");
try { try {
let liveResp = await fetch("https://place-atlas.stefanocoding.me/atlas.json"); let liveResp = await fetch("https://place-atlas.stefanocoding.me/atlas.json");
let liveJson = await liveResp.json(); let liveJson = await liveResp.json();
@ -161,12 +148,12 @@ async function init(){
a[c.id] = c; a[c.id] = c;
return a; return a;
},{}); },{});
let removedEntries = liveJson.map(function(entry) { let removedEntries = liveJson.filter(entry =>
if(atlasReduced[entry.id] === undefined){ atlasReduced[entry.id] === undefined
entry.diff = "delete"; ).map(entry => {
} entry.diff = "delete"
return entry; return entry
}); })
atlas.push(...removedEntries) atlas.push(...removedEntries)
if(mode.includes("only")){ if(mode.includes("only")){
@ -174,11 +161,10 @@ async function init(){
return typeof entry.diff == "string" return typeof entry.diff == "string"
}); });
} }
//TEMP FOR TIME TRAVEL //TEMP FOR TIME TRAVEL
atlasBackup = atlas; atlasBackup = atlas;
} catch (error) { } catch (error) {
console.log("Diff mode failed to load, reverting to normal view - " + error); console.warn("Diff mode failed to load, reverting to normal view.", error);
} finally { } finally {
if(initOverlap && mode.includes("overlap")){ if(initOverlap && mode.includes("overlap")){
initOverlap(); initOverlap();
@ -186,35 +172,12 @@ async function init(){
initView(); initView();
} }
} }
} else if(mode === "explore"){
initExplore();
} else {
initView();
} }
function changeOverlapMode(){
console.log(mode)
switch(mode){
case "overlap":
window.location.href = "?mode=explore"
break;
case "explore":
window.location.href = "?"
break;
default:
window.location.href = "?mode=overlap"
break;
}
return false;
}
const modeMap = {
"view": "Overlap",
"overlap": "Explore",
"explore": "Atlas"
}
const toggleMode = document.getElementById("toggleMode");
toggleMode.onclick = changeOverlapMode;
toggleMode.innerHTML = modeMap[mode] || "Overlap";
document.getElementById("loading").style.display = "none"; document.getElementById("loading").style.display = "none";
document.getElementById("zoomInButton").addEventListener("click", function(e){ document.getElementById("zoomInButton").addEventListener("click", function(e){

View file

@ -1,93 +1,32 @@
/* /*
======================================================================== ========================================================================
The /r/place Atlas The 2022 /r/place Atlas
An Atlas of Reddit's /r/place, with information to each An Atlas of Reddit's 2022 /r/place, with information to each
artwork of the canvas provided by the community. artwork of the canvas provided by the community.
Copyright (C) 2017 Roland Rytz <roland@draemm.li> Copyright (c) 2017 Roland Rytz <roland@draemm.li>
Licensed under the GNU Affero General Public License Version 3 Copyright (c) 2022 r/placeAtlas2 contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
For more information, see:
http://place-atlas.stefanocoding.me/license.txt
Licensed under the GNU Affero General Public License Version 3
https://place-atlas.stefanocoding.me/license.txt
======================================================================== ========================================================================
*/ */
function initOverlap(){ function initOverlap(){
var wrapper = document.getElementById("wrapper"); window.renderBackground = renderBackground
var objectsContainer = document.getElementById("objectsList");
var linesCanvas = document.getElementById("linesCanvas");
var linesContext = linesCanvas.getContext("2d");
var backgroundCanvas = document.createElement("canvas");
backgroundCanvas.width = 2000;
backgroundCanvas.height = 2000;
var backgroundContext = backgroundCanvas.getContext("2d");
var filterInput = document.getElementById("searchList");
var entriesList = document.getElementById("entriesList");
var hideListButton = document.getElementById("hideListButton");
var entriesListShown = true;
var entriesLimit = 50;
var entriesOffset = 0;
var moreEntriesButton = document.createElement("button");
moreEntriesButton.innerHTML = "Show "+entriesLimit+" more";
moreEntriesButton.id = "moreEntriesButton";
moreEntriesButton.onclick = function(){
buildObjectsList();
};
var viewportWidth = document.documentElement.clientWidth;
var hovered = []; var hovered = [];
var lastPos = [0, 0]; buildObjectsList(null, null);
renderBackground(atlas);
var fixed = false; // Fix hovered items in place, so that clicking on links is possible
renderBackground();
render(); render();
buildObjectsList();
// parse linked atlas entry id from link hash
/*if (window.location.hash.substring(3)){
zoom = 4;
applyView();
highlightEntryFromUrl();
}*/
if(document.documentElement.clientWidth > 2000){
entriesListShown = true;
wrapper.className = wrapper.className.replace(/ listHidden/g, "");
}
if(document.documentElement.clientWidth < 2000){
entriesListShown = false;
wrapper.className += " listHidden";
}
applyView(); applyView();
render(); render();
updateLines(); updateLines();
var args = window.location.search; var args = window.location.search;
if(args){ if(args){
id = args.split("id=")[1]; id = args.split("id=")[1];
@ -96,138 +35,7 @@ function initOverlap(){
} }
} }
container.addEventListener("mousemove", function(e){ function renderBackground(atlas) {
updateHovering(e);
});
filterInput.addEventListener("input", function(e){
entriesOffset = 0;
entriesList.innerHTML = "";
entriesList.appendChild(moreEntriesButton);
buildObjectsList(this.value.toLowerCase());
});
document.getElementById("sort").addEventListener("input", function(e){
entriesOffset = 0;
entriesList.innerHTML = "";
entriesList.appendChild(moreEntriesButton);
buildObjectsList(filterInput.value.toLowerCase());
});
hideListButton.addEventListener("click", function(e){
entriesListShown = !entriesListShown;
if(entriesListShown){
wrapper.className = wrapper.className.replace(/ listHidden/g, "");
} else {
wrapper.className += " listHidden";
}
applyView();
updateHovering(e);
render();
updateLines();
});
function highlightEntryFromUrl(){
var objectsContainer = document.getElementById("objectsList");
var id = 0;
var args = window.location.search;
if(args){
id = args.split("id=")[1];
if(id){
id = id.split("&")[0];
}
}
//var id = parseInt(window.location.hash.substring(3));
var entry = atlas.filter(function(e){
return e.id === id;
});
if (entry.length === 1){
entry = entry[0];
var infoElement = createInfoBlock(entry);
objectsContainer.innerHTML = "";
objectsContainer.appendChild(infoElement);
//console.log(entry.center[0]);
//console.log(entry.center[1]);
zoom = 4;
applyView();
zoomOrigin = [
innerContainer.clientWidth/2 - entry.center[0]* zoom// + container.offsetLeft
,innerContainer.clientHeight/2 - entry.center[1]* zoom// + container.offsetTop
];
//console.log(zoomOrigin);
applyView();
hovered = [entry];
render();
hovered[0].element = infoElement;
updateLines();
fixed = true;
}
}
function updateHovering(e){
if(!dragging && !fixed){
var pos = [
(e.clientX - (container.clientWidth/2 - innerContainer.clientWidth/2 + zoomOrigin[0] + container.offsetLeft))/zoom
,(e.clientY - (container.clientHeight/2 - innerContainer.clientHeight/2 + zoomOrigin[1] + container.offsetTop))/zoom
];
if(pos[0] <= 2200 && pos[0] >= -100 && pos[0] <= 2200 && pos[0] >= -100){
var newHovered = [];
for(var i = 0; i < atlas.length; i++){
if(pointIsInPolygon(pos, atlas[i].path)){
newHovered.push(atlas[i]);
}
}
var changed = false;
if(hovered.length == newHovered.length){
for(var i = 0; i < hovered.length; i++){
if(hovered[i].id != newHovered[i].id){
changed = true;
break;
}
}
} else {
changed = true;
}
if(changed){
hovered = newHovered;
objectsContainer.innerHTML = "";
for(var i in hovered){
var element = createInfoBlock(hovered[i]);
objectsContainer.appendChild(element);
hovered[i].element = element;
}
render();
}
}
}
}
function renderBackground(){
backgroundContext.clearRect(0, 0, canvas.width, canvas.height); backgroundContext.clearRect(0, 0, canvas.width, canvas.height);
@ -266,277 +74,4 @@ function initOverlap(){
console.log(blank+" blank pixels, which are "+Math.round(blank/100)/100+"% of the canvas ("+(100-Math.round(blank/100)/100)+"% mapped)"); console.log(blank+" blank pixels, which are "+Math.round(blank/100)/100+"% of the canvas ("+(100-Math.round(blank/100)/100)+"% mapped)");
} }
function buildObjectsList(filter){
if(entriesList.contains(moreEntriesButton)){
entriesList.removeChild(moreEntriesButton);
}
var sortedAtlas;
if(filter){
sortedAtlas = atlas.filter(function(value){
return (value.name.toLowerCase().indexOf(filter) !== -1);
});
document.getElementById("atlasSize").innerHTML = "Found "+sortedAtlas.length+" entries.";
} else {
sortedAtlas = atlas.concat();
document.getElementById("atlasSize").innerHTML = "The Atlas contains "+sortedAtlas.length+" entries.";
}
var sort = document.getElementById("sort").value;
var sortFunction;
//console.log(sort);
switch(sort){
case "alphaAsc":
sortFunction = function(a, b){
return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
}
break;
case "alphaDesc":
sortFunction = function(a, b){
return b.name.toLowerCase().localeCompare(a.name.toLowerCase());
}
break;
case "newest":
sortFunction = function(a, b){
if (a.id > b.id) {
return -1;
}
if (a.id < b.id) {
return 1;
}
// a must be equal to b
return 0;
}
break;
case "oldest":
sortFunction = function(a, b){
if (a.id < b.id) {
return -1;
}
if (a.id > b.id) {
return 1;
}
// a must be equal to b
return 0;
}
break;
}
sortedAtlas.sort(sortFunction);
for(var i = entriesOffset; i < entriesOffset+entriesLimit; i++){
if(i >= sortedAtlas.length){
break;
}
var element = createInfoBlock(sortedAtlas[i]);
element.entry = sortedAtlas[i];
element.addEventListener("mouseenter", function(e){
if(!fixed && !dragging){
objectsContainer.innerHTML = "";
zoomOrigin = [
innerContainer.clientWidth/2 - this.entry.center[0]* zoom// + container.offsetLeft
,innerContainer.clientHeight/2 - this.entry.center[1]* zoom// + container.offsetTop
]
//console.log(zoomOrigin);
applyView();
hovered = [this.entry];
render();
hovered[0].element = this;
updateLines();
}
});
element.addEventListener("mouseleave", function(e){
if(!fixed && !dragging){
hovered = [];
updateLines();
render();
}
});
entriesList.appendChild(element);
}
entriesOffset += entriesLimit;
if(sortedAtlas.length > entriesOffset){
moreEntriesButton.innerHTML = "Show "+Math.min(entriesLimit, sortedAtlas.length - entriesOffset)+" more";
entriesList.appendChild(moreEntriesButton);
}
}
function render(){
context.globalCompositeOperation = "source-over";
context.clearRect(0, 0, canvas.width, canvas.height);
if(hovered.length > 0){
container.style.cursor = "pointer";
} else {
container.style.cursor = "default";
}
for(var i = 0; i < hovered.length; i++){
var path = hovered[i].path;
context.beginPath();
if(path[0]){
context.moveTo(path[0][0], path[0][1]);
}
for(var p = 1; p < path.length; p++){
context.lineTo(path[p][0], path[p][1]);
}
context.closePath();
context.globalCompositeOperation = "source-over";
context.fillStyle = "rgba(0, 0, 0, 1)";
context.fill();
}
context.globalCompositeOperation = "source-out";
context.drawImage(backgroundCanvas, 0, 0);
for(var i = 0; i < hovered.length; i++){
var path = hovered[i].path;
context.beginPath();
if(path[0]){
context.moveTo(path[0][0], path[0][1]);
}
for(var p = 1; p < path.length; p++){
context.lineTo(path[p][0], path[p][1]);
}
context.closePath();
context.globalCompositeOperation = "source-over";
context.strokeStyle = "rgba(0, 0, 0, 1)";
context.stroke();
}
}
function toggleFixed(e){
if(!fixed && hovered.length == 0){
return 0;
}
fixed = !fixed;
if(!fixed){
updateHovering(e);
render();
}
}
function updateLines(){
linesCanvas.width = linesCanvas.clientWidth;
linesCanvas.height = linesCanvas.clientHeight;
linesContext.lineCap = "round";
linesContext.lineWidth = Math.max(Math.min(zoom*1.5, 16*1.5), 6);
linesContext.strokeStyle = "#000000";
for(var i = 0; i < hovered.length; i++){
var element = hovered[i].element;
linesContext.beginPath();
//linesContext.moveTo(element.offsetLeft + element.clientWidth - 10, element.offsetTop + 20);
linesContext.moveTo(
element.getBoundingClientRect().left + document.documentElement.scrollLeft + element.clientWidth/2
,element.getBoundingClientRect().top + document.documentElement.scrollTop + 20
);
linesContext.lineTo(
~~(hovered[i].center[0]*zoom) + innerContainer.offsetLeft
,~~(hovered[i].center[1]*zoom) + innerContainer.offsetTop
);
linesContext.stroke();
}
linesContext.lineWidth = Math.max(Math.min(zoom, 16), 4);
linesContext.strokeStyle = "#FFFFFF";
for(var i = 0; i < hovered.length; i++){
var element = hovered[i].element;
linesContext.beginPath();
linesContext.moveTo(
element.getBoundingClientRect().left + document.documentElement.scrollLeft + element.clientWidth/2
,element.getBoundingClientRect().top + document.documentElement.scrollTop + 20
);
linesContext.lineTo(
~~(hovered[i].center[0]*zoom) + innerContainer.offsetLeft
,~~(hovered[i].center[1]*zoom) + innerContainer.offsetTop
);
linesContext.stroke();
}
}
window.addEventListener("resize", updateLines);
window.addEventListener("mousemove", updateLines);
window.addEventListener("dblClick", updateLines);
window.addEventListener("wheel", updateLines);
container.addEventListener("mousedown", function(e){
lastPos = [
e.clientX
,e.clientY
];
});
container.addEventListener("mouseup", function(e){
if(Math.abs(lastPos[0] - e.clientX) + Math.abs(lastPos[1] - e.clientY) <= 4){
toggleFixed(e);
}
});
objectsContainer.addEventListener("scroll", function(e){
updateLines();
});
window.addEventListener("resize", function(){
//console.log(document.documentElement.clientWidth, document.documentElement.clientHeight);
if(document.documentElement.clientWidth > 2000 && viewportWidth <= 2000){
entriesListShown = true;
wrapper.className = wrapper.className.replace(/ listHidden/g, "");
}
if(document.documentElement.clientWidth < 2000 && viewportWidth >= 2000){
entriesListShown = false;
wrapper.className += " listHidden";
}
viewportWidth = document.documentElement.clientWidth;
applyView();
render();
updateLines();
});
} }

View file

@ -24,9 +24,6 @@ SOFTWARE.
*/ */
function pointIsInPolygon (point, polygon) { function pointIsInPolygon (point, polygon) {
// ray-casting algorithm based on // ray-casting algorithm based on
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html

View file

@ -1,3 +1,17 @@
/*
========================================================================
The 2022 /r/place Atlas
An Atlas of Reddit's 2022 /r/place, with information to each
artwork of the canvas provided by the community.
Copyright (c) 2017 Roland Rytz <roland@draemm.li>
Copyright (c) 2022 r/placeAtlas2 contributors
Licensed under the GNU Affero General Public License Version 3
https://place-atlas.stefanocoding.me/license.txt
========================================================================
*/
var areasSum = 0; var areasSum = 0;
var areas = []; var areas = [];

View file

@ -1,3 +1,18 @@
/*
========================================================================
The 2022 /r/place Atlas
An Atlas of Reddit's 2022 /r/place, with information to each
artwork of the canvas provided by the community.
Copyright (c) 2017 Roland Rytz <roland@draemm.li>
Copyright (c) 2022 r/placeAtlas2 contributors
Licensed under the GNU Affero General Public License Version 3
https://place-atlas.stefanocoding.me/license.txt
========================================================================
*/
const timeConfig = [ const timeConfig = [
{ {
timestamp: 1648822500, timestamp: 1648822500,

View file

@ -1,27 +1,18 @@
/* /*
======================================================================== ========================================================================
The /r/place Atlas The 2022 /r/place Atlas
An Atlas of Reddit's /r/place, with information to each An Atlas of Reddit's 2022 /r/place, with information to each
artwork of the canvas provided by the community. artwork of the canvas provided by the community.
Copyright (C) 2017 Roland Rytz <roland@draemm.li> Copyright (c) 2017 Roland Rytz <roland@draemm.li>
Licensed under the GNU Affero General Public License Version 3 Copyright (c) 2022 r/placeAtlas2 contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
For more information, see:
http://place-atlas.stefanocoding.me/license.txt
Licensed under the GNU Affero General Public License Version 3
https://place-atlas.stefanocoding.me/license.txt
======================================================================== ========================================================================
*/ */
var linesCanvas = document.getElementById("linesCanvas"); var linesCanvas = document.getElementById("linesCanvas");
var linesContext = linesCanvas.getContext("2d"); var linesContext = linesCanvas.getContext("2d");
var hovered = []; var hovered = [];
@ -34,7 +25,147 @@ backgroundCanvas.width = 2000;
backgroundCanvas.height = 2000; backgroundCanvas.height = 2000;
var backgroundContext = backgroundCanvas.getContext("2d"); var backgroundContext = backgroundCanvas.getContext("2d");
var wrapper = document.getElementById("wrapper");
var objectsContainer = document.getElementById("objectsList");
var closeObjectsListButton = document.getElementById("closeObjectsListButton");
var filterInput = document.getElementById("searchList");
var entriesList = document.getElementById("entriesList");
var hideListButton = document.getElementById("hideListButton");
var entriesListShown = false;
var sortedAtlas;
var entriesLimit = 50;
var entriesOffset = 0;
var moreEntriesButton = document.createElement("button");
moreEntriesButton.innerHTML = "Show "+entriesLimit+" more";
moreEntriesButton.id = "moreEntriesButton";
moreEntriesButton.onclick = function(){
buildObjectsList(null, null);
renderBackground();
render();
};
var defaultSort = "shuffle";
document.getElementById("sort").value = defaultSort;
var lastPos = [0, 0];
var fixed = false; // Fix hovered items in place, so that clicking on links is possible
if(document.documentElement.clientWidth > 2000){
entriesListShown = true;
wrapper.classList.remove('listHidden')
}
if(document.documentElement.clientWidth < 2000){
entriesListShown = false;
wrapper.classList.add('listHidden')
}
filterInput.addEventListener("input", function(e){
entriesOffset = 0;
entriesList.innerHTML = "";
entriesList.appendChild(moreEntriesButton);
if(this.value === ""){
document.getElementById("relevantOption").disabled = true;
sortedAtlas = atlas.concat();
buildObjectsList(null, null);
} else {
document.getElementById("relevantOption").disabled = false;
buildObjectsList(this.value.toLowerCase(), "relevant");
}
});
document.getElementById("sort").addEventListener("input", function(e){
entriesOffset = 0;
entriesList.innerHTML = "";
entriesList.appendChild(moreEntriesButton);
if(this.value != "relevant"){
defaultSort = this.value;
}
buildObjectsList(filterInput.value.toLowerCase(), this.value);
});
hideListButton.addEventListener("click", function(e){
entriesListShown = !entriesListShown;
if(entriesListShown){
wrapper.classList.remove('listHidden')
} else {
wrapper.classList.add('listHidden')
}
updateHovering();
applyView();
render();
updateLines();
return false;
});
closeObjectsListButton.addEventListener("click", function(e){
hovered = [];
objectsContainer.innerHTML = "";
updateLines();
closeObjectsListButton.className = "hidden";
fixed = false;
render();
});
function toggleFixed(e, tapped){
if(!fixed && hovered.length == 0){
return 0;
}
fixed = !fixed;
if(!fixed){
updateHovering(e, tapped);
render();
}
}
window.addEventListener("resize", updateLines);
window.addEventListener("mousemove", updateLines);
window.addEventListener("dblClick", updateLines);
window.addEventListener("wheel", updateLines);
objectsContainer.addEventListener("scroll", function(e){
updateLines();
});
window.addEventListener("resize", function(){
//console.log(document.documentElement.clientWidth, document.documentElement.clientHeight);
var viewportWidth = document.documentElement.clientWidth;
if(document.documentElement.clientWidth > 2000 && viewportWidth <= 2000){
entriesListShown = true;
wrapper.className = wrapper.className.replace(/ listHidden/g, "");
}
if(document.documentElement.clientWidth < 2000 && viewportWidth >= 2000){
entriesListShown = false;
wrapper.className += " listHidden";
}
updateHovering();
viewportWidth = document.documentElement.clientWidth;
applyView();
render();
updateLines();
});
function updateLines(){ function updateLines(){
console.log(8)
linesCanvas.width = linesCanvas.clientWidth; linesCanvas.width = linesCanvas.clientWidth;
linesCanvas.height = linesCanvas.clientHeight; linesCanvas.height = linesCanvas.clientHeight;
@ -85,6 +216,7 @@ function updateLines(){
} }
function renderBackground(atlas){ function renderBackground(atlas){
console.log(7)
backgroundContext.clearRect(0, 0, canvas.width, canvas.height); backgroundContext.clearRect(0, 0, canvas.width, canvas.height);
@ -138,274 +270,8 @@ function renderBackground(atlas){
} }
} }
function initView(){
var wrapper = document.getElementById("wrapper");
var objectsContainer = document.getElementById("objectsList");
var closeObjectsListButton = document.getElementById("closeObjectsListButton");
var filterInput = document.getElementById("searchList");
var entriesList = document.getElementById("entriesList");
var hideListButton = document.getElementById("hideListButton");
var entriesListShown = true;
var sortedAtlas;
var entriesLimit = 50;
var entriesOffset = 0;
var moreEntriesButton = document.createElement("button");
moreEntriesButton.innerHTML = "Show "+entriesLimit+" more";
moreEntriesButton.id = "moreEntriesButton";
moreEntriesButton.onclick = function(){
buildObjectsList(null, null);
};
var defaultSort = "shuffle";
document.getElementById("sort").value = defaultSort;
var lastPos = [0, 0];
var fixed = false; // Fix hovered items in place, so that clicking on links is possible
renderBackground(atlas);
render();
buildObjectsList(null, null);
timeCallback = (tempAtlas) => {
renderBackground(tempAtlas);
render();
}
// parse linked atlas entry id from link hash
/*if (window.location.hash.substring(3)){
zoom = 4;
applyView();
highlightEntryFromUrl();
}*/
if(document.documentElement.clientWidth > 2000){
entriesListShown = true;
wrapper.className = wrapper.className.replace(/ listHidden/g, "");
}
if(document.documentElement.clientWidth < 2000){
entriesListShown = false;
wrapper.className += " listHidden";
}
applyView();
render();
updateLines();
var args = window.location.search;
if(args){
id = args.split("id=")[1];
if(id){
highlightEntryFromUrl();
}
}
container.addEventListener("mousemove", function(e){
if(e.sourceCapabilities){
if(!e.sourceCapabilities.firesTouchEvents){
updateHovering(e);
}
} else {
updateHovering(e);
}
});
filterInput.addEventListener("input", function(e){
entriesOffset = 0;
entriesList.innerHTML = "";
entriesList.appendChild(moreEntriesButton);
if(this.value === ""){
document.getElementById("relevantOption").disabled = true;
sortedAtlas = atlas.concat();
buildObjectsList(null, null);
} else {
document.getElementById("relevantOption").disabled = false;
buildObjectsList(this.value.toLowerCase(), "relevant");
}
});
document.getElementById("sort").addEventListener("input", function(e){
entriesOffset = 0;
entriesList.innerHTML = "";
entriesList.appendChild(moreEntriesButton);
if(this.value != "relevant"){
defaultSort = this.value;
}
buildObjectsList(filterInput.value.toLowerCase(), this.value);
});
hideListButton.addEventListener("click", function(e){
entriesListShown = !entriesListShown;
if(entriesListShown){
wrapper.className = wrapper.className.replace(/ listHidden/g, "");
} else {
wrapper.className += " listHidden";
}
updateHovering();
applyView();
render();
updateLines();
return false;
});
closeObjectsListButton.addEventListener("click", function(e){
hovered = [];
objectsContainer.innerHTML = "";
updateLines();
closeObjectsListButton.className = "hidden";
fixed = false;
render();
});
function shuffle(){
//console.log("shuffled atlas");
for (var i = sortedAtlas.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = sortedAtlas[i];
sortedAtlas[i] = sortedAtlas[j];
sortedAtlas[j] = temp;
}
}
function highlightEntryFromUrl(){
var objectsContainer = document.getElementById("objectsList");
var id = 0;
var args = window.location.search;
if(args){
id = args.split("id=")[1];
if(id){
id = id.split("&")[0];
}
}
//var id = parseInt(window.location.hash.substring(3));
var entries = atlas.filter(function(e){
return e.id === id;
});
if (entries.length === 1){
let entry = entries[0];
document.title = entry.name + " on the 2022 /r/place Atlas";
var infoElement = createInfoBlock(entry);
objectsContainer.innerHTML = "";
objectsContainer.appendChild(infoElement);
//console.log(entry.center[0]);
//console.log(entry.center[1]);
zoom = 4;
renderBackground(atlas);
applyView();
zoomOrigin = [
innerContainer.clientWidth/2 - entry.center[0]* zoom// + container.offsetLeft
,innerContainer.clientHeight/2 - entry.center[1]* zoom// + container.offsetTop
];
scaleZoomOrigin = [
2000/2 - entry.center[0]// + container.offsetLeft
,2000/2 - entry.center[1]// + container.offsetTop
];
//console.log(zoomOrigin);
applyView();
hovered = [entry];
render();
hovered[0].element = infoElement;
closeObjectsListButton.className = "";
updateLines();
fixed = true;
}
}
function updateHovering(e, tapped){
var coordsWrapper = document.getElementById("coordsWrapper");
if (entriesListShown) {
coordsWrapper.className = "uncollapsed"
} else {
coordsWrapper.className = "collapsed"
}
if(!dragging && (!fixed || tapped)){
var pos = [
(e.clientX - (container.clientWidth/2 - innerContainer.clientWidth/2 + zoomOrigin[0] + container.offsetLeft))/zoom
,(e.clientY - (container.clientHeight/2 - innerContainer.clientHeight/2 + zoomOrigin[1] + container.offsetTop))/zoom
];
var coords_p = document.getElementById("coords_p");
coords_p.innerText = Math.ceil(pos[0]) + ", " + Math.ceil(pos[1]);
if(pos[0] <= 2200 && pos[0] >= -100 && pos[0] <= 2200 && pos[0] >= -100){
var newHovered = [];
for(var i = 0; i < atlas.length; i++){
if(pointIsInPolygon(pos, atlas[i].path)){
newHovered.push(atlas[i]);
}
}
var changed = false;
if(hovered.length == newHovered.length){
for(var i = 0; i < hovered.length; i++){
if(hovered[i].id != newHovered[i].id){
changed = true;
break;
}
}
} else {
changed = true;
}
if(changed){
hovered = newHovered.sort(function(a, b){
return calcPolygonArea(a.path) - calcPolygonArea(b.path);
});
objectsContainer.innerHTML = "";
for(var i in hovered){
var element = createInfoBlock(hovered[i]);
objectsContainer.appendChild(element);
hovered[i].element = element;
}
if(hovered.length > 0){
closeObjectsListButton.className = "";
} else {
closeObjectsListButton.className = "hidden";
}
render();
}
}
}
}
function buildObjectsList(filter, sort){ function buildObjectsList(filter, sort){
console.log(6)
if(entriesList.contains(moreEntriesButton)){ if(entriesList.contains(moreEntriesButton)){
entriesList.removeChild(moreEntriesButton); entriesList.removeChild(moreEntriesButton);
@ -632,7 +498,19 @@ function initView(){
} }
} }
function shuffle(){
console.log(5)
//console.log("shuffled atlas");
for (var i = sortedAtlas.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = sortedAtlas[i];
sortedAtlas[i] = sortedAtlas[j];
sortedAtlas[j] = temp;
}
}
async function render(){ async function render(){
console.log(4)
context.clearRect(0, 0, canvas.width, canvas.height); context.clearRect(0, 0, canvas.width, canvas.height);
@ -737,25 +615,195 @@ function initView(){
context.stroke(); context.stroke();
} }
} }
function toggleFixed(e, tapped){ function updateHovering(e, tapped){
if(!fixed && hovered.length == 0){ console.log(3)
return 0;
if(!dragging && (!fixed || tapped)){
var pos = [
(e.clientX - (container.clientWidth/2 - innerContainer.clientWidth/2 + zoomOrigin[0] + container.offsetLeft))/zoom
,(e.clientY - (container.clientHeight/2 - innerContainer.clientHeight/2 + zoomOrigin[1] + container.offsetTop))/zoom
];
var coords_p = document.getElementById("coords_p");
coords_p.innerText = Math.ceil(pos[0]) + ", " + Math.ceil(pos[1]);
if(pos[0] <= 2200 && pos[0] >= -100 && pos[0] <= 2200 && pos[0] >= -100){
var newHovered = [];
for(var i = 0; i < atlas.length; i++){
if(pointIsInPolygon(pos, atlas[i].path)){
newHovered.push(atlas[i]);
} }
fixed = !fixed; }
if(!fixed){
updateHovering(e, tapped); var changed = false;
if(hovered.length == newHovered.length){
for(var i = 0; i < hovered.length; i++){
if(hovered[i].id != newHovered[i].id){
changed = true;
break;
}
}
} else {
changed = true;
}
if(changed){
hovered = newHovered.sort(function(a, b){
return calcPolygonArea(a.path) - calcPolygonArea(b.path);
});
objectsContainer.innerHTML = "";
for(var i in hovered){
var element = createInfoBlock(hovered[i]);
objectsContainer.appendChild(element);
hovered[i].element = element;
}
if(hovered.length > 0){
closeObjectsListButton.className = "";
} else {
closeObjectsListButton.className = "hidden";
}
render(); render();
} }
} }
}
}
window.addEventListener("resize", updateLines); function highlightEntryFromUrl(){
window.addEventListener("mousemove", updateLines); console.log(2)
window.addEventListener("dblClick", updateLines);
window.addEventListener("wheel", updateLines);
var objectsContainer = document.getElementById("objectsList");
var id = 0;
var args = window.location.search;
if(args){
id = args.split("id=")[1];
if(id){
id = id.split("&")[0];
}
}
//var id = parseInt(window.location.hash.substring(3));
var entries = atlas.filter(function(e){
return e.id === id;
});
if (entries.length === 1){
let entry = entries[0];
document.title = entry.name + " on the 2022 /r/place Atlas";
var infoElement = createInfoBlock(entry);
objectsContainer.innerHTML = "";
objectsContainer.appendChild(infoElement);
//console.log(entry.center[0]);
//console.log(entry.center[1]);
zoom = 4;
renderBackground(atlas);
applyView();
zoomOrigin = [
innerContainer.clientWidth/2 - entry.center[0]* zoom// + container.offsetLeft
,innerContainer.clientHeight/2 - entry.center[1]* zoom// + container.offsetTop
];
scaleZoomOrigin = [
2000/2 - entry.center[0]// + container.offsetLeft
,2000/2 - entry.center[1]// + container.offsetTop
];
//console.log(zoomOrigin);
applyView();
hovered = [entry];
render();
hovered[0].element = infoElement;
closeObjectsListButton.className = "";
updateLines();
fixed = true;
}
}
function initView(){
console.log(1)
buildObjectsList(null, null);
renderBackground(atlas);
render();
timeCallback = (tempAtlas) => {
renderBackground(tempAtlas);
render();
}
// parse linked atlas entry id from link hash
/*if (window.location.hash.substring(3)){
zoom = 4;
applyView();
highlightEntryFromUrl();
}*/
applyView();
render();
updateLines();
var args = window.location.search;
if(args){
id = args.split("id=")[1];
if(id){
highlightEntryFromUrl();
}
}
}
function initExplore(){
window.updateHovering = updateHovering
function updateHovering(e, tapped){
if(!dragging && (!fixed || tapped)){
var pos = [
(e.clientX - (container.clientWidth/2 - innerContainer.clientWidth/2 + zoomOrigin[0] + container.offsetLeft))/zoom
,(e.clientY - (container.clientHeight/2 - innerContainer.clientHeight/2 + zoomOrigin[1] + container.offsetTop))/zoom
];
var coords_p = document.getElementById("coords_p");
coords_p.innerText = Math.ceil(pos[0]) + ", " + Math.ceil(pos[1]);
}
}
renderBackground(atlas);
applyView();
}
function initGlobal() {
container.addEventListener("mousemove", function(e){
if(e.sourceCapabilities){
if(!e.sourceCapabilities.firesTouchEvents){
updateHovering(e);
}
} else {
updateHovering(e);
}
});
}
function initViewGlobal() {
container.addEventListener("mousedown", function(e){ container.addEventListener("mousedown", function(e){
lastPos = [ lastPos = [
e.clientX e.clientX
@ -798,33 +846,4 @@ function initView(){
} }
} }
}); });
objectsContainer.addEventListener("scroll", function(e){
updateLines();
});
window.addEventListener("resize", function(){
//console.log(document.documentElement.clientWidth, document.documentElement.clientHeight);
var viewportWidth = document.documentElement.clientWidth;
if(document.documentElement.clientWidth > 2000 && viewportWidth <= 2000){
entriesListShown = true;
wrapper.className = wrapper.className.replace(/ listHidden/g, "");
}
if(document.documentElement.clientWidth < 2000 && viewportWidth >= 2000){
entriesListShown = false;
wrapper.className += " listHidden";
}
updateHovering();
viewportWidth = document.documentElement.clientWidth;
applyView();
render();
updateLines();
});
} }

View file

@ -1,22 +1,15 @@
<!-- <!--
======================================================================== ========================================================================
The /r/place Atlas The 2022 /r/place Atlas
An Atlas of Reddit's /r/place, with information to each An Atlas of Reddit's 2022 /r/place, with information to each
artwork of the canvas provided by the community. artwork of the canvas provided by the community.
Copyright (C) 2017 Roland Rytz <roland@draemm.li> Copyright (c) 2017 Roland Rytz <roland@draemm.li>
Licensed under the GNU Affero General Public License Version 3 Copyright (c) 2022 r/placeAtlas2 contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
For more information, see:
http://place-atlas.stefanocoding.me/license.txt
Licensed under the GNU Affero General Public License Version 3
https://place-atlas.stefanocoding.me/license.txt
======================================================================== ========================================================================
--> -->
@ -34,7 +27,7 @@
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1"> <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1">
<link href="./_css/style.css?version=1.0.33" rel="stylesheet" type="text/css" media="all"> <link href="./_css/style.css" rel="stylesheet" type="text/css" media="all">
</head> </head>
<body> <body>
<div id="wrapper"> <div id="wrapper">
@ -56,36 +49,35 @@ <h1>The 2022 /r/place Atlas</h1>
<div id="aboutContainer"> <div id="aboutContainer">
<a id="aboutBackButton" href="./">&lt; Back to the Atlas</a>
<div id="about"> <div id="about">
<a href="https://www.netlify.com"> <a id="aboutBackButton" class="button" href="./">&lt; Back to the Atlas</a>
<a href="https://www.netlify.com" id="netlifyBadges">
<img src="https://www.netlify.com/img/global/badges/netlify-color-bg.svg" alt="Deploys by Netlify" /> <img src="https://www.netlify.com/img/global/badges/netlify-color-bg.svg" alt="Deploys by Netlify" />
<img src="https://api.netlify.com/api/v1/badges/1e7291ce-0680-45ed-9843-47a32a992bbb/deploy-status" alt="Deploys by Netlify" /> <img src="https://api.netlify.com/api/v1/badges/1e7291ce-0680-45ed-9843-47a32a992bbb/deploy-status" alt="Deploys by Netlify" />
</a> </a>
<br>
<h2 id="abouth2">The 2022 /r/place Atlas</h2> <h2 id="abouth2">The 2022 /r/place Atlas</h2>
<p>This is an Atlas aiming to chart all the artworks created during the <a href="https://www.reddit.com/r/place/">/r/place</a> April's fools event on <a href="https://www.reddit.com/" target="_blank">Reddit</a> in 2022.</p> <p>This is an Atlas aiming to chart all the artworks created during the <a href="https://www.reddit.com/r/place/">/r/place</a> April Fools event on <a href="https://www.reddit.com/" target="_blank">Reddit</a> in 2022.</p>
<p>The original code was developed by <a href="/" target="_blank" rel="author">Roland Rytz</a> (<a href="mailto:roland.rytz@gmail.com" target="_blank">mail</a>, <a href="https://reddit.com/user/draemmli/" target="_blank">reddit</a>) and is available under the free <a href="https://www.gnu.org/licenses/agpl-3.0.en.html" target="_blank">AGPL license</a> on <a target="_blank" href="https://github.com/RolandR/place-atlas">GitHub</a>.</p> <p>The original code was developed by <a href="https://draemm.li/various/place-atlas/" target="_blank" rel="author">Roland Rytz</a> (<a href="mailto:roland.rytz@gmail.com" target="_blank">mail</a>, <a href="https://reddit.com/user/draemmli/" target="_blank">reddit</a>) and is available under the free <a href="https://www.gnu.org/licenses/agpl-3.0.en.html" target="_blank">AGPL license</a> on <a target="_blank" href="https://github.com/RolandR/place-atlas">GitHub</a>.</p>
<br> <br>
<p>The currently maintained version of the website is managed by <a href="/" target="_blank" rel="author">Stefano Haagmans</a> and is obtainable under the same license within a <a target="_blank" href="https://github.com/placeAtlas/atlas">Github Fork</a>.</p>. Image's provided by <a target="_blank" href="https://place.thatguyalex.com/">Alex Tsernoh</a></p>. <p>The currently maintained version of the website is managed by <a href="/" target="_blank" rel="author">Stefano Haagmans</a> and is obtainable under the same license within a <a target="_blank" href="https://github.com/placeAtlas/atlas">GitHub fork</a>. Images are provided by <a target="_blank" href="https://place.thatguyalex.com/">Alex Tsernoh</a>.</p>
<p>Maintaining and updating the website takes work, but I enjoy doing it for free and giving this to people. But if you would like to support me, or the people who helped me with contributions to this project. You're free to support us though <a target="_blank" href="https://paypal.me/codixer">Paypal</a>. (I don't have bitcoin)</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 target="_blank" href="https://paypal.me/placeAtlas/5">PayPal</a>, <a target="_blank" href="https://www.patreon.com/placeAtlas">Patreon</a>, or <a target="_blank" href="https://ko-fi.com/placeatlas">Ko-Fi</a>.</p>
<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>
<br> <br>
<p>Roland Rytz worked on the Atlas full-time (and more!) for over two weeks during the 2017 r/place event.</p> <p>Roland Rytz worked on the Atlas full-time (and more!) for over two weeks during the 2017 r/place event.</p>
<p>If you'd like to support Roland, you can do so by <a target="_blank" href="https://paypal.me/draemmli">PayPal</a>.</p> <p>If you'd like to support Roland, you can do so by <a target="_blank" href="https://paypal.me/draemmli">PayPal</a>.</p>
<p>If you donate more than 10(€/$/CHF/mBTC), He'll (hopefully) send you a nice sticker of the Place canvas! (2017 one)</p> <p>If you donate more than 10(€/$/CHF/mBTC), He'll (hopefully) send you a nice sticker of the 2017 Place canvas!</p>
<h2>How to contribute</h2> <h2>How to contribute</h2>
<p>The /r/Place Atlas project relies on user contributions.</p> <p>The /r/Place Atlas project relies on user contributions.</p>
<p>To contribute a label for an artwork, please read <a href="https://www.reddit.com/r/placeAtlas2/comments/tu203o/how_to_contribute/" target="_blank">this post on reddit</a> to learn how to submit a new entry.</p> <p>To contribute a label for an artwork, please read <a href="https://www.reddit.com/r/placeAtlas2/comments/tu203o/how_to_contribute/" target="_blank">this post on Reddit</a> to learn how to submit a new entry.</p>
<p>Alternatively, contributions can be made directly on <a href="https://github.com/placeAtlas/atlas/blob/master/CONTRIBUTING.md">GitHub</a>.</p> <p>Alternatively, contributions can be made directly on <a href="https://github.com/placeAtlas/atlas/blob/master/CONTRIBUTING.md">GitHub</a>.</p>
<p>The <a href="https://reddit.com/r/placeAtlas2/" target="_blank">/r/placeAtlas2</a> subreddit is also the place to submit all bug reports, feature requests or questions.</p> <p>The <a href="https://reddit.com/r/placeAtlas2/" target="_blank">/r/placeAtlas2</a> subreddit is also the place to submit all bug reports, feature requests or questions.</p>
<h2>r/placeAtlas2 (Current) Contributors and Maintainers</h2> <h2>r/placeAtlas2 (Current) Contributors and Maintainers</h2>
<div id="contributors"> <div id="contributors">
<a href="https://reddit.com/user/TCOOfficiall" target="_blank">TCOOfficiall (Current Maintainer)</a> · <a href="https://reddit.com/user/TCOOfficiall" target="_blank">TCOOfficiall (current maintainer)</a> ·
<a href="https://reddit.com/user/prosto_sanja" target="_blank">prosto_sanja (Provided Images)</a> - <a href="https://place.thatguyalex.com/" target="_blank">Website</a> · <a href="https://reddit.com/user/prosto_sanja" target="_blank">prosto_sanja (images)</a> <a href="https://place.thatguyalex.com/" target="_blank">(website)</a> ·
<a href="https://reddit.com/user/electric-blue" target="_blank">electric-blue</a> · <a href="https://reddit.com/user/electric-blue" target="_blank">electric-blue</a> ·
<a href="https://reddit.com/user/m654zy" target="_blank">m654zy</a> · <a href="https://reddit.com/user/m654zy" target="_blank">m654zy</a> ·
<a href="https://reddit.com/user/xXLInkster17Xx" target="_blank">xXLInkster17Xx</a> <a href="https://reddit.com/user/xXLInkster17Xx" target="_blank">xXLInkster17Xx</a>
@ -103,14 +95,5 @@ <h2 id="contacth2">Contact?</h2>
</div> </div>
</div> </div>
</div> </div>
<script type="text/javascript">
document.getElementById("closeBitcoinButton").addEventListener("click", function(e) {
document.getElementById("bitcoinOverlay").style.display = "none";
});
document.getElementById("bitcoinButton").addEventListener("click", function(e) {
document.getElementById("bitcoinOverlay").style.display = "flex";
});
</script>
</body> </body>
</html> </html>

File diff suppressed because it is too large Load diff

View file

@ -1,22 +1,15 @@
<!-- <!--
======================================================================== ========================================================================
The /r/place Atlas The 2022 /r/place Atlas
An Atlas of Reddit's /r/place, with information to each An Atlas of Reddit's 2022 /r/place, with information to each
artwork of the canvas provided by the community. artwork of the canvas provided by the community.
Copyright (C) 2017 Roland Rytz <roland@draemm.li> Copyright (c) 2017 Roland Rytz <roland@draemm.li>
Licensed under the GNU Affero General Public License Version 3 Copyright (c) 2022 r/placeAtlas2 contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
For more information, see:
http://place-atlas.stefanocoding.me/license.txt
Licensed under the GNU Affero General Public License Version 3
https://place-atlas.stefanocoding.me/license.txt
======================================================================== ========================================================================
--> -->
@ -36,7 +29,7 @@
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, minimum-scale=1, maximum-scale=1, shrink-to-fit=no"> <!-- user-scalable=no --> <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, minimum-scale=1, maximum-scale=1, shrink-to-fit=no"> <!-- user-scalable=no -->
<meta name="mobile-web-app-capable" content="yes"> <meta name="mobile-web-app-capable" content="yes">
<link href="./_css/style.css?version=1.0.33" rel="stylesheet" type="text/css" media="all"> <link href="./_css/style.css" rel="stylesheet" type="text/css" media="all">
<link rel="manifest" href="./manifest.webmanifest"> <link rel="manifest" href="./manifest.webmanifest">
<script type="application/ld+json"> <script type="application/ld+json">
@ -60,7 +53,7 @@
}, },
"copyrightHolder": { "@id": "#RolandRytz" }, "copyrightHolder": { "@id": "#RolandRytz" },
"copyrightYear": 2017, "copyrightYear": 2017,
"license": "http://place-atlas.stefanocoding.me/license.txt", "license": "https://place-atlas.stefanocoding.me/license.txt",
"inLanguage": "English", "inLanguage": "English",
"isAccessibleForFree": true, "isAccessibleForFree": true,
"keywords": "reddit, /r/place", "keywords": "reddit, /r/place",
@ -106,14 +99,24 @@ <h1 id="title">The 2022 /r/place Atlas</h1>
</div> </div>
<div id="entriesListContainer"> <div id="entriesListContainer">
<nav> <nav id="entriesListNav">
<a id="aboutLink" href="./about.html">About</a> <a id="aboutLink" href="./about.html" class="button">About</a>
<a id="drawLink" href="./index.html?mode=draw">Draw</a> <a id="drawLink" href="./index.html?mode=draw" class="button">Draw</a>
<a id="toggleMode" onclick="return changeOverlapMode()">Overlap</a> <div class="dropdown button" id="viewModes">
<button title="Discord" onclick="window.location.href='https://discord.gg/pJkm23b2nA'"> <span>Modes</span>
<span class="buffer"></span>
<div class="dropdown-content">
<a href="./">Normal</a>
<a href="./?mode=explore">Explore</a>
<a href="./?mode=overlap">Overlap</a>
<a href="./?mode=diff" class="show-only-on-dev">With Diff</a>
<a href="./?mode=diffonly" class="show-only-on-dev">Diff Only</a>
</div>
</div>
<a title="Discord" href="https://discord.gg/pJkm23b2nA" class="button small" id="entriesListDiscord">
<img class="Discord" alt="Discord Logo" src="./_img/discord.svg"> <img class="Discord" alt="Discord Logo" src="./_img/discord.svg">
</button> </a>
<button title="Donate!" id="donateButton"> <button title="Donate!" id="entriesListDonate" class="small">
<img alt="Donate" src="data:image/svg+xml;utf8,%3Csvg%0A%20%20%20xmlns%3Adc%3D%22http%3A//purl.org/dc/elements/1.1/%22%0A%20%20%20xmlns%3Acc%3D%22http%3A//creativecommons.org/ns%23%22%0A%20%20%20xmlns%3Ardf%3D%22http%3A//www.w3.org/1999/02/22-rdf-syntax-ns%23%22%0A%20%20%20xmlns%3Asvg%3D%22http%3A//www.w3.org/2000/svg%22%0A%20%20%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%0A%20%20%20version%3D%221.1%22%0A%20%20%20width%3D%2263.97776%22%0A%20%20%20height%3D%2263.985764%22%0A%20%20%20id%3D%22svg2%22%3E%0A%20%20%3Cdefs%0A%20%20%20%20%20id%3D%22defs4%22%20/%3E%0A%20%20%3Cmetadata%0A%20%20%20%20%20id%3D%22metadata7%22%3E%0A%20%20%20%20%3Crdf%3ARDF%3E%0A%20%20%20%20%20%20%3Ccc%3AWork%0A%20%20%20%20%20%20%20%20%20rdf%3Aabout%3D%22%22%3E%0A%20%20%20%20%20%20%20%20%3Cdc%3Aformat%3Eimage/svg+xml%3C/dc%3Aformat%3E%0A%20%20%20%20%20%20%20%20%3Cdc%3Atype%0A%20%20%20%20%20%20%20%20%20%20%20rdf%3Aresource%3D%22http%3A//purl.org/dc/dcmitype/StillImage%22%20/%3E%0A%20%20%20%20%20%20%20%20%3Cdc%3Atitle%3E%3C/dc%3Atitle%3E%0A%20%20%20%20%20%20%3C/cc%3AWork%3E%0A%20%20%20%20%3C/rdf%3ARDF%3E%0A%20%20%3C/metadata%3E%0A%20%20%3Cg%0A%20%20%20%20%20transform%3D%22translate%28-239.44047%2C-363.22698%29%22%0A%20%20%20%20%20id%3D%22layer1%22%3E%0A%20%20%20%20%3Cpath%0A%20%20%20%20%20%20%20d%3D%22m%20290.96332%2C384.19885%20c%20-0.59424%2C-6.27896%20-6.01049%2C-8.39164%20-12.8518%2C-9.00126%20l%200.0128%2C-8.70824%20-5.30062%2C-0.007%20-0.0123%2C8.47872%20c%20-1.39346%2C-0.002%20-2.81788%2C0.0235%20-4.23308%2C0.0496%20l%200.0135%2C-8.53485%20-5.29778%2C-0.008%20-0.0149%2C8.70575%20c%20-1.14765%2C0.0217%20-2.27469%2C0.0414%20-3.3736%2C0.0405%20l%20-5.3e-4%2C-0.0271%20-7.31086%2C-0.0134%20-0.007%2C5.66124%20c%200%2C0%203.91442%2C-0.0688%203.84925%2C0.003%202.14703%2C0.004%202.84397%2C1.25133%203.04562%2C2.32724%20l%20-0.0143%2C9.92049%20c%200.14815%2C0.001%200.34143%2C0.008%200.56022%2C0.0378%20-0.17659%2C-3e-5%20-0.36561%2C-0.002%20-0.55995%2C-1.2e-4%20l%20-0.022%2C13.89765%20c%20-0.0952%2C0.67556%20-0.49402%2C1.75232%20-1.99407%2C1.75269%200.0678%2C0.0602%20-3.85316%2C-0.007%20-3.85316%2C-0.007%20l%20-1.06259%2C6.32874%206.89801%2C0.01%20c%201.28367%2C0.003%202.54669%2C0.0271%203.78665%2C0.0368%20l%20-0.0109%2C8.80736%205.29494%2C0.009%200.0128%2C-8.71427%20c%201.45379%2C0.0322%202.86073%2C0.0459%204.23429%2C0.0466%20l%20-0.0152%2C8.67412%205.30061%2C0.007%200.0147%2C-8.79173%20c%208.91219%2C-0.49805%2015.1527%2C-2.73385%2015.93965%2C-11.10113%200.63533%2C-6.73752%20-2.53%2C-9.74895%20-7.5868%2C-10.97123%203.07554%2C-1.56033%205.00104%2C-4.31475%204.55848%2C-8.90928%20z%20m%20-7.44387%2C18.82121%20c%20-0.007%2C6.58182%20-11.27551%2C5.81643%20-14.86789%2C5.81449%20l%200.0187%2C-11.66923%20c%203.59343%2C0.006%2014.85983%2C-1.01023%2014.84919%2C5.85474%20z%20m%20-2.44078%2C-16.46738%20c%20-0.0106%2C5.98811%20-9.40836%2C5.27536%20-12.40064%2C5.27116%20l%200.016%2C-10.58348%20c%202.99229%2C0.004%2012.39322%2C-0.93337%2012.38461%2C5.31232%20z%22%0A%20%20%20%20%20%20%20id%3D%22path3010%22%0A%20%20%20%20%20%20%20style%3D%22fill%3A%23ffffff%22%20/%3E%0A%20%20%3C/g%3E%0A%3C/svg%3E"> <img alt="Donate" src="data:image/svg+xml;utf8,%3Csvg%0A%20%20%20xmlns%3Adc%3D%22http%3A//purl.org/dc/elements/1.1/%22%0A%20%20%20xmlns%3Acc%3D%22http%3A//creativecommons.org/ns%23%22%0A%20%20%20xmlns%3Ardf%3D%22http%3A//www.w3.org/1999/02/22-rdf-syntax-ns%23%22%0A%20%20%20xmlns%3Asvg%3D%22http%3A//www.w3.org/2000/svg%22%0A%20%20%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%0A%20%20%20version%3D%221.1%22%0A%20%20%20width%3D%2263.97776%22%0A%20%20%20height%3D%2263.985764%22%0A%20%20%20id%3D%22svg2%22%3E%0A%20%20%3Cdefs%0A%20%20%20%20%20id%3D%22defs4%22%20/%3E%0A%20%20%3Cmetadata%0A%20%20%20%20%20id%3D%22metadata7%22%3E%0A%20%20%20%20%3Crdf%3ARDF%3E%0A%20%20%20%20%20%20%3Ccc%3AWork%0A%20%20%20%20%20%20%20%20%20rdf%3Aabout%3D%22%22%3E%0A%20%20%20%20%20%20%20%20%3Cdc%3Aformat%3Eimage/svg+xml%3C/dc%3Aformat%3E%0A%20%20%20%20%20%20%20%20%3Cdc%3Atype%0A%20%20%20%20%20%20%20%20%20%20%20rdf%3Aresource%3D%22http%3A//purl.org/dc/dcmitype/StillImage%22%20/%3E%0A%20%20%20%20%20%20%20%20%3Cdc%3Atitle%3E%3C/dc%3Atitle%3E%0A%20%20%20%20%20%20%3C/cc%3AWork%3E%0A%20%20%20%20%3C/rdf%3ARDF%3E%0A%20%20%3C/metadata%3E%0A%20%20%3Cg%0A%20%20%20%20%20transform%3D%22translate%28-239.44047%2C-363.22698%29%22%0A%20%20%20%20%20id%3D%22layer1%22%3E%0A%20%20%20%20%3Cpath%0A%20%20%20%20%20%20%20d%3D%22m%20290.96332%2C384.19885%20c%20-0.59424%2C-6.27896%20-6.01049%2C-8.39164%20-12.8518%2C-9.00126%20l%200.0128%2C-8.70824%20-5.30062%2C-0.007%20-0.0123%2C8.47872%20c%20-1.39346%2C-0.002%20-2.81788%2C0.0235%20-4.23308%2C0.0496%20l%200.0135%2C-8.53485%20-5.29778%2C-0.008%20-0.0149%2C8.70575%20c%20-1.14765%2C0.0217%20-2.27469%2C0.0414%20-3.3736%2C0.0405%20l%20-5.3e-4%2C-0.0271%20-7.31086%2C-0.0134%20-0.007%2C5.66124%20c%200%2C0%203.91442%2C-0.0688%203.84925%2C0.003%202.14703%2C0.004%202.84397%2C1.25133%203.04562%2C2.32724%20l%20-0.0143%2C9.92049%20c%200.14815%2C0.001%200.34143%2C0.008%200.56022%2C0.0378%20-0.17659%2C-3e-5%20-0.36561%2C-0.002%20-0.55995%2C-1.2e-4%20l%20-0.022%2C13.89765%20c%20-0.0952%2C0.67556%20-0.49402%2C1.75232%20-1.99407%2C1.75269%200.0678%2C0.0602%20-3.85316%2C-0.007%20-3.85316%2C-0.007%20l%20-1.06259%2C6.32874%206.89801%2C0.01%20c%201.28367%2C0.003%202.54669%2C0.0271%203.78665%2C0.0368%20l%20-0.0109%2C8.80736%205.29494%2C0.009%200.0128%2C-8.71427%20c%201.45379%2C0.0322%202.86073%2C0.0459%204.23429%2C0.0466%20l%20-0.0152%2C8.67412%205.30061%2C0.007%200.0147%2C-8.79173%20c%208.91219%2C-0.49805%2015.1527%2C-2.73385%2015.93965%2C-11.10113%200.63533%2C-6.73752%20-2.53%2C-9.74895%20-7.5868%2C-10.97123%203.07554%2C-1.56033%205.00104%2C-4.31475%204.55848%2C-8.90928%20z%20m%20-7.44387%2C18.82121%20c%20-0.007%2C6.58182%20-11.27551%2C5.81643%20-14.86789%2C5.81449%20l%200.0187%2C-11.66923%20c%203.59343%2C0.006%2014.85983%2C-1.01023%2014.84919%2C5.85474%20z%20m%20-2.44078%2C-16.46738%20c%20-0.0106%2C5.98811%20-9.40836%2C5.27536%20-12.40064%2C5.27116%20l%200.016%2C-10.58348%20c%202.99229%2C0.004%2012.39322%2C-0.93337%2012.38461%2C5.31232%20z%22%0A%20%20%20%20%20%20%20id%3D%22path3010%22%0A%20%20%20%20%20%20%20style%3D%22fill%3A%23ffffff%22%20/%3E%0A%20%20%3C/g%3E%0A%3C/svg%3E">
</button> </button>
</nav> </nav>
@ -156,13 +159,13 @@ <h1 id="title">The 2022 /r/place Atlas</h1>
<div id="timeControls"> <div id="timeControls">
<input type="range" min="1" max="1" value="1" class="slider" id="timeControlsSlider"> <input type="range" min="1" max="1" value="1" class="slider" id="timeControlsSlider">
</div> </div>
<div id="author">
<p><div id="author">Code owned by <a href="https://github.com/placeAtlas/atlas" target="_blank" rel="author">Place Atlas</a>.. Source on <a target="_blank" href="https://github.com/placeAtlas/atlas">GitHub</a>. This site is powered by <a href="https://www.netlify.com">Netlify</a>. Images provided by <a target="_blank" href="https://place.thatguyalex.com/">Alex Tsernoh</a>.</p> <p>Code owned by <a href="https://github.com/placeAtlas/atlas" target="_blank" rel="author">Place Atlas</a>. Source on <a target="_blank" href="https://github.com/placeAtlas/atlas">GitHub</a>. Site powered by <a href="https://www.netlify.com">Netlify</a>. Images provided by <a target="_blank" href="https://place.thatguyalex.com/">Alex Tsernoh</a>.</p>
</div> </div>
</div> </div>
<div id="drawControlsContainer"> <div id="drawControlsContainer">
<a id="drawBackButton" href="./">&lt; Back to the Atlas</a> <a id="drawBackButton" class="button" href="./">&lt; Back to the Atlas</a>
<div id="drawControls"> <div id="drawControls">
<div> <div>
<button id="undoButton" disabled>Undo</button> <button id="undoButton" disabled>Undo</button>
@ -196,7 +199,7 @@ <h1 id="title">The 2022 /r/place Atlas</h1>
<p>You can then add more information about your object.</p> <p>You can then add more information about your object.</p>
<div style="background-color:#7289DA; padding:20px"> <div style="background-color:#7289DA; padding:20px">
<p><b>Need Help?</b></p> <p><b>Need Help?</b></p>
<b>You can ask for help on our discord server <a href="https://discord.gg/pJkm23b2nA">here</a>!</b><br> <b>You can ask for help on <a href="https://discord.gg/pJkm23b2nA">our Discord server</a>!</b><br>
</div> </div>
</div> </div>
</div> </div>
@ -209,7 +212,7 @@ <h1 id="title">The 2022 /r/place Atlas</h1>
<div id="exportWindow"> <div id="exportWindow">
<p><b>Recommended:</b> Post directly after clicking this button. Don't forget to flair it with the "New Entry" tag. </p> <p><b>Recommended:</b> Post directly after clicking this button. Don't forget to flair it with the "New Entry" tag. </p>
<div style="display:flex; flex-direction:column;align-items:center"> <div style="display:flex; flex-direction:column;align-items:center">
<a href="_blank" id="exportDirectPost">Post Direct to Reddit</a> <a href="_blank" id="exportDirectPost" class="button">Post Direct to Reddit</a>
</div> </div>
<hr style="border-bottom: solid black 1px"/> <hr style="border-bottom: solid black 1px"/>
<i>or...</i> <i>or...</i>
@ -228,30 +231,41 @@ <h1 id="title">The 2022 /r/place Atlas</h1>
<div id="donateWindow"> <div id="donateWindow">
<h2>Donation Links</h2> <h2>Donation Links</h2>
<p>Current 2022 Atlas Maintainers:</p> <p>Current 2022 Atlas Maintainers:</p>
<p> - <a target="_blank" href="https://paypal.me/placeAtlas/5">PayPal</a></p> <a class="button" target="_blank" href="https://paypal.me/placeAtlas/5">
<p> - <a target="_blank" href="https://www.patreon.com/placeAtlas">Patreon</a></p> <svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>PayPal</title><path fill="white" d="M7.076 21.337H2.47a.641.641 0 0 1-.633-.74L4.944.901C5.026.382 5.474 0 5.998 0h7.46c2.57 0 4.578.543 5.69 1.81 1.01 1.15 1.304 2.42 1.012 4.287-.023.143-.047.288-.077.437-.983 5.05-4.349 6.797-8.647 6.797h-2.19c-.524 0-.968.382-1.05.9l-1.12 7.106zm14.146-14.42a3.35 3.35 0 0 0-.607-.541c-.013.076-.026.175-.041.254-.93 4.778-4.005 7.201-9.138 7.201h-2.19a.563.563 0 0 0-.556.479l-1.187 7.527h-.506l-.24 1.516a.56.56 0 0 0 .554.647h3.882c.46 0 .85-.334.922-.788.06-.26.76-4.852.816-5.09a.932.932 0 0 1 .923-.788h.58c3.76 0 6.705-1.528 7.565-5.946.36-1.847.174-3.388-.777-4.471z"/></svg>
<p> - <a target="_blank" href="https://ko-fi.com/placeatlas">Ko-Fi</a></p> PayPal
</a>
<a class="button" target="_blank" href="https://www.patreon.com/placeAtlas">
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Patreon</title><path fill="white" d="M0 .48v23.04h4.22V.48zm15.385 0c-4.764 0-8.641 3.88-8.641 8.65 0 4.755 3.877 8.623 8.641 8.623 4.75 0 8.615-3.868 8.615-8.623C24 4.36 20.136.48 15.385.48z"/></svg>
Patreon
</a>
<a class="button" target="_blank" href="https://ko-fi.com/placeatlas">
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Ko-fi</title><path fill="white" d="M23.881 8.948c-.773-4.085-4.859-4.593-4.859-4.593H.723c-.604 0-.679.798-.679.798s-.082 7.324-.022 11.822c.164 2.424 2.586 2.672 2.586 2.672s8.267-.023 11.966-.049c2.438-.426 2.683-2.566 2.658-3.734 4.352.24 7.422-2.831 6.649-6.916zm-11.062 3.511c-1.246 1.453-4.011 3.976-4.011 3.976s-.121.119-.31.023c-.076-.057-.108-.09-.108-.09-.443-.441-3.368-3.049-4.034-3.954-.709-.965-1.041-2.7-.091-3.71.951-1.01 3.005-1.086 4.363.407 0 0 1.565-1.782 3.468-.963 1.904.82 1.832 3.011.723 4.311zm6.173.478c-.928.116-1.682.028-1.682.028V7.284h1.77s1.971.551 1.971 2.638c0 1.913-.985 2.667-2.059 3.015z"/></svg>
Ko-Fi
</a>
<p>Original 2017 Atlas Developer (draemmli aka Roland Rytz): </p> <p>Original 2017 Atlas Developer (draemmli aka Roland Rytz): </p>
<p> - <a target="_blank" href="https://paypal.me/draemmli">PayPal</a></p> <a class="button" target="_blank" href="https://paypal.me/draemmli">
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>PayPal</title><path fill="white" d="M7.076 21.337H2.47a.641.641 0 0 1-.633-.74L4.944.901C5.026.382 5.474 0 5.998 0h7.46c2.57 0 4.578.543 5.69 1.81 1.01 1.15 1.304 2.42 1.012 4.287-.023.143-.047.288-.077.437-.983 5.05-4.349 6.797-8.647 6.797h-2.19c-.524 0-.968.382-1.05.9l-1.12 7.106zm14.146-14.42a3.35 3.35 0 0 0-.607-.541c-.013.076-.026.175-.041.254-.93 4.778-4.005 7.201-9.138 7.201h-2.19a.563.563 0 0 0-.556.479l-1.187 7.527h-.506l-.24 1.516a.56.56 0 0 0 .554.647h3.882c.46 0 .85-.334.922-.788.06-.26.76-4.852.816-5.09a.932.932 0 0 1 .923-.788h.58c3.76 0 6.705-1.528 7.565-5.946.36-1.847.174-3.388-.777-4.471z"/></svg>
<button id="closeBitcoinButton">Close</button> PayPal
</a>
<br> <br>
<button id="closeDonateButton">Close</button>
</div> </div>
</div> </div>
</div> </div>
<script type="text/javascript" src="./_js/time.js?version=1.0.3"></script> <script type="text/javascript" src="./_js/time.js"></script>
<script type="text/javascript" src="./_js/infoblock.js?version=1.0"></script> <script type="text/javascript" src="./_js/infoblock.js"></script>
<script type="text/javascript" src="./_js/pointInPolygon.js?version=1.0"></script> <script type="text/javascript" src="./_js/pointInPolygon.js"></script>
<script type="text/javascript" src="./_js/atlas.js?version=1.0.50"></script> <script type="text/javascript" src="./_js/atlas.js"></script>
<script type="text/javascript" src="./_js/view.js?version=1.0.4"></script> <script type="text/javascript" src="./_js/view.js"></script>
<script type="text/javascript" src="./_js/overlap.js?version=1.0.4"></script> <script type="text/javascript" src="./_js/overlap.js"></script>
<script type="text/javascript" src="./_js/draw.js?version=1.0.3"></script> <script type="text/javascript" src="./_js/draw.js"></script>
<script type="text/javascript" src="./_js/main.js?version=1.0.3"></script> <script type="text/javascript" src="./_js/main.js"></script>
<!-- <!--
<script type="text/javascript" src="./_js/stats.js?version=1.0.0"></script> <script type="text/javascript" src="./_js/stats.js"></script>
<script type="text/javascript" src="./_js/minified.js?version=1.0.102"></script> <script type="text/javascript" src="./_js/minified.js"></script>
--> -->
</body> </body>
</html> </html>