atlas/web/_js/view.js

948 lines
24 KiB
JavaScript
Raw Normal View History

/*
========================================================================
The 2022 /r/place Atlas
2017-04-06 00:43:45 +02:00
An atlas of Reddit's 2022 /r/place, with information to each
artwork of the canvas provided by the community.
2017-04-06 00:43:45 +02:00
Copyright (c) 2017 Roland Rytz <roland@draemm.li>
Copyright (c) 2022 Place Atlas contributors
Licensed under the GNU Affero General Public License Version 3
2022-04-09 03:23:55 +02:00
https://place-atlas.stefanocoding.me/license.txt
========================================================================
*/
2022-05-06 09:41:22 +02:00
const linesCanvas = document.getElementById("linesCanvas")
const linesContext = linesCanvas.getContext("2d")
let hovered = []
2022-05-06 09:41:22 +02:00
let previousZoomOrigin = [0, 0]
let previousScaleZoomOrigin = [0, 0]
2017-04-10 16:28:22 +02:00
2022-05-06 09:41:22 +02:00
const backgroundCanvas = document.createElement("canvas")
backgroundCanvas.width = 2000
backgroundCanvas.height = 2000
const backgroundContext = backgroundCanvas.getContext("2d")
2022-05-06 09:41:22 +02:00
const wrapper = document.getElementById("wrapper")
const bottomBar = document.getElementById("bottomBar")
2022-04-09 11:27:14 +02:00
const showListButton = document.getElementById("showListButton")
const offcanvasList = document.getElementById("offcanvasList")
const bsOffcanvasList = new bootstrap.Offcanvas(offcanvasList)
const offcanvasDraw = document.getElementById("offcanvasDraw")
const bsOffcanvasDraw = new bootstrap.Offcanvas(offcanvasDraw)
2022-05-06 09:41:22 +02:00
const objectsContainer = document.getElementById("objectsList")
const closeObjectsListButton = document.getElementById("closeObjectsListButton")
const objectsListOverflowNotice = document.getElementById("objectsListOverflowNotice")
2022-04-09 11:27:14 +02:00
2022-05-06 09:41:22 +02:00
const filterInput = document.getElementById("searchList")
2022-04-09 11:27:14 +02:00
2022-05-06 09:41:22 +02:00
const entriesList = document.getElementById("entriesList")
2022-05-06 09:41:22 +02:00
let entriesListShown = false
2022-04-09 11:27:14 +02:00
2022-05-06 09:41:22 +02:00
let sortedAtlas
2022-05-06 09:41:22 +02:00
const entriesLimit = 50
let entriesOffset = 0
const moreEntriesButton = document.createElement("button")
moreEntriesButton.innerHTML = "Show " + entriesLimit + " more"
2022-04-20 10:54:58 +02:00
moreEntriesButton.type = "button"
moreEntriesButton.className = "btn btn-primary d-block mb-2 mx-auto"
2022-05-06 09:41:22 +02:00
moreEntriesButton.id = "moreEntriesButton"
moreEntriesButton.onclick = function () {
2022-05-06 09:41:22 +02:00
buildObjectsList(null, null)
renderBackground()
render()
}
2022-04-09 11:27:14 +02:00
2022-05-06 09:41:22 +02:00
let defaultSort = "shuffle"
document.getElementById("sort").value = defaultSort
2022-04-09 11:27:14 +02:00
2022-05-06 09:41:22 +02:00
let lastPos = [0, 0]
2022-04-09 11:27:14 +02:00
let fixed = false; // Fix hovered items in place, so that clicking on links is possible
2022-04-09 11:27:14 +02:00
filterInput.addEventListener("input", function () {
2022-05-06 09:41:22 +02:00
entriesOffset = 0
entriesList.replaceChildren()
2022-05-06 09:41:22 +02:00
entriesList.appendChild(moreEntriesButton)
2022-04-09 11:27:14 +02:00
if (this.value === "") {
2022-05-06 09:41:22 +02:00
document.getElementById("relevantOption").disabled = true
sortedAtlas = atlas.concat()
buildObjectsList(null, null)
2022-04-09 11:27:14 +02:00
} else {
2022-05-06 09:41:22 +02:00
document.getElementById("relevantOption").disabled = false
buildObjectsList(this.value.toLowerCase(), "relevant")
2022-04-09 11:27:14 +02:00
}
2022-05-06 09:41:22 +02:00
})
2022-04-09 11:27:14 +02:00
document.getElementById("sort").addEventListener("input", function () {
2023-03-17 18:30:33 +01:00
if (this.value !== "relevant") {
2022-05-06 09:41:22 +02:00
defaultSort = this.value
2022-04-09 11:27:14 +02:00
}
2022-05-06 09:41:22 +02:00
resetEntriesList(filterInput.value.toLowerCase(), this.value)
})
2022-04-09 11:27:14 +02:00
offcanvasDraw.addEventListener('show.bs.offcanvas', function () {
2022-05-06 09:41:22 +02:00
wrapper.classList.remove('listHidden')
wrapper.classList.add('listTransitioning')
applyView()
})
offcanvasDraw.addEventListener('shown.bs.offcanvas', function () {
2022-05-06 09:41:22 +02:00
wrapper.classList.remove('listTransitioning')
applyView()
2022-04-20 10:54:58 +02:00
})
offcanvasDraw.addEventListener('hide.bs.offcanvas', function () {
2022-05-06 09:41:22 +02:00
wrapper.classList.add('listHidden')
wrapper.classList.add('listTransitioning')
applyView()
})
offcanvasDraw.addEventListener('hidden.bs.offcanvas', function () {
2022-05-06 09:41:22 +02:00
wrapper.classList.remove('listTransitioning')
applyView()
2022-04-20 10:54:58 +02:00
})
offcanvasList.addEventListener('show.bs.offcanvas', function (e) {
2022-05-06 09:41:22 +02:00
wrapper.classList.remove('listHidden')
wrapper.classList.add('listTransitioning')
applyView()
})
offcanvasList.addEventListener('shown.bs.offcanvas', function (e) {
2022-05-06 09:41:22 +02:00
entriesListShown = true
wrapper.classList.remove('listTransitioning')
updateHovering(e)
applyView()
render()
updateLines()
})
2022-04-09 11:27:14 +02:00
offcanvasList.addEventListener('hide.bs.offcanvas', function () {
2022-05-06 09:41:22 +02:00
wrapper.classList.add('listHidden')
wrapper.classList.add('listTransitioning')
applyView()
})
offcanvasList.addEventListener('hidden.bs.offcanvas', function (e) {
2022-05-06 09:41:22 +02:00
entriesListShown = false
wrapper.classList.remove('listTransitioning')
updateHovering(e)
applyView()
render()
updateLines()
})
closeObjectsListButton.addEventListener("click", clearObjectsList)
bottomBar.addEventListener("mouseover", function () {
if (!fixed) clearObjectsList()
})
function clearObjectsList() {
closeObjectsListButton.classList.add("d-none")
objectsListOverflowNotice.classList.add("d-none")
entriesList.classList.remove("disableHover")
2022-05-06 09:41:22 +02:00
hovered = []
objectsContainer.replaceChildren()
updateLines()
fixed = false
render()
}
2022-04-09 11:27:14 +02:00
function toggleFixed(e, tapped) {
2023-03-17 18:30:33 +01:00
if (!fixed && hovered.length === 0) {
entriesList.classList.remove("disableHover")
2022-05-06 09:41:22 +02:00
return 0
2022-04-09 11:27:14 +02:00
}
2022-05-06 09:41:22 +02:00
fixed = !fixed
if (!fixed) {
2022-05-06 09:41:22 +02:00
updateHovering(e, tapped)
render()
2022-04-09 11:27:14 +02:00
}
entriesList.classList.add("disableHover")
2022-05-06 09:41:22 +02:00
objectsListOverflowNotice.classList.add("d-none")
2022-04-09 11:27:14 +02:00
}
2022-05-06 09:41:22 +02:00
window.addEventListener("resize", updateLines)
window.addEventListener("mousemove", updateLines)
window.addEventListener("dblClick", updateLines)
window.addEventListener("wheel", updateLines)
2022-04-09 11:27:14 +02:00
objectsContainer.addEventListener("scroll", function () {
2022-05-06 09:41:22 +02:00
updateLines()
})
2022-04-09 11:27:14 +02:00
2022-05-06 09:41:22 +02:00
window.addEventListener("resize", function (e) {
//console.log(document.documentElement.clientWidth, document.documentElement.clientHeight)
2022-04-09 11:27:14 +02:00
// Legacy code
2022-05-06 09:41:22 +02:00
let viewportWidth = document.documentElement.clientWidth
2022-04-09 11:27:14 +02:00
if (document.documentElement.clientWidth > 2000 && viewportWidth <= 2000) {
2022-05-06 09:41:22 +02:00
entriesListShown = true
wrapper.classList.remove("listHidden")
2022-04-09 11:27:14 +02:00
}
if (document.documentElement.clientWidth < 2000 && viewportWidth >= 2000) {
2022-05-06 09:41:22 +02:00
entriesListShown = false
wrapper.classList.add("listHidden")
2022-04-09 11:27:14 +02:00
}
2022-05-06 09:41:22 +02:00
updateHovering(e)
2022-04-09 11:27:14 +02:00
2022-05-06 09:41:22 +02:00
viewportWidth = document.documentElement.clientWidth
2022-05-06 09:41:22 +02:00
applyView()
render()
updateLines()
2022-05-06 09:41:22 +02:00
})
2022-04-09 11:27:14 +02:00
function updateLines() {
// Line border
2022-05-06 09:41:22 +02:00
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 = "#222"
for (let i = 0; i < hovered.length; i++) {
2022-05-06 09:41:22 +02:00
const element = hovered[i].element
2023-03-17 18:30:33 +01:00
if (element.getBoundingClientRect().left !== 0) {
2017-04-09 02:08:35 +02:00
2022-05-06 09:41:22 +02:00
linesContext.beginPath()
// Align line based on which side the card is on
if ((element.getBoundingClientRect().left + element.clientWidth / 2) < (document.documentElement.clientWidth / 2)) {
linesContext.moveTo(
element.getBoundingClientRect().left + document.documentElement.scrollLeft + element.clientWidth - 5
, element.getBoundingClientRect().top + document.documentElement.scrollTop + 20
)
} else {
linesContext.moveTo(
element.getBoundingClientRect().left + document.documentElement.scrollLeft + 5
, element.getBoundingClientRect().top + document.documentElement.scrollTop + 20
)
}
2017-04-09 02:08:35 +02:00
linesContext.lineTo(
~~(hovered[i].center[0] * zoom) + innerContainer.offsetLeft
, ~~(hovered[i].center[1] * zoom) + innerContainer.offsetTop
2022-05-06 09:41:22 +02:00
)
linesContext.stroke()
2017-04-09 02:08:35 +02:00
}
}
// Line body
2022-05-06 09:41:22 +02:00
linesContext.lineWidth = Math.max(Math.min(zoom, 16), 4)
linesContext.strokeStyle = "#FFFFFF"
for (let i = 0; i < hovered.length; i++) {
2022-05-06 09:41:22 +02:00
const element = hovered[i].element
2023-03-17 18:30:33 +01:00
if (element.getBoundingClientRect().left !== 0) {
2022-05-06 09:41:22 +02:00
linesContext.beginPath()
// Align line based on which side the card is on
if ((element.getBoundingClientRect().left + element.clientWidth / 2) < (document.documentElement.clientWidth / 2)) {
linesContext.moveTo(
element.getBoundingClientRect().left + document.documentElement.scrollLeft + element.clientWidth - 5
, element.getBoundingClientRect().top + document.documentElement.scrollTop + 20
)
} else {
linesContext.moveTo(
element.getBoundingClientRect().left + document.documentElement.scrollLeft + 5
, element.getBoundingClientRect().top + document.documentElement.scrollTop + 20
)
}
2017-04-09 02:08:35 +02:00
linesContext.lineTo(
~~(hovered[i].center[0] * zoom) + innerContainer.offsetLeft
, ~~(hovered[i].center[1] * zoom) + innerContainer.offsetTop
2022-05-06 09:41:22 +02:00
)
linesContext.stroke()
2017-04-09 02:08:35 +02:00
}
}
}
function renderBackground(atlas) {
2022-05-06 09:41:22 +02:00
backgroundContext.clearRect(0, 0, canvas.width, canvas.height)
2022-05-06 09:41:22 +02:00
//backgroundCanvas.width = 1000 * zoom
//backgroundCanvas.height = 1000 * zoom
2022-05-06 09:41:22 +02:00
//backgroundContext.lineWidth = zoom
2022-05-06 09:41:22 +02:00
backgroundContext.fillStyle = "rgba(0, 0, 0, 0.6)"
backgroundContext.fillRect(0, 0, backgroundCanvas.width, backgroundCanvas.height)
for (let i = 0; i < atlas.length; i++) {
2022-05-06 09:41:22 +02:00
const path = atlas[i].path
2022-05-06 09:41:22 +02:00
backgroundContext.beginPath()
if (path[0]) {
2022-05-06 09:41:22 +02:00
//backgroundContext.moveTo(path[0][0]*zoom, path[0][1]*zoom)
backgroundContext.moveTo(path[0][0], path[0][1])
}
for (let p = 1; p < path.length; p++) {
2022-05-06 09:41:22 +02:00
//backgroundContext.lineTo(path[p][0]*zoom, path[p][1]*zoom)
backgroundContext.lineTo(path[p][0], path[p][1])
}
2022-05-06 09:41:22 +02:00
backgroundContext.closePath()
2022-05-06 09:41:22 +02:00
let bgStrokeStyle
2022-04-08 06:06:16 +02:00
switch (atlas[i].diff) {
case "add":
2022-05-06 09:41:22 +02:00
bgStrokeStyle = "rgba(0, 255, 0, 1)"
backgroundContext.lineWidth = 2
break
2022-04-08 06:06:16 +02:00
case "edit":
2022-05-06 09:41:22 +02:00
bgStrokeStyle = "rgba(255, 255, 0, 1)"
backgroundContext.lineWidth = 2
break
2022-04-08 22:02:14 +02:00
case "delete":
2022-05-06 09:41:22 +02:00
bgStrokeStyle = "rgba(255, 0, 0, 1)"
backgroundContext.lineWidth = 2
break
2022-04-08 06:06:16 +02:00
default:
2022-05-06 09:41:22 +02:00
bgStrokeStyle = "rgba(255, 255, 255, 0.8)"
break
2022-04-08 06:06:16 +02:00
}
2022-05-06 09:41:22 +02:00
backgroundContext.strokeStyle = bgStrokeStyle
backgroundContext.stroke()
backgroundContext.lineWidth = 1
}
}
function buildObjectsList(filter = null, sort = null) {
if (entriesList.contains(moreEntriesButton)) {
2022-05-06 09:41:22 +02:00
entriesList.removeChild(moreEntriesButton)
2022-04-08 01:11:29 +02:00
}
if (!sortedAtlas) {
2022-05-06 09:41:22 +02:00
sortedAtlas = atlas.concat()
document.getElementById("atlasSize").innerHTML = "The Atlas contains " + sortedAtlas.length + " entries."
2022-04-09 11:27:14 +02:00
}
if (filter) {
sortedAtlas = atlas.filter(function (value) {
2022-04-09 11:27:14 +02:00
return (
value.name.toLowerCase().indexOf(filter) !== -1
2022-04-09 11:27:14 +02:00
|| value.description.toLowerCase().indexOf(filter) !== -1
|| value.subreddit && value.subreddit.toLowerCase().indexOf(filter) !== -1
2022-04-09 17:49:27 +02:00
|| value.id === filter
2022-05-06 09:41:22 +02:00
)
})
document.getElementById("atlasSize").innerHTML = "Found " + sortedAtlas.length + " entries."
2022-04-09 11:27:14 +02:00
} else {
2022-05-06 09:41:22 +02:00
document.getElementById("atlasSize").innerHTML = "The Atlas contains " + sortedAtlas.length + " entries."
}
if (sort === null) {
2022-05-06 09:41:22 +02:00
sort = defaultSort
}
2022-05-06 09:41:22 +02:00
renderBackground(sortedAtlas)
render()
2022-05-06 09:41:22 +02:00
document.getElementById("sort").value = sort
2022-05-06 09:41:22 +02:00
//console.log(sort)
2017-04-06 00:43:45 +02:00
2022-05-06 09:41:22 +02:00
let sortFunction
2022-05-06 09:41:22 +02:00
//console.log(sort)
switch (sort) {
2022-04-09 11:27:14 +02:00
case "shuffle":
2022-05-06 09:41:22 +02:00
sortFunction = null
2023-03-17 18:30:33 +01:00
if (entriesOffset === 0) {
2022-05-06 09:41:22 +02:00
shuffle()
2022-04-09 11:27:14 +02:00
}
2022-05-06 09:41:22 +02:00
break
2022-04-09 11:27:14 +02:00
case "alphaAsc":
sortFunction = function (a, b) {
2022-05-06 09:41:22 +02:00
return a.name.toLowerCase().localeCompare(b.name.toLowerCase())
2022-04-09 11:27:14 +02:00
}
2022-05-06 09:41:22 +02:00
break
2022-04-09 11:27:14 +02:00
case "alphaDesc":
sortFunction = function (a, b) {
2022-05-06 09:41:22 +02:00
return b.name.toLowerCase().localeCompare(a.name.toLowerCase())
2022-04-09 11:27:14 +02:00
}
2022-05-06 09:41:22 +02:00
break
2022-04-09 11:27:14 +02:00
case "newest":
sortFunction = function (a, b) {
2022-04-09 11:27:14 +02:00
if (a.id > b.id) {
2022-05-06 09:41:22 +02:00
return -1
2022-04-09 11:27:14 +02:00
}
if (a.id < b.id) {
2022-05-06 09:41:22 +02:00
return 1
2022-04-09 11:27:14 +02:00
}
// a must be equal to b
2022-05-06 09:41:22 +02:00
return 0
2022-04-09 11:27:14 +02:00
}
2022-05-06 09:41:22 +02:00
break
2022-04-09 11:27:14 +02:00
case "oldest":
sortFunction = function (a, b) {
2022-04-09 11:27:14 +02:00
if (a.id < b.id) {
2022-05-06 09:41:22 +02:00
return -1
2022-04-09 11:27:14 +02:00
}
if (a.id > b.id) {
2022-05-06 09:41:22 +02:00
return 1
2022-04-09 11:27:14 +02:00
}
// a must be equal to b
2022-05-06 09:41:22 +02:00
return 0
2022-04-09 11:27:14 +02:00
}
2022-05-06 09:41:22 +02:00
break
2022-04-09 11:27:14 +02:00
case "area":
sortFunction = function (a, b) {
2022-05-06 09:41:22 +02:00
return calcPolygonArea(b.path) - calcPolygonArea(a.path)
2022-04-09 11:27:14 +02:00
}
2022-05-06 09:41:22 +02:00
break
2022-04-09 11:27:14 +02:00
case "relevant":
sortFunction = function (a, b) {
if (a.name.toLowerCase().indexOf(filter) !== -1 && b.name.toLowerCase().indexOf(filter) !== -1) {
2022-04-09 11:27:14 +02:00
if (a.name.toLowerCase().indexOf(filter) < b.name.toLowerCase().indexOf(filter)) {
2022-05-06 09:41:22 +02:00
return -1
2022-04-09 11:27:14 +02:00
}
else if (a.name.toLowerCase().indexOf(filter) > b.name.toLowerCase().indexOf(filter)) {
2022-05-06 09:41:22 +02:00
return 1
2022-04-09 11:27:14 +02:00
} else {
2022-05-06 09:41:22 +02:00
return a.name.toLowerCase().localeCompare(b.name.toLowerCase())
2022-04-09 11:27:14 +02:00
}
} else if (a.name.toLowerCase().indexOf(filter) !== -1) {
2022-05-06 09:41:22 +02:00
return -1
} else if (b.name.toLowerCase().indexOf(filter) !== -1) {
2022-05-06 09:41:22 +02:00
return 1
2022-04-09 11:27:14 +02:00
} else {
if (a.description.toLowerCase().indexOf(filter) < b.description.toLowerCase().indexOf(filter)) {
2022-05-06 09:41:22 +02:00
return -1
2022-04-09 11:27:14 +02:00
}
else if (a.description.toLowerCase().indexOf(filter) > b.description.toLowerCase().indexOf(filter)) {
2022-05-06 09:41:22 +02:00
return 1
2022-04-09 11:27:14 +02:00
} else {
2022-05-06 09:41:22 +02:00
return a.name.toLowerCase().localeCompare(b.name.toLowerCase())
2022-04-09 11:27:14 +02:00
}
}
}
2022-05-06 09:41:22 +02:00
break
2022-04-09 11:27:14 +02:00
}
2017-04-06 00:43:45 +02:00
if (sortFunction) {
2022-05-06 09:41:22 +02:00
sortedAtlas.sort(sortFunction)
2022-04-09 11:27:14 +02:00
}
for (let i = entriesOffset; i < entriesOffset + entriesLimit; i++) {
if (i >= sortedAtlas.length) {
2022-05-06 09:41:22 +02:00
break
}
2022-05-06 09:41:22 +02:00
const element = createInfoBlock(sortedAtlas[i])
2022-05-06 09:41:22 +02:00
element.entry = sortedAtlas[i]
2017-04-09 02:08:35 +02:00
element.addEventListener("mouseenter", function (e) {
if (!fixed && !dragging) {
2022-05-06 09:41:22 +02:00
objectsContainer.replaceChildren()
2022-05-06 09:41:22 +02:00
previousZoomOrigin = [zoomOrigin[0], zoomOrigin[1]]
previousScaleZoomOrigin = [scaleZoomOrigin[0], scaleZoomOrigin[1]]
2017-04-10 12:25:04 +02:00
2022-05-06 09:41:22 +02:00
applyView()
2022-04-09 11:27:14 +02:00
zoomOrigin = [
innerContainer.clientWidth / 2 - this.entry.center[0] * zoom// + container.offsetLeft
, innerContainer.clientHeight / 2 - this.entry.center[1] * zoom// + container.offsetTop
2022-04-09 11:27:14 +02:00
]
2022-04-09 11:27:14 +02:00
scaleZoomOrigin = [
2000 / 2 - this.entry.center[0]
, 2000 / 2 - this.entry.center[1]
2022-04-09 11:27:14 +02:00
]
2022-05-06 09:41:22 +02:00
//console.log(zoomOrigin)
2022-04-09 11:27:14 +02:00
2022-05-06 09:41:22 +02:00
applyView()
hovered = [this.entry]
render()
hovered[0].element = this
updateLines()
}
2022-05-06 09:41:22 +02:00
})
element.addEventListener("click", function (e) {
2022-05-06 09:41:22 +02:00
toggleFixed(e)
if (fixed) {
2022-05-06 09:41:22 +02:00
previousZoomOrigin = [zoomOrigin[0], zoomOrigin[1]]
previousScaleZoomOrigin = [scaleZoomOrigin[0], scaleZoomOrigin[1]]
applyView()
2022-04-09 11:27:14 +02:00
}
// Legacy code
/*if (document.documentElement.clientWidth < 500) {
2022-05-06 09:41:22 +02:00
objectsContainer.replaceChildren()
2022-05-06 09:41:22 +02:00
entriesListShown = false
bsOffcanvasList.hide()
2022-05-06 09:41:22 +02:00
wrapper.classList.add("listHidden")
2022-05-06 09:41:22 +02:00
zoom = 4
renderBackground(atlas)
applyView()
updateHovering(e)
2022-04-09 11:27:14 +02:00
zoomOrigin = [
innerContainer.clientWidth / 2 - this.entry.center[0] * zoom// + container.offsetLeft
, innerContainer.clientHeight / 2 - this.entry.center[1] * zoom// + container.offsetTop
2022-04-09 11:27:14 +02:00
]
2022-04-09 11:27:14 +02:00
scaleZoomOrigin = [
2000 / 2 - this.entry.center[0]
, 2000 / 2 - this.entry.center[1]
2022-04-09 11:27:14 +02:00
]
2022-05-06 09:41:22 +02:00
previousZoomOrigin = [zoomOrigin[0], zoomOrigin[1]]
previousScaleZoomOrigin = [scaleZoomOrigin[0], scaleZoomOrigin[1]]
2022-05-06 09:41:22 +02:00
fixed = true
2022-05-06 09:41:22 +02:00
hovered = [this.entry]
hovered[0].element = this
2022-05-06 09:41:22 +02:00
applyView()
render()
updateLines()
}*/
2022-05-06 09:41:22 +02:00
})
element.addEventListener("mouseleave", function () {
if (!fixed && !dragging) {
2022-05-06 09:41:22 +02:00
zoomOrigin = [previousScaleZoomOrigin[0] * zoom, previousScaleZoomOrigin[1] * zoom]
scaleZoomOrigin = [previousScaleZoomOrigin[0], previousScaleZoomOrigin[1]]
applyView()
hovered = []
updateLines()
render()
2022-04-09 11:27:14 +02:00
}
2022-05-06 09:41:22 +02:00
})
2022-05-06 09:41:22 +02:00
entriesList.appendChild(element)
2022-04-09 11:27:14 +02:00
}
2017-04-09 02:08:35 +02:00
2022-05-06 09:41:22 +02:00
entriesOffset += entriesLimit
2017-04-06 00:43:45 +02:00
if (sortedAtlas.length > entriesOffset) {
2022-05-06 09:41:22 +02:00
moreEntriesButton.innerHTML = "Show " + Math.min(entriesLimit, sortedAtlas.length - entriesOffset) + " more"
entriesList.appendChild(moreEntriesButton)
}
2022-04-09 11:27:14 +02:00
}
function shuffle() {
2022-05-06 09:41:22 +02:00
//console.log("shuffled atlas")
for (let i = sortedAtlas.length - 1; i > 0; i--) {
2022-05-06 09:41:22 +02:00
const j = Math.floor(Math.random() * (i + 1))
const temp = sortedAtlas[i]
sortedAtlas[i] = sortedAtlas[j]
sortedAtlas[j] = temp
2022-04-09 11:27:14 +02:00
}
}
2022-04-10 11:11:34 +02:00
function resetEntriesList() {
2022-05-06 09:41:22 +02:00
entriesOffset = 0
entriesList.replaceChildren()
entriesList.appendChild(moreEntriesButton)
2022-04-10 11:11:34 +02:00
buildObjectsList(filter = null, sort = null)
}
async function render() {
2022-05-06 09:41:22 +02:00
context.clearRect(0, 0, canvas.width, canvas.height)
2022-05-06 09:41:22 +02:00
//canvas.width = 1000*zoom
//canvas.height = 1000*zoom
2022-05-06 09:41:22 +02:00
context.globalCompositeOperation = "source-over"
context.clearRect(0, 0, canvas.width, canvas.height)
if (hovered.length > 0) {
2022-05-06 09:41:22 +02:00
container.style.cursor = "pointer"
2022-04-09 11:27:14 +02:00
} else {
2022-05-06 09:41:22 +02:00
container.style.cursor = "default"
2022-04-09 11:27:14 +02:00
}
for (let i = 0; i < hovered.length; i++) {
2022-05-06 09:41:22 +02:00
const path = hovered[i].path
2022-05-06 09:41:22 +02:00
context.beginPath()
2017-04-06 19:44:09 +02:00
if (path[0]) {
2022-05-06 09:41:22 +02:00
//context.moveTo(path[0][0]*zoom, path[0][1]*zoom)
context.moveTo(path[0][0], path[0][1])
}
for (let p = 1; p < path.length; p++) {
2022-05-06 09:41:22 +02:00
//context.lineTo(path[p][0]*zoom, path[p][1]*zoom)
context.lineTo(path[p][0], path[p][1])
2017-04-10 12:25:04 +02:00
}
2017-04-06 00:43:45 +02:00
2022-05-06 09:41:22 +02:00
context.closePath()
2017-04-10 15:16:34 +02:00
2022-05-06 09:41:22 +02:00
context.globalCompositeOperation = "source-over"
2022-05-06 09:41:22 +02:00
context.fillStyle = "rgba(0, 0, 0, 1)"
context.fill()
2022-04-09 11:27:14 +02:00
}
2017-04-06 00:43:45 +02:00
2022-05-06 09:41:22 +02:00
context.globalCompositeOperation = "source-out"
context.drawImage(backgroundCanvas, 0, 0)
2022-04-09 11:27:14 +02:00
if (hovered.length === 1 && hovered[0].path.length && hovered[0].overrideImage) {
2022-05-06 09:41:22 +02:00
const undisputableHovered = hovered[0]
2022-04-09 11:27:14 +02:00
// Find the left-topmost point of all the paths
2022-05-06 09:41:22 +02:00
const entryPosition = getPositionOfEntry(undisputableHovered)
if (entryPosition) {
2022-05-06 09:41:22 +02:00
const [startX, startY] = entryPosition
const overrideImage = new Image()
2022-04-09 11:27:14 +02:00
const loadingPromise = new Promise((res, rej) => {
2022-05-06 09:41:22 +02:00
overrideImage.onerror = rej
overrideImage.onload = res
})
overrideImage.src = "imageOverrides/" + undisputableHovered.overrideImage
try {
2022-05-06 09:41:22 +02:00
await loadingPromise
context.globalCompositeOperation = "source-over"
context.drawImage(overrideImage, startX, startY)
} catch (ex) {
2022-05-06 09:41:22 +02:00
console.error("Cannot override image.", ex)
2022-04-09 11:27:14 +02:00
}
}
}
for (let i = 0; i < hovered.length; i++) {
2017-04-10 12:25:04 +02:00
2022-05-06 09:41:22 +02:00
const path = hovered[i].path
2022-05-06 09:41:22 +02:00
context.beginPath()
if (path[0]) {
2022-05-06 09:41:22 +02:00
//context.moveTo(path[0][0]*zoom, path[0][1]*zoom)
context.moveTo(path[0][0], path[0][1])
}
for (let p = 1; p < path.length; p++) {
2022-05-06 09:41:22 +02:00
//context.lineTo(path[p][0]*zoom, path[p][1]*zoom)
context.lineTo(path[p][0], path[p][1])
}
2022-05-06 09:41:22 +02:00
context.closePath()
2022-05-06 09:41:22 +02:00
context.globalCompositeOperation = "source-over"
2022-05-06 09:41:22 +02:00
let hoverStrokeStyle
2022-04-09 11:27:14 +02:00
switch (hovered[i].diff) {
case "add":
2022-05-06 09:41:22 +02:00
hoverStrokeStyle = "rgba(0, 155, 0, 1)"
break
2022-04-09 11:27:14 +02:00
case "edit":
2022-05-06 09:41:22 +02:00
hoverStrokeStyle = "rgba(155, 155, 0, 1)"
break
2022-04-09 11:27:14 +02:00
default:
2022-05-06 09:41:22 +02:00
hoverStrokeStyle = "rgba(0, 0, 0, 1)"
break
}
2022-05-06 09:41:22 +02:00
context.strokeStyle = hoverStrokeStyle
//context.lineWidth = zoom
context.stroke()
2022-04-09 11:27:14 +02:00
}
2017-04-06 00:43:45 +02:00
2022-04-09 11:27:14 +02:00
}
function updateHovering(e, tapped) {
if (!dragging && (!fixed || tapped)) {
const 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
2022-05-06 09:41:22 +02:00
]
const coords_p = document.getElementById("coords_p")
2022-04-20 10:54:58 +02:00
// Displays coordinates as zero instead of NaN
2023-03-17 18:30:33 +01:00
if (isNaN(pos[0]) === true) {
coords_p.textContent = "0, 0"
2022-04-20 10:54:58 +02:00
} else {
coords_p.textContent = Math.ceil(pos[0]) + ", " + Math.ceil(pos[1])
2022-04-20 10:54:58 +02:00
}
2022-04-09 11:27:14 +02:00
if (pos[0] <= 2200 && pos[0] >= -100 && pos[0] <= 2200 && pos[0] >= -100) {
2022-05-06 09:41:22 +02:00
const newHovered = []
for (let i = 0; i < atlas.length; i++) {
if (pointIsInPolygon(pos, atlas[i].path)) {
2022-05-06 09:41:22 +02:00
newHovered.push(atlas[i])
2022-04-09 11:27:14 +02:00
}
}
2022-05-06 09:41:22 +02:00
let changed = false
2023-03-17 18:30:33 +01:00
if (hovered.length === newHovered.length) {
for (let i = 0; i < hovered.length; i++) {
2023-03-17 18:30:33 +01:00
if (hovered[i].id !== newHovered[i].id) {
2022-05-06 09:41:22 +02:00
changed = true
break
2022-04-09 11:27:14 +02:00
}
}
2022-04-09 11:27:14 +02:00
} else {
2022-05-06 09:41:22 +02:00
changed = true
}
if (changed) {
hovered = newHovered.sort(function (a, b) {
2022-05-06 09:41:22 +02:00
return calcPolygonArea(a.path) - calcPolygonArea(b.path)
})
2017-04-06 00:43:45 +02:00
2022-05-06 09:41:22 +02:00
objectsContainer.replaceChildren()
for (const i in hovered) {
2022-05-06 09:41:22 +02:00
const element = createInfoBlock(hovered[i])
2017-04-06 00:43:45 +02:00
2022-05-06 09:41:22 +02:00
objectsContainer.appendChild(element)
2022-05-06 09:41:22 +02:00
hovered[i].element = element
2022-04-09 11:27:14 +02:00
}
2022-05-06 09:41:22 +02:00
if (hovered.length > 0) {
document.getElementById("timeControlsSlider").blur()
closeObjectsListButton.classList.remove("d-none")
2022-04-26 09:52:44 +02:00
if ((objectsContainer.scrollHeight > objectsContainer.clientHeight) && !tapped) {
2022-05-06 09:41:22 +02:00
objectsListOverflowNotice.classList.remove("d-none")
2022-04-26 09:52:44 +02:00
} else {
2022-05-06 09:41:22 +02:00
objectsListOverflowNotice.classList.add("d-none")
2022-04-26 09:52:44 +02:00
}
2022-04-09 11:27:14 +02:00
} else {
2022-05-06 09:41:22 +02:00
closeObjectsListButton.classList.add("d-none")
objectsListOverflowNotice.classList.add("d-none")
entriesList.classList.remove("disableHover")
2022-04-09 11:27:14 +02:00
}
2022-05-06 09:41:22 +02:00
render()
2022-04-09 11:27:14 +02:00
}
}
}
2022-04-09 11:27:14 +02:00
}
2022-05-06 09:41:22 +02:00
window.addEventListener("hashchange", highlightEntryFromUrl)
2022-04-09 21:09:57 +02:00
function highlightEntryFromUrl() {
const hash = window.location.hash.substring(1); //Remove hash prefix
const [id, period] = hash.split('/')
2022-04-09 21:09:57 +02:00
if (period) {
2022-05-06 09:41:22 +02:00
const [, targetPeriod, targetVariation] = parsePeriod(period)
updateTime(targetPeriod, targetVariation, true)
} else {
updateTime(defaultPeriod, defaultVariation, true)
}
if (id) {
const entries = atlas.filter(function (e) {
2022-05-06 09:41:22 +02:00
return e.id === id
})
if (entries.length === 1) {
2022-05-06 09:41:22 +02:00
const entry = entries[0]
document.title = entry.name + " on the 2022 r/place Atlas"
if ((!entry.diff || entry.diff !== "delete")) {
if (document.getElementById("objectEditNav")) {
2022-05-06 09:41:22 +02:00
document.getElementById("objectEditNav").href = "./?mode=draw&id=" + id
document.getElementById("objectEditNav").title = "Edit " + entry.name
} else {
2022-05-06 09:41:22 +02:00
const objectEditNav = document.createElement("a")
objectEditNav.className = "btn btn-outline-primary"
objectEditNav.id = "objectEditNav"
objectEditNav.innerText = "Edit"
objectEditNav.href = "./?mode=draw&id=" + id
objectEditNav.title = "Edit " + entry.name
showListButton.parentElement.appendChild(objectEditNav)
}
2023-03-17 18:30:33 +01:00
} else if (entry.diff === "delete" && document.getElementById("objectEditNav")) {
2022-05-06 09:41:22 +02:00
document.getElementById("objectEditNav").remove()
2022-04-24 09:51:41 +02:00
}
2022-05-06 09:41:22 +02:00
const infoElement = createInfoBlock(entry)
objectsContainer.replaceChildren()
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
2022-05-06 09:41:22 +02:00
]
scaleZoomOrigin = [
2000 / 2 - entry.center[0]// + container.offsetLeft
, 2000 / 2 - entry.center[1]// + container.offsetTop
2022-05-06 09:41:22 +02:00
]
//console.log(zoomOrigin)
closeObjectsListButton.classList.remove("d-none")
entriesList.classList.add("disableHover")
2022-05-06 09:41:22 +02:00
applyView()
hovered = [entry]
render()
hovered[0].element = infoElement
updateLines()
fixed = true
2022-04-20 10:54:58 +02:00
}
2022-04-09 11:27:14 +02:00
}
2017-04-06 00:43:45 +02:00
}
function initView() {
2022-05-06 09:41:22 +02:00
buildObjectsList(null, null)
renderBackground(atlas)
render()
2022-04-10 11:11:34 +02:00
document.addEventListener('timeupdate', (event) => {
sortedAtlas = atlas.concat()
resetEntriesList(null, null)
})
2022-04-09 11:27:14 +02:00
// parse linked atlas entry id from link hash
/*if (window.location.hash.substring(3)){
2022-05-06 09:41:22 +02:00
zoom = 4
applyView()
highlightEntryFromUrl()
2022-04-09 11:27:14 +02:00
}*/
2022-05-06 09:41:22 +02:00
applyView()
render()
updateLines()
2022-04-09 11:27:14 +02:00
}
function initExplore() {
2022-04-09 11:27:14 +02:00
window.updateHovering = updateHovering
window.render = function () { }
function updateHovering(e, tapped) {
if (!dragging && (!fixed || tapped)) {
const 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
2022-05-06 09:41:22 +02:00
]
const coords_p = document.getElementById("coords_p")
// Displays coordinates as zero instead of NaN
2023-03-17 18:30:33 +01:00
if (isNaN(pos[0]) === true) {
coords_p.textContent = "0, 0"
} else {
coords_p.textContent = Math.ceil(pos[0]) + ", " + Math.ceil(pos[1])
}
}
}
2022-05-06 09:41:22 +02:00
renderBackground(atlas)
2022-04-09 11:27:14 +02:00
2022-05-06 09:41:22 +02:00
applyView()
2022-04-09 11:27:14 +02:00
}
function initGlobal() {
container.addEventListener("mousemove", function (e) {
if (e.sourceCapabilities) {
if (!e.sourceCapabilities.firesTouchEvents) {
2022-05-06 09:41:22 +02:00
updateHovering(e)
2022-04-09 11:27:14 +02:00
}
} else {
2022-05-06 09:41:22 +02:00
updateHovering(e)
}
2022-05-06 09:41:22 +02:00
})
2022-04-09 11:27:14 +02:00
}
2022-04-09 11:27:14 +02:00
function initViewGlobal() {
container.addEventListener("mousedown", function (e) {
lastPos = [
e.clientX
, e.clientY
2022-05-06 09:41:22 +02:00
]
})
container.addEventListener("touchstart", function (e) {
2023-03-17 18:30:33 +01:00
if (e.touches.length === 1) {
lastPos = [
e.touches[0].clientX
, e.touches[0].clientY
2022-05-06 09:41:22 +02:00
]
}
2022-05-06 09:41:22 +02:00
}, { passive: true })
container.addEventListener("mouseup", function (e) {
if (Math.abs(lastPos[0] - e.clientX) + Math.abs(lastPos[1] - e.clientY) <= 4) {
2022-05-06 09:41:22 +02:00
toggleFixed(e)
}
2022-05-06 09:41:22 +02:00
})
container.addEventListener("touchend", function (e) {
e.preventDefault()
2022-05-06 09:41:22 +02:00
//console.log(e)
//console.log(e.changedTouches[0].clientX)
2023-03-17 18:30:33 +01:00
if (e.changedTouches.length === 1) {
2022-05-06 09:41:22 +02:00
e = e.changedTouches[0]
//console.log(lastPos[0] - e.clientX)
if (Math.abs(lastPos[0] - e.clientX) + Math.abs(lastPos[1] - e.clientY) <= 4) {
2022-05-06 09:41:22 +02:00
//console.log("Foo!!")
dragging = false
fixed = false
2022-04-09 11:27:14 +02:00
setTimeout(
function () {
2022-05-06 09:41:22 +02:00
updateHovering(e, true)
2022-04-09 11:27:14 +02:00
}
2022-05-06 09:41:22 +02:00
, 10)
}
}
2022-05-06 09:41:22 +02:00
})
if (window.location.hash) { // both "/" and just "/#" will be an empty hash string
2022-05-06 09:41:22 +02:00
highlightEntryFromUrl()
}
2022-04-09 17:49:27 +02:00
}